NidhiS09 commited on
Commit
e109bb0
ยท
verified ยท
1 Parent(s): 2e20fa0

Update src/main.py

Browse files
Files changed (1) hide show
  1. src/main.py +402 -397
src/main.py CHANGED
@@ -1,399 +1,404 @@
1
- import os
2
- import json
3
- import uuid
4
- import time
5
- import tempfile
6
- from typing import Any, Dict, List, Tuple
7
-
8
  import streamlit as st
9
- import pandas as pd
10
- from PIL import Image
11
- from huggingface_hub import HfApi, hf_hub_download
12
- from huggingface_hub.utils import HfHubHTTPError
13
-
14
- print("Imported required functions")
15
- # =========================
16
- # CONFIG
17
- # =========================
18
-
19
- st.set_page_config(
20
- page_title="AI Benchmark Arena",
21
- page_icon="๐Ÿ†",
22
- layout="wide",
23
- initial_sidebar_state="expanded",
24
- )
25
- print("Config setup")
26
-
27
- #Set this to the private dataset repo that acts as the "database"
28
- DB_REPO_ID = os.getenv("DB_REPO_ID", "NidhiS09/VizWiz-submissions-db")
29
- DB_REPO_TYPE = "dataset"
30
- print(DB_REPO_ID)
31
-
32
-
33
- # This must exist as a Space Secret in the PUBLIC UI Space
34
- SUBMISSIONS_TOKEN = os.getenv("SUBMISSIONS_TOKEN", "")
35
- print("Token Acquired")
36
-
37
- # Phase config (copied from EvalAI config intent)
38
- PHASES = [
39
- {"label": "Dev (qeury-dev2024)", "codename": "test-dev2024"},
40
- {"label": "Standard (query-standard2024)", "codename": "test-standard2024"},
41
- {"label": "Challenge (query-challenge2024)", "codename": "test-challenge2024"},
42
- ]
43
-
44
- CHALLENGE_TYPES = ["Object Detection", "Instance Segmentation"]
45
-
46
- # Leaderboard columns from your EvalAI yaml
47
- LEADERBOARD_METRICS = ["bbox_mAP", "bbox_AP50", "segm_mAP", "segm_AP50"]
48
- DEFAULT_SORT_METRIC = "segm_AP50"
49
- print("Phases, challenge type and metrics setup")
50
- # =========================
51
- # HELPERS
52
- # =========================
53
-
54
- def _require_token() -> None:
55
- if not SUBMISSIONS_TOKEN:
56
- st.error(
57
- "Missing SUBMISSIONS_TOKEN. Add it in Space Settings โ†’ Secrets "
58
- "(token must have read/write access ONLY to the private DB dataset repo)."
59
- )
60
- st.stop()
61
-
62
-
63
- def _validate_submission_json(obj: Any) -> Tuple[bool, str]:
64
- """
65
- Validates the submission format from your instructions:
66
- - Top-level must be a list
67
- - Each item must be a dict containing:
68
- image_id (int), score (number), category_id (int), area (number),
69
- bbox ([x,y,w,h]), segmentation (list)
70
- """
71
- if not isinstance(obj, list):
72
- return False, "Submission must be a JSON list of annotations."
73
-
74
- required_keys = {"image_id", "score", "category_id", "area", "bbox", "segmentation"}
75
-
76
- for i, ann in enumerate(obj):
77
- if not isinstance(ann, dict):
78
- return False, f"Annotation at index {i} must be an object/dict."
79
-
80
- missing = required_keys - set(ann.keys())
81
- if missing:
82
- return False, f"Annotation at index {i} missing keys: {sorted(list(missing))}"
83
-
84
- # Basic type checks
85
- if not isinstance(ann["image_id"], int):
86
- return False, f"image_id at index {i} must be an integer."
87
- if not isinstance(ann["category_id"], int):
88
- return False, f"category_id at index {i} must be an integer."
89
-
90
- if not isinstance(ann["score"], (int, float)):
91
- return False, f"score at index {i} must be a number."
92
-
93
- if not isinstance(ann["area"], (int, float)):
94
- return False, f"area at index {i} must be a number."
95
-
96
- bbox = ann["bbox"]
97
- if not (isinstance(bbox, list) and len(bbox) == 4 and all(isinstance(x, (int, float)) for x in bbox)):
98
- return False, f"bbox at index {i} must be a list of 4 numbers: [x, y, w, h]."
99
-
100
- segm = ann["segmentation"]
101
- if not isinstance(segm, list):
102
- return False, f"segmentation at index {i} must be a list."
103
-
104
- return True, "OK"
105
-
106
-
107
- def _upload_json(api: HfApi, data: Dict[str, Any] | List[Any], path_in_repo: str) -> None:
108
- with tempfile.NamedTemporaryFile(mode="w", suffix=".json", delete=False) as tmp:
109
- json.dump(data, tmp, ensure_ascii=False)
110
- tmp_path = tmp.name
111
-
112
- try:
113
- api.upload_file(
114
- path_or_fileobj=tmp_path,
115
- path_in_repo=path_in_repo,
116
- repo_id=DB_REPO_ID,
117
- repo_type=DB_REPO_TYPE,
118
- token=SUBMISSIONS_TOKEN,
119
- commit_message=f"Add {path_in_repo}",
120
- )
121
- finally:
122
- try:
123
- os.remove(tmp_path)
124
- except OSError:
125
- pass
126
-
127
-
128
- def _create_submission_record(
129
- *,
130
- pred: List[Dict[str, Any]],
131
- team: str,
132
- model_name: str,
133
- phase_codename: str,
134
- challenge_type: str,
135
- original_filename: str,
136
- ) -> str:
137
- """
138
- Writes pred/meta/status to the private DB dataset repo.
139
- Returns submission_id.
140
- """
141
- _require_token()
142
- api = HfApi()
143
-
144
- submission_id = str(uuid.uuid4())
145
- ts = int(time.time())
146
-
147
- meta = {
148
- "submission_id": submission_id,
149
- "team": team.strip(),
150
- "model": model_name.strip(),
151
- "phase_codename": phase_codename,
152
- "challenge_type": challenge_type,
153
- "timestamp": ts,
154
- "original_filename": original_filename,
155
- }
156
-
157
- status = {"state": "queued", "timestamp": ts}
158
-
159
- base = f"submissions/{submission_id}"
160
- _upload_json(api, pred, f"{base}/pred.json")
161
- _upload_json(api, meta, f"{base}/meta.json")
162
- _upload_json(api, status, f"{base}/status.json")
163
-
164
- return submission_id
165
-
166
-
167
- def _download_leaderboard_jsonl() -> str | None:
168
- """
169
- Downloads leaderboard.jsonl from the DB repo.
170
- Returns local path or None if missing.
171
- """
172
- _require_token()
173
- try:
174
- return hf_hub_download(
175
- repo_id=DB_REPO_ID,
176
- repo_type=DB_REPO_TYPE,
177
- filename="leaderboard.jsonl",
178
- token=SUBMISSIONS_TOKEN,
179
- )
180
- except HfHubHTTPError as e:
181
- # Most common: 404 when file doesn't exist yet
182
- if "404" in str(e):
183
- return None
184
- raise
185
-
186
-
187
- def _load_leaderboard_df() -> pd.DataFrame:
188
- path = _download_leaderboard_jsonl()
189
- if path is None:
190
- return pd.DataFrame(columns=["team", "model", "phase_codename", *LEADERBOARD_METRICS, "timestamp"])
191
-
192
- rows = []
193
- with open(path, "r", encoding="utf-8") as f:
194
- for line in f:
195
- line = line.strip()
196
- if not line:
197
- continue
198
- try:
199
- rows.append(json.loads(line))
200
- except json.JSONDecodeError:
201
- # Skip malformed lines rather than crashing the UI
202
- continue
203
-
204
- if not rows:
205
- return pd.DataFrame(columns=["team", "model", "phase_codename", *LEADERBOARD_METRICS, "timestamp"])
206
-
207
- df = pd.DataFrame(rows)
208
-
209
- # Ensure columns exist
210
- for col in ["team", "model", "phase_codename", "timestamp", *LEADERBOARD_METRICS]:
211
- if col not in df.columns:
212
- df[col] = None
213
-
214
- # Sort descending by default metric
215
- if DEFAULT_SORT_METRIC in df.columns:
216
- df = df.sort_values(by=DEFAULT_SORT_METRIC, ascending=False, kind="mergesort")
217
-
218
- return df
219
-
220
-
221
- # =========================
222
- # UI
223
- # =========================
224
- #2 FUNCTIONS WERE HERE, RENDER_OVERVIEW AND RENDER EVAL
225
-
226
- def page_submit():
227
- st.header("๐Ÿš€ Submit your Predictions")
228
-
229
- col1, col2 = st.columns([2, 1])
230
-
231
- with col2:
232
- st.subheader("Submission Info")
233
- team = st.text_input("Team / Display Name", value=st.session_state.get("team", ""))
234
- model_name = st.text_input("Model Name", value=st.session_state.get("model_name", ""))
235
-
236
- phase_label = st.selectbox("Phase", [p["label"] for p in PHASES])
237
- phase_codename = next(p["codename"] for p in PHASES if p["label"] == phase_label)
238
-
239
- challenge_type = st.radio("Challenge type", CHALLENGE_TYPES, horizontal=False)
240
-
241
- st.session_state["team"] = team
242
- st.session_state["model_name"] = model_name
243
-
244
- st.caption("Your submission will be queued for evaluation. Scores appear on the leaderboard after processing.")
245
-
246
- with col1:
247
- st.subheader("Upload Submission File")
248
- uploaded_file = st.file_uploader("Choose a JSON file", type=["json"])
249
-
250
- if uploaded_file is None:
251
- st.info("Upload a JSON file that contains a list of annotations.")
252
- return
253
-
254
- # Parse JSON
255
- try:
256
- raw = uploaded_file.getvalue().decode("utf-8")
257
- pred_obj = json.loads(raw)
258
- except Exception:
259
- st.error("Could not parse JSON. Please upload a valid JSON file.")
260
- return
261
-
262
- ok, msg = _validate_submission_json(pred_obj)
263
- if not ok:
264
- st.error(f"Invalid submission format: {msg}")
265
- return
266
-
267
- st.success("Submission file looks valid โœ…")
268
-
269
- submit_clicked = st.button("Submit (Queue for Evaluation)", type="primary")
270
-
271
- if submit_clicked:
272
- if not team.strip():
273
- st.error("Please enter Team / Display Name.")
274
- return
275
- if not model_name.strip():
276
- st.error("Please enter Model Name.")
277
- return
278
-
279
- with st.spinner("Uploading submission to the private database repo..."):
280
- try:
281
- submission_id = _create_submission_record(
282
- pred=pred_obj,
283
- team=team,
284
- model_name=model_name,
285
- phase_codename=phase_codename,
286
- challenge_type=challenge_type,
287
- original_filename=uploaded_file.name,
288
- )
289
- except Exception as e:
290
- st.error(f"Upload failed: {e}")
291
- return
292
-
293
- st.balloons()
294
- st.success("Submission queued successfully!")
295
- st.code(f"Submission ID: {submission_id}")
296
-
297
- st.info("Next: the private evaluator will score your submission and update the leaderboard.")
298
-
299
-
300
- def page_leaderboard():
301
- st.header("๐Ÿ† Leaderboard")
302
- st.write(f"Ranked by **{DEFAULT_SORT_METRIC}** (descending).")
303
-
304
- with st.spinner("Loading leaderboard from private database repo..."):
305
- try:
306
- df = _load_leaderboard_df()
307
- except Exception as e:
308
- st.error(f"Could not load leaderboard: {e}")
309
- return
310
-
311
- if df.empty:
312
- st.info("No scored submissions yet. Submit a model to get started!")
313
- return
314
-
315
- # Add Rank column
316
- df_display = df.copy()
317
- df_display.insert(0, "Rank", range(1, len(df_display) + 1))
318
-
319
- # Optional: pretty timestamp
320
- if "timestamp" in df_display.columns:
321
- df_display["timestamp"] = pd.to_datetime(df_display["timestamp"], unit="s", errors="coerce")
322
-
323
- st.dataframe(
324
- df_display,
325
- column_config={
326
- "Rank": st.column_config.Column("Rank", width="small"),
327
- "team": "Team",
328
- "model": "Model",
329
- "phase_codename": "Phase",
330
- "bbox_mAP": st.column_config.NumberColumn("bbox_mAP", format="%.4f"),
331
- "bbox_AP50": st.column_config.NumberColumn("bbox_AP50", format="%.4f"),
332
- "segm_mAP": st.column_config.NumberColumn("segm_mAP", format="%.4f"),
333
- "segm_AP50": st.column_config.NumberColumn("segm_AP50", format="%.4f"),
334
- "timestamp": st.column_config.DatetimeColumn("Scored at", format="D MMM YYYY, h:mm a"),
335
- },
336
- use_container_width=True,
337
- hide_index=True,
338
- )
339
-
340
-
341
- def main():
342
-
343
- st.write("โœ… App booted and rendering UI")
 
 
 
 
 
 
 
 
 
 
 
 
344
 
