client

package module
v0.3.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 31, 2026 License: MIT Imports: 2 Imported by: 0

README

Tengen Speech SDK for Go

Go 语言语音服务客户端 SDK,连接 Speech Arena Gateway,提供流式 TTS(文本转语音)和流式 STT(语音转文本)功能。

安装

go get github.com/jinbozhan/tengen-speech-sdk-go@v0.3.1

TTS - 流式文本转语音

单次合成
import (
    "io"
    "time"
    "github.com/jinbozhan/tengen-speech-sdk-go/tts"
)

config := &tts.Config{
    GatewayURL:     "ws://localhost:8080",
    Provider:       "tengen",
    APIKey:         "sk_xxx",
    VoiceID:        "loongstella",
    Speed:          1.0,
    SampleRate:     8000,
    AudioFormat:    "pcm",
    ConnectTimeout: 30 * time.Second,
    ReadTimeout:    120 * time.Second,
}

client, _ := tts.NewClient(config)
defer client.Close()

// 流式合成,stream 实现 io.Reader
stream, _ := client.SynthesizeStream(ctx, "你好,世界")
defer stream.Close()
io.Copy(outputFile, stream)
多轮合成(Session 复用)

创建一个 Session 后可多次合成,避免重复建连:

session, _ := client.CreateSession(ctx, nil)
defer session.Close()

for _, text := range []string{"第一句", "第二句", "第三句"} {
    stream, _ := session.SynthesizeStream(ctx, text)
    buf := make([]byte, 4096)
    for {
        n, err := stream.Read(buf)
        if n > 0 {
            // 处理音频 buf[:n]
        }
        if err == io.EOF {
            break
        }
    }
}

STT - 流式语音转文本

import (
    "time"
    "github.com/jinbozhan/tengen-speech-sdk-go/stt"
)

config := &stt.Config{
    GatewayURL:     "ws://localhost:8080",
    Provider:       "tengen",
    APIKey:         "sk_xxx",
    Language:       "zh-CN",
    // Languages:   []string{"ms-MY", "en-SG"}, // 多语言候选(LID),非空时优先于 Language
    SampleRate:     16000,
    AudioFormat:    "pcm",
    ConnectTimeout: 30 * time.Second,
    ReadTimeout:    120 * time.Second,
}

client, _ := stt.NewClient(config)
defer client.Close()

// 创建流式会话
session, _ := client.CreateSession(ctx, &stt.StreamOptions{
    Language:    "zh-CN",
    SampleRate:  16000,
    AudioFormat: "pcm",
})
defer session.Close()

// goroutine 发送音频
go func() {
    chunkSize := 16000 * 2 * 100 / 1000 // 100ms 音频块
    buf := make([]byte, chunkSize)
    for {
        n, err := audioReader.Read(buf)
        if err == io.EOF {
            break
        }
        session.Send(buf[:n])
    }
    session.EndInput() // 标记发送完毕
}()

// 接收识别事件
for event := range session.Events() {
    switch event.Type {
    case stt.EventTranscriptPartial:
        fmt.Printf("\r[Partial] %s", event.Text)
    case stt.EventTranscriptFinal:
        // event.Language:LID 检测到的语言(provider 支持且启用多语言候选时填充)
        fmt.Printf("\r[Final] [%.3fs-%.3fs] [%s] %s\n",
            event.StartTime.Seconds(), event.EndTime.Seconds(), event.Language, event.Text)
    case stt.EventSpeechStarted:
        fmt.Println("[SpeechStarted]")
    case stt.EventError:
        fmt.Printf("[Error] %v\n", event.Error)
    case stt.EventSessionEnded:
        break
    }
}

fmt.Printf("TTFB: %dms\n", session.TTFB().Milliseconds())
多语言候选(LID)

传入候选语言列表后,支持 LID 的 provider(如 azure)会在候选集内自动检测实际语言:

config.WithLanguages("ms-MY", "en-SG") // 非空时优先于 Language

