Latest fixxes

This commit is contained in:
Iyeoluwa Akinrinola
2025-05-16 13:23:35 +01:00
parent f00941cece
commit e82861a5db
7 changed files with 709 additions and 13 deletions
+6
View File
@@ -8,6 +8,7 @@ A backend service for OpenWebUI that provides OpenWebUI-compatible API endpoints
- Ollama API proxy - Ollama API proxy
- Chat functionality with model switching - Chat functionality with model switching
- Support for multiple LLM models (gemma3, llama3.3, llama3.1, mistral, deepseek) - Support for multiple LLM models (gemma3, llama3.3, llama3.1, mistral, deepseek)
- Team chat integration with OpenWebUI channels
## Technology Stack ## Technology Stack
@@ -25,6 +26,7 @@ ai_service/
├── embeddings/ # Document processing for RAG ├── embeddings/ # Document processing for RAG
│ └── document_service.py │ └── document_service.py
├── openwebui_api.py # OpenWebUI-compatible API endpoints ├── openwebui_api.py # OpenWebUI-compatible API endpoints
├── openwebui_channels.py # OpenWebUI channels integration
├── config.py # Configuration settings ├── config.py # Configuration settings
├── api.py # FastAPI application ├── api.py # FastAPI application
└── deploy.sh # Deployment script └── deploy.sh # Deployment script
@@ -88,3 +90,7 @@ To configure OpenWebUI to use this service as its backend:
``` ```
2. Restart OpenWebUI to apply the changes. 2. Restart OpenWebUI to apply the changes.
## Team Chat Feature
The service now integrates with OpenWebUI's channels feature to provide team chat functionality. See [TEAM_CHAT_GUIDE.md](TEAM_CHAT_GUIDE.md) for detailed instructions on how to use team chats.
+153
View File
@@ -0,0 +1,153 @@
# Team Chat Guide
This guide explains how to use the team chat feature with OpenWebUI channels.
## Overview
The chatbot now integrates with OpenWebUI's channels feature to provide team chat functionality. When you create a team chat in the chatbot, it automatically creates a corresponding channel in OpenWebUI, allowing multiple users to participate in the same conversation.
## Using Team Chats
### AI Responses in Team Chats
When you send a message in a team chat, the AI will respond both in your local chat and in the OpenWebUI channel. The AI's responses in OpenWebUI channels:
- Are prefixed with a robot emoji (🤖) to clearly identify them as AI responses
- Appear with a special "ai-assistant" user ID to distinguish them from human users
- Are visible to all members of the channel in real-time
This allows all team members to see the conversation with the AI and collaborate effectively.
### How the AI Bot is Triggered
The AI bot can be triggered to respond in two ways:
1. **Through the API**: When you send a message using the `/chats/{chat_id}/messages` endpoint, the AI automatically processes it and responds.
2. **Directly in OpenWebUI**: When someone mentions the AI in an OpenWebUI channel that's linked to a team chat:
- The message is sent to your service through a webhook
- If it contains an AI mention (like `@ai`, `@bot`, etc.), the AI processes it
- The AI sends its response back to the OpenWebUI channel
By default, the AI only responds when explicitly mentioned with one of these triggers:
- `@ai`
- `@bot`
- `@assistant`
- `@chatbot`
You can customize these triggers or make the AI respond to all messages by changing the settings in your `.env` file:
```
# To customize the triggers that activate the AI
AI_TRIGGERS=@ai,@bot,@assistant,@chatbot
# To make the AI respond to all messages (not just mentions)
AI_RESPOND_TO_ALL=false # Change to 'true' to respond to everything
```
This mention-based approach ensures the AI only joins the conversation when explicitly invited, making team chats more focused and preventing the AI from responding to every message.
### Creating a Team Chat
You can create a team chat in two ways:
1. **Through the API**:
```
POST /chats
{
"user_id": "your-user-id",
"title": "Team Chat Name",
"model_id": "llama3.1",
"is_team_chat": true
}
```
2. **Through OpenWebUI**:
- Log in to OpenWebUI at http://104.225.217.215:8080/
- Navigate to the Channels section (look for a "#" or group icon in the sidebar)
- Click "Create Channel" or "+" button
- Give your channel a name and description
- Choose whether it should be private or public
- Click "Create"
### Adding Members to a Team Chat
1. **Through the API**:
```
POST /chats/{chat_id}/members/{user_id}
```
2. **Through OpenWebUI**:
- Open the channel in OpenWebUI
- Look for a "Members" or "Invite" option
- Add users by their username or email
### Sending Messages in a Team Chat
1. **Through the API**:
```
POST /chats/{chat_id}/messages
{
"message": "Your message",
"user_id": "your-user-id"
}
```
2. **Through OpenWebUI**:
- Open the channel in OpenWebUI
- Type your message in the input box
- Press Enter to send
### Viewing Team Chats
1. **Through the API**:
```
GET /chats/user/{user_id}
```
This will return all chats for the user, including team chats where they are a member.
2. **Through OpenWebUI**:
- Log in to OpenWebUI
- Navigate to the Channels section
- You'll see all channels you're a member of
## Technical Implementation
The team chat feature works by:
1. Creating an OpenWebUI channel when a team chat is created
2. Adding members to both the local team chat and the OpenWebUI channel
3. Sending messages to both the local chat and the OpenWebUI channel
4. Deleting the OpenWebUI channel when the team chat is deleted
## Troubleshooting
If you encounter issues with team chats:
1. **Channel not appearing in OpenWebUI**:
- Check if the OpenWebUI server is running
- Verify that the OpenWebUI URL and API key are correctly configured in the `.env` file
2. **Cannot add members to a team chat**:
- Ensure the user exists in OpenWebUI
- Check if the team chat was properly created with `is_team_chat: true`
3. **Messages not appearing in OpenWebUI channel**:
- Check the logs for any errors when sending messages
- Verify that the OpenWebUI channel ID is correctly stored in the chat data
## API Reference
### Team Chat Endpoints
- `POST /chats` - Create a new chat (set `is_team_chat: true` for team chats)
- `GET /chats/user/{user_id}` - Get all chats for a user (includes team chats)
- `POST /chats/{chat_id}/members/{user_id}` - Add a user to a team chat
- `DELETE /chats/{chat_id}/members/{user_id}` - Remove a user from a team chat
- `DELETE /chats/{chat_id}` - Delete a chat (also deletes the OpenWebUI channel)
### OpenWebUI Channel Endpoints
- `GET /channels` - Get all OpenWebUI channels
- `GET /channels/{channel_id}` - Get an OpenWebUI channel by ID
- `POST /channels` - Create a new OpenWebUI channel
+5
View File
@@ -1,6 +1,7 @@
# API configuration # API configuration
API_HOST=0.0.0.0 API_HOST=0.0.0.0
API_PORT=5251 API_PORT=5251
PUBLIC_URL=http://your-public-url:5251 # Public URL for webhooks, needed for OpenWebUI to send channel messages
# OpenWebUI configuration # OpenWebUI configuration
OPENWEBUI_URL=http://104.225.217.215:8080 OPENWEBUI_URL=http://104.225.217.215:8080
@@ -13,3 +14,7 @@ DEFAULT_MODEL=llama3.1
# Document processing # Document processing
CHUNK_SIZE=1000 CHUNK_SIZE=1000
CHUNK_OVERLAP=200 CHUNK_OVERLAP=200
# AI bot configuration
AI_TRIGGERS=@ai,@bot,@assistant,@chatbot # Comma-separated list of triggers that will make the AI respond
AI_RESPOND_TO_ALL=false # Set to 'true' to make the AI respond to all messages, 'false' to only respond to mentions
+152
View File
@@ -13,6 +13,7 @@ from datetime import datetime, timezone
from ai_service.models.model_service import model_service from ai_service.models.model_service import model_service
from ai_service.models.chat_service import chat_service from ai_service.models.chat_service import chat_service
from ai_service.openwebui_api import router as openwebui_router from ai_service.openwebui_api import router as openwebui_router
from ai_service.openwebui_channels import openwebui_channels
from ai_service.config import config from ai_service.config import config
# Create FastAPI app # Create FastAPI app
@@ -37,6 +38,27 @@ app.include_router(openwebui_router, prefix="/api")
# Include Ollama proxy routes # Include Ollama proxy routes
app.include_router(openwebui_router, prefix="/ollama") app.include_router(openwebui_router, prefix="/ollama")
# Register webhook for channel messages on startup
@app.on_event("startup")
async def startup_event():
"""
Register webhook for channel messages on startup.
"""
# Get the public URL of this service
service_url = f"http://{config.API_HOST}:{config.API_PORT}"
if config.PUBLIC_URL:
service_url = config.PUBLIC_URL
# Register webhook
webhook_url = f"{service_url}/webhooks/channel-message"
print(f"Registering webhook for channel messages: {webhook_url}")
success = openwebui_channels.register_webhook(webhook_url)
if success:
print("Successfully registered webhook for channel messages")
else:
print("Failed to register webhook for channel messages")
# Define API models for health check # Define API models for health check
class HealthResponse(BaseModel): class HealthResponse(BaseModel):
"""Response model for health check.""" """Response model for health check."""
@@ -450,3 +472,133 @@ async def delete_chat(chat_id: str):
raise HTTPException(status_code=404, detail="Chat not found") raise HTTPException(status_code=404, detail="Chat not found")
return {"status": "success", "message": "Chat deleted"} return {"status": "success", "message": "Chat deleted"}
# OpenWebUI Channels endpoints
@app.get("/channels")
async def get_openwebui_channels():
"""
Get all OpenWebUI channels.
Returns:
List of channels.
"""
channels = openwebui_channels.get_channels()
return channels
@app.get("/channels/{channel_id}")
async def get_openwebui_channel(channel_id: str):
"""
Get an OpenWebUI channel by ID.
Args:
channel_id: Channel ID.
Returns:
Channel information.
"""
channel = openwebui_channels.get_channel(channel_id)
if not channel:
raise HTTPException(status_code=404, detail="Channel not found")
return channel
@app.post("/channels")
async def create_openwebui_channel(name: str, description: str = "", is_private: bool = False):
"""
Create a new OpenWebUI channel.
Args:
name: Channel name.
description: Channel description.
is_private: Whether the channel is private.
Returns:
Created channel.
"""
channel = openwebui_channels.create_channel(name, description, is_private)
if not channel:
raise HTTPException(status_code=400, detail="Failed to create channel")
return channel
# Webhook endpoint for OpenWebUI channel messages
class ChannelMessageWebhook(BaseModel):
"""Model for channel message webhook."""
channel_id: str = Field(..., description="Channel ID")
message: str = Field(..., description="Message content")
user_id: str = Field(..., description="User ID")
timestamp: Optional[str] = Field(None, description="Message timestamp")
@app.post("/webhooks/channel-message")
async def channel_message_webhook(request: ChannelMessageWebhook):
"""
Webhook endpoint for receiving messages from OpenWebUI channels.
This endpoint is called by OpenWebUI when a message is sent in a channel.
The AI service will process the message and respond in the channel.
Args:
request: Channel message webhook request.
Returns:
Processing status.
"""
try:
print(f"Received channel message webhook: {request.channel_id}, {request.user_id}, {request.message}")
# Find the chat associated with this OpenWebUI channel
chat_id = None
for cid, chat in chat_service.chats.items():
if chat.get('is_team_chat') and chat.get('openwebui_channel_id') == request.channel_id:
chat_id = cid
break
if not chat_id:
print(f"No chat found for OpenWebUI channel {request.channel_id}")
return {"status": "error", "message": "No chat found for this channel"}
# Skip messages from the AI assistant to avoid loops
if request.user_id == "ai-assistant":
return {"status": "skipped", "message": "Skipping AI assistant message"}
# Check if we should respond to all messages or only to mentions
if not config.AI_RESPOND_TO_ALL:
# Check if the message mentions the AI using configured triggers
message_lower = request.message.lower()
is_triggered = False
for trigger in config.AI_TRIGGERS:
if trigger.lower() in message_lower:
is_triggered = True
break
# If no trigger is found, skip processing
if not is_triggered:
print(f"No AI mention found in message, skipping: {request.message[:50]}...")
return {"status": "skipped", "message": "No AI mention found in message"}
# Extract the actual message content (remove the trigger)
# This is a simple approach - for more complex cases, you might want more sophisticated parsing
processed_message = request.message
message_lower = request.message.lower()
# Only try to remove triggers if we're not responding to all messages
if not config.AI_RESPOND_TO_ALL:
for trigger in config.AI_TRIGGERS:
if trigger.lower() in message_lower:
# Remove the trigger from the message
processed_message = request.message.replace(trigger, "").strip()
break
# Process the message and generate a response
response = chat_service.get_chat_response(
chat_id=chat_id,
message=processed_message,
user_id=request.user_id
)
return {"status": "success", "message": "Message processed", "response": response}
except Exception as e:
print(f"Error processing channel message webhook: {str(e)}")
return {"status": "error", "message": f"Error processing message: {str(e)}"}
+11 -3
View File
@@ -3,12 +3,15 @@ Configuration settings for the AI service.
""" """
import os import os
from dotenv import load_dotenv
# Load environment variables from .env file
import os.path import os.path
# Try to load environment variables from .env file
try:
from dotenv import load_dotenv
dotenv_path = os.path.join(os.path.dirname(__file__), '.env') dotenv_path = os.path.join(os.path.dirname(__file__), '.env')
load_dotenv(dotenv_path=dotenv_path) load_dotenv(dotenv_path=dotenv_path)
except ImportError:
print("Warning: python-dotenv not installed. Using environment variables directly.")
class Config: class Config:
"""Base configuration.""" """Base configuration."""
@@ -16,6 +19,7 @@ class Config:
# API configuration # API configuration
API_HOST = os.environ.get('API_HOST', '0.0.0.0') API_HOST = os.environ.get('API_HOST', '0.0.0.0')
API_PORT = int(os.environ.get('API_PORT', 5252)) API_PORT = int(os.environ.get('API_PORT', 5252))
PUBLIC_URL = os.environ.get('PUBLIC_URL', '') # Public URL for webhooks
# OpenWebUI configuration # OpenWebUI configuration
OPENWEBUI_URL = os.environ.get('OPENWEBUI_URL', 'http://104.225.217.215:8080') OPENWEBUI_URL = os.environ.get('OPENWEBUI_URL', 'http://104.225.217.215:8080')
@@ -30,5 +34,9 @@ class Config:
CHUNK_SIZE = int(os.environ.get('CHUNK_SIZE', 1000)) CHUNK_SIZE = int(os.environ.get('CHUNK_SIZE', 1000))
CHUNK_OVERLAP = int(os.environ.get('CHUNK_OVERLAP', 200)) CHUNK_OVERLAP = int(os.environ.get('CHUNK_OVERLAP', 200))
# AI bot configuration
AI_TRIGGERS = os.environ.get('AI_TRIGGERS', '@ai,@bot,@assistant,@chatbot').split(',')
AI_RESPOND_TO_ALL = os.environ.get('AI_RESPOND_TO_ALL', 'false').lower() == 'true'
config = Config() config = Config()
+105 -8
View File
@@ -11,6 +11,7 @@ from typing import List, Dict, Any, Optional
from ai_service.config import config from ai_service.config import config
from ai_service.models.model_service import model_service from ai_service.models.model_service import model_service
from ai_service.models.model_parameters import ModelParameters from ai_service.models.model_parameters import ModelParameters
from ai_service.openwebui_channels import openwebui_channels
class ChatService: class ChatService:
"""Service for chat functionality.""" """Service for chat functionality."""
@@ -61,17 +62,40 @@ class ChatService:
# Generate a unique ID for the chat # Generate a unique ID for the chat
chat_id = str(uuid.uuid4()) chat_id = str(uuid.uuid4())
# Default title if none provided
chat_title = title or f"Chat {len(self.chats) + 1}"
# For team chats, create an OpenWebUI channel
openwebui_channel_id = None
if is_team_chat:
try:
# Create a channel in OpenWebUI
channel_response = openwebui_channels.create_channel(
name=chat_title,
description=f"Team chat created by {user_id}",
is_private=True # Team chats are private by default
)
if channel_response:
openwebui_channel_id = channel_response.get('id')
print(f"Created OpenWebUI channel with ID: {openwebui_channel_id}")
else:
print("Failed to create OpenWebUI channel, continuing with local team chat only")
except Exception as e:
print(f"Error creating OpenWebUI channel: {str(e)}")
# Create chat data # Create chat data
self.chats[chat_id] = { self.chats[chat_id] = {
'id': chat_id, 'id': chat_id,
'title': title or f"Chat {len(self.chats) + 1}", 'title': chat_title,
'user_id': user_id, 'user_id': user_id,
'model_id': model_id or config.DEFAULT_MODEL, 'model_id': model_id or config.DEFAULT_MODEL,
'is_team_chat': is_team_chat, 'is_team_chat': is_team_chat,
'created_at': datetime.utcnow().isoformat(), 'created_at': datetime.now().isoformat(),
'updated_at': datetime.utcnow().isoformat(), 'updated_at': datetime.now().isoformat(),
'messages': [], 'messages': [],
'team_members': [user_id] if is_team_chat else [] 'team_members': [user_id] if is_team_chat else [],
'openwebui_channel_id': openwebui_channel_id
} }
# Save chats to file # Save chats to file
@@ -96,20 +120,47 @@ class ChatService:
if chat_id not in self.chats: if chat_id not in self.chats:
raise ValueError(f"Chat with ID {chat_id} not found") raise ValueError(f"Chat with ID {chat_id} not found")
chat = self.chats[chat_id]
# Create message data # Create message data
message = { message = {
'id': str(uuid.uuid4()), 'id': str(uuid.uuid4()),
'content': content, 'content': content,
'user_id': user_id if is_user_message else None, 'user_id': user_id if is_user_message else None,
'is_user_message': is_user_message, 'is_user_message': is_user_message,
'timestamp': datetime.utcnow().isoformat() 'timestamp': datetime.now().isoformat()
} }
# Add message to chat # Add message to chat
self.chats[chat_id]['messages'].append(message) chat['messages'].append(message)
# Update chat timestamp # Update chat timestamp
self.chats[chat_id]['updated_at'] = datetime.utcnow().isoformat() chat['updated_at'] = datetime.now().isoformat()
# If this is a team chat with an OpenWebUI channel, send the message there too
if chat['is_team_chat'] and 'openwebui_channel_id' in chat and chat['openwebui_channel_id']:
try:
# For AI responses, use a special AI user ID
# This ensures the AI's messages are properly distinguished in OpenWebUI
sender_id = "ai-assistant" if not is_user_message else user_id
# Format the message for OpenWebUI
if is_user_message:
# For user messages, use the regular format
formatted_content = content
else:
# For AI responses, add a special prefix to make it clear it's from the AI
# This helps visually distinguish AI responses in the channel
formatted_content = f"🤖 {content}"
# Send message to OpenWebUI channel
openwebui_channels.send_message(
channel_id=chat['openwebui_channel_id'],
message=formatted_content,
user_id=sender_id
)
except Exception as e:
print(f"Error sending message to OpenWebUI channel: {str(e)}")
# Save chats to file # Save chats to file
self._save_chats() self._save_chats()
@@ -140,7 +191,7 @@ class ChatService:
""" """
user_chats = [] user_chats = []
for chat_id, chat in self.chats.items(): for _, chat in self.chats.items():
# Include private chats owned by the user # Include private chats owned by the user
if chat['user_id'] == user_id and not chat['is_team_chat']: if chat['user_id'] == user_id and not chat['is_team_chat']:
user_chats.append(chat) user_chats.append(chat)
@@ -173,6 +224,21 @@ class ChatService:
if not chat['is_team_chat']: if not chat['is_team_chat']:
return False return False
# Add to OpenWebUI channel if available
if 'openwebui_channel_id' in chat and chat['openwebui_channel_id']:
try:
# Add member to OpenWebUI channel
openwebui_success = openwebui_channels.add_member(
channel_id=chat['openwebui_channel_id'],
user_id=user_id
)
if not openwebui_success:
print(f"Warning: Failed to add user {user_id} to OpenWebUI channel {chat['openwebui_channel_id']}")
except Exception as e:
print(f"Error adding member to OpenWebUI channel: {str(e)}")
# Add to local team members list
if user_id not in chat['team_members']: if user_id not in chat['team_members']:
chat['team_members'].append(user_id) chat['team_members'].append(user_id)
self._save_chats() self._save_chats()
@@ -198,6 +264,21 @@ class ChatService:
if not chat['is_team_chat']: if not chat['is_team_chat']:
return False return False
# Remove from OpenWebUI channel if available
if 'openwebui_channel_id' in chat and chat['openwebui_channel_id']:
try:
# Remove member from OpenWebUI channel
openwebui_success = openwebui_channels.remove_member(
channel_id=chat['openwebui_channel_id'],
user_id=user_id
)
if not openwebui_success:
print(f"Warning: Failed to remove user {user_id} from OpenWebUI channel {chat['openwebui_channel_id']}")
except Exception as e:
print(f"Error removing member from OpenWebUI channel: {str(e)}")
# Remove from local team members list
if user_id in chat['team_members']: if user_id in chat['team_members']:
chat['team_members'].remove(user_id) chat['team_members'].remove(user_id)
self._save_chats() self._save_chats()
@@ -217,6 +298,22 @@ class ChatService:
if chat_id not in self.chats: if chat_id not in self.chats:
return False return False
chat = self.chats[chat_id]
# Delete OpenWebUI channel if this is a team chat
if chat['is_team_chat'] and 'openwebui_channel_id' in chat and chat['openwebui_channel_id']:
try:
# Delete the OpenWebUI channel
openwebui_success = openwebui_channels.delete_channel(
channel_id=chat['openwebui_channel_id']
)
if not openwebui_success:
print(f"Warning: Failed to delete OpenWebUI channel {chat['openwebui_channel_id']}")
except Exception as e:
print(f"Error deleting OpenWebUI channel: {str(e)}")
# Delete the chat from local storage
del self.chats[chat_id] del self.chats[chat_id]
self._save_chats() self._save_chats()
+275
View File
@@ -0,0 +1,275 @@
"""
OpenWebUI channels integration for team chats.
This module provides functions to interact with OpenWebUI channels API
for creating and managing team chats through OpenWebUI's channels feature.
It also includes functionality to listen for and respond to messages in OpenWebUI channels.
"""
import requests
import json
from typing import List, Dict, Any, Optional
from ai_service.config import config
class OpenWebUIChannels:
"""Class for interacting with OpenWebUI channels."""
def __init__(self):
"""Initialize the OpenWebUI channels integration."""
self.openwebui_url = config.OPENWEBUI_URL
self.openwebui_api_key = config.OPENWEBUI_API_KEY
self.headers = {
"Content-Type": "application/json"
}
# Add API key if available
if self.openwebui_api_key:
self.headers["Authorization"] = f"Bearer {self.openwebui_api_key}"
def create_channel(self, name: str, description: str = "", is_private: bool = False) -> Optional[Dict[str, Any]]:
"""
Create a new channel in OpenWebUI.
Args:
name: Name of the channel.
description: Description of the channel.
is_private: Whether the channel is private.
Returns:
Channel data if creation was successful, None otherwise.
"""
try:
# Prepare channel data
channel_data = {
"name": name,
"description": description,
"is_private": is_private
}
# Make API request to create channel
response = requests.post(
f"{self.openwebui_url}/api/channels",
headers=self.headers,
json=channel_data,
timeout=30
)
if response.status_code == 200 or response.status_code == 201:
return response.json()
else:
print(f"Error creating channel: {response.status_code} - {response.text}")
return None
except Exception as e:
print(f"Error creating channel: {str(e)}")
return None
def get_channel(self, channel_id: str) -> Optional[Dict[str, Any]]:
"""
Get a channel by ID.
Args:
channel_id: ID of the channel.
Returns:
Channel data if found, None otherwise.
"""
try:
# Make API request to get channel
response = requests.get(
f"{self.openwebui_url}/api/channels/{channel_id}",
headers=self.headers,
timeout=30
)
if response.status_code == 200:
return response.json()
else:
print(f"Error getting channel: {response.status_code} - {response.text}")
return None
except Exception as e:
print(f"Error getting channel: {str(e)}")
return None
def get_channels(self) -> List[Dict[str, Any]]:
"""
Get all channels.
Returns:
List of channel data.
"""
try:
# Make API request to get channels
response = requests.get(
f"{self.openwebui_url}/api/channels",
headers=self.headers,
timeout=30
)
if response.status_code == 200:
return response.json()
else:
print(f"Error getting channels: {response.status_code} - {response.text}")
return []
except Exception as e:
print(f"Error getting channels: {str(e)}")
return []
def add_member(self, channel_id: str, user_id: str) -> bool:
"""
Add a user to a channel.
Args:
channel_id: ID of the channel.
user_id: ID of the user to add.
Returns:
True if addition was successful, False otherwise.
"""
try:
# Prepare member data
member_data = {
"user_id": user_id
}
# Make API request to add member
response = requests.post(
f"{self.openwebui_url}/api/channels/{channel_id}/members",
headers=self.headers,
json=member_data,
timeout=30
)
return response.status_code == 200 or response.status_code == 201
except Exception as e:
print(f"Error adding member to channel: {str(e)}")
return False
def remove_member(self, channel_id: str, user_id: str) -> bool:
"""
Remove a user from a channel.
Args:
channel_id: ID of the channel.
user_id: ID of the user to remove.
Returns:
True if removal was successful, False otherwise.
"""
try:
# Make API request to remove member
response = requests.delete(
f"{self.openwebui_url}/api/channels/{channel_id}/members/{user_id}",
headers=self.headers,
timeout=30
)
return response.status_code == 200 or response.status_code == 204
except Exception as e:
print(f"Error removing member from channel: {str(e)}")
return False
def delete_channel(self, channel_id: str) -> bool:
"""
Delete a channel.
Args:
channel_id: ID of the channel.
Returns:
True if deletion was successful, False otherwise.
"""
try:
# Make API request to delete channel
response = requests.delete(
f"{self.openwebui_url}/api/channels/{channel_id}",
headers=self.headers,
timeout=30
)
return response.status_code == 200 or response.status_code == 204
except Exception as e:
print(f"Error deleting channel: {str(e)}")
return False
def register_webhook(self, webhook_url: str) -> bool:
"""
Register a webhook to receive channel messages.
Args:
webhook_url: URL of the webhook endpoint.
Returns:
True if registration was successful, False otherwise.
"""
try:
# Prepare webhook data
webhook_data = {
"url": webhook_url,
"events": ["channel_message"]
}
# Make API request to register webhook
response = requests.post(
f"{self.openwebui_url}/api/webhooks",
headers=self.headers,
json=webhook_data,
timeout=30
)
if response.status_code == 200 or response.status_code == 201:
print(f"Successfully registered webhook: {webhook_url}")
return True
else:
print(f"Error registering webhook: {response.status_code} - {response.text}")
return False
except Exception as e:
print(f"Error registering webhook: {str(e)}")
return False
def send_message(self, channel_id: str, message: str, user_id: str) -> Optional[Dict[str, Any]]:
"""
Send a message to a channel.
Args:
channel_id: ID of the channel.
message: Message content.
user_id: ID of the user sending the message.
Returns:
Message data if sending was successful, None otherwise.
"""
try:
# Prepare message data
message_data = {
"content": message,
"user_id": user_id
}
# Make API request to send message
response = requests.post(
f"{self.openwebui_url}/api/channels/{channel_id}/messages",
headers=self.headers,
json=message_data,
timeout=30
)
if response.status_code == 200 or response.status_code == 201:
return response.json()
else:
print(f"Error sending message to channel: {response.status_code} - {response.text}")
return None
except Exception as e:
print(f"Error sending message to channel: {str(e)}")
return None
# Create a singleton instance
openwebui_channels = OpenWebUIChannels()