TimWindecker commited on
Commit
ed7d966
·
verified ·
1 Parent(s): 358e037

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +242 -132
src/streamlit_app.py CHANGED
@@ -8,71 +8,118 @@ import json
8
  # Page config
9
  st.set_page_config(
10
  page_title="NaviTrace Leaderboard",
11
- page_icon="🧭",
12
- layout="wide",
13
  initial_sidebar_state="collapsed"
14
  )
15
 
16
  # Custom CSS for Nerfies-style design
17
  st.markdown("""
18
  <style>
 
 
 
 
 
 
 
 
 
19
  /* Main title styling */
20
  .main-title {
21
  text-align: center;
22
- font-size: 3.5rem;
23
  font-weight: 700;
24
- margin-top: 2rem;
25
- margin-bottom: 1rem;
26
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
27
- -webkit-background-clip: text;
28
- -webkit-text-fill-color: transparent;
29
- background-clip: text;
30
  }
31
 
32
- /* Links container */
33
- .links-container {
34
- text-align: center;
 
 
35
  margin-bottom: 3rem;
36
- font-size: 1.1rem;
37
  }
38
 
39
- .links-container a {
40
- margin: 0 1rem;
 
 
 
 
 
 
41
  text-decoration: none;
42
- color: #667eea;
43
- font-weight: 600;
44
- transition: color 0.3s;
 
45
  }
46
 
47
- .links-container a:hover {
48
- color: #764ba2;
 
 
 
 
 
 
 
 
49
  }
50
 
51
  /* Section headers */
52
  .section-header {
53
- font-size: 2rem;
54
  font-weight: 600;
55
- margin-top: 2rem;
56
- margin-bottom: 1rem;
57
  color: #333;
58
  }
59
 
60
- /* Instructions box */
61
- .instructions-box {
62
- background: linear-gradient(135deg, #667eea15 0%, #764ba215 100%);
63
- border-left: 4px solid #667eea;
64
- padding: 2rem;
65
- border-radius: 8px;
66
  margin: 2rem 0;
 
67
  }
68
 
69
- .instruction-step {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
  font-size: 1.1rem;
71
- margin: 1rem 0;
72
- padding-left: 1.5rem;
 
 
 
 
 
 
73
  }
74
 
75
- /* Button styling */
76
  .stButton>button {
77
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
78
  color: white;
@@ -92,15 +139,16 @@ st.markdown("""
92
  #MainMenu {visibility: hidden;}
93
  footer {visibility: hidden;}
94
 
95
- /* Tab styling */
96
- .stTabs [data-baseweb="tab-list"] {
97
- gap: 2rem;
98
- }
99
-
100
- .stTabs [data-baseweb="tab"] {
101
  font-size: 1.1rem;
102
  font-weight: 600;
103
  }
 
 
 
 
 
104
  </style>
105
  """, unsafe_allow_html=True)
106
 
@@ -117,15 +165,54 @@ def load_sample_data():
117
  'Category-Object': [87.3, 84.7, 81.8, 77.6, 74.8],
118
  })
119
 
120
- def calculate_score(uploaded_file):
121
- """Calculate score from uploaded TSV file"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122
  try:
123
  df = pd.read_csv(uploaded_file, sep='\t')
124
- # Replace this with your actual scoring logic
125
- score = 85.0 # Placeholder
126
- return score, df
 
 
 
127
  except Exception as e:
128
- return None, str(e)
129
 
130
  def create_bar_chart(df, view_type):
131
  """Create interactive bar chart based on view type"""
@@ -201,14 +288,23 @@ def create_bar_chart(df, view_type):
201
  return fig
202
 
203
  # Main content
204
- st.markdown('<h1 class="main-title">🧭 NaviTrace Leaderboard</h1>', unsafe_allow_html=True)
205
 
206
- # Links
207
  st.markdown("""
208
- <div class="links-container">
209
- <a href="https://your-paper-website.com" target="_blank">📄 Paper</a>
210
- <a href="https://huggingface.co/datasets/your-username/navitrace" target="_blank">🤗 Dataset</a>
211
- <a href="https://github.com/your-username/navitrace" target="_blank">💻 GitHub</a>
 
 
 
 
 
 
 
 
 
212
  </div>
213
  """, unsafe_allow_html=True)
214
 
@@ -222,16 +318,13 @@ if 'user_results' in st.session_state:
222
 
223
  # Leaderboard section
224
  st.markdown('<div id="leaderboard"></div>', unsafe_allow_html=True)
225
- st.markdown('<h2 class="section-header">📊 Leaderboard</h2>', unsafe_allow_html=True)
226
 
227
  # View selector
228
- col1, col2, col3 = st.columns([1, 1, 1])
229
- with col1:
230
- view_type = st.selectbox(
231
- "Select View",
232
- ["Total Score", "Per Embodiment", "Per Category"],
233
- label_visibility="collapsed"
234
- )
235
 
236
  # Display chart
237
  fig = create_bar_chart(df, view_type)
@@ -247,8 +340,12 @@ st.plotly_chart(fig, use_container_width=True, config={
247
  }
248
  })
