refactor: 专员目录收敛为 6 个,重整 AI 路由与系统管理页
一次性提交当天全部改动(110 个文件)。 **未按 TOP_CODING_RULES.md G14.5「一次提交只装一件事」拆分** —— 用户明确要求 单一提交,此处如实记录,不静默忽略该冲突。 提交前验证:后端 go build / go vet / go test ./... 全绿,前端 npm run build exit 0,/api/health 与管理员 login 均返回 200。 - 专员目录收敛为 6 个:下线 knowledge-operations / process-coordination / presentation-briefing / report-generation 四个专员(前后端 manifest 与 seed 同步删除),新增 general-assistant。专员的归属关系(拥有哪些技能定义、 哪些目录项、提示词与绑定从哪来)改由 specialists/core 的 ownership.go、 prompt_provider.go、binding_provider.go 统一提供,seed 与 admin_handlers 随之内置化,卸载路径统一走 uninstall.go。 - 技能:补齐 text-to-speech 的前端 manifest(后端包在 HEAD 已存在), skillcore/ownership.go 提供与专员对称的归属查询。 - AI 路由:ai_config.json 由 OpenRouter/Ollama 切到 LMUAI / SiliconFlow / llama.cpp 本地路由,ai_secrets.example.json 与部署 env 样例同步新增 SILICONFLOW_API_KEY。 - 系统管理页重整:新增 AiAdminPage、OrganizationManagementPage,删除 AdminOverviewPage、CompanyConfigPage,SystemConfigPage 精简,nav / router / config/workbench.js 同步调整。依 G05.5,开发阶段直接收口到新结构,不留旧路由。 - 新增 internal/objectrefs:统一统计对象(专员 / 技能 / xapp)的运行时引用 (被多少 xapp、项目、任务引用),供管理页做删除前的影响面判断。 - 公众号创作专员:新增 OfficialAccountSpecialistPanel,workflow 与投递链路调整。 - XApp:考试 / 培训 Shell 扩展,XAppDirectoryPage 与 xappDefinition 同步。 - 文档:新增 GW01–GW05 工作台演进系列与 AR12 对话驱动与结构化交互架构; 同步 AR05 / SY17 / SY23 / SY25 / PL04;TOP_CODING_RULES.md 增补 G05.5。 Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -1,40 +1,95 @@
|
||||
const GENERIC_ROUTE_NAMES = new Set([
|
||||
'默认',
|
||||
'均衡',
|
||||
'全能',
|
||||
'推理',
|
||||
'本地',
|
||||
'快聊',
|
||||
'绘图',
|
||||
'OpenRouter',
|
||||
'OpenAI',
|
||||
'Ollama',
|
||||
])
|
||||
|
||||
function normalizeProviderLabel(provider) {
|
||||
const value = String(provider || '').trim().toLowerCase()
|
||||
if (!value) return ''
|
||||
if (value === 'ollama') return 'Ollama'
|
||||
if (value === 'llamacpp') return 'llama.cpp'
|
||||
if (value === 'lmuai') return 'LMUAI'
|
||||
if (value === 'siliconflow') return 'SiliconFlow'
|
||||
if (value === 'openrouter') return 'OpenRouter'
|
||||
if (value === 'openai') return 'OpenAI'
|
||||
return provider
|
||||
}
|
||||
|
||||
function normalizeModelLabel(model) {
|
||||
return String(model || '')
|
||||
.trim()
|
||||
.split('/')
|
||||
.pop()
|
||||
.replace(/text-embedding-3-small/gi, 'text-embedding-3-small')
|
||||
.replace(/deepseek-v4-flash-0731/gi, 'DeepSeek V4 Flash 0731')
|
||||
.replace(/deepseek-v4-flash/gi, 'DeepSeek V4 Flash')
|
||||
.replace(/deepseek-v3.2/gi, 'DeepSeek V3.2')
|
||||
.replace(/deepseek-flash/gi, 'DeepSeek Flash')
|
||||
.replace(/gpt-5.4-image-2/gi, 'GPT 5.4 Image 2')
|
||||
.replace(/gpt-5.4/gi, 'GPT 5.4')
|
||||
.replace(/grok-4.20/gi, 'Grok 4.20')
|
||||
.replace(/qwen3\.5-4b-q4_k_m\.gguf/gi, 'Qwen3.5 4B')
|
||||
.replace(/qwen2.5:7b/gi, 'Qwen2.5 7B')
|
||||
.replace(/bge-m3/gi, 'BGE-M3')
|
||||
.replace(/llava/gi, 'LLaVA')
|
||||
.replace(/flux-1.1-pro/gi, 'FLUX 1.1 Pro')
|
||||
.trim()
|
||||
}
|
||||
|
||||
function routeUsageLabel(aiRoute) {
|
||||
const routeId = String(aiRoute?.ai_route_id || '').trim()
|
||||
if (routeId === 'chat_route_ollama_qwen') return '本地对话'
|
||||
if (routeId === 'chat_route_ollama_qwen_fast') return '本地快聊'
|
||||
if (routeId === 'embed_route_ollama_bge_m3') return '本地向量'
|
||||
|
||||
const shortRouteName = String(aiRoute?.short_route_name || '').trim()
|
||||
if (!shortRouteName || GENERIC_ROUTE_NAMES.has(shortRouteName)) return ''
|
||||
return shortRouteName
|
||||
}
|
||||
|
||||
function routeModelLabel(aiRoute) {
|
||||
const fromModel = normalizeModelLabel(aiRoute?.model)
|
||||
if (fromModel) return fromModel
|
||||
return normalizeModelLabel(aiRoute?.short_model_name)
|
||||
}
|
||||
|
||||
export function formatAiRouteShortLabel(aiRoute) {
|
||||
if (!aiRoute) return '未设置'
|
||||
if (aiRoute.ai_route_id === 'chat_route_auto' || aiRoute.ai_route_id === 'embed_route_auto') {
|
||||
return '自动'
|
||||
}
|
||||
|
||||
const shortRouteName = (aiRoute.short_route_name || '').trim()
|
||||
const shortModelName = (aiRoute.short_model_name || '').trim()
|
||||
if (shortRouteName && shortModelName) {
|
||||
return `${shortRouteName}/${shortModelName}`
|
||||
}
|
||||
if (shortModelName) return shortModelName
|
||||
if (shortRouteName) return shortRouteName
|
||||
|
||||
const model = (aiRoute.model || '').split('/').pop() || ''
|
||||
const modelShort = model
|
||||
.replace(/text-embedding-3-small/gi, 'Emb3')
|
||||
.replace(/deepseek-v4-flash/gi, 'DS4F')
|
||||
.replace(/deepseek-v3.2/gi, 'DSV3')
|
||||
.replace(/gpt-5.4-image-2/gi, 'G图2')
|
||||
.replace(/gpt-5.4/gi, 'GPT5')
|
||||
.replace(/grok-4.20/gi, 'Grok4')
|
||||
.replace(/qwen2.5:7b/gi, 'Qwen')
|
||||
.replace(/bge-m3/gi, 'BGE')
|
||||
.trim()
|
||||
|
||||
return modelShort || aiRoute.description || aiRoute.ai_route_id || '未设置'
|
||||
const usage = routeUsageLabel(aiRoute)
|
||||
const model = routeModelLabel(aiRoute)
|
||||
if (usage && model) return `${usage} · ${model}`
|
||||
if (model) return model
|
||||
if (usage) return usage
|
||||
return aiRoute.description || aiRoute.ai_route_id || '未设置'
|
||||
}
|
||||
|
||||
export function formatAiRouteTitle(aiRoute) {
|
||||
if (!aiRoute) return '未设置'
|
||||
const provider = normalizeProviderLabel(aiRoute.provider)
|
||||
const model = routeModelLabel(aiRoute)
|
||||
|
||||
if (aiRoute.ai_route_id === 'chat_route_auto' || aiRoute.ai_route_id === 'embed_route_auto') {
|
||||
const detail = [provider, model].filter(Boolean).join(' / ')
|
||||
const resolved = aiRoute.resolved_ai_route_id || ''
|
||||
const detail = aiRoute.description || resolved || '自动选择当前最优可用模型'
|
||||
return `自动 · ${detail}`
|
||||
const suffix = detail || resolved || '自动选择当前最优可用模型'
|
||||
return `自动 · 当前 ${suffix}`
|
||||
}
|
||||
const shortLabel = formatAiRouteShortLabel(aiRoute)
|
||||
const detail = aiRoute.description || [aiRoute.provider, aiRoute.model].filter(Boolean).join(' / ') || aiRoute.ai_route_id
|
||||
return shortLabel === detail ? detail : `${shortLabel} · ${detail}`
|
||||
|
||||
const usage = routeUsageLabel(aiRoute)
|
||||
if (usage && provider && model) return `${usage} · ${provider} / ${model}`
|
||||
if (usage && model) return `${usage} · ${model}`
|
||||
if (provider && model) return `${model} · ${provider}`
|
||||
return aiRoute.description || aiRoute.ai_route_id || '未设置'
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user