ai-chatbot/lib/model3d/model-alias-config.ts
Your Name 2561c66cb8
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled
feat: update workflow categories and admin notifications
2026-05-07 19:31:14 +08:00

346 lines
8.9 KiB
TypeScript

export const THREED_MODEL_ALIAS_CONFIG_SETTING_KEY = "threed_model_alias_config";
export type ThreeDModelAliasEntry = {
id: string;
displayName: string;
realModelId: string;
description: string;
enabled: boolean;
isDefault: boolean;
};
export type ThreeDModelAliasConfig = {
tripoModels: ThreeDModelAliasEntry[];
worldModels: ThreeDModelAliasEntry[];
};
export type PublicThreeDModelAliasEntry = Omit<
ThreeDModelAliasEntry,
"realModelId"
> & {
billingModelId?: string;
};
export type PublicThreeDModelAliasConfig = {
tripoModels: PublicThreeDModelAliasEntry[];
worldModels: PublicThreeDModelAliasEntry[];
};
const DEFAULT_TRIPO_MODEL_ALIASES: ThreeDModelAliasEntry[] = [
{
id: "tripo-standard",
displayName: "标准模型",
realModelId: "Turbo-v1.0-20250506",
description: "默认高速高质量模型,适合大多数 3D 生成场景。",
enabled: true,
isDefault: true,
},
{
id: "tripo-detail",
displayName: "高精模型",
realModelId: "v3.1-20260211",
description: "偏向细节质量和结构还原,适合高要求模型生成。",
enabled: true,
isDefault: false,
},
{
id: "tripo-balance",
displayName: "均衡模型",
realModelId: "v3.0-20250812",
description: "速度与质量更均衡,适合日常生产。",
enabled: true,
isDefault: false,
},
{
id: "tripo-classic",
displayName: "经典模型",
realModelId: "v2.5-20250123",
description: "兼顾稳定性与兼容性,适合保守方案。",
enabled: true,
isDefault: false,
},
{
id: "tripo-stable",
displayName: "稳定模型",
realModelId: "v2.0-20240919",
description: "老版本稳定模型,适合兼容历史流程。",
enabled: true,
isDefault: false,
},
{
id: "tripo-legacy",
displayName: "兼容模型",
realModelId: "v1.4-20240625",
description: "更旧的兼容模型,适合特定老任务回放。",
enabled: true,
isDefault: false,
},
];
const DEFAULT_WORLD_MODEL_ALIASES: ThreeDModelAliasEntry[] = [
{
id: "world-standard",
displayName: "标准质量",
realModelId: "marble-1.1",
description: "默认世界生成质量,适合大多数空间创建。",
enabled: true,
isDefault: true,
},
{
id: "world-fidelity",
displayName: "高保真",
realModelId: "marble-1.1-plus",
description: "更高保真与细节表现,适合高质量空间生成。",
enabled: true,
isDefault: false,
},
{
id: "world-compatible",
displayName: "兼容质量",
realModelId: "marble-1.0",
description: "兼容旧版世界任务和历史工作流。",
enabled: true,
isDefault: false,
},
{
id: "world-draft",
displayName: "快速草稿",
realModelId: "marble-1.0-draft",
description: "更适合快速预览与草稿生成。",
enabled: true,
isDefault: false,
},
];
function sanitizeText(value: unknown) {
return String(value || "").trim();
}
function cloneEntries(entries: ThreeDModelAliasEntry[]) {
return entries.map((entry) => ({ ...entry }));
}
function normalizeEntry(
value: unknown,
index: number,
defaults: ThreeDModelAliasEntry[],
prefix: string,
): ThreeDModelAliasEntry {
const fallback = defaults[index] || defaults[0];
const hasRawObject =
value && typeof value === "object" && !Array.isArray(value);
const raw = hasRawObject ? (value as Record<string, unknown>) : {};
return {
id: sanitizeText(raw.id) || fallback?.id || `${prefix}-${index + 1}`,
displayName: hasRawObject
? sanitizeText(raw.displayName)
: fallback?.displayName || "",
realModelId: hasRawObject
? sanitizeText(raw.realModelId || raw.modelId)
: fallback?.realModelId || "",
description: hasRawObject
? sanitizeText(raw.description)
: fallback?.description || "",
enabled:
typeof raw.enabled === "boolean"
? raw.enabled
: fallback?.enabled !== false,
isDefault:
typeof raw.isDefault === "boolean" ? raw.isDefault : fallback?.isDefault === true,
};
}
function finalizeEntries(
entries: ThreeDModelAliasEntry[],
defaults: ThreeDModelAliasEntry[],
) {
const nextEntries =
entries.length > 0 ? cloneEntries(entries) : cloneEntries(defaults);
const usedIds = new Set<string>();
nextEntries.forEach((entry, index) => {
let nextId = sanitizeText(entry.id) || `${defaults[0]?.id || "model"}-${index + 1}`;
while (usedIds.has(nextId)) {
nextId = `${nextId}-${index + 1}`;
}
entry.id = nextId;
usedIds.add(nextId);
});
const enabledIndex = nextEntries.findIndex((entry) => entry.enabled);
const defaultEnabledIndex = nextEntries.findIndex(
(entry) => entry.enabled && entry.isDefault,
);
const targetDefaultIndex =
defaultEnabledIndex >= 0 ? defaultEnabledIndex : enabledIndex >= 0 ? enabledIndex : 0;
return nextEntries.map((entry, index) => ({
...entry,
isDefault: index === targetDefaultIndex,
}));
}
function normalizeEntryList(
value: unknown,
defaults: ThreeDModelAliasEntry[],
prefix: string,
) {
if (!Array.isArray(value) || value.length === 0) {
return cloneEntries(defaults);
}
return finalizeEntries(
value.map((item, index) => normalizeEntry(item, index, defaults, prefix)),
defaults,
);
}
export function defaultThreeDModelAliasConfig(): ThreeDModelAliasConfig {
return {
tripoModels: cloneEntries(DEFAULT_TRIPO_MODEL_ALIASES),
worldModels: cloneEntries(DEFAULT_WORLD_MODEL_ALIASES),
};
}
export function normalizeThreeDModelAliasConfig(
value: unknown,
): ThreeDModelAliasConfig {
const raw =
value && typeof value === "object" && !Array.isArray(value)
? (value as Record<string, unknown>)
: {};
return {
tripoModels: normalizeEntryList(
raw.tripoModels,
DEFAULT_TRIPO_MODEL_ALIASES,
"tripo-model",
),
worldModels: normalizeEntryList(
raw.worldModels,
DEFAULT_WORLD_MODEL_ALIASES,
"world-model",
),
};
}
export function toPublicThreeDModelAliasConfig(
config: ThreeDModelAliasConfig,
): PublicThreeDModelAliasConfig {
return {
tripoModels: config.tripoModels.map(({ realModelId: _realModelId, ...entry }) => ({
...entry,
})),
worldModels: config.worldModels.map(({ realModelId, ...entry }) => ({
...entry,
billingModelId: realModelId,
})),
};
}
export const DEFAULT_PUBLIC_THREED_MODEL_ALIAS_CONFIG =
toPublicThreeDModelAliasConfig(defaultThreeDModelAliasConfig());
function findEntryByValue<
T extends {
id: string;
displayName: string;
realModelId?: string;
billingModelId?: string;
},
>(entries: T[], value: unknown) {
const normalized = sanitizeText(value);
if (!normalized) return null;
return (
entries.find((entry) => sanitizeText(entry.id) === normalized) ||
entries.find(
(entry) =>
"realModelId" in entry && sanitizeText(entry.realModelId) === normalized,
) ||
entries.find(
(entry) =>
"billingModelId" in entry &&
sanitizeText(entry.billingModelId) === normalized,
) ||
entries.find((entry) => sanitizeText(entry.displayName) === normalized) ||
null
);
}
export function getDefaultThreeDModelAliasId(
entries: Array<{ id: string; enabled?: boolean; isDefault?: boolean }>,
) {
const enabledEntries = entries.filter((entry) => entry.enabled !== false);
const defaultEntry =
enabledEntries.find((entry) => entry.isDefault) || enabledEntries[0] || entries[0];
return sanitizeText(defaultEntry?.id) || "";
}
export function resolveThreeDModelRealId(
value: unknown,
entries: ThreeDModelAliasEntry[],
) {
const match = findEntryByValue(entries, value);
if (match?.realModelId) {
return sanitizeText(match.realModelId);
}
const normalized = sanitizeText(value);
if (normalized) {
return normalized;
}
const fallbackEntry =
entries.find((entry) => entry.enabled && entry.isDefault) ||
entries.find((entry) => entry.enabled) ||
entries[0];
return sanitizeText(fallbackEntry?.realModelId);
}
export function resolveThreeDModelAliasId(
value: unknown,
entries: ThreeDModelAliasEntry[],
) {
const match = findEntryByValue(entries, value);
if (match?.id) {
return sanitizeText(match.id);
}
return sanitizeText(value);
}
export function resolveThreeDModelBillingId<
T extends {
id: string;
displayName: string;
realModelId?: string;
billingModelId?: string;
},
>(value: unknown, entries: T[]) {
const match = findEntryByValue(entries, value);
return sanitizeText(match?.billingModelId || match?.realModelId || value);
}
export function resolveThreeDModelDisplayName<
T extends {
id: string;
displayName: string;
realModelId?: string;
billingModelId?: string;
},
>(
value: unknown,
entries: T[],
fallback = "",
) {
const match = findEntryByValue(entries, value);
if (match?.displayName) {
return sanitizeText(match.displayName);
}
const normalized = sanitizeText(value);
return normalized || fallback;
}