Spaces:
Running
Running
File size: 19,859 Bytes
c055e89 433517c cd5bd26 ca8a2ca c055e89 cd5bd26 0e3778b cd5bd26 1d58cd7 5cd0e1e 746b467 5cd0e1e a80c724 1d58cd7 cd5bd26 abcae38 cd5bd26 1ec31d9 abcae38 0e3778b 1ec31d9 cd5bd26 ca8a2ca cd5bd26 e5109be 18d89f0 20dc216 18d89f0 3ef2ca7 18d89f0 ce15f77 18d89f0 c055e89 cd5bd26 0217d78 c055e89 cd5bd26 c055e89 29a5f2c c055e89 0636bf7 c055e89 20dc216 c055e89 20dc216 cd5bd26 7776ec5 cd5bd26 1cb88a1 cd5bd26 ca8a2ca cd5bd26 1cb88a1 cd5bd26 18d89f0 cd5bd26 18d89f0 20dc216 18d89f0 20dc216 29a5f2c 20dc216 1cb88a1 20dc216 e080e91 18d89f0 29a5f2c e080e91 29a5f2c 2bb5d82 cd5bd26 2bb5d82 20dc216 2bb5d82 433517c af37f5e 3425a41 20dc216 3679f5d cd5bd26 20dc216 3425a41 20dc216 3679f5d cd5bd26 20dc216 cd5bd26 433517c af37f5e 99f01ee af37f5e 10801ae 433517c af37f5e 99f01ee af37f5e 10801ae 433517c af37f5e 99f01ee af37f5e 10801ae 433517c af37f5e 99f01ee af37f5e 10801ae c3c44ca 18d89f0 cd5bd26 2bb5d82 20dc216 18d89f0 c3c44ca 18d89f0 c3c44ca b0986f3 20dc216 cd5bd26 29a5f2c 28550ba cd5bd26 29a5f2c b0986f3 0636bf7 ca8a2ca 8818f44 272f73d ca8a2ca 272f73d ca8a2ca e7774de ca8a2ca e7774de ca8a2ca 89d563e 20dc216 5147f0b 20dc216 7366b46 1ba9e48 18d89f0 1ba9e48 18d89f0 9594ec2 1ba9e48 9594ec2 1ba9e48 89d563e ca8a2ca 9594ec2 ca8a2ca 0636bf7 20dc216 0636bf7 20dc216 c055e89 72d3fba cd5bd26 1cb88a1 a2eae81 8ca296f 20dc216 72d3fba 2519d7f 1225427 2519d7f cd5bd26 18d89f0 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 |
import gradio as gr
import random
import os
import shutil
import pandas as pd
import sqlite3
from datasets import load_dataset
import threading
import time
import uuid
from pathlib import Path
from huggingface_hub import CommitScheduler, delete_file, hf_hub_download
from gradio_client import Client
####################################
# Constants
####################################
AVAILABLE_MODELS = {
'XTTS': 'xttsv2',
'WhisperSpeech': 'whisperspeech',
'ElevenLabs': 'eleven',
'OpenVoice': 'openvoice',
'Pheme': 'pheme',
}
SPACE_ID = os.getenv('HF_ID')
DB_DATASET_ID = os.getenv('DATASET_ID')
DB_NAME = "database.db"
# If /data available => means local storage is enabled => let's use it!
DB_PATH = f"/data/{DB_NAME}" if os.path.isdir("/data") else DB_NAME
AUDIO_DATASET_ID = "ttseval/tts-arena-new"
CITATION_TEXT = """@misc{tts-arena,
title = {Text to Speech Arena},
author = {mrfakename and Srivastav, Vaibhav and Pouget, Lucain and Fourrier, Clémentine},
year = 2024,
publisher = {Hugging Face},
howpublished = "\\url{https://huggingface.co/spaces/ttseval/TTS-Arena}"
}"""
####################################
# Functions
####################################
def create_db_if_missing():
conn = get_db()
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS model (
name TEXT UNIQUE,
upvote INTEGER,
downvote INTEGER
);
''')
cursor.execute('''
CREATE TABLE IF NOT EXISTS vote (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT,
model TEXT,
vote INTEGER
);
''')
def get_db():
return sqlite3.connect(DB_PATH)
def get_leaderboard():
conn = get_db()
cursor = conn.cursor()
cursor.execute('SELECT name, upvote, downvote FROM model WHERE (upvote + downvote) > 5')
data = cursor.fetchall()
df = pd.DataFrame(data, columns=['name', 'upvote', 'downvote'])
df['license'] = df['name'].replace(model_licenses)
df['name'] = df['name'].replace(model_names)
df['votes'] = df['upvote'] + df['downvote']
# df['score'] = round((df['upvote'] / df['votes']) * 100, 2) # Percentage score
## ELO SCORE
df['score'] = 1200
for i in range(len(df)):
for j in range(len(df)):
if i != j:
expected_a = 1 / (1 + 10 ** ((df['score'][j] - df['score'][i]) / 400))
expected_b = 1 / (1 + 10 ** ((df['score'][i] - df['score'][j]) / 400))
actual_a = df['upvote'][i] / df['votes'][i]
actual_b = df['upvote'][j] / df['votes'][j]
df.at[i, 'score'] += 32 * (actual_a - expected_a)
df.at[j, 'score'] += 32 * (actual_b - expected_b)
df['score'] = round(df['score'])
## ELO SCORE
df = df.sort_values(by='score', ascending=False)
df['order'] = ['#' + str(i + 1) for i in range(len(df))]
# df = df[['name', 'score', 'upvote', 'votes']]
df = df[['order', 'name', 'score', 'license', 'votes']]
return df
####################################
# Space initialization
####################################
# Download existing DB
if not os.path.isfile(DB_PATH):
print("Downloading DB...")
try:
cache_path = hf_hub_download(repo_id=DB_DATASET_ID, repo_type='dataset', filename=DB_NAME)
shutil.copyfile(cache_path, DB_PATH)
print("Downloaded DB")
except Exception as e:
print("Error while downloading DB:", e)
# Create DB table (if doesn't exist)
create_db_if_missing()
# Sync local DB with remote repo every 5 minute (only if a change is detected)
scheduler = CommitScheduler(
repo_id=DB_DATASET_ID,
repo_type="dataset",
folder_path=Path(DB_PATH).parent,
every=5,
allow_patterns=DB_NAME,
)
# Load audio dataset
audio_dataset = load_dataset(AUDIO_DATASET_ID)
####################################
# Router API
####################################
router = Client("ttseval/tts-router", hf_token=os.getenv('HF_TOKEN'))
####################################
# Gradio app
####################################
MUST_BE_LOGGEDIN = "Please login with Hugging Face to participate in the TTS Arena."
DESCR = """
# TTS Arena
Vote on different speech synthesis models!
""".strip()
INSTR = """
## Instructions
* Listen to two anonymous models
* Vote on which synthesized audio sounds more natural to you
* If there's a tie, click Skip
**When you're ready to begin, login and begin voting!** The model names will be revealed once you vote.
""".strip()
request = ''
if SPACE_ID:
request = f"""
### Request Model
Please fill out [this form](https://huggingface.co/spaces/{SPACE_ID}/discussions/new?title=%5BModel+Request%5D+&description=%23%23%20Model%20Request%0A%0A%2A%2AModel%20website%2Fpaper%20%28if%20applicable%29%2A%2A%3A%0A%2A%2AModel%20available%20on%2A%2A%3A%20%28coqui%7CHF%20pipeline%7Ccustom%20code%29%0A%2A%2AWhy%20do%20you%20want%20this%20model%20added%3F%2A%2A%0A%2A%2AComments%3A%2A%2A) to request a model.
"""
ABOUT = f"""
## About
The TTS Arena is a project created to evaluate leading speech synthesis models. It is inspired by the [Chatbot Arena](https://chat.lmsys.org/) by LMSYS.
### How it Works
First, vote on two samples of text-to-speech models. The models that synthesized the samples are not revealed to mitigate bias.
As you vote, the leaderboard will be updated based on votes. We calculate a score for each model using a method similar to the [Elo system](https://en.wikipedia.org/wiki/Elo_rating_system).
### Motivation
Recently, many new open-access speech synthesis models have been made available to the community. However, there is no standardized evaluation or benchmark to measure the quality and naturalness of these models.
The TTS Arena is an attempt to benchmark these models and find the highest-quality models available to the community.
{request}
### Privacy Statement
We may store text you enter and generated audio. We store a unique ID for each session.
""".strip()
LDESC = """
## Leaderboard
A list of the models, based on how highly they are ranked!
""".strip()
def reload_audio_dataset():
global audio_dataset
audio_dataset = load_dataset(AUDIO_DATASET_ID)
return 'Reload Audio Dataset'
def del_db(txt):
if not txt.lower() == 'delete db':
raise gr.Error('You did not enter "delete db"')
# Delete local + remote
os.remove(DB_PATH)
delete_file(path_in_repo=DB_NAME, repo_id=DB_DATASET_ID, repo_type='dataset')
# Recreate
create_db_if_missing()
return 'Delete DB'
theme = gr.themes.Base(
font=[gr.themes.GoogleFont('Libre Franklin'), gr.themes.GoogleFont('Public Sans'), 'system-ui', 'sans-serif'],
)
model_names = {
'styletts2': 'StyleTTS 2',
'tacotron': 'Tacotron',
'tacotronph': 'Tacotron Phoneme',
'tacotrondca': 'Tacotron DCA',
'speedyspeech': 'Speedy Speech',
'overflow': 'Overflow TTS',
'vits': 'VITS',
'vitsneon': 'VITS Neon',
'neuralhmm': 'Neural HMM',
'glow': 'Glow TTS',
'fastpitch': 'FastPitch',
'jenny': 'Jenny',
'tortoise': 'Tortoise TTS',
'xtts2': 'Coqui XTTSv2',
'xtts': 'Coqui XTTS',
'openvoice': 'MyShell OpenVoice',
'elevenlabs': 'ElevenLabs',
'openai': 'OpenAI',
'hierspeech': 'HierSpeech++',
'pheme': 'PolyAI Pheme',
'speecht5': 'SpeechT5',
'metavoice': 'MetaVoice-1B',
}
model_licenses = {
'styletts2': 'MIT',
'tacotron': 'BSD-3',
'tacotronph': 'BSD-3',
'tacotrondca': 'BSD-3',
'speedyspeech': 'BSD-3',
'overflow': 'MIT',
'vits': 'MIT',
'openvoice': 'MIT',
'vitsneon': 'BSD-3',
'neuralhmm': 'MIT',
'glow': 'MIT',
'fastpitch': 'Apache 2.0',
'jenny': 'Jenny License',
'tortoise': 'Apache 2.0',
'xtts2': 'CPML (NC)',
'xtts': 'CPML (NC)',
'elevenlabs': 'Proprietary',
'openai': 'Proprietary',
'hierspeech': 'MIT',
'pheme': 'CC-BY',
'speecht5': 'MIT',
'metavoice': 'Apache 2.0',
}
model_links = {
'styletts2': 'https://github.com/yl4579/StyleTTS2',
'tacotron': 'https://github.com/NVIDIA/tacotron2',
'speedyspeech': 'https://github.com/janvainer/speedyspeech',
'overflow': 'https://github.com/shivammehta25/OverFlow',
'vits': 'https://github.com/jaywalnut310/vits',
'openvoice': 'https://github.com/myshell-ai/OpenVoice',
'neuralhmm': 'https://github.com/ketranm/neuralHMM',
'glow': 'https://github.com/jaywalnut310/glow-tts',
'fastpitch': 'https://fastpitch.github.io/',
'tortoise': 'https://github.com/neonbjb/tortoise-tts',
'xtts2': 'https://huggingface.co/coqui/XTTS-v2',
'xtts': 'https://huggingface.co/coqui/XTTS-v1',
'elevenlabs': 'https://elevenlabs.io/',
'openai': 'https://help.openai.com/en/articles/8555505-tts-api',
'hierspeech': 'https://github.com/sh-lee-prml/HierSpeechpp',
'pheme': 'https://github.com/PolyAI-LDN/pheme',
'speecht5': 'https://github.com/microsoft/SpeechT5',
'metavoice': 'https://github.com/metavoiceio/metavoice-src',
}
# def get_random_split(existing_split=None):
# choice = random.choice(list(audio_dataset.keys()))
# if existing_split and choice == existing_split:
# return get_random_split(choice)
# else:
# return choice
# def get_random_splits():
# choice1 = get_random_split()
# choice2 = get_random_split(choice1)
# return (choice1, choice2)
def mkuuid(uid):
if not uid:
uid = uuid.uuid4()
return uid
def upvote_model(model, uname):
conn = get_db()
cursor = conn.cursor()
cursor.execute('UPDATE model SET upvote = upvote + 1 WHERE name = ?', (model,))
if cursor.rowcount == 0:
cursor.execute('INSERT OR REPLACE INTO model (name, upvote, downvote) VALUES (?, 1, 0)', (model,))
cursor.execute('INSERT INTO vote (username, model, vote) VALUES (?, ?, ?)', (uname, model, 1,))
with scheduler.lock:
conn.commit()
cursor.close()
def downvote_model(model, uname):
conn = get_db()
cursor = conn.cursor()
cursor.execute('UPDATE model SET downvote = downvote + 1 WHERE name = ?', (model,))
if cursor.rowcount == 0:
cursor.execute('INSERT OR REPLACE INTO model (name, upvote, downvote) VALUES (?, 0, 1)', (model,))
cursor.execute('INSERT INTO vote (username, model, vote) VALUES (?, ?, ?)', (uname, model, -1,))
with scheduler.lock:
conn.commit()
cursor.close()
def a_is_better(model1, model2, userid):
userid = mkuuid(userid)
if model1 and model2:
upvote_model(model1, str(userid))
downvote_model(model2, str(userid))
return reload(model1, model2, userid)
def b_is_better(model1, model2, userid):
userid = mkuuid(userid)
if model1 and model2:
upvote_model(model2, str(userid))
downvote_model(model1, str(userid))
return reload(model1, model2, userid)
def both_bad(model1, model2, userid):
userid = mkuuid(userid)
if model1 and model2:
downvote_model(model1, str(userid))
downvote_model(model2, str(userid))
return reload(model1, model2, userid)
def both_good(model1, model2, userid):
userid = mkuuid(userid)
if model1 and model2:
upvote_model(model1, str(userid))
upvote_model(model2, str(userid))
return reload(model1, model2, userid)
def reload(chosenmodel1=None, chosenmodel2=None, userid=None):
# Select random splits
row = random.choice(list(audio_dataset['train']))
options = list(random.choice(list(audio_dataset['train'])).keys())
split1, split2 = random.sample(options, 2)
choice1, choice2 = (row[split1], row[split2])
if chosenmodel1 in model_names:
chosenmodel1 = model_names[chosenmodel1]
if chosenmodel2 in model_names:
chosenmodel2 = model_names[chosenmodel2]
out = [
(choice1['sampling_rate'], choice1['array']),
(choice2['sampling_rate'], choice2['array']),
split1,
split2
]
if userid: out.append(userid)
if chosenmodel1: out.append(f'This model was {chosenmodel1}')
if chosenmodel2: out.append(f'This model was {chosenmodel2}')
return out
with gr.Blocks() as leaderboard:
gr.Markdown(LDESC)
# df = gr.Dataframe(interactive=False, value=get_leaderboard())
df = gr.Dataframe(interactive=False, min_width=0, wrap=True, column_widths=[30, 200, 50, 75, 50])
reloadbtn = gr.Button("Refresh")
leaderboard.load(get_leaderboard, outputs=[df])
reloadbtn.click(get_leaderboard, outputs=[df])
gr.Markdown("DISCLAIMER: The licenses listed may not be accurate or up to date, you are responsible for checking the licenses before using the models. Also note that some models may have additional usage restrictions.")
# with gr.Blocks() as vote:
# useridstate = gr.State()
# gr.Markdown(INSTR)
# # gr.LoginButton()
# with gr.Row():
# gr.HTML('<div align="left"><h3>Model A</h3></div>')
# gr.HTML('<div align="right"><h3>Model B</h3></div>')
# model1 = gr.Textbox(interactive=False, visible=False, lines=1, max_lines=1)
# model2 = gr.Textbox(interactive=False, visible=False, lines=1, max_lines=1)
# # with gr.Group():
# # with gr.Row():
# # prevmodel1 = gr.Textbox(interactive=False, show_label=False, container=False, value="Vote to reveal model A")
# # prevmodel2 = gr.Textbox(interactive=False, show_label=False, container=False, value="Vote to reveal model B", text_align="right")
# # with gr.Row():
# # aud1 = gr.Audio(interactive=False, show_label=False, show_download_button=False, show_share_button=False, waveform_options={'waveform_progress_color': '#3C82F6'})
# # aud2 = gr.Audio(interactive=False, show_label=False, show_download_button=False, show_share_button=False, waveform_options={'waveform_progress_color': '#3C82F6'})
# with gr.Group():
# with gr.Row():
# with gr.Column():
# with gr.Group():
# prevmodel1 = gr.Textbox(interactive=False, show_label=False, container=False, value="Vote to reveal model A", lines=1, max_lines=1)
# aud1 = gr.Audio(interactive=False, show_label=False, show_download_button=False, show_share_button=False, waveform_options={'waveform_progress_color': '#3C82F6'})
# with gr.Column():
# with gr.Group():
# prevmodel2 = gr.Textbox(interactive=False, show_label=False, container=False, value="Vote to reveal model B", text_align="right", lines=1, max_lines=1)
# aud2 = gr.Audio(interactive=False, show_label=False, show_download_button=False, show_share_button=False, waveform_options={'waveform_progress_color': '#3C82F6'})
# with gr.Row():
# abetter = gr.Button("A is Better", variant='primary', scale=4)
# # skipbtn = gr.Button("Skip", scale=1)
# bbetter = gr.Button("B is Better", variant='primary', scale=4)
# with gr.Row():
# bothbad = gr.Button("Both are Bad", scale=2)
# skipbtn = gr.Button("Skip", scale=1)
# bothgood = gr.Button("Both are Good", scale=2)
# outputs = [aud1, aud2, model1, model2, useridstate, prevmodel1, prevmodel2]
# abetter.click(a_is_better, outputs=outputs, inputs=[model1, model2, useridstate])
# bbetter.click(b_is_better, outputs=outputs, inputs=[model1, model2, useridstate])
# skipbtn.click(b_is_better, outputs=outputs, inputs=[model1, model2, useridstate])
# bothbad.click(both_bad, outputs=outputs, inputs=[model1, model2, useridstate])
# bothgood.click(both_good, outputs=outputs, inputs=[model1, model2, useridstate])
# vote.load(reload, outputs=[aud1, aud2, model1, model2])
def synthandreturn(text):
# Get two random models
mdl1, mdl2 = random.sample(AVAILABLE_MODELS.keys(), 2)
return (
text,
"Synthesize",
gr.update(visible=True), # r1
gr.update(visible=True), # r2
mdl1, # model1
mdl2, # model2
'Vote to reveal model A', # prevmodel1
router.predict(
text,
AVAILABLE_MODELS[mdl1],
api_name="/synthesize"
), # aud1
'Vote to reveal model B', # prevmodel2
router.predict(
text,
AVAILABLE_MODELS[mdl2],
api_name="/synthesize"
), # aud2
)
with gr.Blocks() as vote:
useridstate = gr.State()
gr.Markdown(INSTR)
with gr.Group():
text = gr.Textbox(label="Enter text to synthesize", info="By entering text, you certify that it is either in the public domain or, if you are its author, you dedicate it into the public domain. You also must agree to the privacy statement in the About page.")
btn = gr.Button("Synthesize", variant='primary')
with gr.Row(visible=False) as r1:
gr.HTML('<div align="left"><h3>Model A</h3></div>')
gr.HTML('<div align="right"><h3>Model B</h3></div>')
model1 = gr.Textbox(interactive=False, lines=1, max_lines=1, visible=False)
model2 = gr.Textbox(interactive=False, lines=1, max_lines=1, visible=False)
with gr.Group(visible=False) as r2:
with gr.Row():
with gr.Column():
with gr.Group():
prevmodel1 = gr.Textbox(interactive=False, show_label=False, container=False, value="Vote to reveal model A", lines=1, max_lines=1)
aud1 = gr.Audio(interactive=False, show_label=False, show_download_button=False, show_share_button=False, waveform_options={'waveform_progress_color': '#3C82F6'})
with gr.Column():
with gr.Group():
prevmodel2 = gr.Textbox(interactive=False, show_label=False, container=False, value="Vote to reveal model B", text_align="right", lines=1, max_lines=1)
aud2 = gr.Audio(interactive=False, show_label=False, show_download_button=False, show_share_button=False, waveform_options={'waveform_progress_color': '#3C82F6'})
with gr.Row():
abetter = gr.Button("A is Better", variant='primary')
bbetter = gr.Button("B is Better", variant='primary')
outputs = [text, btn, r1, r2, model1, model2, prevmodel1, aud1, prevmodel2, aud2]
btn.click(synthandreturn, inputs=[text], outputs=outputs)
nxt_outputs = [aud1, aud2, model1, model2, useridstate, prevmodel1, prevmodel2]
abetter.click(a_is_better, outputs=nxt_outputs, inputs=[model1, model2, useridstate])
bbetter.click(b_is_better, outputs=nxt_outputs, inputs=[model1, model2, useridstate])
# skipbtn.click(b_is_better, outputs=outputs, inputs=[model1, model2, useridstate])
# bothbad.click(both_bad, outputs=outputs, inputs=[model1, model2, useridstate])
# bothgood.click(both_good, outputs=outputs, inputs=[model1, model2, useridstate])
# vote.load(reload, outputs=[aud1, aud2, model1, model2])
with gr.Blocks() as about:
gr.Markdown(ABOUT)
with gr.Blocks() as admin:
rdb = gr.Button("Reload Audio Dataset")
rdb.click(reload_audio_dataset, outputs=rdb)
with gr.Group():
dbtext = gr.Textbox(label="Type \"delete db\" to confirm", placeholder="delete db")
ddb = gr.Button("Delete DB")
ddb.click(del_db, inputs=dbtext, outputs=ddb)
with gr.Blocks(theme=theme, css="footer {visibility: hidden}textbox{resize:none}", title="TTS Leaderboard") as demo:
gr.Markdown(DESCR)
gr.TabbedInterface([vote, leaderboard, about, admin], ['Vote', 'Leaderboard', 'About', 'Admin (ONLY IN BETA)'])
if CITATION_TEXT:
with gr.Row():
with gr.Accordion("📙 Citation", open=False):
gr.Markdown(f"If you use this data in your publication, please cite!\n\nCopy the BibTeX citation to cite this source:\n\n```bibtext\n{CITATION_TEXT}\n```")
demo.queue(api_open=False).launch(show_api=False) |