Documentation
¶
Index ¶
- func SanitizeForTTS(text string) string
- func StripVoiceTags(text string) string
- type Client
- func NewAliyunClient(apiKey, voice, model, url string) Client
- func NewCartesiaClient(apiKey, voiceID string) Client
- func NewCartesiaWSClient(apiKey, voiceID, wsURL string) Client
- func NewClient(cfg *config.Config) (Client, error)
- func NewDeepgramClient(apiKey, model string) Client
- func NewElevenLabsClient(apiKey, voiceID, model string) Client
- func NewMiMoClient(apiKey, voice, model, baseURL string) Client
- func NewMiniMaxClient(apiKey, voiceID, model, baseURL string) Client
- func NewSpeechifyClient(apiKey, voiceID, model string) Client
- func NewTelnyxClient(apiKey, voice string, voiceSpeed float64) Client
- func NewVibeVoiceClient(baseURL, voice string) Client
- func NewVolcengineClient(apiKey, speaker, resource, url string) Client
- type ControllableStreamer
- type ErrMissingAPIKey
- type StreamChunk
- type TelnyxClient
- func (c *TelnyxClient) Synthesize(ctx context.Context, text string) ([]byte, error)
- func (c *TelnyxClient) SynthesizeStream(ctx context.Context, text string) (<-chan StreamChunk, error)
- func (c *TelnyxClient) SynthesizeStreamWithControls(ctx context.Context, text string, vc VoiceControls) (<-chan StreamChunk, error)
- type VoiceControls
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func SanitizeForTTS ¶
SanitizeForTTS removes Markdown formatting characters that TTS engines would otherwise read aloud literally (e.g. "asterisk asterisk Nissan Leaf"). It preserves the underlying text content. RAG chunks and LLM output frequently contain bullet lists, bold spans, and code fences; stripping them here ensures the synthesizer never voices a stray '*'.
func StripVoiceTags ¶
StripVoiceTags removes every known [tag] occurrence from text — used when recording transcripts so delivery hints never pollute what reviews and the LLM history treat as spoken words.
Types ¶
type Client ¶
type Client interface {
// Synthesize produces the full audio for text in one shot.
Synthesize(ctx context.Context, text string) ([]byte, error)
// SynthesizeStream produces audio incrementally via a channel, so playback
// can begin before the full utterance is ready. The channel is always
// closed by the producer (even on error). Cancel ctx to abort early.
//
// Providers that return audio in a single envelope (a JSON body, say)
// satisfy this by emitting one chunk — callers need not care which.
SynthesizeStream(ctx context.Context, text string) (<-chan StreamChunk, error)
}
Client synthesizes text to PCM audio (linear16, 16kHz mono).
func NewAliyunClient ¶ added in v0.1.2
NewAliyunClient creates a Model Studio TTS client. Empty voice, model and url fall back to the package defaults.
func NewCartesiaClient ¶
NewCartesiaClient creates a Cartesia Sonic TTS client. voiceID defaults to Katie if empty.
func NewCartesiaWSClient ¶
NewCartesiaWSClient creates a Cartesia TTS client backed by the WebSocket API. The connection is established lazily on first synthesis request. voiceID defaults to Katie if empty. wsURL overrides the WebSocket endpoint (intended for local dev — see config.CartesiaConfig.WSURL). Empty wsURL means production wss://api.cartesia.ai/tts/websocket.
func NewClient ¶
NewClient returns a TTS client for the configured provider. The returned client wraps the provider in a sanitizer that strips Markdown formatting from every input — TTS engines read characters like '*' and '#' aloud literally, so RAG snippets or LLM-emitted markdown must be scrubbed before synthesis.
func NewDeepgramClient ¶
NewDeepgramClient creates a Deepgram Aura TTS client. An empty model falls back to defaultDeepgramTTSModel.
func NewElevenLabsClient ¶
NewElevenLabsClient creates an ElevenLabs TTS client. voiceID defaults to Rachel if empty. model defaults to eleven_turbo_v2_5.
func NewMiMoClient ¶
NewMiMoClient creates a Xiaomi MiMo TTS client. Empty voice, model and baseURL fall back to the package defaults.
func NewMiniMaxClient ¶
NewMiniMaxClient creates a MiniMax T2A v2 TTS client. Empty voiceID, model and baseURL fall back to the package defaults.
func NewSpeechifyClient ¶
NewSpeechifyClient creates a Speechify Simba TTS client. voiceID defaults to Geffen if empty. model defaults to simba-3.2.
func NewTelnyxClient ¶ added in v0.1.3
NewTelnyxClient creates a Telnyx TTS client. Empty voice defaults to the Qwen3TTS voice Delta; zero voiceSpeed defaults to 1.0.
func NewVibeVoiceClient ¶
NewVibeVoiceClient creates a client that talks to the VibeVoice TTS server. baseURL is the HTTP address (e.g. http://127.0.0.1:8300). voice defaults to "en-Emma_woman" if empty.
func NewVolcengineClient ¶ added in v0.1.3
NewVolcengineClient creates a Doubao TTS client. Empty speaker, resource and url fall back to the package defaults.
type ControllableStreamer ¶
type ControllableStreamer interface {
SynthesizeStreamWithControls(ctx context.Context, text string, vc VoiceControls) (<-chan StreamChunk, error)
}
ControllableStreamer is the optional capability interface for providers (and wrappers) that accept per-utterance voice controls. Callers type-assert and fall back to plain SynthesizeStream when unsupported, so adding a provider never requires touching every Client implementation.
type ErrMissingAPIKey ¶
func (ErrMissingAPIKey) Error ¶
func (e ErrMissingAPIKey) Error() string
type StreamChunk ¶
StreamChunk represents a chunk of synthesized PCM audio streamed from the TTS provider. The channel closes when synthesis is complete. If Err is non-nil the synthesis failed and no further chunks will arrive.
type TelnyxClient ¶ added in v0.1.3
type TelnyxClient struct {
// contains filtered or unexported fields
}
TelnyxClient implements the Client interface against Telnyx's streaming text-to-speech WebSocket API.
The protocol has no per-utterance completion marker: the server emits its isFinal frame only after the client sends an empty-text teardown, and on a persistent connection there is no way to tell one utterance's audio from the next. The adapter therefore opens one connection per utterance: dial, init, text, teardown, collect audio until isFinal, server closes. Measured against the persistent alternative this costs nothing on the live path: synthesis outpaces playback ~2.4x, first audio lands well under a second after dial, and every completion heuristic is avoided.
func (*TelnyxClient) Synthesize ¶ added in v0.1.3
Synthesize produces the full audio for text in one shot by collecting all chunks from SynthesizeStream.
func (*TelnyxClient) SynthesizeStream ¶ added in v0.1.3
func (c *TelnyxClient) SynthesizeStream(ctx context.Context, text string) (<-chan StreamChunk, error)
SynthesizeStream produces PCM audio incrementally via a channel. One utterance maps to one WebSocket connection: dial, init with the resolved voice speed, the full text with flush so synthesis starts immediately, then the empty-text teardown that makes the server emit isFinal and close.
func (*TelnyxClient) SynthesizeStreamWithControls ¶ added in v0.1.3
func (c *TelnyxClient) SynthesizeStreamWithControls(ctx context.Context, text string, vc VoiceControls) (<-chan StreamChunk, error)
SynthesizeStreamWithControls is SynthesizeStream with per-utterance voice controls. The speed rides the init frame of each per-utterance connection, so it can change from one utterance to the next.
type VoiceControls ¶
type VoiceControls struct {
// Speed is a playback-rate multiplier (1.0 = normal). Zero = unset.
// Providers clamp to their own safe range.
Speed float64
// Tone is the normalized tag the LLM emitted ("warm", "empathetic",
// …). Providers with richer expressiveness settings may map it beyond
// speed (e.g. ElevenLabs stability).
Tone string
}
VoiceControls carries per-utterance delivery hints from the conversation layer to the TTS provider — the difference between a flat robotic "sorry, I didn't catch that" and a warm, slightly slower one. Zero value means "provider defaults".
func ParseVoiceTag ¶
func ParseVoiceTag(sentence string) (VoiceControls, string)
ParseVoiceTag strips one leading [tag] from a sentence and returns the matching controls plus the clean sentence. Sentences without a known leading tag come back unchanged with zero controls.
func (VoiceControls) IsZero ¶
func (vc VoiceControls) IsZero() bool
IsZero reports whether no controls were requested.