Skip to content

Commit

Permalink
Merge pull request #41 from dougollerenshaw/clean_up_inheritance
Browse files Browse the repository at this point in the history
Clean up inheritance
  • Loading branch information
dougollerenshaw authored Oct 4, 2024
2 parents 13d3895 + c5239b2 commit 640375b
Show file tree
Hide file tree
Showing 7 changed files with 203 additions and 145 deletions.
7 changes: 2 additions & 5 deletions codeaide/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from PyQt5.QtWidgets import QApplication

from codeaide.logic.chat_handler import ChatHandler
from codeaide.ui.chat_window import ChatWindow
from codeaide.utils import api_utils


Expand All @@ -20,10 +19,8 @@ def main():
print("Error:", message)
else:
app = QApplication(sys.argv)
chat_window = ChatWindow(chat_handler)
chat_handler.set_main_window(chat_window)
chat_window.show()
app.exec_()
chat_handler.start_application()
sys.exit(app.exec_())


if __name__ == "__main__":
Expand Down
90 changes: 37 additions & 53 deletions codeaide/logic/chat_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,18 @@
from codeaide.utils.logging_config import get_logger, setup_logger
from PyQt5.QtWidgets import QMessageBox, QTextEdit
from PyQt5.QtGui import QFont
from PyQt5.QtCore import QObject, QMetaObject, Qt, Q_ARG, pyqtSlot
from PyQt5.QtCore import QObject, QMetaObject, Qt, Q_ARG, pyqtSlot, pyqtSignal
from codeaide.ui.traceback_dialog import TracebackDialog


class ChatHandler(QObject):
# Define custom signals for updating the chat and showing code
update_chat_signal = pyqtSignal(
str, str
) # Signal to update chat with (role, message)
show_code_signal = pyqtSignal(str, str) # Signal to show code with (code, version)
traceback_occurred = pyqtSignal(str)

def __init__(self):
super().__init__()
"""
Expand All @@ -50,7 +58,7 @@ def __init__(self):
self.logger = get_logger()
self.conversation_history = self.file_handler.load_chat_history()
self.terminal_manager = TerminalManager(
traceback_callback=self.show_traceback_dialog
traceback_callback=self.emit_traceback_signal
)
self.latest_version = "0.0"
self.api_client = None
Expand All @@ -64,7 +72,21 @@ def __init__(self):
self.api_key_valid, self.api_key_message = self.check_api_key()
self.logger.info(f"New session started with ID: {self.session_id}")
self.logger.info(f"Session directory: {self.session_dir}")
self.main_window = None # We'll set this later
self.chat_window = None

def start_application(self):
from codeaide.ui.chat_window import (
ChatWindow,
) # Import here to avoid circular imports

self.chat_window = ChatWindow(self)
self.connect_signals()
self.chat_window.show()

def connect_signals(self):
self.update_chat_signal.connect(self.chat_window.add_to_chat)
self.show_code_signal.connect(self.chat_window.show_code)
self.traceback_occurred.connect(self.chat_window.show_traceback_dialog)

def check_api_key(self):
"""
Expand Down Expand Up @@ -570,60 +592,22 @@ def load_previous_session(self, session_id, chat_window):

self.logger.info(f"Loaded previous session with ID: {self.session_id}")

def set_main_window(self, main_window):
self.main_window = main_window
self.logger.info(f"Main window set: {self.main_window}")

def show_traceback_dialog(self, traceback_text):
self.logger.info(f"show_traceback_dialog called with: {traceback_text}")
if self.main_window:
QMetaObject.invokeMethod(
self,
"_display_traceback_dialog",
Qt.QueuedConnection,
Q_ARG(str, traceback_text),
)
else:
self.logger.info("self.main_window is None")

@pyqtSlot(str)
def _display_traceback_dialog(self, traceback_text):
self.logger.info(f"_display_traceback_dialog called with: {traceback_text}")
msg_box = QMessageBox(self.main_window)
msg_box.setWindowTitle("Error Detected")
msg_box.setText("An error was detected in the running script:")
msg_box.setInformativeText(traceback_text)
msg_box.setIcon(QMessageBox.Warning)

# Create custom buttons
send_button = msg_box.addButton("Request a fix", QMessageBox.ActionRole)
ignore_button = msg_box.addButton("Ignore", QMessageBox.RejectRole)

# Set a fixed width for the dialog
msg_box.setFixedWidth(600)

# Make the dialog resizable
msg_box.setSizeGripEnabled(True)

