Spaces:
Running
Running
""" | |
راوي (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 ======== | |
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)}"} | |
) | |
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 ======== | |
async def root(): | |
""" | |
Root endpoint for the API | |
""" | |
return { | |
"message": "مرحباً بك في واجهة برمجة تطبيقات راوي", | |
"docs": f"{BASE_URL}/docs", | |
"status": "active" | |
} | |
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 | |
) |