import os import subprocess import sys import logging from logging.handlers import RotatingFileHandler from datetime import datetime import threading import time # ─────────────── UTF-8 Windows ─────────────── if os.name == 'nt': import ctypes ctypes.windll.kernel32.SetConsoleCP(65001) ctypes.windll.kernel32.SetConsoleOutputCP(65001) # ─────────────── Répertoires de logs ─────────────── BASE_DIR = os.path.dirname(os.path.abspath(__file__)) LOG_DIR = os.path.join(BASE_DIR, "logs") os.makedirs(LOG_DIR, exist_ok=True) # ─────────────── Logger central ─────────────── central_logger = logging.getLogger("Holokia") central_logger.setLevel(logging.INFO) console_handler = logging.StreamHandler(sys.stdout) console_handler.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")) central_file_handler = RotatingFileHandler( os.path.join(LOG_DIR, "holokia.log"), maxBytes=5*1024*1024, backupCount=5, encoding="utf-8" ) central_file_handler.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")) central_logger.addHandler(console_handler) central_logger.addHandler(central_file_handler) central_logger.info("🚀 Démarrage de tous les services Holokia Avatar") central_logger.info(f"📅 Date: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") # ─────────────── Services ─────────────── SERVICES = { "TTS": {"script": "services/tts_service.py", "port": 5000, "prefix": "[TTS]"}, "STT": {"script": "services/stt_service.py", "port": 5001, "prefix": "[STT]"}, "LLM": {"script": "services/llm_service.py", "port": 5002, "prefix": "[LLM]"}, "LiveStream": {"script": "services/live_stream_service.py", "port": 5003, "prefix": "[Live]"}, # "Backend": {"script": os.path.join(BASE_DIR, "app/main.py"), "port": int(os.getenv("PORT", 8000)), "prefix": "[Backend]"} } processes = {} # ─────────────── Fonction pour créer un logger par service ─────────────── def create_service_logger(name): logger = logging.getLogger(name) logger.setLevel(logging.INFO) file_handler = RotatingFileHandler( os.path.join(LOG_DIR, f"{name}.log"), maxBytes=5*1024*1024, backupCount=3, encoding="utf-8" ) file_handler.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")) # Eviter d'ajouter plusieurs handlers si déjà créé if not logger.handlers: logger.addHandler(console_handler) logger.addHandler(file_handler) return logger # ─────────────── Démarrer un service ─────────────── def start_service(name, info): prefix = info["prefix"] port = info["port"] script = info["script"] service_logger = create_service_logger(name) # Ajuster PYTHONPATH #env = os.environ.copy() #env["PYTHONPATH"] = f"{BASE_DIR};{os.path.dirname(script)};{env.get('PYTHONPATH','')}" service_logger.info(f"{prefix} 🚀 Démarrage du service sur le port {port} ...") proc = subprocess.Popen( [sys.executable, script], stdout=sys.stdout, stderr=sys.stderr, bufsize=1, universal_newlines=True, #env=env ) # Les logs des services apparaîtront directement dans stdout return proc # ─────────────── Lancement de tous les services ─────────────── for name, info in SERVICES.items(): proc = start_service(name, info) processes[name] = proc central_logger.info("⚙️ Tous les services ont été lancés. Ctrl+C pour arrêter.") # ─────────────── Boucle de surveillance ─────────────── try: while True: for name, proc in list(processes.items()): ret = proc.poll() if ret is not None: central_logger.error(f"{SERVICES[name]['prefix']} ❌ Service arrêté ! Code: {ret}") proc_new = start_service(name, SERVICES[name]) processes[name] = proc_new time.sleep(2) except KeyboardInterrupt: central_logger.info("⏹ Arrêt de tous les services...") for name, proc in processes.items(): proc.terminate() central_logger.info("✅ Tous les services ont été arrêtés.")