app/backend/constant.py CHANGED
@@ -81,3 +81,9 @@ LEADERBOARD_ICON_MAP = {
81
  "French": "🇫🇷",
82
 
83
  }
 
 
 
 
 
 
 
81
  "French": "🇫🇷",
82
 
83
  }
84
+
85
+
86
+ USERNAME = "embedding-benchmark"
87
+ SPACENAME = "ebr"
88
+ # https://{UserName}-{SpaceName}.hf.space/
89
+ BASE_URL = f"https://{USERNAME}-{SPACENAME}.hf.space/"
app/backend/data_engine.py CHANGED
@@ -20,7 +20,7 @@ COLUMNS_TYPES = ["markdown",
20
 
21
  ]
22
 
23
- GIT_URL = "https://raw.githubusercontent.com/embedding-benchmark/ebr/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"
 
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"
app/backend/data_page.py CHANGED
@@ -6,11 +6,13 @@
6
  import io
7
 
8
  from st_aggrid import AgGrid, JsCode, ColumnsAutoSizeMode
9
-
10
  import streamlit as st
 
 
11
 
12
  from app.backend.app_init_func import LEADERBOARD_MAP
13
- from app.backend.constant import LEADERBOARD_ICON_MAP
 
14
 
15
  COLUMNS = ['model_name',
16
  'embd_dtype', 'embd_dim', 'num_params', 'max_tokens', 'similarity',
@@ -46,7 +48,22 @@ def convert_df_to_csv(df):
46
  return output.getvalue()
47
 
48
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  def render_page(group_name):
 
 
 
50
  # Add theme color and grid styles
51
  st.title("Retrieval Embedding Benchmark (RTEB)")
52
  st.markdown("""
@@ -109,7 +126,14 @@ def render_page(group_name):
109
  float: right;
110
 
111
  }
 
 
 
 
 
 
112
  </style>
 
113
  """, unsafe_allow_html=True)
114
 
115
  # logo
@@ -252,6 +276,7 @@ def render_page(group_name):
252
  'headerName': 'Number of Parameters',
253
  'field': 'num_params',
254
  'cellDataType': 'number',
 
255
  'headerStyle': HEADER_STYLE,
256
  'cellStyle': CELL_STYLE,
257
  'valueFormatter': JsCode(
@@ -263,6 +288,7 @@ def render_page(group_name):
263
  return num;
264
  }"""
265
  ),
 
266
  # 'suppressSizeToFit': True,
267
  },
268
  {
@@ -277,6 +303,8 @@ def render_page(group_name):
277
  'field': column,
278
  'headerStyle': HEADER_STYLE,
279
  'cellStyle': CELL_STYLE,
 
 
280
  # 'suppressSizeToFit': True
281
  } for column in column_list if
282
  column not in (avg_column, "Closed average", "Open average")]
@@ -286,18 +314,20 @@ def render_page(group_name):
286
  'sortable': True,
287
  'resizable': True,
288
  'headerClass': "multi-line-header",
289
- 'autoHeaderHeight': True
 
290
  },
 
291
  "autoSizeStrategy": {
292
- "type": 'fitGridWidth',
293
- "defaultMinWidth": 105,
294
  },
295
  "tooltipShowDelay": 500,
296
-
297
  }
298
 
299
  custom_css = {
300
-
301
  ".a-cell": {
302
  "display": "inline-block",
303
  "white-space": "nowrap",
@@ -306,22 +336,65 @@ def render_page(group_name):
306
  "width": "100%",
307
  "min-width": "0"
308
  },
309
-
310
  ".multi-line-header": {
311
  "text-overflow": "clip",
312
  "overflow": "visible",
313
  "white-space": "normal",
314
  "height": "auto",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
315
  }
316
 
317
  }
318
 
319
- AgGrid(
320
  df,
321
  enable_enterprise_modules=False,
322
  gridOptions=grid_options,
323
  allow_unsafe_jscode=True,
324
- columns_auto_size_mode=ColumnsAutoSizeMode.FIT_CONTENTS,
325
  theme="streamlit",
326
- custom_css=custom_css
 
327
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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',
 
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("""
 
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
 
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(
 
288
  return num;
289
  }"""
290
  ),
291
+ "width": 120,
292
  # 'suppressSizeToFit': True,
293
  },
294
  {
 
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")]
 
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",
 
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/pages/english.py ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ from app.backend.data_page import render_page
2
+
3
+ render_page("english")
app/ui/pages/french.py ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ from app.backend.data_page import render_page
2
+
3
+ render_page("french")
app/ui/pages/legal.py ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ from app.backend.data_page import render_page
2
+
3
+ render_page("legal")
requirements.txt CHANGED
@@ -1,3 +1,6 @@
1
  streamlit==1.41.1
2
  streamlit-aggrid==1.0.5
3
  st-pages==1.0.1
 
 
 
 
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/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
+ }