import http.server import socketserver import os import logging import asyncio from inference_bot import InferenceBot import time # Configure logging logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') COPILOT_HOST = os.getenv("COPILOT_HOST", "0.0.0.0") COPILOT_PORT = int(os.getenv("COPILOT_PORT", 8000)) COPILOT_PATH = "/copilot" # A single user ID for API interactions, as there's no multi-user concept here API_USER_ID = 1 class APIHelper: def __init__(self, bot: InferenceBot): self.bot = bot async def _start_logic(self) -> str: return await self.bot.start() async def _clear_logic(self, user_id: int) -> str: self.bot.clear_conversation_history(user_id) return "Conversation history cleared. Let's start fresh!" def _status_logic(self) -> str: return self.bot.get_bot_status() async def _switch_logic(self) -> str: if hasattr(self.bot, 'switch_model'): return await self.bot.switch_model() else: return "Model switching is not supported for this bot." async def _handle_message_logic(self, user_id: int, user_message: str) -> str: try: response = await self.bot.handle_message(user_id, user_message) return response except Exception as e: logging.error(f"Error in _handle_message_logic for user {user_id}: {str(e)}") return f"Error processing message: {str(e)}" def run(self): run_server(self.bot) logging.info("APIHelper is running. Ready to handle requests.") class CopilotRequestHandler(http.server.BaseHTTPRequestHandler): # This will be set by the server when it's created api_helper_instance: APIHelper = None def _send_response(self, status_code: int, content: str): self.send_response(status_code) self.send_header('Content-type', 'text/plain; charset=utf-8') self.end_headers() self.wfile.write(content.encode('utf-8')) def do_POST(self): if self.path == COPILOT_PATH: content_length = int(self.headers['Content-Length']) post_data_bytes = self.rfile.read(content_length) user_message = post_data_bytes.decode('utf-8').strip() logging.info(f"Received POST from {self.client_address[0]}: {user_message}") response_text = "" # Use a fixed user ID for the API interaction user_id = API_USER_ID if self.api_helper_instance is None: logging.error("APIHelper instance not set on request handler.") self._send_response(500, "Internal Server Error: API Helper not initialized.") return # Simulate command handling based on message content if user_message.startswith('/'): command_parts = user_message.split(' ', 1) command = command_parts[0] if command == '/start': response_text = asyncio.run(self.api_helper_instance._start_logic()) elif command == '/clear': response_text = asyncio.run(self.api_helper_instance._clear_logic(user_id)) elif command == '/status': response_text = self.api_helper_instance._status_logic() elif command == '/switch': response_text = asyncio.run(self.api_helper_instance._switch_logic()) else: # For unknown commands, treat as a regular message or an error response_text = asyncio.run(self.api_helper_instance._handle_message_logic(user_id, user_message)) else: # Treat as a regular message response_text = asyncio.run(self.api_helper_instance._handle_message_logic(user_id, user_message)) self._send_response(200, response_text) else: self._send_response(404, "Not Found") def do_GET(self): if self.path == "/health": self._send_response(200, "API Helper is running") else: self._send_response(404, "Not Found") def run_server(bot_instance: InferenceBot, server_class=http.server.HTTPServer, handler_class=CopilotRequestHandler, host=COPILOT_HOST, port=COPILOT_PORT): # Create an instance of APIHelper api_helper = APIHelper(bot_instance) # Attach the APIHelper instance to the handler class handler_class.api_helper_instance = api_helper try: server_address = (host, port) httpd = server_class(server_address, handler_class) logging.info(f"Starting Copilot API helper on http://{host}:{port}{COPILOT_PATH}") logging.info(f"Health check available at http://{host}:{port}/health") except Exception as e: logging.error(f"Error during server setup: {e}") return # Exit if server setup fails try: httpd.serve_forever() except KeyboardInterrupt: logging.info("Server shutting down...") httpd.server_close()