bgamazay commited on
Commit
47d601f
·
verified ·
1 Parent(s): c0062b7

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +153 -13
app.py CHANGED
@@ -6,8 +6,8 @@ import base64
6
 
7
  CITATION_BUTTON_LABEL = "Copy the following snippet to cite these results"
8
  CITATION_BUTTON_TEXT = r"""@misc{aienergyscore-leaderboard,
9
- author = {Sasha Luccioni and Boris Gamazaychikov and Emma Strubell and Sara Hooker and Yacine Jernite and Carole-Jean Wu and Margaret Mitchell},
10
- title = {AI Energy Score Leaderboard - February 2025},
11
  year = {2025},
12
  publisher = {Hugging Face},
13
  howpublished = "\url{https://huggingface.co/spaces/AIEnergyScore/Leaderboard}",
@@ -18,6 +18,7 @@ tasks = [
18
  'asr.csv',
19
  'object_detection.csv',
20
  'text_classification.csv',
 
21
  'image_captioning.csv',
22
  'question_answering.csv',
23
  'text_generation.csv',
@@ -27,6 +28,21 @@ tasks = [
27
  'summarization.csv'
28
  ]
29
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  ### HELPER FUNCTIONS ###
31
 
32
  def format_stars(score):
@@ -59,12 +75,31 @@ def generate_html_table_from_df(df):
59
 
60
  max_energy = df['gpu_energy_numeric'].max() if not df.empty else 1
61
  color_map = {"1": "black", "2": "black", "3": "black", "4": "black", "5": "black"}
 
 
 
 
 
 
 
 
 
 
 
 
 
62
  html = '<table class="data-table" style="width:100%; border-collapse: collapse; font-family: Inter, sans-serif;">'
63
  html += '<thead><tr style="background-color: #f2f2f2;">'
64
  html += '<th style="text-align: left; padding: 8px;" title="Model name with link to Hugging Face">Model</th>'
65
  html += '<th style="text-align: left; padding: 8px;" title="AI Provider extracted from the model name">Provider</th>'
66
- html += '<th style="text-align: left; padding: 8px;" title="GPU energy consumed in Watt-hours for 1,000 queries">GPU Energy (Wh)</th>'
67
  html += '<th style="text-align: left; padding: 8px;" title="Energy efficiency score (stars)">Score</th>'
 
 
 
 
 
 
68
  html += '</tr></thead>'
69
  html += '<tbody>'
70
  for _, row in df.iterrows():
@@ -79,6 +114,13 @@ def generate_html_table_from_df(df):
79
  html += (f'<td style="padding: 8px;">{energy_str}<br>'
80
  f'<div style="background-color: {bar_color}; width: {bar_width:.1f}%; height: 10px;"></div></td>')
81
  html += f'<td style="padding: 8px;">{row["Score"]}</td>'
 
 
 
 
 
 
 
82
  html += '</tr>'
83
  html += '</tbody></table>'
84
  return f'<div class="table-container">{html}</div>'
@@ -87,8 +129,16 @@ def process_df(task, sort_order="Low to High", filter_fn=None):
87
  df = pd.read_csv(os.path.join("data", "energy", task))
88
  if df.columns[0].startswith("Unnamed:"):
89
  df = df.iloc[:, 1:]
90
- df['energy_score'] = df['energy_score'].astype(int)
91
- df['gpu_energy_numeric'] = pd.to_numeric(df['total_gpu_energy'], errors='raise') * 1000
 
 
 
 
 
 
 
 
92
  if filter_fn is not None:
93
  df = filter_fn(df)
94
  df['Provider'] = df['model'].apply(lambda x: str(x).split('/')[0])
@@ -98,19 +148,37 @@ def process_df(task, sort_order="Low to High", filter_fn=None):
98
  df = df.sort_values(by='gpu_energy_numeric', ascending=ascending)
99
  return df
100
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
  def compute_efficiency_ratio(df):
102
  if df.empty:
103
  return 1
 
104
  min_val = df['gpu_energy_numeric'].min()
105
  max_val = df['gpu_energy_numeric'].max()
106
  ratio = max_val / min_val if min_val > 0 else 1
107
  return ratio
108
 
109
  def generate_info_callout(ratio, scope_text):
 
110
  return (
111
  f'<div style="text-align: right;">'
112
  f'<div class="info-callout" style="display:inline-block; max-width:250px; font-size:0.8em; background-color:#e6ffe6; padding:8px; border-radius:5px;">'
113
- f'💡 There\'s a <strong style="color: black !important;">{ratio:,.1f}x</strong> difference between the highest and lowest energy use in {scope_text}.'
114
  f'</div></div>'
115
  )
116
 
@@ -151,7 +219,7 @@ def get_zip_data_link():
151
 
152
  ### UPDATE FUNCTIONS (RETURNING CALLOUT AND TABLE HTML) ###
153
 
154
- def update_text_generation(selected_display, sort_order):
155
  mapping = {
156
  "A (Single Consumer GPU) <20B parameters": "A",
157
  "B (Single Cloud GPU) 20-66B parameters": "B",
@@ -159,18 +227,49 @@ def update_text_generation(selected_display, sort_order):
159
  }
160
  model_class = mapping.get(selected_display, "A")
161
  def filter_fn(df):
 
 
 
 
 
 
 
162
  if 'class' in df.columns:
163
  return df[df['class'] == model_class]
164
  return df
165
  df = process_df('text_generation.csv', sort_order, filter_fn)
 
166
  ratio = compute_efficiency_ratio(df)
167
  # For Text Generation, use "this class" as the scope.
168
  callout = generate_info_callout(ratio, "this class")
169
  table_html = generate_html_table_from_df(df)
170
  return callout, table_html
171
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
172
  def update_image_generation(sort_order):
173
  df = process_df('image_generation.csv', sort_order)
 
174
  ratio = compute_efficiency_ratio(df)
175
  callout = generate_info_callout(ratio, "this task")
176
  table_html = generate_html_table_from_df(df)
@@ -178,6 +277,7 @@ def update_image_generation(sort_order):
178
 
179
  def update_text_classification(sort_order):
180
  df = process_df('text_classification.csv', sort_order)
 
181
  ratio = compute_efficiency_ratio(df)
182
  callout = generate_info_callout(ratio, "this task")
183
  table_html = generate_html_table_from_df(df)
@@ -185,6 +285,7 @@ def update_text_classification(sort_order):
185
 
186
  def update_image_classification(sort_order):
187
  df = process_df('image_classification.csv', sort_order)
 
188
  ratio = compute_efficiency_ratio(df)
189
  callout = generate_info_callout(ratio, "this task")
190
  table_html = generate_html_table_from_df(df)
@@ -192,6 +293,7 @@ def update_image_classification(sort_order):
192
 
193
  def update_image_captioning(sort_order):
194
  df = process_df('image_captioning.csv', sort_order)
 
195
  ratio = compute_efficiency_ratio(df)
196
  callout = generate_info_callout(ratio, "this task")
197
  table_html = generate_html_table_from_df(df)
@@ -199,6 +301,7 @@ def update_image_captioning(sort_order):
199
 
200
  def update_summarization(sort_order):
201
  df = process_df('summarization.csv', sort_order)
 
202
  ratio = compute_efficiency_ratio(df)
203
  callout = generate_info_callout(ratio, "this task")
204
  table_html = generate_html_table_from_df(df)
@@ -206,6 +309,7 @@ def update_summarization(sort_order):
206
 
207
  def update_asr(sort_order):
208
  df = process_df('asr.csv', sort_order)
 
209
  ratio = compute_efficiency_ratio(df)
210
  callout = generate_info_callout(ratio, "this task")
211
  table_html = generate_html_table_from_df(df)
@@ -213,6 +317,7 @@ def update_asr(sort_order):
213
 
214
  def update_object_detection(sort_order):
215
  df = process_df('object_detection.csv', sort_order)
 
216
  ratio = compute_efficiency_ratio(df)
217
  callout = generate_info_callout(ratio, "this task")
218
  table_html = generate_html_table_from_df(df)
@@ -220,6 +325,7 @@ def update_object_detection(sort_order):
220
 
221
  def update_sentence_similarity(sort_order):
222
  df = process_df('sentence_similarity.csv', sort_order)
 
223
  ratio = compute_efficiency_ratio(df)
224
  callout = generate_info_callout(ratio, "this task")
225
  table_html = generate_html_table_from_df(df)
@@ -227,6 +333,7 @@ def update_sentence_similarity(sort_order):
227
 
228
  def update_extractive_qa(sort_order):
229
  df = process_df('question_answering.csv', sort_order)
 
230
  ratio = compute_efficiency_ratio(df)
231
  callout = generate_info_callout(ratio, "this task")
232
  table_html = generate_html_table_from_df(df)
@@ -238,12 +345,18 @@ def update_all_tasks(sort_order):
238
  df = pd.read_csv(os.path.join("data", "energy", task))
239
  if df.columns[0].startswith("Unnamed:"):
240
  df = df.iloc[:, 1:]
241
- df['energy_score'] = df['energy_score'].astype(int)
242
- df['gpu_energy_numeric'] = pd.to_numeric(df['total_gpu_energy'], errors='raise') * 1000
 
243
  df['Provider'] = df['model'].apply(lambda x: str(x).split('/')[0])
244
  df['Model'] = df['model'].apply(make_link)
245
  df['Score'] = df['energy_score'].apply(format_stars)
 
 
 
 
246
  all_df = pd.concat([all_df, df], ignore_index=True)
 
247
  all_df = all_df.drop_duplicates(subset=['model'])
248
  ascending = True if sort_order == "Low to High" else False
249
  all_df = all_df.sort_values(by='gpu_energy_numeric', ascending=ascending)
@@ -365,14 +478,41 @@ with demo:
365
  with gr.Column(scale=4):
366
  sort_dropdown_tg = gr.Dropdown(choices=["Low to High", "High to Low"], label="Sort", value="Low to High")
367
  with gr.Column(scale=4):
 
 
 
368
  tg_callout = gr.HTML()
369
  tg_table = gr.HTML()
370
- init_callout, init_table = update_text_generation(model_class_options[0], "Low to High")
371
  tg_callout.value = init_callout
372
  tg_table.value = init_table
373
- model_class_dropdown.change(fn=update_text_generation, inputs=[model_class_dropdown, sort_dropdown_tg], outputs=[tg_callout, tg_table])
374
- sort_dropdown_tg.change(fn=update_text_generation, inputs=[model_class_dropdown, sort_dropdown_tg], outputs=[tg_callout, tg_table])
 
375
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
376
  # --- Image Generation Tab ---
377
  with gr.TabItem("Image Generation 📷"):
378
  with gr.Row():
@@ -511,6 +651,6 @@ with demo:
511
  lines=10,
512
  show_copy_button=True,
513
  )
514
- gr.Markdown("Last updated: February 2025")
515
 
516
  demo.launch()
 
6
 
7
  CITATION_BUTTON_LABEL = "Copy the following snippet to cite these results"
8
  CITATION_BUTTON_TEXT = r"""@misc{aienergyscore-leaderboard,
9
+ author = {Sasha Luccioni and Boris Gamazaychikov and Emma Strubell and Sara Hooker and Yacine Jernite and Margaret Mitchell},
10
+ title = {AI Energy Score Leaderboard - December 2025},
11
  year = {2025},
12
  publisher = {Hugging Face},
13
  howpublished = "\url{https://huggingface.co/spaces/AIEnergyScore/Leaderboard}",
 
18
  'asr.csv',
19
  'object_detection.csv',
20
  'text_classification.csv',
21
+ 'reasoning.csv',
22
  'image_captioning.csv',
23
  'question_answering.csv',
24
  'text_generation.csv',
 
28
  'summarization.csv'
29
  ]
