bgamazay commited on
Commit
b643c60
·
verified ·
1 Parent(s): dc19d3a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +172 -113
app.py CHANGED
@@ -2,107 +2,157 @@ import streamlit as st
2
  import pandas as pd
3
  from PIL import Image, ImageDraw, ImageFont
4
  import io
5
- import os, socket
 
 
 
 
 
 
 
 
 
 
 
 
6
 
7
- # --- CSV mapping (HF Space: AIEnergyScore/Leaderboard -> data/energy) ---
 
 
8
  TASK_TO_CSV = {
9
- "Image Generation": "image_generation.csv",
10
- "Text Classification": "text_classification.csv",
11
- "Image Classification": "image_classification.csv",
12
- "Image Captioning": "image_captioning.csv",
13
- "Summarization": "summarization.csv",
14
- "Text Generation": "text_generation.csv",
15
- "Reasoning": "reasoning.csv",
 
 
 
 
16
  }
17
-
18
- # Back-compat so old code like task_to_file[task] keeps working
19
  task_to_file = TASK_TO_CSV
20
 
21
- from huggingface_hub import hf_hub_download
22
-
23
- HF_REPO_ID = "AIEnergyScore/Leaderboard" # this is a Space
24
- HF_REPO_TYPE = "space"
25
- HF_DATA_PREFIX = "data/energy" # where the CSVs live in the Space
26
-
27
  def read_csv_from_hub(file_name: str) -> pd.DataFrame:
28
  """
29
- Download a CSV from the HF Space path data/energy/<file_name>
30
- and return it as a pandas DataFrame.
31
- Falls back to local file if Hub is unavailable.
32
  """
33
  hub_path = f"{HF_DATA_PREFIX}/{file_name}"
34
  try:
35
- # fast DNS sanity check to give a useful error if DNS is down
36
  socket.gethostbyname("huggingface.co")
37
-
38
  local_path = hf_hub_download(
39
  repo_id=HF_REPO_ID,
40
  repo_type=HF_REPO_TYPE,
41
  filename=hub_path,
42
- revision="main", # adjust if you use a branch/tag
43
  resume_download=True
44
  )
45
  return pd.read_csv(local_path)
46
  except Exception as e:
47
- # Fallback to local file if present
48
  try:
49
  return pd.read_csv(file_name)
50
  except Exception:
51
- # re-raise with context so it surfaces nicely in Streamlit
52
  raise RuntimeError(
53
  f"Unable to load '{file_name}' from Hub path '{hub_path}' or locally. "
54
  f"Original error: {e}"
55
  )
56
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
  def main():
58
- # Inject custom CSS to change the color of selected tasks
59
  st.markdown(
60
  """
61
  <style>
62
- /* Change background color of selected items */
63
  .stMultiSelect [data-baseweb="tag"] {
64
- background-color: #3fa45bff !important; /* Custom green */
65
- color: white !important; /* White text */
66
- font-weight: medium;
67
  border-radius: 5px;
68
  padding: 5px 10px;
69
  }
70
-
71
- /* Change hover effect */
72
- .stMultiSelect [data-baseweb="tag"]:hover {
73
- background-color: #358d4d !important;
74
- }
75
-
76
- /* Style the dropdown input field */
77
- .stMultiSelect input {
78
- color: black !important;
79
- }
80
  </style>
81
  """,
82
  unsafe_allow_html=True,
83
  )
84
 
85
- # Sidebar logo and title
86
  with st.sidebar:
87
  col1, col2 = st.columns([1, 5])
88
-
89
  with col1:
90
  logo = Image.open("logo.png")
91
- resized_logo = logo.resize((50, 50))
92
- st.image(resized_logo)
93
-
94
  with col2:
