Skip to content

Repository files navigation

Recorder — 本地离线录音转文字

中文 | English

Windows and Linux CI

一个本地运行的录音转文字桌面 App:macOS 可安装为双击 App,Windows/Linux 提供源码引导安装与启动脚本。 全程离线,不调用任何云 API,音频与文字都不出本机。

以转写准确性为根基,之上提供三种专业模式:

模式 场景 产出
通用转写 会议、访谈、自言自语、任意音频文件 忠实原文的逐字稿(中英混合自动识别)
课堂录音 空旷、有回声、老师离得远、旁边有人闲聊 降噪 + 只留主讲人的逐字稿 + 自动重点总结
雅思口语教官 教官与考生一对一练习(中英夹杂) 区分教官/考生 + 疑似读音/语法/表达问题标注 + 反馈报告

代码主体在 lecture_intel/(历史目录名,App 名为 Recorder)。


为什么再做一个转写 App

市面上的录音转文字应用有一个共同的默认行为:它会悄悄把你说错的话改对。 语法修好、句子理顺、口音抹平——对"记录会议内容"是优点,对"我想知道我说得 怎么样"是灾难,因为诊断价值恰恰在那些错误里。

Recorder 的第一原则是:

任何模式都不改写说话人的措辞选择。说错的原样保留。

需要提示的地方(读音存疑、语法问题、中式表达)只做标注,不动正文。 可选的本地大模型增强也只在"听不清导致的转写错字"上工作,不做润色改写。

