import "server-only"; import { openaiGenerateImage } from "../ai/openai"; import { saveAttachment } from "../storage"; import { recordUsage } from "../usage"; import type { ToolContext } from "./index"; export async function generateImageTool(prompt: string, ctx: ToolContext, opts: { size?: string; quality?: string; model?: string } = {}) { const t0 = Date.now(); const r = await openaiGenerateImage(prompt, { model: opts.model, size: opts.size, quality: opts.quality ?? "medium" }); const img = r.images[0]; if (!img) return { error: "No image returned" }; const att = await saveAttachment({ data: Buffer.from(img.b64, "base64"), filename: `generated-${Date.now()}.png`, mime: "image/png", conversationId: ctx.conversationId, projectId: ctx.projectId, messageId: ctx.messageId, kind: "generated-image", meta: { prompt, model: r.model, revisedPrompt: img.revisedPrompt, size: opts.size, quality: opts.quality } }); const u = r.usage as { input_tokens?: number; output_tokens?: number; input_tokens_details?: { image_tokens?: number; text_tokens?: number } } | undefined; // gpt-image pricing: text input $5/M, image output $30-32/M (verified); image input tokens $8/M const cost = u ? ((u.input_tokens_details?.text_tokens ?? u.input_tokens ?? 0) * 5 + (u.input_tokens_details?.image_tokens ?? 0) * 8 + (u.output_tokens ?? 0) * 32) / 1e6 : null; await recordUsage({ provider: "openai", modelId: r.model, kind: "image", conversationId: ctx.conversationId, projectId: ctx.projectId, messageId: ctx.messageId, usage: { input: u?.input_tokens ?? 0, output: u?.output_tokens ?? 0 }, costEstimated: cost, latencyMs: Date.now() - t0 }); return { attachmentId: att.id, model: r.model, revisedPrompt: img.revisedPrompt, costUsd: cost, note: "Image saved; it is displayed to the user automatically." }; }