martinakaduc commited on
Commit
836764d
β€’
1 Parent(s): f3305db

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +1102 -0
app.py ADDED
@@ -0,0 +1,1102 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ The gradio demo server for chatting with a single model.
3
+ """
4
+
5
+ import argparse
6
+ from collections import defaultdict
7
+ import datetime
8
+ import hashlib
9
+ import json
10
+ import os
11
+ import random
12
+ import time
13
+ import uuid
14
+
15
+ import gradio as gr
16
+ import requests
17
+
18
+ from fastchat.constants import (
19
+ LOGDIR,
20
+ WORKER_API_TIMEOUT,
21
+ ErrorCode,
22
+ MODERATION_MSG,
23
+ CONVERSATION_LIMIT_MSG,
24
+ RATE_LIMIT_MSG,
25
+ SERVER_ERROR_MSG,
26
+ INPUT_CHAR_LEN_LIMIT,
27
+ CONVERSATION_TURN_LIMIT,
28
+ SESSION_EXPIRATION_TIME,
29
+ SURVEY_LINK,
30
+ TASKS,
31
+ LANGUAGES
32
+ )
33
+ from fastchat.model.model_adapter import (
34
+ get_conversation_template,
35
+ )
36
+ from fastchat.model.model_registry import get_model_info, model_info
37
+ from fastchat.serve.api_provider import get_api_provider_stream_iter
38
+ from fastchat.serve.remote_logger import get_remote_logger
39
+ from fastchat.utils import (
40
+ build_logger,
41
+ get_window_url_params_js,
42
+ get_window_url_params_with_tos_js,
43
+ moderation_filter,
44
+ parse_gradio_auth_creds,
45
+ load_image,
46
+ )
47
+
48
+ logger = build_logger("gradio_web_server", "gradio_web_server.log")
49
+
50
+ headers = {"User-Agent": "FastChat Client"}
51
+
52
+ no_change_btn = gr.Button()
53
+ enable_btn = gr.Button(interactive=True, visible=True)
54
+ disable_btn = gr.Button(interactive=False)
55
+ invisible_btn = gr.Button(interactive=False, visible=False)
56
+ enable_text = gr.Textbox(
57
+ interactive=True, visible=True, placeholder="πŸ‘‰ Enter your prompt and press ENTER"
58
+ )
59
+ disable_textbox=gr.Textbox(interactive=False)
60
+ disable_text = gr.Textbox(
61
+ interactive=False,
62
+ visible=True,
63
+ placeholder='Press "🎲 New Round" to start overπŸ‘‡ (Note: Your vote shapes the leaderboard, please vote RESPONSIBLY!)',
64
+ )
65
+
66
+ controller_url = None
67
+ enable_moderation = False
68
+ use_remote_storage = False
69
+
70
+ acknowledgment_md = """
71
+ ### Terms of Service
72
+
73
+ Users are required to agree to the following terms before using the service:
74
+
75
+ The service is a research preview. It only provides limited safety measures and may generate offensive content.
76
+ It must not be used for any illegal, harmful, violent, racist, or sexual purposes.
77
+ Please do not upload any private information.
78
+ The service collects user dialogue data, including both text and images, and reserves the right to distribute it under a Creative Commons Attribution (CC-BY) or a similar license.
79
+
80
+ #### Please report any bug or issue to our [Discord](https://discord.gg/HSWAKCrnFx)/arena-feedback.
81
+
82
+ ### Acknowledgment
83
+ We thank [UC Berkeley SkyLab](https://sky.cs.berkeley.edu/), [Kaggle](https://www.kaggle.com/), [MBZUAI](https://mbzuai.ac.ae/), [a16z](https://www.a16z.com/), [Together AI](https://www.together.ai/), [Hyperbolic](https://hyperbolic.xyz/), [RunPod](https://runpod.io), [Anyscale](https://www.anyscale.com/), [HuggingFace](https://huggingface.co/) for their generous [sponsorship](https://lmsys.org/donations/).
84
+
85
+ <div class="sponsor-image-about">
86
+ <img src="https://storage.googleapis.com/public-arena-asset/skylab.png" alt="SkyLab">
87
+ <img src="https://storage.googleapis.com/public-arena-asset/kaggle.png" alt="Kaggle">
88
+ <img src="https://storage.googleapis.com/public-arena-asset/mbzuai.jpeg" alt="MBZUAI">
89
+ <img src="https://storage.googleapis.com/public-arena-asset/a16z.jpeg" alt="a16z">
90
+ <img src="https://storage.googleapis.com/public-arena-asset/together.png" alt="Together AI">
91
+ <img src="https://storage.googleapis.com/public-arena-asset/hyperbolic_logo.png" alt="Hyperbolic">
92
+ <img src="https://storage.googleapis.com/public-arena-asset/runpod-logo.jpg" alt="RunPod">
93
+ <img src="https://storage.googleapis.com/public-arena-asset/anyscale.png" alt="AnyScale">
94
+ <img src="https://storage.googleapis.com/public-arena-asset/huggingface.png" alt="HuggingFace">
95
+ </div>
96
+ """
97
+
98
+ # JSON file format of API-based models:
99
+ # {
100
+ # "gpt-3.5-turbo": {
101
+ # "model_name": "gpt-3.5-turbo",
102
+ # "api_type": "openai",
103
+ # "api_base": "https://api.openai.com/v1",
104
+ # "api_key": "sk-******",
105
+ # "anony_only": false
106
+ # }
107
+ # }
108
+ #
109
+ # - "api_type" can be one of the following: openai, anthropic, gemini, or mistral. For custom APIs, add a new type and implement it accordingly.
110
+ # - "anony_only" indicates whether to display this model in anonymous mode only.
111
+
112
+ api_endpoint_info = {}
113
+
114
+
115
+ class State:
116
+ def __init__(self, model_name, task, language, is_vision=False):
117
+ self.conv = get_conversation_template(model_name)
118
+ self.conv_id = uuid.uuid4().hex
119
+ self.skip_next = False
120
+ self.model_name = model_name
121
+ self.task = task
122
+ self.language = language
123
+ self.oai_thread_id = None
124
+ self.is_vision = is_vision
125
+
126
+ # NOTE(chris): This could be sort of a hack since it assumes the user only uploads one image. If they can upload multiple, we should store a list of image hashes.
127
+ self.has_csam_image = False
128
+
129
+ self.regen_support = True
130
+ if "browsing" in model_name:
131
+ self.regen_support = False
132
+ self.init_system_prompt(self.conv, is_vision)
133
+
134
+ def init_system_prompt(self, conv, is_vision):
135
+ system_prompt = conv.get_system_message(is_vision)
136
+ if len(system_prompt) == 0:
137
+ return
138
+ current_date = datetime.datetime.now().strftime("%Y-%m-%d")
139
+ system_prompt = system_prompt.replace("{{currentDateTime}}", current_date)
140
+ conv.set_system_message(system_prompt)
141
+
142
+ def to_gradio_chatbot(self):
143
+ return self.conv.to_gradio_chatbot()
144
+
145
+ def dict(self):
146
+ base = self.conv.dict()
147
+ base.update(
148
+ {
149
+ "conv_id": self.conv_id,
150
+ "model_name": self.model_name,
151
+ }
152
+ )
153
+
154
+ if self.is_vision:
155
+ base.update({"has_csam_image": self.has_csam_image})
156
+ return base
157
+
158
+
159
+ def set_global_vars(controller_url_, enable_moderation_, use_remote_storage_):
160
+ global controller_url, enable_moderation, use_remote_storage
161
+ controller_url = controller_url_
162
+ enable_moderation = enable_moderation_
163
+ use_remote_storage = use_remote_storage_
164
+
165
+
166
+ def get_conv_log_filename(is_vision=False, has_csam_image=False):
167
+ t = datetime.datetime.now()
168
+ conv_log_filename = f"{t.year}-{t.month:02d}-{t.day:02d}-conv.json"
169
+ if is_vision and not has_csam_image:
170
+ name = os.path.join(LOGDIR, f"vision-tmp-{conv_log_filename}")
171
+ elif is_vision and has_csam_image:
172
+ name = os.path.join(LOGDIR, f"vision-csam-{conv_log_filename}")
173
+ else:
174
+ name = os.path.join(LOGDIR, conv_log_filename)
175
+
176
+ return name
177
+
178
+
179
+ def get_model_list(controller_url, register_api_endpoint_file, vision_arena):
180
+ global api_endpoint_info
181
+
182
+ # Add models from the controller
183
+ if controller_url:
184
+ ret = requests.post(controller_url + "/refresh_all_workers")
185
+ assert ret.status_code == 200
186
+
187
+ if vision_arena:
188
+ ret = requests.post(controller_url + "/list_multimodal_models")
189
+ models = ret.json()["models"]
190
+ else:
191
+ ret = requests.post(controller_url + "/list_language_models")
192
+ models = ret.json()["models"]
193
+ else:
194
+ models = []
195
+
196
+ # Add models from the API providers
197
+ if register_api_endpoint_file:
198
+ api_endpoint_info = json.load(open(register_api_endpoint_file))
199
+ for mdl, mdl_dict in api_endpoint_info.items():
200
+ mdl_vision = mdl_dict.get("vision-arena", False)
201
+ mdl_text = mdl_dict.get("text-arena", True)
202
+ if vision_arena and mdl_vision:
203
+ models.append(mdl)
204
+ if not vision_arena and mdl_text:
205
+ models.append(mdl)
206
+
207
+ # Remove anonymous models
208
+ models = list(set(models))
209
+ visible_models = models.copy()
210
+ for mdl in models:
211
+ if mdl not in api_endpoint_info:
212
+ continue
213
+ mdl_dict = api_endpoint_info[mdl]
214
+ if mdl_dict["anony_only"]:
215
+ visible_models.remove(mdl)
216
+
217
+ # Sort models and add descriptions
218
+ priority = {k: f"___{i:03d}" for i, k in enumerate(model_info)}
219
+ models.sort(key=lambda x: priority.get(x, x))
220
+ visible_models.sort(key=lambda x: priority.get(x, x))
221
+ logger.info(f"All models: {models}")
222
+ logger.info(f"Visible models: {visible_models}")
223
+ return visible_models, models
224
+
225
+
226
+ def load_demo_single(models, url_params):
227
+ selected_model = models[0] if len(models) > 0 else ""
228
+ if "model" in url_params:
229
+ model = url_params["model"]
230
+ if model in models:
231
+ selected_model = model
232
+
233
+ dropdown_update = gr.Dropdown(choices=models, value=selected_model, visible=True)
234
+ state = None
235
+ return state, dropdown_update
236
+
237
+
238
+ def load_demo(url_params, request: gr.Request):
239
+ global models
240
+
241
+ ip = get_ip(request)
242
+ logger.info(f"load_demo. ip: {ip}. params: {url_params}")
243
+
244
+ if args.model_list_mode == "reload":
245
+ models, all_models = get_model_list(
246
+ controller_url, args.register_api_endpoint_file, vision_arena=False
247
+ )
248
+
249
+ return load_demo_single(models, url_params)
250
+
251
+
252
+ def vote_last_response(state, vote_type, model_selector, task_selector, language_selector, request: gr.Request, **kwargs):
253
+ filename = get_conv_log_filename()
254
+ if "llava" in model_selector:
255
+ filename = filename.replace("2024", "vision-tmp-2024")
256
+
257
+ with open(filename, "a") as fout:
258
+ data = {
259
+ "tstamp": round(time.time(), 4),
260
+ "type": vote_type,
261
+ "language": language_selector,
262
+ "task": task_selector,
263
+ "model": model_selector,
264
+ "state": state.dict(),
265
+ "ip": get_ip(request),
266
+ **kwargs
267
+ }
268
+ fout.write(json.dumps(data) + "\n")
269
+ get_remote_logger().log(data)
270
+
271
+
272
+ def upvote_last_response(state, model_selector, task_selector, language_selector, request: gr.Request):
273
+ ip = get_ip(request)
274
+ logger.info(f"upvote. ip: {ip}")
275
+ vote_last_response(state, "upvote", model_selector, task_selector, language_selector, request)
276
+ return ("",) + (disable_btn,) * 3
277
+
278
+
279
+ def downvote_last_response(state, model_selector, task_selector, language_selector, rewrite_textbox, request: gr.Request):
280
+ ip = get_ip(request)
281
+ logger.info(f"downvote. ip: {ip}")
282
+ vote_last_response(state, "downvote", model_selector, task_selector, language_selector, request, answer_suggestion=rewrite_textbox)
283
+ return ("",) + ("",) + (disable_btn,) * 3
284
+
285
+
286
+ def flag_last_response(state, model_selector, task_selector, language_selector, request: gr.Request):
287
+ ip = get_ip(request)
288
+ logger.info(f"flag. ip: {ip}")
289
+ vote_last_response(state, "flag", model_selector, task_selector, language_selector, request)
290
+ return ("",) + (disable_btn,) * 3
291
+
292
+
293
+ def regenerate(state, request: gr.Request):
294
+ ip = get_ip(request)
295
+ logger.info(f"regenerate. ip: {ip}")
296
+ if not state.regen_support:
297
+ state.skip_next = True
298
+ return (state, state.to_gradio_chatbot(), "", None) + (no_change_btn,) * 5
299
+ state.conv.update_last_message(None)
300
+ return (state, state.to_gradio_chatbot(), "") + (disable_btn,) * 5
301
+
302
+
303
+ def clear_history(request: gr.Request):
304
+ ip = get_ip(request)
305
+ logger.info(f"clear_history. ip: {ip}")
306
+ state = None
307
+ return (state, [], "") + (disable_btn,) * 5
308
+
309
+
310
+ def get_ip(request: gr.Request):
311
+ if "cf-connecting-ip" in request.headers:
312
+ ip = request.headers["cf-connecting-ip"]
313
+ elif "x-forwarded-for" in request.headers:
314
+ ip = request.headers["x-forwarded-for"]
315
+ if "," in ip:
316
+ ip = ip.split(",")[0]
317
+ else:
318
+ ip = request.client.host
319
+ return ip
320
+
321
+
322
+ def add_text(state, model_selector, task_selector, language_selector, system_prompt, text, request: gr.Request):
323
+ ip = get_ip(request)
324
+ logger.info(f"add_text. ip: {ip}. len: {len(text)}")
325
+
326
+ if state is None:
327
+ state = State(model_selector, task_selector, language_selector)
328
+ state.conv.set_system_message(system_prompt)
329
+
330
+ if len(text) <= 0:
331
+ state.skip_next = True
332
+ return (state, state.to_gradio_chatbot(), "", None) + (no_change_btn,) * 5
333
+
334
+ all_conv_text = state.conv.get_prompt()
335
+
336
+ all_conv_text = all_conv_text[-2000:] + "\nuser: " + text
337
+ flagged = moderation_filter(all_conv_text, [state.model_name])
338
+ # flagged = moderation_filter(text, [state.model_name])
339
+ if flagged:
340
+ logger.info(f"violate moderation. ip: {ip}. text: {text}")
341
+ # overwrite the original text
342
+ text = MODERATION_MSG
343
+
344
+ if (len(state.conv.messages) - state.conv.offset) // 2 >= CONVERSATION_TURN_LIMIT:
345
+ logger.info(f"conversation turn limit. ip: {ip}. text: {text}")
346
+ state.skip_next = True
347
+ return (state, state.to_gradio_chatbot(), CONVERSATION_LIMIT_MSG, None) + (
348
+ no_change_btn,
349
+ ) * 5
350
+
351
+ text = text[:INPUT_CHAR_LEN_LIMIT] # Hard cut-off
352
+ state.conv.append_message(state.conv.roles[0], text)
353
+ state.conv.append_message(state.conv.roles[1], None)
354
+ return (state, state.to_gradio_chatbot(), "") + (disable_btn,) * 5
355
+
356
+
357
+ def model_worker_stream_iter(
358
+ conv,
359
+ model_name,
360
+ worker_addr,
361
+ prompt,
362
+ temperature,
363
+ repetition_penalty,
364
+ top_p,
365
+ max_new_tokens,
366
+ images,
367
+ ):
368
+ # Make requests
369
+ gen_params = {
370
+ "model": model_name,
371
+ "prompt": prompt,
372
+ "temperature": temperature,
373
+ "repetition_penalty": repetition_penalty,
374
+ "top_p": top_p,
375
+ "max_new_tokens": max_new_tokens,
376
+ "stop": conv.stop_str,
377
+ "stop_token_ids": conv.stop_token_ids,
378
+ "echo": False,
379
+ }
380
+
381
+ logger.info(f"==== request ====\n{gen_params}")
382
+
383
+ if len(images) > 0:
384
+ gen_params["images"] = images
385
+
386
+ # Stream output
387
+ response = requests.post(
388
+ worker_addr + "/worker_generate_stream",
389
+ headers=headers,
390
+ json=gen_params,
391
+ stream=True,
392
+ timeout=WORKER_API_TIMEOUT,
393
+ )
394
+ for chunk in response.iter_lines(decode_unicode=False, delimiter=b"\0"):
395
+ if chunk:
396
+ data = json.loads(chunk.decode())
397
+ yield data
398
+
399
+
400
+ def is_limit_reached(model_name, ip):
401
+ monitor_url = "http://localhost:9090"
402
+ try:
403
+ ret = requests.get(
404
+ f"{monitor_url}/is_limit_reached?model={model_name}&user_id={ip}", timeout=1
405
+ )
406
+ obj = ret.json()
407
+ return obj
408
+ except Exception as e:
409
+ logger.info(f"monitor error: {e}")
410
+ return None
411
+
412
+
413
+ def bot_response(
414
+ state,
415
+ temperature,
416
+ top_p,
417
+ max_new_tokens,
418
+ request: gr.Request,
419
+ apply_rate_limit=True,
420
+ use_recommended_config=False,
421
+ ):
422
+ ip = get_ip(request)
423
+ logger.info(f"bot_response. ip: {ip}")
424
+ start_tstamp = time.time()
425
+ temperature = float(temperature)
426
+ top_p = float(top_p)
427
+ max_new_tokens = int(max_new_tokens)
428
+
429
+ if state.skip_next:
430
+ # This generate call is skipped due to invalid inputs
431
+ state.skip_next = False
432
+ yield (state, state.to_gradio_chatbot()) + (no_change_btn,) * 5
433
+ return
434
+
435
+ if apply_rate_limit:
436
+ ret = is_limit_reached(state.model_name, ip)
437
+ if ret is not None and ret["is_limit_reached"]:
438
+ error_msg = RATE_LIMIT_MSG + "\n\n" + ret["reason"]
439
+ logger.info(f"rate limit reached. ip: {ip}. error_msg: {ret['reason']}")
440
+ state.conv.update_last_message(error_msg)
441
+ yield (state, state.to_gradio_chatbot()) + (no_change_btn,) * 5
442
+ return
443
+
444
+ conv, model_name, task, language = state.conv, state.model_name, state.task, state.language
445
+ model_api_dict = (
446
+ api_endpoint_info[model_name] if model_name in api_endpoint_info else None
447
+ )
448
+ images = conv.get_images()
449
+
450
+ if model_api_dict is None:
451
+ # Query worker address
452
+ ret = requests.post(
453
+ controller_url + "/get_worker_address", json={"model": model_name}
454
+ )
455
+ worker_addr = ret.json()["address"]
456
+ logger.info(f"model_name: {model_name}, worker_addr: {worker_addr}")
457
+
458
+ # No available worker
459
+ if worker_addr == "":
460
+ conv.update_last_message(SERVER_ERROR_MSG)
461
+ yield (
462
+ state,
463
+ state.to_gradio_chatbot(),
464
+ disable_btn,
465
+ disable_btn,
466
+ disable_btn,
467
+ enable_btn,
468
+ enable_btn,
469
+ )
470
+ return
471
+
472
+ # Construct prompt.
473
+ # We need to call it here, so it will not be affected by "β–Œ".
474
+ prompt = conv.get_prompt()
475
+ # Set repetition_penalty
476
+ if "t5" in model_name:
477
+ repetition_penalty = 1.2
478
+ else:
479
+ repetition_penalty = 1.0
480
+
481
+ stream_iter = model_worker_stream_iter(
482
+ conv,
483
+ model_name,
484
+ worker_addr,
485
+ prompt,
486
+ temperature,
487
+ repetition_penalty,
488
+ top_p,
489
+ max_new_tokens,
490
+ images,
491
+ )
492
+ else:
493
+ # Remove system prompt for API-based models unless specified
494
+ custom_system_prompt = model_api_dict.get("custom_system_prompt", False)
495
+ if not custom_system_prompt:
496
+ conv.set_system_message("")
497
+
498
+ if use_recommended_config:
499
+ recommended_config = model_api_dict.get("recommended_config", None)
500
+ if recommended_config is not None:
501
+ temperature = recommended_config.get("temperature", temperature)
502
+ top_p = recommended_config.get("top_p", top_p)
503
+ max_new_tokens = recommended_config.get(
504
+ "max_new_tokens", max_new_tokens
505
+ )
506
+
507
+ stream_iter = get_api_provider_stream_iter(
508
+ conv,
509
+ model_name,
510
+ model_api_dict,
511
+ temperature,
512
+ top_p,
513
+ max_new_tokens,
514
+ state,
515
+ )
516
+
517
+ html_code = ' <span class="cursor"></span> '
518
+
519
+ # conv.update_last_message("β–Œ")
520
+ conv.update_last_message(html_code)
521
+ yield (state, state.to_gradio_chatbot()) + (disable_btn,) * 5
522
+
523
+ try:
524
+ data = {"text": ""}
525
+ for i, data in enumerate(stream_iter):
526
+ if data["error_code"] == 0:
527
+ output = data["text"].strip()
528
+ conv.update_last_message(output + "β–Œ")
529
+ # conv.update_last_message(output + html_code)
530
+ yield (state, state.to_gradio_chatbot()) + (disable_btn,) * 5
531
+ else:
532
+ output = data["text"] + f"\n\n(error_code: {data['error_code']})"
533
+ conv.update_last_message(output)
534
+ yield (state, state.to_gradio_chatbot()) + (
535
+ disable_btn,
536
+ disable_btn,
537
+ disable_btn,
538
+ enable_btn,
539
+ enable_btn,
540
+ )
541
+ return
542
+ output = data["text"].strip()
543
+ conv.update_last_message(output)
544
+ yield (state, state.to_gradio_chatbot()) + (enable_btn,) * 5
545
+ except requests.exceptions.RequestException as e:
546
+ conv.update_last_message(
547
+ f"{SERVER_ERROR_MSG}\n\n"
548
+ f"(error_code: {ErrorCode.GRADIO_REQUEST_ERROR}, {e})"
549
+ )
550
+ yield (state, state.to_gradio_chatbot()) + (
551
+ disable_btn,
552
+ disable_btn,
553
+ disable_btn,
554
+ enable_btn,
555
+ enable_btn,
556
+ )
557
+ return
558
+ except Exception as e:
559
+ conv.update_last_message(
560
+ f"{SERVER_ERROR_MSG}\n\n"
561
+ f"(error_code: {ErrorCode.GRADIO_STREAM_UNKNOWN_ERROR}, {e})"
562
+ )
563
+ yield (state, state.to_gradio_chatbot()) + (
564
+ disable_btn,
565
+ disable_btn,
566
+ disable_btn,
567
+ enable_btn,
568
+ enable_btn,
569
+ )
570
+ return
571
+
572
+ finish_tstamp = time.time()
573
+ logger.info(f"{output}")
574
+
575
+ conv.save_new_images(
576
+ has_csam_images=state.has_csam_image, use_remote_storage=use_remote_storage
577
+ )
578
+
579
+ filename = get_conv_log_filename(
580
+ is_vision=state.is_vision, has_csam_image=state.has_csam_image
581
+ )
582
+
583
+ with open(filename, "a") as fout:
584
+ data = {
585
+ "tstamp": round(finish_tstamp, 4),
586
+ "type": "chat",
587
+ "language": language,
588
+ "task": task,
589
+ "model": model_name,
590
+ "gen_params": {
591
+ "temperature": temperature,
592
+ "top_p": top_p,
593
+ "max_new_tokens": max_new_tokens,
594
+ },
595
+ "start": round(start_tstamp, 4),
596
+ "finish": round(finish_tstamp, 4),
597
+ "state": state.dict(),
598
+ "ip": get_ip(request),
599
+ }
600
+ fout.write(json.dumps(data) + "\n")
601
+ get_remote_logger().log(data)
602
+
603
+
604
+ block_css = """
605
+ .prose {
606
+ font-size: 105% !important;
607
+ }
608
+
609
+ #arena_leaderboard_dataframe table {
610
+ font-size: 105%;
611
+ }
612
+ #full_leaderboard_dataframe table {
613
+ font-size: 105%;
614
+ }
615
+
616
+ .tab-nav button {
617
+ font-size: 18px;
618
+ }
619
+
620
+ .chatbot h1 {
621
+ font-size: 130%;
622
+ }
623
+ .chatbot h2 {
624
+ font-size: 120%;
625
+ }
626
+ .chatbot h3 {
627
+ font-size: 110%;
628
+ }
629
+
630
+ #chatbot .prose {
631
+ font-size: 90% !important;
632
+ }
633
+
634
+ .sponsor-image-about img {
635
+ margin: 0 20px;
636
+ margin-top: 20px;
637
+ height: 40px;
638
+ max-height: 100%;
639
+ width: auto;
640
+ float: left;
641
+ }
642
+
643
+ .cursor {
644
+ display: inline-block;
645
+ width: 7px;
646
+ height: 1em;
647
+ background-color: black;
648
+ vertical-align: middle;
649
+ animation: blink 1s infinite;
650
+ }
651
+
652
+ .dark .cursor {
653
+ display: inline-block;
654
+ width: 7px;
655
+ height: 1em;
656
+ background-color: white;
657
+ vertical-align: middle;
658
+ animation: blink 1s infinite;
659
+ }
660
+
661
+ @keyframes blink {
662
+ 0%, 50% { opacity: 1; }
663
+ 50.1%, 100% { opacity: 0; }
664
+ }
665
+
666
+ .app {
667
+ max-width: 100% !important;
668
+ padding-left: 5% !important;
669
+ padding-right: 5% !important;
670
+ }
671
+
672
+ a {
673
+ color: #1976D2; /* Your current link color, a shade of blue */
674
+ text-decoration: none; /* Removes underline from links */
675
+ }
676
+ a:hover {
677
+ color: #63A4FF; /* This can be any color you choose for hover */
678
+ text-decoration: underline; /* Adds underline on hover */
679
+ }
680
+ """
681
+
682
+
683
+ # block_css = """
684
+ # #notice_markdown .prose {
685
+ # font-size: 110% !important;
686
+ # }
687
+ # #notice_markdown th {
688
+ # display: none;
689
+ # }
690
+ # #notice_markdown td {
691
+ # padding-top: 6px;
692
+ # padding-bottom: 6px;
693
+ # }
694
+ # #arena_leaderboard_dataframe table {
695
+ # font-size: 110%;
696
+ # }
697
+ # #full_leaderboard_dataframe table {
698
+ # font-size: 110%;
699
+ # }
700
+ # #model_description_markdown {
701
+ # font-size: 110% !important;
702
+ # }
703
+ # #leaderboard_markdown .prose {
704
+ # font-size: 110% !important;
705
+ # }
706
+ # #leaderboard_markdown td {
707
+ # padding-top: 6px;
708
+ # padding-bottom: 6px;
709
+ # }
710
+ # #leaderboard_dataframe td {
711
+ # line-height: 0.1em;
712
+ # }
713
+ # #about_markdown .prose {
714
+ # font-size: 110% !important;
715
+ # }
716
+ # #ack_markdown .prose {
717
+ # font-size: 110% !important;
718
+ # }
719
+ # #chatbot .prose {
720
+ # font-size: 105% !important;
721
+ # }
722
+ # .sponsor-image-about img {
723
+ # margin: 0 20px;
724
+ # margin-top: 20px;
725
+ # height: 40px;
726
+ # max-height: 100%;
727
+ # width: auto;
728
+ # float: left;
729
+ # }
730
+
731
+ # body {
732
+ # --body-text-size: 14px;
733
+ # }
734
+
735
+ # .chatbot h1, h2, h3 {
736
+ # margin-top: 8px; /* Adjust the value as needed */
737
+ # margin-bottom: 0px; /* Adjust the value as needed */
738
+ # padding-bottom: 0px;
739
+ # }
740
+
741
+ # .chatbot h1 {
742
+ # font-size: 130%;
743
+ # }
744
+ # .chatbot h2 {
745
+ # font-size: 120%;
746
+ # }
747
+ # .chatbot h3 {
748
+ # font-size: 110%;
749
+ # }
750
+ # .chatbot p:not(:first-child) {
751
+ # margin-top: 8px;
752
+ # }
753
+
754
+ # .typing {
755
+ # display: inline-block;
756
+ # }
757
+
758
+ # """
759
+
760
+
761
+ def get_model_description_md(models):
762
+ model_description_md = """
763
+ | | | |
764
+ | ---- | ---- | ---- |
765
+ """
766
+ ct = 0
767
+ visited = set()
768
+ for i, name in enumerate(models):
769
+ minfo = get_model_info(name)
770
+ if minfo.simple_name in visited:
771
+ continue
772
+ visited.add(minfo.simple_name)
773
+ one_model_md = f"[{minfo.simple_name}]({minfo.link}): {minfo.description}"
774
+
775
+ if ct % 3 == 0:
776
+ model_description_md += "|"
777
+ model_description_md += f" {one_model_md} |"
778
+ if ct % 3 == 2:
779
+ model_description_md += "\n"
780
+ ct += 1
781
+ return model_description_md
782
+
783
+
784
+ def build_about():
785
+ about_markdown = """
786
+ # About Us
787
+ Chatbot Arena is an open-source research project developed by members from [LMSYS](https://lmsys.org) and UC Berkeley [SkyLab](https://sky.cs.berkeley.edu/). Our mission is to build an open platform to evaluate LLMs by human preference in the real-world.
788
+ We open-source our [FastChat](https://github.com/lm-sys/FastChat) project at GitHub and release chat and human feedback dataset. We invite everyone to join us!
789
+
790
+ ## Open-source contributors
791
+ - [Wei-Lin Chiang](https://infwinston.github.io/), [Lianmin Zheng](https://lmzheng.net/), [Ying Sheng](https://sites.google.com/view/yingsheng/home), [Lisa Dunlap](https://www.lisabdunlap.com/), [Anastasios Angelopoulos](https://people.eecs.berkeley.edu/~angelopoulos/), [Christopher Chou](https://www.linkedin.com/in/chrisychou), [Tianle Li](https://codingwithtim.github.io/), [Siyuan Zhuang](https://www.linkedin.com/in/siyuanzhuang)
792
+ - Advisors: [Ion Stoica](http://people.eecs.berkeley.edu/~istoica/), [Joseph E. Gonzalez](https://people.eecs.berkeley.edu/~jegonzal/), [Hao Zhang](https://cseweb.ucsd.edu/~haozhang/), [Trevor Darrell](https://people.eecs.berkeley.edu/~trevor/)
793
+
794
+ ## Learn more
795
+ - Chatbot Arena [paper](https://arxiv.org/abs/2403.04132), [launch blog](https://lmsys.org/blog/2023-05-03-arena/), [dataset](https://github.com/lm-sys/FastChat/blob/main/docs/dataset_release.md), [policy](https://lmsys.org/blog/2024-03-01-policy/)
796
+ - LMSYS-Chat-1M dataset [paper](https://arxiv.org/abs/2309.11998), LLM Judge [paper](https://arxiv.org/abs/2306.05685)
797
+
798
+ ## Contact Us
799
+ - Follow our [X](https://x.com/lmsysorg), [Discord](https://discord.gg/HSWAKCrnFx) or email us at [email protected]
800
+ - File issues on [GitHub](https://github.com/lm-sys/FastChat)
801
+ - Download our datasets and models on [HuggingFace](https://huggingface.co/lmsys)
802
+
803
+ ## Acknowledgment
804
+ We thank [SkyPilot](https://github.com/skypilot-org/skypilot) and [Gradio](https://github.com/gradio-app/gradio) team for their system support.
805
+ We also thank [UC Berkeley SkyLab](https://sky.cs.berkeley.edu/), [Kaggle](https://www.kaggle.com/), [MBZUAI](https://mbzuai.ac.ae/), [a16z](https://www.a16z.com/), [Together AI](https://www.together.ai/), [Hyperbolic](https://hyperbolic.xyz/), [RunPod](https://runpod.io), [Anyscale](https://www.anyscale.com/), [HuggingFace](https://huggingface.co/) for their generous sponsorship. Learn more about partnership [here](https://lmsys.org/donations/).
806
+
807
+ <div class="sponsor-image-about">
808
+ <img src="https://storage.googleapis.com/public-arena-asset/skylab.png" alt="SkyLab">
809
+ <img src="https://storage.googleapis.com/public-arena-asset/kaggle.png" alt="Kaggle">
810
+ <img src="https://storage.googleapis.com/public-arena-asset/mbzuai.jpeg" alt="MBZUAI">
811
+ <img src="https://storage.googleapis.com/public-arena-asset/a16z.jpeg" alt="a16z">
812
+ <img src="https://storage.googleapis.com/public-arena-asset/together.png" alt="Together AI">
813
+ <img src="https://storage.googleapis.com/public-arena-asset/hyperbolic_logo.png" alt="Hyperbolic">
814
+ <img src="https://storage.googleapis.com/public-arena-asset/runpod-logo.jpg" alt="RunPod">
815
+ <img src="https://storage.googleapis.com/public-arena-asset/anyscale.png" alt="AnyScale">
816
+ <img src="https://storage.googleapis.com/public-arena-asset/huggingface.png" alt="HuggingFace">
817
+ </div>
818
+ """
819
+ gr.Markdown(about_markdown, elem_id="about_markdown")
820
+
821
+
822
+ def build_single_model_ui(models, add_promotion_links=False):
823
+ promotion = (
824
+ f"""
825
+ [Blog](https://lmsys.org/blog/2023-05-03-arena/) | [GitHub](https://github.com/lm-sys/FastChat) | [Paper](https://arxiv.org/abs/2403.04132) | [Dataset](https://github.com/lm-sys/FastChat/blob/main/docs/dataset_release.md) | [Twitter](https://twitter.com/lmsysorg) | [Discord](https://discord.gg/HSWAKCrnFx) | [Kaggle Competition](https://www.kaggle.com/competitions/lmsys-chatbot-arena)
826
+
827
+ {SURVEY_LINK}
828
+
829
+ ## πŸ‘‡ Choose any model to chat
830
+ """
831
+ if add_promotion_links
832
+ else ""
833
+ )
834
+
835
+ notice_markdown = f"""
836
+ # πŸ”οΈ Chat with Large Language Models
837
+ {promotion}
838
+ """
839
+
840
+ state = gr.State()
841
+ gr.Markdown(notice_markdown, elem_id="notice_markdown")
842
+
843
+ with gr.Group(elem_id="share-region-named"):
844
+ with gr.Row(elem_id="model_selector_row_3"):
845
+ language_selector = gr.Dropdown(
846
+ choices=LANGUAGES,
847
+ value='en',
848
+ interactive=True,
849
+ label="Language",
850
+ )
851
+ with gr.Row(elem_id="model_selector_row_2"):
852
+ task_selector = gr.Dropdown(
853
+ choices=TASKS,
854
+ value=TASKS[0] if len(TASKS) > 0 else "",
855
+ interactive=True,
856
+ label="Task",
857
+ )
858
+ with gr.Row(elem_id="model_selector_row"):
859
+ model_selector = gr.Dropdown(
860
+ choices=models,
861
+ value=models[0] if len(models) > 0 else "",
862
+ interactive=True,
863
+ label="Model",
864
+ )
865
+ with gr.Row():
866
+ with gr.Accordion(
867
+ f"πŸ” Expand to see the descriptions of {len(models)} models",
868
+ open=False,
869
+ ):
870
+ model_description_md = get_model_description_md(models)
871
+ gr.Markdown(model_description_md, elem_id="model_description_markdown")
872
+ with gr.Row():
873
+ system_prompt = gr.Textbox(
874
+ show_label=False,
875
+ placeholder="πŸ‘‰ Enter your system prompt",
876
+ elem_id="input_box_3",
877
+ )
878
+ chatbot = gr.Chatbot(
879
+ elem_id="chatbot",
880
+ label="Scroll down and start chatting",
881
+ height=650,
882
+ show_copy_button=True
883
+ )
884
+ with gr.Row():
885
+ textbox = gr.Textbox(
886
+ show_label=False,
887
+ placeholder="πŸ‘‰ Enter your prompt and press ENTER",
888
+ elem_id="input_box",
889
+ )
890
+ send_btn = gr.Button(value="Send", variant="primary", scale=0)
891
+
892
+ with gr.Row() as button_row:
893
+ upvote_btn = gr.Button(value="πŸ‘ Upvote", interactive=False)
894
+ downvote_btn = gr.Button(value="πŸ‘Ž Downvote", interactive=False)
895
+ flag_btn = gr.Button(value="⚠️ Flag", interactive=False)
896
+ regenerate_btn = gr.Button(value="πŸ”„ Regenerate", interactive=False)
897
+ clear_btn = gr.Button(value="πŸ—‘οΈ Clear history", interactive=False)
898
+
899
+ with gr.Row():
900
+ rewrite_textbox = gr.Textbox(
901
+ show_label=False,
902
+ placeholder="πŸ‘‰ Enter your recommended answer and press Downvote",
903
+ elem_id="input_box_2"
904
+ )
905
+
906
+ with gr.Accordion("Parameters", open=False) as parameter_row:
907
+ temperature = gr.Slider(
908
+ minimum=0.0,
909
+ maximum=1.0,
910
+ value=0.7,
911
+ step=0.1,
912
+ interactive=True,
913
+ label="Temperature",
914
+ )
915
+ top_p = gr.Slider(
916
+ minimum=0.0,
917
+ maximum=1.0,
918
+ value=1.0,
919
+ step=0.1,
920
+ interactive=True,
921
+ label="Top P",
922
+ )
923
+ max_output_tokens = gr.Slider(
924
+ minimum=16,
925
+ maximum=2048,
926
+ value=1024,
927
+ step=64,
928
+ interactive=True,
929
+ label="Max output tokens",
930
+ )
931
+
932
+ if add_promotion_links:
933
+ gr.Markdown(acknowledgment_md, elem_id="ack_markdown")
934
+
935
+ # Register listeners
936
+ btn_list = [upvote_btn, downvote_btn, flag_btn, regenerate_btn, clear_btn]
937
+ upvote_btn.click(
938
+ upvote_last_response,
939
+ [state, model_selector, task_selector, language_selector],
940
+ [textbox, upvote_btn, downvote_btn, flag_btn],
941
+ )
942
+ downvote_btn.click(
943
+ downvote_last_response,
944
+ [state, model_selector, task_selector, language_selector, rewrite_textbox],
945
+ [textbox, rewrite_textbox, upvote_btn, downvote_btn, flag_btn],
946
+ )
947
+ flag_btn.click(
948
+ flag_last_response,
949
+ [state, model_selector, task_selector, language_selector],
950
+ [textbox, upvote_btn, downvote_btn, flag_btn],
951
+ )
952
+ regenerate_btn.click(regenerate, state, [state, chatbot, textbox] + btn_list).then(
953
+ bot_response,
954
+ [state, temperature, top_p, max_output_tokens],
955
+ [state, chatbot] + btn_list,
956
+ )
957
+ clear_btn.click(clear_history, None, [state, chatbot, textbox] + btn_list)
958
+
959
+ model_selector.change(clear_history, None, [state, chatbot, textbox] + btn_list)
960
+ language_selector.change(clear_history, None, [state, chatbot, textbox] + btn_list)
961
+ task_selector.change(clear_history, None, [state, chatbot, textbox] + btn_list)
962
+
963
+ textbox.submit(
964
+ add_text,
965
+ [state, model_selector, task_selector, language_selector, system_prompt, textbox],
966
+ [state, chatbot, textbox] + btn_list,
967
+ ).then(
968
+ bot_response,
969
+ [state, temperature, top_p, max_output_tokens],
970
+ [state, chatbot] + btn_list,
971
+ )
972
+ send_btn.click(
973
+ add_text,
974
+ [state, model_selector, task_selector, language_selector, system_prompt, textbox],
975
+ [state, chatbot, textbox] + btn_list,
976
+ ).then(
977
+ bot_response,
978
+ [state, temperature, top_p, max_output_tokens],
979
+ [state, chatbot] + btn_list,
980
+ )
981
+
982
+ return [state, model_selector]
983
+
984
+
985
+ def build_demo(models):
986
+ with gr.Blocks(
987
+ title="Chat with Open Large Language Models",
988
+ theme=gr.themes.Default(),
989
+ css=block_css,
990
+ ) as demo:
991
+ url_params = gr.JSON(visible=False)
992
+
993
+ state, model_selector = build_single_model_ui(models)
994
+
995
+ if args.model_list_mode not in ["once", "reload"]:
996
+ raise ValueError(f"Unknown model list mode: {args.model_list_mode}")
997
+
998
+ if args.show_terms_of_use:
999
+ load_js = get_window_url_params_with_tos_js
1000
+ else:
1001
+ load_js = get_window_url_params_js
1002
+
1003
+ demo.load(
1004
+ load_demo,
1005
+ [url_params],
1006
+ [
1007
+ state,
1008
+ model_selector,
1009
+ ],
1010
+ js=load_js,
1011
+ )
1012
+
1013
+ return demo
1014
+
1015
+
1016
+ if __name__ == "__main__":
1017
+ parser = argparse.ArgumentParser()
1018
+ parser.add_argument("--host", type=str, default="0.0.0.0")
1019
+ parser.add_argument("--port", type=int)
1020
+ parser.add_argument(
1021
+ "--share",
1022
+ action="store_true",
1023
+ help="Whether to generate a public, shareable link",
1024
+ )
1025
+ parser.add_argument(
1026
+ "--controller-url",
1027
+ type=str,
1028
+ default="http://localhost:21001",
1029
+ help="The address of the controller",
1030
+ )
1031
+ parser.add_argument(
1032
+ "--concurrency-count",
1033
+ type=int,
1034
+ default=10,
1035
+ help="The concurrency count of the gradio queue",
1036
+ )
1037
+ parser.add_argument(
1038
+ "--model-list-mode",
1039
+ type=str,
1040
+ default="once",
1041
+ choices=["once", "reload"],
1042
+ help="Whether to load the model list once or reload the model list every time",
1043
+ )
1044
+ parser.add_argument(
1045
+ "--moderate",
1046
+ action="store_true",
1047
+ help="Enable content moderation to block unsafe inputs",
1048
+ )
1049
+ parser.add_argument(
1050
+ "--show-terms-of-use",
1051
+ action="store_true",
1052
+ help="Shows term of use before loading the demo",
1053
+ )
1054
+ parser.add_argument(
1055
+ "--register-api-endpoint-file",
1056
+ type=str,
1057
+ help="Register API-based model endpoints from a JSON file",
1058
+ )
1059
+ parser.add_argument(
1060
+ "--gradio-auth-path",
1061
+ type=str,
1062
+ help='Set the gradio authentication file path. The file should contain one or more user:password pairs in this format: "u1:p1,u2:p2,u3:p3"',
1063
+ )
1064
+ parser.add_argument(
1065
+ "--gradio-root-path",
1066
+ type=str,
1067
+ help="Sets the gradio root path, eg /abc/def. Useful when running behind a reverse-proxy or at a custom URL path prefix",
1068
+ )
1069
+ parser.add_argument(
1070
+ "--use-remote-storage",
1071
+ action="store_true",
1072
+ default=False,
1073
+ help="Uploads image files to google cloud storage if set to true",
1074
+ )
1075
+ args = parser.parse_args()
1076
+ logger.info(f"args: {args}")
1077
+
1078
+ # Set global variables
1079
+ set_global_vars(args.controller_url, args.moderate, args.use_remote_storage)
1080
+ models, all_models = get_model_list(
1081
+ args.controller_url, args.register_api_endpoint_file, vision_arena=False
1082
+ )
1083
+
1084
+ # Set authorization credentials
1085
+ auth = None
1086
+ if args.gradio_auth_path is not None:
1087
+ auth = parse_gradio_auth_creds(args.gradio_auth_path)
1088
+
1089
+ # Launch the demo
1090
+ demo = build_demo(models)
1091
+ demo.queue(
1092
+ default_concurrency_limit=args.concurrency_count,
1093
+ status_update_rate=10,
1094
+ api_open=False,
1095
+ ).launch(
1096
+ server_name=args.host,
1097
+ server_port=args.port,
1098
+ share=args.share,
1099
+ max_threads=200,
1100
+ auth=auth,
1101
+ root_path=args.gradio_root_path,
1102
+ )