adpinzonp commited on
Commit
17f8527
·
verified ·
1 Parent(s): 2530cc3

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. app.py +215 -166
app.py CHANGED
@@ -1,25 +1,5 @@
 
1
  import pandas as pd
2
-
3
- def sheet_to_dataframe(sheet_url):
4
- """
5
- Converts a public Google Sheet into a pandas DataFrame.
6
- sheet_url: sheet URL ("https://docs.google.com/spreadsheets/d/ID/edit#gid=0")
7
- Returns: pandas DataFrame
8
- """
9
- import re
10
- m = re.search(r'/d/([a-zA-Z0-9-_]+)', sheet_url)
11
- gid = re.search(r'gid=([0-9]+)', sheet_url)
12
- if not m or not gid:
13
- raise ValueError("Invalid Google Sheets URL")
14
- sheet_id = m.group(1)
15
- gid = gid.group(1)
16
- # Build the CSV link
17
- csv_url = f"https://docs.google.com/spreadsheets/d/{sheet_id}/export?format=csv&gid={gid}"
18
- # Read the DataFrame
19
- df = pd.read_csv(csv_url)
20
- return df
21
-
22
- # ---------------- App code below ----------------
23
  import numpy as np
24
  import gradio as gr
25
  import plotly.graph_objects as go
@@ -31,21 +11,29 @@ warnings.filterwarnings("ignore", category=FutureWarning)
31
 
32
  DEFAULT_SHEET_URL = "https://docs.google.com/spreadsheets/d/1ygw8nrqI-FdHzyQGczKR5n3t01d-9sxMB_KVoClhoAg/edit?gid=0#gid=0"
33
 
 
 
 
 
 
 
 
 
 
 
 
 
34
 
 
35
  def _parse_percent_value(v):
36
  if v is None or (isinstance(v, float) and np.isnan(v)):
37
  return np.nan
38
  if isinstance(v, (int, float)):
39
  return float(v)
40
  s = str(v).strip()
41
- if s == "":
42
- return np.nan
43
- # Handle NA-like tokens
44
- if s.lower() in {"na", "n/a", "null", "none"}:
45
  return np.nan
46
- # Remove percent sign
47
  s = s.replace("%", "").replace(",", "").strip()
48
- # Handle dashes
49
  if s in {"-", "–", "—"}:
50
  return np.nan
51
  try:
@@ -53,225 +41,286 @@ def _parse_percent_value(v):
53
  except Exception:
54
  return np.nan
55
 
56
-
57
- def _split_columns(df):
58
- """First 4 columns are fixed; rest are benchmarks."""
59
- all_cols = list(df.columns)
60
- if len(all_cols) < 4:
61
- raise ValueError("The sheet must have at least the first four columns: Model, Company, Input price per 1MT, Output price per 1MT")
62
- fixed = all_cols[:4]
63
- benches = all_cols[4:]
64
  return fixed, benches
65
 
66
-
67
- def _clean_benchmarks(df):
68
- """Return numeric benchmark dataframe (0..100 scale if provided as %)."""
69
  fixed, benches = _split_columns(df)
70
  num = df.copy()
71
  for c in benches:
72
  num[c] = num[c].apply(_parse_percent_value)
73
  return num, benches, fixed
74
 
75
-
76
- def _style_table(df_display, benches, cmap="RdYlGn", vmin=0.0, vmax=100.0, precision=1):
77
- """Return an HTML string of a pandas Styler with background gradients on benchmark columns."""
 
 
78
  styler = (
79
- df_display.style
80
- .hide(axis="index")
81
  .format({c: f"{{:.{precision}f}}%" for c in benches}, na_rep="N/A")
82
  .background_gradient(axis=None, subset=benches, cmap=cmap, vmin=vmin, vmax=vmax)
83
- .set_table_styles(
84
- [
85
- {"selector": "th", "props": [("position", "sticky"), ("top", "0"), ("background", "#111"), ("color", "white"), ("z-index", "1")]},
86
- {"selector": "table", "props": [("border-collapse", "collapse"), ("font-family", "Inter, Roboto, Arial, sans-serif")]},
87
- {"selector": "td, th", "props": [("border", "1px solid #333"), ("padding", "6px 8px")]},
88
- {"selector": "tbody tr:nth-child(odd)", "props": [("background-color", "#161616")]},
89
- {"selector": "tbody tr:nth-child(even)", "props": [("background-color", "#0f0f0f")]},
90
- ]
91
- )
92
  .set_properties(subset=df_display.columns[:4], **{"font-weight": "600"})
93
  )
 
 
 
 
 
 
 
 
