realtime-multivoice-tts-client (0.1.5)
Installation
pip install --index-url realtime-multivoice-tts-clientAbout this package
Typed HTTP and protocol-v3 streaming client for Realtime Multivoice TTS
Realtime Multivoice TTS Client
Lightweight typed clients for the Realtime Multivoice TTS HTTP API and raw protocol-v3 stream. This distribution does not install the server, NumPy, VoXtream, or audio playback dependencies.
The canonical wire protocol and identifier/playback semantics are documented in
docs/protocol-v3.md.
gh release download v0.1.5 --pattern 'realtime_multivoice_tts_client-*.whl'
python -m pip install realtime_multivoice_tts_client-0.1.5-py3-none-any.whl
Synchronous Streaming
SyncStreamingClient accepts any Iterable[str], sends each chunk unchanged,
then sends exactly binary b"<EOT>". It receives JSON controls and binary PCM
concurrently and keeps the connection for sequential cycles completed by eos.
from realtime_multivoice_tts_client import PcmEvent, SyncStreamingClient
with SyncStreamingClient("http://127.0.0.1:7860", cycle_timeout_seconds=300) as client:
for event in client.stream(["<ANNOUNCER>Hello ", "world"]):
if isinstance(event, PcmEvent):
consume_pcm(event.data)
Closing an iterator before eos, malformed or mismatched controls, sender
errors, and disconnects close and invalidate the socket. Input is never replayed.
cycle_timeout_seconds is optional and covers the entire cycle through eos;
expiry raises the public StreamingTimeout error. Use separate client instances
when normal and control traffic need different budgets, such as 300 and 10
seconds.
Asynchronous Streaming
StreamingClient provides the same events and guarantees for an
AsyncIterable[str]:
async with StreamingClient("http://127.0.0.1:7860", cycle_timeout_seconds=300) as client:
async for event in client.stream(text_chunks):
consume(event)
Both clients return shared frozen dataclasses: ConfigEvent, PcmEvent,
SegmentEvent, IdentifierEvent, WarningEvent, InterruptEvent, ErrorEvent,
and EosEvent.
Both raise StreamingTimeout when their optional whole-cycle budget expires.
Pass on_identifier to either constructor to receive each server identifier
event immediately before it is yielded. The async client accepts a synchronous
function or an async function and awaits the latter within the cycle timeout.
Listener exceptions abort the cycle and invalidate its connection.
Generated sync and async HTTP clients are constructed with create_http_clients
and create_async_http_clients; public HTTP models live in
realtime_multivoice_tts_client.models.
Identifier Playback Tracking
Inline <IDENTIFIER=value> tags produce IdentifierEvent with
IdentifierStage.SYNTHESIZED. Feed every stream event into the dependency-free,
thread-safe PlaybackTracker, and advance it by the number of sample frames the
audio device actually consumes. It returns each identifier exactly once with
IdentifierStage.PLAYED:
from realtime_multivoice_tts_client import (
IdentifierEvent,
PcmEvent,
PlaybackTracker,
SyncStreamingClient,
)
tracker = PlaybackTracker()
with SyncStreamingClient(
"http://127.0.0.1:7860",
on_identifier=on_identifier,
) as client:
for event in client.stream(["<P1>Hello.<IDENTIFIER=greeting>Next sentence."]):
for played in tracker.observe(event):
on_identifier(played)
if isinstance(event, PcmEvent):
frames_played = play_pcm(event.data)
for played in tracker.advance(frames_played):
on_identifier(played)
Call advance when frames are consumed by the playback callback, not when they
are merely queued. Positions are measured in sample frames, not scalar channel
samples or bytes. On interrupt, observe returns IdentifierStage.SKIPPED for
every synthesized identifier playback had not reached, then resets the tracker
to the new epoch. Identifiers cancelled before synthesis arrive from the server
with the same stage and a null sample index.
on_identifier receives server-emitted SYNTHESIZED, PLAYED, and SKIPPED
events. In stream output mode, playback-derived PLAYED and SKIPPED events are
created locally by PlaybackTracker; dispatch those returned events to the same
listener as shown above.