From d7dc24df09ad25fed407ca46e4a4c604c9b7d3f9 Mon Sep 17 00:00:00 2001 From: damingishere-coder Date: Mon, 19 Oct 2026 10:52:04 +0800 Subject: [PATCH 1/3] chore(release): prepare GroupBrief 2.1.0 --- CHANGELOG.md | 22 ++++++++++++++++++++++ README.md | 14 ++++++++++---- app/version.py | 2 +- docs/KNOWLEDGE.md | 16 +++++++++------- docs/UPGRADING.md | 14 ++++++++++---- frontend/package-lock.json | 4 ++-- frontend/package.json | 2 +- start_windows.bat | 2 +- 8 files changed, 56 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3981b64..07e1a95 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,23 @@ GroupBrief 使用 [Semantic Versioning](https://semver.org/) 记录公开版本 ## [Unreleased] +## [2.1.0] - 2026-10-19 + +### 日报调度与微信交付 + +- 支持自定义日报发送时间与按日期暂停发送,按中国工作日规则确定报告周期;前一工作日模式排除休息日聊天,休息日不再误报日报逾期。 +- 双开微信可按固定头像绑定发送账号,改进冷启动搜索、可访问名称识别和混合符号群名核验,并保护已有聊天草稿。 +- 修复长文字、图片输入区展开和动画引起的定位误判;图片粘贴前核验输入焦点、剪贴板内容及发布序号,短暂占用后重新核验目标。 +- 就绪接口实时报告桌面锁定及微信控件不可用,工作台及时刷新生成与发送失败状态;结果未知时仍停止并等待核对。 - 新增群统一沿用现有启用群最常用的完整工作流配置,修复新增表单与按群名绑定仍使用旧默认值、自动发送意外关闭的问题;保留显式设置和新群独立发送目标。 +### 生成与图片校验 + +- 改进 DeepSeek / Codex 模型路由与设置说明,修复桌面 Codex 更新后的 CLI 路径发现。 +- 修复图片透明层丢失、全角百分号及中英文长昵称分行造成的校验误判,改进副标题与底部总结的画面规则。 + +### 可选 Memory & Insight + - Phase 5:同一群报作品体系加入 Monthly Insight,按原始消息计算自然月统计、日均值、跨月自然周交集趋势与本地关键词。 - 月报复用可追溯 MemoryEntry 与长期故事线,不拼接周报;消息或分析不完整时禁止推断话题消失,内容更新保留历史 revision。 @@ -27,6 +42,12 @@ GroupBrief 使用 [Semantic Versioning](https://semver.org/) 记录公开版本 - 新增“运行任务 → 知识任务”入口。此阶段不调用 AI,不修改原聊天归档,不新增发送行为。 - 安装、数据边界与后续阶段见 [知识底座说明](docs/KNOWLEDGE.md)。 +### 升级与边界 + +- 发布整理本身不增加核心数据库迁移。知识扩展默认关闭,启用前按文档执行显式副本迁移;升级不会自动开启、回填或调用 AI。 +- 重新构建前端并通过原有服务管理器重启。正在生成、发送或结果未知的任务应先等待或核对,详见 [升级指南](docs/UPGRADING.md)。 +- 微信桌面、AI 与邮件仍依赖实际账号和环境;自动化测试不代表外部交付成功。 + ## [2.0.0] - 2026-09-10 ### 新版创作工作台 @@ -80,3 +101,4 @@ GroupBrief 使用 [Semantic Versioning](https://semver.org/) 记录公开版本 [1.0.0]: https://github.com/damingishere-coder/GroupBrief/releases/tag/v1.0.0 [2.0.0]: https://github.com/damingishere-coder/GroupBrief/releases/tag/v2.0.0 +[2.1.0]: https://github.com/damingishere-coder/GroupBrief/releases/tag/v2.1.0 diff --git a/README.md b/README.md index 86bde6c..e5075da 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,15 @@ | 程序计算消息数、发言人数和排行榜,统计口径可配置 | AI 整理摘要与海报提示词,按群设置图片风格 | 按群、按日期保存原始消息、排行、提示词与运行状态 | | 多群进度与待处理项集中在今日工作台 | 右侧工作区完成预览、修改、重新生成与复核 | 新增群沿用现有群的发送配置;发送结果未知时等待人工核对 | -## 2.0:围绕每天的群报工作 +## 2.1:工作日群报与可追溯洞察 + +- **按工作节奏生成**:支持中国工作日、自定义发送时间和按日期暂停发送。 +- **可选消息底座**:本地搜索、长期记忆、故事线、周度与月度洞察保留原文来源;默认关闭,启用步骤见 [Memory & Insight](docs/KNOWLEDGE.md)。 +- **更稳妥的微信交付**:双开账号头像绑定、输入焦点与剪贴板核验,以及实时桌面就绪检查。 + +查看完整 [2.1 更新记录](CHANGELOG.md) 与 [升级步骤](docs/UPGRADING.md)。 + +### 延续 2.0 创作工作台 - **今日工作台**:以日报卡片组织多群处理,打开右侧工作区时仍保留原列表。 - **日报作品**:把预览、提示词、图片、画廊、风格和排行榜模板集中管理。 @@ -38,9 +46,7 @@ - **工作日与周报**:支持工作日日报、周一上一自然周周报与总消息排行。 - **延续既有配置**:保留旧入口兼容和未保存草稿提醒;早期安装请按升级指南检查数据库结构。 -查看完整 [2.0 更新记录](CHANGELOG.md) 与 [旧版升级步骤](docs/UPGRADING.md)。 - -下一阶段的可选消息底座正在分批交付:查看 [Memory & Insight 安装及阶段说明](docs/KNOWLEDGE.md)。新功能默认关闭,沿用当前日报和发送流程。 +可选知识功能沿用当前日报和发送流程,不会因升级自动开启。 ## 看看新版界面 diff --git a/app/version.py b/app/version.py index de83644..6c1da51 100644 --- a/app/version.py +++ b/app/version.py @@ -1,3 +1,3 @@ """公开产品版本;API 路由和数据库版本独立演进。""" -APP_VERSION = "2.0.0" +APP_VERSION = "2.1.0" diff --git a/docs/KNOWLEDGE.md b/docs/KNOWLEDGE.md index c9a89da..f11eccb 100644 --- a/docs/KNOWLEDGE.md +++ b/docs/KNOWLEDGE.md @@ -1,9 +1,11 @@ # Memory & Insight 分阶段实施 -## 当前交付:Phase 0 消息底座 / Phase 1 周度洞察 / Phase 2 本地搜索 +## 当前交付:Phase 0–5 消息底座、搜索、记忆与洞察 -此阶段新增可选的统一消息层、来源记录、后台导入账本和消息证据页面。 -不改变日报流水线、图片、发送账本或原 output 文件。没有 AI 调用。 +2.1 已包含 Phase 0–5,具体能力与边界见下文各阶段。功能默认关闭,需显式安装扩展结构并配置。 + +消息底座增加可选的统一消息层、来源记录、后台导入账本和消息证据页面。 +不改变日报流水线、图片、发送账本或原 output 文件。导入、确定性统计和本地搜索不调用 AI;Phase 3 起的补充 AI 默认关闭,需独立预算与调用账本。 入口:运行任务 → 知识任务。先预览历史导入,再确认本地建库。 每条消息能查看上下文、来源归档及原记录;重复出现在多份快照中的消息只列一次。 @@ -50,13 +52,13 @@ Phase 1 可选独立缺日读取见下文;默认仍关闭。 `/knowledge/status`、`/knowledge/jobs` 提供状态,`/jobs/{id}/pause|retry` 控制本地任务。 `POST /knowledge/backfill/preview` 返回范围及版本;`POST /knowledge/backfill` 验证版本后返回 202。 -## 后续阶段 +## 阶段状态 1. Phase 1(已实现):全员确定性 Weekly Insight、可选独立缺日读取和周期 revision。 2. Phase 2(已实现):中文 FTS5、跨日期检索、报告索引及性能验收。 -3. Phase 3:AI 操作账本、分析复用、增量 Memory、证据验证、合并和撤销。 -4. Phase 4:Storyline 时间轴和内容型周报。 -5. Phase 5:Monthly Insight,复用消息与记忆底座。 +3. Phase 3(已实现):AI 操作账本、分析复用、增量 Memory、证据验证、合并和撤销。 +4. Phase 4(已实现):Storyline 时间轴和内容型周报。 +5. Phase 5(已实现):Monthly Insight,复用消息与记忆底座。 6. Phase 6:存在实际召回缺口后再试点 Semantic Search。 各阶段独立 PR、检查、灰度和回滚。AI 未知结果不得自动重试;历史 AI 首批近 90 天仍需成本预览。 diff --git a/docs/UPGRADING.md b/docs/UPGRADING.md index b9b8b92..b7d75eb 100644 --- a/docs/UPGRADING.md +++ b/docs/UPGRADING.md @@ -1,6 +1,10 @@ -# 从 1.0 升级到 2.0 +# 升级到 2.1 -2.0 统一了新版创作工作台和产品版本。本次版本整理相对发布前主线不新增数据库迁移,也不更改 `/api/v2` 路由或用户既有群配置。早期 1.0 安装与持续更新的 1.x 安装可能处于不同数据库结构,不能仅凭界面版本判断能否直接升级。 +2.1 汇总 2.0 之后的工作日调度、微信交付修复和可选 Memory & Insight。发布整理本身不增加核心数据库迁移,现有群配置、发送账本和历史归档继续保留。 + +从 2.0 升级时,按下文备份、更新依赖、重新构建前端并重启原有服务即可。知识功能默认关闭;需要启用或更新扩展结构时,另按 [Memory & Insight 安装说明](KNOWLEDGE.md) 检查并迁移数据库副本。本次升级不自动执行知识迁移、历史回填或额外 AI 调用。 + +早期 1.0 安装与持续更新的安装可能处于不同数据库结构,不能仅凭界面版本判断能否直接升级;这类安装仍需完成下文的额外检查。 ## 升级前 @@ -33,7 +37,7 @@ npm run build Set-Location .. ``` -如提示无法快进,停止并核对分支差异,不要强推或覆盖。`master` 是持续更新线;需要精确复现 2.0.0 时,在独立干净目录检出 `v2.0.0` 标签。 +如提示无法快进,停止并核对分支差异,不要强推或覆盖。`master` 是持续更新线;需要精确复现 2.1.0 时,在独立干净目录检出 `v2.1.0` 标签。 通过原来的 RunDock / Alter 项目重新启动服务;手动启动的安装则重新运行 `.\start_windows.bat`。不要让托管服务和手动脚本同时占用 8766。启动脚本会复用已有前端,所以升级时必须显式执行上面的构建。 @@ -44,7 +48,9 @@ Invoke-RestMethod http://127.0.0.1:8766/api/version Invoke-RestMethod http://127.0.0.1:8766/api/system/ready ``` -精确安装 2.0.0 时,版本应为 `2.0.0`,就绪结果应为 `ready: true`。浏览器按 `Ctrl+F5`,确认左侧有“今日工作台、日报作品、群聊管理、运行任务、消息归档、设置”;打开一份已有日报检查右侧工作区,再进入设置检查系统健康。验证界面无需触发新的 AI 生成或发送。 +精确安装 2.1.0 时,版本应为 `2.1.0`。依赖环境正常时,就绪结果应为 `ready: true`;桌面锁定、微信控件不可用或当日报告异常会返回 `503` 和具体检查项,需要分别核对,不能只凭版本接口判断可发送。 + +浏览器按 `Ctrl+F5`,确认左侧有“今日工作台、日报作品、群聊管理、运行任务、消息归档、设置”;打开一份已有日报检查右侧工作区,再进入设置检查系统健康。验证界面无需触发新的 AI 生成或发送。 ## 回滚 diff --git a/frontend/package-lock.json b/frontend/package-lock.json index dbe726c..b8a0026 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "groupbrief-frontend", - "version": "2.0.0", + "version": "2.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "groupbrief-frontend", - "version": "2.0.0", + "version": "2.1.0", "dependencies": { "@fontsource-variable/inter": "^5.3.0", "@phosphor-icons/react": "^2.1.10", diff --git a/frontend/package.json b/frontend/package.json index 57d0ccf..2dee932 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,7 +1,7 @@ { "name": "groupbrief-frontend", "private": true, - "version": "2.0.0", + "version": "2.1.0", "type": "module", "scripts": { "dev": "vite", diff --git a/start_windows.bat b/start_windows.bat index 321ad28..00c06b5 100644 --- a/start_windows.bat +++ b/start_windows.bat @@ -5,7 +5,7 @@ title GroupBrief cd /d "%~dp0" echo ============================================ -echo GroupBrief v2.0.0 +echo GroupBrief v2.1.0 echo ============================================ where python >nul 2>nul From 608d5c517585889337377319eeacd70d43bc45b3 Mon Sep 17 00:00:00 2001 From: damingishere-coder Date: Mon, 19 Oct 2026 10:56:05 +0800 Subject: [PATCH 2/3] docs: align release navigation and guides with 2.1 --- README.md | 2 +- docs/README.md | 9 +++++---- docs/USER_GUIDE.md | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index e5075da..317c17a 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@

快速开始 · 使用指南 · - 升级到 2.0 · + 升级到 2.1 · 文档中心 · 更新记录

diff --git a/docs/README.md b/docs/README.md index faec45d..7612e2c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,4 +1,4 @@ -# GroupBrief 2.0 文档 +# GroupBrief 2.1 文档 从第一次启动,到每天处理群报,再到安全更新,按当前目标选择入口。 @@ -6,12 +6,13 @@ | --- | --- | | 了解产品、安装并启动 | [项目首页](../README.md#快速开始) | | 学会新版界面 | [使用指南](USER_GUIDE.md) | -| 从 1.0 更新到 2.0 | [升级指南](UPGRADING.md) | -| 看 2.0 有哪些变化 | [更新记录](../CHANGELOG.md) | +| 从旧版更新到 2.1 | [升级指南](UPGRADING.md) | +| 看 2.1 有哪些变化 | [更新记录](../CHANGELOG.md) | +| 启用可选搜索、记忆与洞察 | [Memory & Insight](KNOWLEDGE.md) | | 理清分支、提交和版本 | [分支与发布约定](BRANCHING.md) | | 参与开发与运行测试 | [贡献指南](../CONTRIBUTING.md) | | 了解界面结构与交互 | [创作工作台设计](UI_REDESIGN.md) | | 在 Docker 中开发、只读验证 | [Docker 说明](DOCKER.md) | | 回顾设计背景 | [历史开发记录](development-history/README.md) | -`audits/`、`development-history/` 和带日期的 rollout 文档记录当时的设计与验收,不代表当前运行状态;当前操作以本目录的使用、升级指南为准。产品版本 2.0.0 与内部 `/api/v2` 路由代号彼此独立。 +`audits/`、`development-history/` 和带日期的 rollout 文档记录当时的设计与验收,不代表当前运行状态;当前操作以本目录的使用、升级指南为准。产品版本 2.1.0 与内部 `/api/v2` 路由代号彼此独立。 diff --git a/docs/USER_GUIDE.md b/docs/USER_GUIDE.md index 6989bc5..8de3af1 100644 --- a/docs/USER_GUIDE.md +++ b/docs/USER_GUIDE.md @@ -1,4 +1,4 @@ -# GroupBrief 2.0 使用指南 +# GroupBrief 2.1 使用指南 ## 第一次使用 From 4318594a539363a31f922b94c2b8446eba8cb01d Mon Sep 17 00:00:00 2001 From: damingishere-coder Date: Mon, 19 Oct 2026 11:01:12 +0800 Subject: [PATCH 3/3] test: synchronize concurrent image regeneration deterministically --- tests/test_v2_image_regeneration.py | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/tests/test_v2_image_regeneration.py b/tests/test_v2_image_regeneration.py index d30e763..b851595 100644 --- a/tests/test_v2_image_regeneration.py +++ b/tests/test_v2_image_regeneration.py @@ -262,6 +262,8 @@ def test_two_different_runs_can_regenerate_concurrently(tmp_path): settings = SimpleNamespace(output_dir=tmp_path, image_generation_concurrency=2) store = RunStore(tmp_path) guard = threading.Lock() + first_started = threading.Event() + both_started = threading.Barrier(2, timeout=10) class ConcurrentGenerator: def __init__(self): @@ -272,10 +274,14 @@ def generate(self, prompt_path, output_path): with guard: self.active += 1 self.maximum = max(self.maximum, self.active) - time.sleep(0.12) - output_path.write_bytes(NEW_PNG) - with guard: - self.active -= 1 + first_started.set() + try: + # 等两项任务都进入生成器,再释放,避免依赖机器的文件写入速度。 + both_started.wait() + output_path.write_bytes(NEW_PNG) + finally: + with guard: + self.active -= 1 return ImageTaskResult(True, image_path=output_path) generator = ConcurrentGenerator() @@ -283,10 +289,13 @@ def generate(self, prompt_path, output_path): store.save_run(group, "2026-08-21", {"status": "SENT"}) store.prompt_path(group, "2026-08-21").write_text("真实 Prompt", encoding="utf-8") store.image_path(group, "2026-08-21").write_bytes(OLD_PNG) - enqueue_regeneration(settings, group, "2026-08-21", generator=generator) - deadline = time.time() + 3 - while time.time() < deadline: + enqueue_regeneration(settings, "并发群A", "2026-08-21", generator=generator) + assert first_started.wait(timeout=10) + enqueue_regeneration(settings, "并发群B", "2026-08-21", generator=generator) + + deadline = time.monotonic() + 15 + while time.monotonic() < deadline: states = [ store.load_run(group, "2026-08-21").get("image_regen_status") for group in ("并发群A", "并发群B")