94
  return styler.to_html()
95
 
96
-
97
- def _filter_rows(df_raw, df_num, benches, text_query, bench_choice, comparator, threshold):
 
 
98
  mask = pd.Series(True, index=df_raw.index)
 
99
  if text_query:
100
  tq = str(text_query).strip().lower()
101
- # Search in Model + Company
102
- mc = (df_raw.iloc[:, 0].astype(str).str.lower().fillna("")
103
- + " " +
104
  df_raw.iloc[:, 1].astype(str).str.lower().fillna(""))
105
  mask &= mc.str.contains(tq, na=False)
106
 
107
  if bench_choice == "Any":
108
  bench_vals = df_num[benches]
109
  if comparator == "≥":
110
- mask &= (bench_vals.ge(threshold)).any(axis=1).fillna(False)
111
  else:
112
- mask &= (bench_vals.le(threshold)).any(axis=1).fillna(False)
113
  elif bench_choice and bench_choice in benches:
114
  col_vals = df_num[bench_choice]
115
- if comparator == "≥":
116
- mask &= col_vals.ge(threshold).fillna(False)
117
- else:
118
- mask &= col_vals.le(threshold).fillna(False)
119
-
120
- return df_raw.loc[mask].reset_index(drop=True), df_num.loc[mask].reset_index(drop=True)
121
-
122
-
123
- def _build_correlation_plot(df_num, benches):
124
- if len(benches) == 0:
125
- fig = go.Figure()
126
- fig.update_layout(title="No benchmark columns found")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127
  return fig
128
-
129
  mat = df_num[benches].astype(float)
130
- if mat.shape[1] == 1:
131
- corr = pd.DataFrame([[1.0]], index=benches, columns=benches)
132
- else:
133
- corr = mat.corr(method="pearson")
134
-
135
- fig = go.Figure(
136
- data=go.Heatmap(
137
- z=corr.values,
138
- x=list(corr.columns),
139
- y=list(corr.index),
140
- colorscale="RdYlGn",
141
- zmin=-1,
142
- zmax=1,
143
- colorbar=dict(title="ρ"),
144
- hoverongaps=False,
145
- )
146
- )
147
- fig.update_layout(
148
- title="Correlation between benchmark variables",
149
- xaxis_nticks=max(5, min(20, len(benches))),
150
- yaxis_nticks=max(5, min(20, len(benches))),
151
- margin=dict(l=60, r=20, t=60, b=60),
152
- height=600,
153
- )
154
  return fig
155
 
156
-
157
  def fetch_and_prepare(url):
158
  df_raw = sheet_to_dataframe(url)
159
  df_num, benches, fixed = _clean_benchmarks(df_raw)
160
  return df_raw, df_num, benches, fixed
161
 
 
 
 
 
 
162
 
163
- def refetch_all(t1_q, t1_bench, t1_op, t1_thr, t3_q, t3_bench, t3_op, t3_thr):
164
- # Always re-fetch from the default sheet
165
- df_raw, df_num, benches, _ = fetch_and_prepare(DEFAULT_SHEET_URL)
166
-
167
- # Correlation
168
  fig_corr = _build_correlation_plot(df_num, benches)
169
 
170
- # Tab 1 initial render (with current filters)
171
- df1_raw_f, df1_num_f = _filter_rows(df_raw, df_num, benches, t1_q, t1_bench, t1_op, t1_thr)
172
- html_tab1 = _style_table(pd.concat([df1_raw_f.iloc[:, :4], df1_num_f[benches]], axis=1), benches)
 
 
 
173
 
174
- # Imputation for Tab 3
175
  bench_only = df_num[benches].astype(float)
 
176
  if bench_only.shape[1] > 1:
177
  imputer = IterativeImputer(random_state=0, sample_posterior=False, max_iter=15, initial_strategy="mean")
