From 1c75eece934271942a203d5369cec4c295753410 Mon Sep 17 00:00:00 2001 From: Iyeoluwa Akinrinola Date: Tue, 20 May 2025 22:23:33 +0100 Subject: [PATCH] Fix team chat integration --- ai_service/api.py | 56 +++++++---- ai_service/bot_manager.py | 138 +++++++++++++++++++++++++--- openwebui-bot/examples/custom_ai.py | 21 ++++- 3 files changed, 182 insertions(+), 33 deletions(-) diff --git a/ai_service/api.py b/ai_service/api.py index 789a17b..7ee7029 100644 --- a/ai_service/api.py +++ b/ai_service/api.py @@ -60,24 +60,46 @@ async def startup_event(): print("=" * 50) print("Starting OpenWebUI bot...") - # Start the bot with configuration - success = await bot_manager.start_bot( - openwebui_url=config.OPENWEBUI_URL, - api_key=config.OPENWEBUI_API_KEY, - model_id=config.DEFAULT_MODEL, - system_prompt=config.BOT_SYSTEM_PROMPT, - temperature=config.BOT_TEMPERATURE, - max_tokens=config.BOT_MAX_TOKENS, - top_p=config.BOT_TOP_P, - triggers=config.BOT_TRIGGERS, - respond_to_all=config.BOT_RESPOND_TO_ALL - ) - - if success: - print("Bot started successfully!") + # Check if the OpenWebUI URL and API key are set + if not config.OPENWEBUI_URL or not config.OPENWEBUI_API_KEY: + print("ERROR: OpenWebUI URL or API key not set. Bot cannot be started.") + print("Please set OPENWEBUI_URL and OPENWEBUI_API_KEY in your .env file.") + print("=" * 50) else: - print("Failed to start bot. Check the logs for details.") - print("=" * 50) + # Try to start the bot with multiple retries + max_retries = 3 + retry_delay = 5 # seconds + success = False + + for attempt in range(1, max_retries + 1): + print(f"Starting bot (attempt {attempt}/{max_retries})...") + + # Start the bot with configuration + success = await bot_manager.start_bot( + openwebui_url=config.OPENWEBUI_URL, + api_key=config.OPENWEBUI_API_KEY, + model_id=config.DEFAULT_MODEL, + system_prompt=config.BOT_SYSTEM_PROMPT, + temperature=config.BOT_TEMPERATURE, + max_tokens=config.BOT_MAX_TOKENS, + top_p=config.BOT_TOP_P, + triggers=config.BOT_TRIGGERS, + respond_to_all=config.BOT_RESPOND_TO_ALL + ) + + if success: + print("Bot started successfully!") + break + else: + print(f"Failed to start bot (attempt {attempt}/{max_retries}).") + if attempt < max_retries: + print(f"Retrying in {retry_delay} seconds...") + await asyncio.sleep(retry_delay) + else: + print("Maximum retry attempts reached. Bot could not be started.") + print("Check the logs for details.") + + print("=" * 50) else: print("OpenWebUI bot is disabled. Set BOT_ENABLED=true in .env to enable it.") diff --git a/ai_service/bot_manager.py b/ai_service/bot_manager.py index ee94f01..75f948e 100644 --- a/ai_service/bot_manager.py +++ b/ai_service/bot_manager.py @@ -8,6 +8,7 @@ import os import sys import asyncio import logging +import traceback from typing import Optional # Set up logging @@ -28,15 +29,65 @@ sys.path.insert(0, openwebui_bot_dir) logger.info(f"Adding OpenWebUI bot directory to Python path: {openwebui_bot_dir}") # Import the bot modules -try: - from env import WEBUI_URL, TOKEN - from examples.custom_ai import main as custom_bot_main -except ImportError as e: - print(f"Error importing OpenWebUI bot modules: {str(e)}") - print("Make sure the openwebui-bot directory exists and contains the required files.") - WEBUI_URL = None - TOKEN = None - custom_bot_main = None +custom_bot_main = None + +# Check if the openwebui-bot directory exists +if not os.path.exists(openwebui_bot_dir): + logger.error(f"OpenWebUI bot directory not found: {openwebui_bot_dir}") +else: + logger.info(f"OpenWebUI bot directory found: {openwebui_bot_dir}") + + # Add examples directory to path + examples_dir = os.path.join(openwebui_bot_dir, 'examples') + if os.path.exists(examples_dir): + sys.path.insert(0, examples_dir) + logger.info(f"Added examples directory to path: {examples_dir}") + + # Check for required files + env_path = os.path.join(openwebui_bot_dir, 'env.py') + custom_ai_path = os.path.join(openwebui_bot_dir, 'examples', 'custom_ai.py') + + if not os.path.exists(env_path): + logger.error(f"env.py not found at {env_path}") + else: + logger.info(f"env.py found at {env_path}") + + if not os.path.exists(custom_ai_path): + logger.error(f"custom_ai.py not found at {custom_ai_path}") + else: + logger.info(f"custom_ai.py found at {custom_ai_path}") + + # Try to import the modules + try: + # Use a different approach to import the modules + sys.path.insert(0, openwebui_bot_dir) + + # Import the custom_ai module + try: + from examples.custom_ai import main as custom_bot_main + logger.info("Successfully imported custom_ai module") + except ImportError as e: + logger.error(f"Error importing custom_ai module: {str(e)}") + + # Try a different approach + try: + import importlib.util + spec = importlib.util.spec_from_file_location("custom_ai", custom_ai_path) + custom_ai = importlib.util.module_from_spec(spec) + spec.loader.exec_module(custom_ai) + custom_bot_main = custom_ai.main + logger.info("Successfully imported custom_ai module using importlib") + except Exception as e: + logger.error(f"Error importing custom_ai module using importlib: {str(e)}") + except Exception as e: + logger.error(f"Error importing OpenWebUI bot modules: {str(e)}") + logger.error(f"Traceback: {traceback.format_exc()}") + + # Log the current state + if custom_bot_main is None: + logger.error("Failed to import custom_bot_main function") + else: + logger.info("Successfully imported custom_bot_main function") # Global variable to store the bot task bot_task = None @@ -55,6 +106,11 @@ async def start_bot( """ Start the OpenWebUI bot. + This function creates a .env file for the bot and starts it in a background task. + The bot connects to OpenWebUI via WebSocket and listens for messages in channels. + When a message mentions the bot (using trigger words like @ai), the bot processes + the message and sends a response back to the channel. + Args: openwebui_url: URL of the OpenWebUI instance. api_key: API key for authentication. @@ -81,6 +137,27 @@ async def start_bot( logger.error("OpenWebUI bot modules not found. Bot cannot be started.") return False + # Create .env file for the bot + try: + env_file_path = os.path.join(openwebui_bot_dir, '.env') + with open(env_file_path, 'w') as f: + f.write(f"# OpenWebUI configuration\n") + f.write(f"WEBUI_URL={openwebui_url}\n") + f.write(f"TOKEN={api_key}\n\n") + f.write(f"# Model configuration\n") + f.write(f"MODEL_ID={model_id}\n\n") + f.write(f"# Bot behavior configuration\n") + f.write(f'SYSTEM_PROMPT="{system_prompt or "You are a helpful AI assistant."}"\n') + f.write(f"TEMPERATURE={temperature or 0.7}\n") + f.write(f"MAX_TOKENS={max_tokens or 2048}\n") + f.write(f"TOP_P={top_p or 0.9}\n") + f.write(f"TRIGGERS={','.join(triggers) if triggers else '@ai,@bot,@assistant,@chatbot'}\n") + f.write(f"RESPOND_TO_ALL={'true' if respond_to_all else 'false'}\n") + logger.info(f"Created .env file at {env_file_path}") + except Exception as e: + logger.error(f"Error creating .env file: {str(e)}") + # Continue anyway, as we'll set environment variables too + # Set environment variables for the bot os.environ["WEBUI_URL"] = openwebui_url os.environ["TOKEN"] = api_key @@ -104,6 +181,7 @@ async def start_bot( # Start the bot in a background task logger.info("Starting OpenWebUI bot...") logger.info(f"OpenWebUI URL: {openwebui_url}") + logger.info(f"API Key: {api_key[:4]}...{api_key[-4:] if len(api_key) > 8 else ''}") logger.info(f"Model: {model_id}") if system_prompt: @@ -120,12 +198,48 @@ async def start_bot( logger.info(f"Respond to all: {respond_to_all}") # Create a task for the bot - bot_task = asyncio.create_task(custom_bot_main()) + try: + # Try to reload the env module to pick up new environment variables + try: + import importlib + if 'env' in sys.modules: + importlib.reload(sys.modules['env']) + logger.info("Reloaded env module") + except Exception as e: + logger.warning(f"Failed to reload env module: {str(e)}") - logger.info("Bot started successfully!") - return True + # Start the bot with a retry mechanism + max_retries = 3 + retry_delay = 5 # seconds + last_error = None + + for attempt in range(1, max_retries + 1): + try: + logger.info(f"Starting bot (attempt {attempt}/{max_retries})...") + bot_task = asyncio.create_task(custom_bot_main()) + logger.info("Bot started successfully!") + return True + except Exception as e: + last_error = e + logger.error(f"Error starting bot (attempt {attempt}/{max_retries}): {str(e)}") + if attempt < max_retries: + logger.info(f"Retrying in {retry_delay} seconds...") + await asyncio.sleep(retry_delay) + else: + logger.error("Maximum retry attempts reached") + + # If we get here, all attempts failed + logger.error(f"Failed to start bot after {max_retries} attempts") + logger.error(f"Last error: {str(last_error)}") + logger.error(f"Traceback: {traceback.format_exc()}") + return False + except Exception as e: + logger.error(f"Error creating bot task: {str(e)}") + logger.error(f"Traceback: {traceback.format_exc()}") + return False except Exception as e: logger.error(f"Error starting bot: {str(e)}") + logger.error(f"Traceback: {traceback.format_exc()}") return False async def stop_bot() -> bool: diff --git a/openwebui-bot/examples/custom_ai.py b/openwebui-bot/examples/custom_ai.py index 8a15493..2de04b9 100644 --- a/openwebui-bot/examples/custom_ai.py +++ b/openwebui-bot/examples/custom_ai.py @@ -4,6 +4,7 @@ import asyncio import socketio import os import sys +import traceback from env import WEBUI_URL, TOKEN from utils import send_message, send_typing import aiohttp @@ -188,13 +189,25 @@ async def main(): try: # Callback function for user-join - async def join_callback(data): + async def join_callback(*args): try: - bot_id = data["id"] - print(f"Bot connected with ID: {bot_id}") - events(bot_id) # Attach the event handlers dynamically + if args and len(args) > 0: + data = args[0] + print(f"Received callback data: {data}") + if isinstance(data, dict) and "id" in data: + bot_id = data["id"] + print(f"Bot connected with ID: {bot_id}") + events(bot_id) # Attach the event handlers dynamically + else: + print(f"Invalid callback data format: {data}") + else: + print("No callback data received") + # If no data is received, use a default ID + print("Using default bot ID") + events("bot-default-id") # Attach the event handlers with a default ID except Exception as e: print(f"Error in join_callback: {str(e)}") + print(traceback.format_exc()) # Authenticate with the server print("Authenticating with the server...")