30
 
31
+ # Mapping for display names in "All Tasks"
32
+ TASK_NAME_MAPPING = {
33
+ 'text_generation.csv': 'Text Generation 💬',
34
+ 'reasoning.csv': 'Reasoning 🧠',
35
+ 'image_generation.csv': 'Image Generation 📷',
36
+ 'text_classification.csv': 'Text Classification 🎭',
37
+ 'image_classification.csv': 'Image Classification 🖼️',
38
+ 'image_captioning.csv': 'Image Captioning 📝',
39
+ 'summarization.csv': 'Summarization 📃',
40
+ 'asr.csv': 'Automatic Speech Recognition 💬',
41
+ 'object_detection.csv': 'Object Detection 🚘',
42
+ 'sentence_similarity.csv': 'Sentence Similarity 📚',
43
+ 'question_answering.csv': 'Extractive QA ❔'
44
+ }
45
+
46
  ### HELPER FUNCTIONS ###
47
 
48
  def format_stars(score):
 
75
 
76
  max_energy = df['gpu_energy_numeric'].max() if not df.empty else 1
77
  color_map = {"1": "black", "2": "black", "3": "black", "4": "black", "5": "black"}
78
+ task_name = df.attrs.get("task_name", "")
79
+
80
+ # Check if we should display the 'Task' column (only for All Tasks view)
81
+ has_task_column = 'Task' in df.columns
82
+
83
+ if task_name not in ["text_generation.csv", "reasoning.csv"]:
84
+ has_test_date = True
85
+ df["test date"] = "Feb 25"
86
+ else:
87
+ has_test_date = ('test date' in df.columns or 'Test Date' in df.columns)
88
+ if 'Test Date' in df.columns and 'test date' not in df.columns:
89
+ df = df.rename(columns={'Test Date':'test date'})
90
+
91
  html = '<table class="data-table" style="width:100%; border-collapse: collapse; font-family: Inter, sans-serif;">'
