跳到正文

azure-speech-gateway

azure-speech-gateway 是一个 Bun + TypeScript 的 Azure Speech 语音网关。它把 Azure 实时语音识别和语音合成包装成与现有本地 / 阿里云语音链路兼容的接口,便于 callflow-esl、FreeSWITCH mod_audio_fork 或管理台测试工具在不改调用方式的 情况下切换到 Azure。

服务启动后会同时监听两个端口:

  • ASR WebSocket 服务:默认 0.0.0.0:10098
  • TTS HTTP 服务:默认 0.0.0.0:9082

运行

在仓库根目录运行:

bash
bun install
bun run dev:azure-speech

也可以进入子项目单独运行:

bash
cd apps/azure-speech-gateway
bun run dev          # 监听模式
bun run start        # 启动一次
bun run typecheck    # TypeScript 类型检查

构建可执行文件

bash
bun run build        # typecheck 后构建 Windows x64
bun run build:win    # 构建 dist/win_x64/azure-speech-gateway.exe
bun run build:linux  # 从当前环境交叉构建 dist/linux_x64/azure-speech-gateway
bun run build:all    # typecheck 后构建 Windows + Linux x64

构建产物是可直接部署的目录,包含一个独立可执行文件和外置 config.json

text
dist/win_x64/azure-speech-gateway.exe
dist/win_x64/config.json
dist/linux_x64/azure-speech-gateway
dist/linux_x64/config.json

运行时默认读取可执行文件同目录下的 config.json。如需使用其它配置文件,可设置 AZURE_SPEECH_GATEWAY_CONFIG_PATH

powershell
cd dist\win_x64
$env:AZURE_SPEECH_GATEWAY_CONFIG_PATH = "C:\deploy\azure-speech-gateway\config.json"
.\azure-speech-gateway.exe

Linux 部署时把 dist/linux_x64/ 复制到目标机器,执行 chmod +x azure-speech-gateway 后运行 ./azure-speech-gateway。Linux 二进制可以在 Windows 上通过 Bun 交叉编译生成, 但仍需在目标 Linux 主机验证 Azure 网络访问、端口监听、缓存目录路径与权限。

配置

配置文件位于 apps/azure-speech-gateway/config.json。Azure Speech key 可以写在配置 文件中,也可以用环境变量覆盖,生产部署建议使用环境变量便于轮换:

powershell
$env:AZURE_SPEECH_KEY="your-subscription-key"
$env:AZURE_SPEECH_REGION="uksouth"
$env:AZURE_SPEECH_TTS_ENDPOINT="https://uksouth.tts.speech.microsoft.com/cognitiveservices/v1"
bun run --cwd apps/azure-speech-gateway start
配置段字段用途
azureregion / endpoint / ttsEndpointAzure Speech 区域、资源 endpoint 与 TTS REST endpoint
azuresubscriptionKeyAzure Speech key,可被 AZURE_SPEECH_KEY 覆盖
asrhost / portASR HTTP/WebSocket 监听地址,默认端口 10098
asrhealthPath / wsPath健康检查与音频 WebSocket 路径,默认 /health/audio
asrwsSubprotocolWebSocket 子协议,默认 audio.drachtio.org,用于兼容 mod_audio_fork
asrmaxSessions最大并发 ASR 会话数
asrmaxQueuedAudioBytesAzure SDK 启动完成前每路最多缓存的音频字节数,默认 524288
asrstartTimeoutMsAzure SDK 启动超时时间,默认 10000
asrautoDetectLanguagesAzure 自动识别候选语言,默认 ["zh-CN", "en-US"]
asrsampleRate / bitsPerSample / channels / format输入音频格式,默认 16000 / 16 / 1 / pcm
ttshost / portTTS HTTP 监听地址,默认端口 9082
ttspublicBaseUrl返回给调用方的公开访问基址,必须是 FreeSWITCH 可访问的地址
ttsdefaultVoice / voices默认音色与 speakerId 到 Azure voice 的映射
ttsoutputFormat / streamOutputFormatAzure TTS REST 的 WAV 与 MP3 输出格式
ttsrequestTimeoutMsAzure TTS REST 请求超时时间,默认 30000
ttsmaxTextLength单次合成文本长度上限
loggingdir / maxSize / maxFiles / level控制台与按天轮转文件日志配置

asr.autoDetectLanguages 用于同一路 ASR 服务内自动检测语音语言,默认同时支持 中文普通话 zh-CN 与美式英语 en-US。常用候选值包括:zh-CNzh-HKzh-TWyue-CNwuu-CNzh-CN-sichuanen-USen-GBen-AUen-CAen-INja-JPko-KRfr-FRde-DEes-ESit-ITpt-BRru-RUth-THvi-VNid-IDhi-IN。完整支持列表以 Microsoft Azure Speech language support 官方文档为准。

ASR 接口

健康检查

http
GET http://127.0.0.1:10098/health

响应示例:

json
{
  "ok": true,
  "service": "azure-speech-gateway-asr",
  "activeSessions": 0,
  "maxSessions": 64,
  "wsPath": "/audio",
  "ioWorkers": 1
}

实时识别 WebSocket

默认地址:

text
ws://127.0.0.1:10098/audio

