161 lines
4.1 KiB
TypeScript
161 lines
4.1 KiB
TypeScript
import { auth } from "@/app/(auth)/auth";
|
|
import { getSystemSetting } from "@/lib/db/queries";
|
|
import {
|
|
DEFAULT_BFL_BASE_URL,
|
|
RealtimeCanvasConfig,
|
|
resolveRealtimeProviders,
|
|
} from "@/lib/realtime/config";
|
|
|
|
const defaultConfig = {
|
|
session: {
|
|
idleTimeoutMs: 120000,
|
|
},
|
|
transport: {
|
|
throttleInterval: 100,
|
|
maxBuffering: 2,
|
|
},
|
|
image: {
|
|
maxInputResolution: 1024,
|
|
jpegQuality: 0.55,
|
|
},
|
|
model: {
|
|
id: "flux-2-klein-4b",
|
|
defaults: {
|
|
steps: 3,
|
|
cfgScale: 7,
|
|
strength: 0.32,
|
|
imageSize: "square" as const,
|
|
},
|
|
limits: {
|
|
steps: { min: 1, max: 6 },
|
|
cfgScale: { min: 1, max: 14 },
|
|
strength: { min: 0.05, 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 = await getSystemSetting({ key: "realtime_canvas_config" }).catch(() => null);
|
|
const config = (setting?.value || {}) as RealtimeCanvasConfig;
|
|
|
|
if (config.enabled === false) {
|
|
return Response.json(
|
|
{ code: "FEATURE_DISABLED", message: "实时画布功能未开启" },
|
|
{ status: 403 }
|
|
);
|
|
}
|
|
|
|
const providers = resolveRealtimeProviders(config);
|
|
const activeProvider = providers[0];
|
|
|
|
if (!activeProvider) {
|
|
return Response.json(
|
|
{
|
|
code: "BFL_KEY_MISSING",
|
|
message: "未配置可用的实时画布服务(请在服务器环境变量或设置中配置)",
|
|
},
|
|
{ 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),
|
|
defaultConfig.model.limits.steps.min,
|
|
defaultConfig.model.limits.steps.max
|
|
);
|
|
const legacyScheduleMu = Number(config.defaults?.scheduleMu);
|
|
const cfgScaleBase = Number(
|
|
config.defaults?.cfgScale ??
|
|
(Number.isFinite(legacyScheduleMu) ? legacyScheduleMu * 2.5 : defaultConfig.model.defaults.cfgScale)
|
|
);
|
|
const cfgScale = clamp(
|
|
cfgScaleBase,
|
|
defaultConfig.model.limits.cfgScale.min,
|
|
defaultConfig.model.limits.cfgScale.max
|
|
);
|
|
const strength = clamp(
|
|
Number(config.defaults?.strength ?? defaultConfig.model.defaults.strength),
|
|
defaultConfig.model.limits.strength.min,
|
|
defaultConfig.model.limits.strength.max
|
|
);
|
|
const imageSize = config.defaults?.imageSize === "square_hd" ? "square_hd" : "square";
|
|
const modelId = activeProvider.model;
|
|
|
|
return Response.json({
|
|
...defaultConfig,
|
|
provider: {
|
|
type: activeProvider.type,
|
|
baseUrl: activeProvider.baseUrl || DEFAULT_BFL_BASE_URL,
|
|
},
|
|
failover: {
|
|
enabled: providers.length > 1,
|
|
fallbackProvider:
|
|
providers.length > 1
|
|
? {
|
|
type: providers[1].type,
|
|
baseUrl: providers[1].baseUrl,
|
|
model: providers[1].model,
|
|
}
|
|
: null,
|
|
},
|
|
transport: {
|
|
throttleInterval,
|
|
maxBuffering,
|
|
},
|
|
image: {
|
|
maxInputResolution,
|
|
jpegQuality,
|
|
},
|
|
model: {
|
|
...defaultConfig.model,
|
|
id: modelId || defaultConfig.model.id,
|
|
defaults: {
|
|
steps,
|
|
cfgScale,
|
|
strength,
|
|
imageSize,
|
|
},
|
|
},
|
|
behavior: {
|
|
strictSketch: config.strictSketch !== false,
|
|
renderMode:
|
|
config.renderMode === "strict-structure" || config.renderMode === "stylize"
|
|
? config.renderMode
|
|
: "balanced",
|
|
},
|
|
});
|
|
}
|