Add OpenWebUI bot integration for channels feature

This commit is contained in:
Iyeoluwa Akinrinola
2025-05-21 09:07:10 +01:00
parent 1c75eece93
commit 4ee0da8db6
8 changed files with 760 additions and 154 deletions
+77
View File
@@ -0,0 +1,77 @@
# OpenWebUI Bot for Channels Integration
This project integrates the [Open WebUI bot](https://github.com/open-webui/bot) to provide AI responses in OpenWebUI channels.
## Overview
The OpenWebUI bot connects to your OpenWebUI instance via WebSocket and listens for messages in channels. When a message mentions the AI (using trigger words like `@ai`), the bot processes the message and sends a response back to the channel.
## Running the Bot Locally
To run the bot locally:
1. Make sure you have Python 3.7+ installed
2. Install the required dependencies:
```bash
pip install python-socketio aiohttp python-dotenv
```
3. Configure the bot by creating a `.env` file in the `openwebui-bot` directory:
```
WEBUI_URL=http://104.225.217.215:8080
TOKEN=GdCU4ieYDqHsLfH2
MODEL_ID=llama3.1
```
4. Run the bot:
```bash
python run_openwebui_bot.py
```
## Deploying the Bot on the Server
To deploy the bot on your server:
1. Run the deployment script:
```bash
./deploy_bot.sh
```
2. Follow the instructions provided by the script to copy the deployment package to your server and run the deployment.
## Bot Configuration
The bot is configured using environment variables in the `.env` file:
- `WEBUI_URL`: URL of your OpenWebUI instance (e.g., `http://104.225.217.215:8080`)
- `TOKEN`: API key for authentication
- `MODEL_ID`: ID of the model to use (e.g., `llama3.1`)
Additional configuration options can be added to the `.env` file:
```
SYSTEM_PROMPT="You are a helpful AI assistant."
TEMPERATURE=0.7
MAX_TOKENS=2048
TOP_P=0.9
TRIGGERS=@ai,@bot,@assistant,@chatbot
RESPOND_TO_ALL=false
```
## Using the Bot
Once the bot is running, you can use it in OpenWebUI channels:
1. Create a channel in OpenWebUI
2. Send a message that mentions the bot (e.g., `@ai What is the capital of France?`)
3. The bot will process your message and send a response
## Troubleshooting
If the bot is not responding to messages:
1. Check that the bot is running and connected to OpenWebUI
2. Verify that you're using one of the trigger words (e.g., `@ai`)
3. Check the logs for any errors
4. Make sure your OpenWebUI URL and API key are correct
## Logs
The bot logs to both the console and a file named `bot_debug.log`. You can check this file for detailed information about what the bot is doing and any errors it encounters.
+33 -2
View File
@@ -216,12 +216,43 @@ async def start_bot(
for attempt in range(1, max_retries + 1): for attempt in range(1, max_retries + 1):
try: try:
logger.info(f"Starting bot (attempt {attempt}/{max_retries})...") logger.info(f"Starting bot (attempt {attempt}/{max_retries})...")
bot_task = asyncio.create_task(custom_bot_main())
logger.info("Bot started successfully!") # Define a monitoring task to restart the bot if it fails
async def monitor_bot_task():
global bot_task
try:
# Start the main bot task
main_task = asyncio.create_task(custom_bot_main())
# Wait for the task to complete or fail
try:
await main_task
logger.warning("Bot task completed unexpectedly")
except asyncio.CancelledError:
logger.info("Bot task was cancelled")
raise
except Exception as e:
logger.error(f"Bot task failed with error: {str(e)}")
logger.error(traceback.format_exc())
# Try to restart the bot
logger.info("Attempting to restart the bot...")
await asyncio.sleep(5) # Wait a bit before restarting
restart_task = asyncio.create_task(custom_bot_main())
bot_task = restart_task # Update the global task reference
logger.info("Bot restarted successfully")
except Exception as e:
logger.error(f"Error in monitor task: {str(e)}")
logger.error(traceback.format_exc())
# Start the monitoring task
bot_task = asyncio.create_task(monitor_bot_task())
logger.info("Bot started successfully with monitoring!")
return True return True
except Exception as e: except Exception as e:
last_error = e last_error = e
logger.error(f"Error starting bot (attempt {attempt}/{max_retries}): {str(e)}") logger.error(f"Error starting bot (attempt {attempt}/{max_retries}): {str(e)}")
logger.error(traceback.format_exc())
if attempt < max_retries: if attempt < max_retries:
logger.info(f"Retrying in {retry_delay} seconds...") logger.info(f"Retrying in {retry_delay} seconds...")
await asyncio.sleep(retry_delay) await asyncio.sleep(retry_delay)
Executable
+130
View File
@@ -0,0 +1,130 @@
#!/bin/bash
# Script to deploy the OpenWebUI bot on the server
# Set the server details
SERVER_IP="104.225.217.215"
SERVER_USER="root"
DEPLOY_DIR="/root/openwebui"
# Create a temporary directory for deployment files
TEMP_DIR=$(mktemp -d)
echo "Created temporary directory: $TEMP_DIR"
# Copy the necessary files to the temporary directory
echo "Copying files to temporary directory..."
cp -r openwebui-bot $TEMP_DIR/
cp run_openwebui_bot.py $TEMP_DIR/
# Create a .env file for the bot
echo "Creating .env file..."
cat > $TEMP_DIR/openwebui-bot/.env << EOF
WEBUI_URL=http://104.225.217.215:8080
TOKEN=GdCU4ieYDqHsLfH2
MODEL_ID=llama3.1
EOF
# Create a systemd service file for the bot
echo "Creating systemd service file..."
cat > $TEMP_DIR/openwebui-bot.service << EOF
[Unit]
Description=OpenWebUI Bot Service
After=network.target
[Service]
Type=simple
User=root
WorkingDirectory=$DEPLOY_DIR
ExecStart=/usr/bin/python3 $DEPLOY_DIR/run_openwebui_bot.py
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
EOF
# Create a deployment script
echo "Creating deployment script..."
cat > $TEMP_DIR/deploy.sh << EOF
#!/bin/bash
# Install required packages
pip install python-socketio aiohttp python-dotenv
# Copy the bot files to the deployment directory
mkdir -p $DEPLOY_DIR
cp -r openwebui-bot $DEPLOY_DIR/
cp run_openwebui_bot.py $DEPLOY_DIR/
# Set up the systemd service
cp openwebui-bot.service /etc/systemd/system/
systemctl daemon-reload
systemctl enable openwebui-bot.service
systemctl start openwebui-bot.service
echo "Bot deployed and started!"
echo "To check the status: systemctl status openwebui-bot.service"
echo "To view logs: journalctl -u openwebui-bot.service -f"
EOF
# Make the deployment script executable
chmod +x $TEMP_DIR/deploy.sh
# Create a README file
echo "Creating README file..."
cat > $TEMP_DIR/README.md << EOF
# OpenWebUI Bot Deployment
This package contains the OpenWebUI bot for channels integration.
## Files
- \`openwebui-bot/\`: The bot code
- \`run_openwebui_bot.py\`: Script to run the bot
- \`openwebui-bot.service\`: Systemd service file
- \`deploy.sh\`: Deployment script
## Deployment
1. Run the deployment script:
\`\`\`
./deploy.sh
\`\`\`
2. Check the status of the bot:
\`\`\`
systemctl status openwebui-bot.service
\`\`\`
3. View the logs:
\`\`\`
journalctl -u openwebui-bot.service -f
\`\`\`
## Configuration
The bot is configured using the \`.env\` file in the \`openwebui-bot\` directory.
EOF
# Create a tar archive of the deployment files
echo "Creating tar archive..."
cd $TEMP_DIR
tar -czf openwebui-bot-deploy.tar.gz *
cd -
# Copy the tar archive to the current directory
cp $TEMP_DIR/openwebui-bot-deploy.tar.gz .
echo "Deployment package created: openwebui-bot-deploy.tar.gz"
echo "To deploy on the server:"
echo "1. Copy the package to the server:"
echo " scp openwebui-bot-deploy.tar.gz $SERVER_USER@$SERVER_IP:~/"
echo "2. SSH into the server:"
echo " ssh $SERVER_USER@$SERVER_IP"
echo "3. Extract the package:"
echo " mkdir -p bot-deploy && tar -xzf openwebui-bot-deploy.tar.gz -C bot-deploy"
echo "4. Run the deployment script:"
echo " cd bot-deploy && ./deploy.sh"
# Clean up
rm -rf $TEMP_DIR
+134 -72
View File
@@ -1,15 +1,27 @@
# Custom AI bot for our specific needs # Custom AI bot with improved error handling and connection methods
import asyncio import asyncio
import socketio import socketio
import os import os
import sys
import traceback import traceback
import logging
import aiohttp
import sys
from env import WEBUI_URL, TOKEN from env import WEBUI_URL, TOKEN
from utils import send_message, send_typing from utils import send_message, send_typing
import aiohttp
# Get configuration from environment variables # Set up logging
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.StreamHandler(),
logging.FileHandler('bot_debug.log')
]
)
logger = logging.getLogger('openwebui_bot')
# Get model configuration from environment variables
MODEL_ID = os.getenv("MODEL_ID", "llama3.1") MODEL_ID = os.getenv("MODEL_ID", "llama3.1")
SYSTEM_PROMPT = os.getenv("SYSTEM_PROMPT", "You are a helpful AI assistant.") SYSTEM_PROMPT = os.getenv("SYSTEM_PROMPT", "You are a helpful AI assistant.")
TEMPERATURE = float(os.getenv("TEMPERATURE", "0.7")) TEMPERATURE = float(os.getenv("TEMPERATURE", "0.7"))
@@ -24,11 +36,11 @@ sio = socketio.AsyncClient(logger=False, engineio_logger=False)
# Event handlers # Event handlers
@sio.event @sio.event
async def connect(): async def connect():
print("Connected to OpenWebUI!") logger.info("Connected to OpenWebUI!")
@sio.event @sio.event
async def disconnect(): async def disconnect():
print("Disconnected from OpenWebUI!") logger.info("Disconnected from OpenWebUI!")
# Function to call the OpenAI-compatible API # Function to call the OpenAI-compatible API
async def openai_chat_completion(messages): async def openai_chat_completion(messages):
@@ -43,7 +55,9 @@ async def openai_chat_completion(messages):
try: try:
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
try: logger.info(f"Sending request to {WEBUI_URL}/api/chat/completions")
logger.debug(f"Payload: {payload}")
async with session.post( async with session.post(
f"{WEBUI_URL}/api/chat/completions", f"{WEBUI_URL}/api/chat/completions",
headers={"Authorization": f"Bearer {TOKEN}"}, headers={"Authorization": f"Bearer {TOKEN}"},
@@ -51,53 +65,52 @@ async def openai_chat_completion(messages):
timeout=300 # 5-minute timeout timeout=300 # 5-minute timeout
) as response: ) as response:
if response.status == 200: if response.status == 200:
return await response.json() result = await response.json()
logger.info("API request successful")
return result
else: else:
# Handle errors or return raw response text
error_text = await response.text() error_text = await response.text()
print(f"API error: {response.status} - {error_text}") logger.error(f"API error: {response.status} - {error_text}")
return {"error": error_text, "status": response.status} return {"error": error_text, "status": response.status}
except aiohttp.ClientError as e:
print(f"HTTP request error: {str(e)}")
return {"error": f"HTTP request error: {str(e)}", "status": 500}
except Exception as e: except Exception as e:
print(f"Unexpected error in openai_chat_completion: {str(e)}") logger.error(f"Error in openai_chat_completion: {str(e)}")
return {"error": f"Unexpected error: {str(e)}", "status": 500} logger.error(traceback.format_exc())
return {"error": f"Error: {str(e)}", "status": 500}
# Helper function to send typing indicators while waiting for a response # Helper function to send typing indicators while waiting for a response
async def send_typing_until_complete(channel_id, coro): async def send_typing_until_complete(channel_id, coro):
""" """
Sends typing indicators every second until the provided coroutine completes. Sends typing indicators every second until the provided coroutine completes.
""" """
task = asyncio.create_task(coro) # Begin the provided coroutine task task = asyncio.create_task(coro)
try: try:
# While the task is running, send typing indicators every second
while not task.done(): while not task.done():
await send_typing(sio, channel_id) await send_typing(sio, channel_id)
await asyncio.sleep(1) await asyncio.sleep(1)
# Await the actual result of the coroutine
return await task return await task
except Exception as e: except Exception as e:
task.cancel() task.cancel()
raise e # Propagate any exceptions that occurred in the coroutine raise e
# Define a function to handle channel events # Define a function to handle channel events
def events(user_id): def events(user_id):
# Use the configured triggers and respond_to_all setting
global TRIGGERS, RESPOND_TO_ALL
@sio.on("channel-events") @sio.on("channel-events")
async def channel_events(data): async def channel_events(data):
if data["user"]["id"] == user_id: try:
logger.debug(f"Received channel event: {data}")
# Ignore events from the bot itself # Ignore events from the bot itself
if data["user"]["id"] == user_id:
logger.debug(f"Ignoring message from self (bot ID: {user_id})")
return return
# Only process message events
if data["data"]["type"] == "message": if data["data"]["type"] == "message":
message_content = data["data"]["data"]["content"] message_content = data["data"]["data"]["content"]
channel_id = data["channel_id"] channel_id = data["channel_id"]
sender_name = data["user"]["name"] sender_name = data["user"]["name"]
print(f"{sender_name}: {message_content}") logger.info(f"Message in channel: {sender_name}: {message_content}")
# Check if we should respond # Check if we should respond
should_respond = RESPOND_TO_ALL should_respond = RESPOND_TO_ALL
@@ -108,11 +121,12 @@ def events(user_id):
for trigger in TRIGGERS: for trigger in TRIGGERS:
trigger_lower = trigger.lower() trigger_lower = trigger.lower()
if trigger_lower in message_lower: if trigger_lower in message_lower:
logger.info(f"Trigger detected: {trigger}")
should_respond = True should_respond = True
break break
if not should_respond: if not should_respond:
# Skip messages that don't mention the bot logger.debug("No trigger detected, skipping message")
return return
# Remove the trigger from the message # Remove the trigger from the message
@@ -159,102 +173,150 @@ def events(user_id):
error_message = response.get("error", "I'm sorry, I couldn't generate a response.") error_message = response.get("error", "I'm sorry, I couldn't generate a response.")
await send_message(channel_id, f"🤖 Error: {error_message}") await send_message(channel_id, f"🤖 Error: {error_message}")
except Exception as e: except Exception as e:
print(f"Error generating response: {str(e)}") logger.error(f"Error generating response: {str(e)}")
logger.error(traceback.format_exc())
await send_message( await send_message(
channel_id, channel_id,
"🤖 Something went wrong while processing your request." "🤖 Something went wrong while processing your request."
) )
except Exception as e:
logger.error(f"Error processing channel event: {str(e)}")
logger.error(traceback.format_exc())
# Define an async function for the main workflow # Define an async function for the main workflow
async def main(): async def main():
max_retries = 3 max_retries = 5
retry_delay = 5 # seconds retry_delay = 5 # seconds
for attempt in range(1, max_retries + 1): for attempt in range(1, max_retries + 1):
try: try:
print(f"Connecting to {WEBUI_URL}... (Attempt {attempt}/{max_retries})") # Ensure the URL is properly formatted
base_url = WEBUI_URL.rstrip('/')
logger.info(f"Connecting to {base_url}... (Attempt {attempt}/{max_retries})")
# Try different connection methods
connection_methods = [
# Method 1: Standard connection
{
"url": base_url,
"socketio_path": "/ws/socket.io",
"transports": ["websocket"],
"description": "Standard WebSocket connection"
},
# Method 2: Alternative socket.io path
{
"url": base_url,
"socketio_path": "/socket.io",
"transports": ["websocket"],
"description": "Alternative socket.io path"
},
# Method 3: Try with polling transport
{
"url": base_url,
"socketio_path": "/ws/socket.io",
"transports": ["polling", "websocket"],
"description": "Polling transport"
},
# Method 4: Alternative path with polling
{
"url": base_url,
"socketio_path": "/socket.io",
"transports": ["polling", "websocket"],
"description": "Alternative path with polling"
}
]
# Try each connection method
connected = False
for method in connection_methods:
if connected:
break
try:
logger.info(f"Trying {method['description']}...")
await sio.connect( await sio.connect(
WEBUI_URL, socketio_path="/ws/socket.io", transports=["websocket"] method["url"],
socketio_path=method["socketio_path"],
transports=method["transports"]
) )
print("Connection established!") logger.info(f"Connection successful using {method['description']}!")
connected = True
except Exception as conn_error:
logger.error(f"{method['description']} failed: {str(conn_error)}")
if not connected:
raise Exception("All connection methods failed")
logger.info("Connection established!")
break # Connection successful, exit the retry loop break # Connection successful, exit the retry loop
except Exception as e: except Exception as e:
print(f"Failed to connect: {e}") logger.error(f"Failed to connect: {e}")
logger.error(traceback.format_exc())
if attempt < max_retries: if attempt < max_retries:
print(f"Retrying in {retry_delay} seconds...") logger.info(f"Retrying in {retry_delay} seconds...")
await asyncio.sleep(retry_delay) await asyncio.sleep(retry_delay)
else: else:
print("Maximum connection attempts reached. Exiting.") logger.error("Maximum connection attempts reached. Exiting.")
return return
try: try:
# Callback function for user-join # Callback function for user-join
async def join_callback(*args): async def join_callback(*args):
try: try:
logger.info(f"Join callback received: {args}")
if args and len(args) > 0: if args and len(args) > 0:
data = args[0] data = args[0]
print(f"Received callback data: {data}")
if isinstance(data, dict) and "id" in data: if isinstance(data, dict) and "id" in data:
bot_id = data["id"] bot_id = data["id"]
print(f"Bot connected with ID: {bot_id}") logger.info(f"Bot connected with ID: {bot_id}")
events(bot_id) # Attach the event handlers dynamically events(bot_id) # Attach the event handlers
else: else:
print(f"Invalid callback data format: {data}") logger.warning(f"Invalid callback data: {data}")
events("bot-default-id") # Use a default ID
else: else:
print("No callback data received") logger.warning("No callback data received")
# If no data is received, use a default ID events("bot-default-id") # 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: except Exception as e:
print(f"Error in join_callback: {str(e)}") logger.error(f"Error in join callback: {str(e)}")
print(traceback.format_exc()) logger.error(traceback.format_exc())
# Authenticate with the server # Authenticate with the server
print("Authenticating with the server...") logger.info("Authenticating with the server...")
await sio.emit("user-join", {"auth": {"token": TOKEN}}, callback=join_callback) await sio.emit("user-join", {"auth": {"token": TOKEN}}, callback=join_callback)
print("Authentication request sent")
# Register for channel events directly since the callback might not provide the bot ID
logger.info("Registering for channel events directly...")
events("bot-user") # Use a default bot ID
# Wait indefinitely to keep the connection open # Wait indefinitely to keep the connection open
print("Waiting for events...") logger.info("Waiting for events...")
await sio.wait() await sio.wait()
except Exception as e: except Exception as e:
print(f"Error in main loop: {str(e)}") logger.error(f"Error in main loop: {str(e)}")
logger.error(traceback.format_exc())
# Actually run the async `main` function using `asyncio` # Graceful shutdown
async def shutdown(): async def shutdown():
"""Gracefully shut down the bot.""" logger.info("Shutting down bot...")
print("\nShutting down bot...")
if sio.connected: if sio.connected:
print("Disconnecting from OpenWebUI...")
await sio.disconnect() await sio.disconnect()
print("Bot shutdown complete.") logger.info("Bot shutdown complete.")
if __name__ == "__main__": if __name__ == "__main__":
print("Starting custom AI bot...") logger.info("Starting custom AI bot...")
print(f"OpenWebUI URL: {WEBUI_URL}") logger.info(f"OpenWebUI URL: {WEBUI_URL}")
print(f"Model: {MODEL_ID}") logger.info(f"Model: {MODEL_ID}")
print(f"System prompt: {SYSTEM_PROMPT[:50]}..." if len(SYSTEM_PROMPT) > 50 else f"System prompt: {SYSTEM_PROMPT}") logger.info(f"Triggers: {TRIGGERS}")
print(f"Temperature: {TEMPERATURE}") logger.info(f"Respond to all: {RESPOND_TO_ALL}")
print(f"Max tokens: {MAX_TOKENS}")
print(f"Top-p: {TOP_P}")
print(f"Triggers: {TRIGGERS}")
print(f"Respond to all: {RESPOND_TO_ALL}")
print("Press Ctrl+C to stop")
try: try:
# Run the main function
asyncio.run(main()) asyncio.run(main())
except KeyboardInterrupt: except KeyboardInterrupt:
print("\nBot stopped by user") logger.info("Bot stopped by user")
# Run the shutdown function
try: try:
asyncio.run(shutdown()) asyncio.run(shutdown())
except Exception as e: except Exception as e:
print(f"Error during shutdown: {str(e)}") logger.error(f"Error during shutdown: {str(e)}")
except Exception as e: except Exception as e:
print(f"Error running bot: {str(e)}") logger.error(f"Error running bot: {str(e)}")
# Try to shut down gracefully logger.error(traceback.format_exc())
try:
asyncio.run(shutdown())
except Exception as shutdown_error:
print(f"Error during shutdown: {str(shutdown_error)}")
+4
View File
@@ -0,0 +1,4 @@
python-socketio>=5.10.0
aiohttp>=3.9.1
python-dotenv>=1.0.0
websockets>=12.0
+9 -6
View File
@@ -2,7 +2,7 @@
""" """
Script to run the OpenWebUI AI bot. Script to run the OpenWebUI AI bot.
This script runs the AI bot example from the openwebui-bot repository. This script runs the custom AI bot from the openwebui-bot repository.
""" """
import sys import sys
@@ -10,17 +10,16 @@ import os
import asyncio import asyncio
# Add the openwebui-bot directory to the Python path # Add the openwebui-bot directory to the Python path
# Use a path relative to the current file's directory to ensure it works in any environment
current_dir = os.path.dirname(os.path.abspath(__file__)) current_dir = os.path.dirname(os.path.abspath(__file__))
openwebui_bot_dir = os.path.join(current_dir, 'openwebui-bot') openwebui_bot_dir = os.path.join(current_dir, 'openwebui-bot')
sys.path.insert(0, openwebui_bot_dir) sys.path.insert(0, openwebui_bot_dir)
print(f"Adding OpenWebUI bot directory to Python path: {openwebui_bot_dir}") print(f"Adding OpenWebUI bot directory to Python path: {openwebui_bot_dir}")
# Import the main function from the AI example # Import the main function from the custom AI example
from examples.ai import main from examples.custom_ai import main, shutdown
if __name__ == "__main__": if __name__ == "__main__":
print("Starting OpenWebUI AI bot...") print("Starting OpenWebUI bot...")
print("Press Ctrl+C to stop") print("Press Ctrl+C to stop")
try: try:
@@ -28,7 +27,11 @@ if __name__ == "__main__":
asyncio.run(main()) asyncio.run(main())
except KeyboardInterrupt: except KeyboardInterrupt:
print("\nBot stopped by user") print("\nBot stopped by user")
# No need to call shutdown here as it's handled in the main function # Run the shutdown function
try:
asyncio.run(shutdown())
except Exception as e:
print(f"Error during shutdown: {str(e)}")
except Exception as e: except Exception as e:
print(f"Error running bot: {str(e)}") print(f"Error running bot: {str(e)}")
print("Check that the OpenWebUI server is running and accessible.") print("Check that the OpenWebUI server is running and accessible.")
+101
View File
@@ -0,0 +1,101 @@
#!/usr/bin/env python3
"""
Script to send a test message to an OpenWebUI channel.
"""
import asyncio
import aiohttp
import json
import sys
# Configuration
OPENWEBUI_URL = "http://104.225.217.215:8080"
API_KEY = "GdCU4ieYDqHsLfH2"
async def create_channel():
"""Create a test channel."""
print("Creating a test channel...")
async with aiohttp.ClientSession() as session:
headers = {"Authorization": f"Bearer {API_KEY}"}
channel_data = {
"name": "Bot Test Channel",
"description": "Channel for testing the bot"
}
try:
async with session.post(
f"{OPENWEBUI_URL}/api/channels",
headers=headers,
json=channel_data
) as response:
if response.status == 200:
channel = await response.json()
channel_id = channel["id"]
print(f"Created channel with ID: {channel_id}")
return channel_id
else:
print(f"Failed to create channel: {response.status} - {await response.text()}")
return None
except Exception as e:
print(f"Error creating channel: {str(e)}")
return None
async def send_message(channel_id, message):
"""Send a message to a channel."""
print(f"Sending message to channel {channel_id}: {message}")
async with aiohttp.ClientSession() as session:
headers = {"Authorization": f"Bearer {API_KEY}"}
message_data = {
"content": message
}
try:
async with session.post(
f"{OPENWEBUI_URL}/api/v1/channels/{channel_id}/messages/post",
headers=headers,
json=message_data
) as response:
if response.status == 200:
print("Message sent successfully!")
return True
else:
print(f"Failed to send message: {response.status} - {await response.text()}")
return False
except Exception as e:
print(f"Error sending message: {str(e)}")
return False
async def main():
"""Main function."""
# Create a channel
channel_id = await create_channel()
if not channel_id:
print("Failed to create a channel. Exiting.")
return False
# Send a test message
success = await send_message(channel_id, "@ai Hello, are you working?")
if success:
print(f"Test complete! Check the channel at {OPENWEBUI_URL}/channels/{channel_id}")
return True
else:
print("Failed to send test message.")
return False
if __name__ == "__main__":
try:
result = asyncio.run(main())
if result:
print("Test successful!")
sys.exit(0)
else:
print("Test failed!")
sys.exit(1)
except KeyboardInterrupt:
print("Test interrupted by user.")
sys.exit(130)
except Exception as e:
print(f"Unexpected error: {str(e)}")
sys.exit(1)
+198
View File
@@ -0,0 +1,198 @@
#!/usr/bin/env python3
"""
Test script for OpenWebUI bot.
This script tests the connection to OpenWebUI and the bot's functionality.
"""
import sys
import os
import asyncio
import aiohttp
import json
import logging
# Set up logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger('bot_test')
# Configuration
OPENWEBUI_URL = "http://104.225.217.215:8080"
API_KEY = "GdCU4ieYDqHsLfH2"
MODEL_ID = "llama3.1"
async def test_openwebui_api():
"""Test the OpenWebUI API connection."""
logger.info("Testing OpenWebUI API connection...")
try:
async with aiohttp.ClientSession() as session:
# Test 1: Check if the API is accessible
logger.info("Testing API access...")
headers = {"Authorization": f"Bearer {API_KEY}"}
async with session.get(
f"{OPENWEBUI_URL}/api/models",
headers=headers
) as response:
if response.status == 200:
models = await response.json()
logger.info(f"API accessible. Available models: {json.dumps(models, indent=2)}")
else:
logger.error(f"API error: {response.status} - {await response.text()}")
return False
# Test 2: Test authentication
logger.info("Testing API authentication...")
headers = {"Authorization": f"Bearer {API_KEY}"}
async with session.get(
f"{OPENWEBUI_URL}/api/channels",
headers=headers
) as response:
if response.status == 200:
channels = await response.json()
logger.info(f"Authentication successful. Channels: {json.dumps(channels, indent=2)}")
else:
logger.error(f"Authentication error: {response.status} - {await response.text()}")
return False
# Test 3: Test chat completion
logger.info("Testing chat completion...")
payload = {
"model": MODEL_ID,
"messages": [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Say hello in one short sentence."}
],
"stream": False
}
async with session.post(
f"{OPENWEBUI_URL}/api/chat/completions",
headers=headers,
json=payload
) as response:
if response.status == 200:
result = await response.json()
if "choices" in result and len(result["choices"]) > 0:
content = result["choices"][0]["message"]["content"]
logger.info(f"Chat completion successful. Response: {content}")
else:
logger.error(f"Chat completion error: Invalid response format - {json.dumps(result, indent=2)}")
return False
else:
logger.error(f"Chat completion error: {response.status} - {await response.text()}")
return False
logger.info("All API tests passed!")
return True
except Exception as e:
logger.error(f"API test error: {str(e)}")
return False
async def test_channel_message():
"""Test sending a message to a channel."""
logger.info("Testing channel message...")
try:
async with aiohttp.ClientSession() as session:
# Get available channels
headers = {"Authorization": f"Bearer {API_KEY}"}
async with session.get(
f"{OPENWEBUI_URL}/api/channels",
headers=headers
) as response:
if response.status == 200:
channels = await response.json()
if not channels or len(channels) == 0:
logger.warning("No channels available. Creating a test channel...")
# Create a test channel
channel_data = {
"name": "Bot Test Channel",
"description": "Channel for testing the bot"
}
async with session.post(
f"{OPENWEBUI_URL}/api/channels",
headers=headers,
json=channel_data
) as create_response:
if create_response.status == 200:
channel = await create_response.json()
channel_id = channel["id"]
logger.info(f"Created test channel with ID: {channel_id}")
else:
logger.error(f"Failed to create channel: {create_response.status} - {await create_response.text()}")
return False
else:
# Use the first available channel
channel_id = channels[0]["id"]
logger.info(f"Using existing channel with ID: {channel_id}")
# Send a test message to the channel
message_data = {
"content": "@ai Hello, are you working?"
}
async with session.post(
f"{OPENWEBUI_URL}/api/v1/channels/{channel_id}/messages/post",
headers=headers,
json=message_data
) as message_response:
if message_response.status == 200:
logger.info("Test message sent successfully!")
logger.info("Check the channel to see if the bot responds.")
logger.info(f"Channel URL: {OPENWEBUI_URL}/channels/{channel_id}")
return True
else:
logger.error(f"Failed to send message: {message_response.status} - {await message_response.text()}")
return False
else:
logger.error(f"Failed to get channels: {response.status} - {await response.text()}")
return False
except Exception as e:
logger.error(f"Channel test error: {str(e)}")
return False
async def main():
"""Run all tests."""
logger.info("Starting OpenWebUI bot tests...")
# Test 1: OpenWebUI API
api_result = await test_openwebui_api()
if not api_result:
logger.error("API tests failed!")
return False
# Test 2: Channel message
channel_result = await test_channel_message()
if not channel_result:
logger.error("Channel tests failed!")
return False
logger.info("All tests completed successfully!")
logger.info("Note: The bot should respond to the test message in the channel.")
logger.info("Check the bot logs to see if it received and processed the message.")
return True
if __name__ == "__main__":
try:
result = asyncio.run(main())
if result:
logger.info("Tests passed!")
sys.exit(0)
else:
logger.error("Tests failed!")
sys.exit(1)
except KeyboardInterrupt:
logger.info("Tests interrupted by user.")
sys.exit(130)
except Exception as e:
logger.error(f"Unexpected error: {str(e)}")
sys.exit(1)