mirror of
https://github.com/vibegif/vibegif.lol.git
synced 2026-04-07 02:12:12 +00:00
Feat: OpenRouter image-only generation helper
This commit is contained in:
121
assets/js/openrouter.js
Normal file
121
assets/js/openrouter.js
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
const OPENROUTER_URL = "https://openrouter.ai/api/v1/chat/completions";
|
||||||
|
|
||||||
|
function toDataUrlMaybe(item) {
|
||||||
|
if (!item) return null;
|
||||||
|
if (typeof item === "string") {
|
||||||
|
if (item.startsWith("http://") || item.startsWith("https://") || item.startsWith("data:image/")) return item;
|
||||||
|
return `data:image/png;base64,${item}`;
|
||||||
|
}
|
||||||
|
if (item.url) return item.url;
|
||||||
|
if (item.image_url?.url) return item.image_url.url;
|
||||||
|
if (item.b64_json) return `data:image/png;base64,${item.b64_json}`;
|
||||||
|
if (item.data) return `data:image/png;base64,${item.data}`;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractImageFromResponse(json) {
|
||||||
|
const c = json?.choices?.[0];
|
||||||
|
if (!c) return null;
|
||||||
|
|
||||||
|
const msg = c.message || {};
|
||||||
|
const content = msg.content;
|
||||||
|
|
||||||
|
if (Array.isArray(content)) {
|
||||||
|
for (const part of content) {
|
||||||
|
if (part?.type === "image_url") {
|
||||||
|
const u = part?.image_url?.url || part?.url;
|
||||||
|
if (u) return u;
|
||||||
|
}
|
||||||
|
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 = [
|
||||||
|
json?.images,
|
||||||
|
json?.data,
|
||||||
|
msg?.images,
|
||||||
|
c?.images
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const pool of fallbackPools) {
|
||||||
|
if (Array.isArray(pool) && pool.length) {
|
||||||
|
const x = toDataUrlMaybe(pool[0]);
|
||||||
|
if (x) return x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof content === "string") {
|
||||||
|
const m = content.match(/https?:\/\/\S+\.(?:png|jpg|jpeg|webp|gif)/i);
|
||||||
|
if (m) return m[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function generateImageFrame({
|
||||||
|
apiKey,
|
||||||
|
model,
|
||||||
|
textPrompt,
|
||||||
|
previousFrames = [],
|
||||||
|
imageSize = "1K",
|
||||||
|
aspectRatio = "1:1"
|
||||||
|
}) {
|
||||||
|
const messages = [];
|
||||||
|
|
||||||
|
// rolling window of 2 frames only
|
||||||
|
const recent = previousFrames.slice(-2);
|
||||||
|
|
||||||
|
if (recent.length) {
|
||||||
|
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 = {
|
||||||
|
model,
|
||||||
|
modalities: ["image"],
|
||||||
|
messages,
|
||||||
|
image_config: {
|
||||||
|
image_size: imageSize,
|
||||||
|
aspect_ratio: aspectRatio
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = await fetch(OPENROUTER_URL, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
Authorization: `Bearer ${apiKey}`,
|
||||||
|
"HTTP-Referer": window.location.origin,
|
||||||
|
"X-Title": "vibegif.lol"
|
||||||
|
},
|
||||||
|
body: JSON.stringify(body)
|
||||||
|
});
|
||||||
|
|
||||||
|
const json = await res.json().catch(() => ({}));
|
||||||
|
|
||||||
|
if (!res.ok) {
|
||||||
|
const msg = json?.error?.message || `OpenRouter error (${res.status})`;
|
||||||
|
throw new Error(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
const image = extractImageFromResponse(json);
|
||||||
|
if (!image) throw new Error("No image found in model response.");
|
||||||
|
return image;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user