Livio Meuli cc14f25e69 refactor: add REVIEW annotations for dead/debug code across frontend and backend
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 10:38:59 +02:00

121 lines
4.4 KiB
Python

"""Manages the chat history and communication with the AI model API."""
import os
from dotenv import load_dotenv
import requests
import json
load_dotenv()
class ChatManager:
"""Handles sending messages and maintaining conversation history.
Connects to an OpenAI-compatible REST endpoint configured via environment
variables. All messages (user, assistant, system) are kept in memory so
the full conversation is sent with every request.
"""
def __init__(self):
self.api_host = os.getenv("HOST")
self.api_port = os.getenv("PORT")
self.api_key = os.getenv("API_KEY")
self.model = os.getenv("MODEL")
self.max_tokens = 2000
# API endpoint URL (OpenAI-compatible format)
self.api_url = f"http://{self.api_host}:{self.api_port}/v1/chat/completions"
# Chat history stored in memory
self.chat_history = []
def add_message(self, role: str, content: str) -> None:
"""Append a single message to the conversation history."""
self.chat_history.append({"role": role, "content": content})
def get_history(self) -> list:
"""Return a copy of the conversation history."""
return list(self.chat_history)
# REVIEW: dead code — clear_history() is never called anywhere in the codebase.
def clear_history(self) -> None:
"""Wipe the conversation history (starts a fresh chat)."""
self.chat_history = []
def send_message(self, user_message: str) -> str:
"""Send a user message to the AI and return its reply.
Adds the user message to history, calls the API with the full history
as context, and appends the AI reply to history before returning it.
"""
# Add user message to history
self.add_message("user", user_message)
try:
# Prepare request to OpenAI-compatible API
headers = {
"Content-Type": "application/json",
}
# Add API key if available
if self.api_key and self.api_key != "EMPTY":
headers["Authorization"] = f"Bearer {self.api_key}"
# Full history is sent so the model has multi-turn conversation context
payload = {
"model": self.model,
"messages": self.chat_history,
"temperature": 0.7,
"max_tokens": self.max_tokens,
"stream": False,
}
# Make API request
response = requests.post(
self.api_url, headers=headers, json=payload, timeout=30
)
# Check if request was successful
if response.status_code != 200:
error_msg = f"API Error {response.status_code}: {response.text}"
raise Exception(error_msg)
# Parse response
response_data = response.json()
# Extract AI message
if "choices" in response_data and len(response_data["choices"]) > 0:
ai_message = response_data["choices"][0]["message"]["content"]
# Add AI response to history
self.add_message("assistant", ai_message)
return ai_message
else:
raise Exception("Invalid API response format")
except requests.exceptions.RequestException as e:
error_msg = f"Connection Error: {str(e)}"
# Add error message to history so user sees it
self.add_message("assistant", f"Error: {error_msg}")
raise Exception(error_msg)
except json.JSONDecodeError as e:
error_msg = f"JSON Decode Error: {str(e)}"
self.add_message("assistant", f"Error: {error_msg}")
raise Exception(error_msg)
except Exception as e:
error_msg = f"Error: {str(e)}"
self.add_message("assistant", f"Error: {error_msg}")
raise Exception(error_msg)
# REVIEW: dead code — get_chat_display() is never called anywhere in the codebase.
# The UI renders st.session_state.chat_history directly. This method also does the
# same thing as get_history() (returns a copy of chat_history with the same fields),
# making it redundant even if it were used.
def get_chat_display(self) -> list:
"""Return a copy of the history suitable for display in the UI."""
return [
{"role": msg["role"], "content": msg["content"]}
for msg in self.chat_history
]