345
- st.sidebar.title("AI Benchmark Arena ๐Ÿ†")
346
-
347
- # Warn early if DB repo isn't configured
348
- if DB_REPO_ID.startswith("NidhiS09/"):
349
- st.sidebar.warning("Set DB_REPO_ID env var or hardcode your private DB dataset repo id in main.py.")
350
-
351
- menu = ["Submit Model", "Leaderboard"]
352
- choice = st.sidebar.radio("Navigation", menu)
353
-
354
- st.sidebar.markdown("---")
355
- st.sidebar.caption("This Space queues submissions to a private DB repo and reads leaderboard results from it.")
356
-
357
- render_overview()
358
- render_eval_details()
359
- st.markdown("---")
360
-
361
- if choice == "Submit Model":
362
- page_submit()
363
- else:
364
- page_leaderboard()
365
-
366
- def render_overview():
367
- with st.expander("โ„น๏ธ Overview of the AI Benchmark Arena"):
368
- st.markdown(
369
- """
370
- **Note:** This Hugging Face Space queues submissions for evaluation and persists results in a private database repo.
371
- """
372
- )
373
- # Keep this optional so missing image doesn't crash the Space
374
- try:
375
- overview_image = Image.open("src/overview_image.png").resize((600, 600))
376
- st.image(overview_image, caption="Example of an object localization task")
377
- except Exception:
378
- st.info("Overview image not found at src/overview_image.png (optional).")
379
-
380
-
381
- def render_eval_details():
382
- with st.expander("๐Ÿ“ How is the Score Calculated?"):
383
- st.markdown(
384
- """
385
- Your submission is evaluated offline by a private evaluator against hidden ground-truth annotations.
386
- The leaderboard reports:
387
-
388
- - bbox_mAP
389
- - bbox_AP50
390
- - segm_mAP
391
- - segm_AP50 (default ranking)
392
-
393
- Raw submissions are kept private; only scores and metadata are shown.
394
- """
395
- )
396
-
397
-
398
- if __name__ == "__main__":
399
- main()
 
 
 
 
 
 
 
 
1
  import streamlit as st
