tts

package
v1.4.9 Latest Latest
Warning

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

Go to latest
Published: May 18, 2026 License: Apache-2.0 Imports: 19 Imported by: 2

Documentation

Overview

Package tts provides text-to-speech services. This file contains WebSocket streaming implementation for Cartesia TTS. It is excluded from coverage testing due to the difficulty of mocking WebSocket connections.

Package tts provides text-to-speech services for converting text responses to audio.

The package defines a common Service interface that abstracts TTS providers, enabling voice AI applications to convert text-only LLM responses to speech.

Architecture

The package provides:

  • Service interface for TTS providers
  • SynthesisConfig for voice/format configuration
  • Voice and AudioFormat types for provider capabilities
  • Multiple provider implementations (OpenAI, ElevenLabs, etc.)

Usage

Basic usage with OpenAI TTS:

service := tts.NewOpenAI(os.Getenv("OPENAI_API_KEY"))
reader, err := service.Synthesize(ctx, "Hello world", tts.SynthesisConfig{
    Voice:  "alloy",
    Format: tts.FormatMP3,
})
if err != nil {
    log.Fatal(err)
}
defer reader.Close()

// Stream audio to speaker or save to file
io.Copy(audioOutput, reader)

Streaming TTS

For low-latency applications, use StreamingService:

streamer := tts.NewCartesia(os.Getenv("CARTESIA_API_KEY"))
chunks, err := streamer.SynthesizeStream(ctx, "Hello world", config)
for chunk := range chunks {
    // Play audio chunk immediately
    speaker.Write(chunk)
}

Available Providers

The package includes implementations for:

  • OpenAI TTS (tts-1, tts-1-hd models)
  • ElevenLabs (high-quality voice cloning)
  • Cartesia (ultra-low latency streaming)
  • Google Cloud Text-to-Speech (multi-language)

Index

Constants

View Source
const (

	// ElevenLabsModelMultilingual is the multilingual v2 model.
	ElevenLabsModelMultilingual = "eleven_multilingual_v2"
	// ElevenLabsModelTurbo is the fast turbo v2.5 model.
	ElevenLabsModelTurbo = "eleven_turbo_v2_5"
	// ElevenLabsModelEnglish is the English monolingual v1 model.
	ElevenLabsModelEnglish = "eleven_monolingual_v1"
	// ElevenLabsModelMultilingualV1 is the older multilingual v1 model.
	ElevenLabsModelMultilingualV1 = "eleven_multilingual_v1"
	// ElevenLabsModelV3 is the v3 expressive model that natively consumes
	// inline characterization tags such as "[whispers]" / "[laughs]".
	// Markup tags are passed through verbatim in the request body for
	// any model whose ID starts with "eleven_v3".
	ElevenLabsModelV3 = "eleven_v3"
)
View Source
const (

	// ModelTTS1 is the OpenAI TTS model optimized for speed. Does not
	// support the `instructions` field — characterization tags supplied
	// to this model are stripped from the spoken text and the LLM
	// directives are dropped (with a debug log).
	ModelTTS1 = "tts-1"
	// ModelTTS1HD is the OpenAI TTS model optimized for quality. Also
	// has no `instructions` support; same behavior as ModelTTS1 for
	// characterization tags.
	ModelTTS1HD = "tts-1-hd"
	// ModelGPT4oMiniTTS is the expressive OpenAI TTS model. Honors the
	// `instructions` request field, which the adapter populates from
	// markup tags in the input text (see runtime/tts/markup).
	ModelGPT4oMiniTTS = "gpt-4o-mini-tts"
)
View Source
const (
	VoiceAlloy   = "alloy"   // Neutral voice.
	VoiceEcho    = "echo"    // Male voice.
	VoiceFable   = "fable"   // British accent.
	VoiceOnyx    = "onyx"    // Deep male voice.
	VoiceNova    = "nova"    // Female voice.
	VoiceShimmer = "shimmer" // Soft female voice.
)

OpenAI voices.

View Source
const (

	// CartesiaModelSonic is the current Sonic model alias for Cartesia
	// TTS. Cartesia retired the dated `sonic-YYYY-MM-DD` IDs; "sonic-3"
	// is the latest generation (better naturalness + faster TTFB than
	// sonic-2 and the original sonic).
	CartesiaModelSonic = "sonic-3"
)

