Your Name f6979f0196
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled
feat: 完善无限画布3D生成与实时画布能力
2026-02-28 22:33:16 +08:00

135 lines
4.1 KiB
TypeScript

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<string, unknown> {
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();
}
}