CODE · 3.0 KB
api/design-images.js
Workspace snapshot · 08/31 23:51
import { authorizeRequest, publicError } from "./security.js";
const ENGINE_URL = "https://ai-banner.agent-venture-studio.com/api/generate-banners";
export const config = { maxDuration: 30 };
export default async function handler(req, res) {
const auth = authorizeRequest(req, process.env, Date.now(), { rateLimit: req.method === "POST" });
if (!auth.ok) return res.status(auth.status).json({ error: auth.error });
try {
if (req.method === "GET") {
const jobIds = String(req.query?.jobIds || "");
if (!jobIds) return res.status(400).json({ error: "jobIdsが必要です" });
const ids = jobIds.split(",").map((id) => id.trim()).filter(Boolean).slice(0, 42);
const jobs = [];
for (let index = 0; index < ids.length; index += 3) {
const group = ids.slice(index, index + 3);
const response = await fetch(`${ENGINE_URL}?jobIds=${encodeURIComponent(group.join(","))}`);
const data = await response.json().catch(() => null);
if (!response.ok) return res.status(response.status === 429 ? 429 : 502).json({ error: response.status === 429 ? "画像生成の上限に達しました" : "画像生成状況を取得できませんでした" });
jobs.push(...(data?.jobs || []));
}
return res.status(200).json({ jobs });
}
if (req.method !== "POST") return res.status(405).json({ error: "GETまたはPOSTのみ利用できます" });
const visuals = Array.isArray(req.body?.visuals) ? req.body.visuals.slice(0, 7) : null;
if (Array.isArray(req.body?.visuals) && (!visuals.length || req.body.visuals.length > 7)) {
return res.status(400).json({ error: "一度に生成できる画像は1〜7枚です" });
}
const payloads = visuals || [req.body || {}];
const jobs = [];
for (const visual of payloads) {
const { sectionId = "", visualId = "", layer = "content", ...payload } = visual || {};
const response = await fetch(ENGINE_URL, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
...payload,
copy: payload.textIntegrated === true && !payload.copy?.cta
? { ...(payload.copy || {}), cta: "" }
: payload.copy,
textless: payload.textIntegrated !== true,
}),
});
const data = await response.json().catch(() => null);
if (!response.ok) {
const label = sectionId ? `(${sectionId})` : "";
const error = new Error(response.status === 429 ? `画像生成の上限に達しました${label}` : `画像生成を開始できませんでした${label}`);
error.status = response.status === 429 ? 429 : 502;
throw error;
}
jobs.push(...(data?.jobs || []).map((job) => ({ ...job, sectionId, visualId: visualId || `${sectionId}:${layer}`, layer })));
}
return res.status(200).json({ jobs });
} catch (error) {
if (error?.status) return res.status(error.status).json({ error: error.message });
const mapped = publicError(error);
return res.status(mapped.status).json({ error: mapped.error });
}
}