92
  html += '<thead><tr style="background-color: #f2f2f2;">'
93
  html += '<th style="text-align: left; padding: 8px;" title="Model name with link to Hugging Face">Model</th>'
94
  html += '<th style="text-align: left; padding: 8px;" title="AI Provider extracted from the model name">Provider</th>'
95
+ html += '<th style="text-align: left; padding: 8px;" title="GPU energy consumed in Watt-hours for 1,000 queries">GPU Energy (Wh) per 1k Queries</th>'
96
  html += '<th style="text-align: left; padding: 8px;" title="Energy efficiency score (stars)">Score</th>'
97
+
98
+ if has_task_column:
99
+ html += '<th style="text-align: left; padding: 8px;" title="Task Category">Task</th>'
100
+
101
+ if has_test_date:
102
+ html += '<th style="text-align: left; padding: 8px;" title="Benchmark test date">Test Date</th>'
103
  html += '</tr></thead>'
104
  html += '<tbody>'
105
  for _, row in df.iterrows():
 
114
  html += (f'<td style="padding: 8px;">{energy_str}<br>'
115
  f'<div style="background-color: {bar_color}; width: {bar_width:.1f}%; height: 10px;"></div></td>')
116
  html += f'<td style="padding: 8px;">{row["Score"]}</td>'
