|
|
@ -14,12 +14,22 @@ v0.1 之后主仓有 4 次提交(翻译延迟优化、设备表合表、收拢 |
|
|
| 1 | echomeet 按 `ServiceType` 四套固定服务商,总结用 `GetSummarizer(svcType, lang)` | 已改为**后台编排**:`PickLLM()` / `GetSummarizer(svcId)`,`ResolveServiceType` 已不存在 | §7.2 | |
|
|
| 1 | echomeet 按 `ServiceType` 四套固定服务商,总结用 `GetSummarizer(svcType, lang)` | 已改为**后台编排**:`PickLLM()` / `GetSummarizer(svcId)`,`ResolveServiceType` 已不存在 | §7.2 | |
|
|
| 2 | 会议总结只吃文本 | 已支持**多模态图片**(`imageurls`),小票识别不用另造轮子 | §12 待确认 1 | |
|
|
| 2 | 会议总结只吃文本 | 已支持**多模态图片**(`imageurls`),小票识别不用另造轮子 | §12 待确认 1 | |
|
|
| 3 | 客户端只有花销 i18n 文案 | `CalendarEventCategory{todo,expense}` + 花销卡片 + 范围内合计**已经写好了** | §6.1 | |
|
|
| 3 | 客户端只有花销 i18n 文案 | `CalendarEventCategory{todo,expense}` + 花销卡片 + 范围内合计**已经写好了** | §6.1 | |
|
|
| 4 | 客户端上传对象存储用腾讯 COS、密钥明文下发 | 已改**服务端签发预签名 URL**,`scene` 是白名单 | §6.4 | |
|
|
| 4 | 客户端上传对象存储用腾讯 COS、密钥明文下发 | 已改**服务端签发预签名 URL**,`scene` 是白名单 | §6.6 | |
|
|
| 5 | `flutter_local_notifications` 只用于录音提示 | 属实,但已有**两个各自独立的 plugin 实例**,且**缺 `timezone` 依赖** | §5.1 | |
|
|
| 5 | `flutter_local_notifications` 只用于录音提示 | 属实,但已有**两个各自独立的 plugin 实例**,且**缺 `timezone` 依赖** | §5.1 | |
|
|
| 6 | 「代办」页要改名 | zh-CN/HK/TW 已改「拾忆/拾憶」,但**只有 11/41 个语言文件有 `tabTodo` 这个 key** | §2.3 | |
|
|
| 6 | 「代办」页要改名 | zh-CN/HK/TW 已改「拾忆/拾憶」,但**只有 11/41 个语言文件有 `tabTodo` 这个 key** | §2.3 | |
|
|
|
|
|
|
|
|
新增三条既有缺陷(详见 §2.4):**MCP 完全没有鉴权**、**账号注销漏表**、**i18n 改名没做完**。 |
|
|
新增三条既有缺陷(详见 §2.4):**MCP 完全没有鉴权**、**账号注销漏表**、**i18n 改名没做完**。 |
|
|
|
|
|
|
|
|
|
|
|
**第二轮全局复核(服务端 → 客户端逐层)又推翻/补充了 5 处**: |
|
|
|
|
|
|
|
|
|
|
|
| # | 原设计 | 复核结论 | 章节 | |
|
|
|
|
|
|---|---|---|---| |
|
|
|
|
|
| 7 | 「拾忆页加分类筛选、换源、删 mock」 | 页面是**纯展示页**:无下拉刷新、无新增按钮、卡片无 onTap,**4 个写接口全无调用点**,`user_edited` 机制空转 | §6.3 | |
|
|
|
|
|
| 8 | 每日弹窗「排在启动第三个」 | 不能 await 在 splash——`6a64c3d0` 刚把 `_initMeetingTemplate` 从启动串行链摘出去,方向相反 | §5.2 | |
|
|
|
|
|
| 9 | 「MCP 三个旧工具改读 memory_item」 | MCP 是独立进程、**从不 RpcCall**、只裸查 MySQL,会变成第二份查询实现;且 mcp.yaml **没有 Redis** | §8.2 | |
|
|
|
|
|
| 10 | cron 风险 = 多副本重复 | compose **无 replicas,当前单副本**;真实风险是**漏跑无补偿**,`state=0` 永远不动且不报错 | §5.3 | |
|
|
|
|
|
| 11 | 「报告生成要不要挂额度」 | 挂不了——既有额度全是「用户主动发起」语义,cron 主动生成扣额度不成立 | §12 待确认 1 | |
|
|
|
|
|
|
|
|
--- |
|
|
--- |
|
|
|
|
|
|
|
|
## 一、背景与目标 |
|
|
## 一、背景与目标 |
|
|
@ -360,6 +370,18 @@ CREATE TABLE memory_report ( |
|
|
**也就是说 `memory` 模块建表失败会让整站 502。** |
|
|
**也就是说 `memory` 模块建表失败会让整站 502。** |
|
|
`CreateTable` 失败必须只 `Errorln` 不外传。 |
|
|
`CreateTable` 失败必须只 `Errorln` 不外传。 |
|
|
|
|
|
|
|
|
|
|
|
⚠️ **路由已实测确认**:gateway 的 `/api/:param1/:param2` 里 **param1 就是服务名** |
|
|
|
|
|
(`this.module.Service().RpcCall(c, param1, comm.Rpc_GatewayHttpRoute, ...)`), |
|
|
|
|
|
param2 进 `args.MsgName`。所以模块挂进 `home` 之后 `/api/home/memory_list` 直接命中, |
|
|
|
|
|
不需要在网关加任何映射。客户端在 `api.dart` 里照现有写法加静态方法即可 |
|
|
|
|
|
(全是 `NWMethod.post` + `/api/home/xxx`)。 |
|
|
|
|
|
|
|
|
|
|
|
⚠️ **ErrorCode 要新开一段**(v0.2 补,文档原先没提)。`errorcode.proto` 的约定是分段编号 + 中文注释: |
|
|
|
|
|
3001-3006 支付、4001 会议、5001-5005 实名、5101-5103 翻译。 |
|
|
|
|
|
memory 建议占 **5201-** 段(如 `MemoryCategoryInvalid` / `MemoryItemNotFound` / |
|
|
|
|
|
`MemoryReportNotReady`)。别复用 `ReqParameterError` 一把梭——客户端要靠码分流 |
|
|
|
|
|
(比如「报告还没生成好」应该是转圈重试,不是弹错)。 |
|
|
|
|
|
|
|
|
⚠️ 照抄时注意 `allhelp/model.go` 那段是**有 bug 的反例**: |
|
|
⚠️ 照抄时注意 `allhelp/model.go` 那段是**有 bug 的反例**: |
|
|
|
|
|
|
|
|
```go |
|
|
```go |
|
|
@ -477,13 +499,35 @@ App 启动/切前台 |
|
|
|
|
|
|
|
|
**`stop()` 必须真的能打断**——`TtsService` 接口已有该方法,且 `speakStream` 是队列式播放,停止时要连带清队列,否则会出现「关了还在念下一句」。 |
|
|
**`stop()` 必须真的能打断**——`TtsService` 接口已有该方法,且 `speakStream` 是队列式播放,停止时要连带清队列,否则会出现「关了还在念下一句」。 |
|
|
|
|
|
|
|
|
⚠️ **启动路径上的弹窗已经有两个了(v0.2 新增)**,本弹窗是第三个,必须排在最后: |
|
|
⚠️⚠️ **`memory_today` 绝不能 await 在 splash 里**(v0.2 全局复核新增,方向与项目刚做的优化相反)。 |
|
|
|
|
|
|
|
|
|
|
|
仓库 `6a64c3d0`「把两处网络请求移出启动与设备页的关键路径」刚刚确立了相反的方向: |
|
|
|
|
|
`_performParallelTasks` **名字叫并行、实际完全串行**,冷启动要串等 |
|
|
|
|
|
网络检查 → 版本检查 → `getLoginToken` → `getAppConfig` 四次网络往返 |
|
|
|
|
|
(原本还有第五次 `_initMeetingTemplate`,理由是「启动时没有任何地方要用它」,**已改成 `unawaited`**)。 |
|
|
|
|
|
其中版本检查与 token 校验之间的串行是**刻意的**(强更弹窗必须先出、把 splash 卡住),不能动。 |
|
|
|
|
|
|
|
|
|
|
|
在这条链上再挂一次 `memory_today` 就是把刚摘掉的成本原样加回来,而且这次摘不掉—— |
|
|
|
|
|
弹窗要用它的数据。**正确做法是不挂**: |
|
|
|
|
|
|
|
|
|
|
|
``` |
|
|
|
|
|
splash 照常在 token 校验后放行导航 → 进主页 |
|
|
|
|
|
主页挂载后异步拉 memory_today(unawaited)→ 拿到再弹窗播报 |
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
弹窗晚一两秒出现是可接受的;启动多等一次往返不可接受 |
|
|
|
|
|
(同一份取舍在设备页那处已经做过一次:「首次连接的新耳机会晚一两秒才出现在列表里, |
|
|
|
|
|
这是『页面立刻可见』的必然结果」)。 |
|
|
|
|
|
|
|
|
|
|
|
⚠️ **顺序上仍然排在第三**,只是「排队」不等于「阻塞启动」: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 顺序 | 弹窗 | 位置 | |
|
|
| 顺序 | 弹窗 | 位置 | |
|
|
|---|---|---| |
|
|
|---|---|---| |
|
|
| 1 | 华为/荣耀「每次启动重新确认隐私政策」 | `login_controller._initDeviceInfo()` | |
|
|
| 1 | 华为/荣耀「每次启动重新确认隐私政策」 | `login_controller._initDeviceInfo()` | |
|
|
| 2 | 强制更新弹窗(不可关闭,会把 splash 卡住) | splash `_performVersionCheckAsync` | |
|
|
| 2 | 强制更新弹窗(不可关闭,会把 splash 卡住) | splash `_performVersionCheckAsync` | |
|
|
| 3 | **每日事项弹窗** ← 新增 | 应在 token 校验通过、进入主页之后 | |
|
|
| 3 | **每日事项弹窗** ← 新增 | 进入主页之后异步拉取、拿到再弹,**不阻塞导航** | |
|
|
|
|
|
|
|
|
排在强更前面会出现「强更窗盖住播报窗、TTS 在背后念」。 |
|
|
排在强更前面会出现「强更窗盖住播报窗、TTS 在背后念」。 |
|
|
**判据:必须等 `_validateTokenAsync` 通过**——未登录时 `memory_today` 拿不到数据。 |
|
|
**判据:必须等 `_validateTokenAsync` 通过**——未登录时 `memory_today` 拿不到数据。 |
|
|
@ -491,6 +535,14 @@ App 启动/切前台 |
|
|
⚠️ **TTS 会和通话翻译抢音频通道**。用户在通话翻译进行中切回前台时不要触发播报, |
|
|
⚠️ **TTS 会和通话翻译抢音频通道**。用户在通话翻译进行中切回前台时不要触发播报, |
|
|
先看 `TranslationController` 的活动状态。这条不做,会在通话里突然插一段「今天有 3 件事」。 |
|
|
先看 `TranslationController` 的活动状态。这条不做,会在通话里突然插一段「今天有 3 件事」。 |
|
|
|
|
|
|
|
|
|
|
|
具体一点:原生 `AzureTtsHelper.swift` 按 `currentRecognitionMode` 分支, |
|
|
|
|
|
`phone_call` 那一支**「被改坏过三次」**(见 `80c6ea1b` 的提交说明与代码注释: |
|
|
|
|
|
外放/听筒/A2DP 路由三次绕回同一个坑,现在按有没有耳机分两支, |
|
|
|
|
|
且分支口径必须与采集侧 `MicrophoneCapture` 的 voice-processing 条件一致)。 |
|
|
|
|
|
播报走的是 `normal` 支、不碰那段代码,**但它们共用同一个 `AVAudioSession`**—— |
|
|
|
|
|
通话翻译进行中触发播报,等于在对方刚调好的会话上再设一次。 |
|
|
|
|
|
**判据只有一个:通话翻译活动期间一律不播报**,不要试图去协调两边的会话配置。 |
|
|
|
|
|
|
|
|
### 5.3 周报/月报生成(需求 4/5)→ **服务端 cron + 异步队列** |
|
|
### 5.3 周报/月报生成(需求 4/5)→ **服务端 cron + 异步队列** |
|
|
|
|
|
|
|
|
照搬 [echomeet/tasks.go](../apps/services/modules/echomeet/tasks.go) 的成熟模式 |
|
|
照搬 [echomeet/tasks.go](../apps/services/modules/echomeet/tasks.go) 的成熟模式 |
|
|
@ -531,6 +583,24 @@ lego cron(在 memory 模块 Start 中注册) |
|
|
`import "yunyan/sys/doubao"` 是历史债:绕过了后台编排,海外应用会去调国内豆包, |
|
|
`import "yunyan/sys/doubao"` 是历史债:绕过了后台编排,海外应用会去调国内豆包, |
|
|
后台换模型也换不掉它。新模块不要再复制这个写法。 |
|
|
后台换模型也换不掉它。新模块不要再复制这个写法。 |
|
|
- 客户端下次打开时 `memory_getreport` 拉取 → 弹窗播报 → 用户确认 → `memory_confirmreport`。**不做「凌晨推送叫醒用户」**。 |
|
|
- 客户端下次打开时 `memory_getreport` 拉取 → 弹窗播报 → 用户确认 → `memory_confirmreport`。**不做「凌晨推送叫醒用户」**。 |
|
|
|
|
|
|
|
|
|
|
|
⚠️ **真正的风险是漏跑,不是重复(v0.2 全局复核修正)**: |
|
|
|
|
|
`docker-compose.yml` 里**没有 `replicas` / `deploy:` 段,当前就是单副本**, |
|
|
|
|
|
所以「多副本重复生成」是前瞻性风险(锁还是要加,部署形态会变),但不是现在会发生的事。 |
|
|
|
|
|
**现在就会发生的是漏跑**:00:30 那次跑到一半容器重启,cron 到点才触发、**不补跑**, |
|
|
|
|
|
于是 `memory_report` 那行永远停在 `state=0`,用户那一周永远没有报告,**且不报任何错**。 |
|
|
|
|
|
|
|
|
|
|
|
**必须有补偿**,照 echomeet 的思路做客户端驱动的兜底(它的 `PollTranscribe` 就是这么解决 |
|
|
|
|
|
「转写回调丢了」的;`allhelp/summary.go` 没做,那是它的缺陷不是范例): |
|
|
|
|
|
|
|
|
|
|
|
``` |
|
|
|
|
|
memory_getreport 被调用时: |
|
|
|
|
|
state=0 且 create_time 超过 N 分钟 → 重新 LPush 入队 |
|
|
|
|
|
state=1 且 update_time 超过 N 分钟 → 判定 worker 已死,重置 state=0 再入队 |
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
⚠️ `timer` 模块的 `timer_uselog`(`cron.AddFunc("1 1 0 * * ?")`)**零防重、零补偿**, |
|
|
|
|
|
靠 Redis `Del` 巧合幂等,日志还用 `fmt.Println`。**不是可照抄的范例。** |
|
|
- ⚠️ **积压要有上限**:用户一个月不开 App 会攒下 4 份周报 + 1 份月报。 |
|
|
- ⚠️ **积压要有上限**:用户一个月不开 App 会攒下 4 份周报 + 1 份月报。 |
|
|
`memory_getreport` 不传 period 时**只返回最近一份未确认的**,其余在拾忆页留个入口自己翻, |
|
|
`memory_getreport` 不传 period 时**只返回最近一份未确认的**,其余在拾忆页留个入口自己翻, |
|
|
不要连弹 5 次。 |
|
|
不要连弹 5 次。 |
|
|
@ -591,7 +661,60 @@ amount = item.amount // expense 分类 |
|
|
在换源后仍然需要——服务端返回的是记忆项原始行,日历要按天摊开。这段逻辑直接留用, |
|
|
在换源后仍然需要——服务端返回的是记忆项原始行,日历要按天摊开。这段逻辑直接留用, |
|
|
只是输入从 `AssistantReminder` 换成 `MemoryItem`。 |
|
|
只是输入从 `AssistantReminder` 换成 `MemoryItem`。 |
|
|
|
|
|
|
|
|
### 6.3 助手提醒的迁移 |
|
|
### 6.3 ⚠️ 拾忆页现在是**纯展示页**,写操作 UI 一个都没有(v0.2 全局复核新增) |
|
|
|
|
|
|
|
|
|
|
|
这是本设计**最大的工作量遗漏**。逐个查证过(`todo_tab.dart` / `todo_scope_list.dart` / `calendar_card.dart`): |
|
|
|
|
|
|
|
|
|
|
|
| 文档里假定存在的 | 实际 | |
|
|
|
|
|
|---|---| |
|
|
|
|
|
| §6.2「下拉刷新」 | 全页 **没有 `RefreshIndicator`,没有 `onRefresh`** | |
|
|
|
|
|
| 闭环全景「手动录入(拾忆页 +)」 | **没有 `FloatingActionButton`,没有 `Icons.add`**,页面没有任何新增入口 | |
|
|
|
|
|
| §4 的 `memory_complete`(勾完成) | 卡片**没有 `onTap`**——全页唯一的 `onTap` 是范围切换 Tab(`controller.setScope`) | |
|
|
|
|
|
| §4 的 `memory_update`(改期)、`memory_del` | 同上,没有编辑/删除入口 | |
|
|
|
|
|
| §3.3 `user_edited` 的整个设计前提「用户勾过改过」 | 用户**当前无法勾也无法改** | |
|
|
|
|
|
|
|
|
|
|
|
也就是说:**10 个服务端接口里有 4 个写接口在客户端没有任何调用点**, |
|
|
|
|
|
而 `user_edited` / `gen_round` 这套「保护用户修改」的机制在没有编辑 UI 之前**完全是空转的**。 |
|
|
|
|
|
|
|
|
|
|
|
一期必须补的交互(分期表 #6 原来只写了「分类筛选、换源、删 mock」,漏了这一整块): |
|
|
|
|
|
|
|
|
|
|
|
1. 卡片 `onTap` → 详情/编辑弹层(改标题、改期、改金额、删除) |
|
|
|
|
|
2. 卡片左侧 checkbox 或左滑 → `memory_complete` |
|
|
|
|
|
3. 页面右下 `+` → 新增(按分类分流:待办/闹钟/灵感/花销四种表单) |
|
|
|
|
|
4. `RefreshIndicator` 包住列表 → 重新 `memory_list` |
|
|
|
|
|
5. 空态页(删掉 mock 之后无数据用户看到的第一屏) |
|
|
|
|
|
|
|
|
|
|
|
⚠️ 另外两处小问题顺手一起收:`TodoTab` 的 `slogan: 'sloganHome'.tr` 还是**首页**的标语; |
|
|
|
|
|
`ensureCalendarController()` 定义在 `todo_tab.dart` 但**全仓无人调用**(两个 binding 都用 `lazyPut`),是死代码。 |
|
|
|
|
|
|
|
|
|
|
|
### 6.4 与网络层/生命周期的对接(v0.2 补,两条都别踩) |
|
|
|
|
|
|
|
|
|
|
|
**(1) 业务错误会自动弹红条,启动路径上的接口必须先加抑制名单。** |
|
|
|
|
|
[auth_interceptor.dart](../apps/client/lib/data/services/network/auth_interceptor.dart) 的 `onResponse`: |
|
|
|
|
|
|
|
|
|
|
|
``` |
|
|
|
|
|
code == 0 → response.data = entity.data ?? {} 然后 resolve |
|
|
|
|
|
code != 0 → response.data = null,next(response),并 Get.snackbar(红色, entity.message) |
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
抑制名单 `_shouldSuppressBusinessErrorSnackbar` 里现在**只有** `user_getinfo` 和 `user_binddevice`。 |
|
|
|
|
|
`memory_today` / `memory_upcoming` 是**启动与前台恢复时自动调**的,一旦返回业务错误, |
|
|
|
|
|
用户什么都没点就先吃一条红条(消息还是后端的英文内部状态词)。**这两个接口要加进名单**, |
|
|
|
|
|
页面改用行内空态/错误态表达。 |
|
|
|
|
|
(`NoLogin` 类消息已被 `_isNotLoggedInMessage` 按内容兜底挡掉,这部分不用管。) |
|
|
|
|
|
|
|
|
|
|
|
⚠️ **`code==0` 且 data 为空时拿到的是 `{}` 不是 `null`**。所以在 MemoryService 里 |
|
|
|
|
|
`resp == null` 只可能是业务错误,`{}` 是「成功但没数据」——两者含义相反,别合并判断 |
|
|
|
|
|
(同 `BesDeviceAuth` 踩过的那个坑)。 |
|
|
|
|
|
|
|
|
|
|
|
**(2) 前台恢复钩子已经有了,别再挂第四个 `WidgetsBindingObserver`。** |
|
|
|
|
|
[app_lifecycle_manager.dart](../apps/client/lib/core/utils/app_lifecycle_manager.dart) 是 |
|
|
|
|
|
`GetxService with WidgetsBindingObserver`,在 `initial_binding.dart` 里 `permanent: true` 注册, |
|
|
|
|
|
暴露 `AppLifecycleState` 的 Rx。§5.1 的「前台恢复重排通知」和 §5.2 的「切前台判断今天弹过没」 |
|
|
|
|
|
一律订阅它。仓库里已经有 `emai_controller` / `translation_controller` / `permissions_controller` |
|
|
|
|
|
三个各自实现的 observer 了,再加一个没有意义。 |
|
|
|
|
|
|
|
|
|
|
|
### 6.5 助手提醒的迁移 |
|
|
|
|
|
|
|
|
`AssistantDirectiveService` 保留(它是**指令流水日志**,有独立价值:排查、统计百炼下发了哪些没实现的指令),但: |
|
|
`AssistantDirectiveService` 保留(它是**指令流水日志**,有独立价值:排查、统计百炼下发了哪些没实现的指令),但: |
|
|
|
|
|
|
|
|
@ -602,7 +725,7 @@ amount = item.amount // expense 分类 |
|
|
上传走同一个 `client_key` 幂等键(用本地 reminder 的 id), |
|
|
上传走同一个 `client_key` 幂等键(用本地 reminder 的 id), |
|
|
这样即使标记丢了、重装了,重复上传也不会插重 |
|
|
这样即使标记丢了、重装了,重复上传也不会插重 |
|
|
|
|
|
|
|
|
### 6.4 花销录入与小票(v0.2 补) |
|
|
### 6.6 花销录入与小票(v0.2 补) |
|
|
|
|
|
|
|
|
上传链路已经就绪,不需要新建:客户端 `user_getuploadurl` 拿预签名 PUT URL → dio 直传 OSS。 |
|
|
上传链路已经就绪,不需要新建:客户端 `user_getuploadurl` 拿预签名 PUT URL → dio 直传 OSS。 |
|
|
要做的只有两件: |
|
|
要做的只有两件: |
|
|
@ -738,6 +861,23 @@ delete from memory_item |
|
|
2. 用户类工具**忽略参数里的 uid**,一律用会话 uid;解不出会话 uid 直接返回错误,不降级; |
|
|
2. 用户类工具**忽略参数里的 uid**,一律用会话 uid;解不出会话 uid 直接返回错误,不降级; |
|
|
3. 存量三个工具(`get_user_tasks`/`allhelp_task`/`cancel_user_task`)同步改。 |
|
|
3. 存量三个工具(`get_user_tasks`/`allhelp_task`/`cancel_user_task`)同步改。 |
|
|
|
|
|
|
|
|
|
|
|
⚠️ **还有一个架构问题:MCP 工具会让查询逻辑变成两份(v0.2 全局复核新增)。** |
|
|
|
|
|
`mcp` 是**独立进程独立服务**,它的工具直接裸查库—— |
|
|
|
|
|
`mysql.Table(comm.TableAllhelpTask).Where("uid = ?", uid)...`(见 `tool_get_user_tasks.go`), |
|
|
|
|
|
**全模块搜不到一次 `RpcCall`**,从不向 home 转发。 |
|
|
|
|
|
所以「5 个新工具」= memory 的过滤条件、分类白名单、权限规则在两个进程各写一遍, |
|
|
|
|
|
改了 home 那边 MCP 不会跟着变,**漂移了也不报错**(EMAI 只是答得不对)。 |
|
|
|
|
|
|
|
|
|
|
|
两条出路,**一期就要选**: |
|
|
|
|
|
- **A(推荐)**:MCP 工具经 RPCX 调 home 的 `memory` 模块。`mcp` 本就是 rpcx 集群服务, |
|
|
|
|
|
gateway 的 `RpcCall(c, "home", ...)` 就是现成写法,只是 mcp 模块从没这么用过。 |
|
|
|
|
|
- **B**:把查询逻辑抽进一个共享包(`comm` 或 `modules/memory/query`),两边都调同一份。 |
|
|
|
|
|
|
|
|
|
|
|
⚠️ 另外 **`mcp.yaml` 只配了 mysql,没有 redis、没有 postgres** |
|
|
|
|
|
(注释原文:「mcp 仅用业务库读写 allhelp_task / user 表」)。 |
|
|
|
|
|
任何基于 Redis 的限流、缓存、幂等在 MCP 侧**都不可用**——选 B 时尤其要注意, |
|
|
|
|
|
选 A 则天然规避。 |
|
|
|
|
|
|
|
|
**新增工具(`ToolGroup_GLOBAL`)**: |
|
|
**新增工具(`ToolGroup_GLOBAL`)**: |
|
|
|
|
|
|
|
|
| 工具 | 描述 | 回答什么问题 | |
|
|
| 工具 | 描述 | 回答什么问题 | |
|
|
@ -861,6 +1001,9 @@ mysql.Delete(comm.TableMemoryReport, "uid=?", uid) |
|
|
| 4 | `General-Meeting` zh-CN 模板第四节改造 | 后台配置 | |
|
|
| 4 | `General-Meeting` zh-CN 模板第四节改造 | 后台配置 | |
|
|
| 5 | `MemoryService` + `MemoryItem` 模型(含 `client_key` 幂等) | 客户端 | |
|
|
| 5 | `MemoryService` + `MemoryItem` 模型(含 `client_key` 幂等) | 客户端 | |
|
|
| 6 | `CalendarEventCategory` 扩到 4 类 + **未知分类兜底** + 分类筛选 + `_rebuildEvents` 换源 + 删 mock 与 40 个 demo key | 客户端 | |
|
|
| 6 | `CalendarEventCategory` 扩到 4 类 + **未知分类兜底** + 分类筛选 + `_rebuildEvents` 换源 + 删 mock 与 40 个 demo key | 客户端 | |
|
|
|
|
|
| 6b | **写操作 UI 全套**:卡片 onTap 编辑层、勾完成、`+` 新增(四种分类表单)、`RefreshIndicator`、空态页(§6.3,原分期表漏了这一整块) | 客户端 | |
|
|
|
|
|
| 6c | `memory_today`/`memory_upcoming` 加进红条抑制名单;前台恢复复用 `AppLifecycleManager`(§6.4) | 客户端 | |
|
|
|
|
|
| 6d | 选定 MCP 取数方式(RPCX 调 home / 抽共享包),一期定下免得三期返工(§8.2) | 后端 | |
|
|
| 7 | 助手 `SET_clock` 改写服务端(带 `client_key`) | 客户端 | |
|
|
| 7 | 助手 `SET_clock` 改写服务端(带 `client_key`) | 客户端 | |
|
|
|
|
|
|
|
|
**验收**:开一次会 → 纪要生成 → 待办自动出现在拾忆页日历上,标注来源会议与负责人; |
|
|
**验收**:开一次会 → 纪要生成 → 待办自动出现在拾忆页日历上,标注来源会议与负责人; |
|
|
@ -901,7 +1044,10 @@ mysql.Delete(comm.TableMemoryReport, "uid=?", uid) |
|
|
| 高 | **i18n 管道本身在漏**:40 个语言只有 1 个不缺 key,其余缺 233~388 个;审计工具结构上不检查缺失 key | 先给 `i18n_audit.py` 加缺失检查并接 CI,否则新增 30~50 个 key 会同样漏掉大半(§2.3) | |
|
|
| 高 | **i18n 管道本身在漏**:40 个语言只有 1 个不缺 key,其余缺 233~388 个;审计工具结构上不检查缺失 key | 先给 `i18n_audit.py` 加缺失检查并接 CI,否则新增 30~50 个 key 会同样漏掉大半(§2.3) | |
|
|
| 高 | **相对时间解析不准**(「下周三前」→ 具体日期) | 注入会议日期 + 服务端二次校验,宁可留空 | |
|
|
| 高 | **相对时间解析不准**(「下周三前」→ 具体日期) | 注入会议日期 + 服务端二次校验,宁可留空 | |
|
|
| 高 | **重新总结冲掉用户修改** | `user_edited` + `gen_round` 双字段 | |
|
|
| 高 | **重新总结冲掉用户修改** | `user_edited` + `gen_round` 双字段 | |
|
|
| 高 | **cron 多副本重复生成报告** | Redis `SET NX EX` 分布式锁 | |
|
|
| 高 | **拾忆页没有任何写操作 UI**——4 个写接口无调用点,`user_edited` 机制空转 | 一期补齐编辑/勾完成/新增/下拉刷新/空态五件(§6.3),分期表 #6 已扩写 | |
|
|
|
|
|
| 高 | **报告漏跑无补偿**:容器重启后 cron 不补跑,`state=0` 永远不动、不报错 | `memory_getreport` 里做超时重新入队(§5.3);当前单副本,重复反而不是现实风险 | |
|
|
|
|
|
| 高 | **MCP 工具会造成第二份查询实现**,两边漂移不报错 | 一期选定走 RPCX 调 home(推荐)或抽共享包(§8.2) | |
|
|
|
|
|
| 中 | cron 多副本重复生成报告(**当前单副本,前瞻性风险**) | Redis `SET NX EX` 分布式锁 | |
|
|
| 高 | **注销漏删新表** | §9.2,与建表同一个 PR 提交 | |
|
|
| 高 | **注销漏删新表** | §9.2,与建表同一个 PR 提交 | |
|
|
| 中 | 端侧指令重试导致重复插入 | `client_key` 幂等键 + 唯一索引 | |
|
|
| 中 | 端侧指令重试导致重复插入 | `client_key` 幂等键 + 唯一索引 | |
|
|
| 中 | 老客户端遇到新分类崩页 | 一期就发未知分类兜底 | |
|
|
| 中 | 老客户端遇到新分类崩页 | 一期就发未知分类兜底 | |
|
|
@ -909,7 +1055,12 @@ mysql.Delete(comm.TableMemoryReport, "uid=?", uid) |
|
|
| 中 | `cancelAll()` 误杀录音前台通知 | 提醒占固定 id 区间,逐条 cancel | |
|
|
| 中 | `cancelAll()` 误杀录音前台通知 | 提醒占固定 id 区间,逐条 cancel | |
|
|
| 中 | LLM 算错金额 | 统计全部走 SQL,LLM 只组织文案;小票识别结果必须回显确认 | |
|
|
| 中 | LLM 算错金额 | 统计全部走 SQL,LLM 只组织文案;小票识别结果必须回显确认 | |
|
|
| 中 | 多一路 LLM 调用增加成本 | 输入用 `summary` 而非全文;失败不重试 | |
|
|
| 中 | 多一路 LLM 调用增加成本 | 输入用 `summary` 而非全文;失败不重试 | |
|
|
|
|
|
| 高 | **每日弹窗把网络往返加回启动关键路径**——与 `6a64c3d0` 刚做的优化方向相反 | `memory_today` 进主页后 `unawaited` 拉取,拿到再弹,不阻塞导航(§5.2) | |
|
|
| 中 | 启动弹窗打架(隐私 / 强更 / 每日播报) | 固定顺序,每日弹窗排最后且在登录态之后 | |
|
|
| 中 | 启动弹窗打架(隐私 / 强更 / 每日播报) | 固定顺序,每日弹窗排最后且在登录态之后 | |
|
|
|
|
|
| 中 | **启动路径接口报错会自动弹红色 snackbar**(AuthInterceptor 默认行为) | `memory_today`/`memory_upcoming` 加进 `_shouldSuppressBusinessErrorSnackbar`(§6.4) | |
|
|
|
|
|
| 中 | **ErrorCode 复用 `ReqParameterError` 会让客户端无法分流**(如「报告还没生成好」该重试而非弹错) | 新开 5201- 段(§4) | |
|
|
|
|
|
| 中 | MCP 侧没有 Redis,限流/缓存/幂等都用不了 | 走 RPCX 调 home 可天然规避(§8.2) | |
|
|
|
|
|
| 低 | `IsSign` 时间戳防重放(`ts <= lastts` 即拒)与拾忆页并发请求冲突 | 当前所有 yaml 都没配 `IsSign`(默认 false),不影响;若将来开启需改成串行或每请求独立 ts | |
|
|
| 中 | **周报的「周一凌晨」是容器固定的北京时间**,纽约用户的周报在他本地周日中午就生成,漏掉周日下半天 | 接受并写进说明,或按 `tz` 分批触发(§5.3) | |
|
|
| 中 | **周报的「周一凌晨」是容器固定的北京时间**,纽约用户的周报在他本地周日中午就生成,漏掉周日下半天 | 接受并写进说明,或按 `tz` 分批触发(§5.3) | |
|
|
| 中 | **「上周」起始日因地区而异**(ISO 周一起 vs 美国周日起) | 明确统一成 ISO 并在 UI 说明,不要留着不定义 | |
|
|
| 中 | **「上周」起始日因地区而异**(ISO 周一起 vs 美国周日起) | 明确统一成 ISO 并在 UI 说明,不要留着不定义 | |
|
|
| 中 | **多币种花销无法合计**,且客户端硬编码 `¥` | 一期只支持单一货币;月报多币种分行列出,不做汇率换算(§3.3) | |
|
|
| 中 | **多币种花销无法合计**,且客户端硬编码 `¥` | 一期只支持单一货币;月报多币种分行列出,不做汇率换算(§3.3) | |
|
|
@ -923,9 +1074,16 @@ mysql.Delete(comm.TableMemoryReport, "uid=?", uid) |
|
|
|
|
|
|
|
|
### 待确认 |
|
|
### 待确认 |
|
|
|
|
|
|
|
|
1. **周报/月报的成本与额度**——每人每周一次 LLM 调用,用户量上来就是纯支出,而项目里 |
|
|
1. **周报/月报的成本控制——但「挂额度」这条路走不通**(v0.2 复核后修正)。 |
|
|
翻译/会议/AI 对话都各有额度桶(`Tradeintegral`/`Meetintegral`/`Aichatintegral`)。 |
|
|
项目里既有的额度扣减**全是「用户主动发起」语义**: |
|
|
报告生成要不要挂额度或 VIP 门槛?目前设计是**所有人免费生成**,需要确认这是有意的。 |
|
|
`echomeet/api_starttask.go` 先 `if user.Meetintegral < seconds` 再 `-=`,失败时 |
|
|
|
|
|
`tasks.go` 里 `+=` 退还;`user/api_usages.go` 的 `Aichatintegral -= 1` 同理。 |
|
|
|
|
|
而周报是 **cron 主动生成的,用户什么都没做**——扣他额度语义上不成立, |
|
|
|
|
|
而且失败退还、余额不足时"报告不生成"要怎么告诉用户,都没有合理的交互位置。 |
|
|
|
|
|
**更合理的三个选项**:① 不挂,当作平台成本(当前设计); |
|
|
|
|
|
② 按 VIP 等级决定生成频率(免费用户只有月报、VIP 才有周报); |
|
|
|
|
|
③ 只给「上周期有 N 条以上记录」的活跃用户生成(§5.3 已有「只给有数据的用户生成」,把阈值调高即可)。 |
|
|
|
|
|
**③ 成本最可控且不需要新概念,建议默认选它。** |
|
|
2. **拾忆页要不要走实名闸门**——现在所有功能卡片都按 `IdVerifyGuard.blocked()` 拦。 |
|
|
2. **拾忆页要不要走实名闸门**——现在所有功能卡片都按 `IdVerifyGuard.blocked()` 拦。 |
|
|
拾忆是底部 tab,整页拦不合适;但语音录入走 EMAI,EMAI 已被拦,等于游客只能手动录。 |
|
|
拾忆是底部 tab,整页拦不合适;但语音录入走 EMAI,EMAI 已被拦,等于游客只能手动录。 |
|
|
要确认这个不对称是可接受的。 |
|
|
要确认这个不对称是可接受的。 |
|
|
|