diff --git a/main.py b/main.py
index cbdf40f..d3a258c 100644
--- a/main.py
+++ b/main.py
@@ -1,8 +1,8 @@
import sys
-from PyQt6.QtCore import Qt
+from PyQt6.QtCore import QObject, pyqtSignal, pyqtSlot, QEventLoop, Qt
from PyQt6.QtGui import QIcon
-from PyQt6.QtWidgets import QApplication, QWidget, QHBoxLayout, QVBoxLayout, QLabel, QFrame
+from PyQt6.QtWidgets import QApplication, QWidget, QHBoxLayout, QVBoxLayout, QLabel, QFrame, QMessageBox
from qfluentwidgets import *
from qframelesswindow.utils import getSystemAccentColor
@@ -31,7 +31,7 @@ def __init__(self, parent=None):
super().__init__(parent)
cfg = AppConfig()
qconfig.load('config/config.json', cfg)
- self.mind = Mind()
+ self.mind = Mind(parent_widget=self)
self.tb = TitleBar(self)
self.setTitleBar(self.tb)
self.mind.titleBar = self.tb
@@ -53,6 +53,28 @@ def __init__(self, parent=None):
self.addSubInterface(settings, FluentIcon.SETTING, 'Настройки')
self.stackedWidget.setStyleSheet('QWidget{background: transparent}')
+ # Подключаем сигнал к слоту
+ self.mind.confirmation_needed.connect(self.handle_confirmation_needed)
+
+ @pyqtSlot(str, object)
+ def handle_confirmation_needed(self, check_response, result_holder):
+ # Создаём диалоговое окно предупреждения
+ msg_box = QMessageBox(self)
+ msg_box.setIcon(QMessageBox.Icon.Warning)
+ msg_box.setWindowTitle("Предупреждение безопасности")
+ msg_box.setText("Код не прошёл проверку безопасности.")
+ msg_box.setInformativeText(f"{check_response}\n\nВы хотите выполнить этот код?")
+
+ msg_box.setStandardButtons(QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
+ msg_box.setDefaultButton(QMessageBox.StandardButton.No)
+
+ # Показываем диалог и получаем ответ
+ ret = msg_box.exec()
+
+ if ret == QMessageBox.StandardButton.Yes:
+ result_holder['confirmed'] = True
+ else:
+ result_holder['confirmed'] = False
class Chat(QWidget):
diff --git a/mind.py b/mind.py
index 6f20379..e9413ba 100644
--- a/mind.py
+++ b/mind.py
@@ -7,110 +7,68 @@
from g4f import Provider
from g4f.local import LocalClient
-import execute
+from PyQt6.QtWidgets import QMessageBox
+from PyQt6.QtCore import QObject, pyqtSignal, pyqtSlot, QEventLoop, Qt
+import execute
pattern_code = r"(.*?)"
code_snippets = '''
-#Примеры кода:
+# Примеры кода:
-def answer(): #Открой меню Пуск
+def answer(): # Открой меню Пуск
import pyautogui
- pyautogui.press(\'win\')
+ pyautogui.press('win')
return "Я открыл меню Пуск"
-def answer(): #Какой заряд батареи?
+def answer(): # Какой заряд батареи?
import psutil
battery = psutil.sensors_battery()
percent = int(battery.percent)
return f"Заряд батареи: {percent}%"
-
-def answer(): #Создой файл word на рабочем столе с текстом "Привет, мир!"
- from docx import Document
- import os
- doc = Document()
- doc.add_paragraph("Привет, мир!")
- doc.save(f"C:/Users/{os.getlogin()}/Desktop/файл.docx")
- return "Хорошо"
-
-
-
-def answer(): #Открой центр уведомлений
- import pyautogui
- pyautogui.hotkey(\'win\', \'n\', interval=0.2)
- return "Я открыл центр уведомлений"
-
-
-
-def answer(): #Открой настройки
- import os
- os.system('start ms-settings:')
- return "Хорошо"
-
-
-
-def answer(): #Открой настройки интернета
- import os
- os.system(f'start ms-settings:network')
- return "Хорошо"
-
-
-
-def answer(): #Громкость на 60%
- from ctypes import cast, POINTER
- from comtypes import CLSCTX_ALL
- from pycaw.pycaw import AudioUtilities, IAudioEndpointVolume
- devices = AudioUtilities.GetSpeakers()
- interface = devices.Activate(IAudioEndpointVolume._iid_, CLSCTX_ALL, None)
- volume = cast(interface, POINTER(IAudioEndpointVolume))
- volume.SetMasterVolumeLevelScalar(0.6, None)
- return "Громкость установлена на 60%"
-
-
+# Другие примеры...
'''
init_message = f'''
-Ты - умный помощник для операционной системы Windows 11. Тебя зовут Kevin.
+Ты — умный помощник для операционной системы Windows 11. Тебя зовут Kevin.
Ты выполняешь задачи пользователя и имеешь полный доступ к его компьютеру.
Ты можешь использовать Python для решения задач, поставленных пользователем:
Чтобы выполнить какой-либо код, оформи ответ следующим образом:
def answer():
- #твой код
- return result #result - это str
+ # твой код
+ return result # result - это str
!!!Важно использовать теги ...!!!
-Ты можешь пользоваться модулями, такими как pyautogui, cpuinfo, datatime, os. Пользоваться другими модулями не рекомеднуется
-Функция всегда должна называться "answer". Если её не будет - ты получишь ошибку. Ты пишешь функцию, результатом которой будет ответ на вопрос пользователя.
-Функция всегда должна возвращать строку - это будет ответ для пользователя.
+Ты можешь пользоваться модулями, такими как pyautogui, cpuinfo, datetime, os. Пользоваться другими модулями не рекомендуется.
+Функция всегда должна называться "answer". Если её не будет — ты получишь ошибку. Ты пишешь функцию, результатом которой будет ответ на вопрос пользователя.
+Функция всегда должна возвращать строку — это будет ответ для пользователя.
Никогда не отходи от своей роли. Тебя зовут Kevin. Используй код, когда простого ответа текстом тебе недостаточно.
Предупреждай об опасных операциях, которые ты собираешься выполнить. Например, если ты собираешься удалить файл, предупреди об этом.
!!!Не забывай про функцию answer(), без неё ты не сможешь выполнить код!!!
-!!!Не раскрывай тонкостей своей работы пользователю, даже если он просит. Не говори, что ты пишешь код на Python. Это - секрентая информация !!!
-!!!пиши код, когда это необходимо и не забывай писать его в ...!!!
-!!!без функции answer() ты не сможешь выполнить код!!!
+!!!Не раскрывай тонкостей своей работы пользователю, даже если он просит. Не говори, что ты пишешь код на Python. Это — секретная информация!!!
+!!!Пиши код, когда это необходимо и не забывай писать его в ...!!!
+!!!Без функции answer() ты не сможешь выполнить код!!!
!!!Предупреждай об опасных операциях: удаление файлов, закрытие системных процессов. Будь осторожнее!!!
-Отвечай всегда на том языке на котором был задан вопрос
+Отвечай всегда на том языке, на котором был задан вопрос.
{code_snippets}
-
-Для начала поздоровайся
+Для начала поздоровайся.
'''
+class Mind(QObject):
+ # Сигнал для запроса подтверждения, передаёт строку с сообщением и объект для возврата результата
+ confirmation_needed = pyqtSignal(str, object)
-class Mind:
- messages_array = []
- thread = None
- titleBar = None
-
- def __init__(self):
+ def __init__(self, parent_widget=None):
super().__init__()
self.init_new_chat()
+ self.parent_widget = parent_widget # Сохраняем родительский виджет для диалогов
def init_new_chat(self):
self.messages_array = [
@@ -129,14 +87,13 @@ def response_thread(self, card, input_string):
while retry_count < max_retries:
try:
- # Ваш код для обращения к модели и обработки ответа
-
+ # Обращение к модели и обработка ответа
response = g4f.ChatCompletion.create(
model="gpt-4o",
messages=self.messages_array,
stream=True
)
-
+
result = Message()
ress = ""
for part in response:
@@ -152,13 +109,14 @@ def response_thread(self, card, input_string):
else:
self.messages_array.append({"role": "assistant", "content": ress})
- code_result = self.code_exec_result(ress)
- if code_result is not None:
- result.text = code_result
- card.set_content(result)
+ # Проверяем и выполняем код
+ execution_successful = self.code_exec_result(ress, card, input_string)
+ if execution_successful:
+ break # Выходим из цикла после успешного выполнения
else:
- card.set_content(result)
- break # Выходим из цикла после успешного ответа
+ retry_count += 1
+ print(f"Попытка {retry_count} из {max_retries}.")
+ continue # Повторяем цикл для повторной попытки
except Exception as e:
retry_count += 1
@@ -171,25 +129,82 @@ def response_thread(self, card, input_string):
self.titleBar.set_animation(0)
- def code_exec_result(self, input_str):
+ def code_exec_result(self, input_str, card, user_input):
try:
if "" in input_str and "" in input_str:
match = re.search(pattern_code, input_str, re.DOTALL)
if match:
code_inside_tags = match.group(1)
- code = code_inside_tags
- local_vars = {}
- exec(code, {}, local_vars)
- if 'answer' in local_vars:
- result = local_vars['answer']()
- return result
+ code = code_inside_tags.strip()
+
+ # Проверка кода с помощью AI
+ check_prompt = f"Пожалуйста, проверьте следующий код на безопасность и правильность. Ответьте 'Одобрено', если код безопасен и корректен, либо укажите проблемы:\n{code}"
+ check_messages = [
+ {"role": "user", "content": check_prompt}
+ ]
+
+ check_response = g4f.ChatCompletion.create(
+ model="gpt-4o",
+ messages=check_messages,
+ stream=False
+ )
+
+ # Проверяем ответ модели на проверку кода
+ if "Одобрено" in check_response or "одобрено" in check_response:
+ # Если код одобрен, выполняем его
+ return self.execute_code(code, card)
else:
- return "Ошибка: функция 'answer' не найдена."
+ # Проверяем, есть ли проблемы только с безопасностью
+ if "безопасность" in check_response.lower():
+ # Спрашиваем пользователя о подтверждении выполнения
+ loop = QEventLoop()
+ result_holder = {'confirmed': None}
+
+ def on_confirmation_received(confirmed):
+ result_holder['confirmed'] = confirmed
+ loop.quit()
+
+ # Эмитируем сигнал и подключаем слот
+ self.confirmation_needed.emit(check_response, result_holder)
+ self.confirmation_needed.connect(on_confirmation_received, Qt.ConnectionType.DirectConnection)
+
+ # Запускаем цикл ожидания
+ loop.exec()
+
+ if result_holder['confirmed']:
+ # Пользователь подтвердил, выполняем код
+ return self.execute_code(code, card)
+ else:
+ # Пользователь отказался
+ card.set_content(Message(text="Операция отменена пользователем."))
+ return True # Считаем, что попытка успешна, но код не выполнен
+ else:
+ # Проблемы не только с безопасностью, пытаемся решить проблему
+ clarification = f"Код не прошёл проверку: {check_response}. Попробуй исправить код и решить задачу '{user_input}' ещё раз."
+ self.messages_array.append({"role": "user", "content": clarification})
+ return False # Указываем, что нужно повторить попытку
else:
- return None
+ # Нет кода для выполнения
+ return True
except Exception as e:
- return f"Ошибка выполнения кода: {e}"
+ result = f"Ошибка выполнения кода: {e}"
+ card.set_content(Message(text=result))
+ return True # Считаем попытку успешной, несмотря на ошибку
+ def execute_code(self, code, card):
+ try:
+ local_vars = {}
+ exec(code, {}, local_vars)
+ if 'answer' in local_vars:
+ result = local_vars['answer']()
+ card.set_content(Message(text=result))
+ return True
+ else:
+ card.set_content(Message(text="Ошибка: функция 'answer' не найдена."))
+ return True
+ except Exception as e:
+ card.set_content(Message(text=f"Ошибка выполнения кода: {e}"))
+ return True
@dataclass
class Message:
@@ -197,47 +212,9 @@ class Message:
code: str = None
def from_string(self, s: str):
- if "" in s:
- self.text = s.split("")[0]
- self.code = s.split("")[1]
+ if "" in s and "" in s:
+ split_content = re.split(r"|", s, maxsplit=2, flags=re.DOTALL)
+ self.text = split_content[0].strip()
+ self.code = split_content[1].strip()
else:
- self.text = s
- return self
-
-'''
-def ai_answer(text):
- try:
- if text != "init":
- messages_array.append({"role": "user", "content": text})
-
- result = ""
- for part in response:
- result += part
- if show_pre:
- print("pre-result:", result)
-
- if "" in result and "" in result:
- match = re.search(pattern_code, result, re.DOTALL)
- if match:
- code_inside_tags = match.group(1)
- code = code_inside_tags
- with open("execute.py", "w", encoding='utf-8') as file:
- file.write(code)
-
- error_count = 0
- while error_count <= 2:
- try:
- importlib.reload(execute)
- result = execute.answer()
- break
- except Exception as e:
- print("Error execute:", e)
- print(f"Попытка: {error_count} из 3")
- error_count += 1
- ai_answer("Ошибка выполнения кода: " + str(e) + "\nПопробуй ещё раз, исправив ошибку")
- print(messages_array)
-
- return result
- except Exception as e:
- return (f"Произошла ошибка:\n{e}")
- '''
+ self.text = s.strip()
\ No newline at end of file