Highlights
SoulX-FlashHead is the toolkit's talking head generator (tools/soulx.py, Modal-only, Apache 2.0). One photo plus audio; preserves the input aspect ratio, so 16:9 presenter images come back 16:9 with no --preprocess workaround.
Demo — 80 seconds from a single still
It holds identity over a long take, which is the reason it is the default. Segment-chained talking heads re-anchor each segment on the previous segment's output, so the failure is absorbing rather than gradual. Measured at 97% of frame-zero sharpness at 70s, flat across 72 segments, on two subjects at three resolutions. ~$0.0024 per second of output, ~6.4-7.9x realtime on an A10G.
Note on the commit log below: EchoMimicV3 was added and removed within this release cycle, so it appears in both directions. It never reached a tagged release and was never installable — nothing to migrate. It was replaced because its identity drift proved unusable: on a controlled A/B (same photo, same 80s audio, same resolution) it fell to 50% of frame-zero sharpness by 70s, collapsing to a featureless smear, where SoulX held 97%.
Also in this release: five Modal/R2 cloud-infrastructure fixes (#70, #71, #72, #73, #75), the _migrate_common refactor (#58, thanks @mhaye9545), and a NarratorPiP fix for the objectPosition prop it declared but ignored.
All commits
- Release v0.20.0: SoulX-FlashHead talking head, Modal/R2 cloud fixes, _migrate_common refactor (f91608a)
- Merge pull request #82 from digitalsamba/feat/soulx-talking-head (a567698)
- REMOVE: EchoMimicV3 — drift made it unusable, SoulX is the default (#81) (fd24349)
- FEAT: tools/soulx.py — SoulX-FlashHead talking head on Modal (#81) (3277ff4)
- FIX: _migrate_common — drop a dead duplicate find_repo_root, BOM and missing future import (c76f87c)
- Merge pull request #78 from mhaye9545/refactor-migrate-common (f9a2475)
- Merge pull request #79 from digitalsamba/feat/echomimic3-talking-head (9f7f3b0)
- DOCS: echomimic3 — usage guide, registry entry, and the SadTalker decision rule (#77) (9c152c3)
- FIX: NarratorPiP — honour the objectPosition prop instead of ignoring it (f169ac2)
- FIX: echomimic3 — stop a segment seam mid-blink latching the eyes shut (#77) (7a3dce4)
- CHANGE: echomimic3 — store weights in a Modal Volume, pin every ref by SHA (#76) (bfadee6)
- refactor: extract _migrate_common module (#58) (18de2b8)
- FEAT: tools/echomimic3.py — EchoMimicV3 talking head on Modal (#77) (d8b1a7c)
- FIX: pin diffusers to a commit in modal-flux2 for reproducible builds (#75) (5558295)
- FIX: drain R2 cleanup on error paths too (upscale, sadtalker, qwen3_tts, dewatermark) (#73) (f52c627)
- FIX: flux2 — raise transformers floor to 4.51 for Qwen3ForCausalLM (#71) (580632f)
- FIX: delete R2 result objects in flux2, music_gen, image_edit, ltx2 (#72) (ce1bd0a)
- FIX: modal-upscale crash-loop — cap opencv <4.12 so numpy stays 1.x for torch 2.1.2 (#70) (a7795c5)
Full Changelog: v0.19.0...v0.20.0