File size: 12,531 Bytes
71e110b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 | #!/usr/bin/env python3
"""
Test script for MuseTalk WebRTC demo mode
Runs headless Chromium and captures metrics
"""
import asyncio
import json
from playwright.async_api import async_playwright
async def run_demo_test(url: str, timeout: int = 120000):
"""Run demo test and return metrics"""
async with async_playwright() as p:
# Launch headless browser
browser = await p.chromium.launch(headless=True)
context = await browser.new_context(
permissions=['microphone']
)
page = await context.new_page()
# Capture console logs
logs = []
page.on('console', lambda msg: logs.append(f"[{msg.type}] {msg.text}"))
print(f"[Test] Opening {url}")
try:
await page.goto(url, timeout=30000)
print("[Test] Page loaded, waiting for demo to complete...")
# Wait for metrics (up to 2 minutes)
try:
await page.wait_for_selector('#demo-metrics-output', timeout=timeout)
print("[Test] Metrics element found!")
metrics = await page.evaluate('() => window.__DEMO_METRICS__')
if metrics:
def fmt(v):
return f"{v:>6}" if v is not None else " N/A "
# MODEL INFORMATION
print("\nπ¦ MODELS USED:")
print("ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ")
print("β Component Model Size β")
print("ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€")
print("β STT Whisper distil-large-v3-ptbr ~1.5 GB β")
print("β LLM google/gemma-3-1b-it ~2.0 GB β")
print("β TTS espeak-ng / ElevenLabs system β")
print("β MuseTalk UNet UNet2DConditionModel 3.4 GB β")
print("β MuseTalk VAE AutoencoderKL (sd-vae) 335 MB β")
print("β Face Detection DWPose 407 MB β")
print("β Face Parser BiSeNet 53 MB β")
print("ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ")
# AVALIAΓΓO PRINCIPAL
ev = metrics.get('evaluation', {})
response_lat = ev.get('responseLatency')
ratio = ev.get('latencyRatio')
grade = ev.get('latencyGrade', 'N/A')
print("\n" + "β" + "β"*60 + "β")
print("β" + " "*10 + "LATΓNCIA DE RESPOSTA" + " "*30 + "β")
print("β" + " "*10 + "(Γ‘udio enviado β resposta comeΓ§a)" + " "*17 + "β")
print("β " + "β"*60 + "β£")
print(f"β" + " "*20 + f">>> {response_lat} ms <<<" + " "*22 + "β")
print("β" + " "*60 + "β")
print(f"β ReferΓͺncia humana: 250 ms" + " "*31 + "β")
print(f"β RazΓ£o: {ratio}x mais lento" + " "*25 + "β")
print(f"β Nota: {grade}" + " "*37 + "β")
print("β" + "β"*60 + "β")
# LatΓͺncias detalhadas - calcular tempos individuais do servidor
lat = metrics.get('latency', {})
sm = metrics.get('serverMetrics', {})
t = sm.get('timings', {}) if sm else {}
# Tempos individuais (nΓ£o acumulados)
stt_time = t.get('stt_done', 0)
llm_time = t.get('llm_done', 0) - t.get('stt_done', 0) if t.get('llm_done') else 0
# TTS separado: espeak vs ElevenLabs
espeak_time = t.get('espeak_done', 0) - t.get('llm_done', 0) if t.get('espeak_done') else 0
tts_time = t.get('tts_done', 0) - t.get('llm_done', 0) if t.get('tts_done') else 0
elevenlabs_time = t.get('elevenlabs_done', 0) - t.get('llm_done', 0) if t.get('elevenlabs_done') else 0
musetalk_first = t.get('first_frame', 0) - t.get('tts_done', 0) if t.get('first_frame') else 0
musetalk_total = t.get('all_done', 0) - t.get('tts_done', 0) if t.get('all_done') else 0
print("\nπ BREAKDOWN DA LATΓNCIA (tempos individuais):")
print(f" 1. STT (Whisper): {stt_time:>6} ms")
print(f" 2. LLM (vLLM/local): {llm_time:>6} ms")
if espeak_time:
print(f" 3. TTS espeak: {espeak_time:>6} ms β usado para vΓdeo")
print(f" TTS ElevenLabs: {elevenlabs_time:>6} ms β paralelo (Γ‘udio final)")
else:
print(f" 3. TTS: {tts_time:>6} ms")
print(f" 4. MuseTalk 1ΒΊFrame: {musetalk_first:>6} ms")
print(f" βββββββββββββββββββββββββββββββββ")
print(f" β LatΓͺncia Resposta: {t.get('first_frame', 0):>6} ms")
print(f" ")
print(f" 5. MuseTalk Total: {musetalk_total:>6} ms")
print(f" βββββββββββββββββββββββββββββββββ")
print(f" Total Pipeline: {t.get('all_done', 0):>6} ms")
# Qualidade
vq = metrics.get('videoQuality', {})
print(f"\nπ¬ QUALIDADE DO VΓDEO:")
print(f" Frames: {vq.get('totalFrames', 0)}/{vq.get('expectedFrames', 0)}")
print(f" Frames perdidos: {vq.get('droppedFrames', 0)} ({vq.get('dropRate', 'N/A')})")
print(f" Travamentos: {vq.get('stutterCount', 0)}")
print(f" Max gap: {vq.get('maxFrameGap', 0)} ms")
print(f" Avg gap: {vq.get('avgFrameGap', 0)} ms")
smooth = "β SIM" if vq.get('isSmooth') else "β NΓO"
print(f" Fluido: {smooth}")
# SincronizaΓ§Γ£o
sync = metrics.get('sync', {})
print(f"\nπ SINCRONIZAΓΓO ΓUDIO/VΓDEO:")
print(f" Offset A/V: {sync.get('audioVideoOffset', 'N/A')} ms")
synced = "β SIM" if sync.get('isSynced') else "β NΓO"
print(f" Sincronizado: {synced}")
# Server metrics
sm = metrics.get('serverMetrics', {})
if sm and sm.get('timings'):
print(f"\nπ₯οΈ SERVIDOR (tempos acumulados):")
t = sm['timings']
stt = t.get('stt_done', 0)
llm = t.get('llm_done', 0)
espeak = t.get('espeak_done', 0)
tts = t.get('tts_done', 0)
elevenlabs = t.get('elevenlabs_done', 0)
first_frame = t.get('first_frame', 0)
all_done = t.get('all_done', 0)
print(f" STT: {stt:>6} ms")
print(f" LLM: {llm:>6} ms (+{llm - stt} ms)")
if espeak:
print(f" espeak: {espeak:>6} ms (+{espeak - llm} ms)")
print(f" TTS ready: {tts:>6} ms (+{tts - espeak} ms)")
else:
print(f" TTS: {tts:>6} ms (+{tts - llm} ms)")
print(f" First Frame: {first_frame:>6} ms")
if elevenlabs:
print(f" ElevenLabs: {elevenlabs:>6} ms (paralelo)")
print(f" Total: {all_done:>6} ms")
# MuseTalk specific timing
if tts and first_frame and all_done:
musetalk_first = first_frame - tts
musetalk_total = all_done - tts
total_frames = vq.get('totalFrames', 0)
print(f"\nπ MUSETALK (UNet2D + VAE inference):")
print(f" Models: UNet2DConditionModel (3.4GB) + AutoencoderKL (335MB)")
print(f" 1ΒΊ Frame: {musetalk_first:>6} ms")
print(f" Total: {musetalk_total:>6} ms")
if total_frames and musetalk_total > 0:
fps = total_frames / (musetalk_total / 1000)
# Calculate realtime factor (assume 25fps output)
audio_duration_sec = total_frames / 25.0
realtime_factor = (musetalk_total / 1000) / audio_duration_sec if audio_duration_sec > 0 else 0
print(f" Frames gerados: {total_frames:>6}")
print(f" Audio duration: {audio_duration_sec:>6.2f} s")
print(f" Gen FPS: {fps:>6.1f} fps")
print(f" Realtime factor: {realtime_factor:>6.2f}x")
# AvaliaΓ§Γ£o MuseTalk
if realtime_factor <= 1.0:
mt_grade = f"A+ ({1/realtime_factor:.1f}x faster than realtime)"
elif fps >= 25:
mt_grade = "A (tempo real)"
elif fps >= 15:
mt_grade = "B (aceitΓ‘vel)"
elif fps >= 10:
mt_grade = "C (lento)"
else:
mt_grade = "F (muito lento)"
print(f" AvaliaΓ§Γ£o: {mt_grade}")
# Resultado final
print("\n" + "="*60)
fluid = metrics.get('conversationFluid', False)
if fluid:
print("β
CONVERSA FLUIDA: SIM")
else:
print("β CONVERSA FLUIDA: NΓO")
if metrics.get('error'):
print(f"β οΈ ERRO: {metrics['error']}")
print("="*60)
# Print full JSON
print("\nπ JSON Completo:")
print(json.dumps(metrics, indent=2))
return metrics
except Exception as e:
print(f"[Test] Timeout: {e}")
metrics = await page.evaluate('() => window.__DEMO_METRICS__ || null')
if metrics:
print("\n[Test] MΓ©tricas parciais:")
print(json.dumps(metrics, indent=2))
return metrics
print("\n[Test] Console logs:")
for log in logs[-30:]:
print(f" {log}")
return {"error": str(e), "logs": logs[-30:]}
except Exception as e:
print(f"[Test] Error: {e}")
return {"error": str(e)}
finally:
await browser.close()
if __name__ == "__main__":
import sys
url = sys.argv[1] if len(sys.argv) > 1 else "http://localhost:3000/?demo=true"
print(f"[Test] Running demo test on: {url}")
result = asyncio.run(run_demo_test(url))
if result and result.get('error'):
sys.exit(1)
|