249
 
 
 
 
 
250
  # Export chart HTML for embedding
251
- with st.expander("📎 Embed Chart in Your Website"):
252
  html_str = fig.to_html(include_plotlyjs='cdn')
253
  st.code(html_str, language='html')
254
  st.download_button(
@@ -258,84 +355,97 @@ with st.expander("📎 Embed Chart in Your Website"):
258
  mime="text/html"
259
  )
260
 
261
- # Detailed table
262
- with st.expander("📋 View Detailed Scores"):
263
- st.dataframe(df.style.background_gradient(cmap='Purples', subset=df.columns[1:]), use_container_width=True)
264
-
265
  # Instructions section
266
- st.markdown('<h2 class="section-header">🚀 Test Your Own Model</h2>', unsafe_allow_html=True)
267
-
268
- st.markdown("""
269
- <div class="instructions-box">
270
- <p style="font-size: 1.2rem; font-weight: 600; margin-bottom: 1.5rem;">Follow these steps to evaluate your model on NaviTrace:</p>
271
- </div>
272
- """, unsafe_allow_html=True)
273
-
274
- # Step 1
275
- st.markdown("### Step 1: Run Evaluation")
276
- st.markdown("""
277
- Download and run our evaluation notebook on your model. The notebook will generate a TSV file with your model's predictions.
278
- """)
279
- col1, col2 = st.columns([1, 3])
280
- with col1:
281
- st.link_button("📓 Evaluation Notebook", "https://colab.research.google.com/your-notebook-link")
282
 
283
- st.markdown("---")
284
-
285
- # Step 2
286
- st.markdown("### Step 2: Upload Results")
287
- st.markdown("Upload the TSV file generated by the evaluation notebook:")
288
- uploaded_file = st.file_uploader("Choose a TSV file", type=['tsv', 'txt'], label_visibility="collapsed")
289
-
290
- st.markdown("---")
291
-
292
- # Step 3
293
- st.markdown("### Step 3: Calculate Score")
294
- if uploaded_file is not None:
295
- if st.button("🧮 Calculate Score", use_container_width=False):
296
- with st.spinner("Calculating scores..."):
297
- score, result = calculate_score(uploaded_file)
298
- if score is not None:
299
- st.success(f"✅ Score calculated successfully: **{score:.1f}**")
300
-
301
- # Store in session state (simplified example)
302
- st.session_state.user_results = {
303
- 'Model': 'Your Model',
304
- 'Total Score': score,
305
- 'Embodiment-A': score + 2,
306
- 'Embodiment-B': score - 1,
307
- 'Embodiment-C': score,
308
- 'Category-Spatial': score + 1,
309
- 'Category-Temporal': score - 1,
310
- 'Category-Object': score,
311
- }
312
-
313
- st.markdown("---")
314
-
315
- # Step 4
316
- st.markdown("### Step 4: View Your Results")
317
- st.markdown("Your model has been added to the leaderboard above!")
318
- st.link_button("🔝 Go to Leaderboard", "#leaderboard")
319
-
320
- else:
321
- st.error(f"❌ Error calculating score: {result}")
322
- else:
323
- st.info("👆 Upload a TSV file to calculate your score")
324
-
325
- st.markdown("---")
326
-
327
- # Step 5
328
- st.markdown("### Step 5: Submit Your Model")
329
- st.markdown("""
330
- Happy with your results? Submit your model to appear on the official leaderboard!
331
- Fill out our submission form with your model details and results.
332
- """)
333
- st.link_button("📝 Submission Form", "https://forms.gle/your-google-form-link")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
334
 
