316 lines
8.3 KiB
TypeScript
316 lines
8.3 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"
|
|
>;
|
|
|
|
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: _realModelId, ...entry }) => ({
|
|
...entry,
|
|
})),
|
|
};
|
|
}
|
|
|
|
export const DEFAULT_PUBLIC_THREED_MODEL_ALIAS_CONFIG =
|
|
toPublicThreeDModelAliasConfig(defaultThreeDModelAliasConfig());
|
|
|
|
function findEntryByValue<
|
|
T extends { id: string; displayName: string; realModelId?: 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) => 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 resolveThreeDModelDisplayName<
|
|
T extends { id: string; displayName: string; realModelId?: 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;
|
|
}
|