Variables

View Source
var (
	// ErrInvalidVoice is returned when the requested voice is not available.
	ErrInvalidVoice = errors.New("invalid or unsupported voice")

	// ErrInvalidFormat is returned when the requested format is not supported.
	ErrInvalidFormat = errors.New("invalid or unsupported audio format")

	// ErrEmptyText is returned when attempting to synthesize empty text.
	ErrEmptyText = errors.New("text cannot be empty")

	// ErrSynthesisFailed is returned when TTS synthesis fails.
	ErrSynthesisFailed = errors.New("speech synthesis failed")

	// ErrRateLimited is returned when API rate limits are exceeded.
	ErrRateLimited = errors.New("rate limit exceeded")

	// ErrQuotaExceeded is returned when account quota is exceeded.
	ErrQuotaExceeded = errors.New("quota exceeded")

	// ErrServiceUnavailable is returned when the TTS service is unavailable.
	ErrServiceUnavailable = errors.New("TTS service unavailable")
)

Common TTS errors.

View Source
var (
	// FormatMP3 is MP3 format (most compatible).
	FormatMP3 = AudioFormat{
		Name:       "mp3",
		MIMEType:   "audio/mpeg",
		SampleRate: sampleRateDefault,
		BitDepth:   0,
		Channels:   1,
	}

	// FormatOpus is Opus format (best for streaming).
	FormatOpus = AudioFormat{
		Name:       "opus",
		MIMEType:   "audio/opus",
		SampleRate: sampleRateDefault,
		BitDepth:   0,
		Channels:   1,
	}

	// FormatAAC is AAC format.
	FormatAAC = AudioFormat{
		Name:       "aac",
		MIMEType:   "audio/aac",
		SampleRate: sampleRateDefault,
		BitDepth:   0,
		Channels:   1,
	}

	// FormatFLAC is FLAC format (lossless).
	FormatFLAC = AudioFormat{
		Name:       "flac",
		MIMEType:   "audio/flac",
		SampleRate: sampleRateDefault,
		BitDepth:   bitDepthDefault,
		Channels:   1,
	}

	// FormatPCM16 is raw 16-bit PCM (for processing).
	FormatPCM16 = AudioFormat{
		Name:       "pcm",
		MIMEType:   "audio/pcm",
		SampleRate: sampleRateDefault,
		BitDepth:   bitDepthDefault,
		Channels:   1,
	}

	// FormatWAV is WAV format (PCM with header).
	FormatWAV = AudioFormat{
		Name:       "wav",
		MIMEType:   "audio/wav",
		SampleRate: sampleRateDefault,
		BitDepth:   bitDepthDefault,
		Channels:   1,
	}
)

Common audio formats.

Functions

func APIKeyFromCredential added in v1.4.5

func APIKeyFromCredential(c credentials.Credential) string

APIKeyFromCredential returns the raw API key from an APIKey credential.

func ComputeTTSCost added in v1.4.7

func ComputeTTSCost(svc any, text string, latency time.Duration) *types.CostInfo

ComputeTTSCost computes the cost for a TTS call given the synthesized text and the service. The svc parameter accepts any value; non-pricer implementations (including mock services) return nil cost without error.

The returned CostInfo has:

  • Quantities["character"] set to the UTF-8 rune count of text
  • TotalCost set to the computed USD amount
  • Capability set to "tts"
  • ProviderName set from ImplName()
  • Latency set to the provided duration

func CostInfoToMetaMap deprecated added in v1.4.7

func CostInfoToMetaMap(ci *types.CostInfo) map[string]any

CostInfoToMetaMap is kept here as a deprecated alias for back-compat with existing call sites. Prefer base.CostInfoToMetaMap directly.

Deprecated: use base.CostInfoToMetaMap.

func PricingFromSpec added in v1.4.7

func PricingFromSpec(spec ProviderSpec) *base.PricingDescriptor

PricingFromSpec extracts an optional pricing override from spec.AdditionalConfig.

func RegisterFactory added in v1.4.5

func RegisterFactory(providerType string, factory Factory)

RegisterFactory registers a factory for the given provider type. Typically called from per-provider package init().

func ResolveCredential added in v1.4.5

func ResolveCredential(
	ctx context.Context,
	providerType string,
	cfgDir string,
	cred *credentials.CredentialConfig,
) (credentials.Credential, error)

