# voice-caption **Repository Path**: yang_tao_code/voice-caption ## Basic Information - **Project Name**: voice-caption - **Description**: No description available - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-10-13 - **Last Updated**: 2026-10-13 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 实时悬浮字幕 · 声纹说话人判定(Windows 10/11) 读取麦克风中的环境人声 → 实时识别为文字 → 以半透明悬浮窗贴在桌面上 → 依据**声纹**自动判断每句话是谁说的,并打上 `人员A` / `人员B` 标签。 **全程本地运行,音频不出本机。** 纯 CPU 可用,不需要显卡。 ![悬浮字幕窗](docs/images/overlay.png) ![图形化设置界面](docs/images/settings-dialog.png) ## 目录 | 想干什么 | 看这里 | |---|---| | 装起来跑通 | [三、安装](#三安装) | | **改哪些参数开、哪些关** | [五、图形化设置界面](#五图形化设置界面推荐) · [docs/CONFIG.md](docs/CONFIG.md) | | 让字幕出得更快 | [5.4 想更快](#54-想更快) | | 让识别更准 | [5.3 想更准按这个顺序开](#53-想更准按这个顺序开) | | 出问题了 | [docs/TROUBLESHOOTING.md](docs/TROUBLESHOOTING.md) | | 改代码 / 看架构 | [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) | | 国内源 / 离线部署 | [docs/DEPLOY-WINDOWS.md](docs/DEPLOY-WINDOWS.md) | | 常见疑问 | [docs/FAQ.md](docs/FAQ.md) | | 版本变更 | [CHANGELOG.md](CHANGELOG.md) | --- ## 一、先看调研:Gitee 上有没有现成项目? **结论:有「实时悬浮字幕」,也有「ASR + 说话人分离」,但两者没有交汇——没有找到同时具备 「实时 + 悬浮窗 + 声纹区分说话人」的开源项目,因此本项目在现成能力之上自研整合。** ### 1. 实时字幕 / 悬浮字幕类(能悬浮,但**不做声纹**) | 项目 | 地址 | 技术栈 | 能力 | 缺什么 | | --------------------------- | ----------------------------------- | ----------------------- | ----------------------------------------------------------------------- | --------------- | | **LiveSub (TransFlow Pro)** | gitee.com/live-sub | Electron + React + Go | 系统/窗口音频捕获、实时字幕、**透明置顶悬浮窗**、多引擎(faster-whisper / 讯飞 / Azure / 腾讯)、LLM 翻译 | 无说话人区分 | | **LiveCaption** | gitee.com/zaneg/livecaption | Go + GoVcl | Windows 桌面字幕,系统/麦克风声音 → 阿里云实时 ASR | 依赖云 API;无声纹 | | **desktop_subtitle** | gitee.com/lukeewin/desktop_subtitle | Java 8 + Netty + JavaCV | 麦克风 → Paraformer-Streaming 流式识别 → 桌面字幕 | 无声纹;仅 JDK8 | | **speech-to-text-overlay** | GitHub: airjairj | Python + Vosk + tkinter | 实时悬浮字幕、多语言、可调样式、**纯离线** | 无声纹;Vosk 中文精度一般 | ### 2. ASR + 说话人分离类(有声纹,但**是离线批处理,不实时、不悬浮**) | 项目 | 地址 | 说明 | | --------------------------- | ------------------------------------------- | -------------------------------------------------------- | | **whisper-diarization** | gitee.com/ldyc/whisper-diarization | Whisper + VAD + Speaker Embedding,处理**已录好的文件**,出带说话人的转写稿 | | **MOSS-Transcribe-Diarize** | gitee.com/boomer001/MOSS-Transcribe-Diarize | 端到端 ASR+说话人分离 0.9B 模型,效果强,但需 GPU、面向长音频离线转写 | | **phpervip/speech-to-text** | gitee.com/phpervip/speech-to-text | Vosk(离线)/Whisper(在线) 双引擎,音视频转文字 | | **vosk-api** | gitee.com/zhao105/vosk-api | 流式离线 ASR,附带简单 speaker identification(x-vector,区分度弱) | | **WhisperLiveKit** | GitHub(非 Gitee) | 实时流式 + 说话人分离(Streaming Sortformer / Diart),最接近需求,但依赖较重生僻 | ### 3. 底层能力库(本项目的选择) | 库 | 地址 | 用途 | | -------------- | ------------------------------------------------- | ------------------------------------------------------------------------------------------ | | **FunASR** | gitee.com/tllgit/FunASR(GitHub 主仓 alibaba/FunASR) | 阿里达摩院工具包:`paraformer-zh-streaming` 流式中文 ASR、`fsmn-vad` 端点检测、`ct-punc` 标点、**`cam++` 说话人声纹** | | **ModelScope** | modelscope.cn | 模型下载源(国内直连快,无需 HuggingFace 网络条件) | ### 选型理由 - **不重复造轮子**:ASR 用 FunASR(中文识别 SOTA 梯队、工业验证、模型全部可从 ModelScope 国内直下); 声纹用 **CAM++**(7.2M 参数、5 万小时训练、192 维 embedding,CPU 上毫秒级)。 - **为什么不用现成悬浮字幕项目**:LiveSub 是 Electron+Go 全栈工程,直接改成带声纹的实时管线, 改动量比自己搭一个 Python 管线更大;LiveCaption / desktop_subtitle 依赖云 API 或 Java 栈,不满足「离线 + 声纹」。 - **因此本项目只做「整合 + 悬浮窗」这部分增量**,把最强的国内可用能力串起来。 --- ## 二、系统架构 ``` 麦克风 (16kHz / 单声道 / float32) │ sounddevice 回调 → 无锁队列 ▼ ┌───────────────────────────┐ │ 能量 VAD(动态噪声底) │ 判断「有没有人在说」 │ pre-roll 200ms 防吃字头 │ └───────────┬───────────────┘ │ 一段完整语音 ┌───────────┴───────────────┐ │ paraformer-zh-streaming │ ← 流式:边说边出字(600ms 粒度) │ 每 100ms 喂一次,实时上屏 │ └───────────┬───────────────┘ │ 句尾定稿 + 该段音频 ┌───────────┴───────────────┐ │ CAM++ 声纹 embedding │ │ 余弦相似度 → 声纹库比对 │ │ 未注册则在线聚类 │ └───────────┬───────────────┘ │ 说话人标签 ┌───────────┴───────────────┐ │ PySide6 悬浮窗 │ │ 无边框 / 置顶 / 半透明圆角 │ │ [人员A] 文本… │ └───────────────────────────┘ ``` **线程模型**:采集(PortAudio 实时线程)→ 处理(`caption-worker` 线程)→ UI(Qt 主线程)。 跨线程只通过 Qt Signal 投递,UI 永不阻塞。 --- ## 三、安装 ### Python 要求 **需要 Python 3.10 ~ 3.13**(推荐 3.12 / 3.13)。两个常见坑: - **不要用 Microsoft Store 版 Python**。它装在 `...\WindowsApps\` 下,`where python` 找得到, 但执行时是空壳,会让 `python -m venv` 静默失败。请从 [python.org](https://www.python.org/downloads/windows/) 下载官方安装包,安装时勾选 **Add python.exe to PATH**。 - **3.14 及以上暂时不行**:torch 2.6 尚无对应版本的轮子。 不确定就直接双击 `setup.bat`——它会自己探测(含常见安装目录扫描), 找不到会打印诊断信息指出差在哪。本机 Python 没进 PATH 也可以手动指定: ```bat setup.bat D:\你的python目录\python.exe ``` ### 方式 A:一键脚本(推荐) ```bat :: 双击运行,自动建 .venv 并安装(已内置阿里云镜像) setup.bat ``` ### 方式 B:手动 ```bat python -m venv .venv .venv\Scripts\python.exe -m pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/ ``` > **镜像实测(本机,同一 torch wheel 2MB 分段请求)** > > | 源 | 实测速度 | 备注 | > | ------------------------------------ | ------------ | ------------------------ | > | 阿里云 `mirrors.aliyun.com/pypi` | **556 KB/s** | ✅ 采用 | > | 腾讯云 `mirrors.cloud.tencent.com/pypi` | 305 KB/s | | > | 清华 `pypi.tuna.tsinghua.edu.cn` | 149 KB/s | ⚠ 对 pip 请求返回 **403**,不可用 | > | 华为云 `repo.huaweicloud.com` | 133 KB/s | | > > 脚本已固定使用阿里云。换环境可改 `setup.bat` 中的 `-i` 参数。 ### 模型准备(约 870MB,仅需一次) | 模型 | 文件 | 大小 | 作用 | | ------------------------------------- | ------------------------ | --------- | ------ | | `paraformer-zh-streaming` | `model.pt` | **880MB** | 流式中文识别 | | `speech_campplus_sv_zh-cn_16k-common` | `campplus_cn_common.bin` | 28MB | 说话人声纹 | 两种获取方式,任选其一: **方式 1(推荐,可控且有断点续传)** —— 下到项目内 `data/models/`,程序会自动优先使用: ```bat :: 只先拿 27MB 的声纹模型,几秒到几分钟 .venv\Scripts\python.exe scripts\download_models.py campplus :: 再拿 880MB 的识别模型(网慢也没关系,Ctrl+C 后重跑会从断点继续) .venv\Scripts\python.exe scripts\download_models.py asr :: 查看本地模型状态 .venv\Scripts\python.exe scripts\download_models.py --check ``` **方式 2(省事)** —— 什么都不做,首次 `run.bat` 时由 FunASR 自动从 ModelScope 拉到 `~/.cache/modelscope/hub/`。缺点是断网后要重来,且不受项目控制。 > 实测环境:ModelScope 单线程下载约 100~~150 KB/s,880MB 大约需要 1.5~~2 小时, > 建议挂着跑或换到带宽更好的网络。声纹模型只有 28MB,可以先下它把声纹链路跑通。 --- ## 四、使用 ### 0. 自检环境 ```bat run.bat --list-devices :: 列出麦克风,拿到设备序号 .venv\Scripts\python.exe scripts\selftest.py --full ``` **没有麦克风也能先验证**: ```bat :: 把悬浮窗渲染成图片,先看样式对不对 .venv\Scripts\python.exe scripts\preview_overlay.py :: 用现成 wav 验证流式识别链路(会打印逐段增量文本和 RTF) .venv\Scripts\python.exe scripts\offline_asr.py 某个音频.wav :: 验证声纹区分能力(用 CAM++ 自带示例:同一人两段 vs 另一个人) .venv\Scripts\python.exe scripts\verify_speaker.py :: 端到端:用真实音频跑完 ASR + 声纹聚类,并生成悬浮窗截图 preview_live.png .venv\Scripts\python.exe scripts\demo_overlay.py ``` `verify_speaker.py` 会打印余弦相似度矩阵,并判断「同人相似度 > 异人相似度」是否成立, 同时给出建议阈值 —— 这是判断你的声学环境/麦克风能否支撑声纹区分的最快方式。 ### 1. 直接开始(自动分配说话人) ```bat run.bat ``` 不认识的人会被自动命名为 `人员A`、`人员B`…(在线聚类模式)。 ### 2. 指定麦克风 / 关闭声纹 ```bat run.bat --device 2 run.bat --no-speaker ``` ### 3.(可选,精度更高)预先录入声纹 想固定认出「张三」「李四」,先各录 5 段: ```bat .venv\Scripts\python.exe scripts\enroll.py 人员A --device 1 .venv\Scripts\python.exe scripts\enroll.py 人员B --device 1 .venv\Scripts\python.exe scripts\enroll.py --list ``` 声纹文件存在 `data/speakers/<名字>.npy`,启动时自动加载; 注册过的人在 `enroll` 模式下不会有「未知」,在 `cluster` 模式下会优先匹配已注册声纹。 ### 交互操作 | 操作 | 效果 | | ----------------------- | ------------------- | | 鼠标拖拽字幕窗 | 移动位置(可在设置里关闭) | | `Ctrl` + 滚轮 | 调整字号(可在设置里关闭) | | 托盘图标双击 | 显示 / 隐藏字幕窗 | | 托盘右键 → **设置…** | 打开图形化设置窗口,**保存即生效** | | 托盘右键 → 重新载入 config.json | 手改过配置文件后热重载 | | 托盘右键 → 退出 | 退出程序 | > 悬浮窗设了 `WindowDoesNotAcceptFocus`(否则会抢焦点、打断你正在输入的东西), > 所以它**收不到键盘事件**,`Esc` 退不出,请用托盘菜单退出。 --- ## 五、图形化设置界面(推荐) 托盘右键 → **设置…**(或 `python app\main.py --settings`)打开。**保存即生效**: 只改字幕窗外观会立刻刷新;改了音频 / 识别 / 断句 / 声纹才会重载模型,而且会等旧线程 真正退出后再新建,不会出现两份模型同时占内存。 ### 5.1 七个标签页 | 标签页 | 能开关什么 / 能调什么 | | ----------- | -------------------------------------------------------------------- | | **预设 / 状态** | 三套一键预设;实时显示「首字上屏延迟 / 定稿延迟」估算;四个模型的就绪状态与按需下载 | | **语音识别** | `启用语音识别`、流式分块、编解码器回看、推理设备、ITN、段末释放缓存、**二次精修**、**标点恢复** | | **语音检测** | `启用断句`、`自适应噪声门限`、自适应倍数、固定阈值、静音判定、最短语音、前置缓冲、最长片段 | | **声纹说话人** | `启用声纹判定`、模式、相似度阈值、最短判定时长、最大人数、**后台判定** | | **音频输入** | `启用音频采集`、麦克风设备、采样率、音频块长、增益 | | **字幕窗** | 显示说话人标签 / 状态文字 / 允许拖动 / Ctrl+滚轮 / 超时清理;字号、行数、不透明度、圆角、位置、边距、停留时间、占位文字 | | **文本纠正** | `启用文本纠正`、内置词表、折叠重复,自定义「错词=>对词」词表(带实时预览) | ### 5.2 三套预设:延迟 ↔ 准确率 | 预设 | 流式分块 | 静音定稿 | 首字上屏 | 适合 | | ------ | ----- | ----- | -------- | ------------- | | 极速 | 360ms | 320ms | 约 420ms | 直播跟读,要求“边说边出” | | 均衡(默认) | 480ms | 600ms | 约 580ms | 日常会议 | | 高准确 | 960ms | 900ms | 约 1060ms | 事后要把字幕当会议记录 | > 首字上屏 ≈ 分块 + 音频块长,**不含 CPU 推理时间**。本机(i7-6700HQ)实测流式 > RTF≈0.44(比实时快约 2.3 倍,3 次重复 0.434 / 0.435 / 0.440),推理本身不是瓶颈, > 所以**延迟主要取决于分块大小**。 > > 反过来说:**如果 CPU 被别的程序占满,RTF 会劣化到 1.0 以上**(实测出现过 1.03), > 那时字幕就会跟不上说话。测延迟前先确认机器是空闲的。 ### 5.3 想更准,按这个顺序开 1. **专有名词用词表**(最划算):人名、公司名、产品名写进「文本纠正」页,一行 `错词=>对词`。 实现是单遍正则替换,长词优先,替换结果不会被后续规则二次改写。 2. **二次精修**:段末用离线 `paraformer-zh` 整段重解码,替换**已定稿**的那一行。 实时上屏不受影响,所以**不牺牲及时性**。代价:848MB 磁盘 + 约 1.2GB 内存。 3. **标点恢复**:给整句补逗号句号,同样只作用于定稿行。283MB 磁盘 + 约 400MB 内存。 4. **预设切到「高准确」**:不花任何内存,代价是晚约 0.5 秒出字。 > 两个可选模型都在「预设 / 状态」页点「下载」(走国内 ModelScope 源,支持断点续传)。 > **不点下载就不会联网**;只勾开关没下模型,状态栏会提示缺模型并自动降级,不会偷偷下载。 ### 5.4 想更快 - 预设切「极速」; - 「音频块长」调到 60ms; - 关掉声纹判定(省一次 CAM++ 推理); - 保持「后台判定」勾选 —— 关掉它会让声纹判定卡在识别线程里,拖慢**下一句**的上屏。 ### 5.5 命令行等价物 ```bat .venv\Scripts\python.exe app\main.py --settings :: 启动并直接打开设置窗 ``` 设置写回 `config.json`(原子写入:先写 `.tmp` 再替换,手改的其它键会保留)。 --- ## 六、参数调整(`config.json`,也可全用图形界面) | 字段 | 默认 | 说明 | | ----------------------------- | --------- | ----------------------------------------------------------------------------- | | `audio.block_ms` | 100 | 每次交给识别线程的音频粒度。调小上屏更平滑,60ms 是「极速」预设值 | | `vad.enabled` | true | 关掉=不再按静音切句,一直连续识别 | | `vad.adaptive` | true | 自适应噪声门限:门限 = max(固定阈值, 底噪 × `adaptive_factor`) | | `vad.energy_threshold` | 0.012 | 固定下限阈值。**环境嘈杂就调大,说话轻就调小** | | `vad.silence_ms` | 600 | 静音多久算一句话结束,直接决定**定稿延迟**。调小=切句快但易断句 | | `vad.min_speech_ms` | 300 | 短于此的片段直接丢弃(防咳嗽、敲键盘出字幕) | | `vad.max_segment_s` | 18 | 单句最长时长,超时强制出稿 | | `asr.chunk_size` | `[0,8,4]` | 流式分块,`[0,8,4]`=480ms。**这是延迟与准确率最主要的旋钮** | | `asr.encoder_chunk_look_back` | 4 | 编码器回看块数,调大更准更慢 | | `asr.use_itn` | true | 数字 / 单位规范化(“二零二六年”→“2026年”) | | `asr.cache_trim` | true | 段末释放推理缓存,长会话内存不缓慢上涨 | | `asr.two_pass` | false | 二次精修(需先下载 848MB 离线模型,多占约 1.2GB 内存) | | `asr.punc` | false | 标点恢复(需先下载 283MB 模型,多占约 400MB 内存) | | `speaker.enabled` | true | 关掉=全部标「说话人」,且省掉 CAM++ 模型的内存 | | `speaker.threshold` | 0.55 | 声纹相似度阈值。**认错人调高,认不出调低**。CAM++ 实测同人≈0.69、异人≈0.01,0.55 附近最稳;设成 0.72 会把同一个人拆成两个人 | | `speaker.mode` | `cluster` | `cluster` 自动分配人员A/B…;`enroll` 只认已注册的人 | | `speaker.async_label` | true | 声纹在独立线程判定,定稿先上屏、标签随后回填 | | `speaker.max_speakers` | 6 | 最多区分几个人 | | `textfix.rules` | `[]` | 自定义纠错词表,元素形如 `"错词=>对词"` | | `overlay.*` | — | 字号 / 行数 / 不透明度 / 位置 / 停留时间 / 各界面开关,见第五节 | --- ## 七、目录结构 ``` voice-caption/ ├── app/ │ ├── main.py 入口:托盘 + 悬浮窗 + 线程桥接 + 设置入口 │ ├── bootstrap.py 启动引导:强制 Qt 先于 torch 加载(Windows 必需) │ ├── config.py 配置加载 / 保存 / 预设 │ ├── settings_dialog.py 图形化设置窗口(7 个标签页) │ ├── audio_capture.py 麦克风采集 │ ├── asr_engine.py FunASR 流式识别 + 离线二次精修 + 标点恢复 │ ├── speaker_id.py 声纹提取 / 声纹库 / 说话人判定 │ ├── pipeline.py VAD 分段 + 主调度 + 后台后处理 │ ├── textfix.py 识别结果纠正(纠错词表 / 重复折叠) │ ├── model_hub.py 模型下载(ModelScope 国内源,断点续传) │ └── overlay.py PySide6 悬浮字幕窗 ├── scripts/ │ ├── enroll.py 声纹录入 │ ├── selftest.py 环境自检 │ ├── patch_funasr.py FunASR 兼容性补丁 + 依赖体检(幂等) │ ├── download_models.py 模型下载(断点续传;`asr_offline` / `punc` 为可选大模型) │ ├── verify_speaker.py 用真实人声验证声纹区分能力 │ ├── offline_asr.py 用 wav 文件离线验证识别链路(不需要麦克风) │ ├── demo_overlay.py 真实音频跑通全链路并输出悬浮窗截图 │ └── preview_overlay.py 把悬浮窗渲染成预览图 ├── tests/ 自动化检查(都不需要麦克风) │ ├── verify_settings.py 设置界面 + 配置链路 + 模型完整性(59 项) │ ├── verify_apply.py 保存设置后的热应用判定(15 项) │ └── inspect_ui.py 离屏渲染设置窗/悬浮窗并输出截图 ├── tools/ │ └── build_wheelhouse.py 把依赖预下成离线轮子(国内源) ├── docs/ 架构 / 配置手册 / 部署 / FAQ / 故障排查 │ └── images/ 文档截图 ├── data/speakers/ 声纹库(*.npy) ├── data/models/ 本地模型(程序优先使用,不提交到仓库) ├── config.json 全部可调参数(图形界面写的就是它) ├── setup.bat / run.bat ├── requirements.txt ├── CHANGELOG.md └── LICENSE ``` > `data/models/`、`data/speakers/*.npy`、 `.venv/`、`artifacts/` 已在 `.gitignore` 中排除, > 仓库里**不放任何模型权重**(最大的是 840MB 的 `model.pt`,Git 不适合存这个)。 ## 八、Windows 环境踩坑记录(均为本机实测) 实测环境:Windows 10 / Python 3.13.14 / torch 2.6.0+cpu / funasr 1.4.16 / PySide6 6.12.0。 下面 6 个问题都会以「进程毫无提示地直接崩溃」的形式出现,排查成本很高,故记录于此。 其中第 2 项由 `requirements.txt` 锁版本解决,第 3 项由 `scripts/patch_funasr.py` 处理, 第 4 项已固化为 `app/bootstrap.py`,重装依赖后跑一次 `patch_funasr.py` 即可。 | # | 现象 | 根因 | 解法 | | | - | ---------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ | ------------------------------------------------------ | | 1 | `import torch` 报 `OSError [WinError 1114] c10.dll 初始化例程失败` | torch 2.7+ 的 Windows wheel 与本机运行时不兼容(用 pefile 核对过,依赖 DLL 一个不缺也没用) | 降到 `torch==2.6.0` + `torchaudio==2.6.0` | | | 2 | `import funasr` 直接段错误(EXIT=139) | `sentencepiece 0.2.2` 的 cp313 win_amd64 wheel 有缺陷,崩在模块初始化(`ctypes.WinDLL` 能加载、`import` 却崩) | `pip install sentencepiece==0.2.1` | | | 3 | 加载模型时 access violation,栈顶停在 `torch/storage.py clone` | funasr `load_pretrained_model()` 对 880MB 的 ckpt 做了一次**冗余深拷贝**,内存不足即崩 | `scripts/patch_funasr.py` 改成直接引用 | | | 4 | `import torch` 之后再 `import PySide6` 段错误 | torch 先把自己的 MSVC / Intel OpenMP 运行时拉进进程,Qt 的 DLL 随后加载发生冲突 | 让 Qt 先行;已固化为 `app/bootstrap.py` 的 `ensure_qt_first()` | | | 5 | 跑 `setup.bat` 满屏「`'--retries'` 不是内部或外部命令」,还夹着乱码 | **bat 文件是 UTF-8,而 cmd 按系统 ANSI(936) 解析 bat**,中文字节被误读后产生引号、竖线等元字符 → 引号不匹配 → 整段命令被吞、连 `echo` 都报外部命令 | bat 一律**存成 GBK(ANSI) + CRLF 换行**,且**不要加 `chcp 65001`** | | 6 | `setup.bat` 走到 `[2/6]` 报「创建虚拟环境失败,请检查 python 是否可用」 | PATH 里那个 `python` 是 **Microsoft Store 的占位程序**(`C:\Users\<你>\AppData\Local\Microsoft\WindowsApps\python.exe`)。`where python` 能列出它、退出码也是 0,但它执行时什么都不做,于是 `python -m venv` 静默失败 | setup.bat 不再只看 `where`,而是对每个候选**真的跑一次版本判断**;另加「常见安装目录扫描」和「排除 3.14」 | | > 第 5 条的规则务必遵守:`chcp` 只改**控制台输出**代码页,**改不了 cmd 解析 bat 文件所用的编码**。 > 所以「bat 里有中文」+「加 chcp 65001」= 中文乱码;正确做法是 bat 存 GBK、不加 chcp。 > 另外 `scripts/*.py` 里所有非 GBK 符号(`✔ ✅ ❌ ⚠ ↻` 等)已换成 ASCII 等价物, > 否则在原生 cmd 的 GBK 控制台下 `print` 会直接抛 `UnicodeEncodeError`。 第 4 条的对照实验: ``` import PySide6; import torch -> ✅ 正常 import torch; import PySide6 -> ❌ 段错误 KMP_DUPLICATE_LIB_OK=TRUE 亦无效 -> ❌ 段错误 ``` **本机验证结论** | 项 | 结果 | | ----------------------- | ------------------------------------------------------------------------------------------------- | | `selftest.py --full` | 全部通过(依赖 / 麦克风 / 模型加载 / 流式接口 / 声纹链路) | | `offline_asr.py` 真实中文语音 | 识别正确,**RTF ≈ 0.44**(3 次 0.434/0.435/0.440,5.55s 音频)。README 原来写的 **0.446 是对的**;CPU 被占满时会劣化到 1.0 以上 | | `verify_speaker.py` | 同人相似度 **0.6936**,异人 **0.0072**,区分度充足 | | `demo_overlay.py` 端到端 | 同一人两段正确聚类为 `人员A`,另一人正确标为 `人员B` | | 图形化设置界面 | 7 个标签页,**59 项**自动化检查全部通过(`tests/verify_settings.py`,离屏渲染,不需要麦克风) | | 设置热应用链路 | **15 项**检查全部通过(外观改动不重载模型 / 识别改动才重载 / stop→is_alive 握手,`tests/verify_apply.py`) | | `app\main.py` 常驻 | 两个模型加载完成、内存稳定在 2046MB、stderr 无 Traceback | --- ## 九、文档与自测 | 文档 | 内容 | |---|---| | [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) | 线程模型、`seg_id` 回调协议、Qt 必须先于 torch、内存预算 | | [docs/CONFIG.md](docs/CONFIG.md) | 全部配置项手册(含 `chunk_size` 换算表、词表写法) | | [docs/DEPLOY-WINDOWS.md](docs/DEPLOY-WINDOWS.md) | 国内源实测选型、代理陷阱、离线轮子、D 盘布局 | | [docs/FAQ.md](docs/FAQ.md) | 常见疑问 | | [docs/TROUBLESHOOTING.md](docs/TROUBLESHOOTING.md) | 按现象查故障(含 6 个"无提示崩溃") | | [CHANGELOG.md](CHANGELOG.md) | 版本变更 | 自动化检查(都不需要麦克风): ```bat :: 环境 / 模型 / 声纹链路 .venv\Scripts\python.exe scripts\selftest.py --full :: 设置界面 + 配置链路 + 模型完整性(59 项) .venv\Scripts\python.exe tests\verify_settings.py :: 保存设置后的热应用判定(15 项) .venv\Scripts\python.exe tests\verify_apply.py :: 离屏渲染设置窗和悬浮窗,产出截图到 artifacts/ .venv\Scripts\python.exe tests\inspect_ui.py ```