from fastapi import FastAPI, HTTPException from fastapi.staticfiles import StaticFiles from fastapi.middleware.cors import CORSMiddleware import os from dotenv import load_dotenv from huggingface_hub import hf_hub_download import json from datetime import datetime, timedelta import aiofiles import aiofiles.os # Load environment variables load_dotenv() # API configuration API_HOST = os.getenv("API_HOST", "0.0.0.0") API_PORT = int(os.getenv("API_PORT", "3002")) HUGGING_FACE_HUB_TOKEN = os.getenv("HUGGING_FACE_HUB_TOKEN") HUGGING_FACE_STORAGE_REPO = os.getenv("HUGGING_FACE_STORAGE_REPO") CACHE_DIR = "cache" CACHE_DURATION = timedelta(seconds=10) app = FastAPI() # Enable CORS app.add_middleware( CORSMiddleware, allow_origins=["*"], # En production, remplacer par les domaines autorisés allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # Ensure cache directory exists os.makedirs(CACHE_DIR, exist_ok=True) async def get_cached_data(): cache_file = os.path.join(CACHE_DIR, "leaderboards_cache.json") cache_meta_file = os.path.join(CACHE_DIR, "cache_metadata.json") try: if await aiofiles.os.path.exists(cache_meta_file): async with aiofiles.open(cache_meta_file, 'r') as f: metadata = json.loads(await f.read()) cache_time = datetime.fromisoformat(metadata['timestamp']) if datetime.now() - cache_time < CACHE_DURATION: async with aiofiles.open(cache_file, 'r') as f: return json.loads(await f.read()) except Exception as e: print(f"Error reading cache: {e}") return None async def update_cache(data): try: async with aiofiles.open(os.path.join(CACHE_DIR, "leaderboards_cache.json"), 'w') as f: await f.write(json.dumps(data)) async with aiofiles.open(os.path.join(CACHE_DIR, "cache_metadata.json"), 'w') as f: await f.write(json.dumps({'timestamp': datetime.now().isoformat()})) except Exception as e: print(f"Error updating cache: {e}") @app.get("/api/leaderboards") async def get_leaderboards(): try: # Check cache first cached_data = await get_cached_data() if cached_data: return cached_data # If no cache or expired, download from HF file_path = hf_hub_download( repo_id=HUGGING_FACE_STORAGE_REPO, filename="final_leaderboards.json", token=HUGGING_FACE_HUB_TOKEN, repo_type="dataset" ) with open(file_path, 'r') as f: data = json.load(f) # Update cache await update_cache(data) return data except Exception as e: raise HTTPException(status_code=500, detail=f"Failed to fetch leaderboards: {str(e)}") # Mount static files for the React client app.mount("/", StaticFiles(directory="static", html=True), name="static") def start(): """Entry point for the Poetry script""" import uvicorn uvicorn.run("server:app", host=API_HOST, port=API_PORT, reload=True) if __name__ == "__main__": start()