ResolveCredential is a thin wrapper around base.ResolveCredential, kept here for back-compat with callers that resolve TTS-specific credential configs.

func SynthesizeWithRetry added in v1.4.2

func SynthesizeWithRetry(
	ctx context.Context,
	svc Service,
	text string,
	config SynthesisConfig,
	retry RetryConfig,
) (io.ReadCloser, error)

SynthesizeWithRetry calls svc.Synthesize with bounded retry on transient errors. Only errors where SynthesisError.Retryable is true are retried; all others are returned immediately. Uses full jitter backoff to avoid synchronized retries across concurrent callers.

func WithCartesiaWSURL

func WithCartesiaWSURL(url string) func(*CartesiaService)

WithCartesiaWSURL sets a custom WebSocket URL.

Types

type AudioFormat

type AudioFormat struct {
	// Name is the format identifier ("mp3", "opus", "pcm", "aac", "flac").
	Name string

	// MIMEType is the content type (e.g., "audio/mpeg").
	MIMEType string

	// SampleRate is the audio sample rate in Hz.
	SampleRate int

	// BitDepth is the bits per sample (for PCM formats).
	BitDepth int

	// Channels is the number of audio channels (1=mono, 2=stereo).
	Channels int
}

AudioFormat describes an audio output format.

func (AudioFormat) String

func (f AudioFormat) String() string

String returns the format name.

type CartesiaOption

type CartesiaOption = base.HTTPServiceOption

CartesiaOption configures the Cartesia TTS service. It is a type alias for base.HTTPServiceOption so callers can pass base.WithBaseURL, base.WithClient, base.WithModel, etc. directly. Use WithCartesiaWSURL for Cartesia-specific options.

type CartesiaService

type CartesiaService struct {
	*base.Implementation    // provides Name, Type, Pricing, Validate, Init, HealthCheck, Close
	*base.HTTPServiceFields // APIKey, BaseURL, Model, Client
	// contains filtered or unexported fields
}

CartesiaService implements TTS using Cartesia's ultra-low latency API. Cartesia specializes in real-time streaming TTS with <100ms first-byte latency.

func NewCartesia

func NewCartesia(apiKey string, opts ...CartesiaOption) *CartesiaService

NewCartesia creates a Cartesia TTS service.

func (*CartesiaService) Close added in v1.4.7

func (s *CartesiaService) Close() error

Close releases resources (no-op for TTS services; HTTP client is shared).

func (*CartesiaService) HealthCheck added in v1.4.7

func (s *CartesiaService) HealthCheck(_ context.Context) error

HealthCheck reports liveness (no-op for TTS services).

func (*CartesiaService) ImplName added in v1.4.7

func (s *CartesiaService) ImplName() string

ImplName returns the implementation name for cost tracking.

func (*CartesiaService) Init added in v1.4.7

func (s *CartesiaService) Init(_ context.Context) error

Init performs asynchronous setup (no-op for TTS services).

func (*CartesiaService) ModelName added in v1.4.7

func (s *CartesiaService) ModelName() string

ModelName returns the configured model name for cost tracking.

func (*CartesiaService) PersonaRubric added in v1.4.7

func (s *CartesiaService) PersonaRubric() string

PersonaRubric implements PersonaRubricProvider. Returns the emotion-only rubric: Cartesia's experimental controls accept a narrow vocabulary (positivity / sadness / anger), so we advertise only the tags the adapter actually maps. Other tags (e.g. whispers, pause) would be dropped by lowerCartesiaMarkup, so we omit them from the rubric to keep persona tokens focused on directives that move audio.

func (*CartesiaService) SupportedFormats

func (s *CartesiaService) SupportedFormats() []AudioFormat

SupportedFormats returns audio formats supported by Cartesia.

func (*CartesiaService) SupportedVoices

func (s *CartesiaService) SupportedVoices() []Voice

SupportedVoices returns a sample of available Cartesia voices.

func (*CartesiaService) Synthesize

func (s *CartesiaService) Synthesize(
	ctx context.Context, text string, config SynthesisConfig,
) (io.ReadCloser, error)

Synthesize converts text to audio using Cartesia's REST API. For streaming output, use SynthesizeStream instead.

func (*CartesiaService) SynthesizeStream

