Update app.py
Browse files
app.py
CHANGED
@@ -14,10 +14,6 @@ from benchmark_selection import BenchmarkSelector, create_benchmark_selection_ui
|
|
14 |
from evaluation_queue import EvaluationQueue, create_model_submission_ui
|
15 |
from leaderboard import Leaderboard, create_leaderboard_ui
|
16 |
from sample_benchmarks import add_sample_benchmarks
|
17 |
-
from fastapi import FastAPI, Request, HTTPException
|
18 |
-
from fastapi.responses import FileResponse, HTMLResponse
|
19 |
-
from fastapi.staticfiles import StaticFiles
|
20 |
-
from pydantic import BaseModel
|
21 |
|
22 |
# Initialize components in main thread
|
23 |
db = DynamicHighscoresDB()
|
@@ -102,8 +98,99 @@ button, input, textarea, select, option,
|
|
102 |
background-color: rgba(250, 250, 250, 0.1);
|
103 |
text-align: center;
|
104 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
105 |
"""
|
106 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
107 |
# Simple manual authentication check
|
108 |
def check_user(request: gr.Request):
|
109 |
if request:
|
@@ -118,8 +205,8 @@ def check_user(request: gr.Request):
|
|
118 |
is_admin = (username == "Quazim0t0")
|
119 |
db.add_user(username, username, is_admin)
|
120 |
user = db.get_user_by_username(username)
|
121 |
-
return
|
122 |
-
return
|
123 |
|
124 |
# Start evaluation queue worker
|
125 |
def start_queue_worker():
|
@@ -133,9 +220,21 @@ def start_queue_worker():
|
|
133 |
|
134 |
# Create Gradio app
|
135 |
with gr.Blocks(css=css, title="Dynamic Highscores") as app:
|
136 |
-
#
|
|
|
|
|
|
|
137 |
with gr.Row(elem_classes=["login-section"]):
|
138 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
139 |
|
140 |
gr.Markdown("# 🏆 Dynamic Highscores", elem_classes=["header"])
|
141 |
gr.Markdown("""
|
@@ -172,232 +271,14 @@ with gr.Blocks(css=css, title="Dynamic Highscores") as app:
|
|
172 |
app.load(
|
173 |
fn=check_user,
|
174 |
inputs=[],
|
175 |
-
outputs=[
|
176 |
)
|
177 |
|
178 |
-
#
|
179 |
-
fastapi_app = FastAPI()
|
180 |
-
|
181 |
-
# Make sure to create a static directory and put the login.html file there
|
182 |
-
os.makedirs("static", exist_ok=True)
|
183 |
-
|
184 |
-
# Save the login HTML to a file
|
185 |
-
login_html_path = os.path.join("static", "login.html")
|
186 |
-
if not os.path.exists(login_html_path):
|
187 |
-
with open(login_html_path, "w") as f:
|
188 |
-
f.write("""<!DOCTYPE html>
|
189 |
-
<html>
|
190 |
-
<head>
|
191 |
-
<meta charset="utf-8" />
|
192 |
-
<meta name="viewport" content="width=device-width" />
|
193 |
-
<title>Dynamic Highscores Login</title>
|
194 |
-
<script src="https://unpkg.com/[email protected]/dist/es-module-shims.js"></script>
|
195 |
-
<script type="importmap">
|
196 |
-
{
|
197 |
-
"imports": {
|
198 |
-
"@huggingface/hub": "https://cdn.jsdelivr.net/npm/@huggingface/[email protected]/+esm"
|
199 |
-
}
|
200 |
-
}
|
201 |
-
</script>
|
202 |
-
<style>
|
203 |
-
body {
|
204 |
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
205 |
-
background-color: #f5f5f5;
|
206 |
-
display: flex;
|
207 |
-
flex-direction: column;
|
208 |
-
align-items: center;
|
209 |
-
justify-content: center;
|
210 |
-
height: 100vh;
|
211 |
-
margin: 0;
|
212 |
-
padding: 20px;
|
213 |
-
}
|
214 |
-
.card {
|
215 |
-
background: white;
|
216 |
-
border-radius: 8px;
|
217 |
-
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
218 |
-
padding: 30px;
|
219 |
-
max-width: 500px;
|
220 |
-
width: 100%;
|
221 |
-
text-align: center;
|
222 |
-
}
|
223 |
-
h1 {
|
224 |
-
color: #333;
|
225 |
-
margin-top: 0;
|
226 |
-
}
|
227 |
-
.signin-btn {
|
228 |
-
cursor: pointer;
|
229 |
-
display: block;
|
230 |
-
margin: 20px auto;
|
231 |
-
transition: transform 0.3s ease;
|
232 |
-
}
|
233 |
-
.signin-btn:hover {
|
234 |
-
transform: scale(1.05);
|
235 |
-
}
|
236 |
-
.hidden {
|
237 |
-
display: none;
|
238 |
-
}
|
239 |
-
#status {
|
240 |
-
margin-top: 20px;
|
241 |
-
padding: 10px;
|
242 |
-
border-radius: 4px;
|
243 |
-
}
|
244 |
-
.success {
|
245 |
-
background-color: #d4edda;
|
246 |
-
color: #155724;
|
247 |
-
}
|
248 |
-
.loading {
|
249 |
-
background-color: #fff3cd;
|
250 |
-
color: #856404;
|
251 |
-
}
|
252 |
-
a.button {
|
253 |
-
display: inline-block;
|
254 |
-
background-color: #3498db;
|
255 |
-
color: white;
|
256 |
-
padding: 10px 20px;
|
257 |
-
border-radius: 4px;
|
258 |
-
text-decoration: none;
|
259 |
-
font-weight: bold;
|
260 |
-
margin-top: 20px;
|
261 |
-
}
|
262 |
-
a.button:hover {
|
263 |
-
background-color: #2980b9;
|
264 |
-
}
|
265 |
-
</style>
|
266 |
-
</head>
|
267 |
-
<body>
|
268 |
-
<div class="card">
|
269 |
-
<h1>Dynamic Highscores</h1>
|
270 |
-
<p>Sign in with your HuggingFace account to submit models and benchmarks.</p>
|
271 |
-
|
272 |
-
<img src="https://huggingface.co/datasets/huggingface/badges/resolve/main/sign-in-with-huggingface-xl-dark.svg"
|
273 |
-
alt="Sign in with Hugging Face"
|
274 |
-
class="signin-btn"
|
275 |
-
id="signin">
|
276 |
-
|
277 |
-
<div id="status" class="hidden"></div>
|
278 |
-
|
279 |
-
<a href="/app" class="button hidden" id="continue-btn">Continue to Dynamic Highscores</a>
|
280 |
-
</div>
|
281 |
-
|
282 |
-
<script type="module">
|
283 |
-
import { oauthLoginUrl, oauthHandleRedirectIfPresent } from "@huggingface/hub";
|
284 |
-
|
285 |
-
const statusElement = document.getElementById("status");
|
286 |
-
const signinButton = document.getElementById("signin");
|
287 |
-
const continueButton = document.getElementById("continue-btn");
|
288 |
-
|
289 |
-
// Function to show status message
|
290 |
-
function showStatus(message, type) {
|
291 |
-
statusElement.textContent = message;
|
292 |
-
statusElement.className = type;
|
293 |
-
statusElement.classList.remove("hidden");
|
294 |
-
}
|
295 |
-
|
296 |
-
// Check if we're returning from OAuth redirect
|
297 |
-
async function checkLogin() {
|
298 |
-
try {
|
299 |
-
showStatus("Checking login status...", "loading");
|
300 |
-
|
301 |
-
// Check if we already have OAuth data in localStorage
|
302 |
-
let oauthResult = localStorage.getItem("oauth");
|
303 |
-
if (oauthResult) {
|
304 |
-
try {
|
305 |
-
oauthResult = JSON.parse(oauthResult);
|
306 |
-
} catch {
|
307 |
-
oauthResult = null;
|
308 |
-
}
|
309 |
-
}
|
310 |
-
|
311 |
-
// If not, check if we're returning from a redirect
|
312 |
-
if (!oauthResult) {
|
313 |
-
oauthResult = await oauthHandleRedirectIfPresent();
|
314 |
-
}
|
315 |
-
|
316 |
-
// If we have OAuth data, we're logged in
|
317 |
-
if (oauthResult) {
|
318 |
-
localStorage.setItem("oauth", JSON.stringify(oauthResult));
|
319 |
-
|
320 |
-
signinButton.classList.add("hidden");
|
321 |
-
showStatus(`Logged in as ${oauthResult.userInfo.name}`, "success");
|
322 |
-
continueButton.classList.remove("hidden");
|
323 |
-
} else {
|
324 |
-
statusElement.classList.add("hidden");
|
325 |
-
signinButton.classList.remove("hidden");
|
326 |
-
}
|
327 |
-
} catch (error) {
|
328 |
-
console.error("Error checking login:", error);
|
329 |
-
showStatus("Error checking login status", "error");
|
330 |
-
}
|
331 |
-
}
|
332 |
-
|
333 |
-
// Setup sign in button
|
334 |
-
signinButton.addEventListener("click", async () => {
|
335 |
-
try {
|
336 |
-
showStatus("Redirecting to HuggingFace login...", "loading");
|
337 |
-
window.location.href = await oauthLoginUrl({
|
338 |
-
redirectUrl: window.location.href,
|
339 |
-
scopes: ["openid", "profile"]
|
340 |
-
});
|
341 |
-
} catch (error) {
|
342 |
-
console.error("Error generating login URL:", error);
|
343 |
-
showStatus("Error starting login process", "error");
|
344 |
-
}
|
345 |
-
});
|
346 |
-
|
347 |
-
// Check login status when page loads
|
348 |
-
checkLogin();
|
349 |
-
</script>
|
350 |
-
</body>
|
351 |
-
</html>""")
|
352 |
-
|
353 |
-
# Create API endpoint for user registration
|
354 |
-
class UserInfo(BaseModel):
|
355 |
-
username: str
|
356 |
-
token: str
|
357 |
-
|
358 |
-
@fastapi_app.post("/api/register_user")
|
359 |
-
async def register_user(userinfo: UserInfo):
|
360 |
-
try:
|
361 |
-
# Create user in database if they don't exist
|
362 |
-
user = db.get_user_by_username(userinfo.username)
|
363 |
-
if not user:
|
364 |
-
is_admin = (userinfo.username == "Quazim0t0")
|
365 |
-
db.add_user(userinfo.username, userinfo.username, is_admin)
|
366 |
-
return {"status": "success"}
|
367 |
-
except Exception as e:
|
368 |
-
raise HTTPException(status_code=500, detail=str(e))
|
369 |
-
|
370 |
-
# Serve static files
|
371 |
-
fastapi_app.mount("/static", StaticFiles(directory="static"), name="static")
|
372 |
-
|
373 |
-
# Root path serves the login page
|
374 |
-
@fastapi_app.get("/")
|
375 |
-
async def serve_login_page():
|
376 |
-
return FileResponse("static/login.html")
|
377 |
-
|
378 |
-
# App path serves the Gradio interface
|
379 |
-
@fastapi_app.get("/app")
|
380 |
-
async def serve_app():
|
381 |
-
# This will redirect to the Gradio interface
|
382 |
-
html_content = """
|
383 |
-
<!DOCTYPE html>
|
384 |
-
<html>
|
385 |
-
<head>
|
386 |
-
<meta http-equiv="refresh" content="0;url=/gradio">
|
387 |
-
<title>Redirecting...</title>
|
388 |
-
</head>
|
389 |
-
<body>
|
390 |
-
Redirecting to Dynamic Highscores...
|
391 |
-
</body>
|
392 |
-
</html>
|
393 |
-
"""
|
394 |
-
return HTMLResponse(content=html_content)
|
395 |
-
|
396 |
-
# Mount Gradio app to FastAPI app
|
397 |
-
app = gr.mount_gradio_app(fastapi_app, app, path="/gradio")
|
398 |
-
|
399 |
-
# Start the queue worker
|
400 |
if __name__ == "__main__":
|
|
|
401 |
queue_thread = threading.Thread(target=start_queue_worker)
|
402 |
queue_thread.daemon = True
|
403 |
-
queue_thread.start()
|
|
|
|
|
|
14 |
from evaluation_queue import EvaluationQueue, create_model_submission_ui
|
15 |
from leaderboard import Leaderboard, create_leaderboard_ui
|
16 |
from sample_benchmarks import add_sample_benchmarks
|
|
|
|
|
|
|
|
|
17 |
|
18 |
# Initialize components in main thread
|
19 |
db = DynamicHighscoresDB()
|
|
|
98 |
background-color: rgba(250, 250, 250, 0.1);
|
99 |
text-align: center;
|
100 |
}
|
101 |
+
|
102 |
+
/* Login button styling */
|
103 |
+
.login-button {
|
104 |
+
background-color: #4CAF50 !important;
|
105 |
+
color: white !important;
|
106 |
+
font-weight: bold;
|
107 |
+
}
|
108 |
+
|
109 |
+
/* Force high contrast on specific input areas */
|
110 |
+
input[type="text"], input[type="password"], textarea {
|
111 |
+
background-color: var(--background-fill-primary) !important;
|
112 |
+
color: var(--body-text-color) !important;
|
113 |
+
}
|
114 |
+
|
115 |
+
/* Force text visibility in multiple contexts */
|
116 |
+
.gradio-markdown p, .gradio-markdown h1, .gradio-markdown h2,
|
117 |
+
.gradio-markdown h3, .gradio-markdown h4, .gradio-markdown li {
|
118 |
+
color: var(--body-text-color) !important;
|
119 |
+
}
|
120 |
+
|
121 |
+
/* Fix dark mode text visibility */
|
122 |
+
@media (prefers-color-scheme: dark) {
|
123 |
+
input, textarea, select {
|
124 |
+
color: #ffffff !important;
|
125 |
+
}
|
126 |
+
|
127 |
+
::placeholder {
|
128 |
+
color: rgba(255, 255, 255, 0.5) !important;
|
129 |
+
}
|
130 |
+
}
|
131 |
"""
|
132 |
|
133 |
+
# JavaScript login implementation
|
134 |
+
def js_login_script():
|
135 |
+
space_host = os.environ.get("SPACE_HOST", "localhost:7860")
|
136 |
+
redirect_uri = f"https://{space_host}"
|
137 |
+
|
138 |
+
return f"""
|
139 |
+
<script src="https://unpkg.com/@huggingface/[email protected]/dist/index.umd.min.js"></script>
|
140 |
+
<script>
|
141 |
+
(async function() {{
|
142 |
+
const HfHub = window.HfHub;
|
143 |
+
try {{
|
144 |
+
// Check if we're returning from OAuth redirect
|
145 |
+
const oauthResult = await HfHub.oauthHandleRedirectIfPresent();
|
146 |
+
|
147 |
+
if (oauthResult) {{
|
148 |
+
console.log("User logged in:", oauthResult);
|
149 |
+
|
150 |
+
// Store the user info in localStorage
|
151 |
+
localStorage.setItem("hf_user", JSON.stringify(oauthResult.userInfo));
|
152 |
+
localStorage.setItem("hf_token", oauthResult.accessToken);
|
153 |
+
|
154 |
+
// Update the UI to show logged in state
|
155 |
+
document.getElementById("login-status").textContent = "Logged in as: " + oauthResult.userInfo.name;
|
156 |
+
document.getElementById("login-button").style.display = "none";
|
157 |
+
|
158 |
+
// Refresh the page to update server-side state
|
159 |
+
setTimeout(() => window.location.reload(), 1000);
|
160 |
+
}}
|
161 |
+
}} catch (error) {{
|
162 |
+
console.error("OAuth error:", error);
|
163 |
+
}}
|
164 |
+
|
165 |
+
// Check if user is already logged in from localStorage
|
166 |
+
const storedUser = localStorage.getItem("hf_user");
|
167 |
+
if (storedUser) {{
|
168 |
+
try {{
|
169 |
+
const userInfo = JSON.parse(storedUser);
|
170 |
+
document.getElementById("login-status").textContent = "Logged in as: " + userInfo.name;
|
171 |
+
document.getElementById("login-button").style.display = "none";
|
172 |
+
}} catch (e) {{
|
173 |
+
console.error("Error parsing stored user:", e);
|
174 |
+
}}
|
175 |
+
}}
|
176 |
+
|
177 |
+
// Setup login button
|
178 |
+
document.getElementById("login-button").addEventListener("click", async function() {{
|
179 |
+
try {{
|
180 |
+
const loginUrl = await HfHub.oauthLoginUrl({{
|
181 |
+
redirectUrl: "{redirect_uri}",
|
182 |
+
scopes: ["openid", "profile"]
|
183 |
+
}});
|
184 |
+
window.location.href = loginUrl;
|
185 |
+
}} catch (error) {{
|
186 |
+
console.error("Error generating login URL:", error);
|
187 |
+
alert("Error starting login process. Please try again.");
|
188 |
+
}}
|
189 |
+
}});
|
190 |
+
}})();
|
191 |
+
</script>
|
192 |
+
"""
|
193 |
+
|
194 |
# Simple manual authentication check
|
195 |
def check_user(request: gr.Request):
|
196 |
if request:
|
|
|
205 |
is_admin = (username == "Quazim0t0")
|
206 |
db.add_user(username, username, is_admin)
|
207 |
user = db.get_user_by_username(username)
|
208 |
+
return username
|
209 |
+
return None
|
210 |
|
211 |
# Start evaluation queue worker
|
212 |
def start_queue_worker():
|
|
|
220 |
|
221 |
# Create Gradio app
|
222 |
with gr.Blocks(css=css, title="Dynamic Highscores") as app:
|
223 |
+
# State to track user
|
224 |
+
user_state = gr.State(None)
|
225 |
+
|
226 |
+
# Login section
|
227 |
with gr.Row(elem_classes=["login-section"]):
|
228 |
+
with gr.Column():
|
229 |
+
gr.HTML("""
|
230 |
+
<div style="display: flex; justify-content: space-between; align-items: center;">
|
231 |
+
<div id="login-status">Not logged in</div>
|
232 |
+
<button id="login-button" style="padding: 8px 16px; background-color: #4CAF50; color: white; border: none; border-radius: 4px; cursor: pointer;">Login with HuggingFace</button>
|
233 |
+
</div>
|
234 |
+
""")
|
235 |
+
|
236 |
+
# Add the JS login script
|
237 |
+
gr.HTML(js_login_script())
|
238 |
|
239 |
gr.Markdown("# 🏆 Dynamic Highscores", elem_classes=["header"])
|
240 |
gr.Markdown("""
|
|
|
271 |
app.load(
|
272 |
fn=check_user,
|
273 |
inputs=[],
|
274 |
+
outputs=[user_state]
|
275 |
)
|
276 |
|
277 |
+
# Launch the app
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
278 |
if __name__ == "__main__":
|
279 |
+
# Start queue worker in a separate thread
|
280 |
queue_thread = threading.Thread(target=start_queue_worker)
|
281 |
queue_thread.daemon = True
|
282 |
+
queue_thread.start()
|
283 |
+
|
284 |
+
app.launch()
|