register / app.py
Maharshi Gor
Added environment packages and repo formatting configs
8037dc7
import json
from datetime import datetime, timezone
from pathlib import Path
import gradio as gr
from huggingface_hub import snapshot_download
from loguru import logger
from pydantic import BaseModel, Field
from envs import API, REPO_ID, USERS_PATH, USERS_REPO
from formatting import styled_error, styled_message, styled_warning
css = """
:root {
color-scheme: light !important;
--block-border-width: 0 !important;
--section-header-text-weight: 600 !important;
--section-header-text-size: 14px !important;
--input-radius: var(--radius-xl) !important;
--font-mono: "Space Mono", monospace !important;
--text-sm: 12px !important;
--text-md: 14px !important;
--text-lg: 16px !important;
--input-text-size: var(--text-sm) !important;
--body-text-size: 14px !important;
--input-background-fill-focus: var(--secondary-300) !important;
// Button Colors
--button-primary-background-fill: var(--primary-800) !important;
--button-secondary-background-fill: var(--secondary-600) !important;
--checkbox-label-text-color: var(--body-text-color) !important;
--card-bg-color: #fcecd4;
--card-btn-color: #D4E4FC;
--card-btn-color-hover: #7DAEF6;
--answer-bg-color: #f0f8ff;
--hover-border-color: #121212;
}
:root .dark {
color-scheme: dark !important;
--block-border-width: 0 !important;
--section-header-text-weight: 600 !important;
--section-header-text-size: 14px !important;
--input-radius: var(--radius-xl) !important;
--font-mono: "Space Mono", monospace !important;
--text-sm: 12px !important;
--text-md: 14px !important;
--text-lg: 16px !important;
--input-text-size: var(--text-sm) !important;
--body-text-size: 14px !important;
--button-primary-background-fill: var(--neutral-100) !important;
--button-secondary-background-fill: var(--secondary-300) !important;
--button-primary-text-color: black !important;
--button-secondary-text-color: black !important;
--checkbox-label-text-color: var(--body-text-color) !important;
--card-bg-color: #383127;
--answer-bg-color: #1a2b3c;
--hover-border-color: #ffffff;
}
.gradio-app {
}
.warning-header {
color: red;
}
.neutral-header {
color: blue;
}
.success-header {
color: green;
}
.gradio-container {
max-width: 1000px;
margin: 0 auto;
padding: 0 8px;
}
"""
def restart_space():
API.restart_space(repo_id=REPO_ID)
def download_dataset_snapshot(repo_id, local_dir):
try:
logger.info(f"Downloading dataset snapshot from {repo_id} to {local_dir}")
snapshot_download(
repo_id=repo_id,
local_dir=local_dir,
repo_type="dataset",
tqdm_class=None,
)
except Exception as e:
logger.error(f"Error downloading dataset snapshot from {repo_id} to {local_dir}: {e}. Restarting space.")
API.restart_space(repo_id=repo_id)
download_dataset_snapshot(USERS_REPO, USERS_PATH)
class User(BaseModel):
"""
Represents a user in the competition system, formatted for HuggingFace datasets.
"""
username: str = Field(description="HuggingFace username of the user")
name: str = Field(description="Full name of the user")
email: str = Field(description="Contact email of the user")
affiliation: str = Field(description="Affiliation of the user")
def create_user(
username: str,
name: str,
email: str,
affiliation: str,
profile: gr.OAuthProfile | None,
) -> User:
"""
Create a user for a tossup model.
Args:
name: Display name of the submission
description: Detailed description of what the submission does
user_email: Email of the user who created the submission
workflow: The workflow configuration for the tossup model
Returns:
Submission object if successful, None if validation fails
"""
# Create the submission
dt = datetime.now(timezone.utc)
submission = User(
username=username,
name=name,
email=email,
affiliation=affiliation,
created_at=dt.isoformat(),
)
return submission
def get_user(username: str) -> User | None:
"""
Get a user from the registered users dataset.
"""
out_path = Path(f"{USERS_PATH}/{username}.json")
if not out_path.exists():
return None
with out_path.open("r") as f:
user_dict = json.load(f)
return User.model_validate(user_dict)
def is_user_logged_in(profile: gr.OAuthProfile | None) -> bool:
"""
Check if a user is logged in.
"""
return profile is not None
def user_signup(
name: str,
email: str,
affiliation: str,
profile: gr.OAuthProfile | None = None,
) -> User:
"""
Sign up for the competition.
"""
if profile is None:
return styled_error("Please sign in using your HuggingFace account to register for the competition.")
try:
username = profile.username
user = get_user(username)
new_user = create_user(
username=username,
name=name,
email=email,
affiliation=affiliation,
profile=profile,
)
# Convert to dictionary format
user_dict = new_user.model_dump()
# Upload to HuggingFace dataset
updated = bool(user)
API.upload_file(
path_or_fileobj=json.dumps(user_dict, indent=2).encode(),
path_in_repo=f"{username}.json",
repo_id=USERS_REPO,
repo_type="dataset",
commit_message=f"{'Update' if updated else 'Add'} user {username}",
)
return styled_message(
f"Successfully {'updated' if updated else 'registered'} user {username} for the competition!<br>"
)
except Exception as e:
logger.exception(e)
return styled_error(
"Error registering for the competition. Please try again later, or contact the organizers at <br><a href='mailto:[email protected]'>[email protected]</a>."
)
def load_user_info(profile: gr.OAuthProfile | None):
if profile is None:
return (
gr.update(interactive=False),
gr.update(interactive=False),
gr.update(interactive=False),
gr.update(interactive=False),
gr.update(
value="<h2 class='warning-header'>Please sign in using your HuggingFace account to register for the competition.</h2>",
),
)
user = get_user(profile.username)
if user is None:
return (
gr.update(interactive=True),
gr.update(interactive=True),
gr.update(interactive=True),
gr.update(interactive=True, value="Register"),
gr.update(
value="<h2 class='neutral-header'>Fill in your details below to register for the competition.</h2>",
),
)
return (
gr.update(interactive=True, value=user.name),
gr.update(interactive=True, value=user.email),
gr.update(interactive=True, value=user.affiliation),
gr.update(interactive=True, value="Update Information"),
gr.update(
value="<h2 class='success-header'>You are already registered! You can update your details below.</h2>",
),
)
with gr.Blocks(title="Register - QANTA 2025 Quizbowl System Submission", css=css) as demo:
gr.Markdown("# Register for QANTA 2025 Quizbowl System Submission")
with gr.Row():
with gr.Column():
# HuggingFace Login Button
hf_login_btn = gr.LoginButton(scale=1)
header = gr.HTML("<h2>Fill in your details below</h2>")
# Registration form
name = gr.Textbox(label="Full Name", placeholder="Enter your full name")
email = gr.Textbox(label="Contact Email", placeholder="Enter your email")
affiliation = gr.Textbox(
label="Affiliation",
placeholder="Enter your organization or institution",
)
submit_btn = gr.Button("Register")
status = gr.Markdown()
submit_btn.click(
fn=user_signup,
inputs=[name, email, affiliation],
outputs=[status],
)
demo.load(
load_user_info,
inputs=[],
outputs=[name, email, affiliation, submit_btn, header],
)
demo.queue(default_concurrency_limit=40).launch()