← GPT-AI-LP
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 });
  }
}