Coloring's picture
feat: pro components
2e77168
raw
history blame
8.26 kB
import base64
import os
import time
import gradio as gr
import modelscope_studio.components.antd as antd
import modelscope_studio.components.antdx as antdx
import modelscope_studio.components.base as ms
import modelscope_studio.components.pro as pro
from modelscope_studio.components.pro.chatbot import (ChatbotBotConfig,
ChatbotPromptsConfig,
ChatbotWelcomeConfig)
from modelscope_studio.components.pro.multimodal_input import \
MultimodalInputUploadConfig
from openai import OpenAI
client = OpenAI(
base_url='https://api-inference.modelscope.cn/v1/',
api_key=os.getenv("MODELSCOPE_API_KEY"), # ModelScope Token
)
model = "Qwen/Qwen2.5-VL-72B-Instruct"
def prompt_select(input_value, e: gr.EventData):
input_value["text"] = e._data["payload"][0]["value"]["description"]
return gr.update(value=input_value)
def clear():
return gr.update(value=None)
def cancel(chatbot_value):
chatbot_value[-1]["loading"] = False
chatbot_value[-1]["status"] = "done"
chatbot_value[-1]["footer"] = "Chat completion paused"
return gr.update(value=chatbot_value), gr.update(loading=False), gr.update(
disabled=False)
def retry(chatbot_value, e: gr.EventData):
index = e._data["payload"][0]["index"]
chatbot_value = chatbot_value[:index]
yield gr.update(loading=True), gr.update(value=chatbot_value), gr.update(
disabled=True)
for chunk in submit(None, chatbot_value):
yield chunk
def image_to_base64(image_path):
with open(image_path, "rb") as image_file:
encoded_string = base64.b64encode(image_file.read()).decode('utf-8')
return f"data:image/jpeg;base64,{encoded_string}"
def format_history(history):
messages = [{"role": "system", "content": "You are a helpful assistant."}]
for item in history:
if item["role"] == "user":
messages.append({
"role":
"user",
"content": [{
"type": "image_url",
"image_url": image_to_base64(file)
} for file in item["content"][0]["content"]
if os.path.exists(file)] +
[{
"type": "text",
"text": item["content"][1]["content"]
}]
})
elif item["role"] == "assistant":
# ignore thought message
messages.append({"role": "assistant", "content": item["content"]})
return messages
def submit(input_value, chatbot_value):
if input_value is not None:
chatbot_value.append({
"role":
"user",
"content": [{
"type": "file",
"content": [f for f in input_value["files"]]
}, {
"type": "text",
"content": input_value["text"]
}],
})
history_messages = format_history(chatbot_value)
chatbot_value.append({
"role": "assistant",
"content": "",
"loading": True,
"status": "pending"
})
yield {
input: gr.update(value=None, loading=True),
clear_btn: gr.update(disabled=True),
chatbot: gr.update(value=chatbot_value)
}
try:
response = client.chat.completions.create(model=model,
messages=history_messages,
stream=True)
start_time = time.time()
for chunk in response:
chatbot_value[-1]["content"] += chunk.choices[0].delta.content
chatbot_value[-1]["loading"] = False
yield {chatbot: gr.update(value=chatbot_value)}
chatbot_value[-1]["footer"] = "{:.2f}".format(time.time() -
start_time) + 's'
chatbot_value[-1]["status"] = "done"
yield {
clear_btn: gr.update(disabled=False),
input: gr.update(loading=False),
chatbot: gr.update(value=chatbot_value),
}
except Exception as e:
chatbot_value[-1]["loading"] = False
chatbot_value[-1]["status"] = "done"
chatbot_value[-1]["content"] = "Failed to respond, please try again."
yield {
clear_btn: gr.update(disabled=False),
input: gr.update(loading=False),
chatbot: gr.update(value=chatbot_value),
}
raise e
with gr.Blocks() as demo, ms.Application(), antdx.XProvider(), ms.AutoLoading(
):
with antd.Flex(vertical=True, gap="middle", elem_style=dict(height=800)):
chatbot = pro.Chatbot(
# for flex=1 to fill the remaining space
height=0,
elem_style=dict(flex=1),
welcome_config=ChatbotWelcomeConfig(
variant="borderless",
icon=
"https://assets.alicdn.com/g/qwenweb/qwen-webui-fe/0.0.44/static/favicon.png",
title=f"Hello, I'm {model}",
description="You can upload images and text to get started.",
prompts=ChatbotPromptsConfig(
title="How can I help you today?",
styles={
"list": {
"width": '100%',
},
"item": {
"flex": 1,
},
},
items=[{
"label":
"πŸ–‹ Make a plan",
"children": [{
"description":
"Help me with a plan to start a business"
}, {
"description":
"Help me with a plan to achieve my goals"
}, {
"description":
"Help me with a plan for a successful interview"
}]
}, {
"label":
"πŸ“… Help me write",
"children": [{
"description":
"Help me write a story with a twist ending"
}, {
"description":
"Help me write a blog post on mental health"
}, {
"description":
"Help me write a letter to my future self"
}]
}])),
user_config=dict(
avatar="https://api.dicebear.com/7.x/miniavs/svg?seed=3"),
bot_config=ChatbotBotConfig(
header=model,
actions=["copy", "retry"],
avatar=
"https://assets.alicdn.com/g/qwenweb/qwen-webui-fe/0.0.44/static/favicon.png"
),
)
with pro.MultimodalInput(upload_config=MultimodalInputUploadConfig(
max_count=4, multiple=True, accept="image/*")) as input:
with ms.Slot("prefix"):
with antd.Button(value=None, color="default",
variant="text") as clear_btn:
with ms.Slot("icon"):
antd.Icon("ClearOutlined")
clear_btn.click(fn=clear, outputs=[chatbot])
submit_event = input.submit(fn=submit,
inputs=[input, chatbot],
outputs=[input, chatbot, clear_btn])
input.cancel(fn=cancel,
inputs=[chatbot],
outputs=[chatbot, input, clear_btn],
cancels=[submit_event],
queue=False)
chatbot.retry(fn=retry,
inputs=[chatbot],
outputs=[input, chatbot, clear_btn])
chatbot.welcome_prompt_select(fn=prompt_select,
inputs=[input],
outputs=[input])
if __name__ == "__main__":
demo.queue().launch()