2
+ st.write("hello")
3
+
4
+
5
+
6
+ # import os
7
+ # import json
8
+ # import uuid
9
+ # import time
10
+ # import tempfile
11
+ # from typing import Any, Dict, List, Tuple
12
+
13
+ # import streamlit as st
14
+ # import pandas as pd
15
+ # from PIL import Image
16
+ # from huggingface_hub import HfApi, hf_hub_download
17
+ # from huggingface_hub.utils import HfHubHTTPError
18
+
19
+ # print("Imported required functions")
20
+ # # =========================
21
+ # # CONFIG
22
+ # # =========================
23
+
24
+ # st.set_page_config(
25
+ # page_title="AI Benchmark Arena",
26
+ # page_icon="๐Ÿ†",
27
+ # layout="wide",
28
+ # initial_sidebar_state="expanded",
29
+ # )
30
+ # print("Config setup")
31
+
32
+ # #Set this to the private dataset repo that acts as the "database"
33
+ # DB_REPO_ID = os.getenv("DB_REPO_ID", "NidhiS09/VizWiz-submissions-db")
34
+ # DB_REPO_TYPE = "dataset"
35
+ # print(DB_REPO_ID)
36
+
37
+
38
+ # # This must exist as a Space Secret in the PUBLIC UI Space
39
+ # SUBMISSIONS_TOKEN = os.getenv("SUBMISSIONS_TOKEN", "")
40
+ # print("Token Acquired")
41
+
42
+ # # Phase config (copied from EvalAI config intent)
43
+ # PHASES = [
44
+ # {"label": "Dev (qeury-dev2024)", "codename": "test-dev2024"},
45
+ # {"label": "Standard (query-standard2024)", "codename": "test-standard2024"},
46
+ # {"label": "Challenge (query-challenge2024)", "codename": "test-challenge2024"},
47
+ # ]
48
+
49
+ # CHALLENGE_TYPES = ["Object Detection", "Instance Segmentation"]
50
+
51
+ # # Leaderboard columns from your EvalAI yaml
52
+ # LEADERBOARD_METRICS = ["bbox_mAP", "bbox_AP50", "segm_mAP", "segm_AP50"]
53
+ # DEFAULT_SORT_METRIC = "segm_AP50"
54
+ # print("Phases, challenge type and metrics setup")
55
+ # # =========================
56
+ # # HELPERS
57
+ # # =========================
58
+
59
+ # def _require_token() -> None:
60
+ # if not SUBMISSIONS_TOKEN:
61
+ # st.error(
62
+ # "Missing SUBMISSIONS_TOKEN. Add it in Space Settings โ†’ Secrets "
63
+ # "(token must have read/write access ONLY to the private DB dataset repo)."
64
+ # )
65
+ # st.stop()
66
+
67
+
68
+ # def _validate_submission_json(obj: Any) -> Tuple[bool, str]:
69
+ # """
70
+ # Validates the submission format from your instructions:
71
+ # - Top-level must be a list
72
+ # - Each item must be a dict containing:
73
+ # image_id (int), score (number), category_id (int), area (number),
74
+ # bbox ([x,y,w,h]), segmentation (list)
75
+ # """
76
+ # if not isinstance(obj, list):
77
+ # return False, "Submission must be a JSON list of annotations."
78
+
79
+ # required_keys = {"image_id", "score", "category_id", "area", "bbox", "segmentation"}
80
+
81
+ # for i, ann in enumerate(obj):
82
+ # if not isinstance(ann, dict):
83
+ # return False, f"Annotation at index {i} must be an object/dict."
84
+
85
+ # missing = required_keys - set(ann.keys())
86
+ # if missing:
87
+ # return False, f"Annotation at index {i} missing keys: {sorted(list(missing))}"
88
+
89
+ # # Basic type checks
90
+ # if not isinstance(ann["image_id"], int):
91
+ # return False, f"image_id at index {i} must be an integer."
92
+ # if not isinstance(ann["category_id"], int):
93
+ # return False, f"category_id at index {i} must be an integer."
94
+
95
+ # if not isinstance(ann["score"], (int, float)):
96
+ # return False, f"score at index {i} must be a number."
97
+
98
+ # if not isinstance(ann["area"], (int, float)):
99
+ # return False, f"area at index {i} must be a number."
100
+
101
+ # bbox = ann["bbox"]
102
+ # if not (isinstance(bbox, list) and len(bbox) == 4 and all(isinstance(x, (int, float)) for x in bbox)):
103
+ # return False, f"bbox at index {i} must be a list of 4 numbers: [x, y, w, h]."
104
+
105
+ # segm = ann["segmentation"]
106
+ # if not isinstance(segm, list):
107
+ # return False, f"segmentation at index {i} must be a list."
108
+
109
+ # return True, "OK"
110
+
111
+
112
+ # def _upload_json(api: HfApi, data: Dict[str, Any] | List[Any], path_in_repo: str) -> None:
113
+ # with tempfile.NamedTemporaryFile(mode="w", suffix=".json", delete=False) as tmp:
114
+ # json.dump(data, tmp, ensure_ascii=False)
115
+ # tmp_path = tmp.name
116
+
117
+ # try:
118
+ # api.upload_file(
119
+ # path_or_fileobj=tmp_path,
120
+ # path_in_repo=path_in_repo,
121
+ # repo_id=DB_REPO_ID,
122
+ # repo_type=DB_REPO_TYPE,
123
+ # token=SUBMISSIONS_TOKEN,
124
+ # commit_message=f"Add {path_in_repo}",
125
+ # )
126
+ # finally:
127
+ # try:
128
+ # os.remove(tmp_path)
129
+ # except OSError:
130
+ # pass
131
+
132
+
133
+ # def _create_submission_record(
134
+ # *,
135
+ # pred: List[Dict[str, Any]],
136
+ # team: str,
137
+ # model_name: str,
138
+ # phase_codename: str,
139
+ # challenge_type: str,
140
+ # original_filename: str,
141
+ # ) -> str:
142
+ # """
143
+ # Writes pred/meta/status to the private DB dataset repo.
144
+ # Returns submission_id.
145
+ # """
146
+ # _require_token()
147
+ # api = HfApi()
148
+
149
+ # submission_id = str(uuid.uuid4())
150
+ # ts = int(time.time())
151
+
152
+ # meta = {
153
+ # "submission_id": submission_id,
154
+ # "team": team.strip(),
155
+ # "model": model_name.strip(),
156
+ # "phase_codename": phase_codename,
157
+ # "challenge_type": challenge_type,
158
+ # "timestamp": ts,
159
+ # "original_filename": original_filename,
160
+ # }
161
+
162
+ # status = {"state": "queued", "timestamp": ts}
163
+
164
+ # base = f"submissions/{submission_id}"
165
+ # _upload_json(api, pred, f"{base}/pred.json")
166
+ # _upload_json(api, meta, f"{base}/meta.json")
167
+ # _upload_json(api, status, f"{base}/status.json")
168
+
169
+ # return submission_id
170
+
171
+
172
+ # def _download_leaderboard_jsonl() -> str | None:
173
+ # """
174
+ # Downloads leaderboard.jsonl from the DB repo.
175
+ # Returns local path or None if missing.
176
+ # """
177
+ # _require_token()
178
+ # try:
179
+ # return hf_hub_download(
180
+ # repo_id=DB_REPO_ID,
181
+ # repo_type=DB_REPO_TYPE,
182
+ # filename="leaderboard.jsonl",
183
+ # token=SUBMISSIONS_TOKEN,
184
+ # )
185
+ # except HfHubHTTPError as e:
186
+ # # Most common: 404 when file doesn't exist yet
187
+ # if "404" in str(e):
188
+ # return None
189
+ # raise
190
+
191
+
192
+ # def _load_leaderboard_df() -> pd.DataFrame:
193
+ # path = _download_leaderboard_jsonl()
194
+ # if path is None:
195
+ # return pd.DataFrame(columns=["team", "model", "phase_codename", *LEADERBOARD_METRICS, "timestamp"])
196
+
197
+ # rows = []
198
+ # with open(path, "r", encoding="utf-8") as f:
199
+ # for line in f:
200
+ # line = line.strip()
201
+ # if not line:
202
+ # continue
203
+ # try:
204
+ # rows.append(json.loads(line))
205
+ # except json.JSONDecodeError:
206
+ # # Skip malformed lines rather than crashing the UI
207
+ # continue
208
+
209
+ # if not rows:
210
+ # return pd.DataFrame(columns=["team", "model", "phase_codename", *LEADERBOARD_METRICS, "timestamp"])
211
+
212
+ # df = pd.DataFrame(rows)
213
+
214
+ # # Ensure columns exist
215
+ # for col in ["team", "model", "phase_codename", "timestamp", *LEADERBOARD_METRICS]:
216
+ # if col not in df.columns:
217
+ # df[col] = None
218
+
219
+ # # Sort descending by default metric
220
+ # if DEFAULT_SORT_METRIC in df.columns:
221
+ # df = df.sort_values(by=DEFAULT_SORT_METRIC, ascending=False, kind="mergesort")
222
+
223
+ # return df
224
+
225
+
226
+ # # =========================
227
+ # # UI
228
+ # # =========================
229
+ # #2 FUNCTIONS WERE HERE, RENDER_OVERVIEW AND RENDER EVAL
230
+
231
+ # def page_submit():
232
+ # st.header("๐Ÿš€ Submit your Predictions")
233
+
234
+ # col1, col2 = st.columns([2, 1])
235
+
236
+ # with col2:
237
+ # st.subheader("Submission Info")
238
+ # team = st.text_input("Team / Display Name", value=st.session_state.get("team", ""))
239
+ # model_name = st.text_input("Model Name", value=st.session_state.get("model_name", ""))
240
+
241
+ # phase_label = st.selectbox("Phase", [p["label"] for p in PHASES])
242
+ # phase_codename = next(p["codename"] for p in PHASES if p["label"] == phase_label)
243
+
244
+ # challenge_type = st.radio("Challenge type", CHALLENGE_TYPES, horizontal=False)
245
+
246
+ # st.session_state["team"] = team
247
+ # st.session_state["model_name"] = model_name
248
+
249
+ # st.caption("Your submission will be queued for evaluation. Scores appear on the leaderboard after processing.")
250
+
251
+ # with col1:
252
+ # st.subheader("Upload Submission File")
253
+ # uploaded_file = st.file_uploader("Choose a JSON file", type=["json"])
254
+
255
+ # if uploaded_file is None:
256
+ # st.info("Upload a JSON file that contains a list of annotations.")
257
+ # return
258
+
259
+ # # Parse JSON
260
+ # try:
261
+ # raw = uploaded_file.getvalue().decode("utf-8")
262
+ # pred_obj = json.loads(raw)
263
+ # except Exception:
264
+ # st.error("Could not parse JSON. Please upload a valid JSON file.")
265
+ # return
266
+
267
+ # ok, msg = _validate_submission_json(pred_obj)
268
+ # if not ok:
269
+ # st.error(f"Invalid submission format: {msg}")
270
+ # return
271
+
272
+ # st.success("Submission file looks valid โœ…")
273
+
274
+ # submit_clicked = st.button("Submit (Queue for Evaluation)", type="primary")
275
+
276
+ # if submit_clicked:
277
+ # if not team.strip():
278
+ # st.error("Please enter Team / Display Name.")
279
+ # return
280
+ # if not model_name.strip():
281
+ # st.error("Please enter Model Name.")
282
+ # return
283
+
284
+ # with st.spinner("Uploading submission to the private database repo..."):
285
+ # try:
286
+ # submission_id = _create_submission_record(
287
+ # pred=pred_obj,
288
+ # team=team,
289
+ # model_name=model_name,
290
+ # phase_codename=phase_codename,
291
+ # challenge_type=challenge_type,
292
+ # original_filename=uploaded_file.name,
293
+ # )
294
+ # except Exception as e:
295
+ # st.error(f"Upload failed: {e}")
296
+ # return
297
+
298
+ # st.balloons()
299
+ # st.success("Submission queued successfully!")
300
+ # st.code(f"Submission ID: {submission_id}")
301
+
302
+ # st.info("Next: the private evaluator will score your submission and update the leaderboard.")
303
+
304
+
305
+ # def page_leaderboard():
306
+ # st.header("๐Ÿ† Leaderboard")
307
+ # st.write(f"Ranked by **{DEFAULT_SORT_METRIC}** (descending).")
308
+
309
+ # with st.spinner("Loading leaderboard from private database repo..."):
310
+ # try:
311
+ # df = _load_leaderboard_df()
312
+ # except Exception as e:
313
+ # st.error(f"Could not load leaderboard: {e}")
314
+ # return
315
+
316
+ # if df.empty:
317
+ # st.info("No scored submissions yet. Submit a model to get started!")
318
+ # return
319
+
320
+ # # Add Rank column
321
+ # df_display = df.copy()
322
+ # df_display.insert(0, "Rank", range(1, len(df_display) + 1))
323
+
324
+ # # Optional: pretty timestamp
325
+ # if "timestamp" in df_display.columns:
326
+ # df_display["timestamp"] = pd.to_datetime(df_display["timestamp"], unit="s", errors="coerce")
327
+
328
+ # st.dataframe(
329
+ # df_display,
330
+ # column_config={
331
+ # "Rank": st.column_config.Column("Rank", width="small"),
332
+ # "team": "Team",
333
+ # "model": "Model",
334
+ # "phase_codename": "Phase",
335
+ # "bbox_mAP": st.column_config.NumberColumn("bbox_mAP", format="%.4f"),
336
+ # "bbox_AP50": st.column_config.NumberColumn("bbox_AP50", format="%.4f"),
337
+ # "segm_mAP": st.column_config.NumberColumn("segm_mAP", format="%.4f"),
338
+ # "segm_AP50": st.column_config.NumberColumn("segm_AP50", format="%.4f"),
339
+ # "timestamp": st.column_config.DatetimeColumn("Scored at", format="D MMM YYYY, h:mm a"),
340
+ # },
341
+ # use_container_width=True,
342
+ # hide_index=True,
343
+ # )
344
+
345
+
346
+ # def main():
347
+
348
+ # st.write("โœ… App booted and rendering UI")
349
 
