TTS守护进程
一种文本到语音(TTS)守护进程服务,缓存音频片段,并为Claude和其他AI助手提供CLI客户端和MCP(模型上下文协议)接口。
特性
- Azure认知服务TTS:使用Azure的神经语音实现高质量的文本到语音转换
- SQLite缓存:自动缓存生成的音频以避免重复的API调用
- 速率限制:Azure API调用的可配置QPS(每秒查询数)限制
- gRPC通信:高效的客户端守护进程通信
- 音频播放:直接使用客户端播放音频
- MCP支持:通过模型上下文协议向Claude公开TTS功能
- 多语言支持:支持20多种语言,包括英语、法语、西班牙语、德语、日语、中文等
建筑
┌──────────────────────────────────┐
│ User / Agent │
└──────────────────────────────────┘
│
│
┌──────────────┴──────────────┐
│ │
▼ ▼
┌──────────────┐ ┌──────────────┐
│ │ │ │
│ │ │ │
│ │ │ │
│ CLI Client │ │ MCP │
│ │ │ │
│ │ │ │
│ │ │ │
└──────────────┘ └──────────────┘
│ │
└──────────────┬──────────────┘
│
▼
┌──────────────┐
│ │
│ │
│ Daemon │
│ (Cache & │
│ Fetch) │
│ │
│ │
└──────────────┘
│
┌──────────────┴──────────────┐
│ │
▼ ▼
┌──────────────┐ ┌──────────────┐
│ │ │ │
│ │ │ │
│ │ │Text-to-Speech│
│Cache (Sqlite)│ │ (Azure) │
│ │ │ │
│ │ │ │
│ │ │ │
└──────────────┘ └──────────────┘关键设计:守护进程处理获取和缓存。客户端在本地处理音频播放。
安装
先决条件
- 转到1.21或更高版本
- Azure认知服务语音订阅密钥
- macOS、Linux或Windows
从源代码构建
# Clone or navigate to the project directory
cd tts-daemon
# Download dependencies
go mod tidy
# Build binaries (development mode)
make build
# or manually:
# go build -o bin/tts-daemon ./cmd/tts-daemon
# go build -o bin/tts-client ./cmd/tts-client
# Build binaries (release/optimized mode - recommended for production)
make release
# Optionally, install to your PATH
go install ./cmd/tts-daemon
go install ./cmd/tts-client构建模式:
- 发展(
make build): 带有调试符号的标准构建,对开发很有用 - 释放(
make release): 优化构建,精简调试符号和更小的二进制大小(约小30%),建议用于生产环境
您还可以构建单个组件:
make daemon # Build daemon only (dev)
make client # Build client only (dev)
make release-daemon # Build daemon only (release)
make release-client # Build client only (release)配置
- 复制示例配置文件:
mkdir -p ~/.config/tts-daemon
cp config.example.yaml ~/.config/tts-daemon/config.yaml- 编辑
~/.config/tts-daemon/config.yaml并添加您的Azure凭据:
azure:
subscription_key: "YOUR_AZURE_SUBSCRIPTION_KEY"
region: "YOUR_AZURE_REGION" # e.g., westus, eastus, westeurope
max_qps: 10.0 # Maximum queries per second (default: 10)
# Optional: Custom voice mappings to override defaults
voices:
en-US: "en-US-AriaNeural" # Use a different voice for US English
es-MX: "es-MX-JorgeNeural" # Use male voice for Mexican Spanish
fr: "fr-FR-HenriNeural" # Use male voice for French
database:
path: "" # Default: ~/.local/share/tts-daemon/cache.db
server:
address: "localhost"
port: 50051
audio:
sample_rate: 44100
buffer_size: 4096获取Azure凭据
- 首选 Azure 门户
- 创建新的“语音服务”资源
- 从资源的“密钥和端点”页面复制订阅密钥和区域
用法
启动守护进程
# Start with default config location (~/.config/tts-daemon/config.yaml)
./bin/tts-daemon
# Or specify a custom config file
./bin/tts-daemon -config /path/to/config.yaml守护进程将:
- 初始化SQLite缓存数据库
- 连接到Azure TTS API
- 开始监听配置的gRPC端口(默认值:50051)
- 启动时记录缓存统计信息
使用CLI客户端
获取音频(存储在缓存中,不播放)
./bin/tts-client "Hello, world!"
./bin/tts-client -lang fr-FR "Bonjour le monde!"
./bin/tts-client -lang es-ES "¡Hola mundo!"播放音频
./bin/tts-client -play "Hello, world!"
./bin/tts-client -play -lang ja-JP "こんにちは世界"
# With verbose output
./bin/tts-client -v -play "Hello, world!"
# Output:
# Audio played successfully
# (from cache)仅检查缓存(不从Azure获取)
./bin/tts-client -cache-only "Hello, world!"强制刷新(绕过缓存和重取)
当您更改了语音设置并想要更新缓存音频时很有用:
./bin/tts-client -force "Hello, world!"
./bin/tts-client -f -play -lang es-MX "el camino" # Short form删除缓存条目
删除特定的缓存音频条目:
./bin/tts-client -D -lang es-MX "el camino"连接到自定义守护进程地址
./bin/tts-client -address localhost:50051 "Hello, world!"CLI选项
-address string
Daemon server address (default "localhost:50051")
-cache-only
Only check cache, don't fetch from Azure
-D
Delete cached entry
-f, -force
Force refresh from Azure, bypassing cache
-lang string
Language code (e.g., en-US, fr-FR, es-ES) (default "en-US")
-mcp
Run in MCP mode
-play
Play audio (default: just fetch)
-v, -verbose
Enable verbose output注: 默认情况下,客户端在成功时保持沉默(无输出)。使用 -v 或 -verbose 查看有关缓存命中率、音频大小等的详细信息。始终显示错误。
与Claude一起使用(MCP模式)
客户端可以在MCP模式下运行,将TTS功能暴露给Claude和其他AI助手。
MCP配置
添加到您的Claude MCP设置中(例如。, claude_desktop_config.json):
{
"mcpServers": {
"tts": {
"command": "/path/to/bin/tts-client",
"args": ["-mcp"]
}
}
}在启动Claude之前,请确保守护进程正在运行。
可用的MCP工具
- fetch_tts:在不播放的情况下获取和缓存音频
- 参数: text (必填), language_code (可选,默认:en-US)
- play_tts:获取(如果需要)、缓存和播放音频
- 参数: text (必填), language_code (可选,默认:en-US)
克劳德互动示例
User: Can you fetch the French pronunciation for "Bonjour, comment allez-vous?"
Claude: [uses fetch_tts tool with language_code: "fr-FR"]
User: Play that for me
Claude: [uses play_tts tool with the same text]支持的语言
该守护进程支持Azure TTS支持的所有语言, 查看详情.
对于较短的语言代码(例如,“fr”而不是“fr-fr”),守护进程将使用最常见的区域变体。
自定义声音
您可以通过在配置文件中添加语音映射来覆盖任何语言的默认语音:
azure:
voices:
en-US: "en-US-AriaNeural" # Different US English voice
es-MX: "es-MX-JorgeNeural" # Male Mexican Spanish voice
fr: "fr-FR-HenriNeural" # Male French voice
ja-JP: "ja-JP-KeitaNeural" # Male Japanese voice寻找可用的声音:
浏览可用语音 Azure的语音库每个语音名称都遵循以下模式: {locale}-{VoiceName}Neural
示例:
en-US-AriaNeural-美国英语,女性en-US-GuyNeural-美国英语,男性es-MX-DaliaNeural-墨西哥西班牙语,女性es-MX-JorgeNeural-墨西哥裔西班牙人,男性fr-FR-DeniseNeural-法国人,女性fr-FR-HenriNeural-法国人,男性
工作原理:
- 当您请求TTS提供语言代码时(例如。,
es-MX) - 守护进程首先检查您的自定义语音映射
- 如果找到,则使用您的自定义语音
- 如果未找到,则返回到内置默认值
这允许您对任何语言使用男性/女性声音、地区口音或特殊声音(如儿童声音或老年人声音)。
缓存的工作原理
- 文本被规范化(小写、空格修剪、标点符号删除)
- SHA-256哈希值由以下生成
language_code:normalized_text - 使用此哈希检查缓存
- 如果找到,则立即返回缓存的音频
- 如果未找到,则从Azure获取音频并将其存储在缓存中
- 所有音频均以MP3格式存储(16kHz,128kbps,单声道)
这确保了:
- 对同一文本的快速重复请求
- 降低Azure API成本
- 脱机处理缓存内容
速率限制
后台程序使用 golang.org/x/time/rate 包裹。这可以防止达到Azure的API限制并控制成本。
默认值:每秒10个请求(可通过配置 azure.max_qps 在配置中)
作为系统服务运行
将TTS守护进程作为系统服务运行可确保它在启动时自动启动,并在崩溃时重新启动。
macOS(launchd)
1.创建LaunchAgent配置
创建 ~/Library/LaunchAgents/com.biesnecker.tts-daemon.plist:
Label
com.biesnecker.tts-daemon
ProgramArguments
/Users/YOUR_USERNAME/path/to/bin/tts-daemon
RunAtLoad
KeepAlive
StandardErrorPath
/Users/YOUR_USERNAME/.local/share/tts-daemon/daemon.err
StandardOutPath
/Users/YOUR_USERNAME/.local/share/tts-daemon/daemon.out
WorkingDirectory
/Users/YOUR_USERNAME
重要提示: 替换 YOUR_USERNAME 并更新路径以匹配您的实际安装。
2.加载服务
# Load and start immediately
launchctl load ~/Library/LaunchAgents/com.biesnecker.tts-daemon.plist
# The daemon will now start automatically at login3.管理服务
# Check if running
launchctl list | grep tts-daemon
# Stop the service
launchctl unload ~/Library/LaunchAgents/com.biesnecker.tts-daemon.plist
# Start the service (if not set to RunAtLoad)
launchctl start com.biesnecker.tts-daemon
# View logs
tail -f ~/.local/share/tts-daemon/daemon.out
tail -f ~/.local/share/tts-daemon/daemon.errLinux(systemd)
1.创建systemd服务文件
选项A:用户服务(推荐) -以用户身份运行,从登录时开始:
创建 ~/.config/systemd/user/tts-daemon.service:
[Unit]
Description=TTS Daemon
After=network.target
[Service]
Type=simple
ExecStart=%h/path/to/bin/tts-daemon
Restart=always
RestartSec=10
StandardOutput=append:%h/.local/share/tts-daemon/daemon.log
StandardError=append:%h/.local/share/tts-daemon/daemon.err
[Install]
WantedBy=default.target选项B:系统服务 -作为系统服务运行(需要root):
创建 /etc/systemd/system/tts-daemon.service:
[Unit]
Description=TTS Daemon
After=network.target
[Service]
Type=simple
User=YOUR_USERNAME
ExecStart=/home/YOUR_USERNAME/path/to/bin/tts-daemon
Restart=always
RestartSec=10
StandardOutput=append:/home/YOUR_USERNAME/.local/share/tts-daemon/daemon.log
StandardError=append:/home/YOUR_USERNAME/.local/share/tts-daemon/daemon.err
[Install]
WantedBy=multi-user.target2.启用并启动服务
用户服务:
# Reload systemd to recognize new service
systemctl --user daemon-reload
# Enable service to start at login
systemctl --user enable tts-daemon
# Start the service now
systemctl --user start tts-daemon
# Check status
systemctl --user status tts-daemon对于系统服务:
# Reload systemd to recognize new service
sudo systemctl daemon-reload
# Enable service to start at boot
sudo systemctl enable tts-daemon
# Start the service now
sudo systemctl start tts-daemon
# Check status
sudo systemctl status tts-daemon3.管理服务
# View logs (user service)
journalctl --user -u tts-daemon -f
# View logs (system service)
sudo journalctl -u tts-daemon -f
# Stop the service
systemctl --user stop tts-daemon # or: sudo systemctl stop tts-daemon
# Restart the service
systemctl --user restart tts-daemon # or: sudo systemctl restart tts-daemon
# Disable autostart
systemctl --user disable tts-daemon # or: sudo systemctl disable tts-daemonWindows(任务计划程序)
1.创建批处理文件包装器
创建 C:\Program Files\tts-daemon\start-daemon.bat:
@echo off
cd /d "%USERPROFILE%"
"C:\Program Files\tts-daemon\tts-daemon.exe" >> "%USERPROFILE%\.local\share\tts-daemon\daemon.log" 2>&12.创建计划任务
使用任务调度器GUI:
- 打开任务计划程序(在“开始”菜单中搜索“任务计划程序”)
- 点击“创建任务…”(不是“创建基本任务”)
- “常规”选项卡:
- 姓名: TTS Daemon - 说明: Text-to-Speech daemon service - 勾选“用户是否登录运行” - 勾选“以最高权限运行”(如果需要) - 配置适用于:Windows 10/11
- 触发器选项卡:
- 点击“新建…” - 开始任务:“启动时”或“登录时” - 勾选“已启用” - 点击“确定”
- 操作选项卡:
- 点击“新建…” - 操作:“启动一个程序” - 程序/脚本: C:\Program Files\tts-daemon\start-daemon.bat - 点击“确定”
- 条件选项卡:
- 取消选中“仅当计算机使用交流电源时启动任务”(如果是笔记本电脑)
- 设置选项卡:
- 勾选“允许任务按需运行” - 勾选“如果正在运行的任务未在请求时结束,请强制其停止” - 如果任务失败,每“1分钟”重新启动一次 - 尝试重新启动最多:“3次”
- 点击“确定”保存
使用命令行(PowerShell作为管理员):
$action = New-ScheduledTaskAction -Execute "C:\Program Files\tts-daemon\start-daemon.bat"
$trigger = New-ScheduledTaskTrigger -AtStartup
$principal = New-ScheduledTaskPrincipal -UserId "$env:USERNAME" -LogonType S4U -RunLevel Highest
$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -RestartCount 3 -RestartInterval (New-TimeSpan -Minutes 1)
Register-ScheduledTask -TaskName "TTS Daemon" -Action $action -Trigger $trigger -Principal $principal -Settings $settings -Description "Text-to-Speech daemon service"3.管理任务
使用GUI:
- 打开任务计划程序
- 在任务列表中查找“TTS守护程序”
- 右键单击以查看选项(运行、结束、禁用、删除、属性)
使用命令行:
# Start the task manually
Start-ScheduledTask -TaskName "TTS Daemon"
# Stop the task
Stop-ScheduledTask -TaskName "TTS Daemon"
# Disable the task
Disable-ScheduledTask -TaskName "TTS Daemon"
# Enable the task
Enable-ScheduledTask -TaskName "TTS Daemon"
# View task status
Get-ScheduledTask -TaskName "TTS Daemon" | Get-ScheduledTaskInfo验证服务是否正在运行
设置服务后,验证其是否正常工作:
# Test with the client
./bin/tts-client -v "Hello, world!"
# If successful, you should see output like:
# Audio fetched successfully
# Cache key: ...
# Audio size: ... bytes
# (fetched from Azure)故障排除
服务无法启动:
- 检查配置文件是否存在于
~/.config/tts-daemon/config.yaml - 验证Azure凭据是否正确
- 检查日志文件中的错误消息
- 确保二进制文件具有执行权限:
chmod +x bin/tts-daemon
无法从客户端连接:
- 验证守护进程是否正在运行:
ps aux | grep tts-daemon(macOS/Linux) - 如果远程连接,请检查防火墙设置
- 验证端口50051未被其他进程使用
Daemon在启动时崩溃:
- 检查日志文件以获取详细的错误消息
- 请先尝试手动运行:
./bin/tts-daemon查看错误 - 验证数据库目录是否可写:
~/.local/share/tts-daemon/
发展
项目结构
tts-daemon/
├── cmd/
│ ├── tts-daemon/ # Daemon main entry point
│ └── tts-client/ # Client main entry point
├── internal/
│ ├── config/ # Configuration parsing
│ ├── daemon/ # gRPC server implementation
│ ├── player/ # Audio playback (beep wrapper)
│ └── tts/ # TTS service, Azure client, caching
├── proto/ # gRPC protocol definitions
├── bin/ # Built binaries
├── config.example.yaml # Example configuration
├── generate.sh # Script to regenerate gRPC code
└── README.md正在重新生成gRPC代码
如果你修改 proto/tts.proto:
./generate.sh这将再生 proto/tts.pb.go 和 proto/tts_grpc.pb.go.
故障排除
守护进程无法启动
- 检查配置文件中的Azure凭据是否正确
- 验证gRPC端口(50051)是否尚未使用
- 检查日志以获取详细的错误消息
客户端无法连接
- 确保守护进程正在运行
- 验证地址和端口是否与守护进程的配置匹配
- 如果远程连接,请检查防火墙设置
音频无法播放
- 确保您的系统已配置音频输出
- 检查MP3编解码器是否受支持
- 尝试在不播放的情况下获取,以验证问题是否与播放有关
速率限制错误
- 减少
max_qps在配置中 - 请稍候,然后重试
- 检查订阅层的Azure服务限制
许可证
该项目根据麻省理工学院许可证获得许可。请参阅LICENSE.txt了解详细信息。
贡献
这是一个个人项目,但欢迎提出建议和改进!
