""" Servidor Integrador - Avatar com TTS Porta: 8080 Conecta: - Orpheus TTS: localhost:8880 - Wav2Lip: localhost:8085 """ import asyncio import json import os from aiohttp import web, ClientSession import aiohttp PORT = 8080 WAV2LIP_URL = "http://localhost:8085" TTS_URL = "http://localhost:8880" # HTML da interface HTML_TEMPLATE = """ Avatar Integrado

Avatar Integrado

Avatar
Conectando...

Performance Statistics

Averages (last 10)

Avg Round-Trip --
Avg TTS Time --
Avg Wav2Lip Time --
Last Round-Trip --
Last TTS Time --
Last Wav2Lip Time --
First Frame --
Audio Duration --
Text Length --

Request History

""" async def index(request): """Serve a página principal""" return web.Response(text=HTML_TEMPLATE, content_type='text/html') async def proxy_mjpeg(request): """Proxy para o stream MJPEG do Wav2Lip""" try: async with ClientSession() as session: async with session.get(f"{WAV2LIP_URL}/mjpeg") as resp: if resp.status == 200: response = web.StreamResponse() response.content_type = resp.content_type await response.prepare(request) async for chunk in resp.content.iter_any(): await response.write(chunk) return response except Exception as e: print(f"Erro ao obter vídeo: {e}") return web.Response(status=503, text="Video not available") async def websocket_handler(request): """WebSocket handler que conecta ao Wav2Lip e TTS""" ws_response = web.WebSocketResponse() await ws_response.prepare(request) # Conectar ao WebSocket do Wav2Lip wav2lip_ws = None try: async with ClientSession() as session: async with session.ws_connect(f"{WAV2LIP_URL}/ws") as wav2lip_ws: async def forward_from_wav2lip(): """Encaminha mensagens do Wav2Lip para o cliente""" try: async for msg in wav2lip_ws: if msg.type == aiohttp.WSMsgType.TEXT: await ws_response.send_str(msg.data) elif msg.type == aiohttp.WSMsgType.BINARY: await ws_response.send_bytes(msg.data) elif msg.type == aiohttp.WSMsgType.ERROR: break except Exception as e: print(f"Erro ao encaminhar de Wav2Lip: {e}") async def forward_from_client(): """Encaminha mensagens do cliente para o Wav2Lip""" try: async for msg in ws_response: if msg.type == aiohttp.WSMsgType.TEXT: data = json.loads(msg.data) if data.get('action') == 'speak': # Envia para o Wav2Lip que já integra com TTS await wav2lip_ws.send_str(json.dumps({ 'action': 'speak', 'text': data['text'], 'voice': data.get('voice', 'tara') })) else: await wav2lip_ws.send_str(msg.data) elif msg.type == aiohttp.WSMsgType.ERROR: break except Exception as e: print(f"Erro ao encaminhar do cliente: {e}") # Executar ambos em paralelo await asyncio.gather( forward_from_wav2lip(), forward_from_client() ) except Exception as e: print(f"Erro WebSocket: {e}") await ws_response.send_json({"status": "error", "message": str(e)}) return ws_response async def health(request): """Health check endpoint""" status = { "status": "ok", "services": {} } async with ClientSession() as session: # Check TTS try: async with session.get(f"{TTS_URL}/") as resp: status["services"]["tts"] = resp.status == 200 except: status["services"]["tts"] = False # Check Wav2Lip try: async with session.get(f"{WAV2LIP_URL}/") as resp: status["services"]["wav2lip"] = resp.status == 200 except: status["services"]["wav2lip"] = False return web.json_response(status) def create_app(): app = web.Application() app.router.add_get('/', index) app.router.add_get('/mjpeg', proxy_mjpeg) app.router.add_get('/ws/avatar', websocket_handler) app.router.add_get('/health', health) return app if __name__ == '__main__': print(f"=== Servidor Integrador ===") print(f"Porta: {PORT}") print(f"TTS: {TTS_URL}") print(f"Wav2Lip: {WAV2LIP_URL}") print(f"Acesse: http://localhost:{PORT}") print("=" * 30) app = create_app() web.run_app(app, host='0.0.0.0', port=PORT)