try: from .agent.chat_history import * from .agent.assistant import * from .llm import * from .llm_settings import llm_settings from .agent.agent import * from .agent.background import * from .gui.signal import * from .gui.button import * from .gui.settings import settings_popup from .gui.llmsettings import llmsettings_popup from .utils.db import * from .utils.telemetry import my_tracer, os_name from .audio.wake_word import wake_word from .audio.tts import text_to_speech from .character import name, developer except ImportError: # This is for running the script directly # in order to test the GUI without rebuilding the package from agent.chat_history import * from agent.assistant import * from llm import * from llm_settings import llm_settings from agent.agent import * from agent.background import * from utils.db import * from gui.signal import * from gui.button import * from gui.settings import settings_popup from gui.llmsettings import llmsettings_popup from utils.telemetry import my_tracer, os_name from audio.wake_word import wake_word from audio.tts import text_to_speech import platform import threading import time import random import math from PyQt5.QtWidgets import QMainWindow, QVBoxLayout, QWidget from PyQt5.QtGui import QMouseEvent, QPainter, QPen, QBrush, QIcon, QColor from PyQt5.QtCore import Qt, QTimer, QRect, pyqtSignal from PyQt5.QtGui import QKeySequence from PyQt5.QtWidgets import QShortcut from PyQt5.QtWidgets import QSpacerItem, QSizePolicy from PyQt5.QtWidgets import QDesktopWidget from PyQt5.QtWidgets import ( QPushButton, QLabel, QHBoxLayout, ) from PyQt5.QtCore import QPoint from PyQt5.QtWidgets import QTextEdit from PyQt5 import QtGui from PyQt5.QtCore import QThread import pygame print("Imported all libraries") from PyQt5 import QtCore try: import ctypes myappid = "khulnasoft.gpt_computer_agent.gui.1" ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid) except: pass the_input_box = None the_input_text = None the_input_box_pre = None the_main_window = None user_id = load_user_id() os_name_ = os_name() from PyQt5.QtCore import QRegExp from PyQt5.QtGui import QSyntaxHighlighter, QTextCharFormat, QFont class PythonSyntaxHighlighter(QSyntaxHighlighter): def __init__(self, parent): super().__init__(parent) self.highlighting_rules = [] # Define different text formats with appropriate colors keyword_format = QTextCharFormat() keyword_format.setForeground(QColor(127, 0, 85)) # Dark purple for keywords built_in_formats = QTextCharFormat() built_in_formats.setForeground( QColor(42, 0, 255) ) # Dark blue for built-ins and constants string_format = QTextCharFormat() string_format.setForeground(QColor(0, 128, 0)) # Green for strings function_format = QTextCharFormat() function_format.setForeground(QColor(0, 0, 255)) # Blue for function names comment_format = QTextCharFormat() comment_format.setForeground(QColor(128, 128, 128)) # Gray for comments comment_format.setFontItalic(True) number_format = QTextCharFormat() number_format.setForeground(QColor(255, 0, 0)) # Red for numbers decorator_format = QTextCharFormat() decorator_format.setForeground(QColor(0, 0, 128)) # Navy blue for decorators # Markdown formatting header_format = QTextCharFormat() header_format.setForeground(QColor(0, 128, 128)) # Teal for headers header_format.setFontWeight(QFont.Bold) bold_format = QTextCharFormat() bold_format.setFontWeight(QFont.Bold) italic_format = QTextCharFormat() italic_format.setFontItalic(True) code_format = QTextCharFormat() code_format.setForeground(QColor(255, 140, 0)) # Dark orange for inline code code_format.setFontFamily("Courier New") code_format.setBackground( QColor(245, 245, 245) ) # Light gray background for inline code block_code_format = QTextCharFormat() block_code_format.setForeground( QColor(255, 140, 0) ) # Dark orange for code blocks block_code_format.setFontFamily("Courier New") block_code_format.setBackground( QColor(245, 245, 245) ) # Light gray background for code blocks # Define the regular expressions keywords = [ "def", "class", "if", "else", "elif", "return", "import", "from", "as", "for", "while", "try", "except", "finally", "with", "async", "await", "yield", "lambda", "global", "nonlocal", "assert", "del", "pass", "break", "continue", "and", "or", "not", "is", "in", ] self.highlighting_rules += [ (QRegExp(r"\b" + word + r"\b"), keyword_format) for word in keywords ] built_ins = [ "True", "False", "None", "__init__", "self", "print", "len", "range", "str", "int", "float", "list", "dict", "set", "tuple", ] self.highlighting_rules += [ (QRegExp(r"\b" + word + r"\b"), built_in_formats) for word in built_ins ] self.highlighting_rules.append( (QRegExp(r'"[^"\\]*(\\.[^"\\]*)*"'), string_format) ) self.highlighting_rules.append( (QRegExp(r"'[^'\\]*(\\.[^'\\]*)*'"), string_format) ) self.highlighting_rules.append((QRegExp(r"\bdef\b\s*(\w+)"), function_format)) self.highlighting_rules.append((QRegExp(r"\bclass\b\s*(\w+)"), function_format)) self.highlighting_rules.append((QRegExp(r"#.*"), comment_format)) self.highlighting_rules.append((QRegExp(r"\b[0-9]+[lL]?\b"), number_format)) self.highlighting_rules.append( (QRegExp(r"\b0[xX][0-9A-Fa-f]+[lL]?\b"), number_format) ) self.highlighting_rules.append( (QRegExp(r"\b0[oO]?[0-7]+[lL]?\b"), number_format) ) self.highlighting_rules.append((QRegExp(r"\b0[bB][01]+[lL]?\b"), number_format)) self.highlighting_rules.append((QRegExp(r"@[^\s]+"), decorator_format)) # Markdown rules self.highlighting_rules.append( (QRegExp(r"^#{1,6} .+"), header_format) ) # Headers self.highlighting_rules.append( (QRegExp(r"\*\*[^*]+\*\*"), bold_format) ) # **bold** self.highlighting_rules.append((QRegExp(r"__[^_]+__"), bold_format)) # __bold__ self.highlighting_rules.append( (QRegExp(r"\*[^*]+\*"), italic_format) ) # *italic* self.highlighting_rules.append((QRegExp(r"_[^_]+_"), italic_format)) # _italic_ self.highlighting_rules.append( (QRegExp(r"`[^`]+`"), code_format) ) # Inline code def highlightBlock(self, text): # Handle code blocks separately if text.strip().startswith("```"): self.setFormat(0, len(text), self.highlighting_rules[-1][1]) return for pattern, format in self.highlighting_rules: expression = QRegExp(pattern) index = expression.indexIn(text) while index >= 0: length = expression.matchedLength() self.setFormat(index, length, format) index = expression.indexIn(text, index + length) readed_sentences = [] import re def split_with_multiple_delimiters(text, delimiters): """ Splits the text by any of the given delimiters while keeping the delimiters in the resulting parts. :param text: The input text to be split. :param delimiters: A string of delimiters to split the text on. :return: A list of parts including the delimiters. """ # Create a regular expression pattern that matches any of the delimiters pattern = re.compile(f"(.*?[{re.escape(delimiters)}])") parts = pattern.findall(text) # Check if the last part is not complete and remove it if necessary if ( parts and text and not any(text.endswith(d) for d in delimiters) and parts and not any(parts[-1].endswith(d) for d in delimiters) ): parts.pop() return parts def click_sound(): pygame.mixer.init() retro = pygame.mixer.Sound(click_sound_path) retro.set_volume(0.1) retro.play() class Worker(QThread): text_to_set = pyqtSignal(str) def __init__(self): super().__init__() self.the_input_text = None self.make_animation = True self.commited_text = [] def run(self): while True: self.msleep(500) # Simulate a time-consuming task if self.the_input_text: last_text = ( self.commited_text[-1] if len(self.commited_text) > 0 else "" ) if self.the_input_text != last_text: self.commited_text.append(self.the_input_text) if len(self.the_input_text) > 90 or not self.make_animation: self.text_to_set.emit(self.the_input_text) else: for i in range(len(self.the_input_text)): self.text_to_set.emit(self.the_input_text[: i + 1]) self.msleep(10) return_key_event = None class CustomTextEdit(QTextEdit): def __init__(self, parent=None): super(CustomTextEdit, self).__init__(parent) def keyPressEvent(self, event): if event.key() == Qt.Key_Return or event.key() == Qt.Key_Enter: global return_key_event return_key_event() super(CustomTextEdit, self).keyPressEvent( event ) # Process other key events normally class Worker_2(QThread): text_to_set = pyqtSignal(str) text_to_set_title_bar = pyqtSignal(str) def __init__(self): super().__init__() self.the_input_text = None self.title_bar_text = None self.prev = None self.commited_text = [] def run(self): while True: self.msleep(500) # Simulate a time-consuming task if self.the_input_text and ( self.prev is None or self.prev != self.the_input_text ): self.prev = self.the_input_text self.text_to_set.emit("True") for i in range(len(self.title_bar_text)): self.text_to_set_title_bar.emit(self.title_bar_text[: i + 1]) self.msleep(10) if not self.the_input_text and self.prev != self.the_input_text: self.prev = self.the_input_text self.text_to_set.emit("False") the_text = " " + name() for i in range(len(the_text)): self.text_to_set_title_bar.emit(the_text[: i + 1]) self.msleep(10) class Worker_3(QThread): text_to_set = pyqtSignal(str) def __init__(self): super().__init__() self.the_input_text = None def run(self): while True: self.msleep(500) # Simulate a time-consuming task if self.the_input_text: self.text_to_set.emit("True") self.the_input_text = None class Worker_collapse(QThread): text_to_set = pyqtSignal(str) def __init__(self): super().__init__() self.the_input_text = None def run(self): while True: self.msleep(500) # Simulate a time-consuming task if self.the_input_text: self.text_to_set.emit("True") self.the_input_text = None class Worker_uncollapse(QThread): text_to_set = pyqtSignal(str) def __init__(self): super().__init__() self.the_input_text = None def run(self): while True: self.msleep(500) # Simulate a time-consuming task if self.the_input_text: self.text_to_set.emit("True") self.the_input_text = None class Worker_show_logo(QThread): text_to_set = pyqtSignal(str) def __init__(self): super().__init__() self.the_input_text = None def run(self): while True: self.msleep(500) # Simulate a time-consuming task if self.the_input_text: self.text_to_set.emit("True") self.the_input_text = None class Worker_hide_logo(QThread): text_to_set = pyqtSignal(str) def __init__(self): super().__init__() self.the_input_text = None def run(self): while True: self.msleep(500) # Simulate a time-consuming task if self.the_input_text: self.text_to_set.emit("True") self.the_input_text = None class Worker_activate_long_gca(QThread): text_to_set = pyqtSignal(str) def __init__(self): super().__init__() self.the_input_text = None def run(self): while True: self.msleep(500) # Simulate a time-consuming task if self.the_input_text: self.text_to_set.emit("True") self.the_input_text = None class Worker_deactivate_long_gca(QThread): text_to_set = pyqtSignal(str) def __init__(self): super().__init__() self.the_input_text = None def run(self): while True: self.msleep(500) # Simulate a time-consuming task if self.the_input_text: self.text_to_set.emit("True") self.the_input_text = None class Worker_tray_and_task_bar_logo(QThread): text_to_set = pyqtSignal(str) def __init__(self): super().__init__() self.the_input_text = None def run(self): while True: self.msleep(500) # Simulate a time-consuming task if self.the_input_text: self.text_to_set.emit("True") self.the_input_text = None class DrawingWidget(QWidget): def __init__(self, parent=None): super(DrawingWidget, self).__init__(parent) # Set widget properties if needed, e.g., size self.main_ = parent self.active_button = "" def paintEvent(self, event): if llm_settings[load_model_settings()]["vision"] is True: self.main_.screen_available = True else: self.main_.screen_available = False self.main_.setAutoFillBackground(True) painter = QPainter(self) painter = painter painter.setRenderHint(QPainter.Antialiasing) painter.setPen(QPen(QColor("#000"), 1)) painter.setBrush(QBrush(Qt.black, Qt.SolidPattern)) center_x = 95 center_y = 40 if "talking" in self.main_.state: # Draw a pulsating circle with smooth easing animation radius_variation = 5 * ( 1 + math.sin(self.main_.pulse_frame * math.pi / 100) ) radius = 70 + radius_variation painter.drawEllipse( int(center_x - radius / 2), int(center_y - radius / 2), int(radius), int(radius), ) elif self.main_.state == "thinking": # more slow pulsating circle with smooth easing animation radius_variation = 5 * ( 1 + math.sin(self.main_.pulse_frame * math.pi / 100) ) radius = 70 + radius_variation painter.drawEllipse( int(center_x - radius / 2), int(center_y - radius / 2), int(radius), int(radius), ) else: radius = 70 if self.main_.screen_available: painter.drawEllipse( # Main Button int(center_x - radius / 2), int(center_y - radius / 2), int(radius), int(radius), ) self.main_.circle_rect = QRect( int(center_x - radius / 2), int(center_y - radius / 2), int(radius), int(radius), ) if not self.main_.state == "thinking": painter.setPen(QPen(QColor("#01EE8A"), 1)) if self.main_.screen_available: painter.drawEllipse( # Main BUtton Green Border int(center_x - radius / 2), int(center_y - radius / 2), int(radius), int(radius), ) else: painter.setPen(QPen(QColor("#23538F"), 1)) painter.drawEllipse( int(center_x - radius / 2), int(center_y - radius / 2), int(radius), int(radius), ) painter.setPen(QPen(QColor("#000"), 1)) small_center_x = 165 small_center_y = 25 small_radius = 30 painter.drawEllipse( # Microphone bacground black int(small_center_x - small_radius / 2), int(small_center_y - small_radius / 2), int(small_radius), int(small_radius), ) self.main_.small_circle_rect = QRect( int(small_center_x - small_radius / 2), int(small_center_y - small_radius / 2), int(small_radius), int(small_radius), ) # Draw the icon inside the circle icon_size = small_radius * 2 // 3 # Adjust the icon size relative to the circle icon_rect = QRect( small_center_x - icon_size // 2, small_center_y - icon_size // 2, icon_size, icon_size, ) self.main_.small_circle_recticon = QIcon(microphone_icon_path) self.main_.small_circle_recticon.paint(painter, icon_rect) small_center_x = 30 small_center_y = 60 small_radius = 30 painter.drawEllipse( int(small_center_x - small_radius / 2), int(small_center_y - small_radius / 2), int(small_radius), int(small_radius), ) self.main_.small_circle_left = QRect( int(small_center_x - small_radius / 2), int(small_center_y - small_radius / 2), int(small_radius), int(small_radius), ) # Draw the icon inside the circle icon_size = small_radius * 2 // 3 # Adjust the icon size relative to the circle icon_rect = QRect( small_center_x - icon_size // 2, small_center_y - icon_size // 2, icon_size, icon_size, ) self.main_.small_circle_lefticon = QIcon(audio_icon_path) self.main_.small_circle_lefticon.paint(painter, icon_rect) small_center_x = 30 small_center_y = 25 small_radius = 30 if self.main_.screen_available: painter.drawEllipse( # ScreenShot BUtton int(small_center_x - small_radius / 2), int(small_center_y - small_radius / 2), int(small_radius), int(small_radius), ) self.main_.small_circle_left_top = QRect( int(small_center_x - small_radius / 2), int(small_center_y - small_radius / 2), int(small_radius), int(small_radius), ) self.main_.screenshot_button_coordinates_size = [ int(small_center_x - small_radius / 2), int(small_center_y - small_radius / 2), int(small_radius), int(small_radius), ] if self.active_button == "screenshot": self.screenshot_button_border_activate(painter) self.active_button = "" if self.main_.screen_available: # Draw the icon inside the circle icon_size = ( small_radius * 2 // 3 ) # Adjust the icon size relative to the circle icon_rect = QRect( small_center_x - icon_size // 2, small_center_y - icon_size // 2, icon_size, icon_size, ) self.main_.small_circle_left_topticon = QIcon(screenshot_icon_path) self.main_.small_circle_left_topticon.paint(painter, icon_rect) small_center_x = 165 small_center_y = 60 small_radius = 30 painter.drawEllipse( int(small_center_x - small_radius / 2), int(small_center_y - small_radius / 2), int(small_radius), int(small_radius), ) self.main_.small_circle_collapse = QRect( int(small_center_x - small_radius / 2), int(small_center_y - small_radius / 2), int(small_radius), int(small_radius), ) # Draw the icon inside the circle icon_size = small_radius * 2 // 3 # Adjust the icon size relative to the circle icon_rect = QRect( small_center_x - icon_size // 2, small_center_y - icon_size // 2, icon_size, icon_size, ) if is_collapse_setting_active(): self.main_.small_circle_collapse_icon = QIcon(down_icon_path) if not is_collapse_setting_active() and is_long_gca_setting_active(): self.main_.small_circle_collapse_icon = QIcon(up_icon_path) if not is_collapse_setting_active() and not is_long_gca_setting_active(): self.main_.small_circle_collapse_icon = QIcon(down_icon_path) self.main_.small_circle_collapse_icon.paint(painter, icon_rect) def screenshot_button_border_activate(self, painter): # Add an white border to the circle painter.setPen(QPen(QColor("#FFF"), 1)) # Draw the ellipse with the specified green border self.main_.screenshot_button_border = painter.drawEllipse( self.main_.screenshot_button_coordinates_size[0], self.main_.screenshot_button_coordinates_size[1], self.main_.screenshot_button_coordinates_size[2], self.main_.screenshot_button_coordinates_size[3], ) painter.setPen(QPen(QColor("#000"), 1)) def mousePressEvent(self, event: QMouseEvent): self.main_.old_position = event.globalPos() with my_tracer.start_span("mouse_press_event") as span: span.set_attribute("user_id", user_id) span.set_attribute("os_name", os_name_) if self.main_.state == "idle" or "talking" in self.main_.state: try: if self.main_.circle_rect.contains(event.pos()): if self.main_.state == "aitalking": self.main_.stop_ai_talking() else: self.main_.screenshot_and_microphone_button_action() except: traceback.print_exc() try: if self.main_.small_circle_rect.contains(event.pos()): if self.main_.state == "aitalking": self.main_.stop_ai_talking() else: click_sound() self.main_.button_handler.toggle_recording( no_screenshot=True ) except: traceback.print_exc() try: if self.main_.small_circle_left.contains(event.pos()): if self.main_.state == "aitalking": self.main_.stop_ai_talking() else: click_sound() self.main_.button_handler.toggle_recording( take_system_audio=True ) except: traceback.print_exc() try: if self.main_.small_circle_left_top.contains(event.pos()): if self.main_.state == "aitalking": self.main_.stop_ai_talking() else: click_sound() self.active_button = "screenshot" self.update() self.main_.button_handler.just_screenshot() except: traceback.print_exc() try: if self.main_.small_circle_collapse.contains(event.pos()): if not is_collapse_setting_active(): if is_long_gca_setting_active(): self.main_.deactivate_long_gca() self.main_.collapse_gca() else: self.main_.activate_long_gca() else: self.main_.uncollapse_gca() self.main_.update() except: pass from PyQt5.QtCore import QVariantAnimation class MainWindow(QMainWindow): api_enabled = False tts_available = True def screenshot_and_microphone_button_action(self): click_sound() if llm_settings[load_model_settings()]["vision"] is True: self.button_handler.toggle_recording(dont_save_image=True) else: self.button_handler.toggle_recording(no_screenshot=True) def stop_ai_talking(self): self.manuel_stop = True self.stop_talking = True def __init__(self): super().__init__() self.background_color = "45, 45, 45" self.opacity = 250 self.border_radius = 10 print("API Enabled:", MainWindow.api_enabled) if MainWindow.api_enabled: try: from .api import start_api start_api() except: raise Exception( "API could not be started, please install gpt-computer-agent[api]" ) self.stop_talking = False self.setWindowFlags( Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint ) # Remove the default title bar # Load the San Francisco font print("Loading font") print(font_dir) try: font_id = QtGui.QFontDatabase.addApplicationFont(font_dir) font_family = QtGui.QFontDatabase.applicationFontFamilies(font_id)[0] self.setFont(QtGui.QFont(font_family)) except: print("Error loading font") self.state = "idle" self.pulse_timer = None self.button_handler = ButtonHandler(self) self.initUI() self.old_position = self.pos() self.collapse = is_collapse_setting_active() if self.collapse: self.collapse_window() global the_main_window the_main_window = self self.general_styling() if is_dark_mode_active(): self.dark_mode() else: self.light_mode() self.wake_word_thread = None self.wake_word_active = False if load_pvporcupine_api_key() != "CHANGE_ME" and is_wake_word_active(): self.wake_word_active = True self.wake_word_trigger() self.manuel_stop = False self.border_animation = None self.complated_answer = False self.reading_thread = False self.reading_thread_2 = False image_layout = QHBoxLayout() self.the_image = QLabel(self) self.the_image.setPixmap(QtGui.QPixmap(load_logo_file_path()).scaled(25, 25)) image_layout.addWidget(self.the_image) self.layout.addLayout(image_layout) self.the_image.setAlignment(Qt.AlignCenter) self.the_image.setFixedHeight(35) # Logo Adding if not is_logo_active_setting_active(): self.the_image.hide() self.update_screen() def put_location(self): if load_location_setting() == "right": self.put_window_to_right_side_of_screen() def init_border_animation(self): # Create a QVariantAnimation to handle color change border_animation = QVariantAnimation( self, valueChanged=self.update_border_color, startValue=QColor("#303030"), endValue=QColor("#23538F"), duration=2000, # Duration for one loop in milliseconds ) border_animation.setLoopCount(-1) # Loop indefinitely return border_animation def start_border_animation(self, status): print("FUNCTION TRİGGERED") if self.border_animation is None: self.border_animation = self.init_border_animation() status = status.lower() == "true" if status: self.border_animation.start() else: self.border_animation.stop() self.title_bar.setStyleSheet( "background-color: #2E2E2E; color: white; border-style: solid; border-radius: 15px; border-width: 0px; color: #fff;" ) def update_border_color(self, color): self.title_bar.setStyleSheet( f"background-color: #2E2E2E; color: white; border-style: solid; border-radius: 15px; border-width: 2px; border-color: {color.name()}; color: #fff;" ) self.title_bar.setStyleSheet( f"background-color: #2E2E2E; color: white; border-style: solid; border-radius: 15px; border-width: 1px; border-color: {color.name()}; color: #fff;" ) # Existing methods... def general_styling(self, a=None): self.setAttribute(Qt.WA_TranslucentBackground) self.setStyleSheet( f"border-radius: {self.border_radius}px; background-color: rgba({self.background_color}, {self.opacity});" ) self.central_widget.setStyleSheet( "border-style: solid; border-width: 1px; border-color: rgb(0,0,0,0);" ) self.input_box_style = "border-radius: 10px; border-bottom: 1px solid #01EE8A;" self.settingsButton_style = ( "border-radius: 5px; height: 25px; border-style: solid;" ) self.llmsettingsButton_style = ( "border-radius: 5px; height: 25px; border-style: solid;" ) self.btn_minimize.setStyleSheet( "background-color: #2E2E2E; color: white; border-style: none;" ) self.btn_close.setStyleSheet( "background-color: #2E2E2E; color: white; border-style: none;" ) def set_background_color(self, color): self.background_color = color self.worker_3.the_input_text = "True" def set_opacity(self, opacity): self.opacity = opacity self.worker_3.the_input_text = "True" def set_border_radius(self, radius): self.border_radius = radius self.worker_3.the_input_text = "True" def wake_word_trigger(self): self.wake_word_thread = threading.Thread(target=self.wake_word) self.wake_word_thread.start() def wake_word(self): from .agent.process import tts_if_you_can while True and is_wake_word_active() and self.wake_word_active: if wake_word(self): def random_accept_words(): return random.choice(["Yes", "Sir", "Boss", "Master"]) tts_if_you_can(random_accept_words(), not_threaded=True) def trigger_wake_word(): if ( is_wake_word_screen_setting_active() and llm_settings[load_model_settings()]["vision"] ): self.button_handler.toggle_recording(dont_save_image=True) else: self.button_handler.toggle_recording(no_screenshot=True) if self.state == "aitalking": self.manuel_stop = True self.stop_talking = True time.sleep(1) trigger_wake_word() print("Stop talking") else: trigger_wake_word() def dark_mode(self): self.setAutoFillBackground(True) p = self.palette() p.setColor( self.backgroundRole(), QColor("#171717") ) # Set background color to white self.setPalette(p) self.input_box.setStyleSheet( self.input_box_style + "background-color: #2E2E2E; color: white;" ) self.settingsButton.setStyleSheet( self.settingsButton_style + "background-color: #2E2E2E; color: white;" ) self.llmsettingsButton.setStyleSheet( self.llmsettingsButton_style + "background-color: #2E2E2E; color: white;" ) def light_mode(self): self.setAutoFillBackground(True) p = self.palette() p.setColor(self.backgroundRole(), QColor("#F0F0F0")) self.setPalette(p) self.input_box.setStyleSheet( self.input_box_style + "background-color: #FFFFFF; color: black;" ) self.settingsButton.setStyleSheet( self.settingsButton_style + "background-color: #FFFFFF; color: black; " ) self.llmsettingsButton.setStyleSheet( self.llmsettingsButton_style + "background-color: #FFFFFF; color: black; " ) def collapse_window(self): the_input_box.hide() self.settingsButton.hide() self.llmsettingsButton.hide() self.update_screen() def initUI(self): self.setWindowTitle("GPT") self.setGeometry(100, 100, 200, 200) width = 210 height = 300 # setting the minimum size self.setMinimumSize(width, height) self.first_height = self.height() self.first_width = self.width() self.central_widget = QWidget(self) self.setCentralWidget(self.central_widget) layout = QVBoxLayout(self.central_widget) # Custom title bar self.title_bar = QWidget(self) self.title_bar.setFixedHeight(30) # Set a fixed height for the title bar self.title_bar.setStyleSheet( "background-color: #2E2E2E; color: #fff; border-radius: 15px; border-style: solid; border-width: 1px; border-color: #303030;" ) self.title_bar_layout = QHBoxLayout(self.title_bar) self.title_bar_layout.setContentsMargins(5, 5, 0, 5) self.title_bar_layout.setSpacing(0) self.btn_minimize = QPushButton("-", self.title_bar) self.btn_minimize.setFixedSize(20, 20) self.btn_minimize.clicked.connect(self.showMinimized) def stop_app(): self.stop_talking = True self.wake_word_active = False if MainWindow.api_enabled: from .api import stop_api stop_api() self.close() self.btn_close = QPushButton("×", self.title_bar) self.btn_close.setFixedSize(20, 20) self.btn_close.clicked.connect(stop_app) self.title_label = QLabel(" " + name(), self.title_bar) # Change font size font = QtGui.QFont() font.setPointSize(11) self.title_label.setFont(font) self.title_label.setStyleSheet("border: 0px solid blue;") self.title_bar_layout.addWidget(self.title_label) self.title_bar_layout.addStretch() self.title_bar_layout.addWidget(self.btn_minimize) self.title_bar_layout.addWidget(self.btn_close) # Create a spacer item with expanding policy spacer = QSpacerItem(5, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.title_bar_layout.addSpacerItem(spacer) # Add spacer to the layout layout.addWidget(self.title_bar) self.drawing_widget = DrawingWidget(self) layout.addWidget(self.drawing_widget) self.layout = layout self.setLayout(layout) # Add keyboard shortcuts self.shortcut_screenshot = QShortcut(QKeySequence("Ctrl+1"), self) self.shortcut_screenshot.activated.connect( lambda: self.button_handler.just_screenshot() ) self.shortcut_screenshot = QShortcut(QKeySequence("Ctrl+2"), self) self.shortcut_screenshot.activated.connect( lambda: self.button_handler.toggle_recording(take_system_audio=True) ) self.shortcut_no_screenshot = QShortcut(QKeySequence("Ctrl+e"), self) self.shortcut_no_screenshot.activated.connect( lambda: self.button_handler.toggle_recording(take_system_audio=True) ) self.shortcut_no_screenshot = QShortcut(QKeySequence("Ctrl+3"), self) self.shortcut_no_screenshot.activated.connect( lambda: self.button_handler.toggle_recording(no_screenshot=True) ) # I want to create an input box to bottom left and a send button to bottom right input_box = CustomTextEdit(self) self.input_box = input_box input_box.setFixedHeight(80) # Set text wrapping. I dont wat to cut the text input_box.setWordWrapMode(QtGui.QTextOption.NoWrap) # Change the font size font = QtGui.QFont() font.setPointSize(12) input_box.setFont(font) self.highlighter = PythonSyntaxHighlighter(self.input_box.document()) if load_api_key() == "CHANGE_ME": input_box.setPlaceholderText("Save your API Key, go to settings") else: if platform.system() == "Darwin": if llm_settings[load_model_settings()]["vision"] is False: input_box.setPlaceholderText("Type here \nsand ↵ ") else: input_box.setPlaceholderText( "Type here \nand ↵ \nor ⌘ + ↵ (+screenshot)" ) else: if llm_settings[load_model_settings()]["vision"] is False: input_box.setPlaceholderText("Type here \nand ↵ ") else: input_box.setPlaceholderText( "Type here \nand ↵ \nor Ctrl + ↵ (+screenshot)" ) # Add an information and use enter icon to the input box for mac input_box.setGeometry(30, self.height() - 60, 200, 80) global the_input_box the_input_box = input_box def input_box_send(): if input_box.toPlainText() != "": click_sound() self.button_handler.input_text(input_box.toPlainText()) def input_box_send_screenshot(): if input_box.toPlainText() != "": click_sound() self.button_handler.input_text_screenshot(input_box.toPlainText()) self.layout.addWidget(input_box) self.shortcut_enter = QShortcut(QKeySequence("Ctrl+Return"), self) self.shortcut_enter.activated.connect(input_box_send_screenshot) global return_key_event return_key_event = input_box_send button_layout_ = QHBoxLayout() self.settingsButton = QPushButton("Chat Settings", self) self.settingsButton.clicked.connect(settings_popup) self.llmsettingsButton = QPushButton("LLM Settings", self) self.llmsettingsButton.clicked.connect(llmsettings_popup) button_layout_.addWidget(self.settingsButton) button_layout_.addWidget(self.llmsettingsButton) self.layout.addLayout(button_layout_) self.worker = Worker() self.worker.text_to_set.connect(self.set_text) self.worker.start() self.worker_2 = Worker_2() self.worker_2.text_to_set.connect(self.start_border_animation) self.worker_2.text_to_set_title_bar.connect(self.set_title_bar_text) self.worker_2.start() self.worker_3 = Worker_3() self.worker_3.text_to_set.connect(self.general_styling) self.worker_3.start() self.worker_collapse = Worker_collapse() self.worker_collapse.text_to_set.connect(self.collapse_gca) self.worker_collapse.start() self.worker_uncollapse = Worker_uncollapse() self.worker_uncollapse.text_to_set.connect(self.uncollapse_gca) self.worker_uncollapse.start() self.worker_show_logo = Worker_show_logo() self.worker_show_logo.text_to_set.connect(self.show_logo) self.worker_show_logo.start() self.worker_hide_logo = Worker_hide_logo() self.worker_hide_logo.text_to_set.connect(self.hide_logo) self.worker_hide_logo.start() self.worker_activate_long_gca = Worker_activate_long_gca() self.worker_activate_long_gca.text_to_set.connect(self.activate_long_gca) self.worker_activate_long_gca.start() self.worker_deactivate_long_gca = Worker_deactivate_long_gca() self.worker_deactivate_long_gca.text_to_set.connect(self.deactivate_long_gca) self.worker_deactivate_long_gca.start() self.worker_tray_and_task_bar_logo = Worker_tray_and_task_bar_logo() self.worker_tray_and_task_bar_logo.text_to_set.connect( self.tray_and_task_bar_logo ) self.worker_tray_and_task_bar_logo.start() # print height and width print(self.height(), self.width()) self.show() def set_text(self, text): global the_input_box vertical_scrollbar = the_input_box.verticalScrollBar() scroll_value = vertical_scrollbar.value() the_input_box.setPlainText(text) vertical_scrollbar.setValue(scroll_value) def set_title_bar_text(self, text): self.title_label.setText(text) def update_from_thread(self, text, system=True): self.worker.make_animation = True if system: text = "System: " + text print("Updating from thread", text) self.worker.the_input_text = text def read_part_task_generate_only(self): if not is_just_text_model_active() and the_main_window.tts_available: threads = {} the_okey_parts = split_with_multiple_delimiters( self.worker.the_input_text, ".?!:" ) for each in the_okey_parts: if the_main_window.stop_talking: break the_thread = threading.Thread(target=text_to_speech, args=(each,)) threads[each] = the_thread the_thread.start() for each in threads.values(): each.join() self.reading_thread_2 = False def read_part_task(self): if not is_just_text_model_active() and the_main_window.tts_available: threads = {} the_okey_parts = split_with_multiple_delimiters( self.worker.the_input_text, ".?!:" ) will_read_parts = [] for each in the_okey_parts: if the_main_window.stop_talking: break if each not in readed_sentences: will_read_parts.append(each) readed_sentences.append(each) the_thread = threading.Thread(target=text_to_speech, args=(each,)) threads[each] = the_thread the_thread.start() for each in will_read_parts: if the_main_window.stop_talking: break threads[each].join() tts_if_you_can(each, not_threaded=True, bypass_other_settings=True) self.reading_thread = False def set_text_to_input_box(self, text): global readed_sentences self.worker.make_animation = False if self.worker.the_input_text.startswith("System:") or self.complated_answer: self.worker.the_input_text = "" self.complated_answer = False readed_sentences = [] if text not in (">", "<>", ">\n", "<", "<\n"): self.worker.the_input_text += text if self.reading_thread is not True and len(self.worker.the_input_text) > 40: self.reading_thread = True threading.Thread(target=self.read_part_task).start() if ( self.reading_thread_2 is not True and len(self.worker.the_input_text) > 250 ): self.reading_thread_2 = True threading.Thread(target=self.read_part_task_generate_only).start() else: print("Problem on text chars") def set_text_from_api(self, text): self.worker.make_animation = True self.worker.the_input_text = text def active_border_animation(self, title_bar_text=None): if self.worker_2.title_bar_text is not None: if self.worker_2.title_bar_text != title_bar_text: return self.worker_2.the_input_text = True if title_bar_text is None: title_bar_text = " " + name() else: title_bar_text = f" {title_bar_text}" if len(title_bar_text) > 33: title_bar_text = title_bar_text[:30] + "..." self.worker_2.title_bar_text = title_bar_text self.btn_minimize.hide() self.btn_close.hide() def deactive_border_animation(self, title_bar_text=None): if title_bar_text is None: title_bar_text = " " + name() else: title_bar_text = f" {title_bar_text}" if len(title_bar_text) > 33: title_bar_text = title_bar_text[:30] + "..." if self.worker_2.title_bar_text is not None: if self.worker_2.title_bar_text != title_bar_text: return self.worker_2.the_input_text = False self.worker_2.title_bar_text = None time.sleep(1) self.btn_minimize.show() self.btn_close.show() def mouseMoveEvent(self, event: QMouseEvent): delta = QPoint(event.globalPos() - self.old_position) if event.buttons() == Qt.LeftButton and self.title_bar.underMouse(): self.move(self.x() + delta.x(), self.y() + delta.y()) self.old_position = event.globalPos() def mousePressEvent(self, event: QMouseEvent): self.old_position = event.globalPos() def remove_screenshot_button(self): self.update() def add_screenshot_button(self): self.update() def update_state(self, new_state): assistant_stopped = False if self.state == "aitalking" and new_state == "idle": assistant_stopped = True if self.manuel_stop: assistant_stopped = False self.manuel_stop = False self.state = new_state print(f"State updated: {new_state}") if "talking" in new_state: self.tray.setIcon(self.tray_active_icon) self.pulse_frame = 0 if self.pulse_timer: self.pulse_timer.stop() self.pulse_timer = None self.pulse_timer = QTimer(self) self.pulse_timer.timeout.connect(self.pulse_circle) self.pulse_timer.start(5) elif new_state == "thinking": the_main_window.update_from_thread("Thinking...") self.pulse_frame = 0 if self.pulse_timer: self.pulse_timer.stop() self.pulse_timer = None self.pulse_timer = QTimer(self) self.pulse_timer.timeout.connect(self.pulse_circle) self.pulse_timer.start(20) elif self.pulse_timer: self.tray.setIcon(self.tray_icon) self.pulse_timer.stop() self.pulse_timer = None self.update() # Trigger a repaint if assistant_stopped: global the_input_box if ( the_input_box.toPlainText().endswith("?") and is_continuously_conversations_setting_active() ): self.button_handler.toggle_recording( no_screenshot=True, new_record=True ) if new_state == "idle": click_sound() def pulse_circle(self): self.pulse_frame = (self.pulse_frame + 1) % 100 self.update() def collapse_gca(self): self.collapse = True self.collapse_window() activate_collapse_setting() self.update_screen() def collapse_gca_api(self): self.worker_collapse.the_input_text = "True" def uncollapse_gca(self): self.collapse = False print() # hide all buttons and input box the_input_box.show() self.settingsButton.show() self.llmsettingsButton.show() deactivate_collapse_setting() self.update_screen() def uncollapse_gca_api(self): self.worker_uncollapse.the_input_text = "True" def show_logo(self): self.the_image.setPixmap(QtGui.QPixmap(load_logo_file_path()).scaled(25, 25)) self.the_image.show() self.update_screen() def tray_and_task_bar_logo(self): app_icon = QtGui.QIcon() app_icon.addFile(load_logo_file_path(), QtCore.QSize(48, 48)) self.the_app.setWindowIcon(app_icon) self.tray.setIcon(app_icon) self.tray_icon = app_icon self.tray_active_icon = app_icon print("ICON Set", load_logo_file_path()) def tray_and_task_bar_logo_api(self): self.worker_tray_and_task_bar_logo.the_input_text = "True" def show_logo_api(self): self.worker_show_logo.the_input_text = "True" def hide_logo(self): self.the_image.hide() self.update_screen() def hide_logo_api(self): self.worker_hide_logo.the_input_text = "True" def activate_long_gca(self): activate_long_gca_setting() self.update_screen() def activate_long_gca_api(self): self.worker_activate_long_gca.the_input_text = "True" def deactivate_long_gca(self): deactivate_long_gca_setting() self.update_screen() def deactivate_long_gca_api(self): self.worker_deactivate_long_gca.the_input_text = "True" def update_screen(self): width = 210 height = 320 if is_logo_active_setting_active(): height += 35 if is_collapse_setting_active(): height = 150 if is_logo_active_setting_active(): height += 35 if is_long_gca_setting_active(): if not is_collapse_setting_active(): height += 500 self.input_box.setFixedHeight(580) else: self.input_box.setFixedHeight(80) self.setFixedSize(width, height) self.put_location() def put_window_to_right_side_of_screen(self): screen = QDesktopWidget().screenGeometry() window = self.frameGeometry() # Calculate x position for the right side of the screen and center vertically x = screen.width() - window.width() # To right side y = (screen.height() - window.height()) // 2 # Center vertically # Add a small offset to the right side x -= 10 self.move(x, y)