| 367 | } |
| 368 | |
| 369 | export async function queryEmbedding( |
| 370 | textToEmbed: string | string[], |
| 371 | model: string = "text-embedding-ada-002", |
| 372 | ): Promise<number[][]> { |
| 373 | const response = await fetch("https://api.openai.com/v1/embeddings", { |
| 374 | method: "POST", |
| 375 | headers: { |
| 376 | "Content-Type": "application/json", |
| 377 | Authorization: `Bearer ${process.env.OPENAI_API_KEY}`, |
| 378 | }, |
| 379 | body: JSON.stringify({ |
| 380 | model, |
| 381 | input: textToEmbed, |
| 382 | }), |
| 383 | }); |
| 384 | |
| 385 | const responseJson: EmbeddingResponse | { error: OpenAIError } = |
| 386 | await response.json(); |
| 387 | |
| 388 | if (response.status === 429) { |
| 389 | // Throwing an error triggers exponential backoff retry |
| 390 | throw new Error( |
| 391 | `OpenAI API rate limit exceeded. Full error: ${JSON.stringify( |
| 392 | responseJson, |
| 393 | )}`, |
| 394 | ); |
| 395 | } |
| 396 | if ("error" in responseJson) { |
| 397 | throw new Error( |
| 398 | "Error from embedding: " + |
| 399 | JSON.stringify(responseJson.error, undefined, 2), |
| 400 | ); |
| 401 | } |
| 402 | |
| 403 | return responseJson.data.map((item) => item.embedding); |
| 404 | } |
| 405 | |
| 406 | function combineMessagesForHFEndpoints(messages: LLMChatMessage[]): string { |
| 407 | return messages |