func (s *CartesiaService) SynthesizeStream(
	ctx context.Context, text string, config SynthesisConfig,
) (<-chan audio.Chunk, error)

SynthesizeStream converts text to audio with streaming output via WebSocket. This provides ultra-low latency (<100ms first-byte) for real-time applications.

func (*CartesiaService) SynthesizeTTS added in v1.4.7

func (s *CartesiaService) SynthesizeTTS(ctx context.Context, req base.TTSRequest) (base.TTSStream, error)

SynthesizeTTS implements base.TTSProvider for CartesiaService.

func (*CartesiaService) Type added in v1.4.7

func (s *CartesiaService) Type() base.ProviderType

Type returns ProviderTypeTTS for CartesiaService.

func (*CartesiaService) Validate added in v1.4.7

func (s *CartesiaService) Validate() error

Validate performs synchronous config validation (no-op for TTS services).

type ElevenLabsOption

type ElevenLabsOption = base.HTTPServiceOption

ElevenLabsOption configures the ElevenLabs TTS service. It is a type alias for base.HTTPServiceOption so callers can pass base.WithBaseURL, base.WithClient, base.WithModel, etc. directly.

type ElevenLabsService

type ElevenLabsService struct {
	*base.Implementation    // provides Name, Type, Pricing, Validate, Init, HealthCheck, Close
	*base.HTTPServiceFields // APIKey, BaseURL, Model, Client
}

ElevenLabsService implements TTS using ElevenLabs' API. ElevenLabs specializes in high-quality voice cloning and natural-sounding speech.

func NewElevenLabs

func NewElevenLabs(apiKey string, opts ...ElevenLabsOption) *ElevenLabsService

NewElevenLabs creates an ElevenLabs TTS service.

func (*ElevenLabsService) Close added in v1.4.7

func (s *ElevenLabsService) Close() error

Close releases resources (no-op for TTS services; HTTP client is shared).

func (*ElevenLabsService) HealthCheck added in v1.4.7

func (s *ElevenLabsService) HealthCheck(_ context.Context) error

HealthCheck reports liveness (no-op for TTS services).

func (*ElevenLabsService) ImplName added in v1.4.7

func (s *ElevenLabsService) ImplName() string

ImplName returns the implementation name for cost tracking.

func (*ElevenLabsService) Init added in v1.4.7

Init performs asynchronous setup (no-op for TTS services).

func (*ElevenLabsService) ModelName added in v1.4.7

func (s *ElevenLabsService) ModelName() string

ModelName returns the configured model name for cost tracking.

func (*ElevenLabsService) PersonaRubric added in v1.4.7

func (s *ElevenLabsService) PersonaRubric() string

PersonaRubric implements PersonaRubricProvider. Returns the full markup rubric on v3-class models (they consume bracket tags natively); older models (v1, v2, turbo) speak the brackets literally, so we return the empty string and the persona prompt is left untouched.

func (*ElevenLabsService) SupportedFormats

func (s *ElevenLabsService) SupportedFormats() []AudioFormat

SupportedFormats returns audio formats supported by ElevenLabs.

func (*ElevenLabsService) SupportedVoices

func (s *ElevenLabsService) SupportedVoices() []Voice

SupportedVoices returns a sample of available ElevenLabs voices. Note: ElevenLabs has many more voices including custom cloned voices. Use the ElevenLabs API to get a complete list of available voices.

func (*ElevenLabsService) Synthesize

func (s *ElevenLabsService) Synthesize(
	ctx context.Context, text string, config SynthesisConfig,
) (io.ReadCloser, error)

Synthesize converts text to audio using ElevenLabs' TTS API.

func (*ElevenLabsService) SynthesizeTTS added in v1.4.7

func (s *ElevenLabsService) SynthesizeTTS(ctx context.Context, req base.TTSRequest) (base.TTSStream, error)

SynthesizeTTS implements base.TTSProvider for ElevenLabsService.

func (*ElevenLabsService) Type added in v1.4.7

Type returns ProviderTypeTTS for ElevenLabsService.

func (*ElevenLabsService) Validate added in v1.4.7

func (s *ElevenLabsService) Validate() error

Validate performs synchronous config validation (no-op for TTS services).

type Factory added in v1.4.5

type Factory = base.Factory[Service]

Factory builds a Service from a spec. Per-provider packages register one of these via init() so this package never needs to import them.