178
- bench_imp = pd.DataFrame(imputer.fit_transform(bench_only), columns=benches)
179
  else:
180
- simp = SimpleImputer(strategy="mean")
181
- bench_imp = pd.DataFrame(simp.fit_transform(bench_only), columns=benches)
182
-
183
- # Tab 3 initial render (with current filters)
184
- df3_raw_f, df3_num_f = _filter_rows(df_raw, bench_imp, benches, t3_q, t3_bench, t3_op, t3_thr)
185
- html_tab3 = _style_table(pd.concat([df3_raw_f.iloc[:, :4], df3_num_f[benches]], axis=1), benches)
186
-
187
- # Dropdown choices
 
 
 
 
 
188
  bench_options = ["Any"] + benches
 
189
 
190
- # Return UI updates and persistent states
191
  return (
192
- html_tab1, # t1_html
193
- fig_corr, # corr_plot
194
- html_tab3, # t3_html
195
  gr.update(choices=bench_options, value=t1_bench if t1_bench in bench_options else "Any"),
 
196
  gr.update(choices=bench_options, value=t3_bench if t3_bench in bench_options else "Any"),
197
- df_raw, # s_df_raw
198
- df_num, # s_df_num
199
- benches, # s_benches
200
- bench_imp # s_bench_imp
201
  )
202
 
203
-
204
- def filter_tab1(s_df_raw, s_df_num, s_benches, text_query, bench_choice, comparator, threshold):
205
- df1_raw_f, df1_num_f = _filter_rows(s_df_raw, s_df_num, s_benches, text_query, bench_choice, comparator, threshold)
206
- html_tab1 = _style_table(pd.concat([df1_raw_f.iloc[:, :4], df1_num_f[s_benches]], axis=1), s_benches)
207
- return html_tab1
208
-
209
-
210
- def filter_tab3(s_df_raw, s_bench_imp, s_benches, text_query, bench_choice, comparator, threshold):
211
- df3_raw_f, df3_num_f = _filter_rows(s_df_raw, s_bench_imp, s_benches, text_query, bench_choice, comparator, threshold)
212
- html_tab3 = _style_table(pd.concat([df3_raw_f.iloc[:, :4], df3_num_f[s_benches]], axis=1), s_benches)
213
- return html_tab3
214
-
215
-
 
 
 
 
 
 
 
 
 
 
 
216
  with gr.Blocks(css="""
217
  /* Scroll horizontal */
218
  .table-wrap { overflow-x: auto; }
219
-
220
- /* Oculta la columna de índice en todas las tablas */
221
  .table-wrap table th.row_heading,
222
  .table-wrap table td.row_heading,
223
  .table-wrap table th.blank {
224
  display: none !important;
225
  }
226
  """) as demo:
227
- gr.Markdown("## Reasoning Modeels benchmark")
 
228
 
229
  with gr.Row():
230
- reload_btn = gr.Button("Reload", variant="primary", scale=1)
231
 
232
- # States to cache the last fetched data for responsive filtering
233
- s_df_raw = gr.State()
234
- s_df_num = gr.State()
235
- s_benches = gr.State()
236
- s_bench_imp = gr.State()
 
237
 
238
  with gr.Tabs():
 
 
239
  with gr.Tab("Original table"):
240
  with gr.Row():
241
- t1_q = gr.Textbox(label="Filter: Model/Company contains", placeholder="e.g., llama", scale=2)
242
- t1_bench = gr.Dropdown(choices=["Any"], value="Any", label="Benchmark", scale=1)
243
- t1_op = gr.Radio(choices=["≥", "≤"], value="≥", label="Comparator", scale=1)
244
- t1_thr = gr.Slider(minimum=0, maximum=100, value=0, step=1, label="Threshold (%)", scale=1)
 
 
 
 
245
  t1_html = gr.HTML(elem_classes=["table-wrap"])
246
 
 
247
  with gr.Tab("Correlation matrix"):
248
  corr_plot = gr.Plot()
249
 
 
250
  with gr.Tab("Imputed table"):
251
  with gr.Row():
