跳到正文

aliyun-speech-gateway

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

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

  • ASR WebSocket 服务:默认 0.0.0.0:10097
  • TTS HTTP 服务:默认 0.0.0.0:9081

运行

在仓库根目录运行:

bash
bun install
bun run dev:aliyun-speech

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

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

配置

配置文件位于 apps/aliyun-speech-gateway/config.json。阿里云凭据建议优先通过 环境变量传入,避免把机器或账号专属值写死到代码中:

powershell
$env:ALIYUN_NLS_APP_KEY="your-app-key"
$env:ALIYUN_NLS_TOKEN="your-token"
$env:ALIYUN_NLS_URL="wss://nls-gateway-cn-shanghai.aliyuncs.com/ws/v1"
bun run --cwd apps/aliyun-speech-gateway start
配置段字段用途
aliyunappKey / token / url阿里云 NLS 应用、临时 token 与网关地址;appKeytoken 可被环境变量覆盖
asrhost / portASR HTTP/WebSocket 监听地址
asrhealthPath / wsPath健康检查与音频 WebSocket 路径,默认 /health/audio
asrwsSubprotocolWebSocket 子协议,默认 audio.drachtio.org,用于兼容 mod_audio_fork
asrmaxSessions最大并发 ASR 会话数
asrstartTimeoutMs / maxQueuedBytes / maxQueuedChunks阿里云 ASR 启动超时,以及启动完成前允许暂存的音频队列上限
asrsampleRate / format发送给阿里云识别 SDK 的音频格式,默认 16000 / pcm
ttshost / portTTS HTTP 监听地址
ttspublicBaseUrl返回给调用方的公开访问基址,必须是 FreeSWITCH 可访问的地址
ttssampleRate合成音频采样率
ttsrequestTimeoutMs / streamStartTimeoutMs普通 TTS 总请求超时,以及流式 TTS 首包超时
ttsdefaultVoice / voices默认音色与 speakerId 到阿里云 voice 的映射
ttsvolume / pitchRate / maxTextLength合成音量、音调和单次文本长度上限
loggingdir / maxSize / maxFiles / level控制台与按天轮转文件日志配置

ASR 接口

健康检查

http
GET http://127.0.0.1:10097/health

响应示例:

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

实时识别 WebSocket

默认地址:

text
ws://127.0.0.1:10097/audio

连接要求:

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

识别结果消息示例:

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": "endpoint",
    "flushReason": "zero-length-binary"
  }
}

错误消息示例:

json
{
  "type": "error",
  "data": {
    "message": "Aliyun NLS request failed"
  }
}

TTS 接口

健康检查

http
GET http://127.0.0.1:9081/health

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

普通 WAV 合成

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

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

响应示例:

json
{
  "wavUrl": "http://127.0.0.1:9081/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:9081/wav/tts-0123456789abcdef.wav
HEAD http://127.0.0.1:9081/wav/tts-0123456789abcdef.wav

流式 MP3 合成

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

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

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

响应示例:

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

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

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

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

对接注意事项

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

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