内容
# 语音转文本工具
 
本地语音转文本工具,由Mistral的Voxtral模型通过MLX提供支持,支持在苹果硅芯片上实时流式播放。提供交互式命令行界面和FastAPI服务器,支持MCP桥接,用于AI代理集成。
### 功能特点
| 功能 | 描述 |
|---------|-------------|
| 流式播放 | 实时音频生成,支持边生成边播放 |
| 交互式命令行界面 | 支持模型和语音选择,ESC退出,支持退格键 |
| REST API服务器 | FastAPI服务器,支持队列式顺序播放和消息状态跟踪 |
| MCP服务器 | 适用于Claude Code和Claude Desktop集成的MCP桥接器 |
| 多语音支持 | 支持20种语音,覆盖9种语言(英语,德语,法语,西班牙语,意大利语,荷兰语,葡萄牙语,印地语,阿拉伯语) |
| 多模型支持 | 支持Voxtral 4B的4位、6位和bf16量化变体 |
在底层,该项目使用 [mlx-audio](https://github.com/Blaizzy/mlx-audio) 加载和推理模型,支持苹果硅芯片, [sounddevice](https://python-sounddevice.readthedocs.io/) 实现实时音频输出, [FastAPI](https://fastapi.tiangolo.com/) 构建HTTP服务器。MCP服务器是一个轻量级TypeScript中继,使用 [Model Context Protocol SDK](https://modelcontextprotocol.io/)。
## 设计原则
所有配置均为显式,不存在硬编码默认值或静默回退。如果`config.yaml`中缺少必需值,应用程序将立即失败,并显示清晰的错误消息。音频文件保存为`data/output/`目录下的WAV文件,并带有时间戳。服务器使用后台工作线程和预读模式:它为下一个请求生成音频,同时当前请求仍在播放,从而消除连续消息之间的间隙。
## 架构
系统有两个独立的入口路径。交互式命令行界面(`src/main.py`)解析模型和语音,然后启动一个工作线程,加载模型并在同一线程上运行生成。FastAPI服务器(`src/server.py`)在启动时加载模型,并通过工作队列和后台音频工作线程序列化所有请求。AI代理通过MCP中继(`mcp/tts-mcp.ts`)到达服务器,这是一个薄的stdio-to-HTTP桥接器;任何普通的HTTP客户端都可以直接调用REST API。在这两个路径中,推理都在苹果硅芯片GPU上通过MLX(Metal)运行,Voxtral模型权重存储在统一内存中。
```text
┌───────────────────────────┐ ┌───────────────────────────┐ ┌───────────────────────────┐
│ AI 代理 │ │ HTTP 客户端 │ │ 终端用户 │
│ Claude Code / Desktop │ │ curl / 脚本 │ │ 对话 │
└─────────────┬─────────────┘ └─────────────┬─────────────┘ └─────────────┬─────────────┘
│ MCP(stdio) │ HTTP │
▼ │ ▼
┌───────────────────────────┐ │ ┌───────────────────────────┐
│ MCP 服务器(Node.js) │ │ │ 命令行界面 · src/main.py │
│ mcp/tts-mcp.ts │ │ │ 交互式聊天 │
│ 工具:say, get_voices, │ │ │ 模型和语音选择 │
│ get_status │ │ │ 队列文本到工作线程 │
└─────────────┬─────────────┘ │ └─────────────┬─────────────┘
│ HTTP │ │ 模型路径 + 文本
▼ ▼ │
┌─────────────┬──────────────────────────────┬───────────────┐ │
│ FastAPI 服务器 · src/server.py │ │
│ │ │
│ REST API POST /say · GET /voices · GET /status/{id} │ │
│ GET /health │ │
│ │ │ │
│ ▼ │ │
│ 工作队列 ───▶ 音频工作线程(预读) │ │
└─────────────────────────────────────────────────┬──────────┘ │
│ │
▼ ▼
┌──────────────────────┐ ┌─────────────┬─────────────────────────┬──────────────┐
│ 苹果硅芯片GPU │ │ 共享TTS引擎 · src/tts.py │
│ Metal via MLX │ │ │
│ │◀── 文本 ───│ 工作线程生成 │
│ Voxtral 4B TTS模型 │── 音频 ──▶│ 命令行界面工作线程加载模型后生成 │
│ 4位 / 6位 / bf16 │ │ │ │
│ 统一内存 │ │ ▼ │
│ │ │ 响度归一化(pyloudnorm · BS.1770-4) │
└──────────────────────┘ │ │ │
│ ├────────────────────────┐ │
│ ▼ ▼ │
│ 播放(sounddevice) WAV写入 │
└─────────────┬────────────────────────┬───────────────┘
│ │
▼ ▼
┌──────────┐ ┌───────────────────┐
│ 扬声器 │ │ data/output/*.wav │
└──────────┘ └───────────────────┘
```
## 前置条件
- **苹果硅芯片Mac** — MLX需要苹果硅芯片(M1/M2/M3/M4)
- **Python 3.12+**
- **uv** — Python包管理器([安装](https://docs.astral.sh/uv/getting-started/installation/))
- **just** — 命令运行器([安装](https://github.com/casey/just#installation))
- **Node.js 18+** — 用于MCP服务器(可选)
## 项目结构
```
.
├── src/ # 应用程序源代码
│ ├── main.py # 命令行界面前端
│ ├── server.py # FastAPI TTS服务器
│ └── tts.py # 共享TTS引擎(配置、生成、播放)
├── tests/ # 单元测试
│ ├── test_main.py
│ ├── test_server.py
│ ├── test_tts.py
│ └── architecture/ # 架构导入规则测试
├── scripts/ # 实用脚本
│ ├── download-model.sh # 交互式模型下载器
│ └── test-concurrent-say.py # 并发/say负载测试
├── mcp/ # MCP服务器(TypeScript)
│ └── tts-mcp.ts # MCP中继到FastAPI服务器
├── config/ # 静态分析规则
│ ├── semgrep/ # Semgrep自定义规则
│ └── codespell/ # 拼写检查配置
├── data/
│ └── output/ # 生成的WAV文件
├── config.yaml # 本地配置(gitignored)
├── justfile # 命令配方
└── pyproject.toml # 项目元数据和依赖项
```
## 安装
```bash
just init
```
创建报告目录并通过`uv sync --all-extras`安装所有依赖项。
### 下载模型
```bash
just download
```
呈现三个Voxtral 4B变体供选择:
| 模型 | 大小 | 速度 |
|-------|------|-------|
| `Voxtral-4B-TTS-2603-mlx-4bit` | ~2.5 GB | 最快(RTF <1.0x) |
| `Voxtral-4B-TTS-2603-mlx-6bit` | ~3.5 GB | 平衡(RTF ~1.1x) |
| `Voxtral-4B-TTS-2603-mlx-bf16` | ~8.0 GB | 最高质量(RTF ~6.3x) |
下载后,更新`config.yaml`中的模型路径。
### 入门指南
1. 运行 `just init` — 安装依赖项并提示下载模型(如果不存在)
2. 运行 `just download` — 下载Voxtral模型(如果未被`init`触发)
3. 使用模型路径和服务器设置创建`config.yaml`(参见下面的配置)
4. 运行 `just serve` — 启动TTS服务器
5. 通过API、命令行界面或MCP桥接发送请求
## 配置
所有配置都存放在项目根目录的`config.yaml`中。该文件被gitignored,必须手动创建。示例:
```yaml
model: /path/to/Voxtral-4B-TTS-2603-mlx-6bit
models_dir: /path/to/models
sample_rate: 24000
default_voice: casual_female
save_wav: true
simplify_punctuation: false
normalize_audio: true
target_lufs: -20.0
true_peak_ceiling_db: -1.0
min_duration_seconds: 0.5
host: 0.0.0.0
port: 12000
```
| 键 | 描述 |
|-----|-------------|
| `model` | 下载的MLX模型目录路径 |
| `models_dir` | 包含模型子目录的基本目录(用于命令行界面模型选择) |
| `sample_rate` | Hz中的音频采样率(Voxtral为24000) |
| `default_voice` | 服务器请求中没有语音覆盖时的默认语音 |
| `save_wav` | 将生成的音频保存到`data/output/`中的WAV文件(`true`或`false`) |
| `simplify_punctuation` | 删除逗号,用句点替换其他标记以获得更干净的语音 |
| `normalize_audio` | 启用仅提升的LUFS响度归一化,每个语句(`true`或`false`) |
| `target_lufs` | 启用`normalize_audio`时,目标集成响度为LUFS(例如,`-20.0`表示播客中间) |
| `true_peak_ceiling_db` | 应用增益后允许的最大真实峰值(dBFS)(例如,`-1.0`);通过4倍过采样测量 |
| `min_duration_seconds` | 语句短于此值将被原样传递(LUFS门控需要~0.4s) |
| `host` | 服务器监听地址 |
| `port` | 服务器监听端口 |
### 响度归一化
不同的Voxtral语音以显著不同的平均级别产生音频。启用`normalize_audio`以应用语句级响度归一化,遵循ITU-R BS.1770-4(EBU R128标准,用于广播):
- 使用[`pyloudnorm`](https://github.com/csteinmetz1/pyloudnorm)以LUFS测量每个语句的集成响度。
- 如果测量值低于`target_lufs`,则应用单个标量增益以将语句提升到目标。
- 如果测量值在或高于目标,则音频保持不变 - 归一化是**仅增强**且从不衰减的,因此已经很响亮的语音被精确保留。
- 在应用增益之前,测量4倍过采样真实峰值,使用`scipy.signal.resample_poly`。增益上限为
结果的真实峰值保持在或低于`true_peak_ceiling_db`,防止样本间剪辑。
- 语句短于`min_duration_seconds`和完全静默的语句将被原样传递。
- 相同的归一化音频用于扬声器播放和保存的WAV文件,因此播放内容与写入磁盘的内容之间没有差异。
## 用法
| 命令 | 描述 |
|---------|-------------|
| `just chat` | 启动交互式聊天 |
| `just serve` | 启动FastAPI TTS服务器(前台) |
| `just stop` | 停止正在运行的服务器 |
| `just status` | 检查服务器是否正在运行 |
### 命令行界面
```bash
just chat
```
提示选择模型和语音,然后进入交互式循环。输入文本并按两次Enter键提交。按两次ESC键退出。
对于一次性使用:
```bash
uv run -m src.main "Hello world" --voice casual_female
```
### 服务器
```bash
just serve
```
启动带有队列播放的FastAPI服务器。服务器在启动时加载模型,并通过后台工作线程顺序处理请求。
## API
FastAPI自动在 `/docs`(Swagger)和`/redoc`(ReDoc)处生成交互式文档。
| 方法 | 端点 | 描述 |
|--------|----------|-------------|
| GET | `/health` | 存活检查 |
| GET | `/voices` | 列出可用语音和默认语音 |
| POST | `/say` | 队列文本进行合成和播放(返回消息ID) |
| GET | `/status/{message_id}` | 检查队列/播放/完成消息的状态 |
### POST /say
```json
{
"text": "Hello, this is a test.",
"voice": "casual_female"
}
```
返回`202 Accepted`,带有消息ID和队列位置。音频通过服务器的扬声器播放。
### 消息生命周期
`queued` -> `playing` -> `completed`(带有音频文件路径)或`error`(带有错误详细信息)。已完成状态在1小时后过期。
## MCP服务器
MCP服务器(`mcp/tts-mcp.ts`)是MCP客户端和FastAPI服务器之间的透明中继。它公开了三个工具:
| 工具 | 描述 |
|------|-------------|
| `say` | 队列文本进行语音合成,指定语音 |
| `get_voices` | 列出所有可用语音 |
| `get_status` | 通过消息ID检查语音请求的状态 |
### 安装
```bash
cd mcp && npm install
```
### 与Claude Code / Claude Desktop一起使用
将以下内容添加到您的MCP配置中:
```json
{
"mcpServers": {
"tts": {
"command": "npx",
"args": ["tsx", "tts-mcp.ts"],
"cwd": "/path/to/mistral-text-to-spech/mcp"
}
}
}
```
MCP服务器读取项目根目录的`config.yaml`以确定服务器URL。
## 开发
### 代码质量
| 命令 | 描述 |
|---------|-------------|
| `just code-format` | 自动修复代码样式和格式 |
| `just code-style` | 检查代码样式和格式(只读) |
| `just code-typecheck` | 使用mypy运行静态类型检查 |
| `just code-lspchecks` | 使用基于LSP的Pyright运行严格类型检查 |
| `just code-security` | 使用bandit运行安全检查 |
| `just code-deptry` | 使用deptry检查依赖项卫生 |
| `just code-spell` | 检查代码和文档中的拼写 |
| `just code-semgrep` | 运行Semgrep静态分析 |
| `just code-audit` | 扫描依赖项以查找已知漏洞 |
| `just code-architecture` | 运行架构导入规则测试 |
| `just code-stats` | 使用pygount生成代码统计信息 |
### 测试
| 命令 | 描述 |
|---------|-------------|
| `just test` | 运行单元测试(快速) |
| `just test-coverage` | 运行单元测试并生成覆盖率报告(80%阈值) |
### CI
- `just ci` — 运行所有验证检查(详细)
- `just ci-quiet` — 运行所有检查(静默,失败快速)
CI管道按顺序运行:init,code-format,code-style,code-typecheck,code-security,code-deptry,code-spell,code-semgrep,code-audit,test,code-architecture,code-lspchecks。
## AI辅助开发
本项目包含一个[CLAUDE.md](CLAUDE.md)文件,包含AI编码助手开发规则。
## 更新日志
查看 [CHANGELOG.md](CHANGELOG.md) 以获取完整的更改列表。
## 资源
- [mlx-audio](https://github.com/Blaizzy/mlx-audio) — 基于MLX的苹果硅芯片音频模型
- [Voxtral](https://mistral.ai/news/voxtral) — Mistral的文本转语音模型
- [Model Context Protocol](https://modelcontextprotocol.io/) — AI工具集成开放协议
- [FastAPI](https://fastapi.tiangolo.com/) — 现代Python Web框架
## 许可证
该项目在MIT许可证下许可。有关详细信息,请参阅 [LICENSE](LICENSE)。
MCP 配置
以下是此 MCP Server 的配置信息,可直接复制到 Cursor 或其他 MCP 客户端中使用。
mcp.json
连接信息
猜你喜欢
暂无推荐服务器