Maharshi Gor commited on
Commit
60ece04
·
1 Parent(s): 4e77918

Registration page

Browse files
Files changed (5) hide show
  1. README.md +1 -1
  2. app.py +286 -0
  3. envs.py +26 -0
  4. formatting.py +33 -0
  5. signup.py +8 -0
README.md CHANGED
@@ -1,5 +1,5 @@
1
  ---
2
- title: Register
3
  emoji: 🦀
4
  colorFrom: yellow
5
  colorTo: indigo
 
1
  ---
2
+ title: QANTA 2025 Registration
3
  emoji: 🦀
4
  colorFrom: yellow
5
  colorTo: indigo
app.py ADDED
@@ -0,0 +1,286 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ from datetime import datetime, timezone
3
+ from pathlib import Path
4
+
5
+ import gradio as gr
6
+ from huggingface_hub import snapshot_download
7
+ from loguru import logger
8
+ from pydantic import BaseModel, Field
9
+
10
+ from envs import API, REPO_ID, USERS_PATH, USERS_REPO
11
+ from formatting import styled_error, styled_message, styled_warning
12
+
13
+ css = """
14
+ :root {
15
+ color-scheme: light !important;
16
+ --block-border-width: 0 !important;
17
+ --section-header-text-weight: 600 !important;
18
+ --section-header-text-size: 14px !important;
19
+ --input-radius: var(--radius-xl) !important;
20
+ --font-mono: "Space Mono", monospace !important;
21
+ --text-sm: 12px !important;
22
+ --text-md: 14px !important;
23
+ --text-lg: 16px !important;
24
+ --input-text-size: var(--text-sm) !important;
25
+ --body-text-size: 14px !important;
26
+ --input-background-fill-focus: var(--secondary-300) !important;
27
+
28
+ // Button Colors
29
+ --button-primary-background-fill: var(--primary-800) !important;
30
+ --button-secondary-background-fill: var(--secondary-600) !important;
31
+ --checkbox-label-text-color: var(--body-text-color) !important;
32
+
33
+
34
+ --card-bg-color: #fcecd4;
35
+ --card-btn-color: #D4E4FC;
36
+ --card-btn-color-hover: #7DAEF6;
37
+ --answer-bg-color: #f0f8ff;
38
+ --hover-border-color: #121212;
39
+ }
40
+
41
+ :root .dark {
42
+ color-scheme: dark !important;
43
+ --block-border-width: 0 !important;
44
+ --section-header-text-weight: 600 !important;
45
+ --section-header-text-size: 14px !important;
46
+ --input-radius: var(--radius-xl) !important;
47
+ --font-mono: "Space Mono", monospace !important;
48
+ --text-sm: 12px !important;
49
+ --text-md: 14px !important;
50
+ --text-lg: 16px !important;
51
+ --input-text-size: var(--text-sm) !important;
52
+ --body-text-size: 14px !important;
53
+
54
+ --button-primary-background-fill: var(--neutral-100) !important;
55
+ --button-secondary-background-fill: var(--secondary-300) !important;
56
+ --button-primary-text-color: black !important;
57
+ --button-secondary-text-color: black !important;
58
+ --checkbox-label-text-color: var(--body-text-color) !important;
59
+
60
+ --card-bg-color: #383127;
61
+ --answer-bg-color: #1a2b3c;
62
+ --hover-border-color: #ffffff;
63
+ }
64
+
65
+ .gradio-app {
66
+
67
+ }
68
+ .warning-header {
69
+ color: red;
70
+ }
71
+
72
+ .neutral-header {
73
+ color: blue;
74
+ }
75
+
76
+ .success-header {
77
+ color: green;
78
+ }
79
+
80
+ .gradio-container {
81
+ max-width: 1000px;
82
+ margin: 0 auto;
83
+ padding: 0 8px;
84
+ }
85
+ """
86
+
87
+
88
+ def restart_space():
89
+ API.restart_space(repo_id=REPO_ID)
90
+
91
+
92
+ def download_dataset_snapshot(repo_id, local_dir):
93
+ try:
94
+ logger.info(f"Downloading dataset snapshot from {repo_id} to {local_dir}")
95
+ snapshot_download(
96
+ repo_id=repo_id,
97
+ local_dir=local_dir,
98
+ repo_type="dataset",
99
+ tqdm_class=None,
100
+ )
101
+ except Exception as e:
102
+ logger.error(
103
+ f"Error downloading dataset snapshot from {repo_id} to {local_dir}: {e}. Restarting space."
104
+ )
105
+ API.restart_space(repo_id=repo_id)
106
+
107
+
108
+ download_dataset_snapshot(USERS_REPO, USERS_PATH)
109
+
110
+
111
+ class User(BaseModel):
112
+ """
113
+ Represents a user in the competition system, formatted for HuggingFace datasets.
114
+ """
115
+
116
+ username: str = Field(description="HuggingFace username of the user")
117
+ name: str = Field(description="Full name of the user")
118
+ email: str = Field(description="Contact email of the user")
119
+ affiliation: str = Field(description="Affiliation of the user")
120
+
121
+
122
+ def create_user(
123
+ username: str,
124
+ name: str,
125
+ email: str,
126
+ affiliation: str,
127
+ profile: gr.OAuthProfile | None,
128
+ ) -> User:
129
+ """
130
+ Create a user for a tossup model.
131
+
132
+ Args:
133
+ name: Display name of the submission
134
+ description: Detailed description of what the submission does
135
+ user_email: Email of the user who created the submission
136
+ workflow: The workflow configuration for the tossup model
137
+
138
+ Returns:
139
+ Submission object if successful, None if validation fails
140
+ """
141
+ # Create the submission
142
+ dt = datetime.now(timezone.utc)
143
+ submission = User(
144
+ username=username,
145
+ name=name,
146
+ email=email,
147
+ affiliation=affiliation,
148
+ created_at=dt.isoformat(),
149
+ )
150
+
151
+ return submission
152
+
153
+
154
+ def get_user(username: str) -> User | None:
155
+ """
156
+ Get a user from the registered users dataset.
157
+ """
158
+ out_path = Path(f"{USERS_PATH}/{username}.json")
159
+ if not out_path.exists():
160
+ return None
161
+ with out_path.open("r") as f:
162
+ user_dict = json.load(f)
163
+ return User.model_validate(user_dict)
164
+
165
+
166
+ def is_user_logged_in(profile: gr.OAuthProfile | None) -> bool:
167
+ """
168
+ Check if a user is logged in.
169
+ """
170
+ return profile is not None
171
+
172
+
173
+ def user_signup(
174
+ name: str,
175
+ email: str,
176
+ affiliation: str,
177
+ profile: gr.OAuthProfile | None = None,
178
+ ) -> User:
179
+ """
180
+ Sign up for the competition.
181
+ """
182
+ if profile is None:
183
+ return styled_error(
184
+ "Please sign in using your HuggingFace account to register for the competition."
185
+ )
186
+ try:
187
+ username = profile.username
188
+ user = get_user(username)
189
+ new_user = create_user(
190
+ username=username,
191
+ name=name,
192
+ email=email,
193
+ affiliation=affiliation,
194
+ profile=profile,
195
+ )
196
+ # Convert to dictionary format
197
+ user_dict = new_user.model_dump()
198
+
199
+ # Upload to HuggingFace dataset
200
+ updated = bool(user)
201
+ API.upload_file(
202
+ path_or_fileobj=json.dumps(user_dict, indent=2).encode(),
203
+ path_in_repo=f"{username}.json",
204
+ repo_id=USERS_REPO,
205
+ repo_type="dataset",
206
+ commit_message=f"{'Update' if updated else 'Add'} user {username}",
207
+ )
208
+
209
+ return styled_message(
210
+ f"Successfully {'updated' if updated else 'registered'} user {username} for the competition!<br>"
211
+ )
212
+
213
+ except Exception as e:
214
+ logger.exception(e)
215
+ return styled_error(
216
+ "Error registering for the competition. Please try again later, or contact the organizers at <br><a href='mailto:[email protected]'>[email protected]</a>."
217
+ )
218
+
219
+
220
+ def load_user_info(profile: gr.OAuthProfile | None):
221
+ if profile is None:
222
+ return (
223
+ gr.update(interactive=False),
224
+ gr.update(interactive=False),
225
+ gr.update(interactive=False),
226
+ gr.update(interactive=False),
227
+ gr.update(
228
+ value="<h2 class='warning-header'>Please sign in using your HuggingFace account to register for the competition.</h2>",
229
+ ),
230
+ )
231
+ user = get_user(profile.username)
232
+ if user is None:
233
+ return (
234
+ gr.update(interactive=True),
235
+ gr.update(interactive=True),
236
+ gr.update(interactive=True),
237
+ gr.update(interactive=True, value="Register"),
238
+ gr.update(
239
+ value="<h2 class='neutral-header'>Fill in your details below to register for the competition.</h2>",
240
+ ),
241
+ )
242
+ return (
243
+ gr.update(interactive=True, value=user.name),
244
+ gr.update(interactive=True, value=user.email),
245
+ gr.update(interactive=True, value=user.affiliation),
246
+ gr.update(interactive=True, value="Update Information"),
247
+ gr.update(
248
+ value="<h2 class='success-header'>You are already registered! You can update your details below.</h2>",
249
+ ),
250
+ )
251
+
252
+
253
+ with gr.Blocks(
254
+ title="Register - QANTA 2025 Quizbowl System Submission", css=css
255
+ ) as demo:
256
+ gr.Markdown("# Register for QANTA 2025 Quizbowl System Submission")
257
+ with gr.Row():
258
+ with gr.Column():
259
+ # HuggingFace Login Button
260
+ hf_login_btn = gr.LoginButton(scale=1)
261
+ header = gr.HTML("<h2>Fill in your details below</h2>")
262
+
263
+ # Registration form
264
+ name = gr.Textbox(label="Full Name", placeholder="Enter your full name")
265
+ email = gr.Textbox(label="Contact Email", placeholder="Enter your email")
266
+ affiliation = gr.Textbox(
267
+ label="Affiliation",
268
+ placeholder="Enter your organization or institution",
269
+ )
270
+
271
+ submit_btn = gr.Button("Register")
272
+ status = gr.Markdown()
273
+
274
+ submit_btn.click(
275
+ fn=user_signup,
276
+ inputs=[name, email, affiliation],
277
+ outputs=[status],
278
+ )
279
+
280
+ demo.load(
281
+ load_user_info,
282
+ inputs=[],
283
+ outputs=[name, email, affiliation, submit_btn, header],
284
+ )
285
+
286
+ demo.queue(default_concurrency_limit=40).launch()
envs.py ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+
3
+ from huggingface_hub import HfApi
4
+
5
+ # Info to change for your repository
6
+ # ----------------------------------
7
+ TOKEN = os.environ.get("HF_TOKEN") # A read/write token for your org
8
+
9
+ # Change to your org - don't forget to create a results and request dataset, with the correct format!
10
+ OWNER = "qanta-challenge"
11
+
12
+ REPO_ID = f"{OWNER}/register"
13
+ USERS_REPO = f"{OWNER}/registered-users"
14
+
15
+ DOCS_REPO_URL = "https://github.com/qanta-challenge/QANTA25"
16
+ DOCS_REPO_BRANCH = "main"
17
+
18
+
19
+ # If you setup a cache later, just change HF_HOME
20
+ CACHE_PATH = os.getenv("HF_HOME", ".")
21
+
22
+ # Local caches
23
+ USERS_PATH = os.path.join(CACHE_PATH, "registered-users")
24
+
25
+
26
+ API = HfApi(token=TOKEN)
formatting.py ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ def model_hyperlink(link, model_name):
2
+ return f'<a target="_blank" href="{link}" style="color: var(--link-text-color); text-decoration: underline;text-decoration-style: dotted;">{model_name}</a>'
3
+
4
+
5
+ def make_clickable_model(model_name):
6
+ link = f"https://huggingface.co/{model_name}"
7
+ return model_hyperlink(link, model_name)
8
+
9
+
10
+ def styled_error(error):
11
+ return f"<p style='color: red; font-size: 20px; text-align: center;'>{error}</p>"
12
+
13
+
14
+ def styled_warning(warn):
15
+ return f"<p style='color: orange; font-size: 20px; text-align: center;'>{warn}</p>"
16
+
17
+
18
+ def tiny_styled_warning(warn):
19
+ return f"<div class='md' style='color: crimson; font-size: 12px; text-align: left;'>{warn}</div>"
20
+
21
+
22
+ def styled_message(message):
23
+ return (
24
+ f"<p style='color: green; font-size: 20px; text-align: center;'>{message}</p>"
25
+ )
26
+
27
+
28
+ def has_no_nan_values(df, columns):
29
+ return df[columns].notna().all(axis=1)
30
+
31
+
32
+ def has_nan_values(df, columns):
33
+ return df[columns].isna().any(axis=1)
signup.py ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ from datetime import datetime, timezone
3
+
4
+ import gradio as gr
5
+ from pydantic import BaseModel, Field
6
+
7
+ from envs import API, USERS_REPO
8
+ from formatting import styled_error, styled_message, styled_warning