Spaces:
Running
Running
add webhook to fetch data properly
Browse files- server/.env.example +1 -1
- server/server.py +60 -13
server/.env.example
CHANGED
|
@@ -4,7 +4,7 @@ HUGGING_FACE_HUB_TOKEN=your_token_here
|
|
| 4 |
|
| 5 |
# Repository ID for storing leaderboard data (required)
|
| 6 |
# Format: username/repo-name
|
| 7 |
-
HUGGING_FACE_STORAGE_REPO=
|
| 8 |
|
| 9 |
# File path in the repository (required)
|
| 10 |
HUGGING_FACE_STORAGE_FILE_PATH=final_leaderboards.json
|
|
|
|
| 4 |
|
| 5 |
# Repository ID for storing leaderboard data (required)
|
| 6 |
# Format: username/repo-name
|
| 7 |
+
HUGGING_FACE_STORAGE_REPO=leaderboard-explorer/leaderboard_explorer
|
| 8 |
|
| 9 |
# File path in the repository (required)
|
| 10 |
HUGGING_FACE_STORAGE_FILE_PATH=final_leaderboards.json
|
server/server.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
from fastapi import FastAPI, HTTPException
|
| 2 |
from fastapi.middleware.cors import CORSMiddleware
|
| 3 |
from fastapi.staticfiles import StaticFiles
|
| 4 |
from apscheduler.schedulers.background import BackgroundScheduler
|
|
@@ -7,6 +7,13 @@ import os
|
|
| 7 |
from dotenv import load_dotenv
|
| 8 |
from huggingface_hub import HfApi
|
| 9 |
import json
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
|
| 11 |
# Load environment variables
|
| 12 |
load_dotenv()
|
|
@@ -49,31 +56,41 @@ hf_api = HfApi(token=HF_TOKEN)
|
|
| 49 |
def fetch_leaderboards():
|
| 50 |
"""Fetch leaderboards data from Hugging Face"""
|
| 51 |
try:
|
| 52 |
-
|
|
|
|
| 53 |
json_path = hf_api.hf_hub_download(
|
| 54 |
repo_id=REPO_ID,
|
| 55 |
filename=FILE_PATH,
|
| 56 |
-
repo_type="dataset"
|
|
|
|
|
|
|
| 57 |
)
|
| 58 |
|
|
|
|
|
|
|
| 59 |
with open(json_path, 'r') as f:
|
| 60 |
-
|
|
|
|
|
|
|
| 61 |
cache["last_updated"] = datetime.now()
|
| 62 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 63 |
|
| 64 |
except Exception as e:
|
| 65 |
-
|
| 66 |
if not cache["data"]: # Only raise if we don't have any cached data
|
| 67 |
raise HTTPException(status_code=500, detail="Failed to fetch leaderboards data")
|
| 68 |
|
| 69 |
-
# Initialize scheduler
|
| 70 |
-
scheduler = BackgroundScheduler()
|
| 71 |
-
scheduler.add_job(fetch_leaderboards, 'interval', minutes=CACHE_DURATION_MINUTES)
|
| 72 |
-
scheduler.start()
|
| 73 |
-
|
| 74 |
# Initial fetch
|
| 75 |
fetch_leaderboards()
|
| 76 |
|
|
|
|
|
|
|
|
|
|
| 77 |
@app.get("/api/leaderboards")
|
| 78 |
async def get_leaderboards():
|
| 79 |
"""Get leaderboards data from cache"""
|
|
@@ -94,8 +111,38 @@ async def health_check():
|
|
| 94 |
"last_updated": cache["last_updated"].isoformat() if cache["last_updated"] else None
|
| 95 |
}
|
| 96 |
|
| 97 |
-
|
| 98 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 99 |
|
| 100 |
if __name__ == "__main__":
|
| 101 |
import uvicorn
|
|
|
|
| 1 |
+
from fastapi import FastAPI, HTTPException, Request
|
| 2 |
from fastapi.middleware.cors import CORSMiddleware
|
| 3 |
from fastapi.staticfiles import StaticFiles
|
| 4 |
from apscheduler.schedulers.background import BackgroundScheduler
|
|
|
|
| 7 |
from dotenv import load_dotenv
|
| 8 |
from huggingface_hub import HfApi
|
| 9 |
import json
|
| 10 |
+
import logging
|
| 11 |
+
|
| 12 |
+
# Configure logging
|
| 13 |
+
logging.basicConfig(
|
| 14 |
+
level=logging.INFO,
|
| 15 |
+
format='%(asctime)s - %(levelname)s - %(message)s'
|
| 16 |
+
)
|
| 17 |
|
| 18 |
# Load environment variables
|
| 19 |
load_dotenv()
|
|
|
|
| 56 |
def fetch_leaderboards():
|
| 57 |
"""Fetch leaderboards data from Hugging Face"""
|
| 58 |
try:
|
| 59 |
+
logging.info(f"Fetching leaderboards from {REPO_ID}/{FILE_PATH}")
|
| 60 |
+
# Download the JSON file directly with force_download to ensure we get the latest version
|
| 61 |
json_path = hf_api.hf_hub_download(
|
| 62 |
repo_id=REPO_ID,
|
| 63 |
filename=FILE_PATH,
|
| 64 |
+
repo_type="dataset",
|
| 65 |
+
force_download=True, # Force download to ensure we get the latest version
|
| 66 |
+
force_filename="leaderboards_latest.json" # Force a specific filename to avoid caching issues
|
| 67 |
)
|
| 68 |
|
| 69 |
+
logging.info(f"File downloaded to: {json_path}")
|
| 70 |
+
|
| 71 |
with open(json_path, 'r') as f:
|
| 72 |
+
new_data = json.load(f)
|
| 73 |
+
old_data = cache["data"]
|
| 74 |
+
cache["data"] = new_data
|
| 75 |
cache["last_updated"] = datetime.now()
|
| 76 |
+
|
| 77 |
+
# Log the differences
|
| 78 |
+
old_len = len(old_data) if old_data and isinstance(old_data, list) else 0
|
| 79 |
+
new_len = len(new_data) if isinstance(new_data, list) else 0
|
| 80 |
+
logging.info(f"Cache updated: Old entries: {old_len}, New entries: {new_len}")
|
| 81 |
+
logging.info(f"Cache update timestamp: {cache['last_updated']}")
|
| 82 |
|
| 83 |
except Exception as e:
|
| 84 |
+
logging.error(f"Error fetching data: {str(e)}", exc_info=True)
|
| 85 |
if not cache["data"]: # Only raise if we don't have any cached data
|
| 86 |
raise HTTPException(status_code=500, detail="Failed to fetch leaderboards data")
|
| 87 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 88 |
# Initial fetch
|
| 89 |
fetch_leaderboards()
|
| 90 |
|
| 91 |
+
# Mount static files
|
| 92 |
+
app.mount("/static", StaticFiles(directory="static", html=True), name="static")
|
| 93 |
+
|
| 94 |
@app.get("/api/leaderboards")
|
| 95 |
async def get_leaderboards():
|
| 96 |
"""Get leaderboards data from cache"""
|
|
|
|
| 111 |
"last_updated": cache["last_updated"].isoformat() if cache["last_updated"] else None
|
| 112 |
}
|
| 113 |
|
| 114 |
+
@app.post("/api/webhook")
|
| 115 |
+
async def handle_webhook(request: Request):
|
| 116 |
+
"""Handle webhook notifications from Hugging Face Hub"""
|
| 117 |
+
try:
|
| 118 |
+
body = await request.json()
|
| 119 |
+
logging.info(f"Received webhook with payload: {body}")
|
| 120 |
+
|
| 121 |
+
# Get the event details
|
| 122 |
+
event = body.get("event", {})
|
| 123 |
+
|
| 124 |
+
# Verify if it's a relevant update (repo content update)
|
| 125 |
+
if event.get("action") == "update" and event.get("scope") == "repo.content":
|
| 126 |
+
try:
|
| 127 |
+
logging.info(f"Dataset update detected for repo {REPO_ID}, file {FILE_PATH}")
|
| 128 |
+
# Force a clean fetch
|
| 129 |
+
fetch_leaderboards()
|
| 130 |
+
if cache["last_updated"]:
|
| 131 |
+
logging.info(f"Cache successfully updated at {cache['last_updated']}")
|
| 132 |
+
return {"status": "success", "message": "Cache updated"}
|
| 133 |
+
else:
|
| 134 |
+
logging.error("Cache update failed: last_updated is None")
|
| 135 |
+
return {"status": "error", "message": "Cache update failed"}
|
| 136 |
+
except Exception as fetch_error:
|
| 137 |
+
logging.error(f"Error during fetch_leaderboards: {str(fetch_error)}", exc_info=True)
|
| 138 |
+
return {"status": "error", "message": f"Failed to update cache: {str(fetch_error)}"}
|
| 139 |
+
|
| 140 |
+
logging.info(f"Ignoring webhook event: action={event.get('action')}, scope={event.get('scope')}")
|
| 141 |
+
return {"status": "ignored", "message": "Event type not relevant"}
|
| 142 |
+
|
| 143 |
+
except Exception as e:
|
| 144 |
+
logging.error(f"Error processing webhook: {str(e)}", exc_info=True)
|
| 145 |
+
raise HTTPException(status_code=500, detail=f"Failed to process webhook: {str(e)}")
|
| 146 |
|
| 147 |
if __name__ == "__main__":
|
| 148 |
import uvicorn
|