( apiKey: string, body: ImageToolBody, requestId: string, logger: ReturnType<typeof createLogger> )
| 520 | } |
| 521 | |
| 522 | async function generateWithOpenAI( |
| 523 | apiKey: string, |
| 524 | body: ImageToolBody, |
| 525 | requestId: string, |
| 526 | logger: ReturnType<typeof createLogger> |
| 527 | ): Promise<GeneratedImageResult> { |
| 528 | const model = pickAllowed(body.model, OPENAI_IMAGE_MODELS, 'gpt-image-1.5') |
| 529 | const size = |
| 530 | model === 'gpt-image-2' |
| 531 | ? pickAllowed(body.size, OPENAI_IMAGE_2_SIZES, 'auto') |
| 532 | : pickAllowed(body.size, OPENAI_IMAGE_SIZES, 'auto') |
| 533 | const outputFormat = pickAllowed(body.outputFormat, IMAGE_OUTPUT_FORMATS, 'png') |
| 534 | const requestBody: Record<string, string | number> = { |
| 535 | model, |
| 536 | prompt: body.prompt, |
| 537 | size, |
| 538 | n: 1, |
| 539 | } |
| 540 | |
| 541 | if (body.quality) { |
| 542 | requestBody.quality = pickAllowed(body.quality, OPENAI_IMAGE_QUALITIES, 'auto') |
| 543 | } |
| 544 | if (body.background) { |
| 545 | requestBody.background = pickAllowed(body.background, OPENAI_IMAGE_BACKGROUNDS, 'auto') |
| 546 | } |
| 547 | if (body.outputFormat) { |
| 548 | requestBody.output_format = outputFormat |
| 549 | } |
| 550 | if (body.moderation) { |
| 551 | requestBody.moderation = pickAllowed(body.moderation, OPENAI_MODERATION_LEVELS, 'auto') |
| 552 | } |
| 553 | |
| 554 | const openaiResponse = await fetch('https://api.openai.com/v1/images/generations', { |
| 555 | method: 'POST', |
| 556 | headers: { |
| 557 | Authorization: `Bearer ${apiKey}`, |
| 558 | 'Content-Type': 'application/json', |
| 559 | }, |
| 560 | body: JSON.stringify(requestBody), |
| 561 | }) |
| 562 | |
| 563 | if (!openaiResponse.ok) { |
| 564 | const error = await readResponseTextWithLimit(openaiResponse, { |
| 565 | maxBytes: DEFAULT_MAX_ERROR_BODY_BYTES, |
| 566 | label: 'OpenAI image error response', |
| 567 | }) |
| 568 | throw new Error(`OpenAI API error: ${openaiResponse.status} - ${error}`) |
| 569 | } |
| 570 | |
| 571 | const data = await readResponseJsonWithLimit(openaiResponse, { |
| 572 | maxBytes: MAX_IMAGE_JSON_BYTES, |
| 573 | label: 'OpenAI image response', |
| 574 | }) |
| 575 | if (!isRecordLike(data)) { |
| 576 | throw new Error('Invalid OpenAI image response') |
| 577 | } |
| 578 | |
| 579 | const firstImage = firstRecord(data.data) |
no test coverage detected