""" راوي (Rawi) - Arabic AI Storytelling Platform Main application file for FastAPI server """ import os import sys import uvicorn import logging import traceback from fastapi import FastAPI, HTTPException, Request from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import JSONResponse from fastapi.exception_handlers import http_exception_handler from starlette import status from dotenv import load_dotenv from fastapi.responses import FileResponse from fastapi.staticfiles import StaticFiles from pathlib import Path # Add the current directory to Python path to enable imports sys.path.append(os.path.dirname(os.path.abspath(__file__))) # Import application routers from routers import story # ======== Configure Logging ======== logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) # ======== Load Environment Variables ======== load_dotenv() # ======== Server Configuration ======== HOST = os.getenv("BACKEND_HOST", "0.0.0.0") PORT = int(os.getenv("BACKEND_PORT", "7860")) # Default port for Hugging Face Spaces BASE_URL = os.getenv("BASE_URL", f"http://{HOST}:{PORT}") # For Hugging Face Spaces, use a directory we know has write permissions if os.path.exists("/code"): # Check if we're in Hugging Face Spaces environment AUDIO_STORAGE_PATH = os.path.abspath("/tmp/audio_files") else: AUDIO_STORAGE_PATH = os.path.abspath(os.getenv("AUDIO_STORAGE_PATH", "./audio_files")) # DeepSeek API Key check DEEPSEEK_API_KEY = os.getenv("DEEPSEEK_API_KEY") # Log server settings logger.info(f"Server settings:") logger.info(f"Host: {HOST}") logger.info(f"Port: {PORT}") logger.info(f"Base URL: {BASE_URL}") logger.info(f"Audio storage path: {AUDIO_STORAGE_PATH}") logger.info(f"DeepSeek API Key set: {bool(DEEPSEEK_API_KEY)}") # ======== Ensure Audio Storage Directory Exists ======== try: Path(AUDIO_STORAGE_PATH).mkdir(parents=True, exist_ok=True) logger.info(f"Created/verified audio storage directory at: {AUDIO_STORAGE_PATH}") except Exception as e: logger.error(f"Error creating audio storage directory: {str(e)}") raise # ======== Initialize FastAPI Application ======== app = FastAPI( title="راوي API", description="واجهة برمجة تطبيقات لمنصة راوي لتوليد القصص العربية باستخدام الذكاء الاصطناعي", version="1.0.0" ) # ======== Exception Handlers ======== @app.exception_handler(Exception) async def global_exception_handler(request: Request, exc: Exception): """ Global exception handler for unhandled exceptions """ logger.error(f"Unhandled exception: {str(exc)}") logger.error(traceback.format_exc()) return JSONResponse( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content={"detail": f"حدث خطأ داخلي في الخادم: {str(exc)}"} ) @app.exception_handler(HTTPException) async def custom_http_exception_handler(request: Request, exc: HTTPException): """ Custom HTTP exception handler """ logger.warning(f"HTTP exception: {exc.status_code} - {exc.detail}") return await http_exception_handler(request, exc) # ======== Configure CORS ======== app.add_middleware( CORSMiddleware, allow_origins=["*"], # Allow all origins for Hugging Face Space allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # ======== Mount Static Files ======== app.mount("/audio", StaticFiles(directory=AUDIO_STORAGE_PATH), name="audio") # ======== Register Routers ======== app.include_router(story.router, prefix="/api/stories", tags=["قصص"]) # ======== API Endpoints ======== @app.get("/", tags=["الرئيسية"]) async def root(): """ Root endpoint for the API """ return { "message": "مرحباً بك في واجهة برمجة تطبيقات راوي", "docs": f"{BASE_URL}/docs", "status": "active" } @app.get("/health", tags=["الحالة"]) async def health_check(): """ Health check endpoint to verify API configuration """ health_status = { "status": "healthy", "deepseek_api": bool(DEEPSEEK_API_KEY), "audio_storage": os.path.exists(AUDIO_STORAGE_PATH), } if not DEEPSEEK_API_KEY: health_status["status"] = "degraded" health_status["message"] = "DeepSeek API key is not set. Story generation will not work." return health_status # ======== Run Application ======== if __name__ == "__main__": uvicorn.run( "main:app", host=HOST, port=PORT, reload=False # Disable in production for better performance )