type OpenAIOption

type OpenAIOption = base.HTTPServiceOption

OpenAIOption configures the OpenAI TTS service. It is a type alias for base.HTTPServiceOption so callers can pass base.WithBaseURL, base.WithClient, base.WithModel, etc. directly.

type OpenAIService

type OpenAIService struct {
	*base.Implementation    // provides Name, Type, Pricing, Validate, Init, HealthCheck, Close
	*base.HTTPServiceFields // APIKey, BaseURL, Model, Client
}

OpenAIService implements TTS using OpenAI's text-to-speech API.

func NewOpenAI

func NewOpenAI(apiKey string, opts ...OpenAIOption) *OpenAIService

NewOpenAI creates an OpenAI TTS service.

func (*OpenAIService) Close added in v1.4.7

func (s *OpenAIService) Close() error

Close releases resources (no-op for TTS services; HTTP client is shared).

func (*OpenAIService) HealthCheck added in v1.4.7

func (s *OpenAIService) HealthCheck(_ context.Context) error

HealthCheck reports liveness (no-op for TTS services).

func (*OpenAIService) ImplName added in v1.4.7

func (s *OpenAIService) ImplName() string

ImplName returns the implementation name for cost tracking.

func (*OpenAIService) Init added in v1.4.7

func (s *OpenAIService) Init(_ context.Context) error

Init performs asynchronous setup (no-op for TTS services).

func (*OpenAIService) ModelName added in v1.4.7

func (s *OpenAIService) ModelName() string

ModelName returns the configured model name for cost tracking.

func (*OpenAIService) PersonaRubric added in v1.4.7

func (s *OpenAIService) PersonaRubric() string

