zhuohan-7 commited on
Commit
b0e6781
·
verified ·
1 Parent(s): 463c494

Upload folder using huggingface_hub

Browse files
Files changed (4) hide show
  1. app/__init__.py +0 -0
  2. app/draw_diagram.py +114 -0
  3. app/pages.py +303 -0
  4. app/show_examples.py +129 -0
app/__init__.py ADDED
File without changes
app/draw_diagram.py ADDED
@@ -0,0 +1,114 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import pandas as pd
3
+ import numpy as np
4
+ from streamlit_echarts import st_echarts
5
+ # from streamlit_echarts import JsCode
6
+ from streamlit_javascript import st_javascript
7
+ # from PIL import Image
8
+ from app.show_examples import *
9
+
10
+ links_dic = {}
11
+
12
+ links_dic = {k.lower().replace('_', '-') : v for k, v in links_dic.items()}
13
+
14
+ # huggingface_image = Image.open('style/huggingface.jpg')
15
+
16
+ def nav_to(value):
17
+ try:
18
+ url = links_dic[str(value).lower()]
19
+ js = f'window.open("{url}", "_blank").then(r => window.parent.location.href);'
20
+ st_javascript(js)
21
+ except:
22
+ pass
23
+
24
+ def draw(folder_name, category_name, dataset_name, metrics):
25
+
26
+ folder = f"./results/{metrics}/"
27
+
28
+ display_names = {
29
+ 'SU': 'Speech Understanding',
30
+ 'ASU': 'Audio Scene Understanding',
31
+ 'VU': 'Voice Understanding'
32
+ }
33
+
34
+ data_path = f'{folder}/{category_name.lower()}.csv'
35
+ chart_data = pd.read_csv(data_path).round(2)
36
+
37
+ # if sorted == 'Ascending':
38
+ # ascend = True
39
+ # else:
40
+ # ascend = False
41
+
42
+ new_dataset_name = dataset_name.replace('-', '_').lower()
43
+ chart_data = chart_data[['Model', new_dataset_name]]
44
+
45
+ chart_data = chart_data.sort_values(by=[new_dataset_name], ascending=True).dropna(axis=0)
46
+
47
+ if len(chart_data) == 0:
48
+ return
49
+
50
+ min_value = round(chart_data.iloc[:, 1::].min().min() - 0.1, 1)
51
+ max_value = round(chart_data.iloc[:, 1::].max().max() + 0.1, 1)
52
+
53
+ options = {
54
+ "title": {"text": f"{display_names[folder_name.upper()]}"},
55
+ "tooltip": {
56
+ "trigger": "axis",
57
+ "axisPointer": {"type": "cross", "label": {"backgroundColor": "#6a7985"}},
58
+ "triggerOn": 'mousemove',
59
+ },
60
+ "legend": {"data": ['Overall Accuracy']},
61
+ "toolbox": {"feature": {"saveAsImage": {}}},
62
+ "grid": {"left": "3%", "right": "4%", "bottom": "3%", "containLabel": True},
63
+ "xAxis": [
64
+ {
65
+ "type": "category",
66
+ "boundaryGap": False,
67
+ "triggerEvent": True,
68
+ "data": chart_data['Model'].tolist(),
69
+ }
70
+ ],
71
+ "yAxis": [{"type": "value",
72
+ "min": min_value,
73
+ "max": max_value,
74
+ # "splitNumber": 10
75
+ }],
76
+ "series": [{
77
+ "name": f"{dataset_name}",
78
+ "type": "line",
79
+ "data": chart_data[f'{new_dataset_name}'].tolist(),
80
+ }],
81
+ }
82
+
83
+ events = {
84
+ "click": "function(params) { return params.value }"
85
+ }
86
+
87
+ value = st_echarts(options=options, events=events, height="500px")
88
+
89
+ if value != None:
90
+ # print(value)
91
+ nav_to(value)
92
+
93
+ # if value != None:
94
+ # highlight_table_line(value)
95
+
96
+ '''
97
+ Show table
98
+ '''
99
+ # st.divider()
100
+ with st.expander('TABLE'):
101
+ # chart_data['Link'] = chart_data['Model'].map(links_dic)
102
+ st.dataframe(chart_data,
103
+ # column_config = {
104
+ # "Link": st.column_config.LinkColumn(
105
+ # display_text= st.image(huggingface_image)
106
+ # ),
107
+ # },
108
+ hide_index = True,
109
+ use_container_width=True)
110
+ '''
111
+ show samples
112
+ '''
113
+ show_examples(category_name, dataset_name, chart_data['Model'].tolist())
114
+
app/pages.py ADDED
@@ -0,0 +1,303 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ from app.draw_diagram import *
3
+
4
+ def dashboard():
5
+
6
+ with st.container():
7
+ st.title("AudioBench")
8
+
9
+ st.markdown("""
10
+ [gh]: https://github.com/AudioLLMs/AudioBench
11
+ [![GitHub watchers](https://img.shields.io/github/watchers/AudioLLMs/AudioBench?style=social)][gh]
12
+ [![GitHub Repo stars](https://img.shields.io/github/stars/AudioLLMs/AudioBench?style=social)][gh]
13
+ """)
14
+
15
+ audio_url = "https://arxiv.org/abs/2406.16020"
16
+
17
+ st.divider()
18
+ st.markdown("#### [AudioBench](%s)" % audio_url)
19
+ st.markdown("##### :dizzy: A comprehensive evaluation benchmark designed for general instruction-following audiolanguage models")
20
+ st.markdown('''
21
+
22
+
23
+ ''')
24
+
25
+ with st.container():
26
+ left_co, center_co, right_co = st.columns([0.5,1, 0.5])
27
+ with center_co:
28
+ st.image("./style/audio_overview.png",
29
+ caption="Overview of the datasets in AudioBench.",
30
+ use_column_width = True)
31
+
32
+ st.markdown('''
33
+
34
+
35
+ ''')
36
+
37
+ st.markdown("###### :dart: Our Benchmark includes: ")
38
+ cols = st.columns(10)
39
+ cols[1].metric(label="Tasks", value="8") #delta="Tasks", delta_color="off"
40
+ cols[2].metric(label="Datasets", value="26")
41
+ cols[3].metric(label="Test Models", value="5")
42
+
43
+ # st.markdown("###### :dart: Supported Models and Datasets: ")
44
+
45
+ # sup = pd.DataFrame(
46
+ # {"Dataset": "LibriSpeech-Clean",
47
+ # "Category": st.selectbox('category', ['Speech Understanding']),
48
+ # "Task": st.selectbox('task', ['Automatic Speech Recognition']),
49
+ # "Metrics": st.selectbox('metrics', ['WER']),
50
+ # "Status":True}
51
+ # )
52
+
53
+ # st.data_editor(sup, num_rows="dynamic")
54
+
55
+
56
+ st.divider()
57
+ with st.container():
58
+ st.markdown("##### Citations")
59
+
60
+ st.markdown('''
61
+ :round_pushpin: AudioBench Paper \n
62
+ @article{wang2024audiobench,
63
+ title={AudioBench: A Universal Benchmark for Audio Large Language Models},
64
+ author={Wang, Bin and Zou, Xunlong and Lin, Geyu and Sun, Shuo and Liu, Zhuohan and Zhang, Wenyu and Liu, Zhengyuan and Aw, AiTi and Chen, Nancy F},
65
+ journal={arXiv preprint arXiv:2406.16020},
66
+ year={2024}
67
+ }
68
+ ''')
69
+
70
+ def asr():
71
+ st.title("Automatic Speech Recognition")
72
+
73
+ filters_levelone = ['LibriSpeech-Test-Clean',
74
+ 'LibriSpeech-Test-Other',
75
+ 'Common-Voice-15-En-Test',
76
+ 'Peoples-Speech-Test',
77
+ 'GigaSpeech-Test',
78
+ 'Earnings21-Test',
79
+ 'Earnings22-Test',
80
+ 'Tedlium3-Test',
81
+ 'Tedlium3-Longform-Test',
82
+ 'IMDA-Part1-ASR-Test',
83
+ 'IMDA-Part2-ASR-Test',
84
+ 'IMDA-Part3-ASR-Test',
85
+ 'IMDA-Part4-ASR-Test',
86
+ 'IMDA-Part5-ASR-Test',
87
+ 'IMDA-Part6-ASR-Test']
88
+
89
+ left, center, _, middle,right = st.columns([0.2, 0.2, 0.2, 0.2 ,0.2])
90
+
91
+ with left:
92
+ filter_1 = st.selectbox('Select Dataset', filters_levelone)
93
+
94
+ # with middle:
95
+ # if filter_1 == filters_levelone[0]:
96
+ # sort_leveltwo = ['LibriSpeech-Test-Clean', 'LibriSpeech-Test-Other', 'Common-Voice-15-En-Test', 'Peoples-Speech-Test',
97
+ # 'GigaSpeech-Test', 'Tedlium3-Test','Tedlium3-Longform-Test', 'Earning-21-Test', 'Earning-22-Test']
98
+ # elif filter_1 == filters_levelone[1]:
99
+ # sort_leveltwo = ['CN-College-Listen-Test', 'SLUE-P2-SQA5-Test', 'DREAM-TTS-Test', 'Public-SG-SpeechQA-Test']
100
+
101
+ # elif filter_1 == filters_levelone[2]:
102
+ # sort_leveltwo = ['OpenHermes-Audio-Test', 'ALPACA-Audio-Test']
103
+
104
+ # sort = st.selectbox("Sort Dataset", sort_leveltwo)
105
+
106
+ # with right:
107
+ # sorted = st.selectbox('by', ['Ascending', 'Descending'])
108
+
109
+ if filter_1:
110
+ draw('su', 'ASR', filter_1, 'wer')
111
+ else:
112
+ draw('su', 'ASR', 'LibriSpeech-Test-Clean', 'wer')
113
+
114
+
115
+ ## examples
116
+
117
+
118
+ def sqa():
119
+ st.title("Speech Question Answering")
120
+
121
+ binary = ['CN-College-Listen-MCQ-Test', 'DREAM-TTS-MCQ-Test']
122
+
123
+ rest = ['SLUE-P2-SQA5-Test',
124
+ 'Public-SG-Speech-QA-Test',
125
+ 'Spoken-Squad-v1']
126
+
127
+ filters_levelone = binary + rest
128
+
129
+ left, center, _, middle,right = st.columns([0.2, 0.2, 0.2, 0.2 ,0.2])
130
+
131
+ with left:
132
+ filter_1 = st.selectbox('Select Dataset', filters_levelone)
133
+
134
+ if filter_1:
135
+ if filter_1 in binary:
136
+ draw('su', 'SQA', filter_1, 'llama3_70b_judge_binary')
137
+ else:
138
+ draw('su', 'SQA', filter_1, 'llama3_70b_judge')
139
+ else:
140
+ draw('su', 'SQA', 'CN-College-Listen-Test', 'llama3_70b_judge_binary')
141
+
142
+ def si():
143
+ st.title("Speech Question Answering")
144
+
145
+ filters_levelone = ['OpenHermes-Audio-Test',
146
+ 'ALPACA-Audio-Test']
147
+
148
+ left, center, _, middle,right = st.columns([0.2, 0.2, 0.2, 0.2 ,0.2])
149
+
150
+ with left:
151
+ filter_1 = st.selectbox('Select Dataset', filters_levelone)
152
+
153
+ if filter_1:
154
+ draw('su', 'SI', filter_1, 'llama3_70b_judge')
155
+ else:
156
+ draw('su', 'SI', 'OpenHermes-Audio-Test', 'llama3_70b_judge')
157
+
158
+ def ac():
159
+ st.title("Audio Captioning")
160
+
161
+ filters_levelone = ['WavCaps-Test',
162
+ 'AudioCaps-Test']
163
+ filters_leveltwo = ['Llama3-70b-judge', 'Meteor']
164
+
165
+ left, center, _, middle,right = st.columns([0.2, 0.2, 0.2, 0.2 ,0.2])
166
+
167
+ with left:
168
+ filter_1 = st.selectbox('Select Dataset', filters_levelone)
169
+ with middle:
170
+ metric = st.selectbox('Select Metric', filters_leveltwo)
171
+
172
+ # with middle:
173
+ # if filter_1 == filters_levelone[0]:
174
+ # sort_leveltwo = ['Clotho-AQA-Test', 'WavCaps-QA-Test', 'AudioCaps-QA-Test']
175
+ # elif filter_1 == filters_levelone[1]:
176
+ # sort_leveltwo = ['WavCaps-Test', 'AudioCaps-Test']
177
+
178
+ # sort = st.selectbox("Sort Dataset", sort_leveltwo)
179
+
180
+ # with right:
181
+ # sorted = st.selectbox('by', ['Ascending', 'Descending'])
182
+
183
+ if filter_1 or metric:
184
+ draw('asu', 'AC',filter_1, metric.lower().replace('-', '_'))
185
+ else:
186
+ draw('asu', 'AC', 'WavCaps-Test', 'llama3_70b_judge')
187
+
188
+ def asqa():
189
+ st.title("Audio Scene Question Answering")
190
+
191
+ filters_levelone = ['Clotho-AQA-Test',
192
+ 'WavCaps-QA-Test',
193
+ 'AudioCaps-QA-Test']
194
+
195
+ left, center, _, middle,right = st.columns([0.2, 0.2, 0.2, 0.2 ,0.2])
196
+
197
+ with left:
198
+ filter_1 = st.selectbox('Select Dataset', filters_levelone)
199
+
200
+ if filter_1:
201
+ draw('asu', 'AQA',filter_1, 'llama3_70b_judge')
202
+ else:
203
+ draw('asu', 'AQA', 'Clotho-AQA-Test', 'llama3_70b_judge')
204
+
205
+ def er():
206
+ st.title("Emotion Recognition")
207
+
208
+ filters_levelone = ['IEMOCAP-Emotion-Test',
209
+ 'MELD-Sentiment-Test',
210
+ 'MELD-Emotion-Test']
211
+ sort_leveltwo = []
212
+
213
+ left, center, _, middle,right = st.columns([0.2, 0.2, 0.2, 0.2 ,0.2])
214
+
215
+ with left:
216
+ filter_1 = st.selectbox('Select Dataset', filters_levelone)
217
+
218
+ # with middle:
219
+ # if filter_1 == filters_levelone[0]:
220
+ # sort_leveltwo = ['IEMOCAP-Emotion-Test', 'MELD-Sentiment-Test', 'MELD-Emotion-Test']
221
+
222
+ # elif filter_1 == filters_levelone[1]:
223
+ # sort_leveltwo = ['VoxCeleb1-Accent-Test']
224
+
225
+ # elif filter_1 == filters_levelone[2]:
226
+ # sort_leveltwo = ['VoxCeleb1-Gender-Test', 'IEMOCAP-Gender-Test']
227
+
228
+ # sort = st.selectbox("Sort Dataset", sort_leveltwo)
229
+
230
+ # with right:
231
+ # sorted = st.selectbox('by', ['Ascending', 'Descending'])
232
+
233
+ if filter_1:
234
+ draw('vu', 'ER', filter_1, 'llama3_70b_judge_binary')
235
+ else:
236
+ draw('vu', 'ER', 'IEMOCAP-Emotion-Test', 'llama3_70b_judge_binary')
237
+
238
+ def ar():
239
+ st.title("Accent Recognition")
240
+
241
+ filters_levelone = ['VoxCeleb-Accent-Test']
242
+
243
+ left, center, _, middle,right = st.columns([0.2, 0.2, 0.2, 0.2 ,0.2])
244
+
245
+ with left:
246
+ filter_1 = st.selectbox('Select Dataset', filters_levelone)
247
+
248
+
249
+ if filter_1:
250
+ draw('vu', 'AR', filter_1, 'llama3_70b_judge')
251
+ else:
252
+ draw('vu', 'AR', 'VoxCeleb-Accent-Test', 'llama3_70b_judge')
253
+
254
+ def gr():
255
+ st.title("Emotion Recognition")
256
+
257
+ filters_levelone = ['VoxCeleb-Gender-Test',
258
+ 'IEMOCAP-Gender-Test']
259
+
260
+ left, center, _, middle,right = st.columns([0.2, 0.2, 0.2, 0.2 ,0.2])
261
+
262
+ with left:
263
+ filter_1 = st.selectbox('Select Dataset', filters_levelone)
264
+
265
+ if filter_1:
266
+ draw('vu', 'GR', filter_1, 'llama3_70b_judge_binary')
267
+ else:
268
+ draw('vu', 'GR', 'VoxCeleb1-Gender-Test', 'llama3_70b_judge_binary')
269
+
270
+ def spt():
271
+ st.title("Speech Translation")
272
+
273
+ filters_levelone = ['Covost2-EN-ID-test',
274
+ 'Covost2-EN-ZH-test',
275
+ 'Covost2-EN-TA-test',
276
+ 'Covost2-ID-EN-test',
277
+ 'Covost2-ZH-EN-test',
278
+ 'Covost2-TA-EN-test']
279
+
280
+ left, center, _, middle,right = st.columns([0.2, 0.2, 0.2, 0.2 ,0.2])
281
+
282
+ with left:
283
+ filter_1 = st.selectbox('Select Dataset', filters_levelone)
284
+
285
+ if filter_1:
286
+ draw('su', 'ST', filter_1, 'bleu')
287
+ else:
288
+ draw('su', 'ST', 'Covost2-EN-ID-test', 'bleu')
289
+
290
+ def cnasr():
291
+ st.title("Chinese Automatic Speech Recognition")
292
+
293
+ filters_levelone = ['Aishell-ASR-ZH-Test']
294
+
295
+ left, center, _, middle,right = st.columns([0.2, 0.2, 0.2, 0.2 ,0.2])
296
+
297
+ with left:
298
+ filter_1 = st.selectbox('Select Dataset', filters_levelone)
299
+
300
+ if filter_1:
301
+ draw('su', 'CNASR', filter_1, 'wer')
302
+ else:
303
+ draw('su', 'CNASR', 'Aishell-ASR-ZH-Test', 'wer')
app/show_examples.py ADDED
@@ -0,0 +1,129 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import datasets
3
+ import numpy as np
4
+
5
+
6
+ def show_examples(category_name, dataset_name, model_lists):
7
+ st.divider()
8
+ sample_folder = f"./examples/{category_name}/{dataset_name}"
9
+ dataset = datasets.load_from_disk(sample_folder)
10
+
11
+ for index in range(len(dataset)):
12
+
13
+ with st.expander(f'EXAMPLE {index+1}'):
14
+ col1, col2 = st.columns([0.3, 0.7], vertical_alignment="center")
15
+
16
+ with col1:
17
+ st.audio(f'{sample_folder}/sample_{index}.wav', format="audio/wav")
18
+
19
+ with col2:
20
+ with st.container():
21
+ custom_css = """
22
+ <style>
23
+ .my-container-question {
24
+ background-color: #F5EEF8;
25
+ padding: 10px;
26
+ border-radius: 10px;
27
+ height: auto;
28
+ }
29
+ </style>
30
+ """
31
+ st.markdown(custom_css, unsafe_allow_html=True)
32
+
33
+ if dataset_name in ['CN-College-Listen-MCQ-Test', 'DREAM-TTS-MCQ-Test']:
34
+
35
+ choices = dataset[index]['other_attributes']['choices']
36
+ if isinstance(choices, str):
37
+ choices_text = choices
38
+ elif isinstance(choices, list):
39
+ choices_text = ' '.join(i for i in choices)
40
+
41
+ question_text = f"""<div class="my-container-question">
42
+ <p>QUESTION: {dataset[index]['instruction']['text']}</p>
43
+ <p>CHOICES: {choices_text}</p>
44
+ </div>
45
+ """
46
+ else:
47
+ question_text = f"""<div class="my-container-question">
48
+ <p>QUESTION: {dataset[index]['instruction']['text']}</p>
49
+ </div>"""
50
+
51
+
52
+ st.markdown(question_text, unsafe_allow_html=True)
53
+
54
+ with st.container():
55
+ custom_css = """
56
+ <style>
57
+ .my-container-answer {
58
+ background-color: #F9EBEA;
59
+ padding: 10px;
60
+ border-radius: 10px;
61
+ height: auto;
62
+ }
63
+ </style>
64
+ """
65
+ st.markdown(custom_css, unsafe_allow_html=True)
66
+ st.markdown(f"""<div class="my-container-answer">
67
+ <p>CORRECT ANSWER: {dataset[index]['answer']['text']}</p>
68
+ </div>""", unsafe_allow_html=True)
69
+
70
+
71
+ st.divider()
72
+ with st.container():
73
+ custom_css = """
74
+ <style>
75
+ .my-container-table {
76
+ background-color: #F2F3F4;
77
+ padding: 10px;
78
+ border-radius: 5px;
79
+ # height: 50px;
80
+ }
81
+ </style>
82
+ """
83
+ st.markdown(custom_css, unsafe_allow_html=True)
84
+
85
+ model_lists.sort()
86
+
87
+ s = ''
88
+ if dataset_name in ['CN-College-Listen-MCQ-Test', 'DREAM-TTS-MCQ-Test']:
89
+ for model in model_lists:
90
+ try:
91
+ s += f"""<tr>
92
+ <td>{model}</td>
93
+ <td><p>{dataset[index][model]['text']}</p> <p>{choices_text}</p></td>
94
+ <td>{dataset[index][model]['model_prediction']}</td>
95
+ </tr>"""
96
+ except:
97
+ print(f"{model} is not in {dataset_name}")
98
+ continue
99
+ else:
100
+ for model in model_lists:
101
+ try:
102
+ s += f"""<tr>
103
+ <td>{model}</td>
104
+ <td>{dataset[index][model]['text']}</td>
105
+ <td>{dataset[index][model]['model_prediction']}</td>
106
+ </tr>"""
107
+ except:
108
+ print(f"{model} is not in {dataset_name}")
109
+ continue
110
+
111
+ body_details = f"""<table style="width:100%">
112
+ <thead>
113
+ <tr style="text-align: center;">
114
+ <th style="width:20%">MODEL</th>
115
+ <th style="width:40%">QUESTION</th>
116
+ <th style="width:40%">MODEL PREDICTION</th>
117
+ </tr>
118
+ {s}
119
+ </thead>
120
+ </table>"""
121
+
122
+ st.markdown(f"""<div class="my-container-table">
123
+ {body_details}
124
+ </div>""", unsafe_allow_html=True)
125
+
126
+ st.text("")
127
+
128
+
129
+