fzliu q275343119 commited on
Commit
41e170e
·
verified ·
1 Parent(s): 6622db2

Repository Migration (#1)

Browse files

- mod - Repository Migration (a9340d426936185e42ddec717a929b4781341490)


Co-authored-by: Y <[email protected]>

app.py ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+
3
+ import streamlit as st
4
+
5
+ from st_pages import get_nav_from_toml, add_page_title
6
+
7
+ from app.backend.app_init_func import LI_CSS, init_leaderboard, init_pages
8
+ from app.backend.data_engine import DataEngine
9
+
10
+ # init global data engine
11
+ data_engine = DataEngine()
12
+
13
+ st.session_state["data_engine"] = data_engine
14
+ st.set_page_config(layout="wide")
15
+
16
+ # init leaderboard and pages
17
+ leaderboard_change, page_change = init_leaderboard()
18
+
19
+ init_pages(leaderboard_change, page_change)
20
+
21
+ # load page tree
22
+ nav = get_nav_from_toml(
23
+ "app/ui/pages_sections.toml"
24
+ )
25
+
26
+ # Add custom CSS
27
+ css = "\n".join(LI_CSS)
28
+ st.markdown(f"""
29
+ <style>
30
+
31
+ div[data-testid="stToolbar"] {{visibility: hidden; height: 0px;}}
32
+
33
+ footer {{visibility: hidden;}}
34
+ </style>
35
+
36
+ <style>
37
+ {css}
38
+ </style>
39
+ """
40
+ , unsafe_allow_html=True)
41
+
42
+ pg = st.navigation(nav)
43
+
44
+ # add_page_title(pg)
45
+
46
+ pg.run()
app/__init__.py ADDED
@@ -0,0 +1 @@
 
 
1
+
app/backend/__init__.py ADDED
@@ -0,0 +1 @@
 
 
1
+
app/backend/app_init_func.py ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import os
3
+
4
+ from app.backend.constant import LEADERBOARD_ICON_MAP
5
+
6
+ LEADERBOARD_MAP = {}
7
+ LI_CSS = []
8
+ PAGE_SECTIONS = []
9
+
10
+
11
+ def init_leaderboard():
12
+ data_engine = st.session_state["data_engine"]
13
+ leaderboard_map = {}
14
+ page_sections = []
15
+ li_css = []
16
+ sort_id = 0
17
+ leaderboard_change = False
18
+ page_change = False
19
+
20
+ for dataset in data_engine.datasets:
21
+ sort_id += 1
22
+ leaderboard = dataset["leaderboard"]
23
+ name = dataset["name"]
24
+
25
+ leaderboard_section = f"{leaderboard.capitalize()} Leaderboard"
26
+ if leaderboard_section not in leaderboard_map:
27
+ leaderboard_map[leaderboard_section] = []
28
+ if name.lower() == leaderboard.lower():
29
+ leaderboard_map[leaderboard_section].append((name, 0))
30
+ else:
31
+ leaderboard_map[leaderboard_section].append((name, sort_id))
32
+ li_css.append(f"""
33
+ ul[data-testid="stSidebarNavItems"] li:nth-child({sort_id}) {{
34
+ text-indent: 2rem;
35
+ }}
36
+ """)
37
+ page_name = leaderboard_section if name.lower() == leaderboard.lower() else name.capitalize()
38
+ page_sections.append(f"""
39
+ [[pages]]
40
+ path = "app/ui/pages/{name}.py"
41
+ name = "{page_name}"
42
+ icon = "{LEADERBOARD_ICON_MAP.get(page_name, "")}"
43
+ """)
44
+
45
+ # ensure leaderboard is first
46
+ for k, v in leaderboard_map.items():
47
+ v.sort(key=lambda x: x[1])
48
+
49
+ if leaderboard_map != LEADERBOARD_MAP:
50
+ LEADERBOARD_MAP.update(leaderboard_map)
51
+ leaderboard_change = True
52
+ if page_sections != PAGE_SECTIONS:
53
+ PAGE_SECTIONS.clear()
54
+ PAGE_SECTIONS.extend(page_sections)
55
+ page_change = True
56
+ if li_css != LI_CSS:
57
+ LI_CSS.clear()
58
+ LI_CSS.extend(li_css)
59
+
60
+ return leaderboard_change, page_change
61
+
62
+
63
+ def init_pages(leaderboard_change, page_change):
64
+ # init pages
65
+ if leaderboard_change:
66
+ with open("app/ui/pages/data_page.py", "r", encoding="utf-8") as f:
67
+ data_page = f.read()
68
+ for leaderboard, group_names in LEADERBOARD_MAP.items():
69
+
70
+ for group_name in group_names:
71
+ path = os.path.join("app/ui/pages", f"{group_name[0]}.py")
72
+ with open(path, "w", encoding="utf-8") as f:
73
+ f.write(data_page.replace("$group_name$", group_name[0])
74
+ )
75
+ if page_change:
76
+ with open("app/ui/pages_sections.toml", "w", encoding="utf-8") as f:
77
+ f.write("\n".join(PAGE_SECTIONS))
78
+
79
+
80
+ if __name__ == '__main__':
81
+ init_leaderboard()
82
+ init_pages()
83
+ print("\n".join(PAGE_SECTIONS))
84
+ print("\n".join(LI_CSS))
app/backend/constant.py ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from enum import Enum
2
+
3
+
4
+ class Navigation(Enum):
5
+ TEXT_LEADERBOARD = "Text Leaderboard"
6
+ MULTIMODAL_LEADERBOARD = "Multimodal Leaderboard"
7
+
8
+
9
+ class TaskCategory(Enum):
10
+ LAW = "Law"
11
+ CODE = "Code"
12
+ CONVERSATIONAL = "Conversational"
13
+ TECH = "Tech"
14
+ LONG_CONTEXT = "Long-context"
15
+ MULTILINGUAL = "Multilingual"
16
+
17
+
18
+ class ModelProvider(Enum):
19
+ OPENAI = "OpenAI"
20
+ VOYAGEAI = "VoyageAI"
21
+ COHERE = "Cohere"
22
+ OTHERS = "Others"
23
+
24
+
25
+ class EvaluationMetric(Enum):
26
+ NDCG_1 = "NDCG@1"
27
+ NDCG_3 = "NDCG@3"
28
+ NDCG_5 = "NDCG@5"
29
+ NDCG_10 = "NDCG@10"
30
+ NDCG_20 = "NDCG@20"
31
+ NDCG_50 = "NDCG@50"
32
+ NDCG_100 = "NDCG@100"
33
+ RECALL_1 = "RECALL@1"
34
+ RECALL_3 = "RECALL@3"
35
+ RECALL_5 = "RECALL@5"
36
+ RECALL_10 = "RECALL@10"
37
+ RECALL_20 = "RECALL@20"
38
+ RECALL_50 = "RECALL@50"
39
+ RECALL_100 = "RECALL@100"
40
+ PRECISION_1 = "PRECISION@1"
41
+ PRECISION_3 = "PRECISION@3"
42
+ PRECISION_5 = "PRECISION@5"
43
+ PRECISION_10 = "PRECISION@10"
44
+ PRECISION_20 = "PRECISION@20"
45
+ PRECISION_50 = "PRECISION@50"
46
+ PRECISION_100 = "PRECISION@100"
47
+
48
+
49
+ class EmbdDtype(Enum):
50
+ ALL = "all"
51
+ FLOAT_32 = "float32"
52
+ INT_8 = "int8"
53
+ BINARY = "binary"
54
+
55
+
56
+ class EmbdDim(Enum):
57
+ OP1 = "<=1k"
58
+ OP2 = "1k-2k"
59
+ OP3 = "2k-5k"
60
+ OP4 = ">=5k"
61
+
62
+
63
+ class Similarity(Enum):
64
+ ALL = "all"
65
+ COSINE = "cosine"
66
+ DOT = "dot"
67
+ EUCLIDEAN = "euclidean"
68
+
69
+
70
+ LEADERBOARD_ICON_MAP = {
71
+ "Text Leaderboard": "📚",
72
+ "Law": "⚖️",
73
+ "Multilingual": "🌎",
74
+ "German": "🇩🇪",
75
+ "Code": "💻",
76
+ "Tech": "🛠️",
77
+ "Legal": "📜",
78
+ "English": "🇬🇧",
79
+ "Healthcare": "🏥",
80
+ "Finance": "💰",
81
+ "French": "🇫🇷",
82
+
83
+ }
84
+
85
+
86
+ USERNAME = "embedding-benchmark"
87
+ SPACENAME = "RTEB"
88
+ # https://{UserName}-{SpaceName}.hf.space/
89
+ BASE_URL = f"https://{USERNAME}-{SPACENAME}.hf.space/"
app/backend/data_engine.py ADDED
@@ -0,0 +1,144 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Data service provider
3
+ """
4
+ import json
5
+ from typing import List
6
+
7
+ import pandas as pd
8
+
9
+ from utils.cache_decorator import cache_df_with_custom_key, cache_dict_with_custom_key
10
+ from utils.http_utils import get
11
+
12
+ COLUMNS = ['model_name',
13
+ 'embd_dtype', 'embd_dim', 'num_params', 'max_tokens', 'similarity',
14
+ 'query_instruct', 'corpus_instruct',
15
+
16
+ ]
17
+ COLUMNS_TYPES = ["markdown",
18
+ 'str', 'str', 'number', 'number', 'str',
19
+ 'str', 'str',
20
+
21
+ ]
22
+
23
+ GIT_URL = "https://raw.githubusercontent.com/embedding-benchmark/rteb/refs/heads/main/results/"
24
+ DATASET_URL = f"{GIT_URL}datasets.json"
25
+ MODEL_URL = f"{GIT_URL}models.json"
26
+ RESULT_URL = f"{GIT_URL}results.json"
27
+
28
+
29
+ class DataEngine:
30
+
31
+ def __init__(self):
32
+ self.df = self.init_dataframe()
33
+
34
+ @property
35
+ @cache_dict_with_custom_key("models")
36
+ def models(self):
37
+ """
38
+ Get models data
39
+ """
40
+ res = get(MODEL_URL)
41
+ if res.status_code == 200:
42
+ return res.json()
43
+ return {}
44
+
45
+ @property
46
+ @cache_dict_with_custom_key("datasets")
47
+ def datasets(self):
48
+ """
49
+ Get tasks data
50
+ """
51
+ res = get(DATASET_URL)
52
+ if res.status_code == 200:
53
+ return res.json()
54
+ return {}
55
+
56
+ @property
57
+ @cache_dict_with_custom_key("results")
58
+ def results(self):
59
+ """
60
+ Get results data
61
+ """
62
+ res = get(RESULT_URL)
63
+ if res.status_code == 200:
64
+ return res.json()
65
+ return {}
66
+
67
+ def init_dataframe(self):
68
+ """
69
+ Initialize DataFrame
70
+ """
71
+ d = {"hello": [123], "world": [456]}
72
+ return pd.DataFrame(d)
73
+
74
+ @cache_df_with_custom_key("json_result")
75
+ def jsons_to_df(self):
76
+
77
+ results_list = self.results
78
+ df_results_list = []
79
+ for result_dict in results_list:
80
+ dataset_name = result_dict["dataset_name"]
81
+ df_result_row = pd.DataFrame(result_dict["results"])
82
+ df_result_row["dataset_name"] = dataset_name
83
+ df_results_list.append(df_result_row)
84
+ df_result = pd.concat(df_results_list)
85
+
86
+ df_result = df_result[["model_name", "dataset_name", "ndcg_at_10", "embd_dim", "embd_dtype"]]
87
+
88
+ df_result["ndcg_at_10"] = (df_result["ndcg_at_10"] * 100).round(2)
89
+
90
+ df_datasets_list = []
91
+ for item in self.datasets:
92
+ dataset_names = item["datasets"]
93
+ df_dataset_row = pd.DataFrame(
94
+ {
95
+ "group_name": [item["name"] for _ in range(len(dataset_names))],
96
+ "dataset_name": dataset_names,
97
+ "leaderboard": [item["leaderboard"] for _ in range(len(dataset_names))]
98
+ }
99
+ )
100
+ df_datasets_list.append(df_dataset_row)
101
+ df_dataset = pd.concat(df_datasets_list).drop_duplicates()
102
+
103
+ models_list = self.models
104
+
105
+ df_model = pd.DataFrame(models_list)
106
+
107
+ df = pd.merge(df_result, df_dataset, on=["dataset_name"], how="inner")
108
+ # df = pd.merge(df, df_model, on=["model_name"], how="inner")
109
+
110
+ # dataset_num_map = {}
111
+ # grouped_dataset_count = df.groupby(["group_name"]).agg({
112
+ # "dataset_name": "nunique"
113
+ # }).reset_index()
114
+ #
115
+ # for _, row in grouped_dataset_count.iterrows():
116
+ # dataset_num_map[row["group_name"]] = row["dataset_name"]
117
+
118
+ grouped_model = df.groupby(["model_name", "group_name", "embd_dim", "embd_dtype"]).agg({
119
+ "ndcg_at_10": "mean",
120
+ }).reset_index()
121
+
122
+ pivot = grouped_model.pivot(index=["model_name", "embd_dim", "embd_dtype"], columns="group_name",
123
+ values=["ndcg_at_10"]).round(2)
124
+
125
+ # Rename columns
126
+ pivot.columns = list(
127
+ map(lambda x: f"{x[1].capitalize()} Average" if x[1] != 'text' else f"Average", pivot.columns))
128
+
129
+ pivot_dataset = df_result.pivot(index=["model_name", "embd_dim", "embd_dtype"], columns="dataset_name", values="ndcg_at_10")
130
+
131
+ df = pd.merge(df_model, pivot, on=["model_name", "embd_dim", "embd_dtype"])
132
+ df = pd.merge(df, pivot_dataset, on=["model_name", "embd_dim", "embd_dtype"])
133
+
134
+ if df.empty:
135
+ return pd.DataFrame(columns=COLUMNS + ["reference"])
136
+ return df
137
+
138
+ def filter_df(self, group_name: str):
139
+ """
140
+ filter_by_providers
141
+ """
142
+ df = self.jsons_to_df()
143
+
144
+ return df[df["group_name"] == group_name][COLUMNS][:]
app/backend/data_page.py ADDED
@@ -0,0 +1,400 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+ # @Date : 2025/2/5 16:26
3
+ # @Author : q275343119
4
+ # @File : data_page.py
5
+ # @Description:
6
+ import io
7
+
8
+ from st_aggrid import AgGrid, JsCode, ColumnsAutoSizeMode
9
+ import streamlit as st
10
+ from utils.st_copy_to_clipboard import st_copy_to_clipboard
11
+ from streamlit_theme import st_theme
12
+
13
+ from app.backend.app_init_func import LEADERBOARD_MAP
14
+ from app.backend.constant import LEADERBOARD_ICON_MAP, BASE_URL
15
+ from app.backend.json_util import compress_msgpack, decompress_msgpack
16
+
17
+ COLUMNS = ['model_name',
18
+ 'embd_dtype', 'embd_dim', 'num_params', 'max_tokens', 'similarity',
19
+ 'query_instruct', 'corpus_instruct', 'reference'
20
+
21
+ ]
22
+ HEADER_STYLE = {'fontSize': '18px'}
23
+ CELL_STYLE = {'fontSize': '18px'}
24
+
25
+
26
+ def is_section(group_name):
27
+ for k, v in LEADERBOARD_MAP.items():
28
+ leaderboard_name = v[0][0]
29
+
30
+ if group_name == leaderboard_name:
31
+ return True
32
+ return False
33
+
34
+
35
+ def get_closed_dataset():
36
+ data_engine = st.session_state["data_engine"]
37
+ closed_list = []
38
+ results = data_engine.results
39
+ for result in results:
40
+ if result.get("is_closed"):
41
+ closed_list.append(result.get("dataset_name"))
42
+ return closed_list
43
+
44
+
45
+ def convert_df_to_csv(df):
46
+ output = io.StringIO()
47
+ df.to_csv(output, index=False)
48
+ return output.getvalue()
49
+
50
+
51
+ def get_column_state():
52
+ """
53
+ get column state from url
54
+ """
55
+ query_params = st.query_params.get("grid_state", None)
56
+ if query_params:
57
+ grid_state = decompress_msgpack(query_params)
58
+ st.session_state.grid_state = grid_state
59
+ return True
60
+ return None
61
+
62
+
63
+ def render_page(group_name):
64
+ grid_state = st.session_state.get("grid_state", {})
65
+ get_column_state()
66
+
67
+ # Add theme color and grid styles
68
+ st.title("Retrieval Embedding Benchmark (RTEB)")
69
+ st.markdown("""
70
+ <style>
71
+ :root {
72
+ --theme-color: rgb(129, 150, 64);
73
+ --theme-color-light: rgba(129, 150, 64, 0.2);
74
+ }
75
+
76
+ /* AG Grid specific overrides */
77
+ .ag-theme-alpine {
78
+ --ag-selected-row-background-color: var(--theme-color-light) !important;
79
+ --ag-row-hover-color: var(--theme-color-light) !important;
80
+ --ag-selected-tab-color: var(--theme-color) !important;
81
+ --ag-range-selection-border-color: var(--theme-color) !important;
82
+ --ag-range-selection-background-color: var(--theme-color-light) !important;
83
+ }
84
+
85
+ .ag-row-hover {
86
+ background-color: var(--theme-color-light) !important;
87
+ }
88
+
89
+ .ag-row-selected {
90
+ background-color: var(--theme-color-light) !important;
91
+ }
92
+
93
+ .ag-row-focus {
94
+ background-color: var(--theme-color-light) !important;
95
+ }
96
+
97
+ .ag-cell-focus {
98
+ border-color: var(--theme-color) !important;
99
+ }
100
+
101
+ /* Keep existing styles */
102
+ .center-text {
103
+ text-align: center;
104
+ color: var(--theme-color);
105
+ }
106
+ .center-image {
107
+ display: block;
108
+ margin-left: auto;
109
+ margin-right: auto;
110
+ }
111
+ h2 {
112
+ color: var(--theme-color) !important;
113
+ }
114
+ .ag-header-cell {
115
+ background-color: var(--theme-color) !important;
116
+ color: white !important;
117
+ }
118
+ a {
119
+ color: var(--theme-color) !important;
120
+ }
121
+ a:hover {
122
+ color: rgba(129, 150, 64, 0.8) !important;
123
+ }
124
+ /* Download Button */
125
+ button[data-testid="stBaseButton-secondary"] {
126
+ float: right;
127
+
128
+ }
129
+ /* Toast On The Top*/
130
+ div[data-testid="stToastContainer"] {
131
+ position: fixed !important;
132
+ z-index: 2147483647 !important;
133
+ }
134
+
135
+ </style>
136
+
137
+ """, unsafe_allow_html=True)
138
+
139
+ # logo
140
+ # st.markdown('<img src="https://www.voyageai.com/logo.svg" class="center-image" width="200">', unsafe_allow_html=True)
141
+ title = f'<h2 class="center-text">{LEADERBOARD_ICON_MAP.get(group_name.capitalize(), "")} {group_name.capitalize()}</h2>'
142
+ if is_section(group_name):
143
+ title = f'<h2 class="center-text">{LEADERBOARD_ICON_MAP.get(group_name.capitalize() + " Leaderboard", "")} {group_name.capitalize() + " Leaderboard"}</h2>'
144
+ # title
145
+ st.markdown(title, unsafe_allow_html=True)
146
+
147
+ data_engine = st.session_state["data_engine"]
148
+
149
+ df = data_engine.jsons_to_df().copy()
150
+
151
+ csv = convert_df_to_csv(df)
152
+ file_name = f"{group_name.capitalize()} Leaderboard" if is_section(group_name) else group_name.capitalize()
153
+ st.download_button(
154
+ label="Download CSV",
155
+ data=csv,
156
+ file_name=f"{file_name}.csv",
157
+ mime="text/csv",
158
+ icon=":material/download:",
159
+ )
160
+
161
+ # get columns
162
+ column_list = []
163
+ avg_column = None
164
+ if is_section(group_name):
165
+ avg_columns = []
166
+ for column in df.columns:
167
+
168
+ if column.startswith("Average"):
169
+ avg_columns.insert(0, column)
170
+ continue
171
+ if "Average" in column:
172
+ avg_columns.append(column)
173
+ continue
174
+ avg_column = avg_columns[0]
175
+ column_list.extend(avg_columns)
176
+ else:
177
+ for column in df.columns:
178
+
179
+ if column.startswith(group_name.capitalize() + " "):
180
+ avg_column = column
181
+
182
+ column_list.append(avg_column)
183
+
184
+ dataset_list = []
185
+
186
+ for dataset_dict in data_engine.datasets:
187
+ if dataset_dict["name"] == group_name:
188
+ dataset_list = dataset_dict["datasets"]
189
+ if not is_section(group_name):
190
+ column_list.extend(dataset_list)
191
+ closed_list = get_closed_dataset()
192
+ close_avg_list = list(set(dataset_list) & set(closed_list))
193
+ df["Closed average"] = df[close_avg_list].mean(axis=1).round(2)
194
+ column_list.append("Closed average")
195
+
196
+ open_avg_list = list(set(dataset_list) - set(closed_list))
197
+ df["Open average"] = df[open_avg_list].mean(axis=1).round(2)
198
+ column_list.append("Open average")
199
+
200
+ df = df[COLUMNS + column_list].sort_values(by=avg_column, ascending=False)
201
+
202
+ # rename avg column name
203
+ if not is_section(group_name):
204
+ new_column = avg_column.replace(group_name.capitalize(), "").strip()
205
+ df.rename(columns={avg_column: new_column}, inplace=True)
206
+ column_list.remove(avg_column)
207
+ avg_column = new_column
208
+
209
+ # setting column config
210
+ grid_options = {
211
+ 'columnDefs': [
212
+ {
213
+ 'headerName': 'Model Name',
214
+ 'field': 'model_name',
215
+ 'pinned': 'left',
216
+ 'sortable': False,
217
+ 'headerStyle': HEADER_STYLE,
218
+ 'cellStyle': CELL_STYLE,
219
+ "tooltipValueGetter": JsCode(
220
+ """function(p) {return p.value}"""
221
+ ),
222
+ "width": 250,
223
+ 'cellRenderer': JsCode("""class CustomHTML {
224
+ init(params) {
225
+ const link = params.data.reference;
226
+ this.eGui = document.createElement('div');
227
+ this.eGui.innerHTML = link ?
228
+ `<a href="${link}" class="a-cell" target="_blank">${params.value} </a>` :
229
+ params.value;
230
+ }
231
+
232
+ getGui() {
233
+ return this.eGui;
234
+ }
235
+ }"""),
236
+ 'suppressSizeToFit': True
237
+
238
+ },
239
+ {'headerName': "Overall Score",
240
+ 'field': avg_column,
241
+ 'headerStyle': HEADER_STYLE,
242
+ 'cellStyle': CELL_STYLE,
243
+ # 'suppressSizeToFit': True
244
+ },
245
+
246
+ # Add Open average column definition
247
+ {'headerName': 'Open Average',
248
+ 'field': 'Open average',
249
+ 'headerStyle': HEADER_STYLE,
250
+ 'cellStyle': CELL_STYLE,
251
+ # 'suppressSizeToFit': True
252
+ },
253
+
254
+ {'headerName': 'Closed Average',
255
+ 'field': 'Closed average',
256
+ 'headerStyle': HEADER_STYLE,
257
+ 'cellStyle': CELL_STYLE,
258
+ # 'suppressSizeToFit': True
259
+ },
260
+
261
+ {
262
+ 'headerName': 'Embd Dtype',
263
+ 'field': 'embd_dtype',
264
+ 'headerStyle': HEADER_STYLE,
265
+ 'cellStyle': CELL_STYLE,
266
+ # 'suppressSizeToFit': True,
267
+ },
268
+ {
269
+ 'headerName': 'Embd Dim',
270
+ 'field': 'embd_dim',
271
+ 'headerStyle': HEADER_STYLE,
272
+ 'cellStyle': CELL_STYLE,
273
+ # 'suppressSizeToFit': True,
274
+ },
275
+ {
276
+ 'headerName': 'Number of Parameters',
277
+ 'field': 'num_params',
278
+ 'cellDataType': 'number',
279
+ "colId": "num_params",
280
+ 'headerStyle': HEADER_STYLE,
281
+ 'cellStyle': CELL_STYLE,
282
+ 'valueFormatter': JsCode(
283
+ """function(params) {
284
+ const num = params.value;
285
+ if (num >= 1e9) return (num / 1e9).toFixed(2) + "B";
286
+ if (num >= 1e6) return (num / 1e6).toFixed(2) + "M";
287
+ if (num >= 1e3) return (num / 1e3).toFixed(2) + "K";
288
+ return num;
289
+ }"""
290
+ ),
291
+ "width": 120,
292
+ # 'suppressSizeToFit': True,
293
+ },
294
+ {
295
+ 'headerName': 'Context Length',
296
+ 'field': 'max_tokens',
297
+ 'headerStyle': HEADER_STYLE,
298
+ 'cellStyle': CELL_STYLE,
299
+ # 'suppressSizeToFit': True,
300
+ },
301
+
302
+ *[{'headerName': column if "Average" not in column else column.replace("Average", "").strip().capitalize(),
303
+ 'field': column,
304
+ 'headerStyle': HEADER_STYLE,
305
+ 'cellStyle': CELL_STYLE,
306
+ "headerTooltip": column if "Average" not in column else column.replace("Average",
307
+ "").strip().capitalize()
308
+ # 'suppressSizeToFit': True
309
+ } for column in column_list if
310
+ column not in (avg_column, "Closed average", "Open average")]
311
+ ],
312
+ 'defaultColDef': {
313
+ 'filter': True,
314
+ 'sortable': True,
315
+ 'resizable': True,
316
+ 'headerClass': "multi-line-header",
317
+ 'autoHeaderHeight': True,
318
+ 'width': 105
319
+ },
320
+
321
+ "autoSizeStrategy": {
322
+ "type": 'fitCellContents',
323
+ "colIds": [column for column in column_list if column not in (avg_column, "Closed average", "Open average")]
324
+ },
325
+ "tooltipShowDelay": 500,
326
+ "initialState": grid_state,
327
+ }
328
+
329
+ custom_css = {
330
+ # Model Name Cell
331
+ ".a-cell": {
332
+ "display": "inline-block",
333
+ "white-space": "nowrap",
334
+ "overflow": "hidden",
335
+ "text-overflow": "ellipsis",
336
+ "width": "100%",
337
+ "min-width": "0"
338
+ },
339
+ # Header
340
+ ".multi-line-header": {
341
+ "text-overflow": "clip",
342
+ "overflow": "visible",
343
+ "white-space": "normal",
344
+ "height": "auto",
345
+ "font-family": 'Arial',
346
+ "font-size": "14px",
347
+ "font-weight": "bold",
348
+ "padding": "10px",
349
+ "text-align": "left",
350
+ }
351
+ ,
352
+ # Filter Options and Input
353
+ ".ag-theme-streamlit .ag-popup": {
354
+ "font-family": 'Arial',
355
+ "font-size": "14px",
356
+
357
+ }
358
+ , ".ag-picker-field-display": {
359
+ "font-family": 'Arial',
360
+ "font-size": "14px",
361
+
362
+ },
363
+ ".ag-input-field-input .ag-text-field-input": {
364
+ "font-family": 'Arial',
365
+ "font-size": "14px",
366
+
367
+ }
368
+
369
+ }
370
+
371
+ grid = AgGrid(
372
+ df,
373
+ enable_enterprise_modules=False,
374
+ gridOptions=grid_options,
375
+ allow_unsafe_jscode=True,
376
+ columns_auto_size_mode=ColumnsAutoSizeMode.FIT_ALL_COLUMNS_TO_VIEW,
377
+ theme="streamlit",
378
+ custom_css=custom_css,
379
+ update_on=["stateUpdated"],
380
+ )
381
+
382
+ @st.dialog("URL")
383
+ def share_url():
384
+ state = grid.grid_state
385
+ if state:
386
+ share_link = f'{BASE_URL.replace("_", "-")}{group_name}/?grid_state={compress_msgpack(state)}'
387
+ else:
388
+ share_link = f'{BASE_URL.replace("_", "-")}{group_name}'
389
+ st.write(share_link)
390
+ theme = st_theme()
391
+ if theme:
392
+ theme = theme.get("base")
393
+ else:
394
+ theme = "light"
395
+ st_copy_to_clipboard(share_link, before_copy_label='📋Push to copy', after_copy_label='✅Text copied!',theme=theme)
396
+
397
+ share_btn = st.button("Share this page", icon=":material/share:")
398
+
399
+ if share_btn:
400
+ share_url()
app/backend/json_util.py ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import msgpack
2
+ import gzip
3
+ import base64
4
+
5
+
6
+ def compress_msgpack(data):
7
+ packed = msgpack.packb(data)
8
+ compressed = gzip.compress(packed)
9
+ return base64.urlsafe_b64encode(compressed).decode('utf-8')
10
+
11
+
12
+ def decompress_msgpack(compressed_str):
13
+ compressed = base64.urlsafe_b64decode(compressed_str)
14
+ unpacked = gzip.decompress(compressed)
15
+ return msgpack.unpackb(unpacked, raw=False)
app/ui/__init__.py ADDED
File without changes
app/ui/pages/__init__.py ADDED
File without changes
app/ui/pages/data_page.py ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ from app.backend.data_page import render_page
2
+
3
+ render_page("$group_name$")
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ streamlit==1.41.1
2
+ streamlit-aggrid==1.0.5
3
+ st-pages==1.0.1
4
+ msgpack==1.1.0
5
+ zstandard==0.23.0
6
+ st-theme==1.2.3
utils/__init__.py ADDED
File without changes
utils/cache_decorator.py ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import time
2
+ from functools import wraps
3
+ import pandas as pd
4
+
5
+ CACHE = {}
6
+ TTL = 3600
7
+
8
+
9
+ def cache_df_with_custom_key(cache_key: str):
10
+ def decorator(func):
11
+ @wraps(func)
12
+ def wrapper(*args, **kwargs):
13
+ if cache_key in CACHE and CACHE[cache_key].get("expiry") - time.time() < TTL:
14
+ return CACHE[cache_key]["data"]
15
+
16
+ result: pd.DataFrame = func(*args, **kwargs)
17
+ if result is not None and not result.empty:
18
+ d = {"expiry": time.time(), "data": result}
19
+ CACHE[cache_key] = d
20
+ return result
21
+
22
+ CACHE[cache_key]["expiry"] += TTL
23
+ return CACHE[cache_key]["data"]
24
+
25
+ return wrapper
26
+
27
+ return decorator
28
+
29
+
30
+ def cache_dict_with_custom_key(cache_key: str):
31
+ def decorator(func):
32
+ @wraps(func)
33
+ def wrapper(*args, **kwargs):
34
+ if cache_key in CACHE and time.time() - CACHE[cache_key].get("expiry") < TTL:
35
+ return CACHE[cache_key]["data"]
36
+
37
+ result: dict = func(*args, **kwargs)
38
+ if result:
39
+ d = {"expiry": time.time(), "data": result}
40
+ CACHE[cache_key] = d
41
+ return result
42
+
43
+ CACHE[cache_key]["expiry"] += TTL
44
+ return CACHE[cache_key]["data"]
45
+
46
+ return wrapper
47
+
48
+ return decorator
49
+
50
+
51
+ if __name__ == '__main__':
52
+ a = time.time()
53
+ time.sleep(5)
54
+ print(time.time() - a)
utils/http_utils.py ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ import requests
2
+
3
+
4
+ def get(url: str, params: str = None, verify: bool = False):
5
+ return requests.get(url, params, verify=verify)
6
+
7
+
utils/st_copy_to_clipboard/__init__.py ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pathlib import Path
2
+ from typing import Optional
3
+
4
+ import streamlit as st
5
+ import streamlit.components.v1 as components
6
+
7
+ # Tell streamlit that there is a component called streamlit_copy_to_clipboard,
8
+ # and that the code to display that component is in the "frontend" folder
9
+ frontend_dir = (Path(__file__).parent / "frontend").absolute()
10
+ _component_func = components.declare_component(
11
+ "streamlit_copy_to_clipboard", path=str(frontend_dir)
12
+ )
13
+
14
+
15
+ def st_copy_to_clipboard(
16
+ text: str,
17
+ before_copy_label: str = "📋",
18
+ after_copy_label: str = "✅",
19
+ show_text: bool = False,
20
+ key: Optional[str] = None,
21
+ theme: str = 'light', # default theme is 'light'
22
+
23
+ ):
24
+ """
25
+ Streamlit component to copy text to clipboard.
26
+
27
+ Parameters
28
+ ----------
29
+ text : str
30
+ The text to be copied to the clipboard.
31
+ before_copy_label : str
32
+ Label of the button before text is copied.
33
+ after_copy_label : str
34
+ Label of the button after text is copied.
35
+ show_text: bool
36
+ If True, show text right before the button and make it clickable as well
37
+ key : str or None
38
+ An optional key that uniquely identifies the component.
39
+ theme: str
40
+ Set the current theme for the button.
41
+ """
42
+ component_value = _component_func(
43
+ key=key,
44
+ text=text,
45
+ before_copy_label=before_copy_label,
46
+ after_copy_label=after_copy_label,
47
+ show_text=show_text,
48
+ theme=theme,
49
+ )
50
+
51
+ return component_value
52
+
53
+
54
+ def main():
55
+ st.write("## Example")
56
+ text = st.text_input("Enter text to copy to clipboard", value="Hello World")
57
+ st_copy_to_clipboard(text)
58
+ st_copy_to_clipboard(text, before_copy_label='📋Push to copy', after_copy_label='✅Text copied!')
59
+ st_copy_to_clipboard(text, before_copy_label='Push to copy', after_copy_label='Text copied!', show_text=True)
60
+ st_copy_to_clipboard(text, before_copy_label='Push to copy', after_copy_label='copied!', show_text=True, theme="dark")
61
+
62
+
63
+
64
+
65
+ if __name__ == "__main__":
66
+ main()
utils/st_copy_to_clipboard/frontend/index.html ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta http-equiv="X-UA-Compatible" content="IE=edge" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>st-copy-to-clipboard</title>
8
+ <script src="./streamlit-component-lib.js"></script>
9
+ <script src="./main.js"></script>
10
+ <link rel="stylesheet" href="./style.css" />
11
+ </head>
12
+
13
+ <body>
14
+ <div id="root">
15
+ <button id="text-element" class="st-copy-to-clipboard-btn"></button>
16
+ <button id="copy-button" class="st-copy-to-clipboard-btn">📋</button>
17
+ </div>
18
+ </body>
19
+ </html>
utils/st_copy_to_clipboard/frontend/main.js ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // The `Streamlit` object exists because our html file includes
2
+ // `streamlit-component-lib.js`.
3
+ // If you get an error about "Streamlit" not being defined, that
4
+ // means you're missing that file.
5
+
6
+ function sendValue(value) {
7
+ Streamlit.setComponentValue(value);
8
+ }
9
+
10
+ /**
11
+ * The component's render function. This will be called immediately after
12
+ * the component is initially loaded, and then again every time the
13
+ * component gets new data from Python.
14
+ */
15
+ function onRender(event) {
16
+ // Only run the render code the first time the component is loaded.
17
+ if (!window.rendered) {
18
+ const { text, before_copy_label, after_copy_label, show_text, theme } = event.detail.args;
19
+
20
+ const container = document.querySelector('#container');
21
+ const button = document.querySelector('#copy-button');
22
+ const textElement = document.querySelector('#text-element');
23
+
24
+ if (theme == 'dark') {
25
+ button.style.border = '1px solid rgba(250, 250, 250, 0.2)';
26
+ button.style.color = 'white';
27
+ }
28
+
29
+ button.textContent = before_copy_label; // Set initial label
30
+
31
+ // Show text if show_text is true
32
+ if (show_text) {
33
+ textElement.textContent = text;
34
+ textElement.style.display = 'inline';
35
+ } else {
36
+ textElement.style.display = 'none';
37
+ }
38
+
39
+ function copyToClipboard() {
40
+ navigator.clipboard.writeText(text);
41
+
42
+ button.textContent = after_copy_label; // Change label after copying
43
+
44
+ setTimeout(() => {
45
+ if (!button) return;
46
+ button.textContent = before_copy_label; // Revert to original label after 1 second
47
+ }, 1000);
48
+ }
49
+ button.addEventListener('click', copyToClipboard);
50
+ textElement.addEventListener('click', copyToClipboard);
51
+
52
+ window.rendered = true;
53
+ }
54
+ }
55
+
56
+ // Render the component whenever python send a "render event"
57
+ Streamlit.events.addEventListener(Streamlit.RENDER_EVENT, onRender);
58
+ // Tell Streamlit that the component is ready to receive events
59
+ Streamlit.setComponentReady();
60
+ // Render with the correct height, if this is a fixed-height component
61
+ Streamlit.setFrameHeight(100);
utils/st_copy_to_clipboard/frontend/streamlit-component-lib.js ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Borrowed minimalistic Streamlit API from Thiago
2
+ // https://discuss.streamlit.io/t/code-snippet-create-components-without-any-frontend-tooling-no-react-babel-webpack-etc/13064
3
+ function sendMessageToStreamlitClient(type, data) {
4
+ console.log(type, data);
5
+ const outData = Object.assign(
6
+ {
7
+ isStreamlitMessage: true,
8
+ type: type,
9
+ },
10
+ data
11
+ );
12
+ window.parent.postMessage(outData, '*');
13
+ }
14
+
15
+ const Streamlit = {
16
+ setComponentReady: function () {
17
+ sendMessageToStreamlitClient('streamlit:componentReady', { apiVersion: 1 });
18
+ },
19
+ setFrameHeight: function (height) {
20
+ sendMessageToStreamlitClient('streamlit:setFrameHeight', { height: height });
21
+ },
22
+ setComponentValue: function (value) {
23
+ sendMessageToStreamlitClient('streamlit:setComponentValue', { value: value });
24
+ },
25
+ RENDER_EVENT: 'streamlit:render',
26
+ events: {
27
+ addEventListener: function (type, callback) {
28
+ window.addEventListener('message', function (event) {
29
+ if (event.data.type === type) {
30
+ event.detail = event.data;
31
+ callback(event);
32
+ }
33
+ });
34
+ },
35
+ },
36
+ };
utils/st_copy_to_clipboard/frontend/style.css ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .st-copy-to-clipboard-btn {
2
+ display: inline-flex;
3
+ -moz-box-align: center;
4
+ align-items: center;
5
+ -moz-box-pack: center;
6
+ justify-content: center;
7
+ font-weight: 400;
8
+ padding: 0.25rem 0.75rem;
9
+ border-radius: 0.5rem;
10
+ min-height: 38.4px;
11
+ margin: 0px;
12
+ line-height: 1.6;
13
+ color: inherit;
14
+ width: auto;
15
+ user-select: none;
16
+ background-color: transparent; /* set bgcolor to transparent to adjust to any theme */
17
+ border: 1px solid rgba(49, 51, 63, 0.2);
18
+ cursor: pointer;
19
+ float: right;
20
+ }
21
+
22
+ .st-copy-to-clipboard-btn:hover {
23
+ border-color: rgb(255, 75, 75);
24
+ color: rgb(255, 75, 75);
25
+ }
26
+
27
+ .st-copy-to-clipboard-btn:active {
28
+ border-color: rgb(255, 75, 75);
29
+ background-color: rgb(255, 75, 75);
30
+ color: rgb(255, 255, 255);
31
+ }