117
+
118
+ if has_task_column:
119
+ html += f'<td style="padding: 8px;">{row["Task"]}</td>'
120
+
121
+ if has_test_date:
122
+ td = row.get('test date', row.get('Test Date', ''))
123
+ html += f'<td style="padding: 8px;">{td}</td>'
124
  html += '</tr>'
125
  html += '</tbody></table>'
126
  return f'<div class="table-container">{html}</div>'
 
129
  df = pd.read_csv(os.path.join("data", "energy", task))
130
  if df.columns[0].startswith("Unnamed:"):
131
  df = df.iloc[:, 1:]
132
+ df['energy_score'] = pd.to_numeric(df['energy_score'], errors='coerce').fillna(0).clip(lower=0, upper=5).astype(int)
133
+ # Using raw numbers, no pre-rounding
134
+ df['gpu_energy_numeric'] = pd.to_numeric(df['total_gpu_energy'], errors='coerce').fillna(0.0) * 1000
135
+ # normalize test date header if present
136
+ if 'Test Date' in df.columns and 'test date' not in df.columns:
137
+ df = df.rename(columns={'Test Date':'test date'})
138
+ if 'test_date' in df.columns and 'test date' not in df.columns:
139
+ df = df.rename(columns={'test_date':'test date'})
140
+ if 'test date' in df.columns:
141
+ df['test date'] = df['test date'].astype(str).str.strip()
142
  if filter_fn is not None:
143
  df = filter_fn(df)
144
  df['Provider'] = df['model'].apply(lambda x: str(x).split('/')[0])
 
148
  df = df.sort_values(by='gpu_energy_numeric', ascending=ascending)
149
  return df
150
 
151
+
152
+ def get_test_date_choices(task_filename):
153
+ try:
154
+ df = pd.read_csv(os.path.join("data","energy", task_filename))
155
+ if df.columns[0].startswith("Unnamed:"):
156
+ df = df.iloc[:,1:]
157
+ if 'Test Date' in df.columns and 'test date' not in df.columns:
158
+ df = df.rename(columns={'Test Date':'test date'})
159
+ if 'test_date' in df.columns and 'test date' not in df.columns:
160
+ df = df.rename(columns={'test_date':'test date'})
161
+ if 'test date' in df.columns:
162
+ return sorted([d for d in df['test date'].astype(str).str.strip().unique().tolist() if d])
163
+ return []
164
+ except Exception:
165
+ return []
166
+
167
  def compute_efficiency_ratio(df):
168
  if df.empty:
169
  return 1
170
+ # Use unrounded raw numbers for calculation
171
  min_val = df['gpu_energy_numeric'].min()
172
  max_val = df['gpu_energy_numeric'].max()
173
  ratio = max_val / min_val if min_val > 0 else 1
174
  return ratio
175
 
176
  def generate_info_callout(ratio, scope_text):
177
+ # Rounded to no decimals (.0f) for display
178
  return (
179
  f'<div style="text-align: right;">'
180
  f'<div class="info-callout" style="display:inline-block; max-width:250px; font-size:0.8em; background-color:#e6ffe6; padding:8px; border-radius:5px;">'
181
+ f'💡 There\'s a <strong style="color: black !important;">{ratio:,.0f}x</strong> difference between the highest and lowest energy use in {scope_text}.'
182
  f'</div></div>'
183
  )
184
 
 
219
 
220
  ### UPDATE FUNCTIONS (RETURNING CALLOUT AND TABLE HTML) ###
221
 
222
+ def update_text_generation(selected_display, sort_order, selected_dates):
223
  mapping = {
224
  "A (Single Consumer GPU) <20B parameters": "A",
225
  "B (Single Cloud GPU) 20-66B parameters": "B",
 
227
  }
228
  model_class = mapping.get(selected_display, "A")
229
  def filter_fn(df):
230
+ # filter by selected test dates as well
231
+ if 'Test Date' in df.columns and 'test date' not in df.columns:
232
+ df.rename(columns={'Test Date':'test date'}, inplace=True)
233
+ if 'test_date' in df.columns and 'test date' not in df.columns:
234
+ df.rename(columns={'test_date':'test date'}, inplace=True)
235
+ if selected_dates:
236
+ df = df[df['test date'].astype(str).isin(selected_dates)]
237
  if 'class' in df.columns:
238
  return df[df['class'] == model_class]
239
  return df
240
  df = process_df('text_generation.csv', sort_order, filter_fn)
241
+ df.attrs["task_name"] = "text_generation.csv"
242
  ratio = compute_efficiency_ratio(df)
243
  # For Text Generation, use "this class" as the scope.
244
  callout = generate_info_callout(ratio, "this class")
245
  table_html = generate_html_table_from_df(df)
246
  return callout, table_html
247
 
