tokenlab-talking-avatar
Turn a portrait and a script or voice recording into a talking-head video with TokenLab avatar and video models. Use when the user says "make this photo talk", "talking avatar", "AI presenter for my s
SKILL.mdskills/tokenlab-talking-avatar/SKILL.md
GitHubTalking Avatar
Make a portrait speak. Pick the path by what the user has:
- A voice recording, or a script plus a place to host audio: speech audio drives an avatar model. You control the voice and the exact timing.
- A short script only: a video model generates the face, the voice, and the lip motion in one call. Fast, but you do not choose the voice.
TokenLab does not offer lip-sync onto an existing video. Every path starts from a still portrait.
Inputs to collect
- Portrait: a public
httpsURL or a TokenLab result URL. Front-facing, face clear and well lit, shoulders visible, mouth closed or neutral. - Speech: a voice recording (public
httpsURL), or the script text. For a script, also the voice and language. - Length: the audio length sets the video length on the avatar models. Keep a first test under 10 s.
- Format: resolution and aspect ratio.
Models
<!-- tokenlab:models:start --> <!-- Generated from the live catalog by scripts/sync_models.py. Do not edit; change preferredModels in catalog.json. -->| Operation | Model | Pick | Use |
|---|---|---|---|
image-to-video |
omnihuman-1-5 |
default | Portrait plus speech audio |
image-to-video |
veed-fabric-1-0 |
alternative | Portrait plus speech, alternative (not live-tested) |
image-to-video |
p-video-avatar |
alternative | Low-cost portrait plus speech |
image-to-video |
veo3.1-fast |
alternative | Portrait plus a short quoted line, no audio file |
tts |
grok-tts |
default | Script to speech audio |
This list refreshes daily from the live catalog. Preferred models come first; otherwise models are ranked by their 24-hour success rate. Before a call, confirm the model with GET /v1/models/{model} and read its price from GET /v1/models/{model}/pricing.
How to choose
Exact fields and values come from each model's contract.
- OmniHuman 1.5 (Path A): a portrait plus speech audio. The default avatar model.
- Fabric 1.0 (Path A): a portrait plus speech, as an alternative.
- P-Video Avatar (Path A): a low-cost portrait plus speech.
- Veo 3.1 Fast (Path B): a portrait plus a short quoted line, with no audio file. Audio is always on. 4, 6, or 8 s.
- Grok TTS: turns the script into speech audio for Path A.
The avatar models price per second of output, and the output follows the audio length. Check GET /v1/models/{model}/pricing for the resolution you send.
Workflow
Run each call with tokenlab-run (contract → estimate → call → poll → result). Commands below use its helper, ../tokenlab-run/scripts/tokenlab_run.py, a path relative to this skill's folder. If you installed this skill without tokenlab-run, send the same requests with curl. --wait stops after 100 s; a longer task keeps running, so continue with the resume command it prints.
Path A: speech audio drives an avatar model
Get the audio. If the user has a recording, use its public
httpsURL. If the user has a script, make speech:python ../tokenlab-run/scripts/tokenlab_run.py run /v1/audio/speech --json '{"model": "MODEL_ID", "input": "Hi, I am Mia. This mug keeps my coffee hot all morning.", "voice": "VOICE", "response_format": "mp3"}' --out line.mp3Take the TTS
MODEL_IDfrom the Models list above (operationtts) and a voice that model lists (for exampleeveon Grok TTS).TTS returns audio bytes, not a URL. Put the file on storage the user controls with a public
httpsURL that stays valid until the task starts (for example a public bucket or CDN path). Adata:URL does not work for speech:audio_urlis capped at 8192 characters, which holds well under one second of audio.POST /v1/filesis not a general audio host.Read the contract:
python ../tokenlab-run/scripts/tokenlab_run.py contract MODEL --operation image-to-video. Send only listed fields.Estimate: per-second price × audio seconds (
ffprobe line.mp3). Add the TTS cost (price per character × script length). Tell the user.Build the body and call:
{"model": "MODEL_ID", "operation": "image-to-video", "image_url": "https://...portrait.jpg", "audio_url": "https://...line.mp3", "prompt": "She speaks to the camera with natural head movement and a friendly expression.", "resolution": "720p"}Take an avatar
MODEL_ID(one that takesaudio_url) from the Models list above forimage-to-video. Sendresolutiononly when its contract lists it.python ../tokenlab-run/scripts/tokenlab_run.py run /v1/videos/generations --json @body.json --wait. Save the task ID. Poll every 5-10 s.
Path B: the video model speaks the line
Read the contract:
python ../tokenlab-run/scripts/tokenlab_run.py contract MODEL --operation image-to-video, with the Veo 3.1 Fast model from the Models list.Estimate: per-second price (audio is always on) ×
duration. Tell the user.Put the line in quotes inside the prompt. Keep it short enough to say in the clip length (about 2-3 words per second):
{"model": "MODEL_ID", "operation": "image-to-video", "image_url": "https://...portrait.jpg", "prompt": "Close-up portrait, eye level, static camera. She looks into the lens, smiles, and says: \"Hi, I'm Mia. This mug keeps my coffee hot all morning.\" Quiet room tone, no music.", "duration": 4, "resolution": "720p", "aspect_ratio": "9:16"}Use the Veo 3.1 Fast
MODEL_IDfrom the Models list above (image-to-video).Call and wait as above.
Both paths
- If a wait times out, resume with
python ../tokenlab-run/scripts/tokenlab_run.py poll TASK_ID. Never create a duplicate task. - Check the lips against the words. To check Path B without listening, transcribe the result's audio with
tokenlab-transcribe-and-subtitleand compare the text with the script. - Return the video URL, the model, the task ID, and the estimate.
Technique
- The portrait decides the result. One face, front-facing or slightly turned, eyes open, mouth closed, no hands or hair over the mouth, even light.
- Clean audio. One speaker, no music bed, no long silences at the start or end. Trim silence first; you pay for every second.
- Prompt the body, not the words (Path A). The audio sets the lips. Use the prompt for expression and gestures: "calm, warm expression, small hand gestures, slight head nods".
- Quote the exact words (Path B). Google's Veo guide says to put speech in quotes. Describe the sound around it ("quiet room tone, no music") so music does not cover the voice.
- Short lines per clip. Split a long script into lines of one or two sentences. Make one clip per line and cut them together.
- Consent. Use only portraits and voices the user has the right to use. Do not imitate a real person without their permission.
Quality bar
- Lip motion matches the words; the voice and mouth stay in sync to the end.
- The face keeps its identity; teeth, eyes, and hair stay stable.
- The video length matches the audio (Path A) or the requested duration (Path B).
- The script is spoken exactly (check with a transcript), and the user saw the estimate first.
Related skills
tokenlab-run: the call, poll, and result mechanics.tokenlab-voiceover: choose a TTS model and voice for the script.tokenlab-transcribe-and-subtitle: check the spoken words and add subtitles.tokenlab-animate-image: a portrait that moves without speech.tokenlab-character-consistency: make the presenter portrait first.