335
  # Footer
336
  st.markdown("---")
337
  st.markdown("""
338
  <div style="text-align: center; color: #666; padding: 2rem 0;">
339
- <p>NaviTrace Benchmark | Contact: your-email@domain.com</p>
340
  </div>
341
  """, unsafe_allow_html=True)
 
8
  # Page config
9
  st.set_page_config(
10
  page_title="NaviTrace Leaderboard",
11
+ page_icon="logo.svg", # Place your SVG file in the repository root
12
+ layout="centered",
13
  initial_sidebar_state="collapsed"
14
  )
15
 
16
  # Custom CSS for Nerfies-style design
17
  st.markdown("""
18
  <style>
19
+ /* Import Font Awesome */
20
+ @import url('https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css');
21
+
22
+ /* Limit page width */
23
+ .main .block-container {
24
+ max-width: 900px;
25
+ padding-top: 3rem;
26
+ }
27
+
28
  /* Main title styling */
29
  .main-title {
30
  text-align: center;
31
+ font-size: 3rem;
32
  font-weight: 700;
33
+ margin-top: 1rem;
34
+ margin-bottom: 2rem;
35
+ color: #333;
 
 
 
36
  }
37
 
38
+ /* Button links container - Nerfies style */
39
+ .button-links {
40
+ display: flex;
41
+ justify-content: center;
42
+ gap: 1rem;
43
  margin-bottom: 3rem;
44
+ flex-wrap: wrap;
45
  }
46
 
47
+ .button-link {
48
+ display: inline-flex;
49
+ align-items: center;
50
+ gap: 0.5rem;
51
+ padding: 0.6rem 1.5rem;
52
+ background-color: #f8f9fa;
53
+ border: 1px solid #dee2e6;
54
+ border-radius: 50px;
55
  text-decoration: none;
56
+ color: #333;
57
+ font-weight: 500;
58
+ transition: all 0.3s ease;
59
+ font-size: 0.95rem;
60
  }
61
 
62
+ .button-link:hover {
63
+ background-color: #e9ecef;
64
+ transform: translateY(-2px);
65
+ box-shadow: 0 4px 8px rgba(0,0,0,0.1);
66
+ color: #333;
67
+ text-decoration: none;
68
+ }
69
+
70
+ .button-link i {
71
+ font-size: 1rem;
72
  }
73
 
74
  /* Section headers */
75
  .section-header {
76
+ font-size: 1.8rem;
77
  font-weight: 600;
78
+ margin-top: 3rem;
79
+ margin-bottom: 1.5rem;
80
  color: #333;
81
  }
82
 
83
+ /* Instructions styling */
84
+ .instruction-item {
85
+ display: flex;
86
+ gap: 1.5rem;
 
 
87
  margin: 2rem 0;
88
+ align-items: flex-start;
89
  }
90
 
91
+ .instruction-number {
92
+ flex-shrink: 0;
93
+ width: 40px;
94
+ height: 40px;
95
+ border-radius: 50%;
96
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
97
+ color: white;
98
+ display: flex;
99
+ align-items: center;
100
+ justify-content: center;
101
+ font-weight: 700;
102
+ font-size: 1.2rem;
103
+ }
104
+
105
+ .instruction-content {
106
+ flex-grow: 1;
107
+ padding-top: 0.3rem;
108
+ }
109
+
110
+ .instruction-title {
111
  font-size: 1.1rem;
112
+ font-weight: 600;
113
+ margin-bottom: 0.5rem;
114
+ color: #333;
115
+ }
116
+
117
+ .instruction-desc {
118
+ color: #666;
119
+ line-height: 1.6;
120
  }
121
 
122
+ /* Streamlit button styling */
123
  .stButton>button {
124
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
125
  color: white;
 
139
  #MainMenu {visibility: hidden;}
140
  footer {visibility: hidden;}
141
 
142
+ /* Expander styling */
143
+ .streamlit-expanderHeader {
 
 
 
 
144
  font-size: 1.1rem;
145
  font-weight: 600;
146
  }
147
+
148
+ /* File uploader */
149
+ [data-testid="stFileUploader"] {
150
+ margin: 1rem 0;
151
+ }
152
  </style>
153
  """, unsafe_allow_html=True)
