Python SDK
Drive Ojin's face models — Oris Presence and Oris Portrait — straight from Python. Feed in your TTS audio; get back a synchronized, lip-synced talking-avatar stream.
The ojin-client SDK is the fastest way to add a real-time talking avatar to a Python app or voice agent. You bring the words (any TTS); the SDK streams back a face that speaks them — perfectly in sync — handling buffering, the playback clock, resampling, and barge-in for you.
Just want a complete agent? If you'd rather not assemble a pipeline, the Human Agent gives you a full speech-in, speech-out avatar with a single line of embed code. Already on Pipecat? Jump to the Pipecat integration.
Requirements
Python 3.10+
An Ojin API key — get yours here
A face-model config ID — a Presence or Portrait configuration from your dashboard
New accounts start with $10 in free credits.
Install
With uv (recommended):
uv add "ojin-client[stv]"Or with pip:
pip install "ojin-client[stv]"The [stv] extra pulls in the speech-to-video helpers (numpy, opencv-python-headless, soxr) that handle resampling, decoding, and the sync math for you.
Authenticate
The client needs your API key and a configuration ID. Keep both out of source — read them from the environment:
Or let the SDK load and validate them for you — resolve_credentials() reads an optional .env file and raises a clear error if either value is missing:
By default the client connects to wss://models.ojin.ai/realtime.
Never hardcode your API key in source or commit it to version control.
Pick your model
The SDK is identical for both face models — the config_id you pass selects which one runs.
A config_id from…
You get
Choose it when
an Oris Presence config
the flagship, fully expressive generative presence — rich expressions and natural movement
quality and expressiveness matter most
an Oris Portrait config
a cost-effective, real-time lip-synced talking face
you want a great talking face at the best price
Create configurations in the dashboard. The code below is the same either way — only the config_id changes.
Two clients, one package
OjinSTVClient (high-level)
OjinClient (low-level)
Import
from ojin.stv import OjinSTVClient
from ojin.ojin_client import OjinClient
You give it
TTS audio at any sample rate
16 kHz mono int16 PCM
You get
synced STVAudioFrame + STVVideoFrame on a 25 fps clock
raw protocol messages (JPEG + PCM)
It handles
buffering, playback clock, resampling, barge-in re-sync
just the WebSocket + wire protocol
Most applications want OjinSTVClient. Reach for OjinClient only when you're writing your own playback/sync layer.
Quickstart
Feed the avatar one utterance of TTS audio and consume the synchronized stream it speaks back.
say() is a one-shot helper for start_turn() + send_tts_audio(). For a live agent, call start_turn() once per utterance and stream chunks with send_tts_audio() as your TTS produces them — the user hears the exact audio you sent, lip-synced to the avatar.
The SDK shapes the input for you. Feed audio at whatever cadence your TTS produces — even tiny 40 ms fragments. OjinSTVClient primes a ~1 s lead after each start_turn() and coalesces your audio into large chunks before forwarding it, so the inference head never starves and lip-sync stays stable. It also paces output_stream() to realtime 25 fps with audio and video already in sync. You don't manage input buffering, the playback clock, or frame-dropping yourself — see Optimizing Performance for how it works and how to tune it.
Events you'll use
Register handlers with @client.on(STVEvent.X) or client.add_listener(STVEvent.X, cb). Handlers may be sync or async; a failing handler never breaks the playback loop.
SESSION_READY
the session is live and ready for audio
BOT_STARTED_SPEAKING
the first speech frame of a turn is played
BOT_STOPPED_SPEAKING
a turn has finished playing
INTERRUPTED
a barge-in was accepted
ERROR
a transport or server error occurred
CLOSED
the session has been torn down
Where to go next
Runnable examples
Realtime streaming and render-to-MP4, ready to clone
Build a voice agent
Drop the avatar into a Pipecat pipeline
Best practices — working-pipeline patterns for browser output and WebRTC backends
Choose a face model — Oris Presence (flagship) or Oris Portrait (cost-effective)
Tune latency & stability — Optimizing Performance and the Troubleshooting guide
Full API surface — the complete client reference lives in the
ojin-clientREADME and on PyPIStarter examples —
02-realtime-speech-to-video(live streaming) and01-speech-to-video-mp4-generator(render to file)
Last updated
Was this helpful?