Module livekit.plugins.smallestai
Smallest AI plugin for LiveKit Agents
See https://docs.livekit.io/agents/integrations/smallestai/ for more information.
Classes
class ChunkedStream (*,
tts: TTS,
input_text: str,
conn_options: APIConnectOptions)-
Expand source code
class ChunkedStream(tts.ChunkedStream): """HTTP-based synthesis — used when synthesize() is called directly.""" def __init__(self, *, tts: TTS, input_text: str, conn_options: APIConnectOptions) -> None: super().__init__(tts=tts, input_text=input_text, conn_options=conn_options) self._tts: TTS = tts self._opts = replace(tts._opts) async def _run(self, output_emitter: tts.AudioEmitter) -> None: try: data = _to_smallest_options(self._opts) data["text"] = self._input_text headers = { "Authorization": f"Bearer {self._opts.api_key}", "Content-Type": "application/json", "X-Source": "livekit", "X-LiveKit-Version": __version__, } async with self._tts._ensure_session().post( f"{self._opts.base_url}/tts", headers=headers, json=data, timeout=aiohttp.ClientTimeout(total=self._conn_options.timeout), ) as resp: if resp.status >= 400: body = await resp.text() raise create_api_error_from_http(body, status=resp.status) output_emitter.initialize( request_id=utils.shortuuid(), sample_rate=self._opts.sample_rate, num_channels=NUM_CHANNELS, mime_type=f"audio/{self._opts.output_format}", ) async for chunk, _ in resp.content.iter_chunks(): output_emitter.push(chunk) output_emitter.flush() except asyncio.TimeoutError: raise APITimeoutError() from None except aiohttp.ClientResponseError as e: raise create_api_error_from_http(e.message, status=e.status) from None except APIStatusError: raise except Exception as e: raise APIConnectionError() from eHTTP-based synthesis — used when synthesize() is called directly.
Ancestors
- livekit.agents.tts.tts.ChunkedStream
- abc.ABC
class STT (*,
model: STTModels | str = 'pulse',
language: str = 'en',
sample_rate: int = 16000,
encoding: STTEncoding | str = 'linear16',
word_timestamps: bool = True,
diarize: bool = False,
format: bool = True,
itn_normalize: bool = False,
numerals: NotGivenOr[bool] = NOT_GIVEN,
keywords: NotGivenOr[list[tuple[str, float]]] = NOT_GIVEN,
sentence_timestamps: bool = False,
redact_pii: bool = False,
redact_pci: bool = False,
endpointing: bool = True,
endpointing_timeout_ms: int | None = 300,
eou_timeout_ms: NotGivenOr[int] = NOT_GIVEN,
vad_events: bool = True,
finalize_on_flush: bool = True,
finalize_on_words: NotGivenOr[bool] = NOT_GIVEN,
max_words: NotGivenOr[int] = NOT_GIVEN,
keepalive_interval: NotGivenOr[float | None] = NOT_GIVEN,
api_key: str | None = None,
http_session: aiohttp.ClientSession | None = None,
base_url: str = 'https://api.smallest.ai/waves/v1',
stream_path: str = '/stt/live')-
Expand source code
class STT(stt.STT): def __init__( self, *, model: STTModels | str = "pulse", language: str = "en", sample_rate: int = 16000, encoding: STTEncoding | str = "linear16", word_timestamps: bool = True, diarize: bool = False, format: bool = True, itn_normalize: bool = False, numerals: NotGivenOr[bool] = NOT_GIVEN, keywords: NotGivenOr[list[tuple[str, float]]] = NOT_GIVEN, sentence_timestamps: bool = False, redact_pii: bool = False, redact_pci: bool = False, endpointing: bool = True, endpointing_timeout_ms: int | None = 300, eou_timeout_ms: NotGivenOr[int] = NOT_GIVEN, vad_events: bool = True, finalize_on_flush: bool = True, finalize_on_words: NotGivenOr[bool] = NOT_GIVEN, max_words: NotGivenOr[int] = NOT_GIVEN, keepalive_interval: NotGivenOr[float | None] = NOT_GIVEN, api_key: str | None = None, http_session: aiohttp.ClientSession | None = None, base_url: str = SMALLEST_STT_BASE_URL, stream_path: str = DEFAULT_STREAM_PATH, ) -> None: """Create a new instance of Smallest AI STT. Args: model: STT model to use. ``"pulse"`` supports streaming and batch transcription. Other models are batch-only; ``stream()`` raises ``ValueError`` for them. language: BCP-47 language code (e.g. "en", "hi", "fr"). Use "multi" for automatic language detection. sample_rate: Audio sample rate in Hz. Supported: 8000, 16000, 22050, 24000, 44100, 48000. Defaults to 16000. Telephony audio should be sent at its native 8000 Hz rather than upsampled. encoding: PCM encoding of the audio stream; "linear16" is the default. word_timestamps: Include per-word start/end timestamps and confidence scores on final transcripts. Defaults to True. diarize: Enable speaker diarization; each word carries a speaker id. Defaults to False. format: Apply punctuation and capitalization to streaming transcripts. Defaults to True. itn_normalize: Run the server's inverse text normalization so spoken numbers come back as digits ("twenty five" -> "25"). Independent of ``format``. Defaults to False. numerals: Legacy digits post-pass; leave unset and use ``itn_normalize``. keywords: Boost recognition via ``(keyword, intensifier)`` tuples, e.g. ``[("NVIDIA", 2.0)]``. Intensifier ~1.0 (mild) to ~5.0 (strong). sentence_timestamps: Include sentence-level timing as an ``"utterances"`` list in ``SpeechData.metadata``. Defaults to False. redact_pii: Mask names, addresses and phone numbers with placeholder tokens; matches are listed in ``SpeechData.metadata["redacted_entities"]``. Reliable for ``language="en"`` and ``"hi"``. Defaults to False. redact_pci: Mask card numbers, CVVs, ZIP codes and account numbers. Reliable for ``language="en"`` and ``"hi"``. Defaults to False. endpointing: Let the server's VAD finalize the open segment once ``endpointing_timeout_ms`` of trailing silence has passed, so the last words of a turn arrive as a final without waiting for the blank-token endpoint at the next decode boundary. Defaults to True. endpointing_timeout_ms: The server VAD silence window in ms, shared by ``endpointing`` and ``vad_events``. Defaults to 300 so the server's final lands before a VAD-driven agent commits the turn (LiveKit commits about 0.55 s after speech with its default VAD): measured against 600 on 19 call recordings this cut the words leaking into the next turn by 60 % at the same accuracy. Shorter windows start cutting inside words. ``None`` uses the server default (600). eou_timeout_ms: Silence (ms) for the transducer's blank-token endpoint. Unset uses the server default (800). Values below the ~1.1 s decode chunk make the server cut finals inside utterances; prefer ``endpointing`` for low latency. vad_events: Ask the server for ``speech_started`` / ``speech_ended`` messages and map them to START_OF_SPEECH / END_OF_SPEECH. This is the only reliable end-of-speech signal: finals alone are also emitted mid-utterance. With it off, every final closes the turn. Defaults to True. finalize_on_flush: Send ``{"type": "finalize"}`` when the framework flushes the stream, so buffered speech is returned as a final immediately. Defaults to True. finalize_on_words: Cut a final every ``max_words`` words during long continuous speech. Unset uses the server default (on). The cut is not a turn end; END_OF_SPEECH still follows the VAD. max_words: Word count for ``finalize_on_words``. Unset uses the server default. keepalive_interval: Seconds between ``{"type": "keepalive"}`` messages, which reset the public API's inactivity timer during long pauses (it answers with ``{"type": "pong"}``). Defaults to 5 s on the public API and off for a direct server, which does not accept the message. ``None`` disables it. api_key: Smallest AI API key. Falls back to the SMALLEST_API_KEY environment variable if not provided. http_session: An existing aiohttp ClientSession to reuse. base_url: API base URL. For a directly reachable inference server pass its ``http://host:port`` and ``stream_path="/transcribe"``. stream_path: Path of the streaming endpoint under ``base_url``. ``"/stt/live"`` on the public API, ``"/transcribe"`` on a server. """ super().__init__( capabilities=stt.STTCapabilities( streaming=model in _STREAMING_MODELS, interim_results=True, diarization=diarize, aligned_transcript="word" if word_timestamps else False, ) ) api_key = api_key or os.environ.get("SMALLEST_API_KEY") if not api_key: raise ValueError( "Smallest AI API key is required, either as argument or set " "SMALLEST_API_KEY environment variable" ) self._opts = _STTOptions( model=model, api_key=api_key, language=language, sample_rate=sample_rate, encoding=encoding, word_timestamps=word_timestamps, diarize=diarize, format=format, itn_normalize=itn_normalize, numerals=numerals if is_given(numerals) else None, keywords=list(keywords) if is_given(keywords) else [], sentence_timestamps=sentence_timestamps, redact_pii=redact_pii, redact_pci=redact_pci, endpointing=endpointing, endpointing_timeout_ms=endpointing_timeout_ms if is_given(endpointing_timeout_ms) else None, eou_timeout_ms=eou_timeout_ms if is_given(eou_timeout_ms) else None, vad_events=vad_events, finalize_on_flush=finalize_on_flush, finalize_on_words=finalize_on_words if is_given(finalize_on_words) else None, max_words=max_words if is_given(max_words) else None, keepalive_interval=( keepalive_interval if is_given(keepalive_interval) else (5.0 if stream_path == DEFAULT_STREAM_PATH else None) ), base_url=base_url, stream_path=stream_path, ) self._session = http_session self._streams: weakref.WeakSet[SpeechStream] = weakref.WeakSet() @property def model(self) -> str: return self._opts.model @property def provider(self) -> str: return "SmallestAI" def _ensure_session(self) -> aiohttp.ClientSession: if not self._session: self._session = utils.http_context.http_session() return self._session async def _recognize_impl( self, buffer: AudioBuffer, *, language: NotGivenOr[str] = NOT_GIVEN, conn_options: APIConnectOptions = DEFAULT_API_CONNECT_OPTIONS, ) -> stt.SpeechEvent: config = self._sanitize_options(language=language) params: dict[str, Any] = { "model": config.model, "language": config.language, "encoding": config.encoding, "sample_rate": config.sample_rate, "word_timestamps": str(config.word_timestamps).lower(), "diarize": str(config.diarize).lower(), } try: async with self._ensure_session().post( url=f"{config.base_url}/stt/", headers={ "Authorization": f"Bearer {config.api_key}", "Content-Type": "application/octet-stream", "X-Source": "livekit", "X-LiveKit-Version": __version__, }, params=params, # to_wav_bytes() produces a valid WAV file; the server auto-detects format. data=rtc.combine_audio_frames(buffer).to_wav_bytes(), timeout=aiohttp.ClientTimeout(total=30, sock_connect=conn_options.timeout), ) as resp: resp.raise_for_status() data = await resp.json() return _batch_transcription_to_speech_event(config.language, data) except asyncio.TimeoutError as e: raise APITimeoutError() from e except aiohttp.ClientResponseError as e: raise APIStatusError( message=e.message, status_code=e.status, request_id=None, body=None ) from e except Exception as e: raise APIConnectionError() from e def stream( self, *, language: NotGivenOr[str] = NOT_GIVEN, conn_options: APIConnectOptions = DEFAULT_API_CONNECT_OPTIONS, ) -> SpeechStream: if not self.capabilities.streaming: raise ValueError( f"{self._opts.model} does not support streaming; use recognize() for batch transcription" ) config = self._sanitize_options(language=language) stream = SpeechStream( stt=self, conn_options=conn_options, opts=config, http_session=self._ensure_session(), ) self._streams.add(stream) return stream def update_options( self, *, model: NotGivenOr[STTModels | str] = NOT_GIVEN, language: NotGivenOr[str] = NOT_GIVEN, sample_rate: NotGivenOr[int] = NOT_GIVEN, encoding: NotGivenOr[STTEncoding | str] = NOT_GIVEN, format: NotGivenOr[bool] = NOT_GIVEN, itn_normalize: NotGivenOr[bool] = NOT_GIVEN, keywords: NotGivenOr[list[tuple[str, float]]] = NOT_GIVEN, sentence_timestamps: NotGivenOr[bool] = NOT_GIVEN, redact_pii: NotGivenOr[bool] = NOT_GIVEN, redact_pci: NotGivenOr[bool] = NOT_GIVEN, endpointing: NotGivenOr[bool] = NOT_GIVEN, endpointing_timeout_ms: NotGivenOr[int] = NOT_GIVEN, eou_timeout_ms: NotGivenOr[int] = NOT_GIVEN, vad_events: NotGivenOr[bool] = NOT_GIVEN, finalize_on_flush: NotGivenOr[bool] = NOT_GIVEN, ) -> None: """Update STT options; propagates to all active streams (triggers reconnect).""" if is_given(model): self._opts.model = model self._capabilities.streaming = model in _STREAMING_MODELS self._opts = _apply_updates( self._opts, language=language, sample_rate=sample_rate, encoding=encoding, format=format, itn_normalize=itn_normalize, keywords=keywords, sentence_timestamps=sentence_timestamps, redact_pii=redact_pii, redact_pci=redact_pci, endpointing=endpointing, endpointing_timeout_ms=endpointing_timeout_ms, eou_timeout_ms=eou_timeout_ms, vad_events=vad_events, finalize_on_flush=finalize_on_flush, ) for stream in self._streams: stream.update_options( model=model, language=language, sample_rate=sample_rate, encoding=encoding, format=format, itn_normalize=itn_normalize, keywords=keywords, sentence_timestamps=sentence_timestamps, redact_pii=redact_pii, redact_pci=redact_pci, endpointing=endpointing, endpointing_timeout_ms=endpointing_timeout_ms, eou_timeout_ms=eou_timeout_ms, vad_events=vad_events, finalize_on_flush=finalize_on_flush, ) def _sanitize_options(self, *, language: NotGivenOr[str] = NOT_GIVEN) -> _STTOptions: config = replace(self._opts) if is_given(language): config.language = language return configHelper class that provides a standard way to create an ABC using inheritance.
Create a new instance of Smallest AI STT.
Args
model- STT model to use.
"pulse"supports streaming and batch transcription. Other models are batch-only;stream()raisesValueErrorfor them. language- BCP-47 language code (e.g. "en", "hi", "fr"). Use "multi" for automatic language detection.
sample_rate- Audio sample rate in Hz. Supported: 8000, 16000, 22050, 24000, 44100, 48000. Defaults to 16000. Telephony audio should be sent at its native 8000 Hz rather than upsampled.
encoding- PCM encoding of the audio stream; "linear16" is the default.
word_timestamps- Include per-word start/end timestamps and confidence scores on final transcripts. Defaults to True.
diarize- Enable speaker diarization; each word carries a speaker id. Defaults to False.
format- Apply punctuation and capitalization to streaming transcripts. Defaults to True.
itn_normalize- Run the server's inverse text normalization so spoken
numbers come back as digits ("twenty five" -> "25"). Independent of
format. Defaults to False. numerals- Legacy digits post-pass; leave unset and use
itn_normalize. keywords- Boost recognition via
(keyword, intensifier)tuples, e.g.[("NVIDIA", 2.0)]. Intensifier ~1.0 (mild) to ~5.0 (strong). sentence_timestamps- Include sentence-level timing as an
"utterances"list inSpeechData.metadata. Defaults to False. redact_pii- Mask names, addresses and phone numbers with placeholder
tokens; matches are listed in
SpeechData.metadata["redacted_entities"]. Reliable forlanguage="en"and"hi". Defaults to False. redact_pci- Mask card numbers, CVVs, ZIP codes and account numbers.
Reliable for
language="en"and"hi". Defaults to False. endpointing- Let the server's VAD finalize the open segment once
endpointing_timeout_msof trailing silence has passed, so the last words of a turn arrive as a final without waiting for the blank-token endpoint at the next decode boundary. Defaults to True. endpointing_timeout_ms- The server VAD silence window in ms, shared by
endpointingandvad_events. Defaults to 300 so the server's final lands before a VAD-driven agent commits the turn (LiveKit commits about 0.55 s after speech with its default VAD): measured against 600 on 19 call recordings this cut the words leaking into the next turn by 60 % at the same accuracy. Shorter windows start cutting inside words.Noneuses the server default (600). eou_timeout_ms- Silence (ms) for the transducer's blank-token endpoint.
Unset uses the server default (800). Values below the ~1.1 s decode
chunk make the server cut finals inside utterances; prefer
endpointingfor low latency. vad_events- Ask the server for
speech_started/speech_endedmessages and map them to START_OF_SPEECH / END_OF_SPEECH. This is the only reliable end-of-speech signal: finals alone are also emitted mid-utterance. With it off, every final closes the turn. Defaults to True. finalize_on_flush- Send
{"type": "finalize"}when the framework flushes the stream, so buffered speech is returned as a final immediately. Defaults to True. finalize_on_words- Cut a final every
max_wordswords during long continuous speech. Unset uses the server default (on). The cut is not a turn end; END_OF_SPEECH still follows the VAD. max_words- Word count for
finalize_on_words. Unset uses the server default. keepalive_interval- Seconds between
{"type": "keepalive"}messages, which reset the public API's inactivity timer during long pauses (it answers with{"type": "pong"}). Defaults to 5 s on the public API and off for a direct server, which does not accept the message.Nonedisables it. api_key- Smallest AI API key. Falls back to the SMALLEST_API_KEY environment variable if not provided.
http_session- An existing aiohttp ClientSession to reuse.
base_url- API base URL. For a directly reachable inference server pass its
http://host:portandstream_path="/transcribe". stream_path- Path of the streaming endpoint under
base_url."/stt/live"on the public API,"/transcribe"on a server.
Ancestors
- livekit.agents.stt.stt.STT
- abc.ABC
- EventEmitter
- typing.Generic
Instance variables
prop model : str-
Expand source code
@property def model(self) -> str: return self._opts.modelGet the model name/identifier for this STT instance.
Returns
The model name if available, "unknown" otherwise.
Note
Plugins should override this property to provide their model information.
prop provider : str-
Expand source code
@property def provider(self) -> str: return "SmallestAI"Get the provider name/identifier for this STT instance.
Returns
The provider name if available, "unknown" otherwise.
Note
Plugins should override this property to provide their provider information.
Methods
def stream(self,
*,
language: NotGivenOr[str] = NOT_GIVEN,
conn_options: APIConnectOptions = APIConnectOptions(max_retry=3, retry_interval=2.0, timeout=10.0)) ‑> livekit.plugins.smallestai.stt.SpeechStream-
Expand source code
def stream( self, *, language: NotGivenOr[str] = NOT_GIVEN, conn_options: APIConnectOptions = DEFAULT_API_CONNECT_OPTIONS, ) -> SpeechStream: if not self.capabilities.streaming: raise ValueError( f"{self._opts.model} does not support streaming; use recognize() for batch transcription" ) config = self._sanitize_options(language=language) stream = SpeechStream( stt=self, conn_options=conn_options, opts=config, http_session=self._ensure_session(), ) self._streams.add(stream) return stream def update_options(self,
*,
model: NotGivenOr[STTModels | str] = NOT_GIVEN,
language: NotGivenOr[str] = NOT_GIVEN,
sample_rate: NotGivenOr[int] = NOT_GIVEN,
encoding: NotGivenOr[STTEncoding | str] = NOT_GIVEN,
format: NotGivenOr[bool] = NOT_GIVEN,
itn_normalize: NotGivenOr[bool] = NOT_GIVEN,
keywords: NotGivenOr[list[tuple[str, float]]] = NOT_GIVEN,
sentence_timestamps: NotGivenOr[bool] = NOT_GIVEN,
redact_pii: NotGivenOr[bool] = NOT_GIVEN,
redact_pci: NotGivenOr[bool] = NOT_GIVEN,
endpointing: NotGivenOr[bool] = NOT_GIVEN,
endpointing_timeout_ms: NotGivenOr[int] = NOT_GIVEN,
eou_timeout_ms: NotGivenOr[int] = NOT_GIVEN,
vad_events: NotGivenOr[bool] = NOT_GIVEN,
finalize_on_flush: NotGivenOr[bool] = NOT_GIVEN) ‑> None-
Expand source code
def update_options( self, *, model: NotGivenOr[STTModels | str] = NOT_GIVEN, language: NotGivenOr[str] = NOT_GIVEN, sample_rate: NotGivenOr[int] = NOT_GIVEN, encoding: NotGivenOr[STTEncoding | str] = NOT_GIVEN, format: NotGivenOr[bool] = NOT_GIVEN, itn_normalize: NotGivenOr[bool] = NOT_GIVEN, keywords: NotGivenOr[list[tuple[str, float]]] = NOT_GIVEN, sentence_timestamps: NotGivenOr[bool] = NOT_GIVEN, redact_pii: NotGivenOr[bool] = NOT_GIVEN, redact_pci: NotGivenOr[bool] = NOT_GIVEN, endpointing: NotGivenOr[bool] = NOT_GIVEN, endpointing_timeout_ms: NotGivenOr[int] = NOT_GIVEN, eou_timeout_ms: NotGivenOr[int] = NOT_GIVEN, vad_events: NotGivenOr[bool] = NOT_GIVEN, finalize_on_flush: NotGivenOr[bool] = NOT_GIVEN, ) -> None: """Update STT options; propagates to all active streams (triggers reconnect).""" if is_given(model): self._opts.model = model self._capabilities.streaming = model in _STREAMING_MODELS self._opts = _apply_updates( self._opts, language=language, sample_rate=sample_rate, encoding=encoding, format=format, itn_normalize=itn_normalize, keywords=keywords, sentence_timestamps=sentence_timestamps, redact_pii=redact_pii, redact_pci=redact_pci, endpointing=endpointing, endpointing_timeout_ms=endpointing_timeout_ms, eou_timeout_ms=eou_timeout_ms, vad_events=vad_events, finalize_on_flush=finalize_on_flush, ) for stream in self._streams: stream.update_options( model=model, language=language, sample_rate=sample_rate, encoding=encoding, format=format, itn_normalize=itn_normalize, keywords=keywords, sentence_timestamps=sentence_timestamps, redact_pii=redact_pii, redact_pci=redact_pci, endpointing=endpointing, endpointing_timeout_ms=endpointing_timeout_ms, eou_timeout_ms=eou_timeout_ms, vad_events=vad_events, finalize_on_flush=finalize_on_flush, )Update STT options; propagates to all active streams (triggers reconnect).
Inherited members
class SpeechStream (*,
stt: STT,
opts: _STTOptions,
conn_options: APIConnectOptions,
http_session: aiohttp.ClientSession)-
Expand source code
class SpeechStream(stt.SpeechStream): _FINALIZE_MSG: str = json.dumps({"type": "finalize"}) _CLOSE_STREAM_MSG: str = json.dumps({"type": "close_stream"}) _KEEPALIVE_MSG: str = json.dumps({"type": "keepalive"}) def __init__( self, *, stt: STT, opts: _STTOptions, conn_options: APIConnectOptions, http_session: aiohttp.ClientSession, ) -> None: super().__init__(stt=stt, conn_options=conn_options, sample_rate=opts.sample_rate) self._opts = opts self._session = http_session self._speaking = False self._session_id = "" self._reconnect_event = asyncio.Event() self._audio_duration_collector = _PeriodicCollector( callback=self._on_audio_duration_report, duration=5.0 ) def update_options( self, *, model: NotGivenOr[STTModels | str] = NOT_GIVEN, language: NotGivenOr[str] = NOT_GIVEN, sample_rate: NotGivenOr[int] = NOT_GIVEN, encoding: NotGivenOr[STTEncoding | str] = NOT_GIVEN, format: NotGivenOr[bool] = NOT_GIVEN, itn_normalize: NotGivenOr[bool] = NOT_GIVEN, keywords: NotGivenOr[list[tuple[str, float]]] = NOT_GIVEN, sentence_timestamps: NotGivenOr[bool] = NOT_GIVEN, redact_pii: NotGivenOr[bool] = NOT_GIVEN, redact_pci: NotGivenOr[bool] = NOT_GIVEN, endpointing: NotGivenOr[bool] = NOT_GIVEN, endpointing_timeout_ms: NotGivenOr[int] = NOT_GIVEN, eou_timeout_ms: NotGivenOr[int] = NOT_GIVEN, vad_events: NotGivenOr[bool] = NOT_GIVEN, finalize_on_flush: NotGivenOr[bool] = NOT_GIVEN, ) -> None: self._opts = _apply_updates( self._opts, model=model, language=language, sample_rate=sample_rate, encoding=encoding, format=format, itn_normalize=itn_normalize, keywords=keywords, sentence_timestamps=sentence_timestamps, redact_pii=redact_pii, redact_pci=redact_pci, endpointing=endpointing, endpointing_timeout_ms=endpointing_timeout_ms, eou_timeout_ms=eou_timeout_ms, vad_events=vad_events, finalize_on_flush=finalize_on_flush, ) self._reconnect_event.set() async def _run(self) -> None: closing_ws = False async def keepalive_task(ws: aiohttp.ClientWebSocketResponse) -> None: # Resets the public API's inactivity timer while no audio flows; the server # answers with a pong that recv_task ignores. interval = self._opts.keepalive_interval if interval is None or interval <= 0: await asyncio.Event().wait() # disabled: idle for the life of the connection return try: while True: await asyncio.sleep(interval) await ws.send_str(SpeechStream._KEEPALIVE_MSG) except (aiohttp.ClientError, ConnectionError) as e: # With no audio flowing this write is where a dropped socket shows first. if closing_ws or self._session.closed: return raise APIConnectionError("Smallest AI STT connection closed unexpectedly") from e @utils.log_exceptions(logger=logger) async def send_task(ws: aiohttp.ClientWebSocketResponse) -> None: nonlocal closing_ws # 50 ms packets, the cadence the Pulse docs recommend. samples_per_chunk = self._opts.sample_rate // 20 audio_bstream = utils.audio.AudioByteStream( sample_rate=self._opts.sample_rate, num_channels=NUM_CHANNELS, samples_per_channel=samples_per_chunk, ) try: async for data in self._input_ch: frames: list[rtc.AudioFrame] = [] flushed = False if isinstance(data, rtc.AudioFrame): frames.extend(audio_bstream.write(data.data.tobytes())) elif isinstance(data, self._FlushSentinel): frames.extend(audio_bstream.flush()) flushed = True for frame in frames: self._audio_duration_collector.push(frame.duration) await ws.send_bytes(frame.data.tobytes()) if flushed: # The framework marked a segment end: the buffered tail is on the # wire, now ask for it back as a final instead of leaving it to # the server's endpointing. self._audio_duration_collector.flush() if self._opts.finalize_on_flush: await ws.send_str(SpeechStream._FINALIZE_MSG) # Input closed: the server flushes, answers with is_last and closes. closing_ws = True await ws.send_str(SpeechStream._CLOSE_STREAM_MSG) except (aiohttp.ClientError, ConnectionError) as e: # A dropped socket surfaces on the write side first. Expected closes just # return; anything else reconnects through _run, like recv_task. if closing_ws or self._session.closed: return raise APIConnectionError("Smallest AI STT connection closed unexpectedly") from e @utils.log_exceptions(logger=logger) async def recv_task(ws: aiohttp.ClientWebSocketResponse) -> None: nonlocal closing_ws while True: msg = await ws.receive() if msg.type in ( aiohttp.WSMsgType.CLOSED, aiohttp.WSMsgType.CLOSE, aiohttp.WSMsgType.CLOSING, ): if closing_ws or self._session.closed: return raise APIStatusError( message="Smallest AI STT connection closed unexpectedly", status_code=ws.close_code or -1, body=f"{msg.data=} {msg.extra=}", ) if msg.type == aiohttp.WSMsgType.ERROR: if closing_ws or self._session.closed: return # An unanswered heartbeat ping closes the socket from our side and # arrives here, not as a close frame; ws.exception() holds the reason. raise APIConnectionError("Smallest AI STT connection lost") from ws.exception() if msg.type != aiohttp.WSMsgType.TEXT: logger.warning("unexpected Smallest AI STT message type: %s", msg.type) continue try: data = json.loads(msg.data) except json.JSONDecodeError: logger.warning( "failed to parse Smallest AI STT message", extra={"lk.pii.data": msg.data} ) continue # Errors: {"type": "error", "status", "message"} from the public API, # {"error": "..."} from a server reached directly. if data.get("type") == "error" or ( "error" in data and "transcript" not in data and "transcription" not in data ): # The payload may echo user content; it goes only in the PII-marked # log field and the exception body, not in the message the retry # logger prints. logger.error("Smallest AI STT error", extra={"lk.pii.data": data}) raise APIStatusError( message=f"Smallest AI STT error ({data.get('status') or 'error'})", status_code=-1, request_id=self._session_id or None, body=data, ) if data.get("type") == "pong": continue self._process_stream_event(data) # The session is fully flushed; nothing else will arrive. if data.get("is_last"): return ws: aiohttp.ClientWebSocketResponse | None = None while True: try: ws = await self._connect_ws() tasks = [ asyncio.create_task(send_task(ws)), asyncio.create_task(recv_task(ws)), ] # Not in the gather: recv_task ends on is_last before the socket closes, and the # session must not wait on a keepalive loop. Its failure still ends the session. keepalive = asyncio.create_task(keepalive_task(ws)) tasks_group = asyncio.gather(*tasks) wait_reconnect_task = asyncio.create_task(self._reconnect_event.wait()) try: done, _ = await asyncio.wait( (tasks_group, wait_reconnect_task, keepalive), return_when=asyncio.FIRST_COMPLETED, ) for task in done: if task != wait_reconnect_task: task.result() if wait_reconnect_task not in done: break self._reconnect_event.clear() finally: await utils.aio.gracefully_cancel(*tasks, wait_reconnect_task, keepalive) tasks_group.cancel() tasks_group.exception() finally: if ws is not None: await ws.close() self._audio_duration_collector.flush() # A socket that ends mid-utterance (reconnect, drop) takes the server's # speech_ended with it: close the turn here so START/END stay paired. self._end_speech() def _stream_params(self) -> dict[str, Any]: """Query parameters for the streaming connection; unset knobs are left to the server.""" o = self._opts params: dict[str, Any] = { "model": o.model, "language": o.language, "encoding": o.encoding, "sample_rate": o.sample_rate, "word_timestamps": str(o.word_timestamps).lower(), "diarize": str(o.diarize).lower(), "format": str(o.format).lower(), "itn_normalize": str(o.itn_normalize).lower(), "sentence_timestamps": str(o.sentence_timestamps).lower(), "redact_pii": str(o.redact_pii).lower(), "redact_pci": str(o.redact_pci).lower(), "endpointing": str(o.endpointing).lower(), "vad_events": str(o.vad_events).lower(), } if o.numerals is not None: params["numerals"] = str(o.numerals).lower() if o.endpointing_timeout_ms is not None: params["endpointing_timeout"] = o.endpointing_timeout_ms if o.eou_timeout_ms is not None: params["eou_timeout_ms"] = o.eou_timeout_ms if o.finalize_on_words is not None: params["finalize_on_words"] = str(o.finalize_on_words).lower() if o.max_words is not None: params["max_words"] = o.max_words if o.keywords: params["keywords"] = ",".join(f"{kw}:{boost:g}" for kw, boost in o.keywords) return params def _ws_url(self) -> str: base = self._opts.base_url.replace("https://", "wss://", 1).replace("http://", "ws://", 1) return f"{base.rstrip('/')}{self._opts.stream_path}?{urlencode(self._stream_params())}" async def _connect_ws(self) -> aiohttp.ClientWebSocketResponse: t0 = time.perf_counter() try: ws = await asyncio.wait_for( self._session.ws_connect( self._ws_url(), headers={ "Authorization": f"Bearer {self._opts.api_key}", "X-Source": "livekit", "X-LiveKit-Version": __version__, }, # Without a heartbeat a half-open socket is never noticed: recv_task # parks on receive() and the exception-driven reconnect never runs. heartbeat=30.0, ), self._conn_options.timeout, ) except asyncio.TimeoutError: raise APIConnectionError("failed to connect to Smallest AI STT") from None except aiohttp.ClientResponseError as e: # RequestInfo carries the request headers, so chaining this error or # formatting it puts the API key in the exception repr. raise APIStatusError( message=e.message, status_code=e.status, request_id=None, body=None ) from None except Exception as e: raise APIConnectionError( f"failed to connect to Smallest AI STT ({type(e).__name__})" ) from None self._report_connection_acquired(time.perf_counter() - t0, False) logger.debug("established Smallest AI STT WebSocket connection") return ws def _on_audio_duration_report(self, duration: float) -> None: self._event_ch.send_nowait( stt.SpeechEvent( type=stt.SpeechEventType.RECOGNITION_USAGE, request_id=self._session_id, alternatives=[], recognition_usage=stt.RecognitionUsage(audio_duration=duration), ) ) def _start_speech(self) -> None: if not self._speaking: self._speaking = True self._event_ch.send_nowait(stt.SpeechEvent(type=stt.SpeechEventType.START_OF_SPEECH)) def _end_speech(self) -> None: if self._speaking: self._speaking = False self._event_ch.send_nowait(stt.SpeechEvent(type=stt.SpeechEventType.END_OF_SPEECH)) def _process_stream_event(self, data: dict[str, Any]) -> None: session_id = data.get("session_id", "") if session_id: self._session_id = session_id msg_type = data.get("type", "") # Acoustic VAD messages: the speaker started or stopped, independent of decoding. if msg_type == "speech_started": self._start_speech() return if msg_type == "speech_ended": self._end_speech() return # The gateway duplicates the server's `transcript` into `transcription`. transcript = data.get("transcript") or data.get("transcription") or "" is_final = bool(data.get("is_final", False)) is_last = bool(data.get("is_last", False)) from_finalize = bool(data.get("from_finalize", False)) # Punctuation-only text ("." or "।" landing in its own chunk) is not a user turn. if _WORD_RE.search(transcript): # Quiet speech the server VAD missed, or vad_events off: the text opens the turn. self._start_speech() alts = _transcript_to_speech_data( language=self._opts.language, data=data, transcript=transcript, start_time_offset=self.start_time_offset, diarize=self._opts.diarize, ) self._event_ch.send_nowait( stt.SpeechEvent( type=( stt.SpeechEventType.FINAL_TRANSCRIPT if is_final else stt.SpeechEventType.INTERIM_TRANSCRIPT ), request_id=self._session_id, alternatives=alts, ) ) # A final closes the turn when it answers a finalize, ends the stream, or the # server says the speaker paused. Other finals are cuts inside an utterance # (word rollover, blank-token endpoint); with vad_events the turn end comes # from speech_ended, without them every final has to count as one. if is_final and ( is_last or from_finalize or data.get("speech_final") is True or not self._opts.vad_events ): self._end_speech()Helper class that provides a standard way to create an ABC using inheritance.
Args: sample_rate : int or None, optional The desired sample rate for the audio input. If specified, the audio input will be automatically resampled to match the given sample rate before being processed for Speech-to-Text. If not provided (None), the input will retain its original sample rate.
Ancestors
- livekit.agents.stt.stt.RecognizeStream
- abc.ABC
Methods
def update_options(self,
*,
model: NotGivenOr[STTModels | str] = NOT_GIVEN,
language: NotGivenOr[str] = NOT_GIVEN,
sample_rate: NotGivenOr[int] = NOT_GIVEN,
encoding: NotGivenOr[STTEncoding | str] = NOT_GIVEN,
format: NotGivenOr[bool] = NOT_GIVEN,
itn_normalize: NotGivenOr[bool] = NOT_GIVEN,
keywords: NotGivenOr[list[tuple[str, float]]] = NOT_GIVEN,
sentence_timestamps: NotGivenOr[bool] = NOT_GIVEN,
redact_pii: NotGivenOr[bool] = NOT_GIVEN,
redact_pci: NotGivenOr[bool] = NOT_GIVEN,
endpointing: NotGivenOr[bool] = NOT_GIVEN,
endpointing_timeout_ms: NotGivenOr[int] = NOT_GIVEN,
eou_timeout_ms: NotGivenOr[int] = NOT_GIVEN,
vad_events: NotGivenOr[bool] = NOT_GIVEN,
finalize_on_flush: NotGivenOr[bool] = NOT_GIVEN) ‑> None-
Expand source code
def update_options( self, *, model: NotGivenOr[STTModels | str] = NOT_GIVEN, language: NotGivenOr[str] = NOT_GIVEN, sample_rate: NotGivenOr[int] = NOT_GIVEN, encoding: NotGivenOr[STTEncoding | str] = NOT_GIVEN, format: NotGivenOr[bool] = NOT_GIVEN, itn_normalize: NotGivenOr[bool] = NOT_GIVEN, keywords: NotGivenOr[list[tuple[str, float]]] = NOT_GIVEN, sentence_timestamps: NotGivenOr[bool] = NOT_GIVEN, redact_pii: NotGivenOr[bool] = NOT_GIVEN, redact_pci: NotGivenOr[bool] = NOT_GIVEN, endpointing: NotGivenOr[bool] = NOT_GIVEN, endpointing_timeout_ms: NotGivenOr[int] = NOT_GIVEN, eou_timeout_ms: NotGivenOr[int] = NOT_GIVEN, vad_events: NotGivenOr[bool] = NOT_GIVEN, finalize_on_flush: NotGivenOr[bool] = NOT_GIVEN, ) -> None: self._opts = _apply_updates( self._opts, model=model, language=language, sample_rate=sample_rate, encoding=encoding, format=format, itn_normalize=itn_normalize, keywords=keywords, sentence_timestamps=sentence_timestamps, redact_pii=redact_pii, redact_pci=redact_pci, endpointing=endpointing, endpointing_timeout_ms=endpointing_timeout_ms, eou_timeout_ms=eou_timeout_ms, vad_events=vad_events, finalize_on_flush=finalize_on_flush, ) self._reconnect_event.set()
class TTS (*,
api_key: str | None = None,
model: TTSModels | str = 'lightning_v3.1_pro',
voice_id: str | None = None,
sample_rate: int = 24000,
speed: float = 1.0,
language: str = 'en',
output_format: TTSEncoding | str = 'pcm',
word_timestamps: bool = False,
max_buffer_flush_ms: int = 0,
use_continuations: bool = True,
max_buffer_delay_ms: int = 3000,
base_url: str = 'https://api.smallest.ai/waves/v1',
ws_url: str = 'wss://api.smallest.ai/waves/v1/tts/live',
http_session: aiohttp.ClientSession | None = None)-
Expand source code
class TTS(tts.TTS): def __init__( self, *, api_key: str | None = None, model: TTSModels | str = "lightning_v3.1_pro", voice_id: str | None = None, sample_rate: int = 24000, speed: float = 1.0, language: str = "en", output_format: TTSEncoding | str = "pcm", word_timestamps: bool = False, max_buffer_flush_ms: int = 0, use_continuations: bool = True, max_buffer_delay_ms: int = 3000, base_url: str = SMALLEST_BASE_URL, ws_url: str = SMALLEST_WS_URL, http_session: aiohttp.ClientSession | None = None, ) -> None: """ Create a new instance of Smallest AI Lightning TTS. Args: api_key: Your Smallest AI API key. model: The TTS model to use. Use "lightning_v3.1" for the standard model with 217 voices across 12 languages, or "lightning_v3.1_pro" (default) for the premium pool with curated American, British, and Indian voices at 44.1 kHz. voice_id: The voice ID to use for synthesis. Defaults to "meher" for "lightning_v3.1_pro" and "sophia" for all other models. Pro voices must be paired with "lightning_v3.1_pro"; standard voices with "lightning_v3.1". sample_rate: Sample rate for the audio output. Both models are natively 44.1 kHz; supported rates are 8000, 16000, 24000, and 44100. speed: Speed of the speech synthesis (0.5–2.0). language: Language of the text to be synthesized. Use "auto" for automatic detection and code-switching. Pro supports "en", "hi", and "auto" only. output_format: Output format for HTTP synthesize() calls ("pcm", "mp3", "wav", "ulaw", "alaw"). WebSocket streaming always returns PCM. word_timestamps: Request per-word timing events from the server and emit them as timed transcript entries alongside audio. Applies to WebSocket streaming only; HTTP synthesize() returns raw audio without word events. Disabled by default. Supported on base-queue English + Hindi voices (meher, devansh, kartik, maithili, liam, avery); other voices silently emit no word events. max_buffer_flush_ms: Server-side buffer bound (milliseconds) for the legacy ``continue``/``flush`` WebSocket protocol (used when ``use_continuations`` is False). As text tokens are streamed in with ``continue: true``, the server accumulates them and forces partial audio output once this many milliseconds of text have buffered, without waiting for an explicit flush. ``0`` (default) disables time-based forced flushing, so audio for a segment is produced when the segment's end-of-input flush is sent. Ignored when ``use_continuations`` is True. use_continuations: Use the ``context_id``-based continuations protocol instead of the legacy ``continue``/``flush`` fields. Continuations let the server release buffered text as soon as it hits a natural sentence boundary (or ``max_buffer_delay_ms`` elapses, whichever comes first) instead of holding everything until an explicit flush, and carry prosody across fragments by priming each release with the audio of the previous one. Defaults to True; set False to fall back to the legacy protocol. max_buffer_delay_ms: Upper bound (0-5000ms) on how long the server holds a buffered fragment waiting for a clean sentence boundary before speaking it anyway. Only applies when ``use_continuations`` is True. Defaults to 3000ms (the server default). base_url: Base URL for the Smallest AI HTTP API. ws_url: WebSocket URL for low-latency streaming synthesis. http_session: An existing aiohttp ClientSession to use. """ super().__init__( capabilities=tts.TTSCapabilities( streaming=True, aligned_transcript=word_timestamps, ), sample_rate=sample_rate, num_channels=NUM_CHANNELS, ) api_key = api_key or os.environ.get("SMALLEST_API_KEY") if not api_key: raise ValueError( "Smallest.ai API key is required, either as argument or set" " SMALLEST_API_KEY environment variable" ) if voice_id is None: voice_id = "meher" if model == "lightning_v3.1_pro" else "sophia" self._opts = _TTSOptions( model=model, api_key=api_key, voice_id=voice_id, sample_rate=sample_rate, speed=speed, language=LanguageCode(language), output_format=output_format, word_timestamps=word_timestamps, max_buffer_flush_ms=max_buffer_flush_ms, use_continuations=use_continuations, max_buffer_delay_ms=max_buffer_delay_ms, base_url=base_url, ws_url=ws_url, ) self._session = http_session self._pool = utils.ConnectionPool[aiohttp.ClientWebSocketResponse]( connect_cb=self._connect_ws, close_cb=self._close_ws, max_session_duration=3600, mark_refreshed_on_get=False, ) @property def model(self) -> str: return self._opts.model @property def provider(self) -> str: return "SmallestAI" def _ensure_session(self) -> aiohttp.ClientSession: if not self._session: self._session = utils.http_context.http_session() return self._session async def _connect_ws(self, timeout: float) -> aiohttp.ClientWebSocketResponse: return await asyncio.wait_for( self._ensure_session().ws_connect( self._opts.ws_url, headers={ "Authorization": f"Bearer {self._opts.api_key}", "X-Source": "livekit", "X-LiveKit-Version": __version__, }, ), timeout, ) async def _close_ws(self, ws: aiohttp.ClientWebSocketResponse) -> None: await ws.close() def update_options( self, *, model: NotGivenOr[TTSModels | str] = NOT_GIVEN, voice_id: NotGivenOr[str] = NOT_GIVEN, speed: NotGivenOr[float] = NOT_GIVEN, sample_rate: NotGivenOr[int] = NOT_GIVEN, language: NotGivenOr[str] = NOT_GIVEN, output_format: NotGivenOr[TTSEncoding | str] = NOT_GIVEN, word_timestamps: NotGivenOr[bool] = NOT_GIVEN, max_buffer_flush_ms: NotGivenOr[int] = NOT_GIVEN, use_continuations: NotGivenOr[bool] = NOT_GIVEN, max_buffer_delay_ms: NotGivenOr[int] = NOT_GIVEN, ) -> None: """Update TTS options.""" if is_given(model): self._opts.model = model if is_given(voice_id): self._opts.voice_id = voice_id if is_given(speed): self._opts.speed = speed if is_given(sample_rate): self._opts.sample_rate = sample_rate # keep the base class property in sync; the framework reads tts.sample_rate self._sample_rate = sample_rate if is_given(language): self._opts.language = LanguageCode(language) if is_given(output_format): self._opts.output_format = output_format if is_given(word_timestamps): self._opts.word_timestamps = word_timestamps self._capabilities.aligned_transcript = word_timestamps if is_given(max_buffer_flush_ms): self._opts.max_buffer_flush_ms = max_buffer_flush_ms if is_given(use_continuations): self._opts.use_continuations = use_continuations if is_given(max_buffer_delay_ms): self._opts.max_buffer_delay_ms = max_buffer_delay_ms def synthesize( self, text: str, *, conn_options: APIConnectOptions = DEFAULT_API_CONNECT_OPTIONS, ) -> ChunkedStream: return ChunkedStream(tts=self, input_text=text, conn_options=conn_options) def stream( self, *, conn_options: APIConnectOptions = DEFAULT_API_CONNECT_OPTIONS, ) -> SynthesizeStream: return SynthesizeStream(tts=self, conn_options=conn_options) def prewarm(self) -> None: self._pool.prewarm() async def aclose(self) -> None: await self._pool.aclose()Helper class that provides a standard way to create an ABC using inheritance.
Create a new instance of Smallest AI Lightning TTS.
Args
api_key- Your Smallest AI API key.
model- The TTS model to use. Use "lightning_v3.1" for the standard model with 217 voices across 12 languages, or "lightning_v3.1_pro" (default) for the premium pool with curated American, British, and Indian voices at 44.1 kHz.
voice_id- The voice ID to use for synthesis. Defaults to "meher" for "lightning_v3.1_pro" and "sophia" for all other models. Pro voices must be paired with "lightning_v3.1_pro"; standard voices with "lightning_v3.1".
sample_rate- Sample rate for the audio output. Both models are natively 44.1 kHz; supported rates are 8000, 16000, 24000, and 44100.
speed- Speed of the speech synthesis (0.5–2.0).
language- Language of the text to be synthesized. Use "auto" for automatic detection and code-switching. Pro supports "en", "hi", and "auto" only.
output_format- Output format for HTTP synthesize() calls ("pcm", "mp3", "wav", "ulaw", "alaw"). WebSocket streaming always returns PCM.
word_timestamps- Request per-word timing events from the server and emit them as timed transcript entries alongside audio. Applies to WebSocket streaming only; HTTP synthesize() returns raw audio without word events. Disabled by default. Supported on base-queue English + Hindi voices (meher, devansh, kartik, maithili, liam, avery); other voices silently emit no word events.
max_buffer_flush_ms- Server-side buffer bound (milliseconds) for the legacy
continue/flushWebSocket protocol (used whenuse_continuationsis False). As text tokens are streamed in withcontinue: true, the server accumulates them and forces partial audio output once this many milliseconds of text have buffered, without waiting for an explicit flush.0(default) disables time-based forced flushing, so audio for a segment is produced when the segment's end-of-input flush is sent. Ignored whenuse_continuationsis True. use_continuations- Use the
context_id-based continuations protocol instead of the legacycontinue/flushfields. Continuations let the server release buffered text as soon as it hits a natural sentence boundary (ormax_buffer_delay_mselapses, whichever comes first) instead of holding everything until an explicit flush, and carry prosody across fragments by priming each release with the audio of the previous one. Defaults to True; set False to fall back to the legacy protocol. max_buffer_delay_ms- Upper bound (0-5000ms) on how long the server holds a
buffered fragment waiting for a clean sentence boundary before speaking it
anyway. Only applies when
use_continuationsis True. Defaults to 3000ms (the server default). base_url- Base URL for the Smallest AI HTTP API.
ws_url- WebSocket URL for low-latency streaming synthesis.
http_session- An existing aiohttp ClientSession to use.
Ancestors
- livekit.agents.tts.tts.TTS
- abc.ABC
- EventEmitter
- typing.Generic
Instance variables
prop model : str-
Expand source code
@property def model(self) -> str: return self._opts.modelGet the model name/identifier for this TTS instance.
Returns
The model name if available, "unknown" otherwise.
Note
Plugins should override this property to provide their model information.
prop provider : str-
Expand source code
@property def provider(self) -> str: return "SmallestAI"Get the provider name/identifier for this TTS instance.
Returns
The provider name if available, "unknown" otherwise.
Note
Plugins should override this property to provide their provider information.
Methods
async def aclose(self) ‑> None-
Expand source code
async def aclose(self) -> None: await self._pool.aclose() def prewarm(self) ‑> None-
Expand source code
def prewarm(self) -> None: self._pool.prewarm()Pre-warm connection to the TTS service
def stream(self,
*,
conn_options: APIConnectOptions = APIConnectOptions(max_retry=3, retry_interval=2.0, timeout=10.0)) ‑> livekit.plugins.smallestai.tts.SynthesizeStream-
Expand source code
def stream( self, *, conn_options: APIConnectOptions = DEFAULT_API_CONNECT_OPTIONS, ) -> SynthesizeStream: return SynthesizeStream(tts=self, conn_options=conn_options) def synthesize(self,
text: str,
*,
conn_options: APIConnectOptions = APIConnectOptions(max_retry=3, retry_interval=2.0, timeout=10.0)) ‑> livekit.plugins.smallestai.tts.ChunkedStream-
Expand source code
def synthesize( self, text: str, *, conn_options: APIConnectOptions = DEFAULT_API_CONNECT_OPTIONS, ) -> ChunkedStream: return ChunkedStream(tts=self, input_text=text, conn_options=conn_options) def update_options(self,
*,
model: NotGivenOr[TTSModels | str] = NOT_GIVEN,
voice_id: NotGivenOr[str] = NOT_GIVEN,
speed: NotGivenOr[float] = NOT_GIVEN,
sample_rate: NotGivenOr[int] = NOT_GIVEN,
language: NotGivenOr[str] = NOT_GIVEN,
output_format: NotGivenOr[TTSEncoding | str] = NOT_GIVEN,
word_timestamps: NotGivenOr[bool] = NOT_GIVEN,
max_buffer_flush_ms: NotGivenOr[int] = NOT_GIVEN,
use_continuations: NotGivenOr[bool] = NOT_GIVEN,
max_buffer_delay_ms: NotGivenOr[int] = NOT_GIVEN) ‑> None-
Expand source code
def update_options( self, *, model: NotGivenOr[TTSModels | str] = NOT_GIVEN, voice_id: NotGivenOr[str] = NOT_GIVEN, speed: NotGivenOr[float] = NOT_GIVEN, sample_rate: NotGivenOr[int] = NOT_GIVEN, language: NotGivenOr[str] = NOT_GIVEN, output_format: NotGivenOr[TTSEncoding | str] = NOT_GIVEN, word_timestamps: NotGivenOr[bool] = NOT_GIVEN, max_buffer_flush_ms: NotGivenOr[int] = NOT_GIVEN, use_continuations: NotGivenOr[bool] = NOT_GIVEN, max_buffer_delay_ms: NotGivenOr[int] = NOT_GIVEN, ) -> None: """Update TTS options.""" if is_given(model): self._opts.model = model if is_given(voice_id): self._opts.voice_id = voice_id if is_given(speed): self._opts.speed = speed if is_given(sample_rate): self._opts.sample_rate = sample_rate # keep the base class property in sync; the framework reads tts.sample_rate self._sample_rate = sample_rate if is_given(language): self._opts.language = LanguageCode(language) if is_given(output_format): self._opts.output_format = output_format if is_given(word_timestamps): self._opts.word_timestamps = word_timestamps self._capabilities.aligned_transcript = word_timestamps if is_given(max_buffer_flush_ms): self._opts.max_buffer_flush_ms = max_buffer_flush_ms if is_given(use_continuations): self._opts.use_continuations = use_continuations if is_given(max_buffer_delay_ms): self._opts.max_buffer_delay_ms = max_buffer_delay_msUpdate TTS options.
Inherited members