154
 
 
165
  'Category-Object': [87.3, 84.7, 81.8, 77.6, 74.8],
166
  })
167
 
168
+ def calculate_score_backend(results_df):
169
+ """
170
+ Calculate score using private test split ground truth.
171
+ This function should:
172
+ 1. Load the private test split ground truth (not exposed to users)
173
+ 2. Compare uploaded predictions with ground truth
174
+ 3. Calculate metrics per embodiment and category
175
+ 4. Return detailed scores
176
+
177
+ Args:
178
+ results_df: DataFrame with columns ['sample_id', 'prediction', ...]
179
+
180
+ Returns:
181
+ dict: Scores breakdown or None if error
182
+ """
183
+ try:
184
+ # TODO: Implement your scoring logic here
185
+ # Example structure:
186
+ # ground_truth = load_private_test_split() # From secure location
187
+ # scores = evaluate_predictions(results_df, ground_truth)
188
+
189
+ # Placeholder - replace with actual calculation
190
+ scores = {
191
+ 'Total Score': 85.0,
192
+ 'Embodiment-A': 87.0,
193
+ 'Embodiment-B': 84.0,
194
+ 'Embodiment-C': 84.0,
195
+ 'Category-Spatial': 86.0,
196
+ 'Category-Temporal': 85.0,
197
+ 'Category-Object': 84.0,
198
+ }
199
+ return scores
200
+ except Exception as e:
201
+ st.error(f"Error calculating score: {str(e)}")
202
+ return None
203
+
204
+ def validate_tsv_format(uploaded_file):
205
+ """Validate that the uploaded TSV has the correct format"""
206
  try:
207
  df = pd.read_csv(uploaded_file, sep='\t')
208
+ # TODO: Add your specific validation logic
209
+ # Check for required columns, data types, etc.
210
+ required_cols = ['sample_id', 'prediction'] # Adjust as needed
211
+ if not all(col in df.columns for col in required_cols):
212
+ return False, f"Missing required columns. Expected: {required_cols}"
213
+ return True, df
214
  except Exception as e:
215
+ return False, f"Error reading file: {str(e)}"
216
 
217
  def create_bar_chart(df, view_type):
218
  """Create interactive bar chart based on view type"""
 
288
  return fig
289
 
290
  # Main content
291
+ st.markdown('<h1 class="main-title">NaviTrace Leaderboard</h1>', unsafe_allow_html=True)
292
 
293
+ # Nerfies-style button links
294
  st.markdown("""
295
+ <div class="button-links">
296
+ <a href="https://your-paper-website.com" target="_blank" class="button-link">
297
+ <i class="fas fa-file-pdf"></i> Paper
298
+ </a>
299
+ <a href="https://huggingface.co/datasets/your-username/navitrace" target="_blank" class="button-link">
300
+ <i class="fas fa-database"></i> Dataset
301
+ </a>
302
+ <a href="https://github.com/your-username/navitrace" target="_blank" class="button-link">
303
+ <i class="fab fa-github"></i> Code
304
+ </a>
305
+ <a href="https://your-demo-link.com" target="_blank" class="button-link">
306
+ <i class="far fa-images"></i> Demo
307
+ </a>
308
  </div>
309
  """, unsafe_allow_html=True)
310
 
 
318
 
319
  # Leaderboard section
320
  st.markdown('<div id="leaderboard"></div>', unsafe_allow_html=True)
321
+ st.markdown('<h2 class="section-header">Leaderboard</h2>', unsafe_allow_html=True)
322
 
323
  # View selector
324
+ view_type = st.selectbox(
325
+ "Select View",
326
+ ["Total Score", "Per Embodiment", "Per Category"],
327
+ )
 
 
 
328
 
329
  # Display chart
330
  fig = create_bar_chart(df, view_type)
 
340
  }
341
  })
342
 
343
+ # Detailed table
344
+ with st.expander("View Detailed Scores"):
345
+ st.dataframe(df.style.background_gradient(cmap='Purples', subset=df.columns[1:]), use_container_width=True)
346
+
347
  # Export chart HTML for embedding
