Skip to content

Commit

Permalink
Added logging, saving log file
Browse files Browse the repository at this point in the history
  • Loading branch information
dougollerenshaw committed Oct 1, 2024
1 parent 33ec66a commit b12ad8d
Show file tree
Hide file tree
Showing 7 changed files with 160 additions and 50 deletions.
19 changes: 12 additions & 7 deletions codeaide/logic/chat_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import sys
import re
import traceback
import logging
from codeaide.utils.api_utils import (
parse_response,
send_api_request,
Expand All @@ -21,6 +22,7 @@
from codeaide.utils.file_handler import FileHandler
from codeaide.utils.terminal_manager import TerminalManager
from codeaide.utils.general_utils import generate_session_id
from codeaide.utils.logging_config import get_logger


class ChatHandler:
Expand All @@ -37,6 +39,7 @@ def __init__(self):
self.session_id = generate_session_id()
self.cost_tracker = CostTracker()
self.file_handler = FileHandler(session_id=self.session_id)
self.logger = get_logger()
self.conversation_history = self.file_handler.load_chat_history()
self.env_manager = EnvironmentManager()
self.terminal_manager = TerminalManager()
Expand All @@ -50,7 +53,7 @@ def __init__(self):
]["max_tokens"]

self.api_key_valid, self.api_key_message = self.check_api_key()
print(f"New session started with ID: {self.session_id}")
self.logger.info(f"New session started with ID: {self.session_id}")

