import logging from fastapi import FastAPI, Request, Depends from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import JSONResponse from starlette import status from app.utils.config import settings from app.utils.security import get_current_user_optional from app.routers import users, chat, audio, images from app.routers import cameroon_data from app.routers import ai def create_app() -> FastAPI: # Configure logging settings.configure_logging() logger = logging.getLogger(__name__) app = FastAPI( title="Carehelp API", description="Backend IA médical pour le Cameroun (Carehelp)", version="1.0.0", contact={ "name": "Carehelp", }, ) app.add_middleware( CORSMiddleware, allow_origins=settings.CORS_ALLOW_ORIGINS, allow_credentials=True, allow_methods=["*"] , allow_headers=["*"] , ) # Routers app.include_router(users.router, prefix="/api", tags=["users"]) app.include_router(chat.router, prefix="/api", tags=["chat"]) app.include_router(audio.router, prefix="/api", tags=["audio"]) app.include_router(images.router, prefix="/api", tags=["images"]) app.include_router(cameroon_data.router, prefix="/api/cameroon-data", tags=["cameroon-data"]) app.include_router(ai.router, prefix="/api", tags=["ai"]) # Log all registered routes for debugging try: route_paths = sorted([getattr(r, 'path', str(r)) for r in app.routes]) logging.getLogger(__name__).info(f"Registered routes: {route_paths}") except Exception as e: logging.getLogger(__name__).error(f"Failed to list routes: {e}") @app.get("/health") def healthcheck(): return {"status": "ok"} # Debug: return list of routes @app.get("/routes") def list_routes(): return {"routes": [ { "path": getattr(r, 'path', str(r)), "name": getattr(r, 'name', None), "methods": list(getattr(r, 'methods', []) or []) } for r in app.routes ]} # No database initialization; Supabase will manage schema @app.post("/gateway") async def gateway(request: Request, current_user=Depends(get_current_user_optional)): """ Endpoint unique pour le frontend. - Mode actions: {"action": "chat|transcribe|analyze-image|analyze-multimodal|translate", "payload": {...}} - Mode unifié (recommandé): {"payload": {text?, image?, images?, audio?, audios?, files?, file_names?, location?, want_stats?, agent_mode?}} Si "action" est omis ou vaut l'un de {"auto", "unified", "ai"}, la requête est routée automatiquement selon les champs fournis. """ body = await request.json() action = body.get("action") payload = body.get("payload", {}) # Mode unifié: pas d'action explicitement fournie ou action spéciale if not action or str(action).lower() in {"auto", "unified", "ai"}: try: req = ai.AIRequest( text=payload.get("text"), image=payload.get("image"), images=payload.get("images"), audio=payload.get("audio"), audios=payload.get("audios"), want_stats=payload.get("want_stats", False), location=payload.get("location"), files=payload.get("files"), file_names=payload.get("file_names"), agent_mode=payload.get("agent_mode"), ) except Exception as e: return JSONResponse(status_code=status.HTTP_400_BAD_REQUEST, content={"detail": f"Payload invalide pour le mode unifié: {e}"}) # Déléguer au point d'entrée IA unifié (gère texte, image(s), audio(s), fichiers) return await ai.ai_endpoint(req) # Proxifier vers les endpoints internes if action == "chat": return await chat.handle_chat_via_gateway(payload, current_user) if action == "transcribe": return await audio.handle_transcription_via_gateway(payload, current_user) if action == "analyze-image": return await images.handle_analyze_image_via_gateway(payload, current_user) if action == "analyze-multimodal": return await images.handle_analyze_multimodal_via_gateway(payload, current_user) if action == "translate": return await chat.handle_translate_via_gateway(payload, current_user) return JSONResponse( status_code=status.HTTP_400_BAD_REQUEST, content={"detail": "Action inconnue"}, ) return app app = create_app() if __name__ == "__main__": import uvicorn uvicorn.run("main:app", host="0.0.0.0", port=int(settings.PORT), reload=True)