252
- t3_q = gr.Textbox(label="Filter: Model/Company contains", placeholder="e.g., llama", scale=2)
253
- t3_bench = gr.Dropdown(choices=["Any"], value="Any", label="Benchmark", scale=1)
254
- t3_op = gr.Radio(choices=["≥", "≤"], value="≥", label="Comparator", scale=1)
255
- t3_thr = gr.Slider(minimum=0, maximum=100, value=0, step=1, label="Threshold (%)", scale=1)
 
 
 
256
  t3_html = gr.HTML(elem_classes=["table-wrap"])
257
 
258
- # On load and on reload, re-fetch from Google Sheets and rebuild everything
259
- args_reload = [t1_q, t1_bench, t1_op, t1_thr, t3_q, t3_bench, t3_op, t3_thr]
260
- outs_reload = [t1_html, corr_plot, t3_html, t1_bench, t3_bench, s_df_raw, s_df_num, s_benches, s_bench_imp]
261
-
 
 
 
 
 
 
 
262
  demo.load(refetch_all, inputs=args_reload, outputs=outs_reload)
263
  reload_btn.click(refetch_all, inputs=args_reload, outputs=outs_reload)
264
 
265
- # Live filtering without refetching
266
- t1_q.change(filter_tab1, inputs=[s_df_raw, s_df_num, s_benches, t1_q, t1_bench, t1_op, t1_thr], outputs=[t1_html])
267
- t1_bench.change(filter_tab1, inputs=[s_df_raw, s_df_num, s_benches, t1_q, t1_bench, t1_op, t1_thr], outputs=[t1_html])
268
- t1_op.change(filter_tab1, inputs=[s_df_raw, s_df_num, s_benches, t1_q, t1_bench, t1_op, t1_thr], outputs=[t1_html])
269
- t1_thr.change(filter_tab1, inputs=[s_df_raw, s_df_num, s_benches, t1_q, t1_bench, t1_op, t1_thr], outputs=[t1_html])
 
 
 
 
270
 
271
- t3_q.change(filter_tab3, inputs=[s_df_raw, s_bench_imp, s_benches, t3_q, t3_bench, t3_op, t3_thr], outputs=[t3_html])
272
- t3_bench.change(filter_tab3, inputs=[s_df_raw, s_bench_imp, s_benches, t3_q, t3_bench, t3_op, t3_thr], outputs=[t3_html])
273
- t3_op.change(filter_tab3, inputs=[s_df_raw, s_bench_imp, s_benches, t3_q, t3_bench, t3_op, t3_thr], outputs=[t3_html])
274
- t3_thr.change(filter_tab3, inputs=[s_df_raw, s_bench_imp, s_benches, t3_q, t3_bench, t3_op, t3_thr], outputs=[t3_html])
 
 
 
 
 
275
 
276
  if __name__ == "__main__":
277
  demo.launch()
 
1
+ import re
2
  import pandas as pd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  import numpy as np
4
  import gradio as gr
5
  import plotly.graph_objects as go
 
11
 
12
  DEFAULT_SHEET_URL = "https://docs.google.com/spreadsheets/d/1ygw8nrqI-FdHzyQGczKR5n3t01d-9sxMB_KVoClhoAg/edit?gid=0#gid=0"
13
 
14
+ # Columnas con formato monetario
15
+ PRICE_COLS = ["Input price per 1MT", "Output price per 1MT"]
16
+
17
+ # ---------- Carga de Google Sheet ----------
18
+ def sheet_to_dataframe(sheet_url: str) -> pd.DataFrame:
19
+ m = re.search(r'/d/([a-zA-Z0-9-_]+)', sheet_url)
20
+ gid = re.search(r'gid=([0-9]+)', sheet_url)
21
+ if not m or not gid:
22
+ raise ValueError("Invalid Google Sheets URL")
23
+ sheet_id, gid = m.group(1), gid.group(1)
24
+ csv_url = f"https://docs.google.com/spreadsheets/d/{sheet_id}/export?format=csv&gid={gid}"
25
+ return pd.read_csv(csv_url)
26
 
27
+ # ---------- Limpieza / parsing ----------
28
  def _parse_percent_value(v):
29
  if v is None or (isinstance(v, float) and np.isnan(v)):
30
  return np.nan
31
  if isinstance(v, (int, float)):
32
  return float(v)
33
  s = str(v).strip()
