Spaces:
Sleeping
Sleeping
| import tempfile | |
| import gradio as gr | |
| from gradio_leaderboard import ColumnFilter, Leaderboard, SearchColumns, SelectColumns | |
| import enviroments.config as config | |
| from sheet_manager.sheet_loader.sheet_cache import ( | |
| get_cached_df, | |
| invalidate_cache, | |
| refresh_if_signal_newer, | |
| ) | |
| from utils.column_rules import ( | |
| AVG_DATASET, | |
| apply_avg_override, | |
| avg_categories, | |
| build_hide_columns, | |
| compute_display_columns, | |
| datasets_for_category, | |
| default_avg_map, | |
| extra_columns, | |
| parse_axes, | |
| ) | |
| def _default_display_columns(df): | |
| categories, _ = parse_axes(df.columns) | |
| default_cats = [c for c in config.DEFAULT_CATEGORIES if c in categories] | |
| return compute_display_columns( | |
| list(df.columns), default_cats, config.DEFAULT_DATASETS | |
| ) | |
| def leaderboard_tab(demo): | |
| """Leaderboard 탭. | |
| gradio_leaderboard.Leaderboard 는 __init__ 시점에 headers/select_columns_config 가 | |
| frozen 되므로 @gr.render 로 컴포넌트 자체를 재빌드한다. | |
| 컬럼 선택은 내장 체크박스(벤치마크 100여 개가 한 줄씩 나열되어 화면을 잡아먹음) | |
| 대신 카테고리 × 데이터셋 2축 + 추가 정보 셀렉터로 대체 — allow=False 로 내장 | |
| UI 를 숨기고, 선택 결과(selected_state)가 바뀔 때마다 default_selection 에 | |
| 반영해 재빌드한다. 축 목록은 utils/column_rules.py 가 df.columns 에서 자동 | |
| 추출하므로 신규 벤치마크 등록 시 별도 설정 없이 셀렉터에 나타난다. | |
| AVG_* 표시값은 시트 값 대신 UI 계산값으로 대체되는데, 계산 기준은 | |
| 표시용 데이터셋 드롭다운과 완전히 분리된 별도 접힘 섹션(avg_sel)에서만 | |
| 바뀐다 — 드롭다운으로 뭘 보든 AVG 는 항상 고정된 기준으로 계산된다. | |
| """ | |
| with gr.Tab("🏆Leaderboard"): | |
| with gr.Accordion( | |
| "🗂️ Select Columns to Display", open=True, elem_id="column-selector-acc" | |
| ): | |
| with gr.Row(): | |
| category_sel = gr.CheckboxGroup( | |
| choices=[], | |
| label="카테고리", | |
| scale=3, | |
| ) | |
| dataset_sel = gr.Dropdown( | |
| choices=[], | |
| value=[], | |
| multiselect=True, | |
| label="데이터셋 (비우면 전체)", | |
| scale=2, | |
| ) | |
| with gr.Row(): | |
| extras_sel = gr.CheckboxGroup( | |
| choices=[], | |
| label="추가 정보", | |
| scale=3, | |
| ) | |
| with gr.Column(scale=2): | |
| preset_default_btn = gr.Button("↩️ 기본 보기", size="sm") | |
| preset_all_btn = gr.Button("📋 전체 보기", size="sm") | |
| # AVG 계산 기준: 카테고리별 패널 (좌우 스크롤). 표시용 데이터셋 | |
| # 드롭다운과 무관하게 여기서 정한 기준으로만 AVG 가 계산된다. | |
| # 패널 구성(카테고리 수)은 앱 시작 시점 시트 기준으로 고정 — | |
| # AVG_<신규> 컬럼이 시트에 새로 생기면 앱 재시작 필요. | |
| axes_columns = list(get_cached_df().columns) | |
| avg_cat_list = avg_categories(axes_columns) | |
| initial_avg_map = default_avg_map(axes_columns) | |
| with gr.Accordion( | |
| "⚙️ AVG 계산 기준 — 카테고리별 (기본: 정식 벤치마크 세트)", | |
| open=False, | |
| elem_id="avg-basis-acc", | |
| ): | |
| avg_sels = {} | |
| with gr.Row(elem_id="avg-basis-row"): | |
| for cat in avg_cat_list: | |
| avg_sels[cat] = gr.CheckboxGroup( | |
| choices=datasets_for_category(axes_columns, cat), | |
| value=initial_avg_map.get(cat, []), | |
| label=f"AVG_{cat}", | |
| ) | |
| avg_reset_btn = gr.Button("↩️ 기본값 복원", size="sm") | |
| avg_sel_components = [avg_sels[c] for c in avg_cat_list] | |
| selected_state = gr.State(None) | |
| def _load_axes(): | |
| df = get_cached_df() | |
| categories, datasets = parse_axes(df.columns) | |
| default_cats = [c for c in config.DEFAULT_CATEGORIES if c in categories] | |
| dmap = default_avg_map(df.columns) | |
| avg_updates = [ | |
| gr.update( | |
| choices=datasets_for_category(df.columns, cat), | |
| value=dmap.get(cat, []), | |
| ) | |
| for cat in avg_cat_list | |
| ] | |
| return ( | |
| gr.update(choices=categories, value=default_cats), | |
| gr.update( | |
| choices=[AVG_DATASET] + datasets, value=config.DEFAULT_DATASETS | |
| ), | |
| gr.update(choices=extra_columns(df.columns), value=[]), | |
| *avg_updates, | |
| ) | |
| demo.load( | |
| _load_axes, | |
| inputs=[], | |
| outputs=[category_sel, dataset_sel, extras_sel, *avg_sel_components], | |
| ) | |
| def _selection_changed(cats, datasets, extras, *avg_values): | |
| df = get_cached_df() | |
| return { | |
| "columns": compute_display_columns( | |
| list(df.columns), cats, datasets, extras | |
| ), | |
| "avg": { | |
| cat: list(vals) for cat, vals in zip(avg_cat_list, avg_values) | |
| }, | |
| } | |
| for control in (category_sel, dataset_sel, extras_sel, *avg_sel_components): | |
| control.input( | |
| _selection_changed, | |
| [category_sel, dataset_sel, extras_sel, *avg_sel_components], | |
| [selected_state], | |
| ) | |
| def _reset_avg(cats, datasets, extras): | |
| df = get_cached_df() | |
| dmap = default_avg_map(df.columns) | |
| updates = [ | |
| gr.update(value=dmap.get(cat, [])) for cat in avg_cat_list | |
| ] | |
| state = { | |
| "columns": compute_display_columns( | |
| list(df.columns), cats, datasets, extras | |
| ), | |
| "avg": dmap, | |
| } | |
| return (*updates, state) | |
| avg_reset_btn.click( | |
| _reset_avg, | |
| inputs=[category_sel, dataset_sel, extras_sel], | |
| outputs=[*avg_sel_components, selected_state], | |
| ) | |
| def _apply_preset(categories, datasets, avg_values): | |
| df = get_cached_df() | |
| all_cats, _ = parse_axes(df.columns) | |
| if categories is None: | |
| cats = all_cats | |
| else: | |
| cats = [c for c in categories if c in all_cats] | |
| cols = compute_display_columns(list(df.columns), cats, datasets, []) | |
| return ( | |
| gr.update(value=cats), | |
| gr.update(value=datasets), | |
| gr.update(value=[]), | |
| { | |
| "columns": cols, | |
| "avg": { | |
| cat: list(vals) for cat, vals in zip(avg_cat_list, avg_values) | |
| }, | |
| }, | |
| ) | |
| preset_default_btn.click( | |
| lambda *avg: _apply_preset( | |
| config.DEFAULT_CATEGORIES, config.DEFAULT_DATASETS, avg | |
| ), | |
| inputs=avg_sel_components, | |
| outputs=[category_sel, dataset_sel, extras_sel, selected_state], | |
| ) | |
| preset_all_btn.click( | |
| lambda *avg: _apply_preset(None, [], avg), | |
| inputs=avg_sel_components, | |
| outputs=[category_sel, dataset_sel, extras_sel, selected_state], | |
| ) | |
| def _build_leaderboard(selection): | |
| avg_map = (selection or {}).get("avg") or None | |
| df = apply_avg_override(refresh_if_signal_newer(), avg_map) | |
| selected_cols = (selection or {}).get("columns") | |
| if not selected_cols: | |
| selected_cols = _default_display_columns(df) | |
| leaderboard = Leaderboard( | |
| value=df, | |
| select_columns=SelectColumns( | |
| default_selection=selected_cols, | |
| cant_deselect=config.OFF_LOAD_COLUMNS, | |
| allow=False, | |
| ), | |
| search_columns=SearchColumns( | |
| primary_column="Model name", | |
| secondary_columns=["TASK"], | |
| placeholder="Search", | |
| label="Search", | |
| ), | |
| hide_columns=build_hide_columns(list(df.columns)), | |
| filter_columns=[ColumnFilter(column="TASK")], | |
| datatype=config.TYPES, | |
| ) | |
| df_state = gr.State(value=df) | |
| refresh_button = gr.Button("🔄 Refresh Leaderboard") | |
| download_button = gr.Button("📥 Download Leaderboard (Excel)") | |
| download_file = gr.File(label="Download", visible=False) | |
| def refresh_leaderboard(): | |
| invalidate_cache() | |
| fresh = apply_avg_override(get_cached_df(), avg_map) | |
| return fresh, fresh | |
| def download_leaderboard(state_df): | |
| tmp = tempfile.NamedTemporaryFile( | |
| delete=False, | |
| suffix=".xlsx", | |
| prefix="leaderboard_", | |
| dir=tempfile.gettempdir(), | |
| ) | |
| tmp.close() | |
| state_df.to_excel(tmp.name, index=False, engine="openpyxl") | |
| return gr.File(value=tmp.name, visible=True) | |
| refresh_button.click( | |
| refresh_leaderboard, | |
| inputs=[], | |
| outputs=[leaderboard, df_state], | |
| ) | |
| download_button.click( | |
| download_leaderboard, | |
| inputs=[df_state], | |
| outputs=[download_file], | |
| ) | |