import { auth } from "@/app/(auth)/auth"; import { getSystemSetting } from "@/lib/db/queries"; type RealtimeCanvasConfig = { enabled?: boolean; falApiKey?: string; apiKey?: string; throttleInterval?: number; maxBuffering?: number; maxInputResolution?: number; jpegQuality?: number; defaults?: { steps?: number; scheduleMu?: number; feedback?: number; imageSize?: "square" | "square_hd"; }; }; type AngleEditConfig = { falApiKey?: string; }; const defaultConfig = { session: { idleTimeoutMs: 120000, }, transport: { throttleInterval: 100, maxBuffering: 2, }, image: { maxInputResolution: 1024, jpegQuality: 0.55, }, model: { id: "fal-ai/flux-2/klein/realtime", defaults: { steps: 3, scheduleMu: 2.3, feedback: 0.95, imageSize: "square" as const, }, limits: { steps: { min: 1, max: 6 }, feedback: { min: 0.7, max: 1.0 }, }, }, features: { history: true, abCompare: false, }, }; function clamp(value: number, min: number, max: number) { return Math.min(max, Math.max(min, value)); } export async function GET() { const session = await auth(); if (!session?.user?.id) { return Response.json({ code: "UNAUTHORIZED", message: "请先登录" }, { status: 401 }); } const [setting, angleEditSetting] = await Promise.all([ getSystemSetting({ key: "realtime_canvas_config" }).catch(() => null), getSystemSetting({ key: "angle_edit_config" }).catch(() => null), ]); const config = (setting?.value || {}) as RealtimeCanvasConfig; const angleEditConfig = (angleEditSetting?.value || {}) as AngleEditConfig; if (config.enabled === false) { return Response.json( { code: "FEATURE_DISABLED", message: "实时画布功能未开启" }, { status: 403 } ); } const falApiKey = String( config.falApiKey || config.apiKey || angleEditConfig.falApiKey || process.env.FAL_KEY || process.env.FAL_API_KEY || "" ).trim(); if (!falApiKey) { return Response.json( { code: "FAL_KEY_MISSING", message: "未配置实时画布 API Key(请在本地AI设置中配置)", }, { status: 500 } ); } const throttleInterval = clamp( Number(config.throttleInterval || defaultConfig.transport.throttleInterval), 60, 260 ); const maxBuffering = clamp( Number(config.maxBuffering || defaultConfig.transport.maxBuffering), 1, 6 ); const maxInputResolution = clamp( Number(config.maxInputResolution || defaultConfig.image.maxInputResolution), 512, 1536 ); const jpegQuality = clamp( Number(config.jpegQuality || defaultConfig.image.jpegQuality), 0.35, 0.82 ); const steps = clamp(Number(config.defaults?.steps || defaultConfig.model.defaults.steps), 1, 6); const scheduleMu = clamp( Number(config.defaults?.scheduleMu || defaultConfig.model.defaults.scheduleMu), 1.5, 3.5 ); const feedback = clamp( Number(config.defaults?.feedback || defaultConfig.model.defaults.feedback), 0.7, 1.0 ); const imageSize = config.defaults?.imageSize === "square_hd" ? "square_hd" : "square"; return Response.json({ ...defaultConfig, transport: { throttleInterval, maxBuffering, }, image: { maxInputResolution, jpegQuality, }, model: { ...defaultConfig.model, defaults: { steps, scheduleMu, feedback, imageSize, }, }, }); }