// 或在创建会话时通过 StreamOptions 指定
session, _ := client.CreateSession(ctx, &stt.StreamOptions{
    Languages:   []string{"ms-MY", "en-SG"},
    SampleRate:  16000,
    AudioFormat: "pcm",
})

检测到的语言通过最终结果事件的 event.Language 回传(仅 EventTranscriptFinal,provider 支持时填充)。

命令行示例

./build.sh
TTS
./bin/tts_stream "你好,世界"
./bin/tts_stream "第一句" "第二句" "第三句"
./bin/tts_stream -provider qwen -voice loongstella -apikey "sk_xxx" "测试"
./bin/tts_stream -speed 1.5 -sample-rate 16000 -output result.wav "快速播放"
参数 默认值 说明
-gateway ws://localhost:8080 Gateway 地址
-provider qwen TTS 提供商
-apikey - API Key
-session-id - 会话 ID(每通电话唯一;与该通话的 STT 使用同值以便 Gateway 侧日志/录音关联;留空由 Gateway 生成)
-voice loongstella Voice ID
-language - 语言代码(文本归一化用,如 en-NG, sw-TZ)
-speed 1.0 语速 (0.5-2.0)
-pitch 1.0 音调 (-10 to 10)
-volume 1.0 音量 (0.0-1.0)
-output output.wav 输出文件路径
-sample-rate 8000 采样率
-channels 1 声道数
-bits 16 采样位深
STT
./bin/stt_stream audio.wav
./bin/stt_stream -provider qwen -language en-US recording.wav
./bin/stt_stream -provider azure -languages ms-MY,en-SG recording.wav
./bin/stt_stream -apikey "sk_xxx" audio.wav
参数 默认值 说明
-gateway ws://localhost:8080 Gateway 地址
-provider azure STT 提供商
-apikey - API Key
-session-id - 会话 ID(每通电话唯一;与该通话的 TTS 使用同值以便 Gateway 侧日志/录音关联;留空由 Gateway 生成)
-language zh-CN 识别语言
-languages - 多语言候选列表(LID),逗号分隔,如 ms-MY,en-SG;非空时优先于 -language
-sample-rate 8000 采样率
-interval 100 音频发送间隔 (ms)

支持的 Provider

Provider STT TTS 说明
tengen Y Y 默认。STT 由网关兜底到 azure;TTS 按 voice_id 查音色库决定实际 provider
azure Y Y Microsoft Azure Speech Services
qwen Y Y 阿里通义千问实时语音
byteplus Y Y BytePlus 语音服务
google Y Y Google Cloud Speech
eleven Y Y ElevenLabs
resemble -- Y Resemble AI(仅 TTS)

STT 侧网关对 tengen/空以外的值原样透传、不做校验:填了不存在的 provider 会在建流时才失败。TTS 侧 provider 仅用于漂移监控,实际 provider 由 voice_id 决定。

前置条件

  1. 运行 Speech Arena Gateway
  2. 获取有效的 API Key(如需认证)

版本历史

v0.3.1
  • 更正 provider 清单:voxnexus 的实现已从 Gateway 下线,README / stt.StreamOptions / tts.SynthesisOptions / docs / protocol 却仍在宣称支持,照着写 Provider: "voxnexus" 要到建流时才失败(STT 侧 Gateway 对 tengen/空以外的值原样透传、不做校验)。按 Gateway 实际注册更正为 STT azure / qwen / byteplus / google / eleventengen 与空值兜底到 azure),TTS 在此基础上多一个 resemble;TTS 的 provider 仅用于漂移监控,实际 provider 由 voice_id 查音色库决定
  • protocol/messages.go 与 Gateway 侧逐字节对齐(此前两份手工拷贝已漂移,无任何同步机制):新增 ErrorCodeTextDecryptFailedTEXT_DECRYPT_FAILED,TTS 入向文本解密失败,客户端会收到该错误码,此前缺常量只能硬编码字符串);补齐 SpeechStarted(慢确认信号,不可用作打断触发)与 TranscriptPartial / TranscriptFinal 的完整文档注释;文件头加同步警示,并列出允许存在的差异
  • NewTranscriptPartial / NewTranscriptFinal 标记 Deprecated:SDK 只消费不生产这两类 S→C 消息,二者无调用点且不填 Language / turn 字段,构造出的消息是残缺的。仅打标记,未删除,编译不受影响
  • 纯文档与常量增量,未改动任何已发布 API 签名,调用方无需改动
