spb/chat-spboucher-ai
Public
1import "server-only";2import { openaiGenerateImage } from "../ai/openai";3import { saveAttachment } from "../storage";4import { recordUsage } from "../usage";5import type { ToolContext } from "./index";67export async function generateImageTool(prompt: string, ctx: ToolContext, opts: { size?: string; quality?: string; model?: string } = {}) {8 const t0 = Date.now();9 const r = await openaiGenerateImage(prompt, { model: opts.model, size: opts.size, quality: opts.quality ?? "medium" });10 const img = r.images[0];11 if (!img) return { error: "No image returned" };12 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 } });13 const u = r.usage as { input_tokens?: number; output_tokens?: number; input_tokens_details?: { image_tokens?: number; text_tokens?: number } } | undefined;14 // gpt-image pricing: text input $5/M, image output $30-32/M (verified); image input tokens $8/M15 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;16 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 });17 return { attachmentId: att.id, model: r.model, revisedPrompt: img.revisedPrompt, costUsd: cost, note: "Image saved; it is displayed to the user automatically." };18}19