fix(secretaria): embed() cai para Gemini se OpenAI falhar (não derruba RAG)
Antes, com openai_key presente, qualquer falha (ex.: 429 insufficient_quota) retornava null sem tentar o Gemini. Agora tenta OpenAI e, em falha, usa Gemini. Aviso documentado: OpenAI (1536d) e Gemini (768d) são incompatíveis — trocar de provider exige reindexar (sync-knowledge + memória de contato). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -49,32 +49,52 @@ export async function embed(text: string, cfg: any): Promise<number[] | null> {
|
||||
if (!input.trim()) return null
|
||||
const openaiKey = cfg?.openai_key as string | undefined
|
||||
const geminiKey = cfg?.gemini_key as string | undefined
|
||||
|
||||
// Preferência: OpenAI; em QUALQUER falha (ex.: 429 insufficient_quota), cai para
|
||||
// o Gemini — assim uma chave OpenAI sem créditos não derruba o RAG.
|
||||
// ⚠️ OpenAI (1536-dim) e Gemini (768-dim) geram espaços vetoriais incompatíveis.
|
||||
// Ao trocar de provider é preciso REINDEXAR (sync-knowledge + memória de contato),
|
||||
// senão o cosseno mistura dimensões e o retrieval fica sem sentido.
|
||||
if (openaiKey) {
|
||||
const v = await embedOpenAI(input, openaiKey)
|
||||
if (v) return v
|
||||
}
|
||||
if (geminiKey) {
|
||||
const v = await embedGemini(input, geminiKey)
|
||||
if (v) return v
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
async function embedOpenAI(input: string, apiKey: string): Promise<number[] | null> {
|
||||
try {
|
||||
if (openaiKey) {
|
||||
const res = await fetch('https://api.openai.com/v1/embeddings', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${openaiKey}` },
|
||||
body: JSON.stringify({ model: 'text-embedding-3-small', input }),
|
||||
})
|
||||
if (!res.ok) return null
|
||||
const data: any = await res.json()
|
||||
return data?.data?.[0]?.embedding ?? null
|
||||
}
|
||||
if (geminiKey) {
|
||||
const url = `https://generativelanguage.googleapis.com/v1beta/models/text-embedding-004:embedContent?key=${geminiKey}`
|
||||
const res = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ model: 'models/text-embedding-004', content: { parts: [{ text: input }] } }),
|
||||
})
|
||||
if (!res.ok) return null
|
||||
const data: any = await res.json()
|
||||
return data?.embedding?.values ?? null
|
||||
}
|
||||
const res = await fetch('https://api.openai.com/v1/embeddings', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${apiKey}` },
|
||||
body: JSON.stringify({ model: 'text-embedding-3-small', input }),
|
||||
})
|
||||
if (!res.ok) return null
|
||||
const data: any = await res.json()
|
||||
return data?.data?.[0]?.embedding ?? null
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
async function embedGemini(input: string, apiKey: string): Promise<number[] | null> {
|
||||
try {
|
||||
const url = `https://generativelanguage.googleapis.com/v1beta/models/text-embedding-004:embedContent?key=${apiKey}`
|
||||
const res = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ model: 'models/text-embedding-004', content: { parts: [{ text: input }] } }),
|
||||
})
|
||||
if (!res.ok) return null
|
||||
const data: any = await res.json()
|
||||
return data?.embedding?.values ?? null
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
export function hasEmbeddingKey(cfg: any): boolean {
|
||||
|
||||
Reference in New Issue
Block a user