34
+ if not s or s.lower() in {"na", "n/a", "null", "none"}:
 
 
 
35
  return np.nan
 
36
  s = s.replace("%", "").replace(",", "").strip()
 
37
  if s in {"-", "–", "—"}:
38
  return np.nan
39
  try:
 
41
  except Exception:
42
  return np.nan
43
 
44
+ def _split_columns(df: pd.DataFrame):
45
+ cols = list(df.columns)
46
+ if len(cols) < 4:
47
+ raise ValueError("Sheet must have at least 4 columns")
48
+ fixed = cols[:4]
49
+ benches = cols[4:]
 
 
50
  return fixed, benches
51
 
52
+ def _clean_benchmarks(df: pd.DataFrame):
 
 
53
  fixed, benches = _split_columns(df)
54
  num = df.copy()
55
  for c in benches:
56
  num[c] = num[c].apply(_parse_percent_value)
57
  return num, benches, fixed
58
 
59
+ # ---------- Estilos ----------
60
+ def _style_table(df_display: pd.DataFrame, benches,
61
+ cmap="RdYlGn", vmin=0.0, vmax=100.0,
62
+ precision=1, imputed_mask: pd.DataFrame | None = None) -> str:
63
+ styler = df_display.style.hide(axis="index")
64
  styler = (
65
+ styler
 
66
  .format({c: f"{{:.{precision}f}}%" for c in benches}, na_rep="N/A")
67
  .background_gradient(axis=None, subset=benches, cmap=cmap, vmin=vmin, vmax=vmax)
68
+ .set_table_styles([
69
+ {"selector": "th", "props": [("position", "sticky"), ("top", "0"), ("background", "#111"), ("color", "white"), ("z-index", "1")]},
70
+ {"selector": "table", "props": [("border-collapse", "collapse"), ("font-family", "Inter, Roboto, Arial, sans-serif")]},
71
+ {"selector": "td, th", "props": [("border", "1px solid #333"), ("padding", "6px 8px")]},
72
+ {"selector": "tbody tr:nth-child(odd)", "props": [("background-color", "#161616")]},
73
+ {"selector": "tbody tr:nth-child(even)", "props": [("background-color", "#0f0f0f")]}
74
+ ])
 
 
75
  .set_properties(subset=df_display.columns[:4], **{"font-weight": "600"})
76
  )
77
+ if imputed_mask is not None:
78
+ # imputed_mask debe tener mismas filas/columnas que df_display[benches]
79
+ def highlight(df):
80
+ styles = pd.DataFrame("", index=df.index, columns=df.columns)
81
+ for col in benches:
82
+ styles.loc[imputed_mask[col], col] = "border: 2px dashed yellow;"
83
+ return styles
84
+ styler = styler.apply(highlight, axis=None)
85
  return styler.to_html()
86
 
87
+ # ---------- Filtros y orden ----------
88
+ def _filter_rows(df_raw: pd.DataFrame, df_num: pd.DataFrame, benches,
89
+ text_query, bench_choice, comparator, threshold):
90
+ """Devuelve dataframes filtrados, conservando índices originales (sin reset)."""
91
  mask = pd.Series(True, index=df_raw.index)
92
+
93
  if text_query:
94
  tq = str(text_query).strip().lower()
95
+ mc = (df_raw.iloc[:, 0].astype(str).str.lower().fillna("") + " " +
 
 
96
  df_raw.iloc[:, 1].astype(str).str.lower().fillna(""))
97
  mask &= mc.str.contains(tq, na=False)
98
 
99
  if bench_choice == "Any":
100
  bench_vals = df_num[benches]
101
  if comparator == "≥":
102
+ mask &= bench_vals.ge(threshold).any(axis=1).fillna(False)
103
  else:
104
+ mask &= bench_vals.le(threshold).any(axis=1).fillna(False)
105
  elif bench_choice and bench_choice in benches:
106
  col_vals = df_num[bench_choice]
