import { normalizePublishedPageSlug } from 'soma-core'; const PHRASE_ALIASES: ReadonlyArray = [ [/我的工作台/u, 'myworkspace'], [/个人工作台/u, 'myworkspace'], [/供应链/u, 'supply-chain'], [/驾驶舱/u, 'dashboard'], [/仪表盘/u, 'dashboard'], [/工作台/u, 'workspace'], [/订单/u, 'orders'], [/客户/u, 'customers'], [/销售/u, 'sales'], [/运营/u, 'operations'], [/风险/u, 'risk'], [/项目/u, 'projects'], [/任务/u, 'tasks'], ]; const GENERIC_LATIN_WORDS = new Set([ 'a', 'an', 'the', 'page', 'build', 'create', 'generate', 'generated', 'new', ]); function stableHash(value: string): string { let hash = 2166136261; for (const char of value) { hash ^= char.codePointAt(0) ?? 0; hash = Math.imul(hash, 16777619); } return (hash >>> 0).toString(36); } function explicitPath(source: string): string | null { const match = source.match(/(?:^|[\s::,,((])\/([a-zA-Z0-9][a-zA-Z0-9_-]{0,63})(?=$|[\s,,。.!!??))])/u); return normalizePublishedPageSlug(match?.[1]); } function semanticChineseSlug(source: string): string | null { const exact = PHRASE_ALIASES.find(([pattern]) => pattern.test(source)); if (exact?.[1] === 'myworkspace') return exact[1]; const matches = PHRASE_ALIASES .map(([pattern, value]) => ({ index: source.search(pattern), value })) .filter((item) => item.index >= 0) .sort((left, right) => left.index - right.index); const parts: string[] = []; for (const { value } of matches) { if (!parts.includes(value)) parts.push(value); } return normalizePublishedPageSlug(parts.join('-')); } function latinSlug(source: string): string | null { const words = source.toLowerCase().match(/[a-z0-9]+/g) ?? []; const meaningful = words.filter((word) => !GENERIC_LATIN_WORDS.has(word)); return normalizePublishedPageSlug(meaningful.slice(0, 6).join('-')); } /** * 为页面蓝图补齐稳定公开身份。模型负责语义命名;显式路径、常用中文语义和 * 稳定 hash 是防止旧模型/降级输出漏 slug 时退回同一个固定页面的三层兜底。 */ export function resolvePageSlug(input: { candidate?: unknown; baseSlug?: unknown; title?: unknown; requirement?: unknown; }): string { for (const candidate of [input.candidate, input.baseSlug]) { const normalized = normalizePublishedPageSlug(candidate); if (normalized) return normalized; } const source = [input.requirement, input.title] .filter((value): value is string => typeof value === 'string' && value.trim() !== '') .join(' ') .trim(); return explicitPath(source) ?? semanticChineseSlug(source) ?? latinSlug(source) ?? `page-${stableHash(source || 'soma-page')}`; }