import { z } from "zod"; import { requireAdmin } from "@/lib/middleware/admin"; import { getAllSystemSettings, getSystemSetting, upsertSystemSetting, } from "@/lib/db/queries"; import { ChatSDKError } from "@/lib/errors"; import { probeRunwareSeedImageSupport } from "@/lib/realtime/runware-capability"; const settingSchema = z.object({ key: z.string(), value: z.any(), }); const DEFAULT_RUNWARE_MODEL = "runware:101@1"; const DEFAULT_RUNWARE_STYLIZE_MODEL = "runware:106@1"; const DEFAULT_RUNWARE_CONTROL_MODEL = "runware:25@1"; function isObjectLike(value: unknown): value is Record { return Boolean(value) && typeof value === "object" && !Array.isArray(value); } function mapProbeStatus(code: string) { if (code === "UPSTREAM_ERROR") return 502; return 400; } export async function GET(request: Request) { try { await requireAdmin(); const { searchParams } = new URL(request.url); const key = searchParams.get("key"); if (key) { const setting = await getSystemSetting({ key }); return Response.json({ setting }); } const settings = await getAllSystemSettings(); return Response.json({ settings }); } catch (error) { if (error instanceof ChatSDKError) { return error.toResponse(); } return new ChatSDKError("offline:admin").toResponse(); } } export async function POST(request: Request) { try { const session = await requireAdmin(); const body = await request.json(); const { key, value } = settingSchema.parse(body); let nextValue = value; if (key === "realtime_canvas_config") { if (!isObjectLike(value)) { return new ChatSDKError("bad_request:api", "realtime_canvas_config value 必须为对象").toResponse(); } const enabled = value.enabled !== false; const runwareApiKey = String(value.runwareApiKey || value.falApiKey || value.apiKey || "").trim(); const runwareModel = String(value.runwareModel || DEFAULT_RUNWARE_MODEL).trim() || DEFAULT_RUNWARE_MODEL; const runwareStylizeModel = String(value.runwareStylizeModel || DEFAULT_RUNWARE_STYLIZE_MODEL).trim() || DEFAULT_RUNWARE_STYLIZE_MODEL; const runwareControlModel = String(value.runwareControlModel || DEFAULT_RUNWARE_CONTROL_MODEL).trim() || DEFAULT_RUNWARE_CONTROL_MODEL; const runwareControlPreprocessor = value.runwareControlPreprocessor === "lineart" || value.runwareControlPreprocessor === "depth" ? value.runwareControlPreprocessor : "canny"; const renderMode = value.renderMode === "strict-structure" || value.renderMode === "stylize" || value.renderMode === "balanced" ? value.renderMode : "balanced"; if (enabled) { if (!runwareApiKey) { return new ChatSDKError("bad_request:api", "启用实时画布必须配置 Runware API Key").toResponse(); } for (const modelId of [runwareModel, runwareStylizeModel].filter(Boolean)) { const probeResult = await probeRunwareSeedImageSupport({ apiKey: runwareApiKey, modelId, }); if (!probeResult.supported) { return Response.json( { code: probeResult.code, message: probeResult.message, }, { status: mapProbeStatus(probeResult.code) } ); } } } nextValue = { ...value, runwareApiKey, falApiKey: runwareApiKey, runwareModel, runwareStylizeModel, runwareControlModel, runwareControlPreprocessor, renderMode, }; } const setting = await upsertSystemSetting({ key, value: nextValue, updatedBy: session.user.id, }); return Response.json({ setting: setting[0] }); } catch (error) { if (error instanceof ChatSDKError) { return error.toResponse(); } if (error instanceof z.ZodError) { return new ChatSDKError("bad_request:api", error.message).toResponse(); } return new ChatSDKError("offline:admin").toResponse(); } }