边界同样要说清:Whisper 解码时本身就会丢弃部分语气词(上游 faster-whisper#901、whisper.cpp#965 报告后均未修复)。50 条评测集实测 (TTS 合成、large-v3 通用模式):英文填充词召回 92%、中文 90%, 半截话保留 100%;丢失以吞掉(如 "er"/"呃")或误写近音字("嗯"→"恨")为主, 均属上游解码固有损耗。详情与决策门见 lecture_intel/eval/README.md。

课堂模式是唯一会清理正文信号的模式,且清理一律留痕:降噪参数与门控 决策、被剔除的时间区间、被折叠的疑似循环,全部写入输出目录的 meta.json—— 每条都可回查,原话永远在标注里。通用与雅思模式对疑似伪影只标注、不动正文。


核心特性

  • 完全离线。Whisper 模型跑在本机,首次下载后可以断网使用。没有账号、没有上传。
  • Apple Silicon GPU 加速。默认 mlx-whisper(Metal);不可用时自动回退 faster-whisper(CPU)。纯 CPU 推理依赖已按平台整理,CPU 设备的自动档使用 small 模型,且支持预下载后离线运行。
  • 跨平台与加速后端:Windows/Linux 的核心、GUI 离屏测试和上传音频转录 smoke test 已加入 GitHub 托管 runner。App/CLI 已接入可选 whisper.cpp Vulkan(兼容的 Intel/AMD GPU)和 Intel OpenVINO GPU;未配置或未能确认 GPU 执行时回退 faster-whisper CPU。真实 GPU 验收通过自托管硬件 workflow 执行,在对应 Intel/AMD 作业通过前 不宣称 GPU 已实机验证。Apple Silicon 使用 MLX/Metal;Intel Mac 使用 CPU。见 GPU 后端实测指南。
  • 中英混合(code-switching)不偏科。中文段落保持中文、英文段落保持英文, 不会被"翻译"成单一语言(实现见下方"工程要点")。
  • 录音来源:各平台支持麦克风和已有音频文件;系统声音链路已接入 macOS (ScreenCaptureKit)、Windows(WASAPI loopback)和 Linux(PipeWire/PulseAudio monitor)。 macOS 的电脑内部声音及麦克风混录可直接使用;Windows/Linux 的系统声音仍需在对应真机上 播放声音并确认生成的 WAV 非静音后,才能视为验收通过。
  • 逐词置信度始终开启——这是雅思模式识别"疑似发音问题"的依据。
  • 长录音稳。2 小时录音在 16GB 机器上按静音分块处理,内存有界、进度真实。
  • 崩溃安全。转写在独立子进程中运行,即使模型进程被系统杀掉,界面不会崩、 已录下的音频不会丢。
  • 导出 txt / md / docx,带时间戳与说话人标签;json 导出附带忠实度标注;旧版 .doc 转换仅 macOS 可用。
  • 深浅色主题,跟随系统。
  • 可选本地大模型(Ollama)。装本机后可做校对 / 课堂总结 / 雅思点评;按语言选用模型。
    选型与安装见 lecture_intel/docs/LLM_MODELS.md。

采集保真

  • 麦克风按 48 kHz / 16-bit / 单声道 裸 PCM 采集。擦音(s/sh/th/f)的对立频段在 8 kHz 以上,16 kHz 采集会在录音瞬间永久丢失它们——而"疑似读音问题"诊断恰恰依赖这些 频段。一切降采样只发生在派生副本上(引擎内部归一化到 16 kHz 供 ASR),输出目录里的 original.wav 终身保持采集原样,并带 SHA-256 哈希。
  • macOS 麦克风模式(菜单栏麦克风图标/控制中心可选 标准 / 语音突显 / 宽谱):建议保持 标准。要验证当前模式的影响,用同一句话分别在两种模式下各录一段,对比两个输出目录的 original.wav 即可(语音突显的 DSP 会改变信号,诊断场景以标准模式为准)。
  • 蓝牙耳机慎用于发音诊断:进入 HFP 通话模式后硬件只输出 16 kHz,且其回声消除/降噪 DSP 不可关闭。要诊断发音,请用有线或模拟麦克风。
  • 每个输出目录自带 meta.json:原始音频哈希、处理链逐步参数(归一化、降噪门控、仲裁、 剔段)、导出文件哈希——逐字稿可证明来自哪版音频。

三种模式细节

通用转写

加载 → 整文件转写 → 导出。中英自动识别,逐字忠实。

课堂录音

ffmpeg 预处理(高通去低频隆隆 + 自适应降噪 + 响度归一,按噪声底门控,参数与决策写入 meta.json)→ 转写 → 疑似重复仲裁(真口吃保留,确认伪影才折叠,原话留在标注)→ 说话人聚类后只保留说话时长最长的主讲人(被剔除区间写入 meta.json)→ 自动提取重点(强调句式、定义句、高频术语、讲解最久的片段)生成 *.summary.md。

雅思口语教官

转写 → 免 token 的两人分离(声纹嵌入 + 聚类,自动判定教官/考生, 界面可一键对调)→ 分析 → 反馈报告。

分析包含四类,全部只标注不改写:

  1. 疑似读音问题:Whisper 逐词置信度异常低的词——声学模型"没听准"的地方, 通常就是读不清、读错或口音偏差的词。已做多重降噪处理(跳过段首伪影、 过滤常用词、要求词长 ≥4)以减少误报。
  2. 语法问题:时态、主谓一致、冠词等;本机有 LanguageTool 服务时用它, 否则走内置规则。
  3. 表达问题:中式英语、搭配不自然。
  4. 教官的纠正:教官现场给出的正确说法,作为参考一并列出。

最后按雅思四项维度(流利度与连贯 / 词汇 / 语法 / 发音)汇总成报告, 报告里嵌入完整逐字稿。


快速开始

需要 Python 3.10+ 与 ffmpeg。进入 lecture_intel/ 后按平台安装:

macOS

uv venv
uv pip install -r requirements.txt
./make_app.sh                    # 安装到 /Applications/Recorder.app

Windows(PowerShell)

powershell -NoProfile -ExecutionPolicy Bypass -File .\install_windows.ps1 -DownloadCpuModel
powershell -NoProfile -ExecutionPolicy Bypass -File .\run_windows.ps1

Linux

bash install_linux.sh --download-cpu-model
./run_linux.sh

Windows/Linux 当前发布形式是源码引导安装,不是签名的独立可执行安装包。已有音频文件上传转录 在各平台共用同一离线流水线;系统声音采集的 Windows/Linux 真机验收不由 CI 的编译和 --capabilities 检查替代;系统声音采集仍需对应设备的真机播放和非静音 WAV 验收。 Vulkan/OpenVINO 的真实 GPU 状态见验收指南。

预下载模型(推荐,尤其是国内网络)

cd lecture_intel
.venv/bin/python3 download_models.py     # 走 hf-mirror.com 镜像,落到本地模型目录

模型分三档,界面里可选:最准 large-v3 / 均衡 large-v3-turbo / 最快 small。下好之后运行时完全不联网。

窗口收窄(紧凑档)时模型下拉只显示图标,对应含义:🎯 = 最准(一箭中靶心)、 ⚖️ = 均衡(天平)、⚡ = 最快(闪电);展开下拉仍是完整名称,收起态悬停也有完整名称的提示。

命令行(无界面)

.venv/bin/python3 transcribe.py 录音.m4a                    # 通用
.venv/bin/python3 transcribe.py 课堂.mp3  -m classroom       # 课堂
.venv/bin/python3 transcribe.py 雅思.webm -m ielts           # 雅思反馈
.venv/bin/python3 transcribe.py a.wav --model large-v3-turbo -f txt -f docx
.venv/bin/python3 transcribe.py 讲座.m4a -l ja               # 指定语言(默认自动检测)

语言选择器列出 13 种语言(中/英/日/韩/法/德/西/乌克兰/阿/泰/越/印尼/印地语), 但**「自动检测」不限于此**——Whisper 本身支持 100 种语言(mlx-whisper 与 faster-whisper 实测为同一张语言表), 列表之外的语音照常识别转写,只是无法在界面或命令行手动指定。

支持 m4a / mp3 / wav / webm / flac / aac / ogg / opus。

输出位置

第一次点「开始转写」会弹一次保存位置确认框(就像浏览器下载那样):默认落在你 git 下来 / 解压的那个文件夹下的 output/—— 路径在运行时向上找 .git 定位,所以每个人都是自己的目录,不写死任何人的本机路径。 从已安装的 App 启动、周围没有仓库时,退回 ~/Documents 下的数据目录, 绝不默认写到 ~/Library/Application Support 或 /Applications 这类系统目录——用户不会去那儿找自己的文件。 确认后按录音文件名建子文件夹存放结果。选择会被记住,之后不再弹;要改用菜单「文件 → 更改输出文件夹…」, 随时查看用「显示输出文件夹」。命令行默认写到音频旁边的 <文件名>_output,可用 -o 指定。

可选:本地大模型增强

装了 Ollama 之后可在界面打开「AI 增强」:修正听不清导致的错字、生成课堂总结、补充雅思考官点评。关掉则走离线规则。模型跑在本机,权重不要提交进 Git。

「不改写」的边界:主转写逐字忠实、永不改写;可选 AI 增强只额外生成一份校对版(补标点、修识别错别字),原文文件保持不变;说话人自己的语言错误只被标注,不被修改。

默认路由:中文录音推荐 Qwen(qwen3 / qwen2.5:7b),其余语言默认 Mistral; 候选链只收可在 Ollama 下载的大语言模型(Ollama 库中目前不存在可下载且真能喂音频的多模态大语言模型,而本 App 本就不向 Ollama 送音频)。 这只是默认值,具体装哪个、装多大由你自行选择。未安装 Ollama 或没装任何匹配模型时,增强自动跳过。安装步骤、内存档位与中国镜像见:

lecture_intel/docs/LLM_MODELS.md


架构

lecture_intel/
├── app.py                GUI 入口(双击目标)
├── transcribe.py         CLI 入口
├── make_app.sh           构建并安装 /Applications/Recorder.app
├── download_models.py    Whisper 模型预下载(镜像直连)
├── docs/LLM_MODELS.md    硬件档位 × Ollama(Qwen/Mistral)选型
│
├── core/                 引擎
│   ├── engine.py         唯一编排入口:run(input, output, mode)
│   ├── modes.py          general / classroom / ielts 三套参数预设
│   ├── transcriber.py    Whisper 封装(mlx → faster-whisper 回退、分块、逐词置信度)
│   ├── provenance.py     meta.json 留痕:原始哈希、处理链逐步参数、导出哈希
│   ├── repeat_arbitration.py  口吃 vs ASR 循环三级仲裁(时间轴 → silencedetect → 孤立重解码)
│   ├── denoise.py        ffmpeg 降噪(课堂,噪声底门控)
│   ├── diarize.py        免 token 说话人分离(声纹嵌入 + 聚类 + 时序平滑)
│   ├── ielts.py          发音 / 语法 / 表达分析与报告
│   ├── classroom.py      重点提取与总结
│   ├── llm.py            可选的本地 LLM 增强(Ollama)
│   ├── sysaudio.py       系统内录驱动
│   ├── runner.py         子进程执行器(崩溃隔离)
│   ├── paths.py          用户数据目录(唯一真源)
│   └── export.py         txt / md / doc / docx 导出
│
├── gui/                  PySide6 界面(首页 / 录音 / 处理 / 结果 + 主题)
├── native/               SystemAudioRecorder.swift(ScreenCaptureKit 内录)
├── dictionaries/         课堂术语词典(旧流水线存档,core 引擎未接入)
└── tests/                无需模型即可跑的单元测试(python -m pytest)

数据流:

音频 →[课堂: 降噪]→ 按静音分块转写(GPU) →[分离说话人 / 只留主讲人]
     →[雅思分析 | 课堂总结]→ 导出

工程要点

这些是把"能跑"做到"准且稳"过程中真正起作用的决定:

整文件送 Whisper,而不是自己切 30s 小段。 早期版本先用 VAD 切段再逐段转写,切口处丢词、重叠处重复、上下文断裂。 Whisper 自带 30s 窗口与跨窗上下文,直接喂整段最准。超长音频只在静音处 分大块,不在句子中间下刀。

分块 + 逐块语言检测,解决中英混说。 单次全局语言判定会把少数语言"翻译"掉(英文模式吃掉中文,中文模式吃掉英文)。 按静音切块后每块独立检测语言,中英各自保真,同时仍然全程在 GPU 上跑。

分块也顺带解决了内存与进度。 2 小时录音不再构建一张巨图(16GB 机器不会 OOM),进度条按块推进, 不会卡在某个百分比不动。转写幻觉产生的重复循环由专门的抑制逻辑收敛。

转写跑在子进程,不是线程。 模型编译时递归很深,会撑爆工作线程的小栈;应用退出时若线程仍在运行会直接 abort。改成 multiprocessing 子进程 + 主线程轮询结果队列后:子进程崩溃只是 子进程崩溃,界面照常、录音文件安全,退出时直接终止子进程即可。

说话人分离不用需要授权令牌的方案。 改用声纹嵌入 + 层次聚类,两人场景足够。同性别声音在声学上常常分不开, 因此加了一层语言混合回退:当声学分离明显失衡、且某段的语言不是考生语言时, 按语言归属分配角色(雅思考生一律答英文,说其他语言的即教官)——中文、日文、 韩文、俄文、泰文教官已用真实音频验证可分,这一步才让教官/考生分离真正可用。 法/德/西这类与英文同用拉丁字母的教官尚未可靠:逐块语种只在每个静音块恰好 只含一种语言时才够用,而真实会话的 60 秒块常混两种语言;且声学分离成功时, 角色判定(_candidate_score)目前还不看段语种。两点均已建任务跟踪。

系统内录自己写 WAV。 ScreenCaptureKit 给出的是非交错 Float32,AVAudioFile / 转换器都拒绝处理, 于是 Swift 侧手动反交错成交错 Int16 并手写 WAV 头。需要一次性授予"屏幕录制" 权限,未授权时界面会给出明确指引。

打包不用 py2app / PyInstaller。 把 torch、mlx 冻进 bundle 体积巨大且脆弱。改为构建一个轻量 .app 启动器, 指向安装好的运行副本;依赖照常可以升级。由于 macOS TCC 会阻止 Finder 启动的 App 读取 ~/Documents,安装脚本会把可运行副本与虚拟环境放到 ~/Library/Application Support/Recorder,从那里启动,真正做到双击即开。


开发历程

项目从 2026 年 5 月做到 7 月,大致五个阶段:

时间 阶段
2026-05-07 ~ 05-17 雅思口语批改原型:语法 / 自然度 / 发音规则 + FastAPI 接口(backend/)
2026-05-30 ~ 06-01 转向课堂录音,搭起 11 步流水线(modules/ + pipeline.py)
2026-06-13 ~ 06-14 推倒重来:mode 驱动的 core/ 引擎,整文件转写取代自切 VAD 段;子进程隔离崩溃
2026-06-18 ~ 06-20 系统内录、深浅色主题、用户数据目录统一
2026-07-05 ~ 07-07 界面改版为四屏,录音来源三选一

早期一直没有用 git 管理,2026-07-28 才导入版本库。因此所有提交的日期都是导入日期, 按上述阶段整理成 23 次提交,每条提交的正文里注明了它对应的原始开发时间。

多语种

规划分三步。当前状态:第 1、3 步已完成并经真实音频验证;第 2 步对中/日/韩/俄/泰 教官已验证可用,法/德/西等拉丁文教官尚未可靠。

  1. 统一语言设置(language)+ 语言工具层——不是单独做一个「检测 App」, 而是让后续分离角色、报告、模型路由有统一参数;
  2. 说话人分离去掉写死中文假设;
  3. 转写语言标签真正多语;再接分析。

实现要点:语言工具层在 core/languages.py,按 Unicode 文字系统判定语言 (假名→日语、谚文→韩语、汉字→中文;拉丁、西里尔、阿拉伯等被多种语言共用的文字 交给 Whisper 自己的检测结果区分),语言设置接入引擎、命令行(transcribe.py -l ja) 与界面「语言」选择器(默认自动检测,共 15 种常用语言)。教官角色判定以「非考生语言」 为准:日/韩/俄/泰教官按文字系统归属分角色,已用五种语言的真实音频逐一验证; 法德西等拉丁文教官要靠分块转写附带的逐块语种区分,实测尚不可靠——逐块语种 仅在单个静音块恰好只含一种语言时才足够,真实会话的 60 秒块常混两种语言, 且声学分离成功时角色判定(_candidate_score)尚未使用段语种(两点已建任务跟踪)。 可选的本地大模型增强(校对 / 课堂总结)按转写自身的语言下 prompt, 不再一律用中文指令;雅思教官点评报告保持中文说明(考生恒为英文作答,且界面为中文), LanguageTool 保持 en-US(诊断对象即考生英文)。中英混说的判定阈值与归属规则保持 不变。规划中的可选项——教官话对照翻译——暂未实现,需要时再议。

模型路由说明见 LLM 指南。

隐私

  • 模型与全部处理都在本机,没有任何网络请求(除首次下载模型)。
  • 录音与转写结果写入本地数据目录(见 core/paths.py),仓库不收录任何音频。
  • 可选的 LLM 增强走本地 Ollama,同样不出网。

开发

python -m pytest          # 仓库根目录运行,仅覆盖 lecture_intel/(默认验证层)
                          # backend/tests 为存档代码,不计入默认验证

改完代码后重新运行 lecture_intel/make_app.sh 同步到已安装的 App。

完整需求与取舍记录见 REQUIREMENTS.md。

目录说明

  • lecture_intel/ — App 主体(唯一在维护的代码)。改界面前请先读 lecture_intel/docs/GUI_DESIGN.md(必须保持的设计约定) 与 lecture_intel/docs/LLM_MODELS.md(本地大模型选型)。
  • aura_gui/、lecture_intel/gui_old/、pipeline.py、config.yaml 与 modules/ 中的课程分类 与结构化模块 — 被 core/ 引擎取代的早期实现,已于 2026-09-20 删除 (modules/audio_loader.py 与其中的数据类仍在使用,故 modules/ 目录保留; aura_gui/ 是界面改版的设计稿源本、早已合并进 lecture_intel/gui/,其设计意图已迁至 lecture_intel/docs/GUI_DESIGN.md)。
  • backend/ + frontend/ — 最早的 FastAPI 雅思批改原型,其分析思路 (发音置信度、语法规则、报告模板)已并入 lecture_intel/core/ielts.py, 保留仅作存档,可忽略。

许可

MIT

About

Offline macOS speech-to-text app with General, Classroom, and IELTS Speaking Coach modes. Faithful transcription—no rewriting. Mic + system audio capture, accelerated on Apple Silicon GPU. 本地离线运行的 macOS 录音转文字 App:通用 / 课堂 / 雅思口语教官三种模式,忠实原文不改写,支持麦克风与系统内录,Apple Silicon GPU 加速。

Topics

Resources

Stars

7 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages