# 语音转文字(STT)功能规格 **日期**: 2026-08-19 **状态**: 设计审批中 **范围**: cfc-langgraph(新增)+ cfc-frontend(改造) --- ## 背景与目标 小程序现有 diet/exercise/sleep 三个语音打卡页已实现录音功能(mp3 格式,`uni.getRecorderManager`),但录音仅上传保存,未做文字转写。本次新增 STT 能力,覆盖两个场景: 1. **打卡语音转文字**:录音后自动转写,文字直接保存至记录,用户无感知。 2. **AI 对话语音输入**:在聊天界面新增语音按钮,录音 → 转写 → 填入输入框 → 用户确认后发送。 --- ## 技术选型 | 项目 | 选型 | 理由 | |------|------|------| | STT 引擎 | faster-whisper 1.2.1 | 轻量(base 140MB),中文识别准确,Python 原生支持 | | 模型 | whisper-base(Systran/faster-whisper-base) | 中英混合识别,CPU 可用,内存 ~256MB(含模型) | | 模型下载源 | hf-mirror.com | 国内可访问,避免直连 HuggingFace 超时 | | 音频格式 | mp3(16kHz mono,WAV float32 内部处理) | 小程序录音输出 mp3,av 库解码 | | 部署方式 | 模型随镜像构建时缓存至 `.cache/`,无需运行时下载 | 避免容器启动慢 | --- ## 架构 ``` [小程序] mp3 录音 │ ▼ [langgraph] POST /api/v1/audio/transcribe │ body: multipart/form-data (file=audio.mp3) ▼ [faster-whisper base] → 转写文字(中文/英文自动检测) │ ▼ { text: "转写结果", language: "zh", duration: 3.2 } ``` **服务启动流程**: 1. FastAPI 启动 → `app/main.py` → 初始化 `WhisperModel('base')` 缓存至全局变量 2. 请求到达 `/api/v1/audio/transcribe` → 读取 mp3 → av 解码 → faster-whisper 转写 → 返回 JSON **模型缓存策略**: - 构建镜像时在 `COPY` 前用 `hf-mirror.com` 预下载模型到 `/root/.cache/huggingface/hub/models--Systran--faster-whisper-base/` - 或:启动时首次加载(约 95s),服务就绪前 healthcheck 返回不健康 --- ## 接口设计 ### 1. langgraph — 语音转写端点 **`POST /api/v1/audio/transcribe`** Request: ``` Content-Type: multipart/form-data file: audio.mp3 (≤30s,≤5MB) ``` Response: ```json { "code": 200, "message": "ok", "data": { "text": "今天早餐吃了鸡蛋和牛奶", "language": "zh", "language_probability": 0.98, "duration": 3.2 } } ``` 错误处理: - 文件为空/格式不支持 → `400` - 转写失败 → `500`,message 含原因 - 超时(>30s 音频) → `413` ### 2. frontend — 打卡页改造(diet/exercise/sleep-checkin.vue) 现有流程:录音 → 上传 mp3 → 保存 `voicePath` → 提交打卡 新增流程:录音 → **调 STT 转写** → 上传 mp3 + 保存 `voiceText` → 提交打卡 改动点: - `recorderManager.onStop` 回调中新增:调 `/api/v1/audio/transcribe` 获取文字 - 表单增加 `voiceText` 字段(隐藏,用于后端存储) - 后端新增字段接收 `voiceText`(`DietCheckinDTO` 增加 `voiceText: Optional[str]`) ### 3. frontend — AI 对话语音输入 在聊天输入框旁新增 🎙️ 按钮,按住录音,松手转写,文字填入输入框。 改动点: - 新增语音按钮组件(复用现有 `uni.getRecorderManager`) - 录音结束 → 调 STT → 结果写入 `this.inputText` - 用户确认后点击发送(与文字输入相同流程) --- ## 数据模型改动 ### backend(Java) `DietCheckinDTO` / `ExerciseCheckinDTO` / `SleepCheckinDTO` 增加字段: ```java private String voiceText; // 语音转写文字 ``` `GrowthRecordService` 新增字段映射(若统一用 `GrowthRecordDTO` 则一并增加)。 ### frontend(小程序) 打卡页表单增加 `voiceText` 字段,提交时携带。 --- ## 依赖变更 **cfc-langgraph/requirements.txt** 新增: ``` faster-whisper==1.2.1 av==18.1.0 ``` **cfc-langgraph/Dockerfile** 新增模型缓存步骤: ```dockerfile # 预下载 whisper base 模型(避免启动时慢下载) RUN HF_ENDPOINT=https://hf-mirror.com \ pip install faster-whisper==1.2.1 av==18.1.0 && \ python3 -c "from faster_whisper import WhisperModel; WhisperModel('base', device='cpu', compute_type='int8')" ``` **cfc-langgraph/.env.production** 无需新增(模型参数硬编码,不配置)。 --- ## 非功能性约束 - **模型加载时间**: ~95s(首次),后续请求 <100ms - **单次转写耗时**: 3 秒语音约 200-500ms(CPU base 模型) - **音频时长限制**: 最大 60 秒(与现有小程序录音 duration 一致) - **并发限制**: 单 worker 串行处理转写(避免多请求同时吃 CPU),预计 QPS ≤2 --- ## 实现顺序建议 1. **langgraph STT 端点** — 独立开发,单接口,测试通过 2. **frontend 打卡页接入** — 三页同步改造,复用同一上传逻辑 3. **frontend 对话语音输入** — 独立 UI 组件,最后接入 4. **backend DTO 字段增加** — 前后端联调时同步 --- ## 风险与缓解 | 风险 | 缓解 | |------|------| | 容器启动慢(模型加载 95s) | healthcheck 初始 delay 延长至 120s | | CPU 资源不足(base 模型内存 ~256MB) | 确认服务器 ≥512MB 内存可用 | | 转写准确率问题(background noise) | 后续可换 medium 模型,本次 base 够用 | | 音频格式兼容(mp3 vs wav) | av 库自动处理多格式 | --- ## 审批 - [ ] 架构设计确认 - [ ] 接口设计确认 - [ ] 依赖变更确认 - [ ] 实现顺序确认