"""Phase 3 component test: avatar upload → idle clip generation. Verifies: - ``VideoEngine.load_models()`` + ``set_avatar(image)`` produces a non-empty idle MP4 blob. - The blob decodes as a valid MP4 (ftyp header). Writes the idle clip to ``tests/component/_out/phase3_idle.mp4`` so you can inspect it visually. Run: docker compose exec voice-chat python -m tests.component.test_03_idle_clip """ from __future__ import annotations import sys from server.video import VideoConfig, VideoEngine from tests.component._common import ensure_sample_avatar, get_logger, write_bytes log = get_logger("test_03") def run(): avatar_path = ensure_sample_avatar() log.info("Using avatar: %s", avatar_path) cfg = VideoConfig.from_dict( { "enabled": True, "mode": "reflective", # reflective skips the library prebake "resolution": 480, "fps": 16, "library": {"base_clip_count": 0, "base_clip_seconds": 3}, } ) engine = VideoEngine(cfg) log.info("Loading models (Wan2.2 + MuseTalk)...") try: engine.load_models() except Exception as e: log.error("FAIL: load_models raised: %s", e) sys.exit(2) log.info("Models loaded.") log.info("Generating idle clip for avatar...") try: engine.set_avatar(avatar_path) except Exception as e: log.error("FAIL: set_avatar raised: %s", e) sys.exit(3) idle = engine.get_idle_clip() assert idle is not None and len(idle) > 0, "idle clip is empty" assert idle[4:8] == b"ftyp", "idle clip is not a valid MP4" out_path = write_bytes("phase3_idle.mp4", idle) log.info("PASS: idle clip written to %s (%d bytes)", out_path, len(idle)) assert engine.is_ready() is True log.info(" engine.is_ready() = True (avatar + models present)") if __name__ == "__main__": run()