# 万川 AI 平台:从账号密码登录到获取模型信息 > 本文基于当前未提交的代码梳理,描述用户在「设置」页填入平台地址 + 账号密码后, > 系统如何登录、拉取模型配置并写入后端 AI 设置的完整链路。 ## 一、整体链路总览 ``` 用户填写平台地址 / 账号 / 密码 │ ▼ [1] POST /api/login ───────────────► 返回 token(缓存到 localStorage) │ ▼ [2] 登录成功后并行触发: ├─ GET /api/system/kb/relation/query 拉取岗位知识库列表 └─ syncModel() 同步模型配置 │ ▼ [3] 按模型编码 code 分别拉取(携带 token): ├─ GET /api/system/model/getByCode/generic 通用/聊天模型(必拉) ├─ GET /api/system/model/getByCode/vision 视觉模型(可选) └─ GET /api/system/model/getByCode/voice 语音模型(可选) │ ▼ [4] 解析 providerModels.encryptedConfig(JSON 字符串) → { modelName, apiKey, endpointUrl } │ ▼ [5] PUT /api/settings 写入后端 SQLite(app_settings 表) │ ▼ [6] 后端聊天/视觉/语音调用时按用途读取这些配置(带回退) ``` 前端实现:[chatlab-web/frontend/src/api/wanchuan.js](chatlab-web/frontend/src/api/wanchuan.js) 触发位置:[chatlab-web/frontend/src/pages/SettingsPage.jsx](chatlab-web/frontend/src/pages/SettingsPage.jsx) 后端设置:[chatlog_fastAPI/routers/settings.py](chatlog_fastAPI/routers/settings.py) --- ## 二、第 1 步:登录获取 token ### 接口 ``` POST {platformUrl}/api/login Content-Type: application/json;charset=UTF-8 ``` ### 请求体 ```json { "username": "用户名", "password": "密码", "loginType": "user" } ``` ### 响应(兼容多种结构) 代码用以下顺序提取 token,任一命中即可: ``` result.token result.data.token result.data.access_token result.access_token ``` 典型返回结构: ```json { "code": 200, "msg": "success", "token": "eyJhbGci...", "data": { "token": "eyJhbGci...", "modules": [ /* 平台模块列表,用于前端展示 */ ] } } ``` ### token 的存储与使用 - 登录成功后 token 写入 `localStorage`,key 为 `chatlab_wanchuan_token`。 - 后续所有平台接口都带两个头(平台同时认这两种): ``` Authorization: Bearer {token} token: Bearer {token} ``` 对应函数:`wanchuanLogin(baseUrl, username, password)` ([wanchuan.js:39](chatlab-web/frontend/src/api/wanchuan.js#L39)) --- ## 三、第 2 步:登录的触发与自动恢复 登录在 [SettingsPage.jsx](chatlab-web/frontend/src/pages/SettingsPage.jsx) 的 `WanchuanPlatformForm` 组件里触发,分两种场景: ### 场景 A:用户点「测试连接」(`handleTestConnection`) 1. 调用 `wanchuanLogin()` 登录。 2. 成功后并行执行: - `fetchKnowledgeBases()` 拉知识库列表 - `syncModel()` 同步平台模型配置 → 写入后端 AI 设置 ### 场景 B:打开设置页自动恢复(`autoLogin`) - 配置(平台地址/账号/密码/已选知识库)以**后端 SQLite 为唯一数据源**, 通过 `GET /api/settings/wanchuan` 读取,不依赖前端 origin(exe 端口变化也能恢复)。 - 挂载时若已有保存的账号密码,自动登录并拉知识库。 - **注意**:自动恢复时**不**自动 `syncModel`,避免覆盖用户在「AI 模型配置」里手改并保存过的值。模型同步只在用户显式操作(点「测试连接」或「从平台获取」)时进行。 --- ## 四、第 3-4 步:按模型编码获取模型信息 这是「获取模型信息」的核心。平台按**用途**用不同的模型编码(code)区分: | code | 用途 | 同步到的后端字段 | |-----------|------------|-----------------------------------------------| | `generic` | 通用/聊天 | `ai_*`(话题分析)+ `summary_*`(报告生成) | | `vision` | 视觉 | `vision_*`(图片/视频描述) | | `voice` | 语音 | `voice_*`(语音转文字) | ### 接口 ``` GET {platformUrl}/api/system/model/getByCode/{code} Authorization: Bearer {token} token: Bearer {token} ``` ### 响应结构 ```json { "code": 200, "msg": "success", "data": { "providerModels": { "modelName": "qwen-plus", "encryptedConfig": "{\"apiKey\":\"sk-xxx\",\"endpointUrl\":\"https://...../v1\"}" } } } ``` 关键点:`data.providerModels.encryptedConfig` 是一个 **JSON 字符串**,需二次 `JSON.parse` 才能拿到 `apiKey` 和 `endpointUrl`。 ### 解析后得到 ```js { modelName: pm.modelName, // 模型名 apiKey: cfg.apiKey, // 来自 encryptedConfig endpointUrl: cfg.endpointUrl, // 来自 encryptedConfig } ``` 对应函数:`getWanchuanModelConfig(baseUrl, code)` ([wanchuan.js:110](chatlab-web/frontend/src/api/wanchuan.js#L110)) 错误处理: - HTTP 非 2xx → 抛 `获取模型[{code}]失败 HTTP {status}`(便于排查 404 路径错 / 401 token 失效)。 - 无 `providerModels` → 抛 `平台未返回模型[{code}]配置`。 --- ## 五、第 5 步:写入后端 AI 设置 `syncWanchuanModelToSettings()` 负责编排三次拉取并合并写入: 1. **generic 必拉**:拿到 `endpointUrl / apiKey / modelName` 后,同时写入两组字段: - 话题分析:`ai_base_url` / `ai_api_key` / `ai_model` - 报告生成:`summary_base_url` / `summary_api_key` / `summary_model` (两者同网关,但分开存便于各组独立回显与覆盖。) 2. **vision / voice 可选**:用 `Promise.all` 并行拉取,**失败则跳过对应字段**(`.catch(() => {})`),不打断聊天模型同步: - `vision_base_url` / `vision_api_key` / `vision_model` - `voice_base_url` / `voice_api_key` / `voice_model` 3. 仅写入**非空字段**;若最终 payload 为空则抛 `平台模型配置为空`。 4. 最后 `PUT /api/settings` 保存到后端: ``` PUT /api/settings Content-Type: application/json ``` ```json { "ai_base_url": "...", "ai_api_key": "...", "ai_model": "...", "summary_base_url": "...", "summary_api_key": "...", "summary_model": "...", "vision_base_url": "...", "vision_api_key": "...", "vision_model": "...", "voice_base_url": "...", "voice_api_key": "...", "voice_model": "..." } ``` 对应函数:`syncWanchuanModelToSettings(baseUrl, codes)` ([wanchuan.js:151](chatlab-web/frontend/src/api/wanchuan.js#L151)) --- ## 六、后端 /api/settings 的处理 实现在 [chatlog_fastAPI/routers/settings.py](chatlog_fastAPI/routers/settings.py)。 ### 可编辑字段(EDITABLE_KEYS) ``` ai_base_url, ai_api_key, ai_model, summary_model, vision_model, voice_model, topic_analysis_prompt, voice_base_url, voice_api_key, vision_base_url, vision_api_key, summary_base_url, summary_api_key ``` ### 密钥脱敏(SECRET_KEYS) `ai_api_key / voice_api_key / vision_api_key / summary_api_key` 四个字段: - **GET** 返回时打码(`_mask_key`,只保留首尾、中间打 `*`)。 - **PUT** 时若值里含 `*`,说明是 GET 返回的打码值(用户没真改),**跳过不写**,避免把真实密钥覆盖成打码串。 ### 存储 所有字段以 key-value 形式存进 SQLite 的 `app_settings` 表(`INSERT ... ON CONFLICT DO UPDATE`)。 --- ## 七、第 6 步:后端运行时如何使用这些配置 实现在 [chatlog_fastAPI/services/ai_client.py](chatlog_fastAPI/services/ai_client.py) 与 [chatlog_fastAPI/services/runtime_settings.py](chatlog_fastAPI/services/runtime_settings.py)。 - `get_ai_settings()`:从 SQLite 读出全部 AI 字段(带默认值),并缓存。 - `get_openai_client()`:聊天类调用(话题分析 / 报告 / 总结 / 对话)用全局 `ai_base_url` + `ai_api_key`。 - `get_client_for(purpose)`:`purpose` 为 `voice` / `vision`, 优先用 `{purpose}_base_url` / `{purpose}_api_key`,**为空则回退**到 `ai_base_url` / `ai_api_key`(单网关场景无需重复配。 - 客户端按 `(base_url, api_key)` 缓存,聊天/视觉/语音可指向不同网关与密钥, 最多累积 3 个,配置变更后自然生成新客户端。 --- ## 八、相关接口速查表 | 步骤 | 方法 | 路径 | 用途 | |------|------|------|------| | 登录 | POST | `{platformUrl}/api/login` | 账号密码换 token | | 知识库 | GET | `{platformUrl}/api/system/kb/relation/query` | 拉岗位知识库列表 | | 模型信息 | GET | `{platformUrl}/api/system/model/getByCode/{code}` | 按 code 取模型配置 | | 上传 | POST | `{platformUrl}/api/system/kb/file/upload/async/{datasetId}` | 上传文件到知识库 | | 读平台配置 | GET | `/api/settings/wanchuan` | 后端存的平台地址/账号/密码/已选库 | | 存平台配置 | PUT | `/api/settings/wanchuan` | 保存平台配置 | | 读 AI 配置 | GET | `/api/settings` | 回显 AI 模型配置(密钥脱敏) | | 写 AI 配置 | PUT | `/api/settings` | 保存/同步 AI 模型配置 | --- ## 九、关键数据结构小结 **登录请求**:`{ username, password, loginType: "user" }` **登录响应取 token**:`result.token` 等多路径兜底 **模型接口响应**:`data.providerModels.{ modelName, encryptedConfig }` **encryptedConfig**(JSON 字符串):`{ apiKey, endpointUrl, ... }` **最终归一化模型对象**:`{ modelName, apiKey, endpointUrl }` **写入后端的 12 个字段**:`{ai,summary,vision,voice}_{base_url,api_key,model}`