upgrading script to v2 with history

This commit is contained in:
Josh Knapp 2025-01-02 17:53:16 -08:00
parent 37b363b317
commit 9d6541ce75
2 changed files with 84 additions and 89 deletions

View File

@ -1,111 +1,100 @@
import os
import discord import discord
from discord.ext import commands from discord.ext import commands
import openai
from openai import OpenAI from openai import OpenAI
import os
from collections import deque
from dotenv import load_dotenv from dotenv import load_dotenv
# 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)
# Add a dictionary to store conversation histories # Message history cache
conversation_histories = {} channel_history = {}
DEFAULT_HISTORY_LIMIT = 50
MAX_HISTORY_LIMIT = 200
async def get_ai_response(prompt, channel_id=None): async def get_chat_history(channel, limit=100):
try:
messages = [] messages = []
async for message in channel.history(limit=limit):
messages.append(f"{message.author.name}: {message.content}")
return "\n".join(reversed(messages))
# Always include history if it exists for this channel async def get_ai_response(context, user_message):
if channel_id in conversation_histories: formatted_prompt = f"##CONTEXT##\n{context}\n##ENDCONTEXT##\n\n{user_message}"
history = conversation_histories[channel_id][-400:] # Get last 400 messages (200 exchanges)
# Format the history as a context block try:
history_text = "\n".join([ response = client.chat.completions.create(model=MODEL_NAME,
f"{'User: ' if msg['role'] == 'user' else 'Assistant: '}{msg['content']}" messages=[
for msg in history {"role": "user", "content": formatted_prompt}
]) ])
formatted_prompt = f"{prompt}\n##CONTEXT##\n{history_text}\n##ENDCONTEXT##"
else:
formatted_prompt = prompt
response = client.chat.completions.create(
model=os.getenv('MODEL_NAME') or "us.anthropic.claude-3-5-sonnet-20241022-v2:0",
messages=[{"role": "user", "content": formatted_prompt}],
temperature=0.7,
max_tokens=500
)
# Store the conversation history if channel_id is provided
if channel_id:
if channel_id not in conversation_histories:
conversation_histories[channel_id] = []
conversation_histories[channel_id].extend([
{"role": "user", "content": prompt},
{"role": "assistant", "content": response.choices[0].message.content}
])
# Always keep last 400 messages (200 exchanges)
if len(conversation_histories[channel_id]) > 400:
conversation_histories[channel_id] = conversation_histories[channel_id][-400:]
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
async def on_ready():
print(f'{bot.user} has connected to Discord!')
@bot.event @bot.event
async def on_message(message): async def on_message(message):
# Ignore messages from the bot itself
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 # Check if bot was mentioned
if bot.user in message.mentions: if bot.user in message.mentions:
prompt = message.content.replace(f'<@{bot.user.id}>', '').strip() should_respond = True
else:
prompt = message.content.strip()
if not prompt: # Check if message is a DM
await message.channel.send("Hello! How can I help you?") if isinstance(message.channel, discord.DMChannel):
return should_respond = True
if should_respond:
async with message.channel.typing(): async with message.channel.typing():
response = await get_ai_response( # Get chat history
prompt, history = await get_chat_history(message.channel)
channel_id=str(message.channel.id)
)
if len(response) > 2000: # Remove bot mention from the message
chunks = [response[i:i+2000] for i in range(0, len(response), 2000)] user_message = message.content.replace(f'<@{bot.user.id}>', '').strip()
for chunk in chunks:
await message.channel.send(chunk) # Get AI response
else: response = await get_ai_response(history, user_message)
await message.channel.send(response)
# Send response
await message.reply(response)
await bot.process_commands(message) await bot.process_commands(message)
def main(): def main():
# Get the Discord token from environment variables if not all([DISCORD_TOKEN, OPENAI_API_KEY, OPENWEBUI_API_BASE, MODEL_NAME]):
discord_token = os.getenv('DISCORD_TOKEN') print("Error: Missing required environment variables")
if not discord_token: return
raise ValueError("Discord token not found in environment variables")
# Run the bot bot.run(DISCORD_TOKEN)
bot.run(discord_token)
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@ -2,6 +2,8 @@ import os
import discord import discord
from discord.ext import commands from discord.ext import commands
import openai import openai
from openai import OpenAI
from collections import deque from collections import deque
from dotenv import load_dotenv from dotenv import load_dotenv
@ -14,9 +16,15 @@ OPENAI_API_KEY = os.getenv('OPENAI_API_KEY')
OPENWEBUI_API_BASE = os.getenv('OPENWEBUI_API_BASE') OPENWEBUI_API_BASE = os.getenv('OPENWEBUI_API_BASE')
MODEL_NAME = os.getenv('MODEL_NAME') 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 # Configure OpenAI
openai.api_key = OPENAI_API_KEY # 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 # openai.api_base = OPENWEBUI_API_BASE
# Initialize Discord bot # Initialize Discord bot
intents = discord.Intents.default() intents = discord.Intents.default()
@ -37,12 +45,10 @@ async def get_ai_response(context, user_message):
formatted_prompt = f"##CONTEXT##\n{context}\n##ENDCONTEXT##\n\n{user_message}" formatted_prompt = f"##CONTEXT##\n{context}\n##ENDCONTEXT##\n\n{user_message}"
try: try:
response = openai.ChatCompletion.create( response = client.chat.completions.create(model=MODEL_NAME,
model=MODEL_NAME,
messages=[ messages=[
{"role": "user", "content": formatted_prompt} {"role": "user", "content": formatted_prompt}
] ])
)
return response.choices[0].message.content return response.choices[0].message.content
except Exception as e: except Exception as e:
return f"Error: {str(e)}" return f"Error: {str(e)}"