An AI avatar pipeline should treat the source portrait as an input contract and the output as a raster candidate that must pass both automated file checks and a manual identity-anchor review. This tutorial creates a stylized still avatar—not a talking video, 3D mesh, or identity credential.
1. Input contract
Use an authorized, front-facing portrait with visible eyes, jaw, and hairline.
input:
permission: true
subject_count: 1
min_face_width_px: 512
view: front_or_near_front
occlusions: none
style_change:
target: flat_editorial_illustration
preserve:
- eye_spacing
- brow_shape
- nose_width
- mouth_shape
- jaw_width
- hairline
output:
ratio: match_input
format: png_or_webp
minimum_side_px: 1024
A group crop or strong side profile makes the contract ambiguous. Fix the input instead of trying to repair identity with a longer prompt.
2. Record the source deterministically
from pathlib import Path
import hashlib
from PIL import Image
source = Path("portrait.jpg")
raw = source.read_bytes()
image = Image.open(source).convert("RGB")
manifest = {
"sha256": hashlib.sha256(raw).hexdigest(),
"width": image.width,
"height": image.height,
"mode": image.mode,
}
print(manifest)
The hash does not prove permission or identity. It only records exactly which source file the review refers to.
3. Use the direct still-avatar form
Open the AI Face Generator workspace. On July 29, 2026 the selected model was Flux Kontext Pro with Prompt, required Input Image, Match Input Image ratio, Public visibility, Generate, and a 12-credit estimate. The final live estimate can change after the real input and settings are selected.
Use a single transformation instruction:
Restyle the authorized portrait as a clean flat editorial avatar. Preserve recognizable eye spacing, brow shape, nose width, mouth shape, jaw width, hairline, skin tone, and head-to-shoulder proportions. Keep the original camera angle and expression. Simplify surface texture into controlled color planes with one soft shadow. Plain muted background. Do not beautify, age-shift, change hairstyle, add accessories, or alter facial geometry.
4. Validate the output file
from pathlib import Path
from PIL import Image, ImageStat
p = Path("avatar.png")
im = Image.open(p).convert("RGB")
errors = []
if min(im.size) < 1024:
errors.append("minimum side is below 1024 px")
if p.stat().st_size > 12 * 1024 * 1024:
errors.append("file exceeds 12 MB delivery budget")
mean = sum(ImageStat.Stat(im).mean) / 3
if mean < 20 or mean > 240:
errors.append("global luminance is suspiciously clipped")
print({"size": im.size, "errors": errors})
This validator catches delivery failures, not identity failures.
5. Manual identity-anchor review
Compare source and output side by side at the same face size:
- eye-to-eye distance;
- eyebrow arc and asymmetry;
- nose width at the nostrils;
- mouth width and cupid's bow;
- jaw width and chin length;
- hairline shape;
- head-to-shoulder proportion.
Mark each anchor pass, uncertain, or fail. Reject the candidate if two or more anchors fail. Do not average a badly changed jaw against a correctly colored background.
Troubleshooting
- Looks generic: remove broad beauty terms; name preserved anchors.
- Wrong age: explicitly preserve age cues and natural skin texture.
- Hair changes: protect hairline, part, length, and silhouette.
- Face becomes too narrow: preserve jaw width and cheekbone distance.
- Output is attractive but not the same person: reject it; aesthetic quality does not satisfy the identity contract.
Technical limits
Flux Kontext Pro produces a raster image. It does not create a rigged avatar, talking video, 3D mesh, reusable biometric model, or identity verification. Automated similarity scores can embed bias and should not replace informed human review. Use only authorized portraits and label synthetic images when context requires it.
After the input contract and validator are ready, generate one avatar candidate and keep the result only if the identity anchors survive.

