import type { VisualTaskQueryResponse, VisualTaskSubmitResponse } from "@/lib/types"; import { signVolcengineRequest } from "@/lib/volcengine/signature"; export type VisualClientConfig = { accessKeyId: string; secretAccessKey: string; region: string; service: string; endpoint: string; }; export function getVisualClientConfig(): VisualClientConfig | null { const accessKeyId = process.env.VOLCENGINE_ACCESS_KEY_ID; const secretAccessKey = process.env.VOLCENGINE_SECRET_ACCESS_KEY; if (!accessKeyId || !secretAccessKey) return null; return { accessKeyId, secretAccessKey, region: process.env.VOLCENGINE_REGION || "cn-north-1", service: process.env.VOLCENGINE_SERVICE || "cv", endpoint: process.env.VOLCENGINE_VISUAL_ENDPOINT || "https://visual.volcengineapi.com" }; } export function shouldMockVisualApi(): boolean { const flag = process.env.JIMENG_VISUAL_MOCK || "auto"; if (flag === "1" || flag === "true") return true; if (flag === "0" || flag === "false") return false; return getVisualClientConfig() === null; } export async function submitVisualTask( payload: Record, config = getVisualClientConfig() ): Promise { if (!config) throw new Error("Volcengine Visual credentials are not configured."); return callVisualApi("CVSync2AsyncSubmitTask", payload, config); } export async function queryVisualTask( payload: Record, config = getVisualClientConfig() ): Promise { if (!config) throw new Error("Volcengine Visual credentials are not configured."); return callVisualApi("CVSync2AsyncGetResult", payload, config); } async function callVisualApi( action: "CVSync2AsyncSubmitTask" | "CVSync2AsyncGetResult", payload: Record, config: VisualClientConfig ): Promise { const body = JSON.stringify(payload); const signed = signVolcengineRequest({ method: "POST", endpoint: config.endpoint, query: { Action: action, Version: "2022-08-31" }, body, accessKeyId: config.accessKeyId, secretAccessKey: config.secretAccessKey, region: config.region, service: config.service }); const response = await fetch(signed.url, { method: "POST", headers: signed.headers, body }); const text = await response.text(); let json: unknown; try { json = JSON.parse(text); } catch { throw new Error(`Volcengine Visual returned non-JSON response: ${response.status} ${text.slice(0, 240)}`); } if (!response.ok) { const message = typeof json === "object" && json && "message" in json ? String(json.message) : text; throw new Error(`Volcengine Visual HTTP ${response.status}: ${message}`); } return json as T; }