hopefully fix repetition with higher temperature and frequency penalty
This commit is contained in:
57
database.py
57
database.py
@@ -4,6 +4,14 @@ from typing import Optional, List, Tuple
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from openai import OpenAI
|
from openai import OpenAI
|
||||||
|
import logging
|
||||||
|
|
||||||
|
# Configure logging
|
||||||
|
logging.basicConfig(
|
||||||
|
level=logging.INFO,
|
||||||
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
||||||
|
)
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
# Database configuration
|
# Database configuration
|
||||||
DB_PATH = os.getenv("DB_PATH", "chat_history.db")
|
DB_PATH = os.getenv("DB_PATH", "chat_history.db")
|
||||||
@@ -24,16 +32,20 @@ class ChatDatabase:
|
|||||||
"""SQLite database with RAG support for storing chat history using OpenAI embeddings."""
|
"""SQLite database with RAG support for storing chat history using OpenAI embeddings."""
|
||||||
|
|
||||||
def __init__(self, db_path: str = DB_PATH):
|
def __init__(self, db_path: str = DB_PATH):
|
||||||
|
logger.info(f"Initializing ChatDatabase with path: {db_path}")
|
||||||
self.db_path = db_path
|
self.db_path = db_path
|
||||||
self.client = OpenAI(base_url=OPENAI_API_EMBED_ENDPOINT, api_key=OPENAI_API_KEY)
|
self.client = OpenAI(base_url=OPENAI_API_EMBED_ENDPOINT, api_key=OPENAI_API_KEY)
|
||||||
|
logger.info("Connecting to OpenAI API for embeddings")
|
||||||
self._initialize_database()
|
self._initialize_database()
|
||||||
|
|
||||||
def _initialize_database(self):
|
def _initialize_database(self):
|
||||||
"""Initialize the SQLite database with required tables."""
|
"""Initialize the SQLite database with required tables."""
|
||||||
|
logger.info(f"Initializing SQLite database at {self.db_path}")
|
||||||
conn = sqlite3.connect(self.db_path)
|
conn = sqlite3.connect(self.db_path)
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
|
||||||
# Create messages table
|
# Create messages table
|
||||||
|
logger.info("Creating chat_messages table if not exists")
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"""
|
"""
|
||||||
CREATE TABLE IF NOT EXISTS chat_messages (
|
CREATE TABLE IF NOT EXISTS chat_messages (
|
||||||
@@ -48,8 +60,10 @@ class ChatDatabase:
|
|||||||
)
|
)
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
logger.info("chat_messages table initialized successfully")
|
||||||
|
|
||||||
# Create embeddings table for RAG
|
# Create embeddings table for RAG
|
||||||
|
logger.info("Creating message_embeddings table if not exists")
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"""
|
"""
|
||||||
CREATE TABLE IF NOT EXISTS message_embeddings (
|
CREATE TABLE IF NOT EXISTS message_embeddings (
|
||||||
@@ -59,28 +73,39 @@ class ChatDatabase:
|
|||||||
)
|
)
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
logger.info("message_embeddings table initialized successfully")
|
||||||
|
|
||||||
# Create index for faster lookups
|
# Create index for faster lookups
|
||||||
|
logger.info("Creating idx_timestamp index if not exists")
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"""
|
"""
|
||||||
CREATE INDEX IF NOT EXISTS idx_timestamp ON chat_messages(timestamp)
|
CREATE INDEX IF NOT EXISTS idx_timestamp ON chat_messages(timestamp)
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
logger.info("idx_timestamp index created successfully")
|
||||||
|
|
||||||
|
logger.info("Creating idx_user_id index if not exists")
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"""
|
"""
|
||||||
CREATE INDEX IF NOT EXISTS idx_user_id ON chat_messages(user_id)
|
CREATE INDEX IF NOT EXISTS idx_user_id ON chat_messages(user_id)
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
logger.info("idx_user_id index created successfully")
|
||||||
|
|
||||||
conn.commit()
|
conn.commit()
|
||||||
|
logger.info("Database initialization completed successfully")
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
def _generate_embedding(self, text: str) -> List[float]:
|
def _generate_embedding(self, text: str) -> List[float]:
|
||||||
"""Generate embedding for text using OpenAI API."""
|
"""Generate embedding for text using OpenAI API."""
|
||||||
|
logger.debug(f"Generating embedding for text (length: {len(text)})")
|
||||||
try:
|
try:
|
||||||
|
logger.info(f"Calling OpenAI API to generate embedding with model: {EMBEDDING_MODEL}")
|
||||||
response = self.client.embeddings.create(
|
response = self.client.embeddings.create(
|
||||||
model=EMBEDDING_MODEL, input=text, encoding_format="float"
|
model=EMBEDDING_MODEL, input=text, encoding_format="float"
|
||||||
)
|
)
|
||||||
|
logger.debug("OpenAI API response received successfully")
|
||||||
|
|
||||||
# The embedding is returned as a nested list: [[embedding_values]]
|
# The embedding is returned as a nested list: [[embedding_values]]
|
||||||
# We need to extract the inner list
|
# We need to extract the inner list
|
||||||
embedding_data = response[0].embedding
|
embedding_data = response[0].embedding
|
||||||
@@ -89,26 +114,38 @@ class ChatDatabase:
|
|||||||
first_item = embedding_data[0]
|
first_item = embedding_data[0]
|
||||||
if isinstance(first_item, list):
|
if isinstance(first_item, list):
|
||||||
# Handle nested structure: [[values]] -> [values]
|
# Handle nested structure: [[values]] -> [values]
|
||||||
|
logger.debug("Extracted embedding from nested structure [[values]]")
|
||||||
return first_item
|
return first_item
|
||||||
else:
|
else:
|
||||||
# Handle direct structure: [values]
|
# Handle direct structure: [values]
|
||||||
|
logger.debug("Extracted embedding from direct structure [values]")
|
||||||
return embedding_data
|
return embedding_data
|
||||||
|
logger.warning("Embedding data is empty or invalid")
|
||||||
return []
|
return []
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error generating embedding: {e}")
|
logger.error(f"Error generating embedding: {e}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def _vector_to_bytes(self, vector: List[float]) -> bytes:
|
def _vector_to_bytes(self, vector: List[float]) -> bytes:
|
||||||
"""Convert vector to bytes for SQLite storage."""
|
"""Convert vector to bytes for SQLite storage."""
|
||||||
return np.array(vector, dtype=np.float32).tobytes()
|
logger.debug(f"Converting vector (length: {len(vector)}) to bytes")
|
||||||
|
result = np.array(vector, dtype=np.float32).tobytes()
|
||||||
|
logger.debug(f"Vector converted to {len(result)} bytes")
|
||||||
|
return result
|
||||||
|
|
||||||
def _bytes_to_vector(self, blob: bytes) -> np.ndarray:
|
def _bytes_to_vector(self, blob: bytes) -> np.ndarray:
|
||||||
"""Convert bytes back to vector."""
|
"""Convert bytes back to vector."""
|
||||||
return np.frombuffer(blob, dtype=np.float32)
|
logger.debug(f"Converting {len(blob)} bytes back to vector")
|
||||||
|
result = np.frombuffer(blob, dtype=np.float32)
|
||||||
|
logger.debug(f"Vector reconstructed with {len(result)} dimensions")
|
||||||
|
return result
|
||||||
|
|
||||||
def _calculate_similarity(self, vec1: np.ndarray, vec2: np.ndarray) -> float:
|
def _calculate_similarity(self, vec1: np.ndarray, vec2: np.ndarray) -> float:
|
||||||
"""Calculate cosine similarity between two vectors."""
|
"""Calculate cosine similarity between two vectors."""
|
||||||
return np.dot(vec1, vec2) / (np.linalg.norm(vec1) * np.linalg.norm(vec2))
|
logger.debug(f"Calculating cosine similarity between vectors of dimension {len(vec1)}")
|
||||||
|
result = np.dot(vec1, vec2) / (np.linalg.norm(vec1) * np.linalg.norm(vec2))
|
||||||
|
logger.debug(f"Similarity calculated: {result:.4f}")
|
||||||
|
return result
|
||||||
|
|
||||||
def add_message(
|
def add_message(
|
||||||
self,
|
self,
|
||||||
@@ -120,11 +157,13 @@ class ChatDatabase:
|
|||||||
guild_id: Optional[str] = None,
|
guild_id: Optional[str] = None,
|
||||||
) -> bool:
|
) -> bool:
|
||||||
"""Add a message to the database and generate its embedding."""
|
"""Add a message to the database and generate its embedding."""
|
||||||
|
logger.info(f"Adding message {message_id} from user {username}")
|
||||||
conn = sqlite3.connect(self.db_path)
|
conn = sqlite3.connect(self.db_path)
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Insert message
|
# Insert message
|
||||||
|
logger.debug(f"Inserting message into chat_messages table: message_id={message_id}")
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"""
|
"""
|
||||||
INSERT OR REPLACE INTO chat_messages
|
INSERT OR REPLACE INTO chat_messages
|
||||||
@@ -133,10 +172,13 @@ class ChatDatabase:
|
|||||||
""",
|
""",
|
||||||
(message_id, user_id, username, content, channel_id, guild_id),
|
(message_id, user_id, username, content, channel_id, guild_id),
|
||||||
)
|
)
|
||||||
|
logger.debug(f"Message {message_id} inserted into chat_messages table")
|
||||||
|
|
||||||
# Generate and store embedding
|
# Generate and store embedding
|
||||||
|
logger.info(f"Generating embedding for message {message_id}")
|
||||||
embedding = self._generate_embedding(content)
|
embedding = self._generate_embedding(content)
|
||||||
if embedding:
|
if embedding:
|
||||||
|
logger.debug(f"Embedding generated successfully for message {message_id}, storing in database")
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"""
|
"""
|
||||||
INSERT OR REPLACE INTO message_embeddings
|
INSERT OR REPLACE INTO message_embeddings
|
||||||
@@ -145,15 +187,20 @@ class ChatDatabase:
|
|||||||
""",
|
""",
|
||||||
(message_id, self._vector_to_bytes(embedding)),
|
(message_id, self._vector_to_bytes(embedding)),
|
||||||
)
|
)
|
||||||
|
logger.debug(f"Embedding stored in message_embeddings table for message {message_id}")
|
||||||
|
else:
|
||||||
|
logger.warning(f"Failed to generate embedding for message {message_id}, skipping embedding storage")
|
||||||
|
|
||||||
# Clean up old messages if exceeding limit
|
# Clean up old messages if exceeding limit
|
||||||
|
logger.info("Checking if cleanup of old messages is needed")
|
||||||
self._cleanup_old_messages(cursor)
|
self._cleanup_old_messages(cursor)
|
||||||
|
|
||||||
conn.commit()
|
conn.commit()
|
||||||
|
logger.info(f"Successfully added message {message_id} to database")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error adding message: {e}")
|
logger.error(f"Error adding message {message_id}: {e}")
|
||||||
conn.rollback()
|
conn.rollback()
|
||||||
return False
|
return False
|
||||||
finally:
|
finally:
|
||||||
|
|||||||
129
main.py
129
main.py
@@ -1,12 +1,18 @@
|
|||||||
import discord
|
import discord
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
import requests
|
|
||||||
import os
|
import os
|
||||||
import base64
|
import base64
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from openai import OpenAI
|
from openai import OpenAI
|
||||||
|
import logging
|
||||||
from database import get_database, CustomBotManager
|
from database import get_database, CustomBotManager
|
||||||
|
|
||||||
|
# Configure logging
|
||||||
|
logging.basicConfig(
|
||||||
|
level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
||||||
|
)
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
DISCORD_TOKEN = os.getenv("DISCORD_TOKEN", "placeholder")
|
DISCORD_TOKEN = os.getenv("DISCORD_TOKEN", "placeholder")
|
||||||
|
|
||||||
OPENAI_API_ENDPOINT = os.getenv("OPENAI_API_ENDPOINT")
|
OPENAI_API_ENDPOINT = os.getenv("OPENAI_API_ENDPOINT")
|
||||||
@@ -35,7 +41,9 @@ OPENAI_COMPLETIONS_URL = f"{OPENAI_API_ENDPOINT}/chat/completions"
|
|||||||
|
|
||||||
@bot.event
|
@bot.event
|
||||||
async def on_ready():
|
async def on_ready():
|
||||||
|
logger.info("Bot is starting up...")
|
||||||
print(f"Bot logged in as {bot.user}")
|
print(f"Bot logged in as {bot.user}")
|
||||||
|
logger.info(f"Bot logged in as {bot.user}")
|
||||||
|
|
||||||
|
|
||||||
@bot.command(name="custom-bot")
|
@bot.command(name="custom-bot")
|
||||||
@@ -45,51 +53,86 @@ async def custom_bot(ctx, bot_name: str, *, personality: str):
|
|||||||
Usage: !custom-bot <bot_name> <personality_description>
|
Usage: !custom-bot <bot_name> <personality_description>
|
||||||
Example: !custom-bot alfred you are a proper british butler
|
Example: !custom-bot alfred you are a proper british butler
|
||||||
"""
|
"""
|
||||||
|
logger.info(
|
||||||
|
f"Custom bot command initiated by {ctx.author.name}: name='{bot_name}', personality length={len(personality)}"
|
||||||
|
)
|
||||||
|
|
||||||
# Validate bot name
|
# Validate bot name
|
||||||
if not bot_name or len(bot_name) < 2 or len(bot_name) > 50:
|
if not bot_name or len(bot_name) < 2 or len(bot_name) > 50:
|
||||||
|
logger.warning(
|
||||||
|
f"Invalid bot name from {ctx.author.name}: '{bot_name}' (length: {len(bot_name) if bot_name else 0})"
|
||||||
|
)
|
||||||
await ctx.send("❌ Invalid bot name. Name must be between 2 and 50 characters.")
|
await ctx.send("❌ Invalid bot name. Name must be between 2 and 50 characters.")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
logger.info(f"Bot name validation passed for '{bot_name}'")
|
||||||
|
|
||||||
# Validate personality
|
# Validate personality
|
||||||
if not personality or len(personality) < 10:
|
if not personality or len(personality) < 10:
|
||||||
|
logger.warning(
|
||||||
|
f"Invalid personality from {ctx.author.name}: length={len(personality) if personality else 0}"
|
||||||
|
)
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
"❌ Invalid personality. Description must be at least 10 characters."
|
"❌ Invalid personality. Description must be at least 10 characters."
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
logger.info(f"Personality validation passed for bot '{bot_name}'")
|
||||||
|
|
||||||
# Create custom bot manager
|
# Create custom bot manager
|
||||||
|
logger.info(f"Initializing CustomBotManager for user {ctx.author.name}")
|
||||||
custom_bot_manager = CustomBotManager()
|
custom_bot_manager = CustomBotManager()
|
||||||
|
|
||||||
# Create the custom bot
|
# Create the custom bot
|
||||||
|
logger.info(
|
||||||
|
f"Attempting to create custom bot '{bot_name}' for user {ctx.author.name}"
|
||||||
|
)
|
||||||
success = custom_bot_manager.create_custom_bot(
|
success = custom_bot_manager.create_custom_bot(
|
||||||
bot_name=bot_name, system_prompt=personality, created_by=str(ctx.author.id)
|
bot_name=bot_name, system_prompt=personality, created_by=str(ctx.author.id)
|
||||||
)
|
)
|
||||||
|
|
||||||
if success:
|
if success:
|
||||||
|
logger.info(
|
||||||
|
f"Successfully created custom bot '{bot_name}' for user {ctx.author.name}"
|
||||||
|
)
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
f"✅ Custom bot **'{bot_name}'** has been created with personality: *{personality}*"
|
f"✅ Custom bot **'{bot_name}'** has been created with personality: *{personality}*"
|
||||||
)
|
)
|
||||||
await ctx.send(f"\nYou can now use this bot with: `!{bot_name} <your message>`")
|
await ctx.send(f"\nYou can now use this bot with: `!{bot_name} <your message>`")
|
||||||
else:
|
else:
|
||||||
|
logger.warning(
|
||||||
|
f"Failed to create custom bot '{bot_name}' for user {ctx.author.name}"
|
||||||
|
)
|
||||||
await ctx.send("❌ Failed to create custom bot. It may already exist.")
|
await ctx.send("❌ Failed to create custom bot. It may already exist.")
|
||||||
|
|
||||||
|
|
||||||
@bot.command(name="list-custom-bots")
|
@bot.command(name="list-custom-bots")
|
||||||
async def list_custom_bots(ctx):
|
async def list_custom_bots(ctx):
|
||||||
"""List all custom bots available in the server"""
|
"""List all custom bots available in the server"""
|
||||||
|
logger.info(f"Listing custom bots requested by {ctx.author.name}")
|
||||||
|
|
||||||
|
# Create custom bot manager
|
||||||
|
logger.info("Initializing CustomBotManager to list custom bots")
|
||||||
custom_bot_manager = CustomBotManager()
|
custom_bot_manager = CustomBotManager()
|
||||||
|
|
||||||
|
logger.info("Fetching list of custom bots from database")
|
||||||
bots = custom_bot_manager.list_custom_bots()
|
bots = custom_bot_manager.list_custom_bots()
|
||||||
|
|
||||||
if not bots:
|
if not bots:
|
||||||
|
logger.info(f"No custom bots found for user {ctx.author.name}")
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
"No custom bots have been created yet. Use `!custom-bot <name> <personality>` to create one."
|
"No custom bots have been created yet. Use `!custom-bot <name> <personality>` to create one."
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
logger.info(
|
||||||
|
f"Found {len(bots)} custom bots, displaying top 10 for {ctx.author.name}"
|
||||||
|
)
|
||||||
bot_list = "🤖 **Available Custom Bots**:\n\n"
|
bot_list = "🤖 **Available Custom Bots**:\n\n"
|
||||||
for name, prompt, creator in bots[:10]: # Limit to 10 bots
|
for name, prompt, creator in bots[:10]: # Limit to 10 bots
|
||||||
bot_list += f"• **{name}** (created by {creator})\n"
|
bot_list += f"• **{name}** (created by {creator})\n"
|
||||||
|
|
||||||
|
logger.info(f"Sending bot list response to {ctx.author.name}")
|
||||||
await ctx.send(bot_list)
|
await ctx.send(bot_list)
|
||||||
|
|
||||||
|
|
||||||
@@ -99,22 +142,48 @@ async def delete_custom_bot(ctx, bot_name: str):
|
|||||||
|
|
||||||
Usage: !delete-custom-bot <bot_name>
|
Usage: !delete-custom-bot <bot_name>
|
||||||
"""
|
"""
|
||||||
|
logger.info(
|
||||||
|
f"Delete custom bot command initiated by {ctx.author.name}: bot_name='{bot_name}'"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Create custom bot manager
|
||||||
|
logger.info("Initializing CustomBotManager for delete operation")
|
||||||
custom_bot_manager = CustomBotManager()
|
custom_bot_manager = CustomBotManager()
|
||||||
|
|
||||||
|
# Get bot info
|
||||||
|
logger.info(f"Looking up custom bot '{bot_name}' in database")
|
||||||
bot_info = custom_bot_manager.get_custom_bot(bot_name)
|
bot_info = custom_bot_manager.get_custom_bot(bot_name)
|
||||||
|
|
||||||
if not bot_info:
|
if not bot_info:
|
||||||
|
logger.warning(f"Custom bot '{bot_name}' not found by user {ctx.author.name}")
|
||||||
await ctx.send(f"❌ Custom bot '{bot_name}' not found.")
|
await ctx.send(f"❌ Custom bot '{bot_name}' not found.")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
logger.info(f"Custom bot '{bot_name}' found, owned by user {bot_info[2]}")
|
||||||
|
|
||||||
|
# Check ownership
|
||||||
if bot_info[2] != str(ctx.author.id):
|
if bot_info[2] != str(ctx.author.id):
|
||||||
|
logger.warning(
|
||||||
|
f"User {ctx.author.name} attempted to delete bot '{bot_name}' they don't own"
|
||||||
|
)
|
||||||
await ctx.send("❌ You can only delete your own custom bots.")
|
await ctx.send("❌ You can only delete your own custom bots.")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
logger.info(f"User {ctx.author.name} is authorized to delete bot '{bot_name}'")
|
||||||
|
|
||||||
|
# Delete the bot
|
||||||
|
logger.info(f"Deleting custom bot '{bot_name}' from database")
|
||||||
success = custom_bot_manager.delete_custom_bot(bot_name)
|
success = custom_bot_manager.delete_custom_bot(bot_name)
|
||||||
|
|
||||||
if success:
|
if success:
|
||||||
|
logger.info(
|
||||||
|
f"Successfully deleted custom bot '{bot_name}' by user {ctx.author.name}"
|
||||||
|
)
|
||||||
await ctx.send(f"✅ Custom bot '{bot_name}' has been deleted.")
|
await ctx.send(f"✅ Custom bot '{bot_name}' has been deleted.")
|
||||||
else:
|
else:
|
||||||
|
logger.warning(
|
||||||
|
f"Failed to delete custom bot '{bot_name}' by user {ctx.author.name}"
|
||||||
|
)
|
||||||
await ctx.send("❌ Failed to delete custom bot.")
|
await ctx.send("❌ Failed to delete custom bot.")
|
||||||
|
|
||||||
|
|
||||||
@@ -125,19 +194,34 @@ async def on_message(message):
|
|||||||
if message.author == bot.user:
|
if message.author == bot.user:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
logger.debug(
|
||||||
|
f"Processing message from {message.author.name}: '{message.content[:50]}...'"
|
||||||
|
)
|
||||||
|
|
||||||
ctx = await bot.get_context(message)
|
ctx = await bot.get_context(message)
|
||||||
|
|
||||||
# Check if the message starts with a custom bot command
|
# Check if the message starts with a custom bot command
|
||||||
content = message.content.lower()
|
content = message.content.lower()
|
||||||
|
|
||||||
|
logger.info(f"Initializing CustomBotManager to check for custom bot commands")
|
||||||
custom_bot_manager = CustomBotManager()
|
custom_bot_manager = CustomBotManager()
|
||||||
|
|
||||||
|
logger.info("Fetching list of custom bots to check for matching commands")
|
||||||
custom_bots = custom_bot_manager.list_custom_bots()
|
custom_bots = custom_bot_manager.list_custom_bots()
|
||||||
|
|
||||||
|
logger.info(f"Checking {len(custom_bots)} custom bots for command match")
|
||||||
for bot_name, system_prompt, _ in custom_bots:
|
for bot_name, system_prompt, _ in custom_bots:
|
||||||
# Check if message starts with the custom bot name followed by a space
|
# Check if message starts with the custom bot name followed by a space
|
||||||
if content.startswith(f"!{bot_name} "):
|
if content.startswith(f"!{bot_name} "):
|
||||||
|
logger.info(
|
||||||
|
f"Custom bot command detected: '{bot_name}' triggered by {message.author.name}"
|
||||||
|
)
|
||||||
|
|
||||||
# Extract the actual message (remove the bot name prefix)
|
# Extract the actual message (remove the bot name prefix)
|
||||||
user_message = message.content[len(f"!{bot_name} ") :]
|
user_message = message.content[len(f"!{bot_name} ") :]
|
||||||
|
logger.debug(
|
||||||
|
f"Extracted user message for bot '{bot_name}': '{user_message[:50]}...'"
|
||||||
|
)
|
||||||
|
|
||||||
# Prepare the payload with custom personality
|
# Prepare the payload with custom personality
|
||||||
payload = {
|
payload = {
|
||||||
@@ -154,6 +238,7 @@ async def on_message(message):
|
|||||||
|
|
||||||
response_prefix = f"**{bot_name} response**"
|
response_prefix = f"**{bot_name} response**"
|
||||||
|
|
||||||
|
logger.info(f"Sending request to OpenAI API for bot '{bot_name}'")
|
||||||
await handle_chat(
|
await handle_chat(
|
||||||
ctx=ctx,
|
ctx=ctx,
|
||||||
message=user_message,
|
message=user_message,
|
||||||
@@ -259,12 +344,6 @@ async def handle_chat(ctx, *, message: str, payload: dict, response_prefix: str)
|
|||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Set headers
|
|
||||||
headers = {
|
|
||||||
"Authorization": f"Bearer {OPENAI_API_KEY}",
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
}
|
|
||||||
|
|
||||||
# Get database instance
|
# Get database instance
|
||||||
db = get_database()
|
db = get_database()
|
||||||
|
|
||||||
@@ -283,16 +362,22 @@ async def handle_chat(ctx, *, message: str, payload: dict, response_prefix: str)
|
|||||||
print(payload)
|
print(payload)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Send request to OpenAI API
|
# Initialize OpenAI client
|
||||||
response = requests.post(
|
client = OpenAI(api_key=OPENAI_API_KEY, base_url=OPENAI_API_ENDPOINT)
|
||||||
OPENAI_COMPLETIONS_URL, json=payload, headers=headers, timeout=300
|
|
||||||
)
|
|
||||||
response.raise_for_status()
|
|
||||||
|
|
||||||
result = response.json()
|
# Call OpenAI API
|
||||||
|
response = client.chat.completions.create(
|
||||||
|
model=payload["model"],
|
||||||
|
messages=payload["messages"],
|
||||||
|
max_completion_tokens=MAX_COMPLETION_TOKENS,
|
||||||
|
frequency_penalty=1.5,
|
||||||
|
presence_penalty=1.5,
|
||||||
|
temperature=1,
|
||||||
|
seed=-1,
|
||||||
|
)
|
||||||
|
|
||||||
# Extract the generated text
|
# Extract the generated text
|
||||||
generated_text = result["choices"][0]["message"]["content"].strip()
|
generated_text = response.choices[0].message.content.strip()
|
||||||
|
|
||||||
# Store both user message and bot response in the database
|
# Store both user message and bot response in the database
|
||||||
db.add_message(
|
db.add_message(
|
||||||
@@ -343,16 +428,18 @@ async def call_llm(ctx, payload: dict) -> str:
|
|||||||
}
|
}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Send request to OpenAI API
|
# Initialize OpenAI client
|
||||||
response = requests.post(
|
client = OpenAI(api_key=OPENAI_API_KEY, base_url=OPENAI_API_ENDPOINT)
|
||||||
OPENAI_COMPLETIONS_URL, json=payload, headers=headers, timeout=300
|
|
||||||
)
|
|
||||||
response.raise_for_status()
|
|
||||||
|
|
||||||
result = response.json()
|
# Call OpenAI API
|
||||||
|
response = client.chat.completions.create(
|
||||||
|
model=payload["model"],
|
||||||
|
messages=payload["messages"],
|
||||||
|
max_tokens=MAX_COMPLETION_TOKENS,
|
||||||
|
)
|
||||||
|
|
||||||
# Extract the generated text
|
# Extract the generated text
|
||||||
generated_text = result["choices"][0]["message"]["content"].strip()
|
generated_text = response.choices[0].message.content.strip()
|
||||||
print(generated_text)
|
print(generated_text)
|
||||||
|
|
||||||
return generated_text
|
return generated_text
|
||||||
|
|||||||
@@ -10,4 +10,5 @@ dependencies = [
|
|||||||
"requests>=2.32.5",
|
"requests>=2.32.5",
|
||||||
"types-requests>=2.32.4.20260107",
|
"types-requests>=2.32.4.20260107",
|
||||||
"numpy>=1.24.0",
|
"numpy>=1.24.0",
|
||||||
|
"pytest>=9.0.2",
|
||||||
]
|
]
|
||||||
|
|||||||
110
uv.lock
generated
110
uv.lock
generated
@@ -566,6 +566,15 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" },
|
{ url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "iniconfig"
|
||||||
|
version = "2.3.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jiter"
|
name = "jiter"
|
||||||
version = "0.13.0"
|
version = "0.13.0"
|
||||||
@@ -968,6 +977,24 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/c9/30/844dc675ee6902579b8eef01ed23917cc9319a1c9c0c14ec6e39340c96d0/openai-2.24.0-py3-none-any.whl", hash = "sha256:fed30480d7d6c884303287bde864980a4b137b60553ffbcf9ab4a233b7a73d94", size = 1120122, upload-time = "2026-02-24T20:02:05.669Z" },
|
{ url = "https://files.pythonhosted.org/packages/c9/30/844dc675ee6902579b8eef01ed23917cc9319a1c9c0c14ec6e39340c96d0/openai-2.24.0-py3-none-any.whl", hash = "sha256:fed30480d7d6c884303287bde864980a4b137b60553ffbcf9ab4a233b7a73d94", size = 1120122, upload-time = "2026-02-24T20:02:05.669Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "packaging"
|
||||||
|
version = "26.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/65/ee/299d360cdc32edc7d2cf530f3accf79c4fca01e96ffc950d8a52213bd8e4/packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4", size = 143416, upload-time = "2026-01-21T20:50:39.064Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529", size = 74366, upload-time = "2026-01-21T20:50:37.788Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pluggy"
|
||||||
|
version = "1.6.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "propcache"
|
name = "propcache"
|
||||||
version = "0.4.1"
|
version = "0.4.1"
|
||||||
@@ -1215,6 +1242,33 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/36/c7/cfc8e811f061c841d7990b0201912c3556bfeb99cdcb7ed24adc8d6f8704/pydantic_core-2.41.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:56121965f7a4dc965bff783d70b907ddf3d57f6eba29b6d2e5dabfaf07799c51", size = 2145302, upload-time = "2025-11-04T13:43:46.64Z" },
|
{ url = "https://files.pythonhosted.org/packages/36/c7/cfc8e811f061c841d7990b0201912c3556bfeb99cdcb7ed24adc8d6f8704/pydantic_core-2.41.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:56121965f7a4dc965bff783d70b907ddf3d57f6eba29b6d2e5dabfaf07799c51", size = 2145302, upload-time = "2025-11-04T13:43:46.64Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pygments"
|
||||||
|
version = "2.19.2"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pytest"
|
||||||
|
version = "9.0.2"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||||
|
{ name = "exceptiongroup", marker = "python_full_version < '3.11'" },
|
||||||
|
{ name = "iniconfig" },
|
||||||
|
{ name = "packaging" },
|
||||||
|
{ name = "pluggy" },
|
||||||
|
{ name = "pygments" },
|
||||||
|
{ name = "tomli", marker = "python_full_version < '3.11'" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/d1/db/7ef3487e0fb0049ddb5ce41d3a49c235bf9ad299b6a25d5780a89f19230f/pytest-9.0.2.tar.gz", hash = "sha256:75186651a92bd89611d1d9fc20f0b4345fd827c41ccd5c299a868a05d70edf11", size = 1568901, upload-time = "2025-12-06T21:30:51.014Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3b/ab/b3226f0bd7cdcf710fbede2b3548584366da3b19b5021e74f5bde2a8fa3f/pytest-9.0.2-py3-none-any.whl", hash = "sha256:711ffd45bf766d5264d487b917733b453d917afd2b0ad65223959f59089f875b", size = 374801, upload-time = "2025-12-06T21:30:49.154Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "requests"
|
name = "requests"
|
||||||
version = "2.32.5"
|
version = "2.32.5"
|
||||||
@@ -1239,6 +1293,60 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" },
|
{ url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tomli"
|
||||||
|
version = "2.4.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/82/30/31573e9457673ab10aa432461bee537ce6cef177667deca369efb79df071/tomli-2.4.0.tar.gz", hash = "sha256:aa89c3f6c277dd275d8e243ad24f3b5e701491a860d5121f2cdd399fbb31fc9c", size = 17477, upload-time = "2026-01-11T11:22:38.165Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3c/d9/3dc2289e1f3b32eb19b9785b6a006b28ee99acb37d1d47f78d4c10e28bf8/tomli-2.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b5ef256a3fd497d4973c11bf142e9ed78b150d36f5773f1ca6088c230ffc5867", size = 153663, upload-time = "2026-01-11T11:21:45.27Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/51/32/ef9f6845e6b9ca392cd3f64f9ec185cc6f09f0a2df3db08cbe8809d1d435/tomli-2.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5572e41282d5268eb09a697c89a7bee84fae66511f87533a6f88bd2f7b652da9", size = 148469, upload-time = "2026-01-11T11:21:46.873Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d6/c2/506e44cce89a8b1b1e047d64bd495c22c9f71f21e05f380f1a950dd9c217/tomli-2.4.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:551e321c6ba03b55676970b47cb1b73f14a0a4dce6a3e1a9458fd6d921d72e95", size = 236039, upload-time = "2026-01-11T11:21:48.503Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b3/40/e1b65986dbc861b7e986e8ec394598187fa8aee85b1650b01dd925ca0be8/tomli-2.4.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e3f639a7a8f10069d0e15408c0b96a2a828cfdec6fca05296ebcdcc28ca7c76", size = 243007, upload-time = "2026-01-11T11:21:49.456Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9c/6f/6e39ce66b58a5b7ae572a0f4352ff40c71e8573633deda43f6a379d56b3e/tomli-2.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1b168f2731796b045128c45982d3a4874057626da0e2ef1fdd722848b741361d", size = 240875, upload-time = "2026-01-11T11:21:50.755Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/aa/ad/cb089cb190487caa80204d503c7fd0f4d443f90b95cf4ef5cf5aa0f439b0/tomli-2.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:133e93646ec4300d651839d382d63edff11d8978be23da4cc106f5a18b7d0576", size = 246271, upload-time = "2026-01-11T11:21:51.81Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0b/63/69125220e47fd7a3a27fd0de0c6398c89432fec41bc739823bcc66506af6/tomli-2.4.0-cp311-cp311-win32.whl", hash = "sha256:b6c78bdf37764092d369722d9946cb65b8767bfa4110f902a1b2542d8d173c8a", size = 96770, upload-time = "2026-01-11T11:21:52.647Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1e/0d/a22bb6c83f83386b0008425a6cd1fa1c14b5f3dd4bad05e98cf3dbbf4a64/tomli-2.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:d3d1654e11d724760cdb37a3d7691f0be9db5fbdaef59c9f532aabf87006dbaa", size = 107626, upload-time = "2026-01-11T11:21:53.459Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2f/6d/77be674a3485e75cacbf2ddba2b146911477bd887dda9d8c9dfb2f15e871/tomli-2.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:cae9c19ed12d4e8f3ebf46d1a75090e4c0dc16271c5bce1c833ac168f08fb614", size = 94842, upload-time = "2026-01-11T11:21:54.831Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3c/43/7389a1869f2f26dba52404e1ef13b4784b6b37dac93bac53457e3ff24ca3/tomli-2.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:920b1de295e72887bafa3ad9f7a792f811847d57ea6b1215154030cf131f16b1", size = 154894, upload-time = "2026-01-11T11:21:56.07Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e9/05/2f9bf110b5294132b2edf13fe6ca6ae456204f3d749f623307cbb7a946f2/tomli-2.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7d6d9a4aee98fac3eab4952ad1d73aee87359452d1c086b5ceb43ed02ddb16b8", size = 149053, upload-time = "2026-01-11T11:21:57.467Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e8/41/1eda3ca1abc6f6154a8db4d714a4d35c4ad90adc0bcf700657291593fbf3/tomli-2.4.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:36b9d05b51e65b254ea6c2585b59d2c4cb91c8a3d91d0ed0f17591a29aaea54a", size = 243481, upload-time = "2026-01-11T11:21:58.661Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d2/6d/02ff5ab6c8868b41e7d4b987ce2b5f6a51d3335a70aa144edd999e055a01/tomli-2.4.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1c8a885b370751837c029ef9bc014f27d80840e48bac415f3412e6593bbc18c1", size = 251720, upload-time = "2026-01-11T11:22:00.178Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7b/57/0405c59a909c45d5b6f146107c6d997825aa87568b042042f7a9c0afed34/tomli-2.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8768715ffc41f0008abe25d808c20c3d990f42b6e2e58305d5da280ae7d1fa3b", size = 247014, upload-time = "2026-01-11T11:22:01.238Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2c/0e/2e37568edd944b4165735687cbaf2fe3648129e440c26d02223672ee0630/tomli-2.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7b438885858efd5be02a9a133caf5812b8776ee0c969fea02c45e8e3f296ba51", size = 251820, upload-time = "2026-01-11T11:22:02.727Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5a/1c/ee3b707fdac82aeeb92d1a113f803cf6d0f37bdca0849cb489553e1f417a/tomli-2.4.0-cp312-cp312-win32.whl", hash = "sha256:0408e3de5ec77cc7f81960c362543cbbd91ef883e3138e81b729fc3eea5b9729", size = 97712, upload-time = "2026-01-11T11:22:03.777Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/69/13/c07a9177d0b3bab7913299b9278845fc6eaaca14a02667c6be0b0a2270c8/tomli-2.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:685306e2cc7da35be4ee914fd34ab801a6acacb061b6a7abca922aaf9ad368da", size = 108296, upload-time = "2026-01-11T11:22:04.86Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/18/27/e267a60bbeeee343bcc279bb9e8fbed0cbe224bc7b2a3dc2975f22809a09/tomli-2.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:5aa48d7c2356055feef06a43611fc401a07337d5b006be13a30f6c58f869e3c3", size = 94553, upload-time = "2026-01-11T11:22:05.854Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/34/91/7f65f9809f2936e1f4ce6268ae1903074563603b2a2bd969ebbda802744f/tomli-2.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:84d081fbc252d1b6a982e1870660e7330fb8f90f676f6e78b052ad4e64714bf0", size = 154915, upload-time = "2026-01-11T11:22:06.703Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/20/aa/64dd73a5a849c2e8f216b755599c511badde80e91e9bc2271baa7b2cdbb1/tomli-2.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9a08144fa4cba33db5255f9b74f0b89888622109bd2776148f2597447f92a94e", size = 149038, upload-time = "2026-01-11T11:22:07.56Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9e/8a/6d38870bd3d52c8d1505ce054469a73f73a0fe62c0eaf5dddf61447e32fa/tomli-2.4.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c73add4bb52a206fd0c0723432db123c0c75c280cbd67174dd9d2db228ebb1b4", size = 242245, upload-time = "2026-01-11T11:22:08.344Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/59/bb/8002fadefb64ab2669e5b977df3f5e444febea60e717e755b38bb7c41029/tomli-2.4.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1fb2945cbe303b1419e2706e711b7113da57b7db31ee378d08712d678a34e51e", size = 250335, upload-time = "2026-01-11T11:22:09.951Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a5/3d/4cdb6f791682b2ea916af2de96121b3cb1284d7c203d97d92d6003e91c8d/tomli-2.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bbb1b10aa643d973366dc2cb1ad94f99c1726a02343d43cbc011edbfac579e7c", size = 245962, upload-time = "2026-01-11T11:22:11.27Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f2/4a/5f25789f9a460bd858ba9756ff52d0830d825b458e13f754952dd15fb7bb/tomli-2.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4cbcb367d44a1f0c2be408758b43e1ffb5308abe0ea222897d6bfc8e8281ef2f", size = 250396, upload-time = "2026-01-11T11:22:12.325Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/aa/2f/b73a36fea58dfa08e8b3a268750e6853a6aac2a349241a905ebd86f3047a/tomli-2.4.0-cp313-cp313-win32.whl", hash = "sha256:7d49c66a7d5e56ac959cb6fc583aff0651094ec071ba9ad43df785abc2320d86", size = 97530, upload-time = "2026-01-11T11:22:13.865Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3b/af/ca18c134b5d75de7e8dc551c5234eaba2e8e951f6b30139599b53de9c187/tomli-2.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:3cf226acb51d8f1c394c1b310e0e0e61fecdd7adcb78d01e294ac297dd2e7f87", size = 108227, upload-time = "2026-01-11T11:22:15.224Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/22/c3/b386b832f209fee8073c8138ec50f27b4460db2fdae9ffe022df89a57f9b/tomli-2.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:d20b797a5c1ad80c516e41bc1fb0443ddb5006e9aaa7bda2d71978346aeb9132", size = 94748, upload-time = "2026-01-11T11:22:16.009Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f3/c4/84047a97eb1004418bc10bdbcfebda209fca6338002eba2dc27cc6d13563/tomli-2.4.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:26ab906a1eb794cd4e103691daa23d95c6919cc2fa9160000ac02370cc9dd3f6", size = 154725, upload-time = "2026-01-11T11:22:17.269Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a8/5d/d39038e646060b9d76274078cddf146ced86dc2b9e8bbf737ad5983609a0/tomli-2.4.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:20cedb4ee43278bc4f2fee6cb50daec836959aadaf948db5172e776dd3d993fc", size = 148901, upload-time = "2026-01-11T11:22:18.287Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/73/e5/383be1724cb30f4ce44983d249645684a48c435e1cd4f8b5cded8a816d3c/tomli-2.4.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:39b0b5d1b6dd03684b3fb276407ebed7090bbec989fa55838c98560c01113b66", size = 243375, upload-time = "2026-01-11T11:22:19.154Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/31/f0/bea80c17971c8d16d3cc109dc3585b0f2ce1036b5f4a8a183789023574f2/tomli-2.4.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a26d7ff68dfdb9f87a016ecfd1e1c2bacbe3108f4e0f8bcd2228ef9a766c787d", size = 250639, upload-time = "2026-01-11T11:22:20.168Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2c/8f/2853c36abbb7608e3f945d8a74e32ed3a74ee3a1f468f1ffc7d1cb3abba6/tomli-2.4.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:20ffd184fb1df76a66e34bd1b36b4a4641bd2b82954befa32fe8163e79f1a702", size = 246897, upload-time = "2026-01-11T11:22:21.544Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/49/f0/6c05e3196ed5337b9fe7ea003e95fd3819a840b7a0f2bf5a408ef1dad8ed/tomli-2.4.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:75c2f8bbddf170e8effc98f5e9084a8751f8174ea6ccf4fca5398436e0320bc8", size = 254697, upload-time = "2026-01-11T11:22:23.058Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f3/f5/2922ef29c9f2951883525def7429967fc4d8208494e5ab524234f06b688b/tomli-2.4.0-cp314-cp314-win32.whl", hash = "sha256:31d556d079d72db7c584c0627ff3a24c5d3fb4f730221d3444f3efb1b2514776", size = 98567, upload-time = "2026-01-11T11:22:24.033Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7b/31/22b52e2e06dd2a5fdbc3ee73226d763b184ff21fc24e20316a44ccc4d96b/tomli-2.4.0-cp314-cp314-win_amd64.whl", hash = "sha256:43e685b9b2341681907759cf3a04e14d7104b3580f808cfde1dfdb60ada85475", size = 108556, upload-time = "2026-01-11T11:22:25.378Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/48/3d/5058dff3255a3d01b705413f64f4306a141a8fd7a251e5a495e3f192a998/tomli-2.4.0-cp314-cp314-win_arm64.whl", hash = "sha256:3d895d56bd3f82ddd6faaff993c275efc2ff38e52322ea264122d72729dca2b2", size = 96014, upload-time = "2026-01-11T11:22:26.138Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b8/4e/75dab8586e268424202d3a1997ef6014919c941b50642a1682df43204c22/tomli-2.4.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:5b5807f3999fb66776dbce568cc9a828544244a8eb84b84b9bafc080c99597b9", size = 163339, upload-time = "2026-01-11T11:22:27.143Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/06/e3/b904d9ab1016829a776d97f163f183a48be6a4deb87304d1e0116a349519/tomli-2.4.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c084ad935abe686bd9c898e62a02a19abfc9760b5a79bc29644463eaf2840cb0", size = 159490, upload-time = "2026-01-11T11:22:28.399Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e3/5a/fc3622c8b1ad823e8ea98a35e3c632ee316d48f66f80f9708ceb4f2a0322/tomli-2.4.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f2e3955efea4d1cfbcb87bc321e00dc08d2bcb737fd1d5e398af111d86db5df", size = 269398, upload-time = "2026-01-11T11:22:29.345Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fd/33/62bd6152c8bdd4c305ad9faca48f51d3acb2df1f8791b1477d46ff86e7f8/tomli-2.4.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e0fe8a0b8312acf3a88077a0802565cb09ee34107813bba1c7cd591fa6cfc8d", size = 276515, upload-time = "2026-01-11T11:22:30.327Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4b/ff/ae53619499f5235ee4211e62a8d7982ba9e439a0fb4f2f351a93d67c1dd2/tomli-2.4.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:413540dce94673591859c4c6f794dfeaa845e98bf35d72ed59636f869ef9f86f", size = 273806, upload-time = "2026-01-11T11:22:32.56Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/47/71/cbca7787fa68d4d0a9f7072821980b39fbb1b6faeb5f5cf02f4a5559fa28/tomli-2.4.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0dc56fef0e2c1c470aeac5b6ca8cc7b640bb93e92d9803ddaf9ea03e198f5b0b", size = 281340, upload-time = "2026-01-11T11:22:33.505Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f5/00/d595c120963ad42474cf6ee7771ad0d0e8a49d0f01e29576ee9195d9ecdf/tomli-2.4.0-cp314-cp314t-win32.whl", hash = "sha256:d878f2a6707cc9d53a1be1414bbb419e629c3d6e67f69230217bb663e76b5087", size = 108106, upload-time = "2026-01-11T11:22:34.451Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/de/69/9aa0c6a505c2f80e519b43764f8b4ba93b5a0bbd2d9a9de6e2b24271b9a5/tomli-2.4.0-cp314-cp314t-win_amd64.whl", hash = "sha256:2add28aacc7425117ff6364fe9e06a183bb0251b03f986df0e78e974047571fd", size = 120504, upload-time = "2026-01-11T11:22:35.764Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b3/9f/f1668c281c58cfae01482f7114a4b88d345e4c140386241a1a24dcc9e7bc/tomli-2.4.0-cp314-cp314t-win_arm64.whl", hash = "sha256:2b1e3b80e1d5e52e40e9b924ec43d81570f0e7d09d11081b797bc4692765a3d4", size = 99561, upload-time = "2026-01-11T11:22:36.624Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/23/d1/136eb2cb77520a31e1f64cbae9d33ec6df0d78bdf4160398e86eec8a8754/tomli-2.4.0-py3-none-any.whl", hash = "sha256:1f776e7d669ebceb01dee46484485f43a4048746235e683bcdffacdf1fb4785a", size = 14477, upload-time = "2026-01-11T11:22:37.446Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tqdm"
|
name = "tqdm"
|
||||||
version = "4.67.3"
|
version = "4.67.3"
|
||||||
@@ -1302,6 +1410,7 @@ dependencies = [
|
|||||||
{ name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
|
{ name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
|
||||||
{ name = "numpy", version = "2.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
|
{ name = "numpy", version = "2.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
|
||||||
{ name = "openai" },
|
{ name = "openai" },
|
||||||
|
{ name = "pytest" },
|
||||||
{ name = "requests" },
|
{ name = "requests" },
|
||||||
{ name = "types-requests" },
|
{ name = "types-requests" },
|
||||||
]
|
]
|
||||||
@@ -1311,6 +1420,7 @@ requires-dist = [
|
|||||||
{ name = "discord", specifier = ">=2.3.2" },
|
{ name = "discord", specifier = ">=2.3.2" },
|
||||||
{ name = "numpy", specifier = ">=1.24.0" },
|
{ name = "numpy", specifier = ">=1.24.0" },
|
||||||
{ name = "openai", specifier = ">=2.24.0" },
|
{ name = "openai", specifier = ">=2.24.0" },
|
||||||
|
{ name = "pytest", specifier = ">=9.0.2" },
|
||||||
{ name = "requests", specifier = ">=2.32.5" },
|
{ name = "requests", specifier = ">=2.32.5" },
|
||||||
{ name = "types-requests", specifier = ">=2.32.4.20260107" },
|
{ name = "types-requests", specifier = ">=2.32.4.20260107" },
|
||||||
]
|
]
|
||||||
|
|||||||
Reference in New Issue
Block a user