107
+ mask &= (col_vals.ge(threshold) if comparator == "≥" else col_vals.le(threshold)).fillna(False)
108
+
109
+ return df_raw.loc[mask], df_num.loc[mask]
110
+
111
+ def _numeric_key_for_price(series: pd.Series) -> pd.Series:
112
+ """Convierte strings con $ y comas a float para ordenar correctamente."""
113
+ key = series.astype(str).str.replace(r"[^\d\.\-]", "", regex=True)
114
+ return pd.to_numeric(key, errors="coerce")
115
+
116
+ def _sort_df(df_full: pd.DataFrame, sort_col: str, ascending: bool) -> pd.DataFrame:
117
+ """Ordena por columna; para PRICE_COLS aplica orden numérico."""
118
+ if not sort_col:
119
+ return df_full
120
+ if sort_col in PRICE_COLS:
121
+ key = _numeric_key_for_price(df_full[sort_col])
122
+ return (
123
+ df_full.assign(_key=key)
124
+ .sort_values("_key", ascending=ascending, na_position="last")
125
+ .drop(columns="_key")
126
+ )
127
+ return df_full.sort_values(sort_col, ascending=ascending, na_position="last")
128
+
129
+ def _sort_with_mask(df_full: pd.DataFrame, mask: pd.DataFrame, sort_col: str, ascending: bool):
130
+ """Ordena df y reordena la máscara imputed en la misma forma."""
131
+ if not sort_col:
132
+ return df_full, mask
133
+ if sort_col in PRICE_COLS:
134
+ key = _numeric_key_for_price(df_full[sort_col])
135
+ else:
136
+ key = df_full[sort_col]
137
+ order = pd.Series(key).sort_values(ascending=ascending, na_position="last").index
138
+ return df_full.loc[order], mask.loc[order]
139
+
140
+ # ---------- Correlación ----------
141
+ def _build_correlation_plot(df_num: pd.DataFrame, benches):
142
+ if not benches:
143
+ fig = go.Figure(); fig.update_layout(title="No benchmark columns found")
144
  return fig
 
145
  mat = df_num[benches].astype(float)
146
+ corr = mat.corr() if mat.shape[1] > 1 else pd.DataFrame([[1.0]], index=benches, columns=benches)
147
+ fig = go.Figure(data=go.Heatmap(
148
+ z=corr.values, x=list(corr.columns), y=list(corr.index),
149
+ colorscale="RdYlGn", zmin=-1, zmax=1, colorbar=dict(title="ρ"), hoverongaps=False
150
+ ))
151
+ fig.update_layout(title="Correlation between benchmark variables",
152
+ xaxis_nticks=min(20, len(benches)),
153
+ yaxis_nticks=min(20, len(benches)),
154
+ margin=dict(l=60, r=20, t=60, b=60), height=600)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
155
  return fig
156
 
157
+ # ---------- Ciclos de carga y UI ----------
158
  def fetch_and_prepare(url):
159
  df_raw = sheet_to_dataframe(url)
160
  df_num, benches, fixed = _clean_benchmarks(df_raw)
161
  return df_raw, df_num, benches, fixed
162
 
163
+ def refetch_all(
164
+ t1_q, t1_bench, t1_op, t1_thr, t1_sort_col, t1_sort_dir,
165
+ t3_q, t3_bench, t3_op, t3_thr, t3_sort_col, t3_sort_dir
166
+ ):
167
+ df_raw, df_num, benches, fixed = fetch_and_prepare(DEFAULT_SHEET_URL)
168
 
169
+ # Correlación
 
 
 
 
170
  fig_corr = _build_correlation_plot(df_num, benches)
171
 
172
+ # ----- TAB 1: ORIGINAL -----
173
+ df1_raw, df1_num = _filter_rows(df_raw, df_num, benches, t1_q, t1_bench, t1_op, t1_thr)
174
+ df1_full = pd.concat([df1_raw.iloc[:, :4], df1_num[benches]], axis=1)
175
+ df1_full = _sort_df(df1_full, t1_sort_col, ascending=(t1_sort_dir == "asc"))
176
+ df1_full = df1_full.reset_index(drop=True)
177
+ html_tab1 = _style_table(df1_full, benches)
178
 
179
+ # ----- TAB 3: IMPUTED -----
180
  bench_only = df_num[benches].astype(float)
181
+ orig_nan = bench_only.isna()
182
  if bench_only.shape[1] > 1:
183
  imputer = IterativeImputer(random_state=0, sample_posterior=False, max_iter=15, initial_strategy="mean")