v0.3.0
  • STT 支持轮次判定:RecognitionEvent 新增 TurnState(complete/incomplete,交棒判据)、TurnIntent(backchannel/wait/normal,决定停不停 TTS)、Trigger(rule/timeout,判定来源)三个字段,由 Gateway 的 turn_detection 开启后下发;同时新增 TurnState* / TurnIntent* / TurnTrigger* 常量组
  • 交棒必须联合判断 TurnState == complete && TurnIntent != wait:只看 TurnState 会在用户说「等一下」时抢话。backchannel 不阻止交棒——「嗯嗯」「好的」是推进分段话术的应答位,短路掉会让机器人停在上一段说不下去
  • TurnIntent 空串 不等于 normal:空串表示本会话无意图判定能力(Gateway 未开启 / 语言未覆盖 / provider 无 partial),normal 表示判过了是普通语音。遇到未知取值时按 normal / incomplete 处理(都往保守侧)
  • 重新引入 speech.stopped 协议消息与 EventSpeechStopped 事件(v0.1.2 曾因 Gateway 未实现而移除)。它是物理静音不是语义轮次结束,不可用于触发交棒;用途是解除等待、超时兜底与 UI 指示。Gateway 保证仅在本段发过 speech.started 后才下发。此前该消息落到未知类型分支,每个语音段刷一条 Warn 日志
  • 调用方无需改动即可编译:纯增量,未改动任何已发布 API 签名。不消费新字段时行为与 v0.2.2 一致
  • RecognitionResult.Segments 不携带轮次字段(与它同样不携带 Language 一致);需要轮次判定请用 CreateSession 的事件流 API
  • stt_stream 示例打印新字段并处理 speech.stopped
v0.2.2
  • 修复服务端优雅关闭(WS Close Frame 1000/1001)时 STT/TTS messageLoop 永久阻塞:该路径只关 conn.closeCh、不写 errorCh,此前 select 无对应分支,导致 STT Events() 的 channel 永不关闭、调用方 for range 卡死,goroutine 与连接滞留到 Session.Close()。典型触发是 Gateway 滚动发布(1001);Gateway 崩溃 / 断网(1006)走 errorCh,此前即正常
  • 调用方无需改动:STT Events() 会正常关闭,for range 自然结束;断连不补发事件,事件类型与话单口径不变。TTS 侧不改变 AudioStream 语义(仍由调用方自身超时兜底),避免断连被误判为"合成正常结束"
v0.2.1
  • STT/TTS 支持逐通话会话 ID:新增 StreamOptions.SessionID / SynthesisOptions.SessionID,经 WS URL session_id 参数透传给 Gateway;同一通话的 STT/TTS 传同值即可在 Gateway 侧关联日志/录音,留空由 Gateway 生成。仅 CreateSession / SynthesizeStreamWithOptions 支持;简化 API(RecognizeFile / RecognizeBytes / SynthesizeToFile / SynthesizeToBytes)不透传。Gateway 未回传同值时 SDK 打印 Warn 日志
  • CreateSession / SynthesizeStreamWithOptions 支持部分填充的 options:零值字段自动回填 client Config 对应值(此前传非 nil opts 时未填字段会按零值发送)
  • TTS WS URL 的 voice_id 预热参数改为 per-call opts 优先、Config 兜底
  • stt_stream / tts_stream 示例新增 -session-id 参数
v0.2.0
  • STT 支持多语言候选(LID):新增 Config.Languages / StreamOptions.Languages 候选语言列表,非空时优先于 Language;最终识别结果通过 RecognitionEvent.Language 回传检测到的语言
  • stt_stream 示例新增 -languages 参数(逗号分隔候选语言)
