509 lines
13 KiB
Markdown
509 lines
13 KiB
Markdown
---
|
||
belongs_to:
|
||
- "[[INDEX · 铸渊·协作指令|GitHub ↔ Notion 桥接协议]]"
|
||
---
|
||
# 🎨 铸渊指令|正式站UI全屏适配 + 智能模型路由 + 开发者编号免配置登录(ZY-UIROUTER-2026-0325-001)· 冰朔直签
|
||
|
||
<aside>
|
||
🔗
|
||
|
||
**指令编号**:ZY-UIROUTER-2026-0325-001
|
||
|
||
**签发人**:冰朔(TCS-0002∞)直签
|
||
|
||
**签发时间**:2026-03-25 16:00 CST
|
||
|
||
**优先级**:P0 · 正式站体验核心
|
||
|
||
**状态**:待铸渊执行
|
||
|
||
**部署规则**:冰朔直通(S5)· 执行完直接部署正式站
|
||
|
||
</aside>
|
||
|
||
<aside>
|
||
⚠️
|
||
|
||
**本指令涉及三个独立模块,按顺序执行:**
|
||
|
||
- Phase 1:UI 全屏响应式适配(电脑 + 手机双版本)
|
||
- Phase 2:智能模型路由(意图识别 → 自动选模型)
|
||
- Phase 3:开发者编号免配置登录(输编号直接进)
|
||
</aside>
|
||
|
||
---
|
||
|
||
## 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` 的 `<head>` 中确保有:
|
||
|
||
```html
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
|
||
```
|
||
|
||
### 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 安全要点
|
||
|
||
<aside>
|
||
🔒
|
||
|
||
1. **API Key 永远不发给前端** — 所有 API 调用由后端代理
|
||
2. **开发者只用编号登录** — 不接触任何密钥
|
||
3. **会话 token 有效期 24h** — 过期重新输入编号
|
||
4. **每次登录写审计日志** — 谁、什么时候、从哪登的
|
||
5. **团队 API Key 存服务器环境变量** — `TEAM_API_KEY`
|
||
</aside>
|
||
|
||
### 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 ← 响应式样式表
|
||
```
|
||
|
||
---
|
||
|
||
## 执行顺序
|
||
|
||
<aside>
|
||
📋
|
||
|
||
**Phase 1(UI适配)→ Phase 2(智能路由)→ Phase 3(免配置登录)**
|
||
|
||
三个 Phase 可以并行开发,但部署顺序按上述。
|
||
|
||
完成后直接部署正式站(冰朔直通 S5 生效)。
|
||
|
||
</aside>
|
||
|
||
---
|
||
|
||
## 回执要求
|
||
|
||
```
|
||
[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
|
||
> |