184
+ bench_imp = pd.DataFrame(imputer.fit_transform(bench_only), columns=benches, index=bench_only.index)
185
  else:
186
+ bench_imp = pd.DataFrame(SimpleImputer(strategy="mean").fit_transform(bench_only),
187
+ columns=benches, index=bench_only.index)
188
+ bench_imp = bench_imp.clip(lower=0.0)
189
+
190
+ df3_raw, df3_num = _filter_rows(df_raw, bench_imp, benches, t3_q, t3_bench, t3_op, t3_thr)
191
+ df3_full = pd.concat([df3_raw.iloc[:, :4], df3_num[benches]], axis=1)
192
+ mask3 = orig_nan.loc[df3_num.index] # Máscara alineada a las filas filtradas
193
+ df3_full, mask3 = _sort_with_mask(df3_full, mask3, t3_sort_col, ascending=(t3_sort_dir == "asc"))
194
+ df3_full = df3_full.reset_index(drop=True)
195
+ mask3 = mask3.reset_index(drop=True)
196
+ html_tab3 = _style_table(df3_full, benches, imputed_mask=mask3)
197
+
198
+ # Opciones de dropdown
199
  bench_options = ["Any"] + benches
200
+ sort_options = fixed + benches
201
 
 
202
  return (
203
+ html_tab1,
204
+ fig_corr,
205
+ html_tab3,
206
  gr.update(choices=bench_options, value=t1_bench if t1_bench in bench_options else "Any"),
207
+ gr.update(choices=sort_options, value=(t1_sort_col if t1_sort_col in sort_options else "Input price per 1MT")),
208
  gr.update(choices=bench_options, value=t3_bench if t3_bench in bench_options else "Any"),
209
+ gr.update(choices=sort_options, value=(t3_sort_col if t3_sort_col in sort_options else "Input price per 1MT")),
210
+ df_raw, df_num, benches, bench_imp, orig_nan
 
 
211
  )
212
 
213
+ def filter_tab1(
214
+ s_df_raw, s_df_num, s_benches,
215
+ t1_q, t1_bench, t1_op, t1_thr,
216
+ t1_sort_col, t1_sort_dir
217
+ ):
218
+ df1_raw, df1_num = _filter_rows(s_df_raw, s_df_num, s_benches, t1_q, t1_bench, t1_op, t1_thr)
219
+ df1_full = pd.concat([df1_raw.iloc[:, :4], df1_num[s_benches]], axis=1)
220
+ df1_full = _sort_df(df1_full, t1_sort_col, ascending=(t1_sort_dir == "asc")).reset_index(drop=True)
221
+ return _style_table(df1_full, s_benches)
222
+
223
+ def filter_tab3(
224
+ s_df_raw, s_bench_imp, s_benches, s_imput_mask,
225
+ t3_q, t3_bench, t3_op, t3_thr,
226
+ t3_sort_col, t3_sort_dir
227
+ ):
228
+ df3_raw, df3_num = _filter_rows(s_df_raw, s_bench_imp, s_benches, t3_q, t3_bench, t3_op, t3_thr)
229
+ df3_full = pd.concat([df3_raw.iloc[:, :4], df3_num[s_benches]], axis=1)
230
+ mask3 = s_imput_mask.loc[df3_num.index]
231
+ df3_full, mask3 = _sort_with_mask(df3_full, mask3, t3_sort_col, ascending=(t3_sort_dir == "asc"))
232
+ df3_full = df3_full.reset_index(drop=True)
233
+ mask3 = mask3.reset_index(drop=True)
234
+ return _style_table(df3_full, s_benches, imputed_mask=mask3)
235
+
236
+ # ---------- UI ----------
237
  with gr.Blocks(css="""
238
  /* Scroll horizontal */
239
  .table-wrap { overflow-x: auto; }
240
+ /* Oculta la columna de índice */
 
241
  .table-wrap table th.row_heading,
242
  .table-wrap table td.row_heading,
243
  .table-wrap table th.blank {
244
  display: none !important;
245
  }
246
  """) as demo:
247
+
248
+ gr.Markdown("## Reasoning Models Benchmarks")
249
 
250
  with gr.Row():
251
+ reload_btn = gr.Button("Reload", variant="primary")
252
 