95
  st.markdown(
96
  """
97
- <div style="
98
- display: flex;
99
- align-items: center;
100
- gap: 10px;
101
- margin: 0;
102
- padding: 0;
103
- font-family: 'Inter', sans-serif;
104
- font-size: 26px;
105
- font-weight: medium;">
106
  AI Energy Score
107
  </div>
108
  """,
@@ -111,38 +161,27 @@ def main():
111
 
112
  st.sidebar.markdown("<hr style='border: 1px solid gray; margin: 15px 0;'>", unsafe_allow_html=True)
113
  st.sidebar.write("### Generate Label:")
114
- # Define the ordered list of tasks.
 
115
  task_order = [
116
- "Text Generation",
117
- "Reasoning",
118
- "Image Generation",
119
- "Text Classification",
120
- "Image Classification",
121
- "Image Captioning",
122
- "Summarization",
123
- "Speech-to-Text (ASR)",
124
- "Object Detection",
125
- "Question Answering",
126
- "Sentence Similarity"
127
  ]
128
- # Task selection
 
129
  st.sidebar.write("#### 1. Select task(s) to view models")
130
  selected_tasks = st.sidebar.multiselect("", options=task_order, default=["Text Generation"])
131
- # Mapping from task to CSV file name.
132
- TASK_TO_CSV = {
133
- "Text Generation": "text_generation.csv",
134
- "Reasoning": "reasoning.csv",
135
- "Image Generation": "image_generation.csv",
136
- "Text Classification": "text_classification.csv",
137
- "Image Classification": "image_classification.csv",
138
- "Image Captioning": "image_captioning.csv",
139
- "Summarization": "summarization.csv",
140
- "Speech-to-Text (ASR)": "asr.csv",
141
- "Object Detection": "object_detection.csv",
142
- "Question Answering": "question_answering.csv",
143
- "Sentence Similarity": "sentence_similarity.csv"
144
- }
145
- st.sidebar.write("#### 2. Select a model to generate label")
146
  default_model_data = {
147
  'provider': "AI Provider",
148
  'model': "Model Name",
@@ -150,15 +189,20 @@ def main():
150
  'date': "",
151
  'task': "",
152
  'hardware': "",
153
- 'energy': "?",
154
  'score': 5
155
  }
 
156
  if not selected_tasks:
157
  model_data = default_model_data
158
  else:
159
  dfs = []
160
  for task in selected_tasks:
161
- file_name = task_to_file[task]
 
 
 
 
162
  try:
163
  df = read_csv_from_hub(file_name)
164
  except FileNotFoundError:
@@ -168,15 +212,31 @@ def main():
168
  st.sidebar.error(f"Error reading '{file_name}' for task {task}: {e}")
169
  continue
170
 
 
171
  df['full_model'] = df['model']
172
  df[['provider', 'model']] = df['model'].str.split(pat='/', n=1, expand=True)
173
- # Multiply raw energy by 1000 to convert to Wh, then round to 2 decimals
 
174
  df['energy'] = (df['total_gpu_energy'] * 1000).round(2)
 
 
175
  df['score'] = df['energy_score'].fillna(1).astype(int)
176
- df['date'] = "February 2025"
 
177
  df['hardware'] = "NVIDIA H100-80GB"
178
  df['task'] = task
179
 
 
 
 
 
 
 
 
 
 
 
 
180
  dfs.append(df)
181
 
182
  if not dfs:
@@ -195,7 +255,7 @@ def main():
195
  model_data = data_df[data_df["full_model"] == selected_model].iloc[0]
196
 
197
  st.sidebar.write("#### 3. Download the label")
198
-
199
  try:
200
  score = int(model_data["score"])
201
  background_path = f"{score}.png"
@@ -228,21 +288,21 @@ def main():
228
  st.sidebar.markdown("<hr style='border: 1px solid gray; margin: 15px 0;'>", unsafe_allow_html=True)
229
  st.sidebar.write("### Key Links")
230
  st.sidebar.markdown(
231
- """
232
- <ul style="margin-top: 0; margin-bottom: 0; padding-left: 20px;">
233
- <li><a href="https://huggingface.co/spaces/AIEnergyScore/Leaderboard" target="_blank">Leaderboard</a></li>
234
- <li><a href="https://huggingface.co/spaces/AIEnergyScore/submission_portal" target="_blank">Submission Portal</a></li>
235
- <li><a href="https://huggingface.github.io/AIEnergyScore/#faq" target="_blank">FAQ</a></li>
236
- <li><a href="https://huggingface.github.io/AIEnergyScore/#documentation" target="_blank">Documentation</a></li>
237
- </ul>
238
- """,
239
- unsafe_allow_html=True,
240
  )
241
 
242
  def create_label_single_pass(background_image, model_data, final_size=(520, 728)):
243
  bg_resized = background_image.resize(final_size, Image.Resampling.LANCZOS)
244
 
245
- # If no task is selected (i.e. using default model_data), return the background without drawing any text.
246
  if not model_data.get("task"):
247
  return bg_resized
248
 
@@ -258,34 +318,33 @@ def create_label_single_pass(background_image, model_data, final_size=(520, 728)
258
 
259
  title_x, title_y = 33, 150
260
  details_x, details_y = 480, 256
261
- energy_x = 480 # Right margin for the energy value
262
- energy_y = 472
263
 
264
- # Capitalize only the first letter of the first word while keeping the rest as is
265
- def smart_capitalize(text):
266
- """Capitalizes the first letter of a string only if it's not already capitalized."""
267
- if not text:
268
- return text # Return unchanged if empty
269
- return text if text[0].isupper() else text[0].upper() + text[1:]
270
-
271
- # Apply smart capitalization
272
  provider_text = smart_capitalize(str(model_data['provider']))
273
  model_text = smart_capitalize(str(model_data['model']))
274
-
275
  draw.text((title_x, title_y), provider_text, font=title_font, fill="black")
276
  draw.text((title_x, title_y + 38), model_text, font=title_font, fill="black")
277
 
278
- details_lines = [str(model_data['date']), str(model_data['task']), str(model_data['hardware'])]
 
 
 
 
 
279
  for i, line in enumerate(details_lines):
280
  bbox = draw.textbbox((0, 0), line, font=details_font)
281
- text_width = bbox[2] - bbox[0] # Get text width
282
  draw.text((details_x - text_width, details_y + i * 47), line, font=details_font, fill="black")
283
 
284
- # Format the energy value to 2 decimal places and right-align the text
285
- energy_text = f"{model_data['energy']:.2f}"
 
 
 
 
286
  energy_bbox = draw.textbbox((0, 0), energy_text, font=energy_font)
287
  energy_text_width = energy_bbox[2] - energy_bbox[0]
288
-
289
  draw.text((energy_x - energy_text_width, energy_y), energy_text, font=energy_font, fill="black")
290
 
291
  return bg_resized
 
2
  import pandas as pd
3
  from PIL import Image, ImageDraw, ImageFont
4
  import io
5
+ import os
6
+ import socket
7
+ import calendar
8
+ import re
9
+ from typing import Optional
10
+ from huggingface_hub import hf_hub_download
11
+
12
+ # =========================
13
+ # Hugging Face Space config
14
+ # =========================
15
+ HF_REPO_ID = "AIEnergyScore/Leaderboard" # Space slug
16
+ HF_REPO_TYPE = "space"
17
+ HF_DATA_PREFIX = "data/energy" # path within the Space
18
 
19
+ # =========================
20
+ # Task -> CSV mapping
21
+ # =========================
22
  TASK_TO_CSV = {
23
+ "Text Generation": "text_generation.csv",
24
+ "Reasoning": "reasoning.csv", # now exists in your Space
25
+ "Image Generation": "image_generation.csv",
26
+ "Text Classification": "text_classification.csv",
27
+ "Image Classification": "image_classification.csv",
28
+ "Image Captioning": "image_captioning.csv",
29
+ "Summarization": "summarization.csv",
30
+ "Speech-to-Text (ASR)": "asr.csv",
31
+ "Object Detection": "object_detection.csv",
32
+ "Question Answering": "question_answering.csv",
33
+ "Sentence Similarity": "sentence_similarity.csv",
34
  }
35
+ # Back-compat if parts of the code still reference this name:
 
36
  task_to_file = TASK_TO_CSV
37
 
38
+ # =========================
39
+ # Helpers
40
+ # =========================
 
 
 
41
  def read_csv_from_hub(file_name: str) -> pd.DataFrame:
42
  """
43
+ Download a CSV from HF Space path data/energy/<file_name>,
44
+ return a pandas DataFrame. Falls back to local if hub unavailable.
 
45
  """
46
  hub_path = f"{HF_DATA_PREFIX}/{file_name}"
47
  try:
48
+ # helpful DNS check
49
  socket.gethostbyname("huggingface.co")
 
50
  local_path = hf_hub_download(
51
  repo_id=HF_REPO_ID,
52
  repo_type=HF_REPO_TYPE,
53
  filename=hub_path,
54
+ revision="main",
55
  resume_download=True
56
  )
57
  return pd.read_csv(local_path)
58
  except Exception as e:
 
59
  try:
60
  return pd.read_csv(file_name)
61
  except Exception:
 
62
  raise RuntimeError(
63
  f"Unable to load '{file_name}' from Hub path '{hub_path}' or locally. "
64
  f"Original error: {e}"
65
  )
66
 
67
+ def _normalize(col: str) -> str:
68
+ return re.sub(r"[^a-z0-9]", "", col.strip().lower())
69
+
70
+ def find_test_date_column(df: pd.DataFrame) -> Optional[str]:
71
+ """
72
+ Locate a 'test date' column. Strategy:
73
+ 1) Exact case-insensitive match 'test date'
74
+ 2) Any header whose normalized form contains both 'test' and 'date'
75
+ 3) Fallback to column E (index 4) if present
76
+ """
77
+ # (1) exact "test date"
78
+ for c in df.columns:
79
+ if c.strip().lower() == "test date":
80
+ return c
81
+ # (2) flexible match
82
+ for c in df.columns:
83
+ cn = _normalize(c)
84
+ if "test" in cn and "date" in cn:
85
+ return c
86
+ # (3) fallback to E (0-based index 4)
87
+ if len(df.columns) >= 5:
88
+ return df.columns[4]
89
+ return None
90
+
91
+ def month_abbrev_to_full(abbrev: str) -> Optional[str]:
92
+ """
93
+ Map 'Feb' -> 'February', 'Oct' -> 'October'. Returns None if unknown.
94
+ """
95
+ if not isinstance(abbrev, str) or not abbrev:
96
+ return None
97
+ abbr = abbrev.strip()[:3].title() # normalize to 3-letter case 'Oct'
98
+ for m in range(1, 13):
99
+ if calendar.month_abbr[m] == abbr:
100
+ return calendar.month_name[m]
101
+ return None
102
+
103
+ def render_date_from_test_date(value: str) -> str:
104
+ """
105
+ Accepts 'Oct 2025', 'Feb 2025' and returns 'October 2025', 'February 2025'.
106
+ Returns '' if it can’t parse.
107
+ """
108
+ if not isinstance(value, str):
109
+ return ""
110
+ s = value.strip()
111
+ m = re.match(r"^([A-Za-z]+)\s+(\d{4})$", s)
112
+ if not m:
113
+ return ""
114
+ month_full = month_abbrev_to_full(m.group(1))
115
+ return f"{month_full} {m.group(2)}" if month_full else ""
116
+
117
+ def smart_capitalize(text):
118
+ """Capitalize first letter only if not already; leave rest unchanged."""
119
+ if not text:
120
+ return text
121
+ return text if text[0].isupper() else text[0].upper() + text[1:]
122
+
123
+ # =========================
124
+ # UI / App
125
+ # =========================
126
  def main():
127
+ # Tag styling
128
  st.markdown(
129
  """
130
  <style>
 
131
  .stMultiSelect [data-baseweb="tag"] {
132
+ background-color: #3fa45bff !important;
133
+ color: white !important;
134
+ font-weight: 500;
135
  border-radius: 5px;
136
  padding: 5px 10px;
137
  }
138
+ .stMultiSelect [data-baseweb="tag"]:hover { background-color: #358d4d !important; }
139
+ .stMultiSelect input { color: black !important; }
 
 
 
 
 
 
 
 
140
  </style>
141
  """,
142
  unsafe_allow_html=True,
143
  )
144
 
145
+ # Sidebar logo & title
146
  with st.sidebar:
147
  col1, col2 = st.columns([1, 5])
 
148
  with col1:
149
  logo = Image.open("logo.png")
150
+ st.image(logo.resize((50, 50)))
 
 
151
  with col2:
152
  st.markdown(
153
  """
154
+ <div style="display:flex;align-items:center;gap:10px;margin:0;padding:0;
155
+ font-family:'Inter',sans-serif;font-size:26px;font-weight:500;">
 
 
 
 
 
 
 
156
  AI Energy Score
157
  </div>
158
  """,
 
161
 
162
  st.sidebar.markdown("<hr style='border: 1px solid gray; margin: 15px 0;'>", unsafe_allow_html=True)
163
  st.sidebar.write("### Generate Label:")
164
+
165
+ # Task order
166
  task_order = [
167
+ "Text Generation",
168
+ "Reasoning",
169
+ "Image Generation",
170
+ "Text Classification",
171
+ "Image Classification",
172
+ "Image Captioning",
173
+ "Summarization",
174
+ "Speech-to-Text (ASR)",
175
+ "Object Detection",
176
+ "Question Answering",
177
+ "Sentence Similarity",
178
  ]
179
+
180
+ # 1) Select task(s)
181
  st.sidebar.write("#### 1. Select task(s) to view models")
182
  selected_tasks = st.sidebar.multiselect("", options=task_order, default=["Text Generation"])
183
+
184
+ # Default when nothing selected
 
 
 
 
 
 
 
 
 
 
 
 
 
185
  default_model_data = {
186
  'provider': "AI Provider",
187
  'model': "Model Name",
 
189
  'date': "",
190
  'task': "",
191
  'hardware': "",
192
+ 'energy': 0.0,
193
  'score': 5
194
  }
195
+
196
  if not selected_tasks:
197
  model_data = default_model_data
198
  else:
199
  dfs = []
200
  for task in selected_tasks:
201
+ file_name = TASK_TO_CSV.get(task)
202
+ if not file_name:
203
+ st.sidebar.error(f"Unknown task '{task}'.")
204
+ continue
205
+
206
  try:
207
  df = read_csv_from_hub(file_name)
208
  except FileNotFoundError:
 
212
  st.sidebar.error(f"Error reading '{file_name}' for task {task}: {e}")
213
  continue
214
 
215
+ # Split provider/model if combined as "Provider/Model"
216
  df['full_model'] = df['model']
217
  df[['provider', 'model']] = df['model'].str.split(pat='/', n=1, expand=True)
218
+
219
+ # Convert kWh -> Wh (total_gpu_energy is in kWh); keep 2 decimals
220
  df['energy'] = (df['total_gpu_energy'] * 1000).round(2)
221
+
222
+ # Score
223
  df['score'] = df['energy_score'].fillna(1).astype(int)
224
+
225
+ # Hardware placeholder (adjust if you have a specific column)
226
  df['hardware'] = "NVIDIA H100-80GB"
227
  df['task'] = task
228
 
229
+ # --- DATE: Use CSV 'test date' for Text Generation & Reasoning ---
230
+ if task in {"Text Generation", "Reasoning"}:
231
+ td_col = find_test_date_column(df)
232
+ if td_col:
233
+ df['date'] = df[td_col].apply(render_date_from_test_date)
234
+ df['date'] = df['date'].fillna("").astype(str)
235
+ else:
236
+ df['date'] = ""
237
+ else:
238
+ df['date'] = ""
239
+
240
  dfs.append(df)
241
 
242
  if not dfs:
 
255
  model_data = data_df[data_df["full_model"] == selected_model].iloc[0]
256
 
257
  st.sidebar.write("#### 3. Download the label")
258
+
259
  try:
260
  score = int(model_data["score"])
261
  background_path = f"{score}.png"
 
288
  st.sidebar.markdown("<hr style='border: 1px solid gray; margin: 15px 0;'>", unsafe_allow_html=True)
289
  st.sidebar.write("### Key Links")
290
  st.sidebar.markdown(
291
+ """
292
+ <ul style="margin-top:0;margin-bottom:0;padding-left:20px;">
293
+ <li><a href="https://huggingface.co/spaces/AIEnergyScore/Leaderboard" target="_blank">Leaderboard</a></li>
294
+ <li><a href="https://huggingface.co/spaces/AIEnergyScore/submission_portal" target="_blank">Submission Portal</a></li>
295
+ <li><a href="https://huggingface.github.io/AIEnergyScore/#faq" target="_blank">FAQ</a></li>
296
+ <li><a href="https://huggingface.github.io/AIEnergyScore/#documentation" target="_blank">Documentation</a></li>
297
+ </ul>
298
+ """,
299
+ unsafe_allow_html=True,
300
  )
301
 
302
  def create_label_single_pass(background_image, model_data, final_size=(520, 728)):
303
  bg_resized = background_image.resize(final_size, Image.Resampling.LANCZOS)
304
 
305
+ # If no task is selected (i.e., using default model_data), return background
306
  if not model_data.get("task"):
307
  return bg_resized
308
 
 
318
 
319
  title_x, title_y = 33, 150
320
  details_x, details_y = 480, 256
321
+ energy_x, energy_y = 480, 472 # right-aligned anchors
 
322
 
 
 
 
 
 
 
 
 
323
  provider_text = smart_capitalize(str(model_data['provider']))
324
  model_text = smart_capitalize(str(model_data['model']))
325
+
326
  draw.text((title_x, title_y), provider_text, font=title_font, fill="black")
327
  draw.text((title_x, title_y + 38), model_text, font=title_font, fill="black")
328
 
329
+ # Right-align details lines (date, task, hardware)
330
+ details_lines = [
331
+ str(model_data.get('date', "")),
332
+ str(model_data.get('task', "")),
333
+ str(model_data.get('hardware', "")),
334
+ ]
335
  for i, line in enumerate(details_lines):
336
  bbox = draw.textbbox((0, 0), line, font=details_font)
337
+ text_width = bbox[2] - bbox[0]
338
  draw.text((details_x - text_width, details_y + i * 47), line, font=details_font, fill="black")
339
 
340
+ # Energy value (two decimals) right-aligned
341
+ try:
342
+ energy_value = float(model_data.get('energy', 0.0))
343
+ except Exception:
344
+ energy_value = 0.0
345
+ energy_text = f"{energy_value:.2f}"
346
  energy_bbox = draw.textbbox((0, 0), energy_text, font=energy_font)
347
  energy_text_width = energy_bbox[2] - energy_bbox[0]
 
348
  draw.text((energy_x - energy_text_width, energy_y), energy_text, font=energy_font, fill="black")
349
 
350
  return bg_resized