v0.1.2
  • 移除 speech.stopped 协议消息、SpeechStopped 结构体及 EventSpeechStopped 事件,清理未使用的代码路径
  • 重命名 examples-sdk 为 examples,统一目录结构
  • 新增 EventSpeechStarted 事件类型
  • TTS CLI 默认 provider 切换为 qwen
  • 新增 TTS Benchmark、TTS Detailed Timing、VAD-Clip ASR 工具
v0.1.1
  • 流式 STT/TTS 稳定版,统一 SDK 接口,日志迁移至 slog

Documentation

Overview

Package client 客户端错误定义

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrSessionNotReady 会话未就绪
	ErrSessionNotReady = errors.New("session not ready")

	// ErrSessionClosed 会话已关闭
	ErrSessionClosed = errors.New("session closed")

	// ErrProviderNotSupported 不支持的提供商
	ErrProviderNotSupported = errors.New("provider not supported")

	// ErrInvalidConfig 无效配置
	ErrInvalidConfig = errors.New("invalid configuration")

	// ErrAudioFormatNotSupported 不支持的音频格式
	ErrAudioFormatNotSupported = errors.New("audio format not supported")

	// ErrFileNotFound 文件未找到
	ErrFileNotFound = errors.New("file not found")

	// ErrTimeout 操作超时
	ErrTimeout = errors.New("operation timeout")
)

预定义错误

Functions

func IsConnectionError

func IsConnectionError(err error) bool

IsConnectionError 判断是否为连接错误

func IsRetryable

func IsRetryable(err error) bool

IsRetryable 判断错误是否可重试

func IsTimeoutError

func IsTimeoutError(err error) bool

IsTimeoutError 判断是否为超时错误

func WrapError

func WrapError(op string, err error) error

WrapError 包装错误

Types

type ClientError

type ClientError struct {
	Op       string // 操作名称
	Provider string // 提供商
	Code     string // 错误代码
	Message  string // 错误信息
	Err      error  // 底层错误
}

ClientError 客户端错误

func NewClientError

func NewClientError(op, provider, code, message string, err error) *ClientError

NewClientError 创建客户端错误

func NewConfigError

func NewConfigError(op, message string) *ClientError

NewConfigError 创建配置错误

func NewConnectionError

func NewConnectionError(op, message string, err error) *ClientError

NewConnectionError 创建连接错误

func NewProtocolError

func NewProtocolError(op, message string, err error) *ClientError

NewProtocolError 创建协议错误

func NewProviderError

func NewProviderError(op, provider, code, message string) *ClientError

NewProviderError 创建提供商错误

func NewTimeoutError

func NewTimeoutError(op, message string) *ClientError

NewTimeoutError 创建超时错误

func (*ClientError) Error

func (e *ClientError) Error() string

func (*ClientError) Unwrap

func (e *ClientError) Unwrap() error

Directories

Path Synopsis
Package audio 音频格式转换
Package audio 音频格式转换
cmd
test_vad_clip_asr command
Package main - VAD-Clip ASR 端到端正确性测试
Package main - VAD-Clip ASR 端到端正确性测试
tts_benchmark command
Package main 提供TTS并发测试工具
Package main 提供TTS并发测试工具
tts_detailed_timing command
Package main 提供TTS详细时延分析工具
Package main 提供TTS详细时延分析工具
examples
stt_stream command
Package main STT 客户端演示程序
Package main STT 客户端演示程序
tts_pipeline command
Package main TTS 管道化合成示例
Package main TTS 管道化合成示例
tts_stream command
Package main TTS 多轮合成示例
Package main TTS 多轮合成示例
Package logging 提供人类友好的 slog 日志格式化
Package logging 提供人类友好的 slog 日志格式化
Package protocol 定义统一 WebSocket 消息协议
Package protocol 定义统一 WebSocket 消息协议
Package stt 提供STT客户端SDK
Package stt 提供STT客户端SDK
Package transport 提供WebSocket连接管理
Package transport 提供WebSocket连接管理
Package tts 提供TTS客户端SDK
Package tts 提供TTS客户端SDK

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL