Fix: docs-aligned image request and response parsing

This commit is contained in:
2026-03-20 21:22:26 -07:00
parent bc2d492803
commit d512ed31f7

View File

@@ -8,51 +8,46 @@ function toDataUrlMaybe(item) {
} }
if (item.url) return item.url; if (item.url) return item.url;
if (item.image_url?.url) return item.image_url.url; if (item.image_url?.url) return item.image_url.url;
if (item.imageUrl?.url) return item.imageUrl.url;
if (item.b64_json) return `data:image/png;base64,${item.b64_json}`; if (item.b64_json) return `data:image/png;base64,${item.b64_json}`;
if (item.data) return `data:image/png;base64,${item.data}`; if (item.data) return `data:image/png;base64,${item.data}`;
return null; return null;
} }
function extractImageFromResponse(json) { function extractImageFromResponse(json) {
const c = json?.choices?.[0]; const msg = json?.choices?.[0]?.message;
if (!c) return null; if (!msg) return null;
const msg = c.message || {}; // Primary docs format: message.images[].image_url.url
const content = msg.content; if (Array.isArray(msg.images) && msg.images.length) {
for (const image of msg.images) {
const url = image?.image_url?.url || image?.imageUrl?.url || image?.url;
if (url) return url;
const maybe = toDataUrlMaybe(image);
if (maybe) return maybe;
}
}
if (Array.isArray(content)) { // Fallback: content parts
for (const part of content) { if (Array.isArray(msg.content)) {
for (const part of msg.content) {
if (part?.type === "image_url") { if (part?.type === "image_url") {
const u = part?.image_url?.url || part?.url; const u = part?.image_url?.url || part?.imageUrl?.url || part?.url;
if (u) return u; if (u) return u;
} }
if (part?.type === "output_image" && part?.image_url?.url) return part.image_url.url; if (part?.type === "output_image" && part?.image_url?.url) return part.image_url.url;
if (part?.type === "text" && typeof part.text === "string") {
const m = part.text.match(/https?:\/\/\S+\.(?:png|jpg|jpeg|webp|gif)/i);
if (m) return m[0];
}
} }
} }
const fallbackPools = [ // Extra fallback pools
json?.images, const fallbackPools = [json?.images, json?.data, msg?.data, json?.choices?.[0]?.images];
json?.data,
msg?.images,
c?.images
];
for (const pool of fallbackPools) { for (const pool of fallbackPools) {
if (Array.isArray(pool) && pool.length) { if (Array.isArray(pool) && pool.length) {
const x = toDataUrlMaybe(pool[0]); const maybe = toDataUrlMaybe(pool[0]);
if (x) return x; if (maybe) return maybe;
} }
} }
if (typeof content === "string") {
const m = content.match(/https?:\/\/\S+\.(?:png|jpg|jpeg|webp|gif)/i);
if (m) return m[0];
}
return null; return null;
} }
@@ -64,37 +59,24 @@ export async function generateImageFrame({
imageSize = "1K", imageSize = "1K",
aspectRatio = "1:1" aspectRatio = "1:1"
}) { }) {
const messages = []; // Docs recommend text first, then images in content array
const content = [{ type: "text", text: textPrompt }];
// rolling window of 2 frames only for (const frame of previousFrames.slice(-2)) {
const recent = previousFrames.slice(-2); content.push({
type: "image_url",
if (recent.length) { image_url: { url: frame }
for (const frame of recent) { });
messages.push({
role: "user",
content: [
{ type: "image_url", image_url: { url: frame } }
]
});
}
} }
messages.push({
role: "user",
content: [
{ type: "text", text: textPrompt }
]
});
const body = { const body = {
model, model,
modalities: ["image"], modalities: ["image"], // As requested: image only
messages, messages: [{ role: "user", content }],
image_config: { image_config: {
image_size: imageSize, image_size: imageSize,
aspect_ratio: aspectRatio aspect_ratio: aspectRatio
} },
stream: false
}; };
const res = await fetch(OPENROUTER_URL, { const res = await fetch(OPENROUTER_URL, {
@@ -109,7 +91,6 @@ export async function generateImageFrame({
}); });
const json = await res.json().catch(() => ({})); const json = await res.json().catch(() => ({}));
if (!res.ok) { if (!res.ok) {
const msg = json?.error?.message || `OpenRouter error (${res.status})`; const msg = json?.error?.message || `OpenRouter error (${res.status})`;
throw new Error(msg); throw new Error(msg);