348
+ with st.expander("Embed Chart in Your Website"):
349
  html_str = fig.to_html(include_plotlyjs='cdn')
350
  st.code(html_str, language='html')
351
  st.download_button(
 
355
  mime="text/html"
356
  )
357
 
 
 
 
 
358
  # Instructions section
359
+ st.markdown('<h2 class="section-header">Evaluate Your Model</h2>', unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
360
 
361
+ with st.expander("How to Test Your Model", expanded=False):
362
+ # Step 1
363
+ st.markdown("""
364
+ <div class="instruction-item">
365
+ <div class="instruction-number">1</div>
366
+ <div class="instruction-content">
367
+ <div class="instruction-title">Run Evaluation</div>
368
+ <div class="instruction-desc">
369
+ Download and run our evaluation notebook on your model. The notebook will generate a TSV file with your model's predictions on the test set.
370
+ </div>
371
+ </div>
372
+ </div>
373
+ """, unsafe_allow_html=True)
374
+
375
+ st.link_button("📓 Open Evaluation Notebook", "https://colab.research.google.com/your-notebook-link", use_container_width=False)
376
+
377
+ # Step 2
378
+ st.markdown("""
379
+ <div class="instruction-item">
380
+ <div class="instruction-number">2</div>
381
+ <div class="instruction-content">
382
+ <div class="instruction-title">Upload Results</div>
383
+ <div class="instruction-desc">
384
+ Upload the TSV file generated by the evaluation notebook. Your predictions will be evaluated against our private test set.
385
+ </div>
386
+ </div>
387
+ </div>
388
+ """, unsafe_allow_html=True)
389
+
390
+ uploaded_file = st.file_uploader("Choose a TSV file", type=['tsv', 'txt'])
391
+
392
+ # Step 3
393
+ st.markdown("""
394
+ <div class="instruction-item">
395
+ <div class="instruction-number">3</div>
396
+ <div class="instruction-content">
397
+ <div class="instruction-title">Calculate Score</div>
398
+ <div class="instruction-desc">
399
+ Click the button below to evaluate your predictions. Scores are calculated using the private test set ground truth.
400
+ </div>
401
+ </div>
402
+ </div>
403
+ """, unsafe_allow_html=True)
404
+
405
+ if uploaded_file is not None:
406
+ if st.button("Calculate Score", use_container_width=False):
407
+ with st.spinner("Validating and calculating scores..."):
408
+ # Validate format
409
+ is_valid, result = validate_tsv_format(uploaded_file)
410
+ if is_valid:
411
+ # Calculate score using private ground truth
412
+ scores = calculate_score_backend(result)
413
+ if scores is not None:
414
+ st.success(f"✅ Score calculated successfully: **{scores['Total Score']:.1f}**")
415
+
416
+ # Store in session state
417
+ st.session_state.user_results = {
418
+ 'Model': 'Your Model',
419
+ **scores
420
+ }
421
+ st.info("👆 Scroll up to see your model on the leaderboard!")
422
+ st.rerun()
423
+ else:
424
+ st.error(f"❌ Invalid file format: {result}")
425
+ else:
426
+ st.info("👆 Upload a TSV file to calculate your score")
427
+
428
+ # Step 4
429
+ st.markdown("""
430
+ <div class="instruction-item">
431
+ <div class="instruction-number">4</div>
432
+ <div class="instruction-content">
433
+ <div class="instruction-title">Submit to Official Leaderboard</div>
434
+ <div class="instruction-desc">
435
+ Happy with your results? Submit your model to appear on the official leaderboard.
436
+ All submissions undergo manual verification to ensure quality and prevent gaming.
437
+ Fill out the form below with your model details and results.
438
+ </div>
439
+ </div>
440
+ </div>
441
+ """, unsafe_allow_html=True)
442
+
443
+ st.link_button("Submit Model (Google Form)", "https://forms.gle/your-google-form-link", use_container_width=False)
444
 
445
  # Footer
446
  st.markdown("---")
447
  st.markdown("""
448
  <div style="text-align: center; color: #666; padding: 2rem 0;">
449
+ <p>NaviTrace Benchmark | <a href="mailto:your-email@domain.com" style="color: #667eea;">Contact</a></p>
450
  </div>
451
  """, unsafe_allow_html=True)