248
+
249
+ def update_reasoning(selected_display, sort_order):
250
+ mapping = {
251
+ "A (Single Consumer GPU) <20B parameters": "A",
252
+ "B (Single Cloud GPU) 20-66B parameters": "B",
253
+ "C (Multiple Cloud GPUs) >66B parameters": "C"
254
+ }
255
+ model_class = mapping.get(selected_display, "A")
256
+
257
+ def filter_fn(df):
258
+ # class-only filter; no test-date filtering for Reasoning
259
+ if 'class' in df.columns:
260
+ df = df[df['class'] == model_class]
261
+ return df
262
+
263
+ df = process_df('reasoning.csv', sort_order, filter_fn)
264
+ df.attrs["task_name"] = "reasoning.csv"
265
+ ratio = compute_efficiency_ratio(df)
266
+ callout = generate_info_callout(ratio, "this class")
267
+ table_html = generate_html_table_from_df(df)
268
+ return callout, table_html
269
+
270
  def update_image_generation(sort_order):
271
  df = process_df('image_generation.csv', sort_order)
272
+ df.attrs["task_name"] = 'image_generation.csv'
273
  ratio = compute_efficiency_ratio(df)
274
  callout = generate_info_callout(ratio, "this task")
275
  table_html = generate_html_table_from_df(df)
 
277
 
278
  def update_text_classification(sort_order):
279
  df = process_df('text_classification.csv', sort_order)
280
+ df.attrs["task_name"] = 'text_classification.csv'
281
  ratio = compute_efficiency_ratio(df)
282
  callout = generate_info_callout(ratio, "this task")
283
  table_html = generate_html_table_from_df(df)
 
285
 
286
  def update_image_classification(sort_order):
287
  df = process_df('image_classification.csv', sort_order)
288
+ df.attrs["task_name"] = 'image_classification.csv'
289
  ratio = compute_efficiency_ratio(df)
290
  callout = generate_info_callout(ratio, "this task")
291
  table_html = generate_html_table_from_df(df)
 
293
 
294
  def update_image_captioning(sort_order):
295
  df = process_df('image_captioning.csv', sort_order)
296
+ df.attrs["task_name"] = 'image_captioning.csv'
297
  ratio = compute_efficiency_ratio(df)
298
  callout = generate_info_callout(ratio, "this task")
299
  table_html = generate_html_table_from_df(df)
 
301
 
302
  def update_summarization(sort_order):
303
  df = process_df('summarization.csv', sort_order)
304
+ df.attrs["task_name"] = 'summarization.csv'
305
  ratio = compute_efficiency_ratio(df)
306
  callout = generate_info_callout(ratio, "this task")
307
  table_html = generate_html_table_from_df(df)
 
309
 
310
  def update_asr(sort_order):
311
  df = process_df('asr.csv', sort_order)
312
+ df.attrs["task_name"] = 'asr.csv'
313
  ratio = compute_efficiency_ratio(df)
314
  callout = generate_info_callout(ratio, "this task")
315
  table_html = generate_html_table_from_df(df)
 
317
 
318
  def update_object_detection(sort_order):
319
  df = process_df('object_detection.csv', sort_order)
320
+ df.attrs["task_name"] = 'object_detection.csv'
321
  ratio = compute_efficiency_ratio(df)
322
  callout = generate_info_callout(ratio, "this task")
323
  table_html = generate_html_table_from_df(df)
 
325
 
326
  def update_sentence_similarity(sort_order):
327
  df = process_df('sentence_similarity.csv', sort_order)
328
+ df.attrs["task_name"] = 'sentence_similarity.csv'
329
  ratio = compute_efficiency_ratio(df)
330
  callout = generate_info_callout(ratio, "this task")
331
  table_html = generate_html_table_from_df(df)
 
333
 
334
  def update_extractive_qa(sort_order):
335
  df = process_df('question_answering.csv', sort_order)
336
+ df.attrs["task_name"] = 'question_answering.csv'
337
  ratio = compute_efficiency_ratio(df)
338
  callout = generate_info_callout(ratio, "this task")
339
  table_html = generate_html_table_from_df(df)
 
345
  df = pd.read_csv(os.path.join("data", "energy", task))
346
  if df.columns[0].startswith("Unnamed:"):
347
  df = df.iloc[:, 1:]
