2026-04-19-02-48-25 重构AI接口配置:多服务商底座架构、OpenAI兼容协议、动态模型切换、旧数据自动迁移

This commit is contained in:
2026-04-19 02:53:26 +08:00
parent 221daf61a5
commit d5cbbf9137
8 changed files with 416 additions and 59 deletions

View File

@@ -441,3 +441,106 @@
- 在无法使用 Docker 的环境中,可将 `npm run build && npm run preview -- --host` 作为标准部署脚本。
- 重新部署前务必先清理旧的同类型进程,避免端口冲突或多版本服务同时运行导致访问混乱。
- **切勿使用 Shell 后台任务(`run_in_background=true`)长时间运行 `npm run preview`**,因为任务超时机制(默认 60s会强制终止 preview 进程,导致服务中断。
---
## 记录 22参考信息文件夹导致 tsc 编译失败
**A. 具体问题**
执行 `npm run lint``tsc --noEmit`)时,报错 `参考信息/参考-ReportEditor.tsx` 中找不到模块 `'../components/Sidebar'` 等。该文件只是用户提供的参考代码,不应参与编译。
**B. 产生问题原因**
`tsconfig.json` 中没有配置 `exclude` 字段TypeScript 默认会递归编译项目根目录下所有 `.ts`/`.tsx` 文件,包括非源码的参考文件。
**C. 解决问题方案**
`tsconfig.json` 中增加 `exclude` 字段:
```json
"exclude": ["参考信息", "dist", "node_modules"]
```
**D. 后续如何避免问题**
- 任何非源码的参考文件、文档、备份代码必须放在被 `tsconfig.exclude``.gitignore` 排除的目录中。
- 修改 `tsconfig.json` 后应立即运行 `npm run lint` 验证排除是否生效。
---
## 记录 23大文件2200+行)增量修改的定位策略
**A. 具体问题**
`ReportEditor.tsx` 有 2224 行需要在多处插入代码imports、state、函数、工具栏 JSX、tab 切换 JSX、AI 面板 JSX、Diff 弹窗 JSX。直接全文搜索效率低且容易定位错误。
**B. 产生问题原因**
单文件组件承载了过多功能编辑器、视频分析、表单、AI 面板),导致任何新增功能都需要在文件的多个离散位置插入代码。
**C. 解决问题方案**
采用 **"Grep 定位 + 精确读取 + StrReplaceFile"** 的三段式策略:
1. 先用 `Grep` 找到目标代码的精确行号
2.`ReadFile` 读取该行号前后 10-20 行,获取精确文本
3.`StrReplaceFile` 进行最小化字符串替换,确保只改目标区域
**D. 后续如何避免问题**
- 对于超过 1500 行的单文件组件,新增功能时应优先使用 `Grep` 定位关键锚点(如 `const [activeTab``<div className="flex items-center gap-1 p-3` 等),避免盲目滚动阅读。
- 若需在同一文件的 5 个以上位置插入代码,建议先用 Agent 生成修改草案,再人工审核关键锚点。
- 考虑在未来重构中将超大组件按功能拆分为子组件(如 `ReportEditorToolbar``ReportEditorAiPanel`),降低后续修改成本。
---
## 记录 24数据结构重构时的旧数据迁移策略
**A. 具体问题**
重构 `SystemSettings` 时,将 `apiEndpoint`/`apiKey`/`kimiApiKey`/`kimiApiEndpoint` 四个散装字段替换为 `activeAiProvider` + `aiProviders` 字典结构。如果直接删除旧字段,已配置 API Key 的老用户会丢失配置。
**B. 产生问题原因**
TypeScript 接口变更后,从 `localStorage` 读出的旧数据对象缺少新字段,直接赋值给新类型的 state 会导致类型错误(缺少 `activeAiProvider``aiProviders`)或运行时逻辑断裂。
**C. 解决问题方案**
1.`SystemSettings.tsx` 的初始化 `useEffect` 中增加数据迁移逻辑:
```ts
if (!savedSettings.aiProviders) {
const providers = { ...DEFAULT_AI_PROVIDERS };
if ((savedSettings as any).kimiApiKey || (savedSettings as any).kimiApiEndpoint) {
providers.kimi = {
endpoint: (savedSettings as any).kimiApiApiEndpoint || providers.kimi.endpoint,
apiKey: (savedSettings as any).kimiApiKey || '',
modelName: 'kimi-k2-5'
};
}
savedSettings.aiProviders = providers;
savedSettings.activeAiProvider = 'kimi';
storage.set('systemSettings', savedSettings);
}
```
2. 使用 `(savedSettings as any)` 临时绕过旧字段的类型检查,避免在 `types.ts` 中保留废弃字段。
3. 迁移后旧字段仍保留在 `localStorage` 中(不主动删除),但代码不再读取。
**D. 后续如何避免问题**
- 任何涉及 `localStorage` 数据结构变更的重构,都必须在初始化入口提供**自动迁移逻辑**,否则用户数据会静默丢失。
- 迁移逻辑应使用 `try/catch` 包裹,防止脏数据导致页面白屏。
- 旧字段可通过 `(obj as any).oldField` 安全访问,无需在类型定义中长期保留废弃字段。
---
## 记录 25多服务商配置字典的 UI 绑定模式
**A. 具体问题**
SystemSettings 需要支持 4 个服务商Kimi/DeepSeek/OpenAI/自定义),每个服务商有 3 个配置项endpoint/apiKey/modelName。若用 12 个独立 state 或输入框,代码会极其臃肿。
**B. 产生问题原因**
早期设计采用平铺字段(`kimiApiKey`、`deepseekApiKey`...),导致每新增一个服务商就要改 types + UI + 调用逻辑三处。
**C. 解决问题方案**
采用 **"字典 + 动态下标"** 模式:
1. `types.ts` 中统一定义 `Record<string, AiProviderConfig>`
2. UI 中只有一个 `activeAiProvider` select下方 3 个输入框统一绑定到 `aiProviders[activeAiProvider].xxx`
3. `onChange` 时创建浅拷贝更新:
```ts
const next = { ...settings.aiProviders };
next[settings.activeAiProvider] = { ...next[settings.activeAiProvider], endpoint: e.target.value };
setSettings({ ...settings, aiProviders: next });
```
**D. 后续如何避免问题**
- 当一组配置具有"同构多实例"特征时(多个服务商、多个环境、多个账号),优先使用 `Record<string, Config>` 而非平铺字段。
- 动态表单的 `onChange` 必须注意不可变更新:先浅拷贝外层字典,再浅拷贝当前项,最后修改目标字段。直接 `settings.aiProviders[k].endpoint = x` 会触发 React 引用比较优化导致不刷新。