# Set a monospace font for the traceback text
text_browser = msg_box.findChild(QTextEdit)
if text_browser:
font = QFont("Courier")
font.setStyleHint(QFont.Monospace)
font.setFixedPitch(True)
font.setPointSize(10)
text_browser.setFont(font)

msg_box.exec_()

if msg_box.clickedButton() == send_button:
self.send_traceback_to_agent(traceback_text)
def emit_traceback_signal(self, traceback_text):
self.logger.info(
f"ChatHandler: Emitting traceback signal with text: {traceback_text[:50]}..."
)
self.traceback_occurred.emit(traceback_text)

def send_traceback_to_agent(self, traceback_text):
self.logger.info(
f"ChatHandler: Sending traceback to agent: {traceback_text[:50]}..."
)
message = (
"The following error occurred when running the code you just provided:\n\n"
f"```\n{traceback_text}\n```\n\n"
"Please provide a solution that avoids this error."
)
self.main_window.input_text.setPlainText(message)
self.main_window.on_submit()
self.logger.info(f"ChatHandler: Setting input text in chat window")
self.chat_window.input_text.setPlainText(message)
self.logger.info(f"ChatHandler: Calling on_submit in chat window")
self.chat_window.on_submit()
51 changes: 44 additions & 7 deletions codeaide/ui/chat_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
MODEL_SWITCH_MESSAGE,
)
from codeaide.utils.logging_config import get_logger
from codeaide.ui.traceback_dialog import TracebackDialog


class ChatWindow(QMainWindow):
Expand Down Expand Up @@ -160,15 +161,18 @@ def eventFilter(self, obj, event):

def on_submit(self):
user_input = self.input_text.toPlainText().strip()
self.logger.info(
f"ChatWindow: on_submit called with input: {user_input[:50]}..."
)
if not user_input:
self.logger.info("ChatWindow: Empty input, returning")
return

self.logger.info(f"User input: {user_input}")

# Clear the input field immediately
self.logger.info(f"ChatWindow: Processing user input")
self.input_text.clear()

if self.waiting_for_api_key:
self.logger.info("ChatWindow: Handling API key input")
(
success,
message,
Expand All @@ -179,17 +183,21 @@ def on_submit(self):
if success:
self.enable_ui_elements()
else:
# Immediately display user input and "Thinking..." message
self.logger.info("ChatWindow: Adding user input to chat")
self.add_to_chat("User", user_input)
self.disable_ui_elements()
self.add_to_chat("AI", "Thinking... 🤔")

# Use QTimer to process the input after the UI has updated
self.logger.info("ChatWindow: Scheduling call_process_input_async")
QTimer.singleShot(100, lambda: self.call_process_input_async(user_input))

def call_process_input_async(self, user_input):
# Process the input
self.logger.info(
f"ChatWindow: call_process_input_async called with input: {user_input[:50]}..."
)
response = self.chat_handler.process_input(user_input)
self.logger.info(
f"ChatWindow: Received response from chat handler: {str(response)[:50]}..."
)
self.handle_response(response)

def on_modify(self):
Expand Down Expand Up @@ -270,6 +278,7 @@ def update_or_create_code_popup(self, response):
self.code_popup = CodePopup(
self,
self.chat_handler.file_handler,
self.chat_handler.terminal_manager,
code,
requirements,
self.chat_handler.run_generated_code,
Expand Down Expand Up @@ -398,3 +407,31 @@ def load_chat_contents(self):
for item in self.chat_contents:
self.add_to_chat(item["sender"], item["message"])
self.logger.info(f"Loaded {len(self.chat_contents)} messages from chat log")

def show_code(self, code, version):
if not self.code_popup:
self.code_popup = CodePopup(
self,
self.chat_handler.file_handler,
code,
[],
self.chat_handler.run_generated_code,
chat_handler=self.chat_handler,
)
else:
self.code_popup.update_with_new_version(code, [])
self.code_popup.show()
self.code_popup.raise_()
self.code_popup.activateWindow()

def show_traceback_dialog(self, traceback_text):
self.logger.info(
f"ChatWindow: show_traceback_dialog called with text: {traceback_text[:50]}..."
)
dialog = TracebackDialog(self, traceback_text)
self.logger.info("ChatWindow: Showing TracebackDialog")
if dialog.exec_():
self.logger.info("ChatWindow: User requested to fix the traceback")
self.chat_handler.send_traceback_to_agent(traceback_text)
else:
self.logger.info("ChatWindow: User chose to ignore the traceback")
25 changes: 12 additions & 13 deletions codeaide/ui/code_popup.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
QWidget,
QPlainTextEdit,
QMessageBox,
QDialog,
)
from pygments import highlight
from pygments.lexers import PythonLexer
Expand All @@ -33,7 +34,6 @@
CODE_WINDOW_HEIGHT,
CODE_WINDOW_WIDTH,
)
from codeaide.utils.terminal_manager import TerminalManager


