malek-messaoudii
commited on
Commit
·
8ddb255
1
Parent(s):
8791d59
Update main.py
Browse files
main.py
CHANGED
|
@@ -37,9 +37,9 @@ def cleanup_temp_files():
|
|
| 37 |
if temp_dir.exists():
|
| 38 |
try:
|
| 39 |
shutil.rmtree(temp_dir)
|
| 40 |
-
logger.info("✓
|
| 41 |
except Exception as e:
|
| 42 |
-
logger.warning(f"⚠
|
| 43 |
|
| 44 |
# Appeler au démarrage
|
| 45 |
cleanup_temp_files()
|
|
@@ -51,36 +51,47 @@ def cleanup_on_exit():
|
|
| 51 |
if temp_dir.exists():
|
| 52 |
try:
|
| 53 |
shutil.rmtree(temp_dir)
|
|
|
|
| 54 |
except:
|
| 55 |
-
|
| 56 |
|
| 57 |
# --- Import des singletons de services ---
|
| 58 |
try:
|
| 59 |
from services.stance_model_manager import stance_model_manager
|
| 60 |
-
from services.label_model_manager import kpa_model_manager
|
| 61 |
-
logger.info("✓
|
| 62 |
except ImportError as e:
|
| 63 |
-
logger.warning(f"⚠
|
| 64 |
stance_model_manager = None
|
| 65 |
kpa_model_manager = None
|
| 66 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 67 |
# --- Lifespan / startup API ---
|
| 68 |
@asynccontextmanager
|
| 69 |
async def lifespan(app: FastAPI):
|
| 70 |
logger.info("="*60)
|
| 71 |
-
logger.info("🚀 API
|
| 72 |
logger.info("="*60)
|
| 73 |
|
| 74 |
# Vérifier les clés API
|
| 75 |
if not GROQ_API_KEY:
|
| 76 |
-
logger.warning("⚠ GROQ_API_KEY
|
| 77 |
else:
|
| 78 |
-
logger.info("✓ GROQ_API_KEY
|
| 79 |
|
| 80 |
if not HUGGINGFACE_API_KEY:
|
| 81 |
-
logger.warning("⚠ HUGGINGFACE_API_KEY
|
| 82 |
else:
|
| 83 |
-
logger.info("✓ HUGGINGFACE_API_KEY
|
| 84 |
|
| 85 |
# Précharger les modèles Hugging Face si configuré
|
| 86 |
if PRELOAD_MODELS_ON_STARTUP:
|
|
@@ -89,28 +100,37 @@ async def lifespan(app: FastAPI):
|
|
| 89 |
if LOAD_STANCE_MODEL and stance_model_manager and HUGGINGFACE_STANCE_MODEL_ID:
|
| 90 |
try:
|
| 91 |
stance_model_manager.load_model(HUGGINGFACE_STANCE_MODEL_ID, HUGGINGFACE_API_KEY)
|
| 92 |
-
logger.info("✓
|
| 93 |
except Exception as e:
|
| 94 |
-
logger.error(f"✗
|
| 95 |
|
| 96 |
# Charger KPA model
|
| 97 |
if LOAD_KPA_MODEL and kpa_model_manager and HUGGINGFACE_LABEL_MODEL_ID:
|
| 98 |
try:
|
| 99 |
kpa_model_manager.load_model(HUGGINGFACE_LABEL_MODEL_ID, HUGGINGFACE_API_KEY)
|
| 100 |
-
logger.info("✓ KPA
|
| 101 |
except Exception as e:
|
| 102 |
-
logger.error(f"✗
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 103 |
|
| 104 |
logger.info("="*60)
|
| 105 |
-
logger.info("✓
|
| 106 |
logger.info(f" STT Model: {GROQ_STT_MODEL}")
|
| 107 |
logger.info(f" TTS Model: {GROQ_TTS_MODEL}")
|
| 108 |
logger.info(f" Chat Model: {GROQ_CHAT_MODEL}")
|
|
|
|
| 109 |
logger.info("="*60)
|
| 110 |
|
| 111 |
yield
|
| 112 |
|
| 113 |
-
logger.info("🛑
|
| 114 |
# Nettoyage final
|
| 115 |
cleanup_on_exit()
|
| 116 |
|
|
@@ -139,64 +159,47 @@ app.add_middleware(
|
|
| 139 |
try:
|
| 140 |
from routes.stt_routes import router as stt_router
|
| 141 |
app.include_router(stt_router, prefix="/api/v1/stt", tags=["Speech To Text"])
|
| 142 |
-
logger.info("✓ STT
|
| 143 |
except ImportError as e:
|
| 144 |
-
logger.warning(f"⚠ STT
|
| 145 |
except Exception as e:
|
| 146 |
-
logger.warning(f"⚠
|
| 147 |
|
| 148 |
# TTS Routes
|
| 149 |
try:
|
| 150 |
from routes.tts_routes import router as tts_router
|
| 151 |
app.include_router(tts_router, prefix="/api/v1/tts", tags=["Text To Speech"])
|
| 152 |
-
logger.info("✓ TTS
|
| 153 |
except ImportError as e:
|
| 154 |
-
logger.warning(f"⚠ TTS
|
| 155 |
except Exception as e:
|
| 156 |
-
logger.warning(f"⚠
|
| 157 |
|
| 158 |
-
#
|
| 159 |
-
try:
|
| 160 |
-
from routes import api_router
|
| 161 |
-
app.include_router(api_router)
|
| 162 |
-
logger.info("✓ Main API routes loaded")
|
| 163 |
-
except ImportError as e:
|
| 164 |
-
logger.warning(f"⚠ Main API routes not found: {e}")
|
| 165 |
-
except Exception as e:
|
| 166 |
-
logger.warning(f"⚠ Failed loading main API routes: {e}")
|
| 167 |
-
|
| 168 |
-
# Dans main.py, après les autres routes
|
| 169 |
try:
|
| 170 |
from routes.voice_chat_routes import router as voice_chat_router
|
| 171 |
app.include_router(voice_chat_router, tags=["Voice Chat"])
|
| 172 |
-
logger.info("✓ Voice Chat
|
| 173 |
except ImportError as e:
|
| 174 |
-
logger.warning(f"⚠ Voice Chat
|
| 175 |
except Exception as e:
|
| 176 |
-
logger.warning(f"⚠
|
| 177 |
|
| 178 |
-
#
|
| 179 |
try:
|
| 180 |
-
from
|
| 181 |
-
|
| 182 |
-
|
| 183 |
except ImportError as e:
|
| 184 |
-
logger.warning(f"⚠
|
| 185 |
-
|
|
|
|
| 186 |
|
| 187 |
-
#
|
| 188 |
if MCP_ENABLED:
|
| 189 |
-
|
| 190 |
-
|
| 191 |
-
logger.info("✓ MCP Server initialized")
|
| 192 |
-
except Exception as e:
|
| 193 |
-
logger.error(f"✗ MCP initialization failed: {e}")
|
| 194 |
|
| 195 |
-
# Après les autres routes, ajoutez
|
| 196 |
-
if MCP_ENABLED:
|
| 197 |
-
app.include_router(mcp_router)
|
| 198 |
-
logger.info("✓ MCP routes loaded")
|
| 199 |
-
|
| 200 |
# --- Basic routes ---
|
| 201 |
@app.get("/health", tags=["Health"])
|
| 202 |
async def health():
|
|
@@ -204,12 +207,17 @@ async def health():
|
|
| 204 |
health_status = {
|
| 205 |
"status": "healthy",
|
| 206 |
"service": "NLP Debater + Groq Voice",
|
|
|
|
| 207 |
"features": {
|
| 208 |
"stt": GROQ_STT_MODEL if GROQ_API_KEY else "disabled",
|
| 209 |
"tts": GROQ_TTS_MODEL if GROQ_API_KEY else "disabled",
|
| 210 |
"chat": GROQ_CHAT_MODEL if GROQ_API_KEY else "disabled",
|
| 211 |
-
"stance_model": "loaded" if (stance_model_manager and stance_model_manager
|
| 212 |
-
"kpa_model": "loaded" if (kpa_model_manager and kpa_model_manager
|
|
|
|
|
|
|
|
|
|
|
|
|
| 213 |
}
|
| 214 |
}
|
| 215 |
return health_status
|
|
@@ -217,42 +225,64 @@ async def health():
|
|
| 217 |
@app.get("/", tags=["Root"])
|
| 218 |
async def root():
|
| 219 |
"""Root endpoint with API information"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 220 |
return {
|
| 221 |
-
"message": "NLP Debater API
|
| 222 |
"version": API_VERSION,
|
| 223 |
-
"endpoints":
|
| 224 |
-
"docs": "/docs",
|
| 225 |
-
"redoc": "/redoc",
|
| 226 |
-
"health": "/health",
|
| 227 |
-
"stt": "/api/v1/stt/",
|
| 228 |
-
"tts": "/api/v1/tts/"
|
| 229 |
-
},
|
| 230 |
"models": {
|
| 231 |
-
"stt": GROQ_STT_MODEL,
|
| 232 |
-
"tts": GROQ_TTS_MODEL,
|
| 233 |
-
"chat": GROQ_CHAT_MODEL
|
|
|
|
| 234 |
}
|
| 235 |
}
|
| 236 |
|
| 237 |
# --- Error handlers ---
|
| 238 |
@app.exception_handler(404)
|
| 239 |
async def not_found_handler(request, exc):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 240 |
return {
|
| 241 |
"error": "Not Found",
|
| 242 |
-
"message": f"
|
| 243 |
-
"available_endpoints":
|
| 244 |
-
"GET /": "API information",
|
| 245 |
-
"GET /health": "Health check",
|
| 246 |
-
"POST /api/v1/stt/": "Speech to text",
|
| 247 |
-
"POST /api/v1/tts/": "Text to speech"
|
| 248 |
-
}
|
| 249 |
}
|
| 250 |
|
| 251 |
# --- Run server ---
|
| 252 |
if __name__ == "__main__":
|
| 253 |
logger.info("="*60)
|
| 254 |
-
logger.info(f"
|
| 255 |
-
logger.info(f"
|
| 256 |
logger.info("="*60)
|
| 257 |
|
| 258 |
uvicorn.run(
|
|
|
|
| 37 |
if temp_dir.exists():
|
| 38 |
try:
|
| 39 |
shutil.rmtree(temp_dir)
|
| 40 |
+
logger.info("✓ Fichiers temporaires audio nettoyés")
|
| 41 |
except Exception as e:
|
| 42 |
+
logger.warning(f"⚠ Impossible de nettoyer le répertoire temporaire: {e}")
|
| 43 |
|
| 44 |
# Appeler au démarrage
|
| 45 |
cleanup_temp_files()
|
|
|
|
| 51 |
if temp_dir.exists():
|
| 52 |
try:
|
| 53 |
shutil.rmtree(temp_dir)
|
| 54 |
+
logger.info("Nettoyage final des fichiers temporaires")
|
| 55 |
except:
|
| 56 |
+
logger.warning("Échec du nettoyage final")
|
| 57 |
|
| 58 |
# --- Import des singletons de services ---
|
| 59 |
try:
|
| 60 |
from services.stance_model_manager import stance_model_manager
|
| 61 |
+
from services.label_model_manager import kpa_model_manager # Corrigé: kpa_model_manager, pas label_model_manager
|
| 62 |
+
logger.info("✓ Gestionnaires de modèles importés")
|
| 63 |
except ImportError as e:
|
| 64 |
+
logger.warning(f"⚠ Impossible d'importer les gestionnaires de modèles: {e}")
|
| 65 |
stance_model_manager = None
|
| 66 |
kpa_model_manager = None
|
| 67 |
|
| 68 |
+
# --- Vérification MCP ---
|
| 69 |
+
try:
|
| 70 |
+
from services.mcp_service import init_mcp_server
|
| 71 |
+
from routes.mcp_routes import router as mcp_router
|
| 72 |
+
MCP_ENABLED = True
|
| 73 |
+
logger.info("✓ Modules MCP détectés")
|
| 74 |
+
except ImportError as e:
|
| 75 |
+
logger.warning(f"⚠ MCP non disponible: {e}")
|
| 76 |
+
MCP_ENABLED = False
|
| 77 |
+
|
| 78 |
# --- Lifespan / startup API ---
|
| 79 |
@asynccontextmanager
|
| 80 |
async def lifespan(app: FastAPI):
|
| 81 |
logger.info("="*60)
|
| 82 |
+
logger.info("🚀 DÉMARRAGE API - Chargement des modèles et vérification des APIs...")
|
| 83 |
logger.info("="*60)
|
| 84 |
|
| 85 |
# Vérifier les clés API
|
| 86 |
if not GROQ_API_KEY:
|
| 87 |
+
logger.warning("⚠ GROQ_API_KEY non configurée. Fonctions STT/TTS désactivées.")
|
| 88 |
else:
|
| 89 |
+
logger.info("✓ GROQ_API_KEY configurée")
|
| 90 |
|
| 91 |
if not HUGGINGFACE_API_KEY:
|
| 92 |
+
logger.warning("⚠ HUGGINGFACE_API_KEY non configurée. Modèles locaux désactivés.")
|
| 93 |
else:
|
| 94 |
+
logger.info("✓ HUGGINGFACE_API_KEY configurée")
|
| 95 |
|
| 96 |
# Précharger les modèles Hugging Face si configuré
|
| 97 |
if PRELOAD_MODELS_ON_STARTUP:
|
|
|
|
| 100 |
if LOAD_STANCE_MODEL and stance_model_manager and HUGGINGFACE_STANCE_MODEL_ID:
|
| 101 |
try:
|
| 102 |
stance_model_manager.load_model(HUGGINGFACE_STANCE_MODEL_ID, HUGGINGFACE_API_KEY)
|
| 103 |
+
logger.info("✓ Modèle de détection de stance chargé")
|
| 104 |
except Exception as e:
|
| 105 |
+
logger.error(f"✗ Échec chargement modèle stance: {e}")
|
| 106 |
|
| 107 |
# Charger KPA model
|
| 108 |
if LOAD_KPA_MODEL and kpa_model_manager and HUGGINGFACE_LABEL_MODEL_ID:
|
| 109 |
try:
|
| 110 |
kpa_model_manager.load_model(HUGGINGFACE_LABEL_MODEL_ID, HUGGINGFACE_API_KEY)
|
| 111 |
+
logger.info("✓ Modèle KPA chargé")
|
| 112 |
except Exception as e:
|
| 113 |
+
logger.error(f"✗ Échec chargement modèle KPA: {e}")
|
| 114 |
+
|
| 115 |
+
# Initialiser MCP si disponible
|
| 116 |
+
if MCP_ENABLED:
|
| 117 |
+
try:
|
| 118 |
+
init_mcp_server(app)
|
| 119 |
+
logger.info("✓ Serveur MCP initialisé")
|
| 120 |
+
except Exception as e:
|
| 121 |
+
logger.error(f"✗ Échec initialisation MCP: {e}")
|
| 122 |
|
| 123 |
logger.info("="*60)
|
| 124 |
+
logger.info("✓ Démarrage terminé. API prête à recevoir des requêtes.")
|
| 125 |
logger.info(f" STT Model: {GROQ_STT_MODEL}")
|
| 126 |
logger.info(f" TTS Model: {GROQ_TTS_MODEL}")
|
| 127 |
logger.info(f" Chat Model: {GROQ_CHAT_MODEL}")
|
| 128 |
+
logger.info(f" MCP: {'Activé' if MCP_ENABLED else 'Désactivé'}")
|
| 129 |
logger.info("="*60)
|
| 130 |
|
| 131 |
yield
|
| 132 |
|
| 133 |
+
logger.info("🛑 Arrêt de l'API...")
|
| 134 |
# Nettoyage final
|
| 135 |
cleanup_on_exit()
|
| 136 |
|
|
|
|
| 159 |
try:
|
| 160 |
from routes.stt_routes import router as stt_router
|
| 161 |
app.include_router(stt_router, prefix="/api/v1/stt", tags=["Speech To Text"])
|
| 162 |
+
logger.info("✓ Route STT chargée (Groq Whisper)")
|
| 163 |
except ImportError as e:
|
| 164 |
+
logger.warning(f"⚠ Route STT non trouvée: {e}")
|
| 165 |
except Exception as e:
|
| 166 |
+
logger.warning(f"⚠ Échec chargement route STT: {e}")
|
| 167 |
|
| 168 |
# TTS Routes
|
| 169 |
try:
|
| 170 |
from routes.tts_routes import router as tts_router
|
| 171 |
app.include_router(tts_router, prefix="/api/v1/tts", tags=["Text To Speech"])
|
| 172 |
+
logger.info("✓ Route TTS chargée (Groq PlayAI TTS)")
|
| 173 |
except ImportError as e:
|
| 174 |
+
logger.warning(f"⚠ Route TTS non trouvée: {e}")
|
| 175 |
except Exception as e:
|
| 176 |
+
logger.warning(f"⚠ Échec chargement route TTS: {e}")
|
| 177 |
|
| 178 |
+
# Voice Chat Routes
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 179 |
try:
|
| 180 |
from routes.voice_chat_routes import router as voice_chat_router
|
| 181 |
app.include_router(voice_chat_router, tags=["Voice Chat"])
|
| 182 |
+
logger.info("✓ Route Voice Chat chargée")
|
| 183 |
except ImportError as e:
|
| 184 |
+
logger.warning(f"⚠ Route Voice Chat non trouvée: {e}")
|
| 185 |
except Exception as e:
|
| 186 |
+
logger.warning(f"⚠ Échec chargement route Voice Chat: {e}")
|
| 187 |
|
| 188 |
+
# Main API Routes (KPA, Stance, etc.)
|
| 189 |
try:
|
| 190 |
+
from routes import api_router
|
| 191 |
+
app.include_router(api_router)
|
| 192 |
+
logger.info("✓ Routes API principales chargées")
|
| 193 |
except ImportError as e:
|
| 194 |
+
logger.warning(f"⚠ Routes API principales non trouvées: {e}")
|
| 195 |
+
except Exception as e:
|
| 196 |
+
logger.warning(f"⚠ Échec chargement routes API principales: {e}")
|
| 197 |
|
| 198 |
+
# MCP Routes
|
| 199 |
if MCP_ENABLED:
|
| 200 |
+
app.include_router(mcp_router, prefix="/api/v1", tags=["MCP"])
|
| 201 |
+
logger.info("✓ Routes MCP chargées")
|
|
|
|
|
|
|
|
|
|
| 202 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 203 |
# --- Basic routes ---
|
| 204 |
@app.get("/health", tags=["Health"])
|
| 205 |
async def health():
|
|
|
|
| 207 |
health_status = {
|
| 208 |
"status": "healthy",
|
| 209 |
"service": "NLP Debater + Groq Voice",
|
| 210 |
+
"version": API_VERSION,
|
| 211 |
"features": {
|
| 212 |
"stt": GROQ_STT_MODEL if GROQ_API_KEY else "disabled",
|
| 213 |
"tts": GROQ_TTS_MODEL if GROQ_API_KEY else "disabled",
|
| 214 |
"chat": GROQ_CHAT_MODEL if GROQ_API_KEY else "disabled",
|
| 215 |
+
"stance_model": "loaded" if (stance_model_manager and hasattr(stance_model_manager, 'model_loaded') and stance_model_manager.model_loaded) else "not loaded",
|
| 216 |
+
"kpa_model": "loaded" if (kpa_model_manager and hasattr(kpa_model_manager, 'model_loaded') and kpa_model_manager.model_loaded) else "not loaded",
|
| 217 |
+
"mcp": "enabled" if MCP_ENABLED else "disabled"
|
| 218 |
+
},
|
| 219 |
+
"endpoints": {
|
| 220 |
+
"mcp": "/api/v1/mcp" if MCP_ENABLED else "disabled"
|
| 221 |
}
|
| 222 |
}
|
| 223 |
return health_status
|
|
|
|
| 225 |
@app.get("/", tags=["Root"])
|
| 226 |
async def root():
|
| 227 |
"""Root endpoint with API information"""
|
| 228 |
+
endpoints = {
|
| 229 |
+
"docs": "/docs",
|
| 230 |
+
"redoc": "/redoc",
|
| 231 |
+
"health": "/health",
|
| 232 |
+
"stt": "/api/v1/stt/",
|
| 233 |
+
"tts": "/api/v1/tts/",
|
| 234 |
+
"voice_chat": "/voice-chat/voice",
|
| 235 |
+
}
|
| 236 |
+
|
| 237 |
+
if MCP_ENABLED:
|
| 238 |
+
endpoints["mcp"] = {
|
| 239 |
+
"health": "/api/v1/mcp/health",
|
| 240 |
+
"tools": "/api/v1/mcp/tools",
|
| 241 |
+
"resources": "/api/v1/mcp/resources",
|
| 242 |
+
"call_tool": "/api/v1/mcp/tools/call"
|
| 243 |
+
}
|
| 244 |
+
|
| 245 |
return {
|
| 246 |
+
"message": "NLP Debater API avec support vocal Groq et MCP",
|
| 247 |
"version": API_VERSION,
|
| 248 |
+
"endpoints": endpoints,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 249 |
"models": {
|
| 250 |
+
"stt": GROQ_STT_MODEL if GROQ_API_KEY else "disabled",
|
| 251 |
+
"tts": GROQ_TTS_MODEL if GROQ_API_KEY else "disabled",
|
| 252 |
+
"chat": GROQ_CHAT_MODEL if GROQ_API_KEY else "disabled",
|
| 253 |
+
"mcp": "enabled" if MCP_ENABLED else "disabled"
|
| 254 |
}
|
| 255 |
}
|
| 256 |
|
| 257 |
# --- Error handlers ---
|
| 258 |
@app.exception_handler(404)
|
| 259 |
async def not_found_handler(request, exc):
|
| 260 |
+
endpoints = {
|
| 261 |
+
"GET /": "Informations API",
|
| 262 |
+
"GET /health": "Health check",
|
| 263 |
+
"POST /api/v1/stt/": "Speech to text",
|
| 264 |
+
"POST /api/v1/tts/": "Text to speech",
|
| 265 |
+
"POST /voice-chat/voice": "Voice chat"
|
| 266 |
+
}
|
| 267 |
+
|
| 268 |
+
if MCP_ENABLED:
|
| 269 |
+
endpoints.update({
|
| 270 |
+
"GET /api/v1/mcp/health": "Health check MCP",
|
| 271 |
+
"GET /api/v1/mcp/tools": "Liste outils MCP",
|
| 272 |
+
"POST /api/v1/mcp/tools/call": "Appel d'outil MCP"
|
| 273 |
+
})
|
| 274 |
+
|
| 275 |
return {
|
| 276 |
"error": "Not Found",
|
| 277 |
+
"message": f"URL {request.url} non trouvée",
|
| 278 |
+
"available_endpoints": endpoints
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 279 |
}
|
| 280 |
|
| 281 |
# --- Run server ---
|
| 282 |
if __name__ == "__main__":
|
| 283 |
logger.info("="*60)
|
| 284 |
+
logger.info(f"Démarrage du serveur sur {HOST}:{PORT}")
|
| 285 |
+
logger.info(f"Mode reload: {RELOAD}")
|
| 286 |
logger.info("="*60)
|
| 287 |
|
| 288 |
uvicorn.run(
|