yuchenlin commited on
Commit
a415f27
β€’
1 Parent(s): 4401f8e

urial bench

Browse files
Files changed (8) hide show
  1. .gitignore +2 -0
  2. README.md +4 -5
  3. app.py +137 -0
  4. constants.py +91 -0
  5. init.py +95 -0
  6. leaderboard_data.jsonl +13 -0
  7. requirements.txt +1 -0
  8. utils_display.py +43 -0
.gitignore ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ __pycache__
2
+ .DS_Store
README.md CHANGED
@@ -1,13 +1,12 @@
1
  ---
2
- title: URIAL Bench
3
- emoji: πŸ“Š
4
- colorFrom: gray
5
- colorTo: indigo
6
  sdk: gradio
7
  sdk_version: 4.19.2
8
  app_file: app.py
9
  pinned: false
10
- license: apache-2.0
11
  ---
12
 
13
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: URIAL Bench (Eval Base LLMs on MT-Bench)
3
+ emoji: πŸ‘
4
+ colorFrom: blue
5
+ colorTo: yellow
6
  sdk: gradio
7
  sdk_version: 4.19.2
8
  app_file: app.py
9
  pinned: false
 
10
  ---
11
 
12
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
app.py ADDED
@@ -0,0 +1,137 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """A gradio app that renders a static leaderboard. This is used for Hugging Face Space."""
2
+ import ast
3
+ import argparse
4
+ import glob
5
+ import pickle
6
+
7
+ import gradio as gr
8
+ import numpy as np
9
+ import pandas as pd
10
+ import gradio as gr
11
+ import pandas as pd
12
+ from pathlib import Path
13
+ import json
14
+ from constants import BANNER, INTRODUCTION_TEXT, CITATION_TEXT, METRICS_TAB_TEXT, DIR_OUTPUT_REQUESTS
15
+ from init import is_model_on_hub, upload_file, load_all_info_from_dataset_hub
16
+ from utils_display import AutoEvalColumn, fields, make_clickable_model, styled_error, styled_message
17
+ from datetime import datetime, timezone
18
+
19
+ LAST_UPDATED = "Feb 27th 2024"
20
+
21
+ css = """
22
+ .markdown-text{font-size: 16pt}
23
+ th {
24
+ text-align: center;
25
+ }
26
+ td {
27
+ font-size: 16px; /* Adjust the font size as needed */
28
+ text-align: center;
29
+ }
30
+
31
+ """
32
+
33
+ column_names = {
34
+ "model": "Model",
35
+ "Overall": "All 🎯",
36
+ "Turn 1": "Turn 1️⃣",
37
+ "Turn 2": "Turn 2️⃣",
38
+ }
39
+
40
+ model_info = {
41
+ "gpt-4": {"hf_name": "https://platform.openai.com/", "pretty_name": "gpt-4"},
42
+ "gpt-3.5-turbo": {"hf_name": "https://platform.openai.com/", "pretty_name": "gpt-3.5-turbo"},
43
+ "Llama-2-70b-hf": {"hf_name": "meta-llama/Llama-2-70b-hf", "pretty_name": "Llama-2-70B"},
44
+ "Llama-2-13b-hf": {"hf_name": "meta-llama/Llama-2-13b-hf", "pretty_name": "Llama-2-13B"},
45
+ "Llama-2-7b-hf": {"hf_name": "meta-llama/Llama-2-7b-hf", "pretty_name": "Llama-2-7B"},
46
+ "Mixtral-8x7B-v0.1": {"hf_name": "mistralai/Mixtral-8x7B-v0.1", "pretty_name": "Mixtral-8x7B"},
47
+ "Mistral-7b-v0.1": {"hf_name": "mistralai/Mistral-7B-v0.1", "pretty_name": "Mistral-7B"},
48
+ "Yi-34B": {"hf_name": "01-ai/Yi-34B", "pretty_name": "Yi-34B"},
49
+ "Yi-6B": {"hf_name": "01-ai/Yi-6B", "pretty_name": "Yi-6B"},
50
+ "gemma-7b": {"hf_name": "google/gemma-7b", "pretty_name": "Gemma-7B"},
51
+ "gemma-2b": {"hf_name": "google/gemma-2b", "pretty_name": "Gemma-2B"},
52
+ "phi-2": {"hf_name": "microsoft/phi-2", "pretty_name": "Phi-2 (2.7B)"},
53
+ "olmo": {"hf_name": "allenai/OLMo-7B", "pretty_name": "OLMo-7B"},
54
+ }
55
+
56
+
57
+ # Formats the columns
58
+ def formatter(x):
59
+ if type(x) is str:
60
+ x = x
61
+ else:
62
+ x = round(x, 2)
63
+ return x
64
+
65
+
66
+
67
+ def build_demo(original_df, TYPES):
68
+ with gr.Blocks(theme=gr.themes.Soft(), css=css) as demo:
69
+ # gr.HTML(BANNER, elem_id="banner")
70
+ gr.Markdown(INTRODUCTION_TEXT, elem_classes="markdown-text")
71
+
72
+ with gr.Tabs(elem_classes="tab-buttons") as tabs:
73
+ with gr.TabItem("πŸ… Leaderboard", elem_id="od-benchmark-tab-table", id=0):
74
+ leaderboard_table = gr.components.Dataframe(
75
+ value=original_df,
76
+ datatype=TYPES,
77
+ height=1000,
78
+ wrap=False,
79
+ elem_id="leaderboard-table",
80
+ interactive=False,
81
+ visible=True,
82
+ min_width=60,
83
+ )
84
+
85
+ with gr.TabItem("πŸ“ˆ Metrics", elem_id="od-benchmark-tab-table", id=1):
86
+ gr.Markdown(METRICS_TAB_TEXT, elem_classes="markdown-text")
87
+
88
+
89
+ gr.Markdown(f"Last updated on **{LAST_UPDATED}**", elem_classes="markdown-text")
90
+
91
+ with gr.Row():
92
+ with gr.Accordion("πŸ“™ Citation", open=False):
93
+ gr.Textbox(
94
+ value=CITATION_TEXT, lines=7,
95
+ label="Copy the BibTeX to cite URIAL and MT-Bench",
96
+ elem_id="citation-button",
97
+ show_copy_button=True)
98
+ # ).style(show_copy_button=True)
99
+
100
+ return demo
101
+
102
+ if __name__ == "__main__":
103
+
104
+ parser = argparse.ArgumentParser()
105
+ parser.add_argument("--share", action="store_true")
106
+ parser.add_argument("--result_file", help="Path to results table", default="leaderboard_data.jsonl")
107
+ args = parser.parse_args()
108
+
109
+ bench_results = args.result_file
110
+
111
+ original_df = pd.read_json(bench_results, lines=True)
112
+
113
+ print(original_df.columns)
114
+
115
+ for col in original_df.columns:
116
+ if col == "model":
117
+ original_df[col] = original_df[col].apply(lambda x: x.replace(x, make_clickable_model(x, model_info)))
118
+ else:
119
+ original_df[col] = original_df[col].apply(formatter) # For numerical values
120
+
121
+ # Define the first column explicitly, add 'Overall' as the second column, and then append the rest excluding 'Overall'
122
+ new_order = [original_df.columns[0], 'Overall'] + [col for col in original_df.columns if col not in [original_df.columns[0], 'Overall']]
123
+
124
+ # Reorder the DataFrame columns using the new order
125
+ reordered_df = original_df[new_order]
126
+
127
+ reordered_df.sort_values(by='Overall', inplace=True, ascending=False)
128
+
129
+ reordered_df.rename(columns=column_names, inplace=True)
130
+
131
+ # COLS = [c.name for c in fields(AutoEvalColumn)]
132
+ # TYPES = [c.type for c in fields(AutoEvalColumn)]
133
+
134
+ TYPES = ["markdown", "number"]
135
+ demo = build_demo(reordered_df, TYPES)
136
+ demo.launch(share=args.share)
137
+
constants.py ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pathlib import Path
2
+
3
+ # Directory where request by models are stored
4
+ DIR_OUTPUT_REQUESTS = Path("requested_models")
5
+ EVAL_REQUESTS_PATH = Path("eval_requests")
6
+
7
+ ##########################
8
+ # Text definitions #
9
+ ##########################
10
+
11
+ banner_url = "https://huggingface.co/spaces/WildEval/WildBench-Leaderboard/resolve/main/%E2%80%8Eleaderboard_logo_v2.png" # the same repo here.
12
+ BANNER = f'<div style="display: flex; justify-content: space-around;"><img src="{banner_url}" alt="Banner" style="width: 40vw; min-width: 300px; max-width: 600px;"> </div>'
13
+
14
+ TITLE = "<html> <head> <style> h1 {text-align: center;} </style> </head> <body> <h1> URIAL Bench </b> </body> </html>"
15
+
16
+
17
+ INTRODUCTION_TEXT= """
18
+ # URIAL Bench (Evaluating Base LLMs with URIAL on MT-Bench)
19
+ [πŸ›œ Website](https://allenai.github.io/re-align/index.html) | [πŸ’» GitHub](https://github.com/Re-Align/URIAL) | [πŸ“– Paper](https://arxiv.org/abs/2312.01552) | [🐦 Twitter](https://x.com/billyuchenlin/status/1759541978881311125?s=20)
20
+
21
+ > URIAL Bench tests the capacity of base LLMs for alignment without introducing the factors of fine-tuning (learning rate, data, etc.), which are hard to control for fair comparisons.
22
+ Specifically, we use [URIAL](https://github.com/Re-Align/URIAL/tree/main/run_scripts/mt-bench#run-urial-inference) to align a base LLM, and evaluate its performance on MT-Bench.
23
+
24
+ - [πŸ‘ URIAL](https://arxiv.org/abs/2312.01552) uses three constant examples to align BASE LLMs with in-context learning.
25
+ - [πŸ“Š MT-Bench](https://huggingface.co/spaces/lmsys/mt-bench) is a small, curated benchmark with two turns of instruction following tasks in 10 domains.
26
+
27
+
28
+ """
29
+
30
+
31
+ CITATION_TEXT = """@inproceedings{
32
+ Lin2024ReAlign,
33
+ title={The Unlocking Spell on Base LLMs: Rethinking Alignment via In-Context Learning},
34
+ author={Bill Yuchen Lin and Abhilasha Ravichander and Ximing Lu and Nouha Dziri and Melanie Sclar and Khyathi Chandu and Chandra Bhagavatula and Yejin Choi},
35
+ booktitle={International Conference on Learning Representations},
36
+ year={2024},
37
+ url={https://arxiv.org/abs/2312.01552}
38
+ }
39
+
40
+ @misc{zheng2023judging,
41
+ title={Judging LLM-as-a-Judge with MT-Bench and Chatbot Arena},
42
+ author={Lianmin Zheng and Wei-Lin Chiang and Ying Sheng and Siyuan Zhuang and Zhanghao Wu and Yonghao Zhuang and Zi Lin and Zhuohan Li and Dacheng Li and Eric P. Xing and Hao Zhang and Joseph E. Gonzalez and Ion Stoica},
43
+ year={2023},
44
+ eprint={2306.05685},
45
+ archivePrefix={arXiv},
46
+ primaryClass={cs.CL}
47
+ }
48
+ """
49
+
50
+ METRICS_TAB_TEXT = """
51
+ Here you will find details about the different metrics reported in our leaderboard.
52
+
53
+ ## Metrics
54
+
55
+ 🎯 Win Rate and Elo Ratings are popular metrics for evaluating LLMs general capabilities by comparing the with a strong reference model. [WIP]
56
+
57
+ ### Win Rate vs. ChatGPT
58
+
59
+ [WIP]
60
+
61
+ ```
62
+ Example:
63
+ ```
64
+
65
+
66
+
67
+ ### Elo Rating
68
+
69
+ [WIP]
70
+
71
+ ```
72
+ Example:
73
+ ```
74
+
75
+ ## How to reproduce our results
76
+
77
+ The WildBench Leaderboard will be a continued effort to benchmark open source/access LLMs.
78
+ Along with the Leaderboard we're open-sourcing the codebase used for running these evaluations.
79
+ For more details head over to our repo at: https://github.com/WildEval/WildBench-Leaderboard
80
+
81
+ P.S. We'd love to know which other models you'd like us to benchmark next. Contributions are more than welcome! β™₯️
82
+
83
+ ## Benchmark datasets
84
+
85
+
86
+ | Dataset | Domain | Source | size | License |
87
+ |-----------------------------------------------------------------|--------------------------|--------------|------|---------|
88
+ | [WildBench](https://huggingface.co/datasets/WildEval/WildBench) | in-the-wild user queries | [WildChat]() | XXX | XXX |
89
+
90
+
91
+ """
init.py ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import pandas as pd
3
+ from constants import EVAL_REQUESTS_PATH
4
+ from pathlib import Path
5
+ from huggingface_hub import HfApi, Repository
6
+
7
+ TOKEN_HUB = os.environ.get("TOKEN_HUB", None)
8
+ QUEUE_REPO = os.environ.get("QUEUE_REPO", None)
9
+ QUEUE_PATH = os.environ.get("QUEUE_PATH", None)
10
+
11
+ hf_api = HfApi(
12
+ endpoint="https://huggingface.co",
13
+ token=TOKEN_HUB,
14
+ )
15
+
16
+ def load_all_info_from_dataset_hub():
17
+ eval_queue_repo = None
18
+ results_csv_path = None
19
+ requested_models = None
20
+
21
+ passed = True
22
+ if TOKEN_HUB is None:
23
+ passed = False
24
+ else:
25
+ print("Pulling evaluation requests and results.")
26
+
27
+ eval_queue_repo = Repository(
28
+ local_dir=QUEUE_PATH,
29
+ clone_from=QUEUE_REPO,
30
+ use_auth_token=TOKEN_HUB,
31
+ repo_type="dataset",
32
+ )
33
+ eval_queue_repo.git_pull()
34
+
35
+ # Local directory where dataset repo is cloned + folder with eval requests
36
+ directory = QUEUE_PATH / EVAL_REQUESTS_PATH
37
+ requested_models = get_all_requested_models(directory)
38
+ requested_models = [p.stem for p in requested_models]
39
+ # Local directory where dataset repo is cloned
40
+ csv_results = get_csv_with_results(QUEUE_PATH)
41
+ # csv_results = pd.read_json(QUEUE_PATH, lines=True)
42
+ if csv_results is None:
43
+ passed = False
44
+ if not passed:
45
+ print("No HuggingFace token or result path provided. Skipping evaluation requests and results.")
46
+
47
+ return eval_queue_repo, requested_models, csv_results
48
+
49
+
50
+ def upload_file(requested_model_name, path_or_fileobj):
51
+ dest_repo_file = Path(EVAL_REQUESTS_PATH) / path_or_fileobj.name
52
+ dest_repo_file = str(dest_repo_file)
53
+ hf_api.upload_file(
54
+ path_or_fileobj=path_or_fileobj,
55
+ path_in_repo=str(dest_repo_file),
56
+ repo_id=QUEUE_REPO,
57
+ token=TOKEN_HUB,
58
+ repo_type="dataset",
59
+ commit_message=f"Add {requested_model_name} to eval queue")
60
+
61
+ def get_all_requested_models(directory):
62
+ directory = Path(directory)
63
+ all_requested_models = list(directory.glob("*.txt"))
64
+ return all_requested_models
65
+
66
+ def get_csv_with_results(directory):
67
+ directory = Path(directory)
68
+ all_csv_files = list(directory.glob("*.csv"))
69
+ latest = [f for f in all_csv_files if f.stem.endswith("latest")]
70
+ if len(latest) != 1:
71
+ return None
72
+ return latest[0]
73
+
74
+
75
+
76
+ def is_model_on_hub(model_name, revision="main") -> bool:
77
+ try:
78
+ model_name = model_name.replace(" ","")
79
+ author = model_name.split("/")[0]
80
+ model_id = model_name.split("/")[1]
81
+ if len(author) == 0 or len(model_id) == 0:
82
+ return False, "is not a valid model name. Please use the format `author/model_name`."
83
+ except Exception as e:
84
+ return False, "is not a valid model name. Please use the format `author/model_name`."
85
+
86
+ try:
87
+ models = list(hf_api.list_models(author=author, search=model_id))
88
+ matched = [model_name for m in models if m.modelId == model_name]
89
+ if len(matched) != 1:
90
+ return False, "was not found on the hub!"
91
+ else:
92
+ return True, None
93
+ except Exception as e:
94
+ print(f"Could not get the model from the hub.: {e}")
95
+ return False, "was not found on hub!"
leaderboard_data.jsonl ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {"model": "gpt-4", "Turn 1": 8.95625, "Turn 2": 9.025, "Overall": 8.990625, "coding": 8.55, "extraction": 9.375, "humanities": 9.95, "math": 6.8, "reasoning": 9.0, "roleplay": 8.9, "stem": 9.7, "writing": 9.65}
2
+ {"model": "gpt-3.5-turbo", "Turn 1": 8.075, "Turn 2": 7.8125, "Overall": 7.94375, "coding": 6.9, "extraction": 8.85, "humanities": 9.55, "math": 6.3, "reasoning": 5.65, "roleplay": 8.4, "stem": 8.7, "writing": 9.2}
3
+ {"model": "Llama-2-70b-hf", "Turn 1": 7.60625, "Turn 2": 6.6125, "Overall": 7.109375, "coding": 4.15, "extraction": 7.7, "humanities": 9.75, "math": 3.6, "reasoning": 6.1, "roleplay": 7.325, "stem": 8.75, "writing": 9.5}
4
+ {"model": "Mixtral-8x7B-v0.1", "Turn 1": 7.69375, "Turn 2": 6.1875, "Overall": 6.940625, "coding": 5.3, "extraction": 7.05, "humanities": 9.2, "math": 4.85, "reasoning": 5.3, "roleplay": 7.4, "stem": 8.225, "writing": 8.2}
5
+ {"model": "Mistral-7b-v0.1", "Turn 1": 7.4875, "Turn 2": 5.8625, "Overall": 6.675, "coding": 4.6, "extraction": 7.75, "humanities": 9.075, "math": 3.4, "reasoning": 4.9, "roleplay": 7.65, "stem": 8.275, "writing": 7.75}
6
+ {"model": "Yi-34B", "Turn 1": 7.19375, "Turn 2": 6.15625, "Overall": 6.675, "coding": 3.85, "extraction": 6.8, "humanities": 8.475, "math": 4.8, "reasoning": 6.0, "roleplay": 7.75, "stem": 7.825, "writing": 7.9}
7
+ {"model": "gemma-7b", "Turn 1": 6.96875, "Turn 2": 5.0375, "Overall": 6.003125, "coding": 3.95, "extraction": 6.25, "humanities": 8.825, "math": 4.35, "reasoning": 4.5, "roleplay": 6.25, "stem": 7.25, "writing": 6.65}
8
+ {"model": "phi-2", "Turn 1": 7.0375, "Turn 2": 4.6625, "Overall": 5.85, "coding": 4.25, "extraction": 4.45, "humanities": 8.85, "math": 3.8, "reasoning": 4.55, "roleplay": 7.2, "stem": 7.0, "writing": 6.7}
9
+ {"model": "Llama-2-13b-hf", "Turn 1": 6.26875, "Turn 2": 4.4125, "Overall": 5.340625, "coding": 2.8, "extraction": 4.7, "humanities": 8.3, "math": 2.85, "reasoning": 2.9, "roleplay": 6.625, "stem": 7.025, "writing": 7.525}
10
+ {"model": "Yi-6B", "Turn 1": 5.95625, "Turn 2": 3.9875, "Overall": 4.971875, "coding": 2.3, "extraction": 2.95, "humanities": 8.775, "math": 2.5, "reasoning": 3.5, "roleplay": 6.95, "stem": 7.7, "writing": 5.1}
11
+ {"model": "Llama-2-7b-hf", "Turn 1": 5.75, "Turn 2": 3.9125, "Overall": 4.83125, "coding": 1.65, "extraction": 3.4, "humanities": 8.075, "math": 1.6, "reasoning": 3.45, "roleplay": 7.475, "stem": 6.8, "writing": 6.2}
12
+ {"model": "gemma-2b", "Turn 1": 5.08125, "Turn 2": 2.8625, "Overall": 3.971875, "coding": 1.8, "extraction": 3.1, "humanities": 5.65, "math": 3.3, "reasoning": 2.55, "roleplay": 5.7, "stem": 5.725, "writing": 3.95}
13
+ {"model": "olmo", "Turn 1": 3.95, "Turn 2": 2.8625, "Overall": 3.40625, "coding": 1.65, "extraction": 2.45, "humanities": 4.9, "math": 1.25, "reasoning": 2.45, "roleplay": 5.3, "stem": 5.3, "writing": 3.95}
requirements.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ gradio==4.19.2
utils_display.py ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from dataclasses import dataclass
2
+
3
+ # These classes are for user facing column names, to avoid having to change them
4
+ # all around the code when a modif is needed
5
+ @dataclass
6
+ class ColumnContent:
7
+ name: str
8
+ type: str
9
+
10
+ def fields(raw_class):
11
+ return [v for k, v in raw_class.__dict__.items() if k[:2] != "__" and k[-2:] != "__"]
12
+
13
+ @dataclass(frozen=True)
14
+ class AutoEvalColumn: # Auto evals column
15
+ model = ColumnContent("Model", "markdown")
16
+ avg_wer = ColumnContent("Average WER ⬇️", "number")
17
+ rtf = ColumnContent("RTF (1e-3) ⬇️", "number")
18
+ ami_wer = ColumnContent("AMI", "number")
19
+ e22_wer = ColumnContent("Earnings22", "number")
20
+ gs_wer = ColumnContent("Gigaspeech", "number")
21
+ lsc_wer = ColumnContent("LS Clean", "number")
22
+ lso_wer = ColumnContent("LS Other", "number")
23
+ ss_wer = ColumnContent("SPGISpeech", "number")
24
+ tl_wer = ColumnContent("Tedlium", "number")
25
+ vp_wer = ColumnContent("Voxpopuli", "number")
26
+ cv_wer = ColumnContent("Common Voice", "number")
27
+
28
+
29
+ def make_clickable_model(model_name, model_info):
30
+ if model_info[model_name]['hf_name'].startswith("http"):
31
+ link = model_info[model_name]['hf_name']
32
+ else:
33
+ link = f"https://huggingface.co/{model_info[model_name]['hf_name']}"
34
+ return f'<a target="_blank" href="{link}" style="color: var(--link-text-color); text-decoration: underline;text-decoration-style: dotted;">{model_info[model_name]["pretty_name"]}</a>'
35
+
36
+ def styled_error(error):
37
+ return f"<p style='color: red; font-size: 20px; text-align: center;'>{error}</p>"
38
+
39
+ def styled_warning(warn):
40
+ return f"<p style='color: orange; font-size: 20px; text-align: center;'>{warn}</p>"
41
+
42
+ def styled_message(message):
43
+ return f"<p style='color: green; font-size: 20px; text-align: center;'>{message}</p>"