350
+ # st.sidebar.title("AI Benchmark Arena ๐Ÿ†")
351
+
352
+ # # Warn early if DB repo isn't configured
353
+ # if DB_REPO_ID.startswith("NidhiS09/"):
354
+ # st.sidebar.warning("Set DB_REPO_ID env var or hardcode your private DB dataset repo id in main.py.")
355
+
356
+ # menu = ["Submit Model", "Leaderboard"]
357
+ # choice = st.sidebar.radio("Navigation", menu)
358
+
359
+ # st.sidebar.markdown("---")
360
+ # st.sidebar.caption("This Space queues submissions to a private DB repo and reads leaderboard results from it.")
361
+
362
+ # render_overview()
363
+ # render_eval_details()
364
+ # st.markdown("---")
365
+
366
+ # if choice == "Submit Model":
367
+ # page_submit()
368
+ # else:
369
+ # page_leaderboard()
370
+
371
+ # def render_overview():
372
+ # with st.expander("โ„น๏ธ Overview of the AI Benchmark Arena"):
373
+ # st.markdown(
374
+ # """
375
+ # **Note:** This Hugging Face Space queues submissions for evaluation and persists results in a private database repo.
376
+ # """
377
+ # )
378
+ # # Keep this optional so missing image doesn't crash the Space
379
+ # try:
380
+ # overview_image = Image.open("src/overview_image.png").resize((600, 600))
381
+ # st.image(overview_image, caption="Example of an object localization task")
382
+ # except Exception:
383
+ # st.info("Overview image not found at src/overview_image.png (optional).")
384
+
385
+
386
+ # def render_eval_details():
387
+ # with st.expander("๐Ÿ“ How is the Score Calculated?"):
388
+ # st.markdown(
389
+ # """
390
+ # Your submission is evaluated offline by a private evaluator against hidden ground-truth annotations.
391
+ # The leaderboard reports:
392
+
393
+ # - bbox_mAP
394
+ # - bbox_AP50
395
+ # - segm_mAP
396
+ # - segm_AP50 (default ranking)
397
+
398
+ # Raw submissions are kept private; only scores and metadata are shown.
399
+ # """
400
+ # )
401
+
402
+
403
+ # if __name__ == "__main__":
404
+ # main()