SpeakMore 是一个本地语音输入工具。Electron 负责桌面壳、固定快捷键、托盘、本地数据和结果交付;本地 FastAPI 后端负责音频转写和大模型文本处理。Windows 是当前稳定版,macOS 已支持本地 .app / DMG 构建,签名和公证仍需要发布凭证。
当前正式 ASR 模型只支持 FunAudioLLM/SenseVoiceSmall。发布包不内置模型;首次运行进入“初始化”页后,由用户点击下载并加载 SenseVoiceSmall,下载失败时会显示明确错误。
- Windows
Right Alt/ macOSOption:听写,结果自动粘贴;无法确认可信输入目标时显示悬浮面板。 - Windows
Right Alt + Space/ macOSOption + Space:自由提问,结果显示在悬浮面板,不自动粘贴;有可信选区时携带选区上下文。 - Windows
Right Alt + Right Shift/ macOSOption + Shift:语音翻译,结果粘贴到当前光标位置;无法确认可信输入目标时显示悬浮面板。 Escape:取消当前未完成语音会话,或关闭当前悬浮面板。- 录音时显示悬浮胶囊和麦克风音量。
- 主窗口包含初始化、首页、历史记录、词典和设置。
- 历史、设置、词典和自动学习候选只保存在本机。
自动粘贴必须先确认可信文本输入目标;不满足条件时显示悬浮卡片,不静默写剪贴板和发送粘贴快捷键。macOS 自动学习只在自动粘贴成功后短时观察本轮目标,选区上下文只服务自由提问。
Windows x64 当前生成解压即用 zip。macOS 当前可生成本地 .app、zip 和 DMG。发布包包含:
SpeakMore.exe或SpeakMore.app- Electron 运行文件
- 本地后端可执行文件
- Windows 文本观察 helper 或 macOS helper 源码
ffmpeg- Renderer 构建产物
模型不打包。首次运行需要联网下载 SenseVoiceSmall,Windows 默认缓存到 %LOCALAPPDATA%\Typeless\models\funasr,macOS 默认缓存到 ~/Library/Application Support/SpeakMore/models/funasr。用户在“初始化”页点击下载后,页面会显示下载/加载状态、耗时、成功或失败结果。离线环境可以提前准备模型目录,并通过 SENSEVOICE_SMALL_MODEL_DIR 指向该目录。
main 是统一源码主线,Windows 和 macOS 代码都合并在这里。源码仓库只保存代码、测试、配置、打包脚本和文档,不提交打包后的 ZIP、DMG、EXE、APP、blockmap、release/ 或 release-artifacts/。
发布时从 main 拉 release/vX.Y.Z 分支,只做版本号、签名、公证和 release note 等发布准备。打包产物由本机或 CI 生成后上传到 GitHub Releases 附件,不用 Git 分支长期保存产物。
开发者从源码使用时直接拉 main 并按“开发安装”和“启动”章节运行。普通用户使用时不需要拉源码,应在 GitHub Releases 下载对应平台产物:
- Windows:下载 ZIP,解压后运行
SpeakMore.exe。 - macOS:下载 DMG 或 ZIP,安装或解压后运行
SpeakMore.app。
.
├── server/ # 本地 FastAPI 后端
│ ├── main.py # HTTP / WebSocket 接口、就绪状态、音频转码
│ ├── asr.py # SenseVoiceSmall 加载与转写
│ ├── refiner.py # 大模型文本清洗、提问、翻译
│ ├── runtime_config.py # .env、HOST、PORT、CORS 配置
│ └── .env.example # 后端环境变量模板
├── electron-app/ # Electron 主进程和桌面壳
│ ├── main.js # 主进程组合根
│ ├── preload.js # Renderer 安全 IPC 桥接
│ ├── right-alt-listener.ps1 # Windows 低级键盘监听器
│ ├── macos-option-listener.c # macOS 开发态 Option 监听器
│ ├── macos-platform-helper.m # macOS Accessibility、粘贴、选区和文本观察 helper
│ ├── audio-session-control.ps1 # Windows 后台音频会话静音/恢复
│ ├── windows-text-observer/ # UIA 文本观察 helper
│ └── renderer/ # Vite + React + MUI + TypeScript 前端
├── shared/ # 前后端共享元数据
├── scripts/ # 验证和发布脚本
├── packaging/ # 打包配置
├── package.json # 根启动、构建和验证脚本
└── AGENTS.md # 项目协作约定
- Windows 10/11 x64。
- macOS 15+ arm64 当前按开发态 MVP 验证。
- Node.js 24 推荐。
- Python 3.10+。
- Windows 需要 PowerShell;macOS Option 监听器需要 Xcode Command Line Tools 提供的
clang。 ffmpeg。- 可用麦克风。
- 可用的大模型 API Key;默认不包含任何真实 Key。
安装根依赖:
npm ci安装前端依赖:
cd electron-app/renderer
npm ci安装后端依赖:
Windows PowerShell:
cd ..\..\server
python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -r requirements.txtmacOS:
cd ../../server
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt复制后端环境变量模板:
Windows PowerShell:
copy server\.env.example server\.envmacOS:
cp server/.env.example server/.env示例配置:
DEEPSEEK_API_KEY=
DEEPSEEK_BASE_URL=https://api.deepseek.com/v1
SENSEVOICE_SMALL_MODEL_DIR=
TYPELESS_MODEL_CACHE_DIR=
FUNASR_DEVICE=
HOST=127.0.0.1
PORT=8000
CORS_ALLOWED_ORIGINS=null,http://127.0.0.1:5173,http://localhost:5173server/.env 已被忽略,不要提交真实密钥。客户端设置页传入的大模型配置优先;DeepSeek 变量仅作为本地后端回退配置。
LLM provider、API Key 和模型名由设置页保存到本机 Electron userData/local-data/settings.json。
未填写当前 provider 的 API Key 时,语音录音会在启动前被拦截,不会打开麦克风或连接语音后端。默认 provider 是 DeepSeek。
macOS 开发态需要先在系统设置里允许当前终端或 Electron 使用“辅助功能”权限,否则全局 Option 监听器、自动粘贴、选区读取和自动学习观察不可用。
设置页会显示 macOS 辅助功能权限状态,并提供打开系统设置的入口。当前 macOS 阶段会在可信输入目标中自动粘贴听写和翻译结果;粘贴成功后会短时观察本轮 focused text target 的用户修正并生成自动学习候选。权限缺失、目标不可用或粘贴失败时会展示悬浮面板。自由提问会读取 AX confirmed 选区作为上下文,结果仍只展示悬浮面板。
构建前端:
npm run renderer:build检查本地开发前置条件:
npm run doctornpm run doctor 只检查,不安装依赖。它会确认根目录 Electron 依赖、renderer 构建产物、server/.venv 和后端核心包是否存在。
启动后端:
npm run servernpm run server 必须使用 server/.venv 中的 Python,并会先检查 fastapi、uvicorn、funasr、torch、torchaudio 和 transformers 等核心包。缺少 venv 或核心包时会直接失败并打印准备命令,避免误用 Conda 或系统 Python。如需临时指定其它 Python,可设置 SPEAKMORE_SERVER_PYTHON。
检查后端状态:
Windows PowerShell:
Invoke-WebRequest http://127.0.0.1:8000/health | Select-Object StatusCode
Invoke-WebRequest http://127.0.0.1:8000/model/status | Select-Object StatusCode
Invoke-WebRequest http://127.0.0.1:8000/ready | Select-Object StatusCodemacOS:
curl -i http://127.0.0.1:8000/health
curl -i http://127.0.0.1:8000/model/status
curl -i http://127.0.0.1:8000/ready含义:
/health返回 200:后端进程存活。/model/status返回 200:模型初始化状态可查询。/ready返回 200:ASR 模型已预热,语音链路可用。/ready返回 503:模型未开始下载、正在下载/加载,或下载/加载失败。
启动 Electron:
npm startnpm start 会先检查根目录 Electron 依赖和 electron-app/renderer/dist/index.html。缺少时不会打开 Electron,而是提示运行 npm install 或 npm run renderer:build。
模型查找顺序为:
SENSEVOICE_SMALL_MODEL_DIR- 用户设置的
modelCacheDir/ 后端TYPELESS_MODEL_CACHE_DIR - Windows
%LOCALAPPDATA%\Typeless\models\funasr,macOS~/Library/Application Support/SpeakMore/models/funasr %USERPROFILE%\.cache\huggingface\hub或当前用户的 Hugging Face cache- 都未命中时,初始化页点击下载后保存到用户设置的
modelCacheDir,未设置时保存到平台默认模型目录
如果手动配置 SENSEVOICE_SMALL_MODEL_DIR,目录内必须包含 SenseVoiceSmall 所需文件。
后端通过 FUNASR_DEVICE 选择 FunASR 运行设备:
- 空值:保持默认稳定策略,优先 CUDA,最后 CPU,不自动启用 MPS。
auto:自动探测,优先 CUDA,其次 macOS MPS,最后 CPU。cpu:固定 CPU,最稳定。cuda/cuda:0:显式使用 CUDA;不可用时回退 CPU。mps:显式使用 Apple Silicon MPS;不可用或初始化失败时回退 CPU。
GET /model/status 会返回 device、requested_device、device_source 和 fallback_reason,用于确认实际运行设备和回退原因。
macOS 设置页提供“语音识别运行设备”入口,可选择默认、MPS 或 CPU。开发态后端通常由开发者手动启动,npm run server 会优先使用 server/.venv;如需验证 MPS,可使用 FUNASR_DEVICE=mps npm run server。打包态由 Electron 启动内置后端;用户切换 MPS 后,需要真正退出应用再重新打开,后端会按本地设置注入 FUNASR_DEVICE=mps 并加载模型。
Windows 设置页提供“语音识别运行设备”入口,可选择默认、CUDA 或 CPU。开发态后端通常由开发者手动启动;如需验证 CUDA,可使用 $env:FUNASR_DEVICE='cuda:0'; npm run server。打包态由 Electron 启动内置后端;用户切换 CUDA 后,需要真正退出应用再重新打开,后端会按本地设置注入 FUNASR_DEVICE=cuda:0 并加载模型。
macOS MPS 目前只作为 Apple Silicon 实验加速路径,不承诺性能指标。Windows CUDA 选项只适用于 NVIDIA CUDA 环境;Intel Arc 等非 NVIDIA GPU 不会因为选择 CUDA 自动获得加速,后端会回退 CPU 并通过 fallback_reason 暴露原因。
打包脚本可以保留在 main,但产物不能提交到 Git。生成的 ZIP、DMG、EXE、APP 和 blockmap 只用于本机验证或上传到 GitHub Releases。
Windows 便携包:
npm run build:portable:win
npm run verify:portable:winmacOS 本地 App、zip 和 DMG:
npm run build:app:mac
npm run verify:app:macmacOS 打包态 MPS 重启生效烟测:
npm run smoke:app-mps:macmacOS release 签名和公证需要先提供 Developer ID 和 Apple notarization 凭证,再运行:
npm run build:release:mac支持的签名和公证环境变量:
- 签名:
CSC_LINK或CSC_NAME,以及需要时的CSC_KEY_PASSWORD。 - App Store Connect API Key:
APPLE_API_KEY、APPLE_API_KEY_ID、APPLE_API_ISSUER。 - Apple ID:
APPLE_ID、APPLE_APP_SPECIFIC_PASSWORD、APPLE_TEAM_ID。 - Keychain profile:
APPLE_KEYCHAIN_PROFILE,需要时配合APPLE_KEYCHAIN。
没有签名凭证时,build:app:mac 会生成本地 ad-hoc 签名产物并跳过公证,适合本机验证;公开分发必须使用 build:release:mac。
Electron 主进程把业务数据写到:
Electron userData/local-data/
主要文件和目录:
settings.json:本地设置。history.json:最近历史列表。history-stats.json:累计统计。dictionary.json:正式词典词条。dictionary-candidates.json:自动学习候选词条。recording.log:本地排查日志。recordings/:录音相关本地产物目录。
这些内容不进入仓库,也不进入便携发布包。
词典正式词条和自动学习候选只保存在本机 userData/local-data/。每轮请求只会把启用词条中按动态分数裁剪后的部分传给本地后端,默认 24 条,后端硬上限 40 条。
自动学习只围绕本轮 SpeakMore 自动粘贴结果做短时观察,只接受短词或短语级纠错,不采集无关全局文本,不学习整句改写、摘要结果、问答命令或无上下文大段替换。
GET /health:后端进程存活检查。GET /model/status:查询 SenseVoiceSmall 初始化状态。POST /model/download:启动 SenseVoiceSmall 下载/加载任务。GET /ready:语音链路就绪检查。POST /config/reload:刷新后端回退配置。POST /ai/voice_flow:上传完整音频并返回处理结果。WebSocket /ws/rt_voice_flow:实时录音流接口。
WebSocket 语音流固定输入来自 16kHz、单声道、pcm_s16le 二进制 chunk,并在 start_audio.parameters.audio_format 声明音频格式。兼容上传入口会先把音频转成 PCM16 再交给 ASR。
前端测试:
cd electron-app\renderer
npm test前端构建:
npm run renderer:build主进程语法检查:
node --check electron-app\main.js快捷键转发测试:
node --test electron-app\right-alt-relay.test.js历史统计测试:
node --test electron-app\history-stats-store.test.mjs后端核心语音协议验证:
npm run verify:voice开源边界验证:
npm run verify:open-source后端全部测试:
cd server
python -m pytest -q先检查:
Invoke-WebRequest http://127.0.0.1:8000/ready | Select-Object StatusCode如果 /ready 是 503,先打开初始化页查看模型状态;常见原因是还没点击下载、模型还在下载/加载、下载失败,或 SENSEVOICE_SMALL_MODEL_DIR 配置错误。
第一次没有本地 SenseVoiceSmall 模型时,需要在初始化页点击下载并等待加载完成。网络慢或无法访问模型源时,语音功能会暂时不可用,页面会保留失败原因。
到设置页的大模型区域填写自己的 API Key 并保存。未填写 API Key 时,录音启动会被拦截。
确认 ffmpeg 可用:
ffmpeg -version主录音链路固定发送 PCM16;兼容入口上传的其他音频仍需要 ffmpeg 转码。
优先检查设置页里的 provider、API Key 和模型名。保存后,Electron 会把配置写入本机 settings.json,并随语音或文本请求传给本地后端。
仓库不会提交以下内容:
node_modules/- 构建产物
server/.env- 日志文件
- Python 缓存
- 本地 AI 工作上下文
docs/ai/context/ - Electron
userData/local-data/