348
+
349
+ df['energy_score'] = pd.to_numeric(df['energy_score'], errors='coerce').fillna(0).clip(lower=0, upper=5).astype(int)
350
+ df['gpu_energy_numeric'] = pd.to_numeric(df['total_gpu_energy'], errors='coerce').fillna(0.0) * 1000
351
  df['Provider'] = df['model'].apply(lambda x: str(x).split('/')[0])
352
  df['Model'] = df['model'].apply(make_link)
353
  df['Score'] = df['energy_score'].apply(format_stars)
354
+
355
+ # Add Task column with emoji
356
+ df['Task'] = TASK_NAME_MAPPING.get(task, task)
357
+
358
  all_df = pd.concat([all_df, df], ignore_index=True)
359
+
360
  all_df = all_df.drop_duplicates(subset=['model'])
361
  ascending = True if sort_order == "Low to High" else False
362
  all_df = all_df.sort_values(by='gpu_energy_numeric', ascending=ascending)
 
478
  with gr.Column(scale=4):
479
  sort_dropdown_tg = gr.Dropdown(choices=["Low to High", "High to Low"], label="Sort", value="Low to High")
480
  with gr.Column(scale=4):
481
+ tg_date_choices = get_test_date_choices("text_generation.csv")
482
+ date_dropdown_tg = gr.Dropdown(choices=tg_date_choices, value=tg_date_choices, multiselect=True, label="Test Date")
483
+ with gr.Column(scale=3):
484
  tg_callout = gr.HTML()
485
  tg_table = gr.HTML()
486
+ init_callout, init_table = update_text_generation(model_class_options[0], "Low to High", get_test_date_choices("text_generation.csv"))
487
  tg_callout.value = init_callout
488
  tg_table.value = init_table
489
+ model_class_dropdown.change(fn=update_text_generation, inputs=[model_class_dropdown, sort_dropdown_tg, date_dropdown_tg], outputs=[tg_callout, tg_table])
490
+ sort_dropdown_tg.change(fn=update_text_generation, inputs=[model_class_dropdown, sort_dropdown_tg, date_dropdown_tg], outputs=[tg_callout, tg_table])
491
+ date_dropdown_tg.change(fn=update_text_generation, inputs=[model_class_dropdown, sort_dropdown_tg, date_dropdown_tg], outputs=[tg_callout, tg_table])
492
 
493
+ # --- Reasoning Tab ---
494
+ with gr.TabItem("Reasoning 🧠"):
495
+ with gr.Row():
496
+ with gr.Column(scale=4):
497
+ model_class_options = [
498
+ "A (Single Consumer GPU) <20B parameters",
499
+ "B (Single Cloud GPU) 20-66B parameters",
500
+ "C (Multiple Cloud GPUs) >66B parameters"
501
+ ]
502
+ rs_class_dropdown = gr.Dropdown(choices=model_class_options, value=model_class_options[0], label="Select Model Class")
503
+ with gr.Column(scale=4):
504
+ rs_sort_dropdown = gr.Dropdown(choices=["Low to High", "High to Low"], label="Sort", value="Low to High")
505
+ with gr.Column(scale=4):
506
+ rs_callout = gr.HTML()
507
+
508
+ rs_table = gr.HTML()
509
+ init_callout, init_table = update_reasoning(model_class_options[0], "Low to High")
510
+ rs_callout.value = init_callout
511
+ rs_table.value = init_table
512
+
513
+ rs_class_dropdown.change(fn=update_reasoning, inputs=[rs_class_dropdown, rs_sort_dropdown], outputs=[rs_callout, rs_table])
514
+ rs_sort_dropdown.change(fn=update_reasoning, inputs=[rs_class_dropdown, rs_sort_dropdown], outputs=[rs_callout, rs_table])
515
+
516
  # --- Image Generation Tab ---
517
  with gr.TabItem("Image Generation 📷"):
518
  with gr.Row():
 
651
  lines=10,
652
  show_copy_button=True,
653
  )
654
+ gr.Markdown("Last updated: December 2025")
655
 
656
  demo.launch()