连接要求:

  • 请求头 Sec-WebSocket-Protocol 需要包含配置中的 asr.wsSubprotocol
  • 第一个文本帧可携带 metadata,常见字段包括 channel_uuidchannelUuiduuidcall_uuidcallUuidsessionIdsession_id
  • 后续二进制帧为 16kHz、16-bit、单声道 PCM 音频。
  • 发送零长度二进制帧表示请求服务端 flush 并关闭 Azure 识别会话。

识别结果消息示例:

json
{
  "type": "transcription",
  "data": {
    "text": "您好,请问有什么可以帮您",
    "isFinal": true,
    "utteranceIndex": 1,
    "speechStarted": true,
    "speechActive": false,
    "speechSegmentDetected": true,
    "speechSegmentCompleted": true,
    "serverSessionId": "ws-1",
    "channelUuid": "call-uuid",
    "metadataText": "{\"channel_uuid\":\"call-uuid\"}",
    "finalReason": "final",
    "flushReason": "zero-length-binary"
  }
}

错误消息示例:

json
{
  "type": "error",
  "data": {
    "message": "Azure Speech recognition canceled"
  }
}

TTS 接口

健康检查

http
GET http://127.0.0.1:9082/health

响应会返回服务监听信息、当前采样率和可用 speakers。该结构兼容管理台对 TTS 服务的健康检查。

普通 WAV 合成

http
POST http://127.0.0.1:9082/tts
Content-Type: application/json

{
  "text": "您好,欢迎致电。",
  "speakerId": 0,
  "speed": 1
}

响应示例:

json
{
  "wavUrl": "http://127.0.0.1:9082/wav/tts-0123456789abcdef.wav",
  "fileName": "tts-0123456789abcdef.wav",
  "sampleRate": 16000,
  "cached": false
}

相同 text + speakerId + speed + voice 的请求会复用 public/wav/ 下的缓存文件。 生成后的 WAV 可以通过以下接口读取:

http
GET  http://127.0.0.1:9082/wav/tts-0123456789abcdef.wav
HEAD http://127.0.0.1:9082/wav/tts-0123456789abcdef.wav

流式 MP3 合成

先创建一个短期流式播放链接:

http
POST http://127.0.0.1:9082/tts-stream
Content-Type: application/json

{
  "text": "这是一段需要尽快开始播放的文本。",
  "speakerId": 0,
  "speed": 1
}

响应示例:

json
{
  "streamUrl": "http://127.0.0.1:9082/tts-stream/tts-0123456789abcdef.mp3",
  "streamPath": "/tts-stream/tts-0123456789abcdef.mp3",
  "sampleRate": 16000,
  "cached": false
}

随后客户端访问 streamUrl,服务会在该 GET 连接内调用 Azure TTS REST 并输出 Content-Type: audio/mpeg 的 MP3 数据流,同时写入 public/mp3/ 下的本地缓存文件。 相同 text + speakerId + speed + voice + format=mp3 的请求会复用同一个 tts-<16位hash>.mp3,缓存命中时 POST /tts-stream 会返回 cached: true

http
GET  http://127.0.0.1:9082/tts-stream/tts-0123456789abcdef.mp3
HEAD http://127.0.0.1:9082/tts-stream/tts-0123456789abcdef.mp3

首次 GET 如果合成失败、客户端断开或写文件失败,服务会删除临时文件,不留下半截 正式缓存。5 分钟 TTL 只限制未生成缓存前的内存播放票据;已经落盘的 MP3 文件不受 该 TTL 限制。

对接注意事项

  • 如果要让 callflow-esl 使用 Azure ASR,把 apps/callflow-esl/config.jsonaudioFork.wsUrl 改为 ws://<gateway-host>:10098/audiobugNamemixType=monosampleRate=16k 保持与本地 ASR 一致即可。
  • 如果要让 callflow-esl 使用 Azure TTS,把 tts.profiles.wav.endpoint 改为 http://<gateway-host>:9082/tts,把 tts.profiles.shout.endpoint 改为 http://<gateway-host>:9082/tts-stream。流式播放仍按 tts.profiles.shout.playbackPrefix 交给 FreeSWITCH 播放。
  • 管理台的 TTS 试听页可以直接填 http://<gateway-host>:9082/tts;ASR 测试页可把 主机和端口改成 <gateway-host>:10098,上传 16kHz mono PCM16 WAV 或用浏览器录音测试。
  • tts.publicBaseUrl 必须配置成 FreeSWITCH 或调用方能够访问到的地址;如果服务 运行在另一台机器上,不要保留默认的 127.0.0.1
  • ASR 输入默认按 16kHz 单声道 PCM 处理,调用方需要保证实际音频格式与 asr.sampleRateasr.bitsPerSampleasr.channels 一致。
  • /wav/:fileName 只允许读取本服务生成的 tts-<16位hash>.wav 文件名,避免 通过 URL 访问其他本地文件。
  • /tts-stream/:fileName 只允许读取本服务生成的 tts-<16位hash>.mp3 文件名, 避免通过 URL 访问其他本地文件。
  • 本服务没有内置鉴权,建议只暴露在可信网络内,或放在带鉴权的反向代理之后。
  • 任务结束后如果手动启动过服务,请停止对应 Bun 进程,避免端口被后续联调占用。

文档与代码在同一仓库维护,现有 Markdown 是唯一内容源。