Zeli AvatarDeveloper docs

Guides / Creating avatars

Creating avatars

Bring your own face: upload a custom image or video and get a streaming avatar you can drive from your app. Do it once in the portal, or entirely through the API.

From the portal

Sign in at /portal/avatars, paste an API key, and drop in a photo or a short video. A short video gives the most lifelike result: real head motion, captured from you. A still photo works too, and becomes a talking photo: the mouth moves in sync with the audio while the head stays still. When it finishes preparing you get an avatar id and a snippet to stream it. Manage your keys at /portal/keys.

From the API

Create the same avatar programmatically. A video source gives real head motion; a still photo gives a talking photo: moving mouth, still head.

from zeli import ZeliClient, AvatarConfig, ClientOptions
 
client = ZeliClient(
    api_key="YOUR_API_KEY",
    options=ClientOptions(server_url="https://zeli-avatar.zelibot.xyz"),
)
 
status = await client.create_avatar("founder.mp4", name="founder")
print(status.avatar_id, status.status)  # e.g. "founder" "preparing"

create_avatar returns an AvatarStatus (preparing or ready). Poll list_avatars until it's ready:

from zeli._avatars import avatar_is_ready
 
while not avatar_is_ready(await client.list_avatars(), status.avatar_id):
    await asyncio.sleep(2.5)

Avatar creation and live conversation processing are separate operations. Review the creation flow's provider and region information before uploading a face, and obtain the required consent. Some optional creation providers process images outside Australia. The selected speech and language-model providers determine conversation processing regions independently.

Natural motion from a photo

POST /v1/photo_avatar.create builds motion clips when that capability is available for your deployment and the submitted face passes consent checks. A deployment without the capability returns 501 feature_disabled; unverified consent is rejected. Use create_avatar above for the supported talking-photo upload flow.

The SDK method and its request/response shape are settled, and the call carries the server-side consent verification the pipeline requires:

created = await client.create_avatar_from_photo(
    "headshot.jpg", avatar_id="founder", tones=["neutral", "warm"],
    consent_token="<from your consent flow>",
)
print(created.avatar_id, [c.tone for c in created.clips])

If consent isn't verified you get a ConsentError (with .decision); a rejected key raises AuthenticationError. On a server without the feature enabled, the 501 surfaces as a ZeliError with code feature_disabled.

Then stream it

Once an avatar is ready, drive it like any built-in avatar. Reference it by id:

client = ZeliClient(
    avatar_config=AvatarConfig(avatar_id="founder"),
    api_key="YOUR_API_KEY",
    options=ClientOptions(server_url="https://zeli-avatar.zelibot.xyz"),
)
 
async with client.connect() as session:
    await session.talk("Hi, welcome to the demo.")
    async for frame in session.video_frames():
        img = frame.to_ndarray(format="rgb24")

See Connecting and Driving the avatar for the full streaming loop.

Zeli Avatar · real-time avatars over WebRTC · self-hostable · AU data residency · source