|
""" |
|
Main application for Dynamic Highscores system. |
|
|
|
This file integrates all components into a unified application. |
|
""" |
|
|
|
import os |
|
import gradio as gr |
|
import threading |
|
import time |
|
from database_schema import DynamicHighscoresDB |
|
from auth import HuggingFaceAuth |
|
from benchmark_selection import BenchmarkSelector, create_benchmark_selection_ui |
|
from evaluation_queue import EvaluationQueue, create_model_submission_ui |
|
from leaderboard import Leaderboard, create_leaderboard_ui |
|
from sample_benchmarks import add_sample_benchmarks |
|
from fastapi import FastAPI, Request, HTTPException |
|
from fastapi.responses import FileResponse, HTMLResponse |
|
from fastapi.staticfiles import StaticFiles |
|
from pydantic import BaseModel |
|
|
|
|
|
db = DynamicHighscoresDB() |
|
auth_manager = HuggingFaceAuth(db) |
|
benchmark_selector = BenchmarkSelector(db, auth_manager) |
|
evaluation_queue = EvaluationQueue(db, auth_manager) |
|
leaderboard = Leaderboard(db) |
|
|
|
|
|
print("Checking for existing benchmarks...") |
|
benchmarks = db.get_benchmarks() |
|
if not benchmarks or len(benchmarks) == 0: |
|
print("No benchmarks found. Adding sample benchmarks...") |
|
try: |
|
|
|
print(f"Database path: {db.db_path}") |
|
|
|
|
|
num_added = add_sample_benchmarks() |
|
print(f"Added {num_added} sample benchmarks.") |
|
except Exception as e: |
|
print(f"Error adding sample benchmarks: {str(e)}") |
|
|
|
try: |
|
print("Attempting direct benchmark insertion...") |
|
db.add_benchmark( |
|
name="MMLU (Massive Multitask Language Understanding)", |
|
dataset_id="cais/mmlu", |
|
description="Tests knowledge across 57 subjects" |
|
) |
|
print("Added fallback benchmark.") |
|
except Exception as inner_e: |
|
print(f"Fallback insertion failed: {str(inner_e)}") |
|
else: |
|
print(f"Found {len(benchmarks)} existing benchmarks.") |
|
|
|
|
|
css = """ |
|
/* Theme-adaptive colored info box */ |
|
.info-text { |
|
background-color: rgba(53, 130, 220, 0.1); |
|
padding: 12px; |
|
border-radius: 8px; |
|
border-left: 4px solid #3498db; |
|
margin: 12px 0; |
|
} |
|
|
|
/* High-contrast text for elements - works in light and dark themes */ |
|
.info-text, .header, .footer, .tab-content, |
|
button, input, textarea, select, option, |
|
.gradio-container *, .markdown-text { |
|
color: var(--text-color, inherit) !important; |
|
} |
|
|
|
/* Container styling */ |
|
.container { |
|
max-width: 1200px; |
|
margin: 0 auto; |
|
} |
|
|
|
/* Header styling */ |
|
.header { |
|
text-align: center; |
|
margin-bottom: 20px; |
|
font-weight: bold; |
|
font-size: 24px; |
|
} |
|
|
|
/* Footer styling */ |
|
.footer { |
|
text-align: center; |
|
margin-top: 40px; |
|
padding: 20px; |
|
border-top: 1px solid var(--border-color-primary, #eee); |
|
} |
|
|
|
/* Login section styling */ |
|
.login-section { |
|
padding: 10px; |
|
margin-bottom: 15px; |
|
border-radius: 8px; |
|
background-color: rgba(250, 250, 250, 0.1); |
|
text-align: center; |
|
} |
|
""" |
|
|
|
|
|
def check_user(request: gr.Request): |
|
if request: |
|
username = request.headers.get("HF-User") |
|
if username: |
|
|
|
print(f"User logged in: {username}") |
|
user = db.get_user_by_username(username) |
|
if not user: |
|
|
|
print(f"Creating new user: {username}") |
|
is_admin = (username == "Quazim0t0") |
|
db.add_user(username, username, is_admin) |
|
user = db.get_user_by_username(username) |
|
return f"Logged in as: {username}" |
|
return "Not logged in. Please <a href='/'>login</a> first." |
|
|
|
|
|
def start_queue_worker(): |
|
|
|
time.sleep(2) |
|
try: |
|
print("Starting evaluation queue worker...") |
|
evaluation_queue.start_worker() |
|
except Exception as e: |
|
print(f"Error starting queue worker: {e}") |
|
|
|
|
|
with gr.Blocks(css=css, title="Dynamic Highscores") as app: |
|
|
|
with gr.Row(elem_classes=["login-section"]): |
|
login_status = gr.Markdown("Checking login status...") |
|
|
|
gr.Markdown("# 🏆 Dynamic Highscores", elem_classes=["header"]) |
|
gr.Markdown(""" |
|
Welcome to Dynamic Highscores - a community benchmark platform for evaluating and comparing language models. |
|
|
|
- **Add your own benchmarks** from HuggingFace datasets |
|
- **Submit your models** for CPU-only evaluation |
|
- **Compare performance** across different models and benchmarks |
|
- **Filter results** by model type (Merge, Agent, Reasoning, Coding, etc.) |
|
""", elem_classes=["info-text"]) |
|
|
|
|
|
with gr.Tabs() as tabs: |
|
with gr.TabItem("📊 Leaderboard", id=0): |
|
leaderboard_ui = create_leaderboard_ui(leaderboard, db) |
|
|
|
with gr.TabItem("🚀 Submit Model", id=1): |
|
submission_ui = create_model_submission_ui(evaluation_queue, auth_manager, db) |
|
|
|
with gr.TabItem("🔍 Benchmarks", id=2): |
|
benchmark_ui = create_benchmark_selection_ui(benchmark_selector, auth_manager) |
|
|
|
gr.Markdown(""" |
|
### About Dynamic Highscores |
|
|
|
This platform allows users to select benchmarks from HuggingFace datasets and evaluate models against them. |
|
Each user can submit one benchmark per day (admin users are exempt from this limit). |
|
All evaluations run on CPU only to ensure fair comparisons. |
|
|
|
Created by Quazim0t0 |
|
""", elem_classes=["footer"]) |
|
|
|
|
|
app.load( |
|
fn=check_user, |
|
inputs=[], |
|
outputs=[login_status] |
|
) |
|
|
|
|
|
fastapi_app = FastAPI() |
|
|
|
|
|
os.makedirs("static", exist_ok=True) |
|
|
|
|
|
login_html_path = os.path.join("static", "login.html") |
|
if not os.path.exists(login_html_path): |
|
with open(login_html_path, "w") as f: |
|
f.write("""<!DOCTYPE html> |
|
<html> |
|
<head> |
|
<meta charset="utf-8" /> |
|
<meta name="viewport" content="width=device-width" /> |
|
<title>Dynamic Highscores Login</title> |
|
<script src="https://unpkg.com/[email protected]/dist/es-module-shims.js"></script> |
|
<script type="importmap"> |
|
{ |
|
"imports": { |
|
"@huggingface/hub": "https://cdn.jsdelivr.net/npm/@huggingface/[email protected]/+esm" |
|
} |
|
} |
|
</script> |
|
<style> |
|
body { |
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; |
|
background-color: #f5f5f5; |
|
display: flex; |
|
flex-direction: column; |
|
align-items: center; |
|
justify-content: center; |
|
height: 100vh; |
|
margin: 0; |
|
padding: 20px; |
|
} |
|
.card { |
|
background: white; |
|
border-radius: 8px; |
|
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); |
|
padding: 30px; |
|
max-width: 500px; |
|
width: 100%; |
|
text-align: center; |
|
} |
|
h1 { |
|
color: #333; |
|
margin-top: 0; |
|
} |
|
.signin-btn { |
|
cursor: pointer; |
|
display: block; |
|
margin: 20px auto; |
|
transition: transform 0.3s ease; |
|
} |
|
.signin-btn:hover { |
|
transform: scale(1.05); |
|
} |
|
.hidden { |
|
display: none; |
|
} |
|
#status { |
|
margin-top: 20px; |
|
padding: 10px; |
|
border-radius: 4px; |
|
} |
|
.success { |
|
background-color: #d4edda; |
|
color: #155724; |
|
} |
|
.loading { |
|
background-color: #fff3cd; |
|
color: #856404; |
|
} |
|
a.button { |
|
display: inline-block; |
|
background-color: #3498db; |
|
color: white; |
|
padding: 10px 20px; |
|
border-radius: 4px; |
|
text-decoration: none; |
|
font-weight: bold; |
|
margin-top: 20px; |
|
} |
|
a.button:hover { |
|
background-color: #2980b9; |
|
} |
|
</style> |
|
</head> |
|
<body> |
|
<div class="card"> |
|
<h1>Dynamic Highscores</h1> |
|
<p>Sign in with your HuggingFace account to submit models and benchmarks.</p> |
|
|
|
<img src="https://huggingface.co/datasets/huggingface/badges/resolve/main/sign-in-with-huggingface-xl-dark.svg" |
|
alt="Sign in with Hugging Face" |
|
class="signin-btn" |
|
id="signin"> |
|
|
|
<div id="status" class="hidden"></div> |
|
|
|
<a href="/app" class="button hidden" id="continue-btn">Continue to Dynamic Highscores</a> |
|
</div> |
|
|
|
<script type="module"> |
|
import { oauthLoginUrl, oauthHandleRedirectIfPresent } from "@huggingface/hub"; |
|
|
|
const statusElement = document.getElementById("status"); |
|
const signinButton = document.getElementById("signin"); |
|
const continueButton = document.getElementById("continue-btn"); |
|
|
|
// Function to show status message |
|
function showStatus(message, type) { |
|
statusElement.textContent = message; |
|
statusElement.className = type; |
|
statusElement.classList.remove("hidden"); |
|
} |
|
|
|
// Check if we're returning from OAuth redirect |
|
async function checkLogin() { |
|
try { |
|
showStatus("Checking login status...", "loading"); |
|
|
|
// Check if we already have OAuth data in localStorage |
|
let oauthResult = localStorage.getItem("oauth"); |
|
if (oauthResult) { |
|
try { |
|
oauthResult = JSON.parse(oauthResult); |
|
} catch { |
|
oauthResult = null; |
|
} |
|
} |
|
|
|
// If not, check if we're returning from a redirect |
|
if (!oauthResult) { |
|
oauthResult = await oauthHandleRedirectIfPresent(); |
|
} |
|
|
|
// If we have OAuth data, we're logged in |
|
if (oauthResult) { |
|
localStorage.setItem("oauth", JSON.stringify(oauthResult)); |
|
|
|
signinButton.classList.add("hidden"); |
|
showStatus(`Logged in as ${oauthResult.userInfo.name}`, "success"); |
|
continueButton.classList.remove("hidden"); |
|
} else { |
|
statusElement.classList.add("hidden"); |
|
signinButton.classList.remove("hidden"); |
|
} |
|
} catch (error) { |
|
console.error("Error checking login:", error); |
|
showStatus("Error checking login status", "error"); |
|
} |
|
} |
|
|
|
// Setup sign in button |
|
signinButton.addEventListener("click", async () => { |
|
try { |
|
showStatus("Redirecting to HuggingFace login...", "loading"); |
|
window.location.href = await oauthLoginUrl({ |
|
redirectUrl: window.location.href, |
|
scopes: ["openid", "profile"] |
|
}); |
|
} catch (error) { |
|
console.error("Error generating login URL:", error); |
|
showStatus("Error starting login process", "error"); |
|
} |
|
}); |
|
|
|
// Check login status when page loads |
|
checkLogin(); |
|
</script> |
|
</body> |
|
</html>""") |
|
|
|
|
|
class UserInfo(BaseModel): |
|
username: str |
|
token: str |
|
|
|
@fastapi_app.post("/api/register_user") |
|
async def register_user(userinfo: UserInfo): |
|
try: |
|
|
|
user = db.get_user_by_username(userinfo.username) |
|
if not user: |
|
is_admin = (userinfo.username == "Quazim0t0") |
|
db.add_user(userinfo.username, userinfo.username, is_admin) |
|
return {"status": "success"} |
|
except Exception as e: |
|
raise HTTPException(status_code=500, detail=str(e)) |
|
|
|
|
|
fastapi_app.mount("/static", StaticFiles(directory="static"), name="static") |
|
|
|
|
|
@fastapi_app.get("/") |
|
async def serve_login_page(): |
|
return FileResponse("static/login.html") |
|
|
|
|
|
@fastapi_app.get("/app") |
|
async def serve_app(): |
|
|
|
html_content = """ |
|
<!DOCTYPE html> |
|
<html> |
|
<head> |
|
<meta http-equiv="refresh" content="0;url=/gradio"> |
|
<title>Redirecting...</title> |
|
</head> |
|
<body> |
|
Redirecting to Dynamic Highscores... |
|
</body> |
|
</html> |
|
""" |
|
return HTMLResponse(content=html_content) |
|
|
|
|
|
app = gr.mount_gradio_app(fastapi_app, app, path="/gradio") |
|
|
|
|
|
if __name__ == "__main__": |
|
queue_thread = threading.Thread(target=start_queue_worker) |
|
queue_thread.daemon = True |
|
queue_thread.start() |