bnitokyo/InternVL
0
1import argparse2from ast import parse3import datetime4import json5import os6import time7import hashlib8import re9 10import gradio as gr11import requests12import random13from filelock import FileLock14from io import BytesIO15from PIL import Image, ImageDraw, ImageFont16 17from constants import LOGDIR18from utils import (19 build_logger,20 server_error_msg,21 violates_moderation,22 moderation_msg,23 load_image_from_base64,24 get_log_filename,25)26from conversation import Conversation27 28logger = build_logger("gradio_web_server", "gradio_web_server.log")29 30headers = {"User-Agent": "InternVL-Chat Client"}31 32no_change_btn = gr.Button()33enable_btn = gr.Button(interactive=True)34disable_btn = gr.Button(interactive=False)35 36 37def write2file(path, content):38 lock = FileLock(f"{path}.lock")39 with lock:40 with open(path, "a") as fout:41 fout.write(content)42 43 44def sort_models(models):45 def custom_sort_key(model_name):46 # InternVL-Chat-V1-5 should be the first item47 if model_name == "InternVL-Chat-V1-5":48 return (1, model_name) # 1 indicates highest precedence49 elif model_name.startswith("InternVL-Chat-V1-5-"):50 return (1, model_name) # 1 indicates highest precedence51 else:52 return (0, model_name) # 0 indicates normal order53 54 models.sort(key=custom_sort_key, reverse=True)55 try: # We have five InternVL-Chat-V1-5 models, randomly choose one to be the first56 first_three = models[:4]57 random.shuffle(first_three)58 models[:4] = first_three59 except:60 pass61 return models62 63 64def get_model_list():65 logger.info(f"Call `get_model_list`")66 ret = requests.post(args.controller_url + "/refresh_all_workers")67 logger.info(f"status_code from `get_model_list`: {ret.status_code}")68 assert ret.status_code == 20069 ret = requests.post(args.controller_url + "/list_models")70 logger.info(f"status_code from `list_models`: {ret.status_code}")71 models = ret.json()["models"]72 models = sort_models(models)73 74 logger.info(f"Models (from {args.controller_url}): {models}")75 return models76 77 78get_window_url_params = """79function() {80 const params = new URLSearchParams(window.location.search);81 url_params = Object.fromEntries(params);82 console.log(url_params);83 return url_params;84 }85"""86 87 88def init_state(state=None):89 if state is not None:90 del state91 return Conversation()92 93 94def find_bounding_boxes(state, response):95 pattern = re.compile(r"<ref>\s*(.*?)\s*</ref>\s*<box>\s*(\[\[.*?\]\])\s*</box>")96 matches = pattern.findall(response)97 results = []98 for match in matches:99 results.append((match[0], eval(match[1])))100 returned_image = None101 latest_image = state.get_images(source=state.USER)[-1]102 returned_image = latest_image.copy()103 width, height = returned_image.size104 draw = ImageDraw.Draw(returned_image)105 for result in results:106 line_width = max(1, int(min(width, height) / 200))107 random_color = (108 random.randint(0, 128),109 random.randint(0, 128),110 random.randint(0, 128),111 )112 category_name, coordinates = result113 coordinates = [114 (115 float(x[0]) / 1000,116 float(x[1]) / 1000,117 float(x[2]) / 1000,118 float(x[3]) / 1000,119 )120 for x in coordinates121 ]122 coordinates = [123 (124 int(x[0] * width),125 int(x[1] * height),126 int(x[2] * width),127 int(x[3] * height),128 )129 for x in coordinates130 ]131 for box in coordinates:132 draw.rectangle(box, outline=random_color, width=line_width)133 font = ImageFont.truetype("assets/SimHei.ttf", int(20 * line_width / 2))134 text_size = font.getbbox(category_name)135 text_width, text_height = (136 text_size[2] - text_size[0],137 text_size[3] - text_size[1],138 )139 text_position = (box[0], max(0, box[1] - text_height))140 draw.rectangle(141 [142 text_position,143 (text_position[0] + text_width, text_position[1] + text_height),144 ],145 fill=random_color,146 )147 draw.text(text_position, category_name, fill="white", font=font)148 return returned_image if len(matches) > 0 else None149 150 151def query_image_generation(response, sd_worker_url, timeout=15):152 if not sd_worker_url:153 return None154 sd_worker_url = f"{sd_worker_url}/generate_image/"155 pattern = r"```drawing-instruction\n(.*?)\n```"156 match = re.search(pattern, response, re.DOTALL)157 if match:158 payload = {"caption": match.group(1)}159 print("drawing-instruction:", payload)160 response = requests.post(sd_worker_url, json=payload, timeout=timeout)161 response.raise_for_status() # 检查HTTP请求是否成功162 image = Image.open(BytesIO(response.content))163 return image164 else:165 return None166 167 168def load_demo(url_params, request: gr.Request = None):169 if not request:170 logger.info(f"load_demo. ip: {request.client.host}. params: {url_params}")171 172 dropdown_update = gr.Dropdown(visible=True)173 if "model" in url_params:174 model = url_params["model"]175 if model in models:176 dropdown_update = gr.Dropdown(value=model, visible=True)177 178 state = init_state()179 return state, dropdown_update180 181 182def load_demo_refresh_model_list(request: gr.Request = None):183 if not request:184 logger.info(f"load_demo. ip: {request.client.host}")185 models = get_model_list()186 state = init_state()187 dropdown_update = gr.Dropdown(188 choices=models, value=models[0] if len(models) > 0 else ""189 )190 return state, dropdown_update191 192 193def vote_last_response(state, liked, model_selector, request: gr.Request):194 conv_data = {195 "tstamp": round(time.time(), 4),196 "like": liked,197 "model": model_selector,198 "state": state.dict(),199 "ip": request.client.host,200 }201 write2file(get_log_filename(), json.dumps(conv_data) + "\n")202 203 204def upvote_last_response(state, model_selector, request: gr.Request):205 logger.info(f"upvote. ip: {request.client.host}")206 vote_last_response(state, True, model_selector, request)207 textbox = gr.MultimodalTextbox(value=None, interactive=True)208 return (textbox,) + (disable_btn,) * 3209 210 211def downvote_last_response(state, model_selector, request: gr.Request):212 logger.info(f"downvote. ip: {request.client.host}")213 vote_last_response(state, False, model_selector, request)214 textbox = gr.MultimodalTextbox(value=None, interactive=True)215 return (textbox,) + (disable_btn,) * 3216 217 218def vote_selected_response(219 state, model_selector, request: gr.Request, data: gr.LikeData220):221 logger.info(222 f"Vote: {data.liked}, index: {data.index}, value: {data.value} , ip: {request.client.host}"223 )224 conv_data = {225 "tstamp": round(time.time(), 4),226 "like": data.liked,227 "index": data.index,228 "model": model_selector,229 "state": state.dict(),230 "ip": request.client.host,231 }232 write2file(get_log_filename(), json.dumps(conv_data) + "\n")233 return234 235 236def flag_last_response(state, model_selector, request: gr.Request):237 logger.info(f"flag. ip: {request.client.host}")238 vote_last_response(state, "flag", model_selector, request)239 textbox = gr.MultimodalTextbox(value=None, interactive=True)240 return (textbox,) + (disable_btn,) * 3241 242 243def regenerate(state, image_process_mode, request: gr.Request):244 logger.info(f"regenerate. ip: {request.client.host}")245 # state.messages[-1][-1] = None246 state.update_message(Conversation.ASSISTANT, None, -1)247 prev_human_msg = state.messages[-2]248 if type(prev_human_msg[1]) in (tuple, list):249 prev_human_msg[1] = (*prev_human_msg[1][:2], image_process_mode)250 state.skip_next = False251 textbox = gr.MultimodalTextbox(value=None, interactive=True)252 return (state, state.to_gradio_chatbot(), textbox) + (disable_btn,) * 5253 254 255def clear_history(request: gr.Request):256 logger.info(f"clear_history. ip: {request.client.host}")257 state = init_state()258 textbox = gr.MultimodalTextbox(value=None, interactive=True)259 return (state, state.to_gradio_chatbot(), textbox) + (disable_btn,) * 5260 261 262def change_system_prompt(state, system_prompt, request: gr.Request):263 logger.info(f"Change system prompt. ip: {request.client.host}")264 state.set_system_message(system_prompt)265 return state266 267 268def add_text(state, message, system_prompt, model_selector, request: gr.Request):269 print(f"state: {state}")270 if not state:271 state, model_selector = load_demo_refresh_model_list(request)272 images = message.get("files", [])273 text = message.get("text", "").strip()274 logger.info(f"add_text. ip: {request.client.host}. len: {len(text)}")275 # import pdb; pdb.set_trace()276 textbox = gr.MultimodalTextbox(value=None, interactive=False)277 if len(text) <= 0 and len(images) == 0:278 state.skip_next = True279 return (state, state.to_gradio_chatbot(), textbox) + (no_change_btn,) * 5280 if args.moderate:281 flagged = violates_moderation(text)282 if flagged:283 state.skip_next = True284 textbox = gr.MultimodalTextbox(285 value={"text": moderation_msg}, interactive=True286 )287 return (state, state.to_gradio_chatbot(), textbox) + (no_change_btn,) * 5288 images = [Image.open(path).convert("RGB") for path in images]289 290 if len(images) > 0 and len(state.get_images(source=state.USER)) > 0:291 state = init_state(state)292 state.set_system_message(system_prompt)293 state.append_message(Conversation.USER, text, images)294 state.skip_next = False295 return (state, state.to_gradio_chatbot(), textbox, model_selector) + (296 disable_btn,297 ) * 5298 299 300def http_bot(301 state,302 model_selector,303 temperature,304 top_p,305 repetition_penalty,306 max_new_tokens,307 max_input_tiles,308 # bbox_threshold,309 # mask_threshold,310 request: gr.Request,311):312 logger.info(f"http_bot. ip: {request.client.host}")313 start_tstamp = time.time()314 model_name = model_selector315 if hasattr(state, "skip_next") and state.skip_next:316 # This generate call is skipped due to invalid inputs317 yield (318 state,319 state.to_gradio_chatbot(),320 gr.MultimodalTextbox(interactive=False),321 ) + (no_change_btn,) * 5322 return323 324 # Query worker address325 controller_url = args.controller_url326 ret = requests.post(327 controller_url + "/get_worker_address", json={"model": model_name}328 )329 worker_addr = ret.json()["address"]330 logger.info(f"model_name: {model_name}, worker_addr: {worker_addr}")331 332 # No available worker333 if worker_addr == "":334 # state.messages[-1][-1] = server_error_msg335 state.update_message(Conversation.ASSISTANT, server_error_msg)336 yield (337 state,338 state.to_gradio_chatbot(),339 gr.MultimodalTextbox(interactive=False),340 disable_btn,341 disable_btn,342 disable_btn,343 enable_btn,344 enable_btn,345 )346 return347 348 all_images = state.get_images(source=state.USER)349 all_image_paths = [state.save_image(image) for image in all_images]350 351 # Make requests352 pload = {353 "model": model_name,354 "prompt": state.get_prompt(),355 "temperature": float(temperature),356 "top_p": float(top_p),357 "max_new_tokens": max_new_tokens,358 "max_input_tiles": max_input_tiles,359 # "bbox_threshold": bbox_threshold,360 # "mask_threshold": mask_threshold,361 "repetition_penalty": repetition_penalty,362 "images": f"List of {len(all_images)} images: {all_image_paths}",363 }364 logger.info(f"==== request ====\n{pload}")365 pload.pop("images")366 pload["prompt"] = state.get_prompt(inlude_image=True)367 state.append_message(Conversation.ASSISTANT, state.streaming_placeholder)368 yield (369 state,370 state.to_gradio_chatbot(),371 gr.MultimodalTextbox(interactive=False),372 ) + (disable_btn,) * 5373 374 try:375 # Stream output376 response = requests.post(377 worker_addr + "/worker_generate_stream",378 headers=headers,379 json=pload,380 stream=True,381 timeout=20,382 )383 for chunk in response.iter_lines(decode_unicode=False, delimiter=b"\0"):384 if chunk:385 data = json.loads(chunk.decode())386 if data["error_code"] == 0:387 if "text" in data:388 output = data["text"].strip()389 output += state.streaming_placeholder390 391 image = None392 if "image" in data:393 image = load_image_from_base64(data["image"])394 _ = state.save_image(image)395 396 state.update_message(Conversation.ASSISTANT, output, image)397 yield (398 state,399 state.to_gradio_chatbot(),400 gr.MultimodalTextbox(interactive=False),401 ) + (disable_btn,) * 5402 else:403 output = (404 f"**{data['text']}**" + f" (error_code: {data['error_code']})"405 )406 407 state.update_message(Conversation.ASSISTANT, output, None)408 yield (409 state,410 state.to_gradio_chatbot(),411 gr.MultimodalTextbox(interactive=True),412 ) + (413 disable_btn,414 disable_btn,415 disable_btn,416 enable_btn,417 enable_btn,418 )419 return420 except requests.exceptions.RequestException as e:421 state.update_message(Conversation.ASSISTANT, server_error_msg, None)422 yield (423 state,424 state.to_gradio_chatbot(),425 gr.MultimodalTextbox(interactive=True),426 ) + (427 disable_btn,428 disable_btn,429 disable_btn,430 enable_btn,431 enable_btn,432 )433 return434 435 ai_response = state.return_last_message()436 if "<ref>" in ai_response:437 returned_image = find_bounding_boxes(state, ai_response)438 returned_image = [returned_image] if returned_image else []439 state.update_message(Conversation.ASSISTANT, ai_response, returned_image)440 if "```drawing-instruction" in ai_response:441 returned_image = query_image_generation(442 ai_response, sd_worker_url=sd_worker_url443 )444 returned_image = [returned_image] if returned_image else []445 state.update_message(Conversation.ASSISTANT, ai_response, returned_image)446 447 state.end_of_current_turn()448 449 yield (450 state,451 state.to_gradio_chatbot(),452 gr.MultimodalTextbox(interactive=True),453 ) + (enable_btn,) * 5454 455 finish_tstamp = time.time()456 logger.info(f"{output}")457 data = {458 "tstamp": round(finish_tstamp, 4),459 "like": None,460 "model": model_name,461 "start": round(start_tstamp, 4),462 "finish": round(start_tstamp, 4),463 "state": state.dict(),464 "images": all_image_paths,465 "ip": request.client.host,466 }467 write2file(get_log_filename(), json.dumps(data) + "\n")468 469 470title_html = """471<h2> <span class="gradient-text" id="text">InternVL2</span><span class="plain-text">: Better than the Best—Expanding Performance Boundaries of Open-Source Multimodal Models with the Progressive Scaling Strategy</span></h2>472<a href="https://internvl.github.io/blog/2024-07-02-InternVL-2.0/">[📜 InternVL2 Blog]</a> 473<a href="https://huggingface.co/spaces/OpenGVLab/InternVL">[🤗 HF Demo]</a> 474<a href="https://github.com/OpenGVLab/InternVL?tab=readme-ov-file#quick-start-with-huggingface">[🚀 Quick Start]</a> 475<a href="https://github.com/OpenGVLab/InternVL/blob/main/document/How_to_use_InternVL_API.md">[🌐 API]</a> 476"""477 478tos_markdown = """479### Terms of use480By using this service, users are required to agree to the following terms:481The service is a research preview intended for non-commercial use only. It only provides limited safety measures and may generate offensive content. It must not be used for any illegal, harmful, violent, racist, or sexual purposes. The service may collect user dialogue data for future research.482Please click the "Flag" button if you get any inappropriate answer! We will collect those to keep improving our moderator.483For an optimal experience, please use desktop computers for this demo, as mobile devices may compromise its quality.484"""485 486 487learn_more_markdown = """488### License489The service is a research preview intended for non-commercial use only, subject to the model [License](https://github.com/facebookresearch/llama/blob/main/MODEL_CARD.md) of LLaMA, [Terms of Use](https://openai.com/policies/terms-of-use) of the data generated by OpenAI, and [Privacy Practices](https://chrome.google.com/webstore/detail/sharegpt-share-your-chatg/daiacboceoaocpibfodeljbdfacokfjb) of ShareGPT. Please contact us if you find any potential violation.490 491### Acknowledgement492This demo is modified from LLaVA's demo. Thanks for their awesome work!493"""494# .gradio-container {margin: 5px 10px 0 10px !important};495block_css = """496.gradio-container {margin: 0.1% 1% 0 1% !important; max-width: 98% !important;};497#buttons button {498 min-width: min(120px,100%);499}500 501.gradient-text {502 font-size: 28px;503 width: auto;504 font-weight: bold;505 background: linear-gradient(45deg, red, orange, yellow, green, blue, indigo, violet);506 background-clip: text;507 -webkit-background-clip: text;508 color: transparent;509}510 511.plain-text {512 font-size: 22px;513 width: auto;514 font-weight: bold;515}516"""517 518js = """519function createWaveAnimation() {520 const text = document.getElementById('text');521 var i = 0;522 setInterval(function() {523 const colors = [524 'red, orange, yellow, green, blue, indigo, violet, purple',525 'orange, yellow, green, blue, indigo, violet, purple, red',526 'yellow, green, blue, indigo, violet, purple, red, orange',527 'green, blue, indigo, violet, purple, red, orange, yellow',528 'blue, indigo, violet, purple, red, orange, yellow, green',529 'indigo, violet, purple, red, orange, yellow, green, blue',530 'violet, purple, red, orange, yellow, green, blue, indigo',531 'purple, red, orange, yellow, green, blue, indigo, violet',532 ];533 const angle = 45;534 const colorIndex = i % colors.length;535 text.style.background = `linear-gradient(${angle}deg, ${colors[colorIndex]})`;536 text.style.webkitBackgroundClip = 'text';537 text.style.backgroundClip = 'text';538 text.style.color = 'transparent';539 text.style.fontSize = '28px';540 text.style.width = 'auto';541 text.textContent = 'InternVL2';542 text.style.fontWeight = 'bold';543 i += 1;544 }, 200);545 const params = new URLSearchParams(window.location.search);546 url_params = Object.fromEntries(params);547 // console.log(url_params);548 // console.log('hello world...');549 // console.log(window.location.search);550 // console.log('hello world...');551 // alert(window.location.search)552 // alert(url_params);553 return url_params;554}555 556"""557 558 559def build_demo(embed_mode):560 textbox = gr.MultimodalTextbox(561 interactive=True,562 file_types=["image", "video"],563 placeholder="Enter message or upload file...",564 show_label=False,565 )566 567 with gr.Blocks(568 title="InternVL-Chat",569 theme=gr.themes.Default(),570 css=block_css,571 ) as demo:572 state = gr.State()573 574 if not embed_mode:575 # gr.Markdown(title_markdown)576 gr.HTML(title_html)577 578 with gr.Row():579 with gr.Column(scale=2):580 581 with gr.Row(elem_id="model_selector_row"):582 model_selector = gr.Dropdown(583 choices=models,584 value=models[0] if len(models) > 0 else "",585 # value="InternVL-Chat-V1-5",586 interactive=True,587 show_label=False,588 container=False,589 )590 591 with gr.Accordion("System Prompt", open=False) as system_prompt_row:592 system_prompt = gr.Textbox(593 value="请尽可能详细地回答用户的问题。",594 label="System Prompt",595 interactive=True,596 )597 with gr.Accordion("Parameters", open=False) as parameter_row:598 temperature = gr.Slider(599 minimum=0.0,600 maximum=1.0,601 value=0.2,602 step=0.1,603 interactive=True,604 label="Temperature",605 )606 top_p = gr.Slider(607 minimum=0.0,608 maximum=1.0,609 value=0.7,610 step=0.1,611 interactive=True,612 label="Top P",613 )614 repetition_penalty = gr.Slider(615 minimum=1.0,616 maximum=1.5,617 value=1.1,618 step=0.02,619 interactive=True,620 label="Repetition penalty",621 )622 max_output_tokens = gr.Slider(623 minimum=0,624 maximum=4096,625 value=1024,626 step=64,627 interactive=True,628 label="Max output tokens",629 )630 max_input_tiles = gr.Slider(631 minimum=1,632 maximum=32,633 value=12,634 step=1,635 interactive=True,636 label="Max input tiles (control the image size)",637 )638 examples = gr.Examples(639 examples=[640 [641 {642 "files": [643 "gallery/prod_9.jpg",644 ],645 "text": "What's at the far end of the image?",646 }647 ],648 [649 {650 "files": [651 "gallery/astro_on_unicorn.png",652 ],653 "text": "What does this image mean?",654 }655 ],656 [657 {658 "files": [659 "gallery/prod_12.png",660 ],661 "text": "What are the consequences of the easy decisions shown in this image?",662 }663 ],664 [665 {666 "files": [667 "gallery/child_1.jpg",668 "gallery/child_2.jpg",669 f"gallery/child_3.jpg",670 ],671 "text": "这三帧图片讲述了一件什么事情?",672 }673 ],674 ],675 inputs=[textbox],676 )677 678 with gr.Column(scale=8):679 chatbot = gr.Chatbot(680 elem_id="chatbot",681 label="InternVL2",682 height=580,683 show_copy_button=True,684 show_share_button=True,685 avatar_images=[686 "assets/human.png",687 "assets/assistant.png",688 ],689 bubble_full_width=False,690 )691 with gr.Row():692 with gr.Column(scale=8):693 textbox.render()694 with gr.Column(scale=1, min_width=50):695 submit_btn = gr.Button(value="Send", variant="primary")696 with gr.Row(elem_id="buttons") as button_row:697 upvote_btn = gr.Button(value="👍 Upvote", interactive=False)698 downvote_btn = gr.Button(value="👎 Downvote", interactive=False)699 flag_btn = gr.Button(value="⚠️ Flag", interactive=False)700 # stop_btn = gr.Button(value="⏹️ Stop Generation", interactive=False)701 regenerate_btn = gr.Button(702 value="🔄 Regenerate", interactive=False703 )704 clear_btn = gr.Button(value="🗑️ Clear", interactive=False)705 706 if not embed_mode:707 gr.Markdown(tos_markdown)708 gr.Markdown(learn_more_markdown)709 url_params = gr.JSON(visible=False)710 711 # Register listeners712 btn_list = [upvote_btn, downvote_btn, flag_btn, regenerate_btn, clear_btn]713 upvote_btn.click(714 upvote_last_response,715 [state, model_selector],716 [textbox, upvote_btn, downvote_btn, flag_btn],717 )718 downvote_btn.click(719 downvote_last_response,720 [state, model_selector],721 [textbox, upvote_btn, downvote_btn, flag_btn],722 )723 chatbot.like(724 vote_selected_response,725 [state, model_selector],726 [],727 )728 flag_btn.click(729 flag_last_response,730 [state, model_selector],731 [textbox, upvote_btn, downvote_btn, flag_btn],732 )733 regenerate_btn.click(734 regenerate,735 [state, system_prompt],736 [state, chatbot, textbox] + btn_list,737 ).then(738 http_bot,739 [740 state,741 model_selector,742 temperature,743 top_p,744 repetition_penalty,745 max_output_tokens,746 max_input_tiles,747 # bbox_threshold,748 # mask_threshold,749 ],750 [state, chatbot, textbox] + btn_list,751 )752 clear_btn.click(clear_history, None, [state, chatbot, textbox] + btn_list)753 754 textbox.submit(755 add_text,756 [state, textbox, system_prompt, model_selector],757 [state, chatbot, textbox, model_selector] + btn_list,758 ).then(759 http_bot,760 [761 state,762 model_selector,763 temperature,764 top_p,765 repetition_penalty,766 max_output_tokens,767 max_input_tiles,768 # bbox_threshold,769 # mask_threshold,770 ],771 [state, chatbot, textbox] + btn_list,772 )773 submit_btn.click(774 add_text,775 [state, textbox, system_prompt, model_selector],776 [state, chatbot, textbox, model_selector] + btn_list,777 ).then(778 http_bot,779 [780 state,781 model_selector,782 temperature,783 top_p,784 repetition_penalty,785 max_output_tokens,786 max_input_tiles,787 # bbox_threshold,788 # mask_threshold,789 ],790 [state, chatbot, textbox] + btn_list,791 )792 793 # NOTE: The following code will be not triggered when deployed on HF space.794 # It's very strange. I don't know why.795 """796 if args.model_list_mode == "once":797 demo.load(798 load_demo,799 [url_params],800 [state, model_selector],801 js=js,802 )803 elif args.model_list_mode == "reload":804 demo.load(805 load_demo_refresh_model_list,806 None,807 [state, model_selector],808 js=js,809 )810 else:811 raise ValueError(f"Unknown model list mode: {args.model_list_mode}")812 """813 814 return demo815 816 817if __name__ == "__main__":818 parser = argparse.ArgumentParser()819 parser.add_argument("--host", type=str, default="0.0.0.0")820 parser.add_argument("--port", type=int, default=7860)821 parser.add_argument("--controller-url", type=str, default=None)822 parser.add_argument("--concurrency-count", type=int, default=10)823 parser.add_argument(824 "--model-list-mode", type=str, default="reload", choices=["once", "reload"]825 )826 parser.add_argument("--sd-worker-url", type=str, default=None)827 parser.add_argument("--share", action="store_true")828 parser.add_argument("--moderate", action="store_true")829 parser.add_argument("--embed", action="store_true")830 args = parser.parse_args()831 logger.info(f"args: {args}")832 if not args.controller_url:833 args.controller_url = os.environ.get("CONTROLLER_URL", None)834 835 if not args.controller_url:836 raise ValueError("controller-url is required.")837 838 models = get_model_list()839 840 sd_worker_url = args.sd_worker_url841 logger.info(args)842 demo = build_demo(args.embed)843 demo.queue(api_open=False).launch(844 server_name=args.host,845 server_port=args.port,846 share=args.share,847 max_threads=args.concurrency_count,848 )849 