caesar-one's picture
Small improvements.
9a49194
import io
import re
from typing import *
import pandas as pd
import streamlit as st
from pandas.api.types import is_bool_dtype, is_datetime64_any_dtype, is_numeric_dtype
GITHUB_URL = "https://github.com/RSTLess-research/"
NON_BENCHMARK_COLS = ["Publisher"]
def extract_table_and_format_from_markdown_text(markdown_table: str) -> pd.DataFrame:
"""Extracts a table from a markdown text and formats it as a pandas DataFrame.
Args:
text (str): Markdown text containing a table.
Returns:
pd.DataFrame: Table as pandas DataFrame.
"""
df = (
pd.read_table(io.StringIO(markdown_table), sep="|", header=0, index_col=1)
.dropna(axis=1, how="all") # drop empty columns
.iloc[1:] # drop first row which is the "----" separator of the original markdown table
.sort_index(ascending=True)
.apply(lambda x: x.str.strip() if x.dtype == "object" else x)
.replace("", float("NaN"))
.astype(float, errors="ignore")
)
# remove whitespace from column names and index
df.columns = df.columns.str.strip()
df.index = df.index.str.strip()
df.index.name = df.index.name.strip()
return df
def extract_markdown_table_from_multiline(multiline: str, table_headline: str, next_headline_start: str = "#") -> str:
"""Extracts the markdown table from a multiline string.
Args:
multiline (str): content of README.md file.
table_headline (str): Headline of the table in the README.md file.
next_headline_start (str, optional): Start of the next headline. Defaults to "#".
Returns:
str: Markdown table.
Raises:
ValueError: If the table could not be found.
"""
# extract everything between the table headline and the next headline
table = []
start = False
for line in multiline.split("\n"):
if line.startswith(table_headline):
start = True
elif line.startswith(next_headline_start):
start = False
elif start:
table.append(line + "\n")
if len(table) == 0:
raise ValueError(f"Could not find table with headline '{table_headline}'")
return "".join(table)
def remove_markdown_links(text: str) -> str:
"""Modifies a markdown text to remove all markdown links.
Example: [DISPLAY](LINK) to DISPLAY
First find all markdown links with regex.
Then replace them with: $1
Args:
text (str): Markdown text containing markdown links
Returns:
str: Markdown text without markdown links.
"""
# find all markdown links
markdown_links = re.findall(r"\[([^\]]+)\]\(([^)]+)\)", text)
# remove link keep display text
for display, link in markdown_links:
text = text.replace(f"[{display}]({link})", display)
return text
def filter_dataframe_by_model_type(df: pd.DataFrame, model_type_column: str = 'Lang.', ignore_columns: List[str] = None) -> pd.DataFrame:
"""
Filter dataframe by the rows based on model type and by user-selected columns.
This function provides a user interface to select model types and columns for filtering a DataFrame.
Model types are dynamically derived from the column specified as 'model_type_column'.
Args:
df (pd.DataFrame): Original dataframe.
model_type_column (str): Column name that contains model types for filtering.
ignore_columns (list[str], optional): Columns to ignore when showing in column selection. Defaults to None.
Returns:
pd.DataFrame: Filtered dataframe.
"""
df = df.copy()
if ignore_columns is None:
ignore_columns = []
# Streamlit UI Container
modification_container = st.container()
with modification_container:
# Selection for model types
unique_model_types = sorted(df[model_type_column].unique())
selected_model_types = st.multiselect("Filter by model type:", unique_model_types)
# Filter dataframe by selected model types
if selected_model_types:
df = df[df[model_type_column].isin(selected_model_types)]
# Column selection excluding the model type column and any specified ignore columns
valid_columns = sorted(set(df.columns) - set(ignore_columns) - {model_type_column})
selected_columns = st.multiselect("Filter by columns:", valid_columns)
# Filter dataframe to include only the selected columns plus the model type column
if selected_columns:
df = pd.DataFrame(df[[model_type_column] + selected_columns])
return df
def filter_dataframe_by_row_and_columns(df: pd.DataFrame, ignore_columns: List[str] = None) -> pd.DataFrame:
"""
Filter dataframe by the rows and columns to display.
This does not select based on the values in the dataframe, but rather on the index and columns.
Modified from https://blog.streamlit.io/auto-generate-a-dataframe-filtering-ui-in-streamlit-with-filter_dataframe/
Args:
df (pd.DataFrame): Original dataframe
ignore_columns (list[str], optional): Columns to ignore. Defaults to None.
Returns:
pd.DataFrame: Filtered dataframe
"""
df = df.copy()
if ignore_columns is None:
ignore_columns = []
modification_container = st.container()
with modification_container:
to_filter_index = st.multiselect("Filter by model:", sorted(df.index))
if to_filter_index:
df = pd.DataFrame(df.loc[to_filter_index])
to_filter_columns = st.multiselect(
"Filter by benchmark:", sorted([c for c in df.columns if c not in ignore_columns])
)
if to_filter_columns:
df = pd.DataFrame(df[ignore_columns + to_filter_columns])
return df
def filter_dataframe_by_column_values(df: pd.DataFrame) -> pd.DataFrame:
"""
Filter dataframe by the values in the dataframe.
Modified from https://blog.streamlit.io/auto-generate-a-dataframe-filtering-ui-in-streamlit-with-filter_dataframe/
Args:
df (pd.DataFrame): Original dataframe
Returns:
pd.DataFrame: Filtered dataframe
"""
df = df.copy()
modification_container = st.container()
with modification_container:
to_filter_columns = st.multiselect("Filter results on:", df.columns)
left, right = st.columns((1, 20))
for column in to_filter_columns:
if is_bool_dtype(df[column]):
user_bool_input = right.checkbox(f"{column}", value=True)
df = df[df[column] == user_bool_input]
elif is_numeric_dtype(df[column]):
_min = float(df[column].min())
_max = float(df[column].max())
if (_min != _max) and pd.notna(_min) and pd.notna(_max):
step = 0.01
user_num_input = right.slider(
f"Values for {column}:",
min_value=round(_min - step, 2),
max_value=round(_max + step, 2),
value=(_min, _max),
step=step,
)
df = df[df[column].between(*user_num_input)]
elif is_datetime64_any_dtype(df[column]):
user_date_input = right.date_input(
f"Values for {column}:",
value=(
df[column].min(),
df[column].max(),
),
)
if isinstance(user_date_input, Iterable) and len(user_date_input) == 2:
user_date_input_datetime = tuple(map(pd.to_datetime, user_date_input))
start_date, end_date = user_date_input_datetime
df = df.loc[df[column].between(start_date, end_date)]
else:
selected_values = right.multiselect(
f"Values for {column}:",
sorted(df[column].unique()),
)
if selected_values:
df = df[df[column].isin(selected_values)]
return df
def setup_basic():
title = "๐Ÿ† Italian LLM-Leaderboard ๐Ÿ‡ฎ๐Ÿ‡น๐ŸคŒ"
st.set_page_config(
page_title=title,
page_icon="๐Ÿ†๐Ÿ‡ฎ๐Ÿ‡น๐ŸคŒ",
layout="wide",
)
st.title(title)
st.markdown(
"The Italian Open LLM Leaderboard published along with the paper _DanteLLM: Let's Push Italian LLM Research Forward!_ ๐ŸคŒ๐Ÿ‡ฎ๐Ÿ‡น๐Ÿ† (To be presented at: LREC-COLING 2024, May 20th-25th) \n"
)
def setup_leaderboard(readme: str):
leaderboard_table = extract_markdown_table_from_multiline(readme, table_headline="## Leaderboard")
leaderboard_table = remove_markdown_links(leaderboard_table)
df_leaderboard = extract_table_and_format_from_markdown_text(leaderboard_table)
st.markdown("## Leaderboard")
modify = st.checkbox("Add filters")
if modify:
df_leaderboard = filter_dataframe_by_row_and_columns(df_leaderboard, ignore_columns=NON_BENCHMARK_COLS)
df_leaderboard = filter_dataframe_by_column_values(df_leaderboard)
df_leaderboard = filter_dataframe_by_model_type(df_leaderboard)
df_leaderboard = df_leaderboard.sort_values(by=['Avg.'], ascending=False)
df_leaderboard["Rank"] = df_leaderboard["Avg."].rank(ascending=False)
# move rank at 0-th column
# Ensure 'Rank' is the first column
cols = ['Rank'] + [col for col in df_leaderboard.columns if col != 'Rank']
df_leaderboard = df_leaderboard[cols]
#print(df_leaderboard.columns)
#df_leaderboard.reset_index(drop=True, inplace=True)
st.dataframe(df_leaderboard)
st.download_button(
"Download leaderboard as .html",
df_leaderboard.to_html().encode("utf-8"),
"leaderboard.html",
"text/html",
key="download-html",
)
st.download_button(
"Download leaderboard as .csv",
df_leaderboard.to_csv().encode("utf-8"),
"leaderboard.csv",
"text/csv",
key="download-csv",
)
def setup_benchmarks(readme: str):
benchmarks_table = extract_markdown_table_from_multiline(readme, table_headline="## Benchmarks")
df_benchmarks = extract_table_and_format_from_markdown_text(benchmarks_table)
st.markdown("## Covered Benchmarks")
selected_benchmark = st.selectbox("Select a benchmark to learn more:", df_benchmarks.index.unique())
df_selected = df_benchmarks.loc[selected_benchmark]
text = [
f"Name: {selected_benchmark}",
]
for key in df_selected.keys():
text.append(f"{key}: {df_selected[key]} ")
st.markdown(" \n".join(text))
def setup_sources():
st.markdown("## Sources")
st.markdown(
"The results of this leaderboard are collected from the individual papers and published results of the model "
"authors. If you are interested in the sources of each individual reported model value, please visit the "
f"[llm-leaderboard]({GITHUB_URL}) repository."
)
def setup_disclaimer():
st.markdown("## Authors")
st.markdown(
"""
- [Andrea Bacciu](https://www.linkedin.com/in/andreabacciu/)* (Work done prior joining Amazon)
- [Cesare Campagnano](https://www.linkedin.com/in/caesar-one/)*
- [Giovanni Trappolini](https://www.linkedin.com/in/giovanni-trappolini/)
- [Prof. Fabrizio Silvestri](https://www.linkedin.com/in/fabrizio-silvestri-a6b0391/)
\*Equal contribution
"""
)
st.markdown("## Ack")
st.markdown(
f"Special thanks to [llm-leaderboard](https://github.com/LudwigStumpp/llm-leaderboard) for the initial inspiration and codebase"
)
def setup_footer():
st.markdown(
"""
---
Made with โค๏ธ by the awesome open-source Italian community ๐ŸคŒ๐Ÿ‡ฎ๐Ÿ‡น.
"""
)
def main():
setup_basic()
with open("README.md", "r") as f:
readme = f.read()
setup_leaderboard(readme)
setup_benchmarks(readme)
setup_sources()
setup_disclaimer()
setup_footer()
if __name__ == "__main__":
main()