class LineNumberArea(QWidget):
Expand Down Expand Up @@ -242,14 +242,22 @@ def highlightBlock(self, text):
self.setCurrentBlockState(0)


class CodePopup(QWidget):
class CodePopup(QDialog):
def __init__(
self, parent, file_handler, code, requirements, run_callback, chat_handler
self,
parent,
file_handler,
terminal_manager,
code,
requirements,
run_callback,
chat_handler,
):
super().__init__(parent, Qt.Window)
super().__init__(parent)
self.setWindowTitle("💻 Generated Code 💻")
self.resize(CODE_WINDOW_WIDTH, CODE_WINDOW_HEIGHT)
self.file_handler = file_handler
self.terminal_manager = terminal_manager
self.run_callback = run_callback
self.setup_ui()
self.load_versions()
Expand All @@ -261,14 +269,6 @@ def __init__(
# Use the chat_handler passed as an argument, or try to get it from the parent
self.chat_handler = chat_handler or (parent.chat_handler if parent else None)

# Create TerminalManager with a safe traceback callback
self.terminal_manager = TerminalManager(
traceback_callback=self.safe_show_traceback_dialog
)

def safe_show_traceback_dialog(self, traceback_text):
self.chat_handler.show_traceback_dialog(traceback_text)

def setup_ui(self):
layout = QVBoxLayout(self)
layout.setSpacing(5)
Expand Down Expand Up @@ -370,7 +370,6 @@ def on_run(self):
with open(req_path, "w") as f:
f.write("\n".join(requirements))

# Assuming you have a TerminalManager instance available as self.terminal_manager
self.terminal_manager.run_script(code_path, req_path)

def on_copy_code(self):
Expand Down
44 changes: 44 additions & 0 deletions codeaide/ui/traceback_dialog.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
from PyQt5.QtWidgets import QMessageBox, QTextEdit
from PyQt5.QtGui import QFont
from PyQt5.QtCore import Qt
import logging


def get_logger():
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
return logger


class TracebackDialog(QMessageBox):
def __init__(self, parent, traceback_text):
super().__init__(parent)
self.logger = get_logger()
self.logger.info(
f"TracebackDialog: Initializing with text: {traceback_text[:50]}..."
)
self.setWindowTitle("Error Detected")
self.setText("An error was detected in the running script:")
self.setInformativeText(traceback_text)
self.setIcon(QMessageBox.Warning)

self.setFixedWidth(600)
self.setSizeGripEnabled(True)

self.send_button = self.addButton("Request a fix", QMessageBox.ActionRole)
self.ignore_button = self.addButton("Ignore", QMessageBox.RejectRole)

text_browser = self.findChild(QTextEdit)
if text_browser:
font = QFont("Courier")
font.setStyleHint(QFont.Monospace)
font.setFixedPitch(True)
font.setPointSize(10)
text_browser.setFont(font)

def exec_(self):
self.logger.info("TracebackDialog: Executing dialog")
result = super().exec_()
user_choice = "fix" if self.clickedButton() == self.send_button else "ignore"
self.logger.info(f"TracebackDialog: User chose to {user_choice} the traceback")
return self.clickedButton() == self.send_button
8 changes: 4 additions & 4 deletions codeaide/utils/terminal_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,11 +150,11 @@ def process_line(self, line):
def show_traceback_if_any(self):
if self.traceback_buffer:
traceback_text = "\n".join(self.traceback_buffer)
self.logger.info("\nERROR DETECTED:")
self.logger.info("-----------------------")
self.logger.info(traceback_text)
self.logger.info("-----------------------")
self.logger.info(
f"ScriptRunner: Traceback detected: {traceback_text[:50]}..."
)
if self.traceback_callback:
self.logger.info("ScriptRunner: Calling traceback callback")
self.traceback_callback(traceback_text)
self.traceback_buffer = []

Expand Down
Loading

0 comments on commit 640375b

Please sign in to comment.