p-video-avatar
P-Video-Avatar does one thing and does it fast: it makes a still portrait speak. Give it a single image and either a script or an audio track, and it returns a lip-synced video of that person delivering the words — with body movement, expression, and a background that behaves. Speech can come from your own recording or from thirty built-in voices across ten languages, so a script-to-video pipeline needs no external text-to-speech step. Output follows the aspect ratio of the input image, which makes the same portrait serve both a landscape hero cut and a vertical social clip. It is built for volume: ad variants, localized support explainers, and education segments where one approved face has to say many different things.
P-Video-Avatar
Pruna AI's avatar model. It turns a single portrait image into a speaking video — lip-synced, with body movement and expression.
It is narrow on purpose. It does not generate scenes, retarget motion from a driver clip, or edit existing footage. It makes a still talk, and it is built to do that at production volume.
⚠️ Safety Filtering Is Off by Default
disable_safety_filter defaults to true. Prompt and image safety checks are disabled
unless you turn them on.
This is the reverse of most generation APIs, and it matters more here than it would elsewhere. This model takes an arbitrary portrait and makes it say an arbitrary script. Deployed with the default and without your own controls, that is a tool for putting words in someone's mouth.
Pruna's own guidance is to keep the default behaviour only where you have an explicit moderated workflow. If you do not have one:
{ "disable_safety_filter": false }Regardless of this setting, you remain responsible for the likeness you upload. Pruna states it directly: respect the copyright of the images you use as input, and of the speech and video you generate. A portrait of a real person requires that person's consent, and no API parameter supplies it.
How It Works
You give the model two things.
A portrait image — required. This is the first frame, and it determines identity, framing, and
aspect ratio. Formats: jpg, jpeg, png, webp.
Words — either a script for the built-in voices, or an audio file to lip-sync against. If both are supplied, the audio wins and the script is ignored.
Everything else shapes the result rather than defining it.
Parameters
Required
| Parameter | Type | Description |
|---|---|---|
image | file / URL | First frame. jpg, jpeg, png, webp. Determines identity and aspect ratio. |
Plus either voice_script or audio.
Optional
| Parameter | Default | Description |
|---|---|---|
audio | — | Audio track driving speech and timing. Overrides voice_script. |
voice_script | "" | What the avatar says, when no audio is supplied. |
voice | Zephyr (Female) | Which built-in voice speaks. |
voice_language | English (US) | Output language for generated speech. |
voice_prompt | Say the following. | How it is said — tone, pace, energy. Not the words. |
video_prompt | The person is talking. | On-camera motion, framing, background behaviour. |
resolution | 720p | 720p or 1080p. |
seed | random | For reproducible generations. |
disable_safety_filter | true | See the warning above. |
disable_prompt_upsampling | false | Pass raw prompt text instead of enhanced. |
negative_prompt | "" | Experimental. Elements to suppress. |
negative_prompt_strength | 0 | Experimental. Both must be set for either to apply. |
The two prompt fields do different jobs, and mixing them degrades both. voice_prompt controls
delivery: "warm support specialist, calm pace", "no sales hype, clear consonants".
video_prompt controls the picture: "fixed eye-level shot, small hand gestures", "soft office
blur behind subject, no zoom". Do not restate the script in either.
Voices and Languages
Ten languages: English (US), English (UK), Spanish, French, German, Italian, Portuguese (Brazil), Japanese, Korean, Hindi.
Thirty built-in voices, named after stars: Achernar, Achird, Algenib, Algieba, Alnilam, Aoede, Autonoe, Callirrhoe, Charon, Despina, Enceladus, Erinome, Fenrir, Gacrux, Iapetus, Kore, Laomedeia, Leda, Orus, Puck, Pulcherrima, Rasalgethi, Sadachbia, Sadaltager, Schedar, Sulafat, Umbriel, Vindemiatrix, Zephyr, Zubenelgenubi.
Align the voice with the face. Pruna is explicit about this: voice gender, language, and the identity in the start frame should match. A mismatch reads as wrong immediately, even when every individual element is good.
Rewrite scripts per locale rather than translating them. Shipping English phrasing through a French voice produces speech that is technically correct and audibly foreign.
The Prompt Formula
Pruna publishes a four-part structure worth following literally.
| Slot | Fast pass | Locked-in |
|---|---|---|
Start frame (image) | One line: who, outfit, basic light. Single subject. | Age, wardrobe, expression, light direction, set, lens and aspect spelled out. |
voice_script | Short lines, one beat per sentence, in the target language. | Ear-tested for speech synthesis, rewritten per locale, with natural pauses. |
voice_prompt | Tone and pace in a few words. | Role, register, and what to avoid — hype, theatrical delivery. |
video_prompt | Steady shot, small motion, simple background. | Fixed camera, repeatable gestures, static or softly blurred background. |
When lip sync drifts, lock the camera. Pruna's recommendation: no pan, no zoom, no handheld if the mouth or frame wobbles. A fixed camera is the single most effective fix for unstable sync.
"Single subject" belongs in the start frame prompt. A second face in the image is the most common cause of an unusable result.
Aspect Ratio Comes From the Image
Output follows the input image. A landscape start frame gives a landscape video; a portrait start frame gives a vertical one.
There is no aspect ratio parameter. Generate the still at the ratio you need — 16:9 for a web hero cut, 9:16 for social — and the video follows.
This is also how you get one identity across formats: same person, same wardrobe, same lighting, two start frames at two ratios.
Capabilities
| Capability | Value |
|---|---|
input_types | image (required), text, audio |
output_types | video |
audio_output | Yes — lip-synced speech |
resolutions | 720p, 1080p |
languages | 10 |
voices | 30 built-in |
recommended_max_duration | Under 3 minutes |
endpoint | /v1/video/generations |
requires_prompt | No — but an image and either a script or audio are required |
Using P-Video-Avatar on DEVUP AI
Endpoint: POST https://api.devupai.com/v1/video/generations
Video generation on this platform is synchronous — a request can hold the connection open for several minutes. Set a generous timeout.
The response returns a signed URL in data[0].url that expires 300 seconds after the response
is produced, after which the proxy returns HTTP 403. Download immediately, or request
response_format: "b64_json" for inline bytes. Videos above the 20 MB inline limit fall back to a
URL automatically, with a note inside _devup.
Every response carries _devup with cost_dzd for the request and balance_dzd for what remains.
Verify the request shape before building
This model requires an image input. Confirm how that field is accepted on your path before
writing a pipeline around it — a video model that takes a mandatory image is a different request
shape from a prompt-only text-to-video model.
curl -X POST "https://api.devupai.com/v1/video/generations" \
-H "Authorization: Bearer $DEVUP_API_KEY" \
-H "Content-Type: application/json" \
--max-time 900 \
-d '{
"model": "PrunaAI/p-video-avatar",
"image": "https://example.com/portrait.jpg",
"voice_script": "Bienvenue. Configurons votre premier flux en deux minutes.",
"voice": "Kore (Female)",
"voice_language": "French",
"voice_prompt": "Professional onboarding, clear articulation, approachable tone.",
"video_prompt": "Fixed camera, centered; light hand motion, stable framing.",
"resolution": "720p",
"disable_safety_filter": false
}'Read what comes back. A success tells you the shape is accepted; an error tells you which fields are not. Either answer is worth knowing before you build.
Downloading the result — Python
import os
import requests
DEVUP_API_KEY = os.environ["DEVUP_API_KEY"]
response = requests.post(
"https://api.devupai.com/v1/video/generations",
headers={
"Authorization": f"Bearer {DEVUP_API_KEY}",
"Content-Type": "application/json",
},
json={
"model": "PrunaAI/p-video-avatar",
"image": portrait_url,
"voice_script": "Welcome. Let's connect your data in under two minutes.",
"voice": "Zephyr (Female)",
"voice_language": "English (US)",
"voice_prompt": "Warm support specialist, calm pace.",
"video_prompt": "Fixed eye-level shot, small hand gestures, soft office blur behind subject.",
"resolution": "720p",
"seed": 42,
"disable_safety_filter": False,
},
timeout=900, # synchronous generation — minutes, not seconds
)
response.raise_for_status()
result = response.json()
# Download immediately — the signed URL expires 300 seconds after the response.
with open("avatar.mp4", "wb") as handle:
handle.write(requests.get(result["data"][0]["url"], timeout=120).content)
print(f"Cost: {result['_devup']['cost_dzd']} DZD · Balance: {result['_devup']['balance_dzd']} DZD")seed is set deliberately here. When you are testing prompt changes, a fixed seed is what lets you
attribute a difference to the change rather than to sampling.
Node.js
import { writeFile } from "node:fs/promises";
const response = await fetch("https://api.devupai.com/v1/video/generations", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.DEVUP_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "PrunaAI/p-video-avatar",
image: portraitUrl,
voice_script: "Welcome. Let's get you set up.",
voice: "Puck (Male)",
resolution: "720p",
disable_safety_filter: false,
}),
signal: AbortSignal.timeout(900_000),
});
if (!response.ok) {
throw new Error(`Request failed with status ${response.status}`);
}
const result = await response.json();
const video = await fetch(result.data[0].url);
await writeFile("avatar.mp4", Buffer.from(await video.arrayBuffer()));Production Workflow
The pattern this model was designed around, and the one that keeps cost sane.
Iterate at 720p, deliver at 1080p. Cost scales per second of output and by resolution. Get the prompt, voice, and timing right at the lower tier, then rerun the final asset at the higher one. Composition, delivery, and motion carry across — only the pixels change.
Fix the seed while iterating. Change one variable at a time. With a random seed you cannot tell whether a difference came from your edit or from the sampler.
Reuse one approved start frame across a campaign. The identity is in the image. One portrait, many scripts, many languages — that is the whole point of the model, and it is what separates it from re-shooting.
Prefer uploaded audio when pronunciation matters. Brand names, product names, technical terms,
and anything in a language you are not certain the synthesiser handles well. The built-in voices are
fast and scale; a recording is exact.
Limitations
- Safety filtering is off by default.
disable_safety_filterdefaults totrue. Set it tofalseunless you have your own moderation layer. - Likeness and consent are your responsibility. The model will animate any face you give it. No parameter supplies permission.
- Ten languages only — Arabic is not among them.
- No aspect ratio parameter. Output follows the input image; control it there.
- Clips under three minutes are recommended. Longer generations show gradual consistency drift, which Pruna describes as a current limitation across diffusion video models generally.
- One subject only. A second face in the start frame is the most common cause of failure.
- Not for motion retargeting or footage editing. This model generates new speech from one still. Animating a still from existing footage, swapping characters in footage, or editing footage are different models.
- Negative prompting is experimental. Both
negative_promptandnegative_prompt_strengthmust be set for either to apply, and higher strengths can affect identity, motion, or background unpredictably. - Synchronous generation. Requests hold the connection for minutes; plan timeouts accordingly.
- Signed URLs expire after 300 seconds.
- No architecture, parameter count, or technical report is published.
- No per-request spending limit exists on this platform. Bound generation volume in your own application layer.
- Not a safety layer. Apply your own moderation to input images, scripts, and output before publishing.