Files
zyt/docs/plans/followup-audio-deployment.md
T

90 lines
9.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 回访录音提炼:实现与发布门禁
## 当前交付边界
源码在隔离工作副本 `/Users/long/.codex/worktrees/followup-audio/zyt`。原目录 `/Users/long/Work/zyt` 的已有源码保持不变;未提交、未推送、未迁移生产、未部署。入口默认关闭。
已完成网页患者编辑入口、诊单绑定私有分片上传、独立持久异步任务、Dify原始音频传递、可编辑审阅草稿、显式人工确认、多表原子写入、同日真实记录明细、历史跟踪备注、来源审核轨迹及90天清理。
**真实模型门禁仍未通过**:本地 qwen/openai 探针都真实执行并返回 `CONFIG_MISSING`,没有上传录音、没有产生已知模型调用。只能说明隔离环境未配置,不能推断生产Dify是否支持。媒体测试中的完整一小时WAV→MP3、HTTP回环模型和浏览器合成数据不是实际Dify识别验收;混合口音需代表性脱敏样例。
## 使用与数据规则
- 入口:网页问诊列表→编辑患者→回访录音。PC/H5共用现有编辑组件;桌面客户端不增加入口。
- 每次一个文件,MP3/M4A/WAV/AMR,最多500MiB/3600秒,按服务端实际元数据检查,2MiB分片。
- 原件只在 `server/runtime/private/followup_audio/`;播放需登录令牌请求头及患者权限。没有公开录音URL,没有伪造医生通话记录。
- AMR或超出上游预算的录音生成私有临时32kbps/16kHz单声道MP3,校验完整时长,不截断、不自动分段改语义;默认上游预算20MiB。原件保留不改,处理副本在成功或失败后清理。
- 通话时间采用北京时间,模型解释今天/昨天等;模糊范围需客服确认,不能自动随便取一天。时段缺钟点时早上08:00、中午12:00、下午15:00、晚上20:00、睡前22:00,明确标记估算并要求审阅。
- 同值不同测量保留不同记录;重复提及同一事件才合并。默认钟点相同不自动去重。相同诊单+音频SHA256+模型复用原任务,换文件名、上传ID或通话时间不绕过未知请求防重发;日期错误在审阅中修正,已采纳任务不重新写入。
- 字段、字典、身份锁、phonePlain和dailyRecord权限均在服务端校验。未提及不等于正常/无,不自动生成诊断或处方。病历当前值与历史记录分开选择。
- 草稿有版本和不可变来源证据。冲突刷新最新快照并取消选择,保留用户编辑供重新确认;不静默覆盖。原病历表单有未保存修改时不允许被录音结果覆盖。
- 确认写入使用一个事务(单次READ COMMITTED,不更改连接默认),锁定任务与真实记录,审计同事务,重复确认幂等。存在不明确的值可不采纳,不要求全部接受。
## 配置与运行前检查
1. 核对实际数据库字段/表前缀,先在线备份;经发布授权后应用 `server/sql/2026_09_29_followup_audio.sql`。SQL使用现有 `zyt_` 前缀,可重复执行;新增四表及血糖时间来源字段,不改旧数据。不得把测试库模拟schema当作生产已核验。
2. 使用 `server/.env.followup-audio.example`,继续复用现有 `[prescription_ai]` base URL/profile凭据。不要把生产数据库凭据复制到本地测试环境,不要把API密钥放前端或提交Git。
3. PHP8.2已做本地验证;需要curl/fileinfo/openssl、可执行FFmpeg/FFprobe。Web/worker用户都必须可读写同一个私有录音目录,目录不能放在public或公开存储域名下。部署多节点需共享私有存储和稳定加密密钥(至少32字符,离线备份),不要依赖各节点自动生成不同runtime key。
4. 反向代理/PHP单请求上限至少容纳2MiB分片及表单开销;不要将500MiB整个请求交给PHP上传。短期处理副本也要计入磁盘容量。
5. Dify存储副本/缓存的保留与删除策略另行核验;本系统90天删除不代表Dify侧已删除。现实现没有通用Dify远端删除凭证或删除API,不能作此承诺。
## 合成音频能力门禁
本地生成器仅接收输出目录,不接受患者录音;使用macOS `say`(默认Tingting)和FFmpeg/FFprobe。Linux消费者不需要say;可安全转移已生成合成夹具及清单。不要重新生成已有manifest或重发状态未确认的探针。
现成合成夹具:`/private/tmp/zyt-followup-audio-synthetic-gate/manifest.json`(60/900/3598秒,独立首尾口令和事实;预期答案只在本地manifest,不能放进提示词)。需要重建时使用新的输出目录:
```sh
cd /Users/long/.codex/worktrees/followup-audio/zyt
python3 scripts/generate_followup_audio_fixtures.py --output /private/tmp/followup-audio-new-synthetic-gate
cd server
php think followup-audio:probe --synthetic --manifest /private/tmp/zyt-followup-audio-synthetic-gate/manifest.json --profile qwen --case all
# 仅当另一个profile也准备供客服使用时,再单独验证openai。
```
必须核实真实音频被读取、首尾事实和数值/否定/时间关系、未截断长录音,再用获准的代表性脱敏口音样例人工回听评估。上传成功、HTTP200或纯文本回复都不是通过。探针有状态文件:已通过的case复用;结果未知先核对原Dify任务/账单,禁止自动重发。不要删除未知状态来强制重试。
只有验证通过的profile可加入 `VERIFIED_PROFILES`;人工核验通过后才设置 `AUDIO_VERIFIED=true`,经授权发布后再设 `ENABLED=true`。默认 `timestamp_verified=false`,不把LLM编出的毫秒位置当成ASR对齐。
## 独立消费者、清理与故障处理
```sh
# cwd为部署目录的server;用Supervisor/systemd管理,不在网页请求内跑模型。
php think followup-audio:work
php think followup-audio:work --once
php think followup-audio:cleanup
```
- 初始全局并发1,可通过CONCURRENCY配置1–8;独立数据库租约/互斥,不占用原处方队列。
- 600秒租约高于240秒请求预算,处理过程中续租。权限撤销、患者重绑、旧worker令牌均不得继续上传/回写。
- `needs_reconciliation` 表示请求可能已经被接收,不能自动/手动再次调用;请核对已保存上游IDs、任务和账单。现版本不提供绕过此状态的“强制重试”按钮。
- 经确认且允许重试的本地失败保留已有成果。模型不支持音频、结构校验失败或能力未验证,不得成功落诊单。
- 将cleanup纳入目标环境已批准的定时任务(本轮未安装定时任务)。90天起点为上传创建时间;清除原件、完整转写及可还原全文的分析副本,保留正式记录和必要采纳审计;活动租约不被清理,清理部分失败退出非零,便于监控。
- 关注队列等待时间、needs_reconciliation、失败码、租约恢复、磁盘和清理errors;日志不得包含录音内容、完整病历或凭据。
## 本地检查与回退
已有验证:真正隔离MySQL并发claim/create/apply、权限撤回/转派、单事务故障回滚;真实HTTP multipart和媒体处理;实际Vue组件测试;浏览器合成数据完成任务详情→草稿→确认采纳→刷新。完整网页构建通过,未执行发布脚本。全量vue-tsc在同一生成声明环境下基线和修改后均60条诊断,本功能文件0条,新诊断签名0。
```sh
cd /Users/long/.codex/worktrees/followup-audio/zyt
FOLLOWUP_AUDIO_TEST_ALLOW_DISPOSABLE=1 FOLLOWUP_AUDIO_TEST_MYSQL_PORT=23316 FOLLOWUP_AUDIO_TEST_MYSQL_PASSWORD=followup_audio_isolated_test php server/tests/FollowupAudioCoreTest.php
node --test admin/tests/followup-audio.test.cjs
node admin/scripts/verify-daily-records.cjs
```
数据库命令只允许一次性本地测试容器,禁止换为线上端口。测试容器连接信息是固定合成测试凭据,不是业务凭据。
发布回退先关闭入口并停止本功能消费者,保留旧静态资源和数据库备份。新增表/列应保留以保护审计;源码回退脚本只恢复源码,**不撤销已写入病历**。正式记录若需恢复,必须按审核轨迹和当前版本另做受控补偿,不能整库回滚覆盖其他人的新数据。
主交付四角色及源码回退验证位于 `/Users/long/Work/zyt/artifacts/followup-audio-20260929/`;补充研究、局部检查与未通过的真实模型门禁保留在工作副本 `artifacts/followup-audio-implementation/`。
## 2026-09-29 页面重整与提炼补测
- 页面改为“紧凑录音列表 → 摘要和分类结果表 → 单项核对弹窗”。上传和原文默认收起,已写入记录用只读文本;窄屏固定核对操作列,日期/估算标记仍可见。
- 在真实诊单抽屉组件、1440×1000视口、相同4项合成数据下,常驻输入控件从25个减至4个复选框,内容滚动高度从2802px减至852px;上传、取消单项编辑、分类不丢选择、草稿与确认写入均做了浏览器合成接口验证。它不是生产/真实模型识别证据。
- 独立补测发现并修复:临床语义候选不再因空字段而默认采纳;对家属/提问/否定/纠正等上下文强制人工复核。该规则是保守防守,不证明语言语义识别准确。
- 饮食早餐/午餐/晚餐提炼别名映射到实际`*_foods`字段,审阅读回、审计、现有日常表单编辑和提交保持一致,未选餐食及图片不清空;CSV合法值`0`不再被`empty()`抹去;医院诊断选项使用现有页面的三个静态枚举。
- 补测通过30条规则、16条防守和5条跨层检查,以及真实隔离MySQL113项检查。9个模型语义案例仍标注NOT_VERIFIED;真实Dify最新探针仍CONFIG_MISSING。不得把这些本地测试描述为真实ASR、方言或一小时录音识别已通过。
- 本次完整补测账本见工作副本`artifacts/followup-audio-implementation/extraction-acceptance-20260929.md`和`.json`,保留修复前结果、修复后结果及独立回滚证据。主四角色路径保持不变,本次记录追加到原验证记录。