Concepts / Voices
Voices
The voice is the timbre the avatar speaks with. It's set once on the avatar persona, alongside the language and (for conversational turns) the model that generates the words.
Selecting a voice
Set voice_id on AvatarConfig:
from zeli import AvatarConfig
AvatarConfig(
avatar_id="01-presenter-male__confident",
voice_id="your-voice-id",
)The voice the avatar speaks with. Omit it for the server's configured voice.
AvatarConfig.language_code is never transmitted, so setting it
changes nothing. The language follows the voice you chose and the words you
send. See Configuration for the full list of
fields that do and do not reach a server.
Text-to-speech vs. the model
How the words are chosen depends on how you drive the avatar:
talk(text)speaks your exact text directly through TTS in the configured voice. The conversational model is not involved.send_message(text)runs the server's conversational model (llm_id), and the avatar speaks the generated reply in the configured voice.
# Exact words, straight to the voice
await session.talk("Reading this verbatim.")
# Model generates the words, the voice speaks them
await session.send_message("Introduce yourself in one sentence.")The conversational model
Set llm_id on the persona to choose the model for this session. It is sent
on POST /connect, so the choice is made before the first turn and applies to
every turn of the session. Omit it to take the server's own configured model.
from zeli import AvatarConfig
AvatarConfig(
avatar_id="01-presenter-male__confident",
voice_id="your-voice-id",
llm_id="au.anthropic.claude-opus-5-5",
)Model to answer this session's turns with. The JavaScript SDK spells the same
field llmId. Read the ids a server offers from its
GET /api/settings under models.
A model id says both which model and where it
runs, and the same weights are reachable at more than one address. So a server
handed an id it will not run does not quietly substitute its own: it answers
400 model_refused at the connect and the SDK raises
ModelRefusedError (JavaScript:
ModelRefusedError), carrying the id you named and the reason. A
silent fallback would leave you judging a model you are not talking to, and
could move the conversation to another country without saying so.
AvatarConfig.system_prompt is never transmitted. The system prompt
is a server setting rather than a session one: configure it on the server itself
through GET / POST /api/settings. The model is the one
of those settings a single session may also choose for itself.
Use talk when you already have the words (your own model, a script,
or fixed copy) and send_message when you want the server's model to
generate them. See Driving the avatar.