Compare commits

...

15 Commits

Author SHA1 Message Date
82fc9ea5f9 removing the tools calls
All checks were successful
OpenWebUI Discord Bot / Build-and-Push (push) Successful in 1m33s
2025-02-04 13:39:34 -08:00
65c981f889 pushing changes 2025-01-06 19:44:47 -08:00
1d390685a6 Update required for new modules 2025-01-02 20:02:12 -08:00
4fbbf89afe Update required for new modules 2025-01-02 20:00:38 -08:00
d8e22a9773 Updating bot and removing .env file 2025-01-02 19:47:54 -08:00
8144971707 update the discord main bot to allow it to be packaged with Docker 2025-01-02 19:41:08 -08:00
45249174ba pushing updates for bot 2025-01-02 19:38:42 -08:00
9d6541ce75 upgrading script to v2 with history 2025-01-02 17:53:16 -08:00
37b363b317 adding V2
All checks were successful
OpenWebUI Discord Bot / Build-and-Push (push) Successful in 1m0s
2025-01-02 17:22:32 -08:00
43f40981db Include History for Chatbot
All checks were successful
OpenWebUI Discord Bot / Build-and-Push (push) Successful in 59s
2024-12-31 19:18:31 -08:00
35839395f4 adding back the dm chat
All checks were successful
OpenWebUI Discord Bot / Build-and-Push (push) Successful in 58s
2024-12-30 21:52:32 -08:00
jknapp
aa9d6e9765 Merge pull request 'Adding the ability to look at history but not including it every time' (#2) from set-message-history into main
All checks were successful
OpenWebUI Discord Bot / Build-and-Push (push) Successful in 1m0s
Reviewed-on: #2
2024-12-31 05:46:22 +00:00
ff48937482 fixing changes from merge 2024-12-30 21:45:37 -08:00
41b0173680 Merge branch 'main' into set-message-history 2024-12-30 21:42:23 -08:00
b0258d2a1f Adding the ability to look at history but not including it every time 2024-12-30 21:37:29 -08:00
7 changed files with 262 additions and 55 deletions

1
.gitignore vendored
View File

@@ -1 +1,2 @@
scripts/.env scripts/.env
v2/.env

View File

@@ -11,7 +11,7 @@ RUN apt-get update && apt-get install -y \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
# Install required packages # Install required packages
RUN pip install --no-cache-dir discord.py python-dotenv openai RUN pip install --no-cache-dir discord.py python-dotenv openai requests asyncio
# Copy the bot script # Copy the bot script
COPY /scripts/discordbot.py . COPY /scripts/discordbot.py .

View File

@@ -1,44 +1,99 @@
import os
import discord import discord
from discord.ext import commands from discord.ext import commands
from openai import OpenAI from openai import OpenAI
import os import base64
import requests
from io import BytesIO
from collections import deque
from dotenv import load_dotenv from dotenv import load_dotenv
import json
import datetime
import aiohttp
from typing import Dict, Any, List
# Load environment variables # Load environment variables
load_dotenv() load_dotenv()
# Get environment variables
DISCORD_TOKEN = os.getenv('DISCORD_TOKEN')
OPENAI_API_KEY = os.getenv('OPENAI_API_KEY')
OPENWEBUI_API_BASE = os.getenv('OPENWEBUI_API_BASE')
MODEL_NAME = os.getenv('MODEL_NAME')
# Configure OpenAI client to point to OpenWebUI # Configure OpenAI client to point to OpenWebUI
client = OpenAI( client = OpenAI(
api_key=os.getenv('OPENAI_API_KEY'), api_key=os.getenv('OPENAI_API_KEY'),
base_url=os.getenv('OPENWEBUI_API_BASE') # e.g., "http://localhost:8080/v1" base_url=os.getenv('OPENWEBUI_API_BASE') # e.g., "http://localhost:8080/v1"
) )
# Configure OpenAI
# TODO: The 'openai.api_base' option isn't read in the client API. You will need to pass it when you instantiate the client, e.g. 'OpenAI(base_url=OPENWEBUI_API_BASE)'
# openai.api_base = OPENWEBUI_API_BASE
# Initialize Discord bot # Initialize Discord bot
intents = discord.Intents.default() intents = discord.Intents.default()
intents.message_content = True intents.message_content = True
bot = commands.Bot(command_prefix="!", intents=intents) intents.messages = True
bot = commands.Bot(command_prefix='!', intents=intents)
async def get_chat_history(channel, limit=50): # Message history cache
channel_history = {}
async def download_image(url):
response = requests.get(url)
if response.status_code == 200:
image_data = BytesIO(response.content)
base64_image = base64.b64encode(image_data.read()).decode('utf-8')
return base64_image
return None
async def get_chat_history(channel, limit=100):
messages = [] messages = []
async for message in channel.history(limit=limit): async for message in channel.history(limit=limit):
# Skip bot's own messages content = f"{message.author.name}: {message.content}"
if message.author == bot.user:
continue # Handle attachments (images)
messages.append({"role": "user", "content": message.content}) for attachment in message.attachments:
return list(reversed(messages)) # Return in chronological order if any(attachment.filename.lower().endswith(ext) for ext in ['.png', '.jpg', '.jpeg', '.gif', '.webp']):
content += f" [Image: {attachment.url}]"
messages.append(content)
return "\n".join(reversed(messages))
async def get_ai_response(context, user_message, image_urls=None):
system_message = f"\"\"\"Previous conversation context:{context}"""
messages = [
{"role": "system", "content": system_message},
{"role": "user", "content": [] if image_urls else user_message}
]
# Handle messages with images differently
if image_urls:
content_parts = [{"type": "text", "text": user_message}]
for url in image_urls:
base64_image = await download_image(url)
if base64_image:
content_parts.append({
"type": "image_url",
"image_url": {
"url": f"data:image/jpeg;base64,{base64_image}"
}
})
messages[1]["content"] = content_parts
async def get_ai_response(messages):
try: try:
response = client.chat.completions.create( response = client.chat.completions.create(
model=os.getenv('MODEL_NAME') or "us.anthropic.claude-3-5-sonnet-20241022-v2:0", model=MODEL_NAME,
messages=messages, messages=messages
temperature=0.7,
max_tokens=500
) )
return response.choices[0].message.content return response.choices[0].message.content
except Exception as e: except Exception as e:
print(f"Error getting AI response: {e}") return f"Error: {str(e)}"
return "Sorry, I encountered an error while processing your request."
@bot.event @bot.event
async def on_message(message): async def on_message(message):
@@ -46,49 +101,49 @@ async def on_message(message):
if message.author == bot.user: if message.author == bot.user:
return return
# Respond to DMs or when mentioned in a server should_respond = False
if isinstance(message.channel, discord.DMChannel) or bot.user in message.mentions:
# For mentions, remove the bot mention from the message
if bot.user in message.mentions:
prompt = message.content.replace(f'<@{bot.user.id}>', '').strip()
else:
prompt = message.content.strip()
# If there's no prompt # Check if bot was mentioned
if not prompt: if bot.user in message.mentions:
await message.channel.send("Hello! How can I help you?") should_respond = True
return
# Show typing indicator while processing # Check if message is a DM
if isinstance(message.channel, discord.DMChannel):
should_respond = True
if should_respond:
async with message.channel.typing(): async with message.channel.typing():
# Get chat history # Get chat history
chat_history = await get_chat_history(message.channel) history = await get_chat_history(message.channel)
# Add current message to history # Remove bot mention from the message
chat_history.append({"role": "user", "content": prompt}) user_message = message.content.replace(f'<@{bot.user.id}>', '').strip()
# Get response from OpenWebUI with chat history context # Collect image URLs from the message
response = await get_ai_response(chat_history) image_urls = []
for attachment in message.attachments:
if any(attachment.filename.lower().endswith(ext) for ext in ['.png', '.jpg', '.jpeg', '.gif', '.webp']):
image_urls.append(attachment.url)
# Send the response # Get AI response
# Split long messages if they exceed Discord's character limit response = await get_ai_response(history, user_message, image_urls)
if len(response) > 2000:
chunks = [response[i:i+2000] for i in range(0, len(response), 2000)] # Send response
for chunk in chunks: await message.reply(response)
await message.channel.send(chunk)
else:
await message.channel.send(response)
await bot.process_commands(message) await bot.process_commands(message)
def main(): @bot.event
# Get the Discord token from environment variables async def on_ready():
discord_token = os.getenv('DISCORD_TOKEN') print(f'{bot.user} has connected to Discord!')
if not discord_token:
raise ValueError("Discord token not found in environment variables")
# Run the bot
bot.run(discord_token) def main():
if not all([DISCORD_TOKEN, OPENAI_API_KEY, OPENWEBUI_API_BASE, MODEL_NAME]):
print("Error: Missing required environment variables")
return
bot.run(DISCORD_TOKEN)
if __name__ == "__main__": if __name__ == "__main__":
main() main()

4
scripts/requirements.txt Normal file
View File

@@ -0,0 +1,4 @@
discord.py
openai
python-dotenv
requests

4
v2/.env.example Normal file
View File

@@ -0,0 +1,4 @@
DISCORD_TOKEN=your_discord_bot_token
OPENAI_API_KEY=your_openai_api_key
OPENWEBUI_API_BASE=http://your.api.endpoint/v1
MODEL_NAME="Your_Model_Name"

139
v2/bot.py Normal file
View File

@@ -0,0 +1,139 @@
import os
import discord
from discord.ext import commands
from openai import OpenAI
import base64
import requests
from io import BytesIO
from collections import deque
from dotenv import load_dotenv
# Load environment variables
load_dotenv()
# Get environment variables
DISCORD_TOKEN = os.getenv('DISCORD_TOKEN')
OPENAI_API_KEY = os.getenv('OPENAI_API_KEY')
OPENWEBUI_API_BASE = os.getenv('OPENWEBUI_API_BASE')
MODEL_NAME = os.getenv('MODEL_NAME')
# Configure OpenAI client to point to OpenWebUI
client = OpenAI(
api_key=os.getenv('OPENAI_API_KEY'),
base_url=os.getenv('OPENWEBUI_API_BASE') # e.g., "http://localhost:8080/v1"
)
# Configure OpenAI
# TODO: The 'openai.api_base' option isn't read in the client API. You will need to pass it when you instantiate the client, e.g. 'OpenAI(base_url=OPENWEBUI_API_BASE)'
# openai.api_base = OPENWEBUI_API_BASE
# Initialize Discord bot
intents = discord.Intents.default()
intents.message_content = True
intents.messages = True
bot = commands.Bot(command_prefix='!', intents=intents)
# Message history cache
channel_history = {}
async def download_image(url):
response = requests.get(url)
if response.status_code == 200:
image_data = BytesIO(response.content)
base64_image = base64.b64encode(image_data.read()).decode('utf-8')
return base64_image
return None
async def get_chat_history(channel, limit=100):
messages = []
async for message in channel.history(limit=limit):
content = f"{message.author.name}: {message.content}"
# Handle attachments (images)
for attachment in message.attachments:
if any(attachment.filename.lower().endswith(ext) for ext in ['.png', '.jpg', '.jpeg', '.gif', '.webp']):
content += f" [Image: {attachment.url}]"
messages.append(content)
return "\n".join(reversed(messages))
async def get_ai_response(context, user_message, image_urls=None):
messages = [{"role": "user", "content": []}]
# Add text content
text_content = f"##CONTEXT##\n{context}\n##ENDCONTEXT##\n\n{user_message}"
messages[0]["content"].append({"type": "text", "text": text_content})
# Add image content if present
if image_urls:
for url in image_urls:
base64_image = await download_image(url)
if base64_image:
messages[0]["content"].append({
"type": "image_url",
"image_url": {
"url": f"data:image/jpeg;base64,{base64_image}"
}
})
try:
response = client.chat.completions.create(
model=MODEL_NAME,
messages=messages
)
return response.choices[0].message.content
except Exception as e:
return f"Error: {str(e)}"
@bot.event
async def on_message(message):
# Ignore messages from the bot itself
if message.author == bot.user:
return
should_respond = False
# Check if bot was mentioned
if bot.user in message.mentions:
should_respond = True
# Check if message is a DM
if isinstance(message.channel, discord.DMChannel):
should_respond = True
if should_respond:
async with message.channel.typing():
# Get chat history
history = await get_chat_history(message.channel)
# Remove bot mention from the message
user_message = message.content.replace(f'<@{bot.user.id}>', '').strip()
# Collect image URLs from the message
image_urls = []
for attachment in message.attachments:
if any(attachment.filename.lower().endswith(ext) for ext in ['.png', '.jpg', '.jpeg', '.gif', '.webp']):
image_urls.append(attachment.url)
# Get AI response
response = await get_ai_response(history, user_message, image_urls)
# Send response
await message.reply(response)
await bot.process_commands(message)
@bot.event
async def on_ready():
print(f'{bot.user} has connected to Discord!')
def main():
if not all([DISCORD_TOKEN, OPENAI_API_KEY, OPENWEBUI_API_BASE, MODEL_NAME]):
print("Error: Missing required environment variables")
return
bot.run(DISCORD_TOKEN)
if __name__ == "__main__":
main()

4
v2/requirements.txt Normal file
View File

@@ -0,0 +1,4 @@
discord.py
openai
python-dotenv
requests