PersonaRubric implements PersonaRubricProvider. Returns the full markup rubric on gpt-4o-mini-tts (the model honors arbitrary instructions via the request's instructions field). Older models (tts-1, tts-1-hd) do not understand the markup, so we return the empty string — emitting tags would just waste persona tokens.

func (*OpenAIService) SupportedFormats

func (s *OpenAIService) SupportedFormats() []AudioFormat

SupportedFormats returns audio formats supported by OpenAI TTS.

func (*OpenAIService) SupportedVoices

func (s *OpenAIService) SupportedVoices() []Voice

SupportedVoices returns available OpenAI voices.

func (*OpenAIService) Synthesize

func (s *OpenAIService) Synthesize(
	ctx context.Context, text string, config SynthesisConfig,
) (io.ReadCloser, error)

Synthesize converts text to audio using OpenAI's TTS API.

func (*OpenAIService) SynthesizeTTS added in v1.4.7

func (s *OpenAIService) SynthesizeTTS(ctx context.Context, req base.TTSRequest) (base.TTSStream, error)

SynthesizeTTS implements base.TTSProvider for OpenAIService. It bridges the base.TTSRequest to the existing Synthesize method and wraps the response in a streaming ttsStream.

func (*OpenAIService) Type added in v1.4.7

func (s *OpenAIService) Type() base.ProviderType

Type returns ProviderTypeTTS for all TTS services.

func (*OpenAIService) Validate added in v1.4.7

func (s *OpenAIService) Validate() error

Validate performs synchronous config validation (no-op for TTS services).

type PersonaRubricProvider added in v1.4.7

type PersonaRubricProvider interface {
	PersonaRubric() string
}

PersonaRubricProvider is an optional extension interface that TTS adapters implement to advertise the bracket-tag rubric an upstream persona / script should splice into its system prompt. Implementations return the empty string when the configured model cannot consume characterization markup — callers MUST treat the empty string as "do not inject any rubric" so we do not waste persona tokens on tags that would be silently dropped.

See github.com/AltairaLabs/PromptKit/runtime/tts/markup for the canonical rubric strings each adapter may return.

type ProviderSpec added in v1.4.5

type ProviderSpec = base.CapabilitySpec

ProviderSpec is the runtime form of a TTS-provider declaration. It is a type alias for base.CapabilitySpec so the field shape is shared with STT, embedding, and image factories without code duplication.

type RetryConfig added in v1.4.2

type RetryConfig struct {
	// MaxAttempts is the total number of attempts including the initial
	// call. 3 means "initial + up to 2 retries". Values < 1 are
	// treated as 1 (no retry).
	MaxAttempts int
	// InitialDelay is the base backoff before the first retry.
	InitialDelay time.Duration
	// MaxDelay caps the per-attempt backoff.
	MaxDelay time.Duration
}

RetryConfig configures bounded retry for TTS synthesis calls. Defaults are on (unlike streaming retry) because TTS calls are one-shot and idempotent — retry has no content-duplication risk, and the alternative is silence.

func DefaultRetryConfig added in v1.4.2

func DefaultRetryConfig() RetryConfig

DefaultRetryConfig returns sensible defaults for TTS retry.

type Service

type Service interface {
	// Name returns the provider identifier (for logging/debugging).
	Name() string

	// Synthesize converts text to audio.
	// Returns a reader for streaming audio data.
	// The caller is responsible for closing the reader.
	Synthesize(ctx context.Context, text string, config SynthesisConfig) (io.ReadCloser, error)

	// SupportedVoices returns available voices for this provider.
	SupportedVoices() []Voice

	// SupportedFormats returns supported audio output formats.
	SupportedFormats() []AudioFormat
}

Service converts text to speech audio. This interface abstracts different TTS providers (OpenAI, ElevenLabs, etc.) enabling voice AI applications to use any provider interchangeably.

func CreateFromSpec added in v1.4.5

func CreateFromSpec(spec ProviderSpec) (Service, error)

CreateFromSpec returns a Service implementation for the given spec.

type StreamingService

type StreamingService interface {
	Service

	// SynthesizeStream converts text to audio with streaming output.
	// Returns a channel that receives audio chunks as they're generated.
	// The channel is closed when synthesis completes or an error occurs.
	SynthesizeStream(ctx context.Context, text string, config SynthesisConfig) (<-chan audio.Chunk, error)
}

StreamingService extends Service with streaming synthesis capabilities. Streaming TTS provides lower latency by returning audio chunks as they're generated.

type SynthesisConfig

type SynthesisConfig struct {
	// Voice is the voice ID to use for synthesis.
	// Available voices vary by provider - use SupportedVoices() to list options.
	Voice string

	// Format is the output audio format.
	// Default is MP3 for most providers.
	Format AudioFormat

	// Speed is the speech rate multiplier (0.25-4.0, default 1.0).
	// Not all providers support speed adjustment.
	Speed float64

	// Pitch adjusts the voice pitch (-20 to 20 semitones, default 0).
	// Not all providers support pitch adjustment.
	Pitch float64

	// Language is the language code for synthesis (e.g., "en-US").
	// Required for some providers, optional for others.
	Language string

	// Model is the TTS model to use (provider-specific).
	// For OpenAI: "tts-1" (fast) or "tts-1-hd" (high quality).
	Model string
}

SynthesisConfig configures text-to-speech synthesis.

func DefaultSynthesisConfig

func DefaultSynthesisConfig() SynthesisConfig

DefaultSynthesisConfig returns sensible defaults for synthesis.

type SynthesisError

type SynthesisError struct {
	// Provider is the TTS provider that returned the error.
	Provider string

	// Code is the provider-specific error code.
	Code string

	// Message is the error message.
	Message string

	// Cause is the underlying error (if any).
	Cause error

	// Retryable indicates if the error is transient and retry may succeed.
	Retryable bool
}

SynthesisError provides detailed error information from TTS providers.

func NewSynthesisError

func NewSynthesisError(provider, code, message string, cause error, retryable bool) *SynthesisError

NewSynthesisError creates a new SynthesisError.

func (*SynthesisError) Error

func (e *SynthesisError) Error() string

Error implements the error interface.

func (*SynthesisError) Unwrap

func (e *SynthesisError) Unwrap() error

Unwrap returns the underlying error.

type Voice

type Voice struct {
	// ID is the provider-specific voice identifier.
	ID string

	// Name is a human-readable voice name.
	Name string

	// Language is the primary language code (e.g., "en", "es", "fr").
	Language string

	// Gender is the voice gender ("male", "female", "neutral").
	Gender string

	// Description provides additional voice characteristics.
	Description string

	// Preview is a URL to a voice sample (if available).
	Preview string
}

Voice describes a TTS voice available from a provider.

Directories

Path Synopsis
Package markup is the canonical scanner for TTS characterization tags.
Package markup is the canonical scanner for TTS characterization tags.

Jump to

Keyboard shortcuts

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