253
+ # States
254
+ s_df_raw = gr.State()
255
+ s_df_num = gr.State()
256
+ s_benches = gr.State()
257
+ s_bench_imp = gr.State()
258
+ s_imput_mask = gr.State()
259
 
260
  with gr.Tabs():
261
+
262
+ # Tab 1: Original
263
  with gr.Tab("Original table"):
264
  with gr.Row():
265
+ t1_q = gr.Textbox(label="Filter: Model/Company contains", placeholder="e.g., llama", scale=2)
266
+ t1_bench = gr.Dropdown(choices=["Any"], value="Any", label="Benchmark")
267
+ t1_op = gr.Radio(choices=["≥", "≤"], value="≥", label="Comparator")
268
+ t1_thr = gr.Slider(minimum=0, maximum=100, value=0, step=1, label="Threshold (%)")
269
+ # Inicializa choices y value neutros; se actualizan en refetch_all
270
+ t1_sort_col = gr.Dropdown(choices=["Model","Company","Input price per 1MT","Output price per 1MT"],
271
+ value=None, label="Sort by")
272
+ t1_sort_dir = gr.Radio(choices=["asc", "desc"], value="asc", label="Direction")
273
  t1_html = gr.HTML(elem_classes=["table-wrap"])
274
 
275
+ # Tab 2: Correlation
276
  with gr.Tab("Correlation matrix"):
277
  corr_plot = gr.Plot()
278
 
279
+ # Tab 3: Imputed
280
  with gr.Tab("Imputed table"):
281
  with gr.Row():
282
+ t3_q = gr.Textbox(label="Filter: Model/Company contains", placeholder="e.g., llama", scale=2)
283
+ t3_bench = gr.Dropdown(choices=["Any"], value="Any", label="Benchmark")
284
+ t3_op = gr.Radio(choices=["≥", "≤"], value="≥", label="Comparator")
285
+ t3_thr = gr.Slider(minimum=0, maximum=100, value=0, step=1, label="Threshold (%)")
286
+ t3_sort_col = gr.Dropdown(choices=["Model","Company","Input price per 1MT","Output price per 1MT"],
287
+ value=None, label="Sort by")
288
+ t3_sort_dir = gr.Radio(choices=["asc", "desc"], value="asc", label="Direction")
289
  t3_html = gr.HTML(elem_classes=["table-wrap"])
290
 
291
+ # Load / Reload
292
+ args_reload = [
293
+ t1_q, t1_bench, t1_op, t1_thr, t1_sort_col, t1_sort_dir,
294
+ t3_q, t3_bench, t3_op, t3_thr, t3_sort_col, t3_sort_dir
295
+ ]
296
+ outs_reload = [
297
+ t1_html, corr_plot, t3_html,
298
+ t1_bench, t1_sort_col,
299
+ t3_bench, t3_sort_col,
300
+ s_df_raw, s_df_num, s_benches, s_bench_imp, s_imput_mask
301
+ ]
302
  demo.load(refetch_all, inputs=args_reload, outputs=outs_reload)
303
  reload_btn.click(refetch_all, inputs=args_reload, outputs=outs_reload)
304
 
305
+ # Eventos en vivo TAB 1
306
+ for comp in [t1_q, t1_bench, t1_op, t1_thr, t1_sort_col, t1_sort_dir]:
307
+ comp.change(
308
+ filter_tab1,
309
+ inputs=[s_df_raw, s_df_num, s_benches,
310
+ t1_q, t1_bench, t1_op, t1_thr,
311
+ t1_sort_col, t1_sort_dir],
312
+ outputs=[t1_html]
313
+ )
314
 
315
+ # Eventos en vivo TAB 3
316
+ for comp in [t3_q, t3_bench, t3_op, t3_thr, t3_sort_col, t3_sort_dir]:
317
+ comp.change(
318
+ filter_tab3,
319
+ inputs=[s_df_raw, s_bench_imp, s_benches, s_imput_mask,
320
+ t3_q, t3_bench, t3_op, t3_thr,
321
+ t3_sort_col, t3_sort_dir],
322
+ outputs=[t3_html]
323
+ )
324
 
325
  if __name__ == "__main__":
326
  demo.launch()