diff --git a/README.md b/README.md index 345d923..41ebb34 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ memory capabilities of Qwen. It also comes with example applications such as Browser Assistant, Code Interpreter, and Custom Assistant. # News +* Dec 3, 2024: Upgrade GUI to Gradio 5 based. Note: GUI requires Python 3.10 or higher. * 🔥🔥🔥 Sep 18, 2024: Added [Qwen2.5-Math Demo](./examples/tir_math.py) to showcase the Tool-Integrated Reasoning capabilities of Qwen2.5-Math. Note: The python executor is not sandboxed and is intended for local testing only, not for production use. # Getting Started diff --git a/README_CN.md b/README_CN.md index ec3500a..4caf68b 100644 --- a/README_CN.md +++ b/README_CN.md @@ -8,6 +8,7 @@ Qwen-Agent是一个开发框架。开发者可基于本框架开发Agent应用,充分利用基于通义千问模型(Qwen)的指令遵循、工具使用、规划、记忆能力。本项目也提供了浏览器助手、代码解释器、自定义助手等示例应用。 # 更新 +* Dec 3, 2024: GUI 升级为基于 Gradio 5。注意:如果需要使用GUI,Python版本需要3.10及以上。 * 🔥🔥🔥Sep 18, 2024: 新增[Qwen2.5-Math Demo](./examples/tir_math.py)以展示Qwen2.5-Math基于工具的推理能力。注意:代码执行工具未进行沙箱保护,仅适用于本地测试,不可用于生产。 # 开始上手 diff --git a/examples/group_chat_demo.py b/examples/group_chat_demo.py index ba9d738..cd0b284 100644 --- a/examples/group_chat_demo.py +++ b/examples/group_chat_demo.py @@ -5,7 +5,7 @@ from qwen_agent.agents import GroupChat, GroupChatCreator from qwen_agent.agents.user_agent import PENDING_USER_INPUT -from qwen_agent.gui.gradio import gr, mgr +from qwen_agent.gui.gradio_dep import gr, mgr, ms from qwen_agent.llm.schema import ContentItem, Message @@ -260,50 +260,50 @@ def add_text_create(history, text): 'Current GroupChat: (If editing, please maintain this JSON format)', value=json.dumps(CFGS, indent=4, ensure_ascii=False), interactive=True) - - with gr.Tab('Chat', elem_id='chat-tab'): - with gr.Column(): - chatbot = mgr.Chatbot(elem_id='chatbot', height=750, show_copy_button=True, flushing=False) - with gr.Row(): - with gr.Column(scale=3, min_width=0): - auto_speak_button = gr.Button('Randomly select an agent to speak first') - auto_speak_button.click(app, display_config, chatbot) - with gr.Column(scale=10): - chat_txt = gr.Textbox( - show_label=False, - placeholder='Chat with Qwen...', - container=False, - ) - with gr.Column(scale=1, min_width=0): - chat_clr_bt = gr.Button('Clear') - - chat_txt.submit(add_text, [chat_txt, display_config], [chatbot, chat_txt], - queue=False).then(app, display_config, chatbot) - - chat_clr_bt.click(chat_clear, None, [chatbot], queue=False) - - demo.load(chat_clear, None, [chatbot], queue=False) - - with gr.Tab('Create', elem_id='chat-tab'): - with gr.Column(scale=9, min_width=0): - chatbot = mgr.Chatbot(elem_id='chatbot0', height=750, show_copy_button=True, flushing=False) - with gr.Row(): - with gr.Column(scale=13): - chat_txt = gr.Textbox( - show_label=False, - placeholder='Chat with Qwen...', - container=False, - ) - with gr.Column(scale=1, min_width=0): - chat_clr_bt = gr.Button('Clear') - - txt_msg = chat_txt.submit(add_text_create, [chatbot, chat_txt], [chatbot, chat_txt], - queue=False).then(app_create, [chatbot, display_config], - [chatbot, display_config]) - txt_msg.then(lambda: gr.update(interactive=True), None, [chat_txt], queue=False) - - chat_clr_bt.click(chat_clear_create, None, [chatbot, chat_txt], queue=False) - demo.load(chat_clear_create, None, [chatbot, chat_txt], queue=False) + with ms.Application(): + with gr.Tab('Chat', elem_id='chat-tab'): + with gr.Column(): + chatbot = mgr.Chatbot(elem_id='chatbot', height=750, show_copy_button=True, flushing=False) + with gr.Row(): + with gr.Column(scale=3, min_width=0): + auto_speak_button = gr.Button('Randomly select an agent to speak first') + auto_speak_button.click(app, display_config, chatbot) + with gr.Column(scale=10): + chat_txt = gr.Textbox( + show_label=False, + placeholder='Chat with Qwen...', + container=False, + ) + with gr.Column(scale=1, min_width=0): + chat_clr_bt = gr.Button('Clear') + + chat_txt.submit(add_text, [chat_txt, display_config], [chatbot, chat_txt], + queue=False).then(app, display_config, chatbot) + + chat_clr_bt.click(chat_clear, None, [chatbot], queue=False) + + demo.load(chat_clear, None, [chatbot], queue=False) + + with gr.Tab('Create', elem_id='chat-tab'): + with gr.Column(scale=9, min_width=0): + chatbot = mgr.Chatbot(elem_id='chatbot0', height=750, show_copy_button=True, flushing=False) + with gr.Row(): + with gr.Column(scale=13): + chat_txt = gr.Textbox( + show_label=False, + placeholder='Chat with Qwen...', + container=False, + ) + with gr.Column(scale=1, min_width=0): + chat_clr_bt = gr.Button('Clear') + + txt_msg = chat_txt.submit(add_text_create, [chatbot, chat_txt], [chatbot, chat_txt], + queue=False).then(app_create, [chatbot, display_config], + [chatbot, display_config]) + txt_msg.then(lambda: gr.update(interactive=True), None, [chat_txt], queue=False) + + chat_clr_bt.click(chat_clear_create, None, [chatbot, chat_txt], queue=False) + demo.load(chat_clear_create, None, [chatbot, chat_txt], queue=False) if __name__ == '__main__': demo.queue().launch() diff --git a/qwen_agent/__init__.py b/qwen_agent/__init__.py index 637bbba..9cd8f9a 100644 --- a/qwen_agent/__init__.py +++ b/qwen_agent/__init__.py @@ -1,4 +1,4 @@ -__version__ = '0.0.11' +__version__ = '0.0.12' from .agent import Agent from .multi_agent_hub import MultiAgentHub diff --git a/qwen_agent/gui/__init__.py b/qwen_agent/gui/__init__.py index 709cdad..37e3c99 100644 --- a/qwen_agent/gui/__init__.py +++ b/qwen_agent/gui/__init__.py @@ -1,8 +1,9 @@ -from qwen_agent.gui.gradio import gr, mgr +from qwen_agent.gui.gradio_dep import gr, mgr, ms from qwen_agent.gui.web_ui import WebUI __all__ = [ 'gr', + 'ms', 'mgr', 'WebUI', ] diff --git a/qwen_agent/gui/gradio.py b/qwen_agent/gui/gradio_dep.py similarity index 69% rename from qwen_agent/gui/gradio.py rename to qwen_agent/gui/gradio_dep.py index 52d7c1f..a223bee 100644 --- a/qwen_agent/gui/gradio.py +++ b/qwen_agent/gui/gradio_dep.py @@ -1,7 +1,8 @@ try: import gradio as gr assert gr.__version__ >= '4.0' - import modelscope_studio as mgr # noqa + import modelscope_studio.components.base as ms # noqa + import modelscope_studio.components.legacy as mgr # noqa except Exception as e: raise ImportError('The dependencies for GUI support are not installed. ' 'Please install the required dependencies by running: pip install "qwen-agent[gui]"') from e diff --git a/qwen_agent/gui/web_ui.py b/qwen_agent/gui/web_ui.py index 1a0dd13..1f02f19 100644 --- a/qwen_agent/gui/web_ui.py +++ b/qwen_agent/gui/web_ui.py @@ -76,7 +76,7 @@ def run(self, **kwargs): self.run_kwargs = kwargs - from qwen_agent.gui.gradio import gr, mgr + from qwen_agent.gui.gradio_dep import gr, mgr, ms customTheme = gr.themes.Default( primary_hue=gr.themes.utils.colors.blue, @@ -88,104 +88,104 @@ def run(self, theme=customTheme, ) as demo: history = gr.State([]) + with ms.Application(): + with gr.Row(elem_classes='container'): + with gr.Column(scale=4): + chatbot = mgr.Chatbot(value=convert_history_to_chatbot(messages=messages), + avatar_images=[ + self.user_config, + self.agent_config_list, + ], + height=900, + avatar_image_width=80, + flushing=False, + show_copy_button=True, + latex_delimiters=[{ + 'left': '\\(', + 'right': '\\)', + 'display': True + }, { + 'left': '\\begin{equation}', + 'right': '\\end{equation}', + 'display': True + }, { + 'left': '\\begin{align}', + 'right': '\\end{align}', + 'display': True + }, { + 'left': '\\begin{alignat}', + 'right': '\\end{alignat}', + 'display': True + }, { + 'left': '\\begin{gather}', + 'right': '\\end{gather}', + 'display': True + }, { + 'left': '\\begin{CD}', + 'right': '\\end{CD}', + 'display': True + }, { + 'left': '\\[', + 'right': '\\]', + 'display': True + }]) + + input = mgr.MultimodalInput(placeholder=self.input_placeholder,) + + with gr.Column(scale=1): + if len(self.agent_list) > 1: + agent_selector = gr.Dropdown( + [(agent.name, i) for i, agent in enumerate(self.agent_list)], + label='Agents', + info='选择一个Agent', + value=0, + interactive=True, + ) + + agent_info_block = self._create_agent_info_block() + + agent_plugins_block = self._create_agent_plugins_block() + + if self.prompt_suggestions: + gr.Examples( + label='推荐对话', + examples=self.prompt_suggestions, + inputs=[input], + ) - with gr.Row(elem_classes='container'): - with gr.Column(scale=4): - chatbot = mgr.Chatbot(value=convert_history_to_chatbot(messages=messages), - avatar_images=[ - self.user_config, - self.agent_config_list, - ], - height=900, - avatar_image_width=80, - flushing=False, - show_copy_button=True, - latex_delimiters=[{ - 'left': '\\(', - 'right': '\\)', - 'display': True - }, { - 'left': '\\begin{equation}', - 'right': '\\end{equation}', - 'display': True - }, { - 'left': '\\begin{align}', - 'right': '\\end{align}', - 'display': True - }, { - 'left': '\\begin{alignat}', - 'right': '\\end{alignat}', - 'display': True - }, { - 'left': '\\begin{gather}', - 'right': '\\end{gather}', - 'display': True - }, { - 'left': '\\begin{CD}', - 'right': '\\end{CD}', - 'display': True - }, { - 'left': '\\[', - 'right': '\\]', - 'display': True - }]) - - input = mgr.MultimodalInput(placeholder=self.input_placeholder,) - - with gr.Column(scale=1): if len(self.agent_list) > 1: - agent_selector = gr.Dropdown( - [(agent.name, i) for i, agent in enumerate(self.agent_list)], - label='Agents', - info='选择一个Agent', - value=0, - interactive=True, + agent_selector.change( + fn=self.change_agent, + inputs=[agent_selector], + outputs=[agent_selector, agent_info_block, agent_plugins_block], + queue=False, ) - agent_info_block = self._create_agent_info_block() - - agent_plugins_block = self._create_agent_plugins_block() - - if self.prompt_suggestions: - gr.Examples( - label='推荐对话', - examples=self.prompt_suggestions, - inputs=[input], - ) - - if len(self.agent_list) > 1: - agent_selector.change( - fn=self.change_agent, - inputs=[agent_selector], - outputs=[agent_selector, agent_info_block, agent_plugins_block], + input_promise = input.submit( + fn=self.add_text, + inputs=[input, chatbot, history], + outputs=[input, chatbot, history], queue=False, ) - input_promise = input.submit( - fn=self.add_text, - inputs=[input, chatbot, history], - outputs=[input, chatbot, history], - queue=False, - ) - - if len(self.agent_list) > 1 and enable_mention: - input_promise = input_promise.then( - self.add_mention, - [chatbot, agent_selector], - [chatbot, agent_selector], - ).then( - self.agent_run, - [chatbot, history, agent_selector], - [chatbot, history, agent_selector], - ) - else: - input_promise = input_promise.then( - self.agent_run, - [chatbot, history], - [chatbot, history], - ) + if len(self.agent_list) > 1 and enable_mention: + input_promise = input_promise.then( + self.add_mention, + [chatbot, agent_selector], + [chatbot, agent_selector], + ).then( + self.agent_run, + [chatbot, history, agent_selector], + [chatbot, history, agent_selector], + ) + else: + input_promise = input_promise.then( + self.agent_run, + [chatbot, history], + [chatbot, history], + ) - input_promise.then(self.flushed, None, [input]) + input_promise.then(self.flushed, None, [input]) demo.load(None) @@ -217,7 +217,7 @@ def add_text(self, _input, _chatbot, _history): _chatbot.append([_input, None]) - from qwen_agent.gui.gradio import gr + from qwen_agent.gui.gradio_dep import gr yield gr.update(interactive=False, value=None), _chatbot, _history @@ -295,7 +295,7 @@ def agent_run(self, _chatbot, _history, _agent_selector=None): logger.info('agent_run response:\n' + pprint.pformat(responses, indent=2)) def flushed(self): - from qwen_agent.gui.gradio import gr + from qwen_agent.gui.gradio_dep import gr return gr.update(interactive=True) @@ -314,7 +314,7 @@ def _get_agent_index_by_name(self, agent_name): return 0 def _create_agent_info_block(self, agent_index=0): - from qwen_agent.gui.gradio import gr + from qwen_agent.gui.gradio_dep import gr agent_config_interactive = self.agent_config_list[agent_index] @@ -326,7 +326,7 @@ def _create_agent_info_block(self, agent_index=0): )) def _create_agent_plugins_block(self, agent_index=0): - from qwen_agent.gui.gradio import gr + from qwen_agent.gui.gradio_dep import gr agent_interactive = self.agent_list[agent_index] diff --git a/qwen_server/workstation_server.py b/qwen_server/workstation_server.py index f04ccb3..e91ba59 100644 --- a/qwen_server/workstation_server.py +++ b/qwen_server/workstation_server.py @@ -8,7 +8,7 @@ except ImportError: pass from qwen_agent.agents import ArticleAgent, Assistant, ReActChat -from qwen_agent.gui import gr, mgr +from qwen_agent.gui import gr, mgr, ms from qwen_agent.gui.utils import get_avatar_image from qwen_agent.llm import get_chat_model from qwen_agent.llm.base import ModelServiceError @@ -85,7 +85,7 @@ def chat_clear(): def chat_clear_pure(): app_global_para['pure_messages'] = [] - return None, None + return [] def chat_clear_last(): @@ -498,96 +498,98 @@ def format_generate(edit, context): """) with gr.Tab('Chat', elem_id='chat-tab'): - with gr.Column(): - chatbot = mgr.Chatbot( - elem_id='chatbot', - height=680, - show_copy_button=True, - avatar_images=[None, get_avatar_image('qwen')], - flushing=False, - ) - with gr.Row(): - with gr.Column(scale=1, min_width=0): - file_btn = gr.UploadButton('Upload', file_types=['file']) - - with gr.Column(scale=13): - chat_txt = gr.Textbox( - show_label=False, - placeholder='Chat with Qwen...', - container=False, - ) - with gr.Column(scale=1, min_width=0): - chat_clr_bt = gr.Button('Clear') - - with gr.Column(scale=1, min_width=0): - chat_stop_bt = gr.Button('Stop') - with gr.Column(scale=1, min_width=0): - chat_re_bt = gr.Button('Again') - with gr.Row(): - with gr.Column(scale=2, min_width=0): - plug_bt = gr.Dropdown( - [CI_OPTION, DOC_OPTION], - label='Plugin', - info='', - value=DOC_OPTION, - ) - with gr.Column(scale=8, min_width=0): - hidden_file_path = gr.Textbox(interactive=False, label='The uploaded file is displayed here') - - txt_msg = chat_txt.submit(add_text, [chatbot, chat_txt], [chatbot, chat_txt], - queue=False).then(bot, [chatbot, plug_bt], chatbot) - txt_msg.then(lambda: gr.update(interactive=True), None, [chat_txt], queue=False) - - re_txt_msg = (chat_re_bt.click(rm_text, [chatbot], [chatbot, chat_txt], - queue=False).then(chat_clear_last, None, - None).then(bot, [chatbot, plug_bt], chatbot)) - re_txt_msg.then(lambda: gr.update(interactive=True), None, [chat_txt], queue=False) - - file_msg = file_btn.upload(add_file, [file_btn, plug_bt], [hidden_file_path], queue=False) - file_msg.then(update_browser_list, None, browser_list) - - chat_clr_bt.click(chat_clear, None, [chatbot, hidden_file_path], queue=False) - # re_bt.click(re_bot, chatbot, chatbot) - chat_stop_bt.click(chat_clear_last, None, None, cancels=[txt_msg, re_txt_msg], queue=False) - - plug_bt.change(choose_plugin, plug_bt, [file_btn, hidden_file_path]) + with ms.Application(): + with gr.Column(): + chatbot = mgr.Chatbot( + elem_id='chatbot', + height=680, + show_copy_button=True, + avatar_images=[None, get_avatar_image('qwen')], + flushing=False, + ) + with gr.Row(): + with gr.Column(scale=1, min_width=0): + file_btn = gr.UploadButton('Upload', file_types=['file']) + + with gr.Column(scale=13): + chat_txt = gr.Textbox( + show_label=False, + placeholder='Chat with Qwen...', + container=False, + ) + with gr.Column(scale=1, min_width=0): + chat_clr_bt = gr.Button('Clear') + + with gr.Column(scale=1, min_width=0): + chat_stop_bt = gr.Button('Stop') + with gr.Column(scale=1, min_width=0): + chat_re_bt = gr.Button('Again') + with gr.Row(): + with gr.Column(scale=2, min_width=0): + plug_bt = gr.Dropdown( + [CI_OPTION, DOC_OPTION], + label='Plugin', + info='', + value=DOC_OPTION, + ) + with gr.Column(scale=8, min_width=0): + hidden_file_path = gr.Textbox(interactive=False, label='The uploaded file is displayed here') + + txt_msg = chat_txt.submit(add_text, [chatbot, chat_txt], [chatbot, chat_txt], + queue=False).then(bot, [chatbot, plug_bt], chatbot) + txt_msg.then(lambda: gr.update(interactive=True), None, [chat_txt], queue=False) + + re_txt_msg = (chat_re_bt.click(rm_text, [chatbot], [chatbot, chat_txt], + queue=False).then(chat_clear_last, None, + None).then(bot, [chatbot, plug_bt], chatbot)) + re_txt_msg.then(lambda: gr.update(interactive=True), None, [chat_txt], queue=False) + + file_msg = file_btn.upload(add_file, [file_btn, plug_bt], [hidden_file_path], queue=False) + file_msg.then(update_browser_list, None, browser_list) + + chat_clr_bt.click(chat_clear, None, [chatbot, hidden_file_path], queue=False) + # re_bt.click(re_bot, chatbot, chatbot) + chat_stop_bt.click(chat_clear_last, None, None, cancels=[txt_msg, re_txt_msg], queue=False) + + plug_bt.change(choose_plugin, plug_bt, [file_btn, hidden_file_path]) with gr.Tab('Pure Chat', elem_id='pure-chat-tab'): gr.Markdown('Note: The chat box on this tab will not use any browsing history!') - with gr.Column(): - pure_chatbot = mgr.Chatbot( - elem_id='pure_chatbot', - height=680, - show_copy_button=True, - avatar_images=[None, get_avatar_image('qwen')], - flushing=False, - ) - with gr.Row(): - with gr.Column(scale=13): - chat_txt = gr.Textbox( - show_label=False, - placeholder='Chat with Qwen...', - container=False, - ) - with gr.Column(scale=1, min_width=0): - chat_clr_bt = gr.Button('Clear') - with gr.Column(scale=1, min_width=0): - chat_stop_bt = gr.Button('Stop') - with gr.Column(scale=1, min_width=0): - chat_re_bt = gr.Button('Again') - - txt_msg = chat_txt.submit(pure_add_text, [pure_chatbot, chat_txt], [pure_chatbot, chat_txt], - queue=False).then(pure_bot, pure_chatbot, pure_chatbot) - txt_msg.then(lambda: gr.update(interactive=True), None, [chat_txt], queue=False) - - re_txt_msg = chat_re_bt.click(rm_text, [pure_chatbot], [pure_chatbot, chat_txt], - queue=False).then(pure_chat_clear_last, None, - None).then(pure_bot, pure_chatbot, pure_chatbot) - re_txt_msg.then(lambda: gr.update(interactive=True), None, [chat_txt], queue=False) - - chat_clr_bt.click(chat_clear_pure, None, pure_chatbot, queue=False) - - chat_stop_bt.click(pure_chat_clear_last, None, None, cancels=[txt_msg, re_txt_msg], queue=False) + with ms.Application(): + with gr.Column(): + pure_chatbot = mgr.Chatbot( + elem_id='pure_chatbot', + height=680, + show_copy_button=True, + avatar_images=[None, get_avatar_image('qwen')], + flushing=False, + ) + with gr.Row(): + with gr.Column(scale=13): + chat_txt = gr.Textbox( + show_label=False, + placeholder='Chat with Qwen...', + container=False, + ) + with gr.Column(scale=1, min_width=0): + chat_clr_bt = gr.Button('Clear') + with gr.Column(scale=1, min_width=0): + chat_stop_bt = gr.Button('Stop') + with gr.Column(scale=1, min_width=0): + chat_re_bt = gr.Button('Again') + + txt_msg = chat_txt.submit(pure_add_text, [pure_chatbot, chat_txt], [pure_chatbot, chat_txt], + queue=False).then(pure_bot, pure_chatbot, pure_chatbot) + txt_msg.then(lambda: gr.update(interactive=True), None, [chat_txt], queue=False) + + re_txt_msg = chat_re_bt.click(rm_text, [pure_chatbot], [pure_chatbot, chat_txt], + queue=False).then(pure_chat_clear_last, None, + None).then(pure_bot, pure_chatbot, pure_chatbot) + re_txt_msg.then(lambda: gr.update(interactive=True), None, [chat_txt], queue=False) + + chat_clr_bt.click(chat_clear_pure, None, pure_chatbot, queue=False) + + chat_stop_bt.click(pure_chat_clear_last, None, None, cancels=[txt_msg, re_txt_msg], queue=False) date1.change(update_app_global_para, [date1, date2], None).then(update_browser_list, None, browser_list).then(chat_clear, None, [chatbot, hidden_file_path]) diff --git a/setup.py b/setup.py index cc1195c..36d0755 100644 --- a/setup.py +++ b/setup.py @@ -99,9 +99,9 @@ def read_description() -> str: # Gradio has bad version compatibility. Therefore, we use `==` instead of `>=`. 'pydantic==2.9.2', 'pydantic-core==2.23.4', - 'gradio==4.44.0', - 'gradio-client==1.3.0', - 'modelscope-studio==0.5.0', + 'gradio>=5.0.0', + 'gradio-client==1.4.0', + 'modelscope-studio~=1.0.0b', ], }, url='https://github.com/QwenLM/Qwen-Agent',