Skip to content
Merged
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 52 additions & 21 deletions convex/lib/embeddings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,27 +12,58 @@ export async function generateEmbedding(text: string) {
return emptyEmbedding()
}

const response = await fetch('https://api.openai.com/v1/embeddings', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${apiKey}`,
},
body: JSON.stringify({
model: EMBEDDING_MODEL,
input: text,
}),
})

if (!response.ok) {
const message = await response.text()
throw new Error(`Embedding failed: ${message}`)
}
const maxRetries = 3
const baseDelay = 1000
let lastError: unknown

for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const response = await fetch('https://api.openai.com/v1/embeddings', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${apiKey}`,
},
body: JSON.stringify({
model: EMBEDDING_MODEL,
input: text,
}),
})

if (!response.ok) {
const message = await response.text()
const isRateLimit = response.status === 429
const isServerError = response.status >= 500

const payload = (await response.json()) as {
data?: Array<{ embedding: number[] }>
if ((isRateLimit || isServerError) && attempt < maxRetries - 1) {
const delay = baseDelay * Math.pow(2, attempt)
console.warn(
`OpenAI API error (${response.status}), retrying in ${delay}ms (attempt ${attempt + 1}/${maxRetries})`,
)
await new Promise((resolve) => setTimeout(resolve, delay))
continue
}

throw new Error(`Embedding failed: ${message}`)
}

const payload = (await response.json()) as {
data?: Array<{ embedding: number[] }>
}
const embedding = payload.data?.[0]?.embedding
if (!embedding) throw new Error('Embedding missing from response')
return embedding
} catch (error) {
lastError = error
if (attempt < maxRetries - 1 && error instanceof Error) {
const delay = baseDelay * Math.pow(2, attempt)
console.warn(`Network error, retrying in ${delay}ms (attempt ${attempt + 1}/${maxRetries})`)
await new Promise((resolve) => setTimeout(resolve, delay))
continue
}
throw error
}
}
const embedding = payload.data?.[0]?.embedding
if (!embedding) throw new Error('Embedding missing from response')
return embedding

throw lastError ?? new Error('Embedding failed after retries')
}