Initial upload for secondary development

This commit is contained in:
2026-06-08 19:00:03 +08:00
commit b913b8c78c
81 changed files with 27139 additions and 0 deletions

397
CHANGELOG.md Normal file
View File

@@ -0,0 +1,397 @@
# 修改日志 CHANGELOG
本文件记录每次代码修改的内容、原因与时间,精确到分钟,便于回溯和审查。
**规则:每次修复 Bug 或新增功能,必须在此文件追加一条记录。**
---
## [2026-05-11 01:15] 项目瘦身:清理分发包多余文件
### 背景
项目原始大小 2.3 GB包含构建产物、Go SDK、PyInstaller 输出等开发专用文件,发送给用户体积过大。清理后保留"无痕启动控制台"完整运行所需的最小文件集。
### 删除内容
| 路径 | 大小 | 原因 |
|------|------|------|
| `chatlog_fastAPI/dist/` | 653 MB | PyInstaller 打包输出,不走此 exe 启动 |
| `chatlog_fastAPI/build/` | 206 MB | PyInstaller 中间产物 |
| `electron-launcher/dist/` | 349 MB | electron-builder 安装包,不走此包启动 |
| `go_env/` | 276 MB | 完整 Go SDKchatlog.exe 已编译完毕 |
| `chatlab-web/frontend/dist/` | ~1 MB | Vite 构建输出,走 npm run dev |
| `cmd/` `internal/` `pkg/` `bin/` | <2 MB | Go 源码,不重新编译则无用 |
| `chatlab-web/backend/` | 49 KB | 废弃旧版 Python 后端 |
| `scripts/` `.github/` `.vscode/` | 小 | 开发专用 |
| `main.go` `go.mod` `go.sum` `Makefile` `.goreleaser.yaml` `.gitignore` | 小 | Go 构建文件 |
| `lib/windows_x64/wx_key.exp/.lib/.pdb` | 小 | 链接/调试符号,运行只需 .dll |
| `chatlog_fastAPI/__pycache__/` 等 | 28 KB | Python 字节码缓存,运行时自动重建 |
| `chatlog_fastAPI/chatlog.db` `knowledge.db` `*.spec` `test_wxid.py` `backend_design.md` | 小 | 空文件/调试/设计文档 |
| `test_audio*.py` `test_upload.go.bak` `launcher_error.log` | 小 | 临时调试文件 |
| `README.md` `chatlab.md` `dll调用指南.md` `启动与编译命令指南.md` | 小 | 开发参考文档 |
| `chatlog_fastAPI/knowledge_wxid_*.db` | ~224 KB | 个人账号知识库,用户登录后自动生成 |
**节省:~1.49 GB2.3 GB → 863 MB**
### 保留内容(最小运行集)
```
get_wechat_me/
├── 无痕启动控制台.vbs 启动入口
├── chatlog.exe Go 后端63 MB
├── CHANGELOG.md / README.md / DISCLAIMER.md / LICENSE
├── lib/windows_x64/wx_key.dll
├── electron-launcher/
│ ├── main.js / preload.js / index.html / package.json / package-lock.json
│ └── node_modules/650 MBelectron 二进制)
├── chatlog_fastAPI/
│ ├── main.py / config.py / database.py / scheduler.py
│ ├── .env / requirements.txt
│ ├── routers/ / services/
└── chatlab-web/frontend/
├── src/ / public/ / index.html / vite.config.js / package.json
└── node_modules/150 MBVite + React
```
## [2026-05-11 01:05] Bug 修复:可搜索下拉浮层背景透明
### 问题描述
上一轮新增的"添加群聊"可搜索下拉浮层背景完全透明,条目文字叠在底层内容上,可读性极差。
### 根因
代码中使用了 `var(--surface)``var(--surface-2)` 两个 CSS 变量,但 `index.css``:root` 从未定义这两个变量,浏览器 fallback 为 `transparent`
这两个变量在整个项目(`TopicsPage.jsx``KnowledgePage.jsx``MessageBubble.jsx``SettingsPage.jsx``App.jsx`)中被广泛引用。
### 修改文件明细
#### 1. `chatlab-web/frontend/src/index.css`
**改动**:在 `:root` 的颜色变量区域追加两行别名定义:
```css
/* 别名:兼容组件中使用的 var(--surface) / var(--surface-2) */
--surface: #ffffff; /* 等同于 --bg-surface */
--surface-2: #f0f2f5; /* 等同于 --bg-overlay */
```
**原因**:项目现有的背景变量命名为 `--bg-surface``--bg-overlay` 等,但大量组件使用了更简短的 `--surface`/`--surface-2` 命名。根本修复是在 CSS 中统一补充定义这两个别名,一次修复所有引用,避免逐文件替换。
```
位置chatlab-web/frontend/src/index.css:root 第 6 行后
新增 3 行
```
---
#### 2. `chatlab-web/frontend/src/pages/TopicsPage.jsx`
**改动**:将浮层容器和条目中仍残留的错误变量名手动替换为正确值:
- 浮层容器:`var(--surface)``var(--bg-surface)`
- 条目默认背景:`transparent``var(--bg-surface)`(使其与浮层容器背景一致)
- 条目选中态:`var(--surface-2)``var(--bg-overlay)`
- `onMouseEnter``var(--surface-2)``var(--bg-hover)`
- `onMouseLeave``var(--surface-2)``var(--bg-overlay)`
**原因**:在 CSS 补充别名定义之外,同步将浮层的引用改为语义更明确的 `--bg-*` 系列变量,确保悬停/选中状态的颜色层次感正确(白底 → 悬停浅灰 → 选中深灰)。
```
位置showGroupDropdown 浮层(第 315-340 行)
修改 5 处变量名
```
---
### 总结
| 文件 | 改动性质 | 解决的问题 |
|------|----------|-----------|
| `chatlab-web/frontend/src/index.css` | Bug 修复 | 全局补充 `--surface`/`--surface-2` CSS 变量定义,消除所有相关透明背景问题 |
| `chatlab-web/frontend/src/pages/TopicsPage.jsx` | 变量名规范化 | 浮层下拉列表背景透明,条目悬停/选中状态无法区分 |
---
## [2026-05-10 15:42] Bug 修复:新账号首次解密引导 + 账号切换前端数据刷新
### 问题描述
1. **新账号无法在启动器一键解密**:切换到从未登录过的新微信账号时,需要手动进入 chatlog.exe 的 TUI 界面执行解密,启动器无法自动引导。
2. **账号切换后前端消息不刷新**切换微信账号并重启控制台后React 前端仍然显示上一个账号的会话列表和消息,没有切换到新账号的数据。
3. **FastAPI 层账号数据库不切换**`_resolved_wxid` 全局变量一旦解析成功后永不刷新,账号切换后 Python 业务层仍读取旧账号的知识库数据库。
---
### 修改文件明细
#### 1. `electron-launcher/main.js`
**改动**:在 `keyProcess.on('close')` 回调中,读取完 `savedWorkDir` 后,新增对工作目录的检测逻辑:
- 若工作目录不存在或目录内无 `.db` 文件 → 判定为"新账号首次解密",向渲染进程发送 `show-decrypt-dialog` IPC 事件,弹出引导弹窗。
- 若工作目录已存在 `.db` 文件 → 判定为"已解密账号",直接启动 server不弹窗。
**原因**`chatlog.exe key` 命令执行完毕后会更新 `~/.chatlog/chatlog.json``last_account`,此时读取的 `savedWorkDir` 才是当前账号对应的工作目录。通过检测该目录是否含有解密产物(`.db` 文件),即可区分新旧账号。
```
位置electron-launcher/main.jskeyProcess.on('close') 内,第 251 行附近
新增约 20 行代码
```
---
#### 2. `electron-launcher/preload.js`
**改动**:在 `contextBridge.exposeInMainWorld` 中新增一条 IPC 监听:
```js
onShowDecryptDialog: (callback) => ipcRenderer.on('show-decrypt-dialog', () => callback())
```
**原因**Electron 的 contextIsolation 模式下,渲染进程无法直接访问 `ipcRenderer`,必须通过 `preload.js``contextBridge` 安全暴露。新增的 `show-decrypt-dialog` 事件需要在这里注册后,`index.html` 中的 JS 才能通过 `window.electronAPI.onShowDecryptDialog` 收到通知。
```
位置electron-launcher/preload.js第 19-20 行
新增 1 行
```
---
#### 3. `electron-launcher/index.html`
**改动CSS 部分)**:新增模态弹窗相关样式(`.modal-overlay``.modal-box``.modal-title``.modal-body``.modal-steps``.modal-footer``.modal-spinner` 及其动画)。
**改动HTML 部分)**:在 `<body>` 顶部新增 `#decrypt-dialog` 模态弹窗元素,包含:
- 标题:"🔓 检测到新账号,正在解密数据"
- 操作步骤引导(切换到微信、点击聊天窗口、翻看历史消息)
- 与 chatlog.exe 一致的提示说明
- 底部旋转 spinner + 计时显示
**改动JS 部分)**
- 新增 `decryptDialog``decryptDialogStatus``decryptDialogElapsed` DOM 引用。
- `onDecryptStatus` 回调中额外同步更新弹窗计时器(`decryptDialogElapsed`)。
- `onDecryptReady` 回调中增加 `decryptDialog.classList.remove('show')` 关闭弹窗。
- 新增 `window.electronAPI.onShowDecryptDialog` 监听,收到事件时显示弹窗。
**原因**:用户切换新账号时需要按照 chatlog.exe TUI 中相同的操作提示(点击微信聊天界面)才能完成密钥提取。弹窗承担了原来需要手动进入 TUI 界面的提示职责,实现"一键解密"体验。
```
位置electron-launcher/index.html
新增 ~90 行 CSS + HTML + JS
```
---
#### 4. `chatlab-web/frontend/src/App.jsx`
**改动**
1. **去掉 localStorage 冷加载旧账号数据**:将 `useState(() => loadSessionCache())` 改为 `useState([])`,避免启动时直接显示上一个账号的旧会话列表。
2. **新增账号指纹机制**
- `calcFingerprint(sessions)` —— 取前 3 个会话 id 拼接成指纹字符串。
- `loadAccountFingerprint()` / `saveAccountFingerprint(fp)` —— 读写 localStorage 中的 `chatlab_account_fingerprint` 键。
3. **`getSessions` 返回后检测账号切换**`loadSessions` 函数(封装了原 `getSessions` 调用)在拿到新会话列表后,对比新旧指纹。若指纹不同,说明账号已切换,立即执行:
- `localStorage.removeItem(CACHE_KEY)` 清除旧缓存。
- `setSelectedRoom(null)` 重置当前选中群(否则会拿旧群 id 去查询新账号的消息)。
4. **每 30 秒轮询一次**:新增 `useEffect` 设置 30 秒定时器,静默调用 `loadSessions(true)`(轮询模式不显示 loading 也不报错),以便在用户不刷新页面的情况下自动感知账号切换。
**原因**
- 旧代码的 `getSessions()` 只在组件挂载时执行一次,账号切换不触发重新加载。
- 旧代码从 localStorage 取缓存作为初始 state导致旧账号数据在新账号登录时"闪现"。
- 两处修复合力确保前端始终显示当前微信账号的真实数据。
```
位置chatlab-web/frontend/src/App.jsx
修改约 40 行,新增约 30 行
```
---
#### 5. `chatlog_fastAPI/database.py`
**改动**
1. 新增 `import time`
2. 新增全局变量 `_wxid_last_resolved: float = 0.0` 和常量 `_WXID_TTL = 60.0`
3. `get_current_wxid()` 函数:在命中现有缓存时增加时间判断 `(now - _wxid_last_resolved) < _WXID_TTL`,超过 60 秒强制重新解析。
4. 在两处成功解析到 wxid 时,均更新 `_wxid_last_resolved = time.time()`
**原因**:原代码中 `_resolved_wxid` 一旦解析成功就永久缓存,账号切换后 Python 层仍用旧 wxid 路由到旧知识库数据库文件(`knowledge_<旧wxid>.db`),导致 AI 话题分析、知识库搜索等功能数据错误。60 秒 TTL 平衡了性能与准确性。
```
位置chatlog_fastAPI/database.py第 1-53 行
修改约 10 行,新增约 5 行
```
---
#### 6. `chatlog_fastAPI/main.py`
**改动**
1. 新增 `import asyncio``import logging`
2. 新增后台协程 `_account_watch_loop()`:每 60 秒调用一次 `update_db_path()`,静默捕获异常。
3.`lifespan` 上下文管理器中,`yield` 前用 `asyncio.create_task` 启动该协程,`yield` 后取消任务并等待清理。
**原因**:仅靠 `database.py` 的 TTL 机制还不够——TTL 只在被调用时才重新检测,如果 FastAPI 长时间运行无请求则无法触发。后台轮询任务确保即使 FastAPI 在后台静默运行,账号切换也能在约 60 秒内被感知并切换数据库。
```
位置chatlog_fastAPI/main.py全文
修改约 5 行,新增约 15 行
```
---
### 总结
| 文件 | 改动性质 | 解决的问题 |
|------|----------|-----------|
| `electron-launcher/main.js` | 功能新增 | 新账号自动检测 + 弹窗触发 |
| `electron-launcher/preload.js` | IPC 暴露 | 渲染进程收到新账号通知 |
| `electron-launcher/index.html` | UI 新增 | 首次解密引导弹窗,等同 chatlog.exe TUI 提示 |
| `chatlab-web/frontend/src/App.jsx` | Bug 修复 + 功能增强 | 账号切换后前端立即显示新账号数据 |
| `chatlog_fastAPI/database.py` | Bug 修复 | 账号切换后 Python 层自动切换知识库数据库 |
| `chatlog_fastAPI/main.py` | 功能新增 | 后台定期检测账号变化,无需依赖请求触发 |
---
## [2026-05-11 00:32] Bug 修复AI话题分析 & 知识库 4 个 UI 问题
### 问题描述
1. **AI话题分析"添加群聊"无搜索**:群聊列表使用原生 `<select>`,群多时只能逐条翻找,体验差。
2. **知识库文档无分组**:文档平铺展示,无法区分属于哪个群聊/话题。
3. **AI分析无进度条**:点击"AI 分析"或"AI 生成知识文档"后,用户不知道当前执行到哪一步。
4. **管理消息弹窗"已添加"不可操作**:已加入话题的消息显示静态文字"已添加",无法直接点击移除。
---
### 修改文件明细
#### 1. `chatlab-web/frontend/src/pages/TopicsPage.jsx`
**Bug 1 修复 — 群聊选择改为可搜索下拉**
- 将"添加群聊"面板内的原生 `<select>` 替换为自定义可搜索组件:`<input>` 搜索框 + 绝对定位浮层列表。
- 新增 state`groupSearchKeyword``showGroupDropdown`
- 浮层列表实时过滤(同时匹配群聊名称和群 ID点击某项后填充输入框并收起浮层。
```
位置showAddGroup 块内(第 268 行附近)
新增约 45 行 JSX
```
**Bug 3A 修复 — AI分析进度条**
- `handleInitGroup` 轮询中新增 `JSON.parse(task.progress)` 解析,将 `{processed, total}` 赋值到 `initProgress` state初始化/完成时重置为 null
- 在"AI 分析"按钮下方插入进度条 UI显示 `processed/total` 数值 + 彩色进度条宽度由百分比驱动0.5s 过渡动画)。
- 新增 state`initProgress`
```
位置handleInitGroup 函数(第 117 行)+ 按钮区域(第 336 行)
修改约 15 行,新增约 22 行
```
**Bug 3B 修复 — AI生成知识文档进度条**
- `handleSummarize` 改为接收后端返回的 `task_id``res.data.task_id`),若存在则用 `getTask(task_id)` 每 3 秒轮询,解析 `progress` 字段,更新 `summarizeProgress` state若无 task_id 则 fallback 5 秒后刷新。
- 在"AI 生成知识文档"按钮下方插入进度条 UI与 3A 样式一致,宽度 180px
- 新增导入:`getTask`(已在 `api/index.js` 中定义)。
- 新增 state`summarizeProgress`
```
位置handleSummarize 函数(第 241 行)+ 按钮区域(第 422 行)
修改约 12 行,新增约 40 行
```
**Bug 4 修复 — "已添加"改为红色"移除"按钮**
- 管理消息弹窗左栏:将 `topicSeqs.has(Number(m.id))` 为真时显示的 `<span>已添加</span>` 改为红色 `<button> 移除</button>`,点击调用已有的 `handleRemoveMsg(Number(m.id))`
- 样式:`color: 'var(--danger)'``borderColor: 'rgba(243,139,168,0.4)'`
```
位置:管理消息弹窗左栏消息列表(第 531 行)
修改 1 处,约 6 行
```
---
#### 2. `chatlog_fastAPI/routers/knowledge.py`
**Bug 2 后端 — SQL 联表返回 group_name**
- 两处 `SELECT`(普通查询 + FTS 关键词查询)均扩展为:
- 新增 `LEFT JOIN groups g ON t.group_id=g.id`
- 新增返回字段:`t.group_id``g.name as group_name`
- 普通查询的 `ORDER BY` 改为 `ORDER BY g.name, k.updated_at DESC`,使同一群聊的文档聚在一起。
```
位置chatlog_fastAPI/routers/knowledge.py第 18-33 行
修改约 8 行
```
---
#### 3. `chatlab-web/frontend/src/pages/KnowledgePage.jsx`
**Bug 2 前端 — 文档列表按群聊分组展示**
- 将原来平铺的 `docs.map(...)` 改为先按 `doc.group_name`(后端新增字段)分组,渲染时在每个群聊前加粘性标题头(灰色小号大写文字,背景 `var(--surface-2)``position: sticky`)。
- `group_name` 为空时归入"未知群聊"分组。
```
位置KnowledgePage.jsx第 96-114 行
修改约 20 行,新增约 30 行
```
---
#### 4. `chatlog_fastAPI/routers/topics.py`
**Bug 3B 后端 — summarize 接口返回 task_id**
- `POST /api/topics/{id}/summarize` 在调用 `run_summarize` 前,先向 `ai_tasks` 表插入一条类型为 `'summarize'`、状态为 `'running'` 的记录,并把 `task_id` 随响应返回:`{"ok": True, "task_id": task_id}`
- 前端可用 `getTask(task_id)` 轮询该记录的 `status`/`progress` 字段以展示进度。
```
位置chatlog_fastAPI/routers/topics.py第 142-151 行
修改约 10 行
```
---
#### 5. `chatlog_fastAPI/services/summary_engine.py`
**Bug 3B 后端 — run_summarize 接收 task_id完成/出错时更新状态**
- 函数签名新增可选参数 `task_id: int | None = None`
- 新增内部辅助函数 `_update_task(status, processed, total)`打开独立数据库连接UPDATE `ai_tasks` 记录的 `status``progress`
- 在以下关键节点调用 `_update_task`
- 任务开始:`running, 0, 1`
- 无消息/无有效消息/LLM 失败:`error, 0, 1`
- 生成完成:`done, 1, 1`
- 新增 `import json`(用于序列化 progress 字段)。
```
位置chatlog_fastAPI/services/summary_engine.py第 65-190 行
修改约 8 行,新增约 20 行
```
---
### 总结
| 文件 | 改动性质 | 解决的问题 |
|------|----------|-----------|
| `TopicsPage.jsx` | UI 替换 + 功能新增 | Bug1可搜索下拉+ Bug3A初始化进度条+ Bug3B生成知识文档进度条+ Bug4移除按钮 |
| `KnowledgePage.jsx` | UI 重构 | Bug2知识库按群聊分组展示 |
| `chatlog_fastAPI/routers/knowledge.py` | SQL 扩展 | Bug2返回 group_name 字段) |
| `chatlog_fastAPI/routers/topics.py` | 功能新增 | Bug3Bsummarize 接口返回 task_id |
| `chatlog_fastAPI/services/summary_engine.py` | 功能新增 | Bug3B运行时更新 ai_tasks 进度状态) |