def check_api_key(self):
"""
Expand All @@ -63,7 +66,9 @@ def check_api_key(self):
self.api_key_set = self.api_client is not None

if not self.api_key_set:
self.logger.warning("API key not set")
return False, self.get_api_key_instructions(self.current_provider)
self.logger.info("API key is valid")
return True, None

def get_api_key_instructions(self, provider):
Expand Down Expand Up @@ -166,7 +171,7 @@ def process_input(self, user_input):
Returns:
dict: A response dictionary containing the type and content of the response.
"""
print(f"Processing input: {user_input}")
self.logger.info(f"Processing input: {user_input}")
try:
if not self.api_key_set:
return {
Expand All @@ -190,7 +195,7 @@ def process_input(self, user_input):
try:
return self.process_ai_response(response)
except ValueError as e:
print(f"ValueError: {str(e)}\n")
self.logger.error(f"ValueError: {str(e)}\n")
if not self.is_last_attempt(attempt):
self.add_error_prompt_to_history(str(e))
else:
Expand Down Expand Up @@ -484,12 +489,12 @@ def is_task_in_progress(self):
return bool(self.conversation_history)

def set_model(self, provider, model):
print(f"In set_model: provider: {provider}, model: {model}")
self.logger.info(f"In set_model: provider: {provider}, model: {model}")
if provider not in AI_PROVIDERS:
print(f"Invalid provider: {provider}")
self.logger.error(f"Invalid provider: {provider}")
return False, None
if model not in AI_PROVIDERS[provider]["models"]:
print(f"Invalid model {model} for provider {provider}")
self.logger.error(f"Invalid model {model} for provider {provider}")
return False, None

self.current_provider = provider
Expand All @@ -503,7 +508,7 @@ def set_model(self, provider, model):
if not api_key_valid:
return False, message

print(f"Model {model} for provider {provider} set successfully.")
self.logger.info(f"Model {model} for provider {provider} set successfully.")
return True, None

def clear_conversation_history(self):
Expand Down
25 changes: 19 additions & 6 deletions codeaide/ui/chat_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import sys
import traceback
import time
import logging
from PyQt5.QtCore import Qt, QTimer
from PyQt5.QtGui import QColor
from PyQt5.QtWidgets import (
Expand Down Expand Up @@ -37,11 +38,13 @@
DEFAULT_MODEL,
MODEL_SWITCH_MESSAGE,
)
from codeaide.utils.logging_config import get_logger


class ChatWindow(QMainWindow):
def __init__(self, chat_handler):
super().__init__()
self.logger = get_logger()
self.setWindowTitle("🤖 CodeAIde 🤖")
self.setGeometry(0, 0, CHAT_WINDOW_WIDTH, CHAT_WINDOW_HEIGHT)
self.chat_handler = chat_handler
Expand All @@ -64,6 +67,8 @@ def __init__(self, chat_handler):
self.timer.start(500)
self.timer.timeout.connect(lambda: None)

self.logger.info("Chat window initialized")

def setup_ui(self):
central_widget = QWidget(self)
self.setCentralWidget(central_widget)
Expand Down Expand Up @@ -134,6 +139,8 @@ def setup_ui(self):

main_layout.addLayout(button_layout)

self.logger.info("Chat window UI initialized")

def eventFilter(self, obj, event):
if obj == self.input_text and event.type() == event.KeyPress:
if (
Expand All @@ -151,6 +158,8 @@ def on_submit(self):
if not user_input:
return

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

# Clear the input field immediately
self.input_text.clear()

Expand Down Expand Up @@ -189,6 +198,8 @@ def add_to_chat(self, sender, message):
self.chat_display.append(html_message + "<br>")
self.chat_display.ensureCursorVisible()

self.logger.debug(f"Adding message to chat from {sender}: {message}")

def display_thinking(self):
self.add_to_chat("AI", "Thinking... 🤔")

Expand Down Expand Up @@ -263,13 +274,15 @@ def load_example(self):
QMessageBox.information(self, "No Selection", "No example was selected.")

def on_exit(self):
self.logger.info("User clicked Exit button, awaiting reply")
reply = QMessageBox.question(
self,
"Quit",
"Do you want to quit?",
QMessageBox.Yes | QMessageBox.No,
QMessageBox.No,
)
self.logger.info(f"User clicked Exit button, reply: {reply}")
if reply == QMessageBox.Yes:
self.close()

Expand All @@ -291,7 +304,7 @@ def update_model_dropdown(self, provider):
if models:
self.model_dropdown.setCurrentText(list(models)[0])
else:
print(f"No models available for provider {provider}")
self.logger.info(f"No models available for provider {provider}")

def update_chat_handler(self):
provider = self.provider_dropdown.currentText()
Expand All @@ -303,17 +316,17 @@ def update_chat_handler(self):
current_version = self.chat_handler.get_latest_version()
success, message = self.chat_handler.set_model(provider, model)

print(f"In update_chat_handler: current_version: {current_version}")
print(f"In update_chat_handler, success: {success}")
print(f"In update_chat_handler, message: {message}")
self.logger.info(f"In update_chat_handler: current_version: {current_version}")
self.logger.info(f"In update_chat_handler, success: {success}")
self.logger.info(f"In update_chat_handler, message: {message}")

if not success:
print(f"In update_chat_handler, not success")
self.logger.info(f"In update_chat_handler, not success")
if message: # This indicates that an API key is required
self.waiting_for_api_key = True
self.add_to_chat("AI", message)
else:
print(f"In update_chat_handler, not success, no message")
self.logger.info(f"In update_chat_handler, not success, no message")
self.add_to_chat(
"System",
f"Failed to set model {model} for provider {provider}. Please check your API key.",
Expand Down
30 changes: 18 additions & 12 deletions codeaide/utils/api_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,17 @@
from decouple import config, AutoConfig
import hjson
from anthropic import APIError
import logging

from codeaide.utils.constants import (
AI_PROVIDERS,
DEFAULT_MODEL,
DEFAULT_PROVIDER,
SYSTEM_PROMPT,
)
from codeaide.utils.logging_config import get_logger

logger = get_logger()


class MissingAPIKeyException(Exception):
Expand All @@ -34,11 +38,13 @@ def get_api_client(provider=DEFAULT_PROVIDER, model=DEFAULT_MODEL):

api_key_name = AI_PROVIDERS[provider]["api_key_name"]
api_key = config(api_key_name, default=None)
print(f"Attempting to get API key for {provider} with key name: {api_key_name}")
print(f"API key found: {'Yes' if api_key else 'No'}")
logger.info(
f"Attempting to get API key for {provider} with key name: {api_key_name}"
)
logger.info(f"API key found: {'Yes' if api_key else 'No'}")

if api_key is None or api_key.strip() == "":
print(f"API key for {provider} is missing or empty")
logger.warning(f"API key for {provider} is missing or empty")
return None

if provider.lower() == "anthropic":
Expand All @@ -48,7 +54,7 @@ def get_api_client(provider=DEFAULT_PROVIDER, model=DEFAULT_MODEL):
else:
raise ValueError(f"Unsupported provider: {provider}")
except Exception as e:
print(f"Error initializing {provider.capitalize()} API client: {str(e)}")
logger.error(f"Error initializing {provider.capitalize()} API client: {str(e)}")
return None


Expand Down Expand Up @@ -81,13 +87,13 @@ def save_api_key(service, api_key):

return True
except Exception as e:
print(f"Error saving API key: {str(e)}")
logger.error(f"Error saving API key: {str(e)}")
return False


def send_api_request(api_client, conversation_history, max_tokens, model, provider):
print(f"Sending API request with model: {model} and max_tokens: {max_tokens}")
print(f"Conversation history: {conversation_history}\n")
logger.info(f"Sending API request with model: {model} and max_tokens: {max_tokens}")
logger.debug(f"Conversation history: {conversation_history}")

try:
if provider.lower() == "anthropic":
Expand All @@ -113,19 +119,19 @@ def send_api_request(api_client, conversation_history, max_tokens, model, provid
else:
raise NotImplementedError(f"API request for {provider} not implemented")

print(f"Received response from {provider}")
print(f"Response object: {response}")
logger.info(f"Received response from {provider}")
logger.debug(f"Response object: {response}")
return response
except Exception as e:
print(f"Error in API request to {provider}: {str(e)}")
logger.error(f"Error in API request to {provider}: {str(e)}")
return None


def parse_response(response, provider):
if not response:
raise ValueError("Empty or invalid response received")

print(f"Received response: {response}\n")
logger.debug(f"Received response: {response}")

if provider.lower() == "anthropic":
if not response.content:
Expand Down Expand Up @@ -182,4 +188,4 @@ def check_api_connection():

if __name__ == "__main__":
success, message = check_api_connection()
print(f"Connection {'successful' if success else 'failed'}: {message}")
logger.info(f"Connection {'successful' if success else 'failed'}: {message}")
45 changes: 36 additions & 9 deletions codeaide/utils/environment_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
import subprocess
import sys
import venv
from codeaide.utils.logging_config import get_logger

logger = get_logger()


class EnvironmentManager:
Expand All @@ -16,20 +19,31 @@ def __init__(self, env_name="codeaide_env"):

def _setup_environment(self):
if not os.path.exists(self.env_path):
logger.info(f"Creating new virtual environment at {self.env_path}")
venv.create(self.env_path, with_pip=True)
else:
logger.info(f"Using existing virtual environment at {self.env_path}")

def _get_installed_packages(self):
pip_path = (
os.path.join(self.env_path, "bin", "pip")
if os.name != "nt"
else os.path.join(self.env_path, "Scripts", "pip.exe")
)
result = subprocess.run(
f"{pip_path} freeze", shell=True, check=True, capture_output=True, text=True
)
self.installed_packages = {
pkg.split("==")[0].lower() for pkg in result.stdout.split("\n") if pkg
}
try:
result = subprocess.run(
f"{pip_path} freeze",
shell=True,
check=True,
capture_output=True,
text=True,
)
self.installed_packages = {
pkg.split("==")[0].lower() for pkg in result.stdout.split("\n") if pkg
}
logger.info(f"Found {len(self.installed_packages)} installed packages")
except subprocess.CalledProcessError as e:
logger.error(f"Error getting installed packages: {e}")

def install_requirements(self, requirements_file):
pip_path = (
Expand All @@ -44,19 +58,32 @@ def install_requirements(self, requirements_file):

if packages_to_install:
packages_str = " ".join(packages_to_install)
logger.info(f"Installing new packages: {packages_str}")
try:
subprocess.run(
f"{pip_path} install {packages_str}", shell=True, check=True
)
self.installed_packages.update(packages_to_install)
logger.info(
f"Successfully installed {len(packages_to_install)} new packages"
)
return list(packages_to_install)
except subprocess.CalledProcessError as e:
print(f"Error installing requirements: {e}")
logger.error(f"Error installing requirements: {e}")
return []
else:
logger.info("No new packages to install")
return []

def get_activation_command(self):
if os.name == "nt": # Windows
return f"call {os.path.join(self.env_path, 'Scripts', 'activate.bat')}"
activation_path = os.path.join(self.env_path, "Scripts", "activate.bat")
else: # Unix-like
return f"source {os.path.join(self.env_path, 'bin', 'activate')}"
activation_path = os.path.join(self.env_path, "bin", "activate")

logger.info(f"Generated activation command for {os.name} system")
return (
f"call {activation_path}"
if os.name == "nt"
else f"source {activation_path}"
)
Loading

0 comments on commit b12ad8d

Please sign in to comment.