diff --git a/.gitignore b/.gitignore index d41e60e..f9f73a5 100644 --- a/.gitignore +++ b/.gitignore @@ -7,7 +7,11 @@ dist/ .venv config.yaml +build/ +cache **.lock # Ignore Python cache files **/__pycache__/ /session + +main.spec \ No newline at end of file diff --git a/agent/woker_agent.py b/agent/woker_agent.py index 3e1d878..62e044b 100644 --- a/agent/woker_agent.py +++ b/agent/woker_agent.py @@ -33,19 +33,21 @@ class WorkerAgent: def get_iter(question): llm = LLM_Util().llm() tools = ToolsUtil.get_tools() - instructions = "" + example = """例子如下:案例1:```Thought: 我需要使用工具吗? 需要\nAction: 桌面路径\nAction Input: 无\nObservation: c:/path/develop```\n +案例2:```Thought: 我需要使用工具吗? 需要\nAction: 打开应用\nAction Input: xxx\nObservation: 打开成功```\n +案例3:```Thought: 我需要使用工具吗? 不需要\nFinal Answer: 您的桌面上有以下文件```\n +""" prompt = PromptTemplate( - template="{instructions}\n\nTOOLS:\n------\n\n你可以使用以下工具:\n\n{tools}\n\n使用工具时,请使用以下格式:\n\n" + template="TOOLS:\n------\n\n你可以使用以下工具:\n\n{tools}\n\n使用工具时,请使用以下格式:\n\n" "```\n'Thought: 我需要使用工具吗? 需要\nAction: {tool_names}'\n" "'Action Input: Action的输入'\n'Observation: 运行Action的结果'\n```" "\n\n当输出内容时,或者不需要使用工具,必须使用以下格式: " - "\n\n```\nThought: 我需要使用工具吗? 不需要\nFinal Answer: [你的回复]\n```\n\n开始!\n\n" + "\n\n```\nThought: 我需要使用工具吗? 不需要\nFinal Answer: [你的回复]\n```\n\n{example}\n\n" "Previous conversation history:\n{chat_history}\n\nNew input: {input}\n{agent_scratchpad}", input_variables=['agent_scratchpad', 'input', 'tool_names', 'tools'], partial_variables={'chat_history': '', 'instructions': ""} ) - base_prompt = hub.pull("langchain-ai/react-agent-template") - # prompt = base_prompt.partial(instructions=instructions) + prompt = prompt.partial(example=example) agent = create_react_agent(llm=llm, tools=tools, prompt=prompt) agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True, handle_parsing_errors=True) return agent_executor.iter({"input": question}) diff --git a/pages/chat_page.py b/pages/chat_page.py index 694bad7..1342a7a 100644 --- a/pages/chat_page.py +++ b/pages/chat_page.py @@ -5,6 +5,7 @@ from PyQt6.QtWidgets import QLabel, QTextEdit, QListWidgetItem, QSpacerItem, QSi from agent.woker_agent import WorkerAgent from pages.bse_page import BasePage +from pages.func_list_page import FuncListPage from utils.config import Config from utils.qt_util import QtUtil @@ -62,7 +63,6 @@ class ChatPage(BasePage): chat_input.setGeometry(QtCore.QRect(40, 580, 601, 51)) chat_input.setStyleSheet("border-radius: 30px") chat_input.setObjectName("chat_input") - self.ui.action_widget.hide() self.new_conversation( "你好,欢迎来到智子 🎉\n\n智子是一个让普通人成为超级个体的Agent开发平台,只要你有想法,都可以用智子快速、低门槛搭建专属于你的 Agent!", "system" @@ -72,10 +72,24 @@ class ChatPage(BasePage): # 设置 QListWidget 的选择模式为 NoSelection self.ui.chat_list.setSelectionMode(QAbstractItemView.SelectionMode.NoSelection) # 设置 QListWidget 的焦点策略为 NoFocus + self.ui.chat_list.setFocusPolicy(Qt.FocusPolicy.NoFocus) + # 垂直滚动条滑动时才显示,否则隐藏 + self.ui.chat_list.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded) + # 隐藏水平滚动条 + self.ui.chat_list.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) # self.ui.select_action.clicked.connect(self.select_action_clicked) setting_action = self.ui.setting_action setting_action.triggered.connect(self.open_setting_page) + # 添加按钮点击事件,打开添加对话框 + self.ui.add_action.clicked.connect(self.open_add_dialog) + + def open_add_dialog(self): + self.func_list_page = FuncListPage(parent=self.ui) + # self.func_list_page.setParent(self.ui) + + self.func_list_page.show() + self.ui.hide() def open_setting_page(self): self.setting_page = QtUtil.load_ui("setting_page.ui") @@ -97,13 +111,6 @@ class ChatPage(BasePage): def cancel_btn(self): self.setting_page.close() - def hide_action(self, event): - action_widget = self.ui.action_widget - if not QRect(action_widget.mapToGlobal(QPoint(0, 0)), action_widget.size()).contains(event.globalPos()): - action_widget.hide() - - def select_action_clicked(self): - self.ui.action_widget.show() def new_conversation(self, text, role): text = text.replace("\n", "
") diff --git a/pages/chat_page.ui b/pages/chat_page.ui index 8d5658e..8e799a8 100644 --- a/pages/chat_page.ui +++ b/pages/chat_page.ui @@ -40,58 +40,18 @@ border-radius: 30px - + 40 - 340 - 201 - 201 + 550 + 75 + 23 - - background: rgb(255, 255, 255) + + 注入魔力 - - - - 120 - 0 - 75 - 23 - - - - 新增插件 - - - - - - 0 - 30 - 201 - 171 - - - - background: transparent; -border: none; - - - - - - 0 - 0 - 101 - 16 - - - - 已选用 0/0 个插件 - - diff --git a/pages/edit_action_list_view.py b/pages/edit_action_list_view.py index 874a91c..0b4e49a 100644 --- a/pages/edit_action_list_view.py +++ b/pages/edit_action_list_view.py @@ -124,8 +124,8 @@ class ActionList(QListWidget): mime_data.setData(self.MY_MIME_TYPE, byte_array) # 设置拖拽缩略图 drag = QDrag(self) - icon = self.style().standardIcon(QStyle.StandardPixmap.SP_TitleBarNormalButton) drag.setMimeData(mime_data) + icon = self.style().standardIcon(QStyle.StandardPixmap.SP_TitleBarNormalButton) pixmap = icon.pixmap(10, 10) drag.setPixmap(pixmap) # 拖拽结束 diff --git a/pages/func_list_page.py b/pages/func_list_page.py index 76af55e..205e7ca 100644 --- a/pages/func_list_page.py +++ b/pages/func_list_page.py @@ -1,10 +1,13 @@ +import typing +from PyQt6 import QtCore from PyQt6.QtCore import QSize, Qt from PyQt6.QtGui import QIcon -from PyQt6.QtWidgets import QGraphicsOpacityEffect, QToolButton +from PyQt6.QtWidgets import QGraphicsOpacityEffect, QToolButton, QMainWindow, QWidget from pages.bse_page import BasePage from pages.edit_page import EditPage, GlobalUtil from utils.qt_util import QtUtil +from PyQt6.uic import loadUiType class AddFuncButton(QToolButton): def __init__(self, func_status, func_list_pos_row, func_list_pos_column, func_list_page): @@ -48,17 +51,33 @@ class AddFuncButton(QToolButton): self.opacity_effect.setOpacity(0) -class FuncListPage(BasePage): + + +interface_ui = QtUtil.load_ui_type("func_list_page.ui") + + +class FuncListPage(QMainWindow, interface_ui): + def __init__(self, parent): + self.parent_ui = parent + super().__init__() + self.setupUi(self) + self.setup_up() + + # 关闭事件 + def closeEvent(self, event): + self.parent_ui.show() + def setup_up(self): - self.ui = QtUtil.load_ui("func_list_page.ui") + # self.ui = QtUtil.load_ui("func_list_page.ui") # 四行三列,辅满通用应用列表布局 for i in range(3): # 3行 for j in range(4): # 4列 - add_button = AddFuncButton("通用", i, j, self.ui) - self.ui.general_layout.addWidget(add_button, i, j) + add_button = AddFuncButton("通用", i, j, self) + self.general_layout.addWidget(add_button, i, j) # 四行四列,辅满专属应用列表布局 for i in range(3): # 4行 for j in range(4): # 4列 - add_button = AddFuncButton("专属", i, j, self.ui) - self.ui.special_layout.addWidget(add_button, i, j) + add_button = AddFuncButton("专属", i, j, self) + self.special_layout.addWidget(add_button, i, j) + diff --git a/tools/FindDesktopPath.py b/tools/FindDesktopPath.py index 22eec6c..b43621f 100644 --- a/tools/FindDesktopPath.py +++ b/tools/FindDesktopPath.py @@ -1,7 +1,5 @@ import os - -from langchain_core.tools import BaseTool - +from langchain.tools import BaseTool class FindDesktopPath(BaseTool): name = "桌面路径" @@ -9,6 +7,6 @@ class FindDesktopPath(BaseTool): # args_schema = None - def _run(self, *tool_args, **tool_kwargs): + def _run(self): desktop_path = os.path.join(os.path.expanduser("~"), "Desktop") - return desktop_path + return desktop_path \ No newline at end of file diff --git a/tools/ListAllFile.py b/tools/ListAllFile.py index f66a529..9861e43 100644 --- a/tools/ListAllFile.py +++ b/tools/ListAllFile.py @@ -1,7 +1,6 @@ import os - -from langchain_core.tools import BaseTool from pydantic import BaseModel, Field +from langchain.tools import BaseTool class ListAllFileInput(BaseModel): diff --git a/tools/ListDesktopFiles.py b/tools/ListDesktopFiles.py index 9841d77..f61c2c3 100644 --- a/tools/ListDesktopFiles.py +++ b/tools/ListDesktopFiles.py @@ -1,7 +1,5 @@ import os - -from langchain_core.tools import BaseTool - +from langchain.tools import BaseTool from tools.FindDesktopPath import FindDesktopPath from tools.ListAllFile import ListAllFile @@ -10,7 +8,8 @@ class ListDesktopFiles(BaseTool): name = "桌面的所有文件" description = "返回桌面的所有文件" - def _run(self, *tool_args, **tool_kwargs): + def _run(self, *args): + print(args) desk_top_path = FindDesktopPath().invoke(input={}) all_files = ListAllFile().invoke(input={"path": desk_top_path}) return all_files diff --git a/tools/OpenApplication.py b/tools/OpenApplication.py index 930e81a..3e4b9fc 100644 --- a/tools/OpenApplication.py +++ b/tools/OpenApplication.py @@ -1,16 +1,18 @@ import subprocess -from langchain.tools import BaseTool, ToolException # Updated import statement +from langchain.tools import BaseTool # Added ToolException impor from pydantic import BaseModel, Field - +from langchain_core.tools import ToolException class OpenApplicationInput(BaseModel): path: str = Field(description="应用路径", title="应用路径") - class OpenApplicationAction(BaseTool): name = "打开应用" description = "打开指定目录的应用" args_schema = OpenApplicationInput def _run(self, path): - subprocess.Popen(path) + try: + subprocess.Popen(path) + except Exception as e: + raise ToolException(f"请好好检查一下路径,是不是有不合理的字符,比如`\nObservation: `、`非路径内容`") # Using ToolException here diff --git a/tools/base_tool.py b/tools/base_tool.py new file mode 100644 index 0000000..c628787 --- /dev/null +++ b/tools/base_tool.py @@ -0,0 +1,7 @@ +from langchain_core.tools import BaseTool +class BaseTool(BaseTool): + def run(self, **kwargs): + pass + + def _run(self, **kwargs): + return self.run(**kwargs) diff --git a/utils/qt_util.py b/utils/qt_util.py index f7a66c7..feb3225 100644 --- a/utils/qt_util.py +++ b/utils/qt_util.py @@ -2,20 +2,29 @@ import os import sys from PyQt6 import uic +from PyQt6.uic import loadUiType class QtUtil: - @staticmethod - def load_ui(*path): - # 项目根目录 - # project_root_path = os.path.abspath(os.path.dirname(__file__)) + @classmethod + def get_root_path(cls): project_root_path = os.path.dirname(os.path.realpath(sys.argv[0])) - path = os.path.join(project_root_path, "pages", *path) + return project_root_path + + + @classmethod + def load_ui(cls, *path): + # 项目根目录 + path = os.path.join(cls.get_root_path(), "pages", *path) return uic.loadUi(path) - @staticmethod - def get_icon(*path): - project_root_path = os.path.dirname(os.path.realpath(sys.argv[0])) - # project_root_path = os.path.abspath(os.path.dirname(__file__)) - path = os.path.join(project_root_path, "source", *path) + @classmethod + def load_ui_type(cls, *path): + path = os.path.join(cls.get_root_path(), "pages", *path) + interface_ui, _ = loadUiType(path) + return interface_ui + + @classmethod + def get_icon(cls, *path): + path = os.path.join(cls.get_root_path(), "source", *path) return path