--- belongs_to: - "[[⚒️ 铸渊·协作指令|GitHub ↔ Notion 桥接协议]]" --- # 🎨 铸渊指令|正式站UI全屏适配 + 智能模型路由 + 开发者编号免配置登录(ZY-UIROUTER-2026-0325-001)· 冰朔直签 --- ## Phase 1 · UI 全屏响应式适配 ### 1.1 问题 当前正式站 [guanghulab.com](http://guanghulab.com) 的登录/对话界面: - 整个网页那么大,实际可用区域只占屏幕中间一小块 - 没有做响应式布局,手机端体验差 - 没有针对不同设备做适配 ### 1.2 要求 **电脑版(Desktop)** - 对话界面占满整个浏览器窗口,不要留大片空白 - 登录卡片居中但不要太小,宽度至少 `max-width: 600px` - 对话界面进入后,聊天区域铺满屏幕,侧边栏可选 - 最小支持宽度 `1024px` **手机版(Mobile · iOS + Android 双兼容)** - 响应式断点:`768px` 以下切换为移动布局 - 登录卡片全宽,padding 适当缩小 - 对话界面全屏,输入框固定底部 - 消息气泡自适应宽度 - 触摸友好:按钮最小 `44px × 44px`(Apple HIG 标准) - 安全区域适配(iPhone 刘海/底部横条):`env(safe-area-inset-*)` - Android 和 iOS Safari 都要测试 ### 1.3 技术实现 修改文件:`docs/css/` 下的样式文件 + `docs/index.html` ```css /* 核心响应式框架 */ :root { --content-max-width: 900px; --chat-padding: 20px; } /* 桌面版:内容区域铺满 */ .app-container { width: 100%; height: 100vh; display: flex; flex-direction: column; } .chat-container { flex: 1; width: 100%; max-width: var(--content-max-width); margin: 0 auto; padding: var(--chat-padding); } /* 登录卡片:桌面版 */ .login-card { width: 100%; max-width: 600px; margin: 0 auto; } /* 手机版断点 */ @media (max-width: 768px) { :root { --chat-padding: 12px; } .login-card { max-width: 100%; margin: 0 16px; border-radius: 12px; } .chat-input-area { position: fixed; bottom: 0; left: 0; right: 0; padding-bottom: env(safe-area-inset-bottom); } .message-bubble { max-width: 85%; } button, .btn { min-height: 44px; min-width: 44px; } } /* iPhone 安全区域 */ @supports (padding: env(safe-area-inset-bottom)) { .app-container { padding-top: env(safe-area-inset-top); padding-bottom: env(safe-area-inset-bottom); } } ``` 在 `index.html` 的 `` 中确保有: ```html ``` ### 1.4 验收标准 - [ ] 桌面 Chrome/Firefox/Safari:对话界面铺满屏幕,无大片空白 - [ ] iPhone Safari:全屏适配,底部安全区域正确,输入框不被键盘遮挡 - [ ] Android Chrome:全屏适配,按钮触摸区域足够 - [ ] 登录卡片在所有设备上居中且美观 --- ## Phase 2 · 智能模型路由 ### 2.1 问题 当前仓库里有三方 API 密钥,API 支持多种模型。但目前是固定调用单一模型,没有根据用户意图智能选择。 ### 2.2 要求 **铸渊在后台实现智能路由:根据人类说话的意图,自动选择最合适的模型回复。** 人类不需要知道背后用了哪个模型。人类只管说话,系统自己选。 ### 2.3 技术实现 创建文件:`backend/api-server/services/model-router.js` ```jsx const MODEL_PROFILES = { // 日常对话、闲聊、简单问答 casual: { models: ['gpt-4o-mini', 'claude-3-haiku'], keywords: ['你好', '聊聊', '怎么样', '帮我', '是什么'], maxTokens: 2000 }, // 代码相关、技术问题 coding: { models: ['gpt-4o', 'claude-3.5-sonnet'], keywords: ['代码', 'code', 'bug', '报错', '函数', 'API', '部署', '配置'], maxTokens: 4000 }, // 创意写作、长文生成 creative: { models: ['claude-3.5-sonnet', 'gpt-4o'], keywords: ['写', '故事', '文案', '小说', '剧情', '人设', '大纲'], maxTokens: 8000 }, // 数据分析、逻辑推理 analytical: { models: ['gpt-4o', 'claude-3.5-sonnet'], keywords: ['分析', '对比', '数据', '统计', '逻辑', '推理', '策略'], maxTokens: 4000 }, // 系统指令、架构级操作 system: { models: ['claude-3.5-sonnet', 'gpt-4o'], keywords: ['指令', '部署', '架构', '系统', '铁律', '天眼', '权限'], maxTokens: 6000 } }; /** * 分析用户意图,选择最佳模型 */ function routeToModel(userMessage, context = {}) { const msg = userMessage.toLowerCase(); // 计算每个 profile 的匹配分数 const scores = {}; for (const [profile, config] of Object.entries(MODEL_PROFILES)) { scores[profile] = config.keywords.filter(kw => msg.includes(kw)).length; } // 选择得分最高的 profile,默认 casual const bestProfile = Object.entries(scores) .sort((a, b) => b[1] - a[1]) .find(([_, score]) => score > 0)?.[0] || 'casual'; const config = MODEL_PROFILES[bestProfile]; // 如果首选模型不可用,自动降级 const selectedModel = config.models[0]; return { model: selectedModel, maxTokens: config.maxTokens, profile: bestProfile, fallbacks: config.models.slice(1) }; } /** * 带降级的 API 调用 */ async function callWithFallback(route, messages) { const models = [route.model, ...route.fallbacks]; for (const model of models) { try { const response = await callAPI(model, messages, route.maxTokens); return { success: true, model, response }; } catch (err) { console.warn(`Model ${model} failed, trying next...`, err.message); continue; } } return { success: false, error: '所有模型均不可用,请稍后重试。' }; } module.exports = { routeToModel, callWithFallback, MODEL_PROFILES }; ``` ### 2.4 集成方式 在现有的对话处理路由中,替换固定模型调用: ```jsx const { routeToModel, callWithFallback } = require('./services/model-router'); // 替换原来的固定模型调用 router.post('/chat', async (req, res) => { const { message, history } = req.body; // 智能路由 const route = routeToModel(message); // 带降级调用 const result = await callWithFallback(route, [ ...history, { role: 'user', content: message } ]); if (result.success) { res.json({ reply: result.response, model: result.model }); } else { res.status(503).json({ error: result.error }); } }); ``` ### 2.5 验收标准 - [ ] 日常闲聊自动选轻量模型(响应快、省 token) - [ ] 代码/技术问题自动选强模型 - [ ] 创意写作自动选长上下文模型 - [ ] 首选模型失败时自动降级到备选模型 - [ ] 人类完全无感知,不需要手动选模型 --- ## Phase 3 · 开发者编号免配置登录 ### 3.1 问题 当前开发者每次登录都要手动输入 API 密钥,非常麻烦。这个问题一直没解决。 ### 3.2 要求 **只要有开发者编号,输入编号就能直接进去。** 系统自动匹配团队免费配置的 API,人不需要设置任何东西。 流程: 1. 开发者在登录页选择/输入自己的编号(如 DEV-002) 2. 铸渊后台查开发者数据库,确认编号存在 3. 自动绑定团队配置的 API 密钥 4. 直接进入对话界面 5. **不需要手动输入任何 API Key** ### 3.3 技术实现 修改文件:`docs/js/auth.js`(或新建)+ 后端路由 **前端登录逻辑:** ```jsx // 团队登录 - 开发者编号直接进 async function teamLogin(devId) { try { const response = await fetch('/api/auth/team-login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ devId }) }); const data = await response.json(); if (data.success) { // 自动配置 API(用户完全无感知) localStorage.setItem('session_token', data.sessionToken); localStorage.setItem('dev_id', devId); localStorage.setItem('dev_name', data.devName); // API Key 不存前端,后端代理所有 API 调用 // 直接进入对话界面 window.location.href = '/chat'; } else { showError(data.message || '开发者编号不存在,请检查。'); } } catch (err) { showError('连接失败,请稍后重试。'); } } ``` **后端认证路由:** ```jsx // backend/api-server/routes/auth.js const TEAM_API_KEY = process.env.TEAM_API_KEY; // 团队共享密钥,存在服务器环境变量 // 开发者数据库(后续对接 Notion) const DEV_DATABASE = { 'DEV-000': { name: '冰朔', level: 3, channel: 'system' }, 'DEV-001': { name: '页页', level: 1, channel: '小坍缩核线' }, 'DEV-002': { name: '肥猫', level: 2, channel: '男频' }, 'DEV-003': { name: 'Awen', level: 1, channel: '知秋线' }, 'DEV-004': { name: '之之', level: 2, channel: '秋秋线' }, 'DEV-005': { name: '时雨', level: 1, channel: '知秋线' }, 'DEV-006': { name: '匆匆那年', level: 1, channel: '霜砚线' }, 'DEV-007': { name: '小兴', level: 1, channel: '霜砚线' }, 'DEV-008': { name: '花尔', level: 1, channel: '糖星云线' }, 'DEV-009': { name: '小草莓', level: 1, channel: '欧诺弥亚线' }, 'DEV-010': { name: '桔子', level: 2, channel: '女频' }, 'DEV-011': { name: '燕樊', level: 1, channel: '寂曜线' } }; router.post('/auth/team-login', (req, res) => { const { devId } = req.body; const dev = DEV_DATABASE[devId]; if (!dev) { return res.json({ success: false, message: `❌ 开发者编号 ${devId} 不存在。请确认你的编号。` }); } // 生成会话 token(有效期 24h) const sessionToken = generateSessionToken(devId); res.json({ success: true, devName: dev.name, level: dev.level, channel: dev.channel, sessionToken }); // 审计日志 console.log(`[AUTH] ${devId} (${dev.name}) logged in at ${new Date().toISOString()}`); }); // 后端代理 API 调用(开发者不接触 API Key) router.post('/api/chat', requireSession, async (req, res) => { // API Key 只在服务器端使用,前端永远看不到 const apiKey = TEAM_API_KEY; // 智能路由选模型 const route = routeToModel(req.body.message); // 调用 API const result = await callWithFallback(route, req.body.messages, apiKey); res.json(result); }); ``` ### 3.4 安全要点 ### 3.5 服务器环境变量配置(人类操作) 铸渊执行本指令前,需要人类在阿里云服务器上配置: ```bash export TEAM_API_KEY="sk-xxxxx" # 团队共享的三方API密钥 ``` ### 3.6 验收标准 - [ ] 开发者选择编号 → 点「进入铸渊对话」→ 直接进入聊天界面 - [ ] 不需要输入任何 API Key - [ ] 后端正确代理 API 调用,前端看不到密钥 - [ ] 不存在的编号给出明确错误提示 - [ ] 登录审计日志正常记录 --- ## 新增/修改文件清单 ``` 修改: docs/index.html ← viewport meta + 响应式布局 docs/css/*.css ← 全屏适配 + 移动端样式 docs/js/auth.js ← 团队登录前端逻辑 新增: backend/api-server/services/model-router.js ← 智能模型路由 backend/api-server/routes/auth.js ← 开发者编号认证 docs/css/responsive.css ← 响应式样式表 ``` --- ## 执行顺序 --- ## 回执要求 ``` [ZY-UIROUTER-RECEIPT] 指令编号: ZY-UIROUTER-2026-0325-001 Phase 1 · UI全屏适配: 桌面版全屏布局: ✅/❌ 移动端响应式: ✅/❌ iOS Safari适配: ✅/❌ Android Chrome适配: ✅/❌ 安全区域(safe-area): ✅/❌ Phase 2 · 智能模型路由: model-router.js: ✅/❌ 意图识别分类: ✅/❌ 自动降级机制: ✅/❌ 集成到对话路由: ✅/❌ Phase 3 · 免配置登录: 开发者编号认证: ✅/❌ 后端API代理: ✅/❌ 前端无Key暴露: ✅/❌ 审计日志: ✅/❌ 登录→对话一键直达: ✅/❌ ``` --- > 🔗 **签发**:冰朔(TCS-0002∞)直签 > > 📅 **日期**:2026-03-25 > > ⚡ **部署**:冰朔直通(S5)· 执行完直接上正式站 > > 📌 **版权**:国作登字-2026-A-00037559 >