← GPT-AI-BANNER
CODE · 3.1 KB

api/generate-banners.js

Workspace snapshot · 09/04 13:35

import { buildBannerPrompts, buildRuntimePrompt, callRuntimeRpc, IMAGE_ENGINE, loadPromptSettings, RUNTIME_SERVICE_ID, runtimeEnvironment } from "./banner-core.js";

export const config = { maxDuration: 30 };

export function publicRuntimeGenerationEnabled(environment = process.env) {
  return environment.PUBLIC_RUNTIME_GENERATION_ENABLED === "true";
}

export default async function handler(req, res) {
  if (!publicRuntimeGenerationEnabled()) {
    return res.status(503).json({
      error: "公開画像生成は利用ポリシー確認中のため停止しています",
      code: "PUBLIC_IMAGE_RUNTIME_DISABLED",
    });
  }
  const runtime = runtimeEnvironment();
  if (req.method === "GET" && !req.query?.jobIds) {
    if (!runtime.connected) return res.status(200).json({ connected: false, engine: IMAGE_ENGINE });
    try {
      const status = await callRuntimeRpc({
        rpc: "avs_llm_public_image_service_status",
        payload: { p_service_id: RUNTIME_SERVICE_ID, p_token: runtime.token },
      });
      return res.status(200).json(status);
    } catch {
      return res.status(200).json({ connected: false, engine: IMAGE_ENGINE });
    }
  }
  if (!runtime.connected) return res.status(503).json({ error: "VPS画像生成基盤が未接続です", code: "IMAGE_RUNTIME_NOT_CONFIGURED" });

  if (req.method === "GET") {
    const jobIds = String(req.query.jobIds).split(",").filter(Boolean).slice(0, 3);
    if (!jobIds.length) return res.status(400).json({ error: "jobIdsが必要です" });
    try {
      const jobs = await Promise.all(jobIds.map(jobId => callRuntimeRpc({
        rpc: "avs_llm_public_get_image_job",
        payload: { p_service_id: RUNTIME_SERVICE_ID, p_token: runtime.token, p_job_id: jobId },
      })));
      return res.status(200).json({ engine: IMAGE_ENGINE, jobs });
    } catch (error) {
      return res.status(error.status || 502).json({ error: error.message, code: error.code });
    }
  }

  if (req.method !== "POST") return res.status(405).json({ error: "GETまたはPOSTのみ利用できます" });
  let prompts;
  try {
    const promptSettings = await loadPromptSettings();
    prompts = buildBannerPrompts(req.body, promptSettings);
  } catch (error) {
    return res.status(400).json({ error: error.message });
  }
  const requestId = crypto.randomUUID();
  const settled = await Promise.allSettled(prompts.map(async item => ({
    direction: item.direction,
    jobId: await callRuntimeRpc({
      rpc: "avs_llm_public_enqueue_image_job",
      payload: {
        p_service_id: RUNTIME_SERVICE_ID,
        p_token: runtime.token,
        p_request_id: requestId,
        p_direction: item.direction,
        p_prompt: buildRuntimePrompt(item),
        p_width: item.width,
        p_height: item.height,
      },
    }),
  })));
  const jobs = settled.map((result, index) => result.status === "fulfilled"
    ? { ...result.value, status: "QUEUED" }
    : { direction: prompts[index].direction, status: "FAILED", error: result.reason?.message || "画像生成を開始できませんでした" });
  return res.status(jobs.some(item => item.jobId) ? 202 : 502).json({ engine: IMAGE_ENGINE, requestId, jobs });
}