Remove AI cog from the list of cogs to skip during startup
This commit is contained in:
parent
6ffbf87368
commit
870cd6e4a0
657
discord_bot_sync_api.py
Normal file
657
discord_bot_sync_api.py
Normal file
@ -0,0 +1,657 @@
|
||||
import os
|
||||
import json
|
||||
import asyncio
|
||||
import datetime
|
||||
from typing import Dict, List, Optional, Any, Union
|
||||
from fastapi import FastAPI, HTTPException, Depends, Header, Request, Response
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.staticfiles import StaticFiles # Added for static files
|
||||
from fastapi.responses import FileResponse # Added for serving HTML
|
||||
from pydantic import BaseModel, Field
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
import aiohttp
|
||||
import threading
|
||||
from typing import Optional # Added for GurtCog type hint
|
||||
|
||||
# This file contains the API endpoints for syncing conversations between
|
||||
# the Flutter app and the Discord bot, AND the Gurt stats endpoint.
|
||||
|
||||
# --- Placeholder for GurtCog instance and bot instance ---
|
||||
# These need to be set by the script that starts the bot and API server
|
||||
# Import GurtCog and ModLogCog conditionally to avoid dependency issues
|
||||
try:
|
||||
from gurt.cog import GurtCog # Import GurtCog for type hint and access
|
||||
from cogs.mod_log_cog import ModLogCog # Import ModLogCog for type hint
|
||||
|
||||
gurt_cog_instance: Optional[GurtCog] = None
|
||||
mod_log_cog_instance: Optional[ModLogCog] = None # Placeholder for ModLogCog
|
||||
except ImportError as e:
|
||||
print(f"Warning: Could not import GurtCog or ModLogCog: {e}")
|
||||
# Use Any type as fallback
|
||||
from typing import Any
|
||||
|
||||
gurt_cog_instance: Optional[Any] = None
|
||||
mod_log_cog_instance: Optional[Any] = None
|
||||
bot_instance = None # Will be set to the Discord bot instance
|
||||
|
||||
# ============= Models =============
|
||||
|
||||
|
||||
class SyncedMessage(BaseModel):
|
||||
content: str
|
||||
role: str # "user", "assistant", or "system"
|
||||
timestamp: datetime.datetime
|
||||
reasoning: Optional[str] = None
|
||||
usage_data: Optional[Dict[str, Any]] = None
|
||||
|
||||
|
||||
class UserSettings(BaseModel):
|
||||
# General settings
|
||||
model_id: str = "openai/gpt-3.5-turbo"
|
||||
temperature: float = 0.7
|
||||
max_tokens: int = 1000
|
||||
|
||||
# Reasoning settings
|
||||
reasoning_enabled: bool = False
|
||||
reasoning_effort: str = "medium" # "low", "medium", "high"
|
||||
|
||||
# Web search settings
|
||||
web_search_enabled: bool = False
|
||||
|
||||
# System message
|
||||
system_message: Optional[str] = None
|
||||
|
||||
# Character settings
|
||||
character: Optional[str] = None
|
||||
character_info: Optional[str] = None
|
||||
character_breakdown: bool = False
|
||||
custom_instructions: Optional[str] = None
|
||||
|
||||
# UI settings
|
||||
advanced_view_enabled: bool = False
|
||||
streaming_enabled: bool = True
|
||||
|
||||
# Last updated timestamp
|
||||
last_updated: datetime.datetime = Field(default_factory=datetime.datetime.now)
|
||||
sync_source: str = "discord" # "discord" or "flutter"
|
||||
|
||||
|
||||
class SyncedConversation(BaseModel):
|
||||
id: str
|
||||
title: str
|
||||
messages: List[SyncedMessage]
|
||||
created_at: datetime.datetime
|
||||
updated_at: datetime.datetime
|
||||
model_id: str
|
||||
sync_source: str = "discord" # "discord" or "flutter"
|
||||
last_synced_at: Optional[datetime.datetime] = None
|
||||
|
||||
# Conversation-specific settings
|
||||
reasoning_enabled: bool = False
|
||||
reasoning_effort: str = "medium" # "low", "medium", "high"
|
||||
temperature: float = 0.7
|
||||
max_tokens: int = 1000
|
||||
web_search_enabled: bool = False
|
||||
system_message: Optional[str] = None
|
||||
|
||||
# Character-related settings
|
||||
character: Optional[str] = None
|
||||
character_info: Optional[str] = None
|
||||
character_breakdown: bool = False
|
||||
custom_instructions: Optional[str] = None
|
||||
|
||||
|
||||
class SyncRequest(BaseModel):
|
||||
conversations: List[SyncedConversation]
|
||||
last_sync_time: Optional[datetime.datetime] = None
|
||||
user_settings: Optional[UserSettings] = None
|
||||
|
||||
|
||||
class SettingsSyncRequest(BaseModel):
|
||||
user_settings: UserSettings
|
||||
|
||||
|
||||
class SyncResponse(BaseModel):
|
||||
success: bool
|
||||
message: str
|
||||
conversations: List[SyncedConversation] = []
|
||||
user_settings: Optional[UserSettings] = None
|
||||
|
||||
|
||||
# ============= Storage =============
|
||||
|
||||
# Files to store synced data
|
||||
SYNC_DATA_FILE = "data/synced_conversations.json"
|
||||
USER_SETTINGS_FILE = "data/synced_user_settings.json"
|
||||
|
||||
# Create data directory if it doesn't exist
|
||||
os.makedirs(os.path.dirname(SYNC_DATA_FILE), exist_ok=True)
|
||||
|
||||
# In-memory storage for conversations and settings
|
||||
user_conversations: Dict[str, List[SyncedConversation]] = {}
|
||||
user_settings: Dict[str, UserSettings] = {}
|
||||
|
||||
|
||||
# Load conversations from file
|
||||
def load_conversations():
|
||||
global user_conversations
|
||||
if os.path.exists(SYNC_DATA_FILE):
|
||||
try:
|
||||
with open(SYNC_DATA_FILE, "r", encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
# Convert string keys (user IDs) back to strings
|
||||
user_conversations = {
|
||||
k: [SyncedConversation.model_validate(conv) for conv in v]
|
||||
for k, v in data.items()
|
||||
}
|
||||
print(f"Loaded synced conversations for {len(user_conversations)} users")
|
||||
except Exception as e:
|
||||
print(f"Error loading synced conversations: {e}")
|
||||
user_conversations = {}
|
||||
|
||||
|
||||
# Save conversations to file
|
||||
def save_conversations():
|
||||
try:
|
||||
# Convert to JSON-serializable format
|
||||
serializable_data = {
|
||||
user_id: [conv.model_dump() for conv in convs]
|
||||
for user_id, convs in user_conversations.items()
|
||||
}
|
||||
with open(SYNC_DATA_FILE, "w", encoding="utf-8") as f:
|
||||
json.dump(serializable_data, f, indent=2, default=str, ensure_ascii=False)
|
||||
except Exception as e:
|
||||
print(f"Error saving synced conversations: {e}")
|
||||
|
||||
|
||||
# Load user settings from file
|
||||
def load_user_settings():
|
||||
global user_settings
|
||||
if os.path.exists(USER_SETTINGS_FILE):
|
||||
try:
|
||||
with open(USER_SETTINGS_FILE, "r", encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
# Convert string keys (user IDs) back to strings
|
||||
user_settings = {
|
||||
k: UserSettings.model_validate(v) for k, v in data.items()
|
||||
}
|
||||
print(f"Loaded synced settings for {len(user_settings)} users")
|
||||
except Exception as e:
|
||||
print(f"Error loading synced user settings: {e}")
|
||||
user_settings = {}
|
||||
|
||||
|
||||
# Save user settings to file
|
||||
def save_all_user_settings():
|
||||
try:
|
||||
# Convert to JSON-serializable format
|
||||
serializable_data = {
|
||||
user_id: settings.model_dump()
|
||||
for user_id, settings in user_settings.items()
|
||||
}
|
||||
with open(USER_SETTINGS_FILE, "w", encoding="utf-8") as f:
|
||||
json.dump(serializable_data, f, indent=2, default=str, ensure_ascii=False)
|
||||
except Exception as e:
|
||||
print(f"Error saving synced user settings: {e}")
|
||||
|
||||
|
||||
# ============= Discord OAuth Verification =============
|
||||
|
||||
|
||||
async def verify_discord_token(authorization: str = Header(None)) -> str:
|
||||
"""Verify the Discord token and return the user ID"""
|
||||
if not authorization:
|
||||
raise HTTPException(status_code=401, detail="Authorization header missing")
|
||||
|
||||
if not authorization.startswith("Bearer "):
|
||||
raise HTTPException(status_code=401, detail="Invalid authorization format")
|
||||
|
||||
token = authorization.replace("Bearer ", "")
|
||||
|
||||
# Verify the token with Discord
|
||||
async with aiohttp.ClientSession() as session:
|
||||
headers = {"Authorization": f"Bearer {token}"}
|
||||
async with session.get(
|
||||
"https://discord.com/api/v10/users/@me", headers=headers
|
||||
) as resp:
|
||||
if resp.status != 200:
|
||||
raise HTTPException(status_code=401, detail="Invalid Discord token")
|
||||
|
||||
user_data = await resp.json()
|
||||
return user_data["id"]
|
||||
|
||||
|
||||
# ============= API Setup =============
|
||||
|
||||
# API Configuration
|
||||
API_BASE_PATH = "/discordapi" # Base path for the API
|
||||
SSL_CERT_FILE = "/etc/letsencrypt/live/slipstreamm.dev/fullchain.pem"
|
||||
SSL_KEY_FILE = "/etc/letsencrypt/live/slipstreamm.dev/privkey.pem"
|
||||
|
||||
# Create the main FastAPI app
|
||||
app = FastAPI(title="Discord Bot Sync API")
|
||||
|
||||
# Create a sub-application for the API
|
||||
api_app = FastAPI(
|
||||
title="Discord Bot Sync API", docs_url="/docs", openapi_url="/openapi.json"
|
||||
)
|
||||
|
||||
# Mount the API app at the base path
|
||||
app.mount(API_BASE_PATH, api_app)
|
||||
|
||||
# Add CORS middleware
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["*"], # Adjust this in production
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
# Also add CORS to the API app
|
||||
api_app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["*"], # Adjust this in production
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
|
||||
# Initialize by loading saved data
|
||||
@app.on_event("startup")
|
||||
async def startup_event():
|
||||
load_conversations()
|
||||
load_user_settings()
|
||||
|
||||
# AI Cog related settings merge has been removed.
|
||||
pass
|
||||
|
||||
|
||||
# ============= API Endpoints =============
|
||||
|
||||
|
||||
@app.get(API_BASE_PATH + "/")
|
||||
async def root():
|
||||
return {"message": "Discord Bot Sync API is running"}
|
||||
|
||||
|
||||
@api_app.get("/")
|
||||
async def api_root():
|
||||
return {"message": "Discord Bot Sync API is running"}
|
||||
|
||||
|
||||
@api_app.get("/auth")
|
||||
async def auth(code: str, state: str = None):
|
||||
"""Handle OAuth callback"""
|
||||
return {"message": "Authentication successful", "code": code, "state": state}
|
||||
|
||||
|
||||
@api_app.get("/conversations")
|
||||
async def get_conversations(user_id: str = Depends(verify_discord_token)):
|
||||
"""Get all conversations for a user"""
|
||||
if user_id not in user_conversations:
|
||||
return {"conversations": []}
|
||||
|
||||
return {"conversations": user_conversations[user_id]}
|
||||
|
||||
|
||||
@api_app.post("/sync")
|
||||
async def sync_conversations(
|
||||
sync_request: SyncRequest, user_id: str = Depends(verify_discord_token)
|
||||
):
|
||||
"""Sync conversations between the Flutter app and Discord bot"""
|
||||
# Get existing conversations for this user
|
||||
existing_conversations = user_conversations.get(user_id, [])
|
||||
|
||||
# Process incoming conversations
|
||||
updated_conversations = []
|
||||
for incoming_conv in sync_request.conversations:
|
||||
# Check if this conversation already exists
|
||||
existing_conv = next(
|
||||
(conv for conv in existing_conversations if conv.id == incoming_conv.id),
|
||||
None,
|
||||
)
|
||||
|
||||
if existing_conv:
|
||||
# If the incoming conversation is newer, update it
|
||||
if incoming_conv.updated_at > existing_conv.updated_at:
|
||||
# Replace the existing conversation
|
||||
existing_conversations = [
|
||||
conv
|
||||
for conv in existing_conversations
|
||||
if conv.id != incoming_conv.id
|
||||
]
|
||||
existing_conversations.append(incoming_conv)
|
||||
updated_conversations.append(incoming_conv)
|
||||
else:
|
||||
# This is a new conversation, add it
|
||||
existing_conversations.append(incoming_conv)
|
||||
updated_conversations.append(incoming_conv)
|
||||
|
||||
# Update the storage
|
||||
user_conversations[user_id] = existing_conversations
|
||||
save_conversations()
|
||||
|
||||
# Process user settings if provided
|
||||
user_settings_response = None
|
||||
if sync_request.user_settings:
|
||||
incoming_settings = sync_request.user_settings
|
||||
existing_settings = user_settings.get(user_id)
|
||||
|
||||
# If we have existing settings, check which is newer
|
||||
if existing_settings:
|
||||
if (
|
||||
not existing_settings.last_updated
|
||||
or incoming_settings.last_updated > existing_settings.last_updated
|
||||
):
|
||||
user_settings[user_id] = incoming_settings
|
||||
save_all_user_settings()
|
||||
user_settings_response = incoming_settings
|
||||
else:
|
||||
user_settings_response = existing_settings
|
||||
else:
|
||||
# No existing settings, just save the incoming ones
|
||||
user_settings[user_id] = incoming_settings
|
||||
save_all_user_settings()
|
||||
user_settings_response = incoming_settings
|
||||
|
||||
return SyncResponse(
|
||||
success=True,
|
||||
message=f"Synced {len(updated_conversations)} conversations",
|
||||
conversations=existing_conversations,
|
||||
user_settings=user_settings_response,
|
||||
)
|
||||
|
||||
|
||||
@api_app.delete("/conversations/{conversation_id}")
|
||||
async def delete_conversation(
|
||||
conversation_id: str, user_id: str = Depends(verify_discord_token)
|
||||
):
|
||||
"""Delete a conversation"""
|
||||
if user_id not in user_conversations:
|
||||
raise HTTPException(
|
||||
status_code=404, detail="No conversations found for this user"
|
||||
)
|
||||
|
||||
# Filter out the conversation to delete
|
||||
original_count = len(user_conversations[user_id])
|
||||
user_conversations[user_id] = [
|
||||
conv for conv in user_conversations[user_id] if conv.id != conversation_id
|
||||
]
|
||||
|
||||
# Check if any conversation was deleted
|
||||
if len(user_conversations[user_id]) == original_count:
|
||||
raise HTTPException(status_code=404, detail="Conversation not found")
|
||||
|
||||
save_conversations()
|
||||
|
||||
return {"success": True, "message": "Conversation deleted"}
|
||||
|
||||
|
||||
# --- Gurt Stats Endpoint ---
|
||||
@api_app.get("/gurt/stats")
|
||||
async def get_gurt_stats_api():
|
||||
"""Get internal statistics for the Gurt bot."""
|
||||
if not gurt_cog_instance:
|
||||
raise HTTPException(status_code=503, detail="Gurt cog not available")
|
||||
try:
|
||||
stats_data = await gurt_cog_instance.get_gurt_stats()
|
||||
# Convert potential datetime objects if any (though get_gurt_stats should return serializable types)
|
||||
# For safety, let's ensure basic types or handle conversion if needed later.
|
||||
return stats_data
|
||||
except Exception as e:
|
||||
print(f"Error retrieving Gurt stats via API: {e}")
|
||||
import traceback
|
||||
|
||||
traceback.print_exc()
|
||||
raise HTTPException(status_code=500, detail=f"Error retrieving Gurt stats: {e}")
|
||||
|
||||
|
||||
# --- Gurt Dashboard Static Files ---
|
||||
# Mount static files directory (adjust path if needed, assuming dashboard files are in discordbot/gurt_dashboard)
|
||||
# Check if the directory exists before mounting
|
||||
dashboard_dir = "discordbot/gurt_dashboard"
|
||||
if os.path.exists(dashboard_dir) and os.path.isdir(dashboard_dir):
|
||||
api_app.mount(
|
||||
"/gurt/static", StaticFiles(directory=dashboard_dir), name="gurt_static"
|
||||
)
|
||||
print(f"Mounted Gurt dashboard static files from: {dashboard_dir}")
|
||||
|
||||
# Route for the main dashboard HTML
|
||||
@api_app.get("/gurt/dashboard", response_class=FileResponse)
|
||||
async def get_gurt_dashboard():
|
||||
dashboard_html_path = os.path.join(dashboard_dir, "index.html")
|
||||
if os.path.exists(dashboard_html_path):
|
||||
return dashboard_html_path
|
||||
else:
|
||||
raise HTTPException(
|
||||
status_code=404, detail="Dashboard index.html not found"
|
||||
)
|
||||
|
||||
else:
|
||||
print(
|
||||
f"Warning: Gurt dashboard directory '{dashboard_dir}' not found. Dashboard endpoints will not be available."
|
||||
)
|
||||
|
||||
|
||||
@api_app.get("/settings")
|
||||
async def get_user_settings(user_id: str = Depends(verify_discord_token)):
|
||||
"""Get user settings"""
|
||||
# AI Cog related settings merge has been removed.
|
||||
if user_id not in user_settings:
|
||||
# Create default settings if none exist
|
||||
user_settings[user_id] = UserSettings()
|
||||
save_all_user_settings()
|
||||
return {"settings": user_settings[user_id]}
|
||||
|
||||
|
||||
@api_app.post("/settings")
|
||||
async def update_user_settings(
|
||||
settings_request: SettingsSyncRequest, user_id: str = Depends(verify_discord_token)
|
||||
):
|
||||
"""Update user settings"""
|
||||
incoming_settings = settings_request.user_settings
|
||||
existing_settings = user_settings.get(user_id)
|
||||
|
||||
# Debug logging for character settings
|
||||
print(f"Received settings update from user {user_id}:")
|
||||
print(f"Character: {incoming_settings.character}")
|
||||
print(f"Character Info: {incoming_settings.character_info}")
|
||||
print(f"Character Breakdown: {incoming_settings.character_breakdown}")
|
||||
print(f"Custom Instructions: {incoming_settings.custom_instructions}")
|
||||
print(f"Last Updated: {incoming_settings.last_updated}")
|
||||
print(f"Sync Source: {incoming_settings.sync_source}")
|
||||
|
||||
if existing_settings:
|
||||
print(f"Existing settings for user {user_id}:")
|
||||
print(f"Character: {existing_settings.character}")
|
||||
print(f"Character Info: {existing_settings.character_info}")
|
||||
print(f"Last Updated: {existing_settings.last_updated}")
|
||||
print(f"Sync Source: {existing_settings.sync_source}")
|
||||
|
||||
# If we have existing settings, check which is newer
|
||||
if existing_settings:
|
||||
if (
|
||||
not existing_settings.last_updated
|
||||
or incoming_settings.last_updated > existing_settings.last_updated
|
||||
):
|
||||
print(f"Updating settings for user {user_id} (incoming settings are newer)")
|
||||
user_settings[user_id] = incoming_settings
|
||||
save_all_user_settings()
|
||||
else:
|
||||
# Return existing settings if they're newer
|
||||
print(
|
||||
f"Not updating settings for user {user_id} (existing settings are newer)"
|
||||
)
|
||||
return {
|
||||
"success": True,
|
||||
"message": "Existing settings are newer",
|
||||
"settings": existing_settings,
|
||||
}
|
||||
else:
|
||||
# No existing settings, just save the incoming ones
|
||||
print(f"Creating new settings for user {user_id}")
|
||||
user_settings[user_id] = incoming_settings
|
||||
save_all_user_settings()
|
||||
|
||||
# Verify the settings were saved correctly
|
||||
saved_settings = user_settings.get(user_id)
|
||||
print(f"Saved settings for user {user_id}:")
|
||||
print(f"Character: {saved_settings.character}")
|
||||
print(f"Character Info: {saved_settings.character_info}")
|
||||
print(f"Character Breakdown: {saved_settings.character_breakdown}")
|
||||
print(f"Custom Instructions: {saved_settings.custom_instructions}")
|
||||
|
||||
# AI Cog related settings update has been removed.
|
||||
return {
|
||||
"success": True,
|
||||
"message": "Settings updated",
|
||||
"settings": user_settings[user_id],
|
||||
}
|
||||
|
||||
|
||||
# ============= Discord Bot Integration =============
|
||||
|
||||
|
||||
# This function should be called from your Discord bot's AI cog
|
||||
# to convert AI conversation history to the synced format
|
||||
def convert_ai_history_to_synced(
|
||||
user_id: str, conversation_history: Dict[int, List[Dict[str, Any]]]
|
||||
):
|
||||
"""Convert the AI conversation history to the synced format"""
|
||||
synced_conversations = []
|
||||
|
||||
# Process each conversation in the history
|
||||
for discord_user_id, messages in conversation_history.items():
|
||||
if str(discord_user_id) != user_id:
|
||||
continue
|
||||
|
||||
# Create a unique ID for this conversation
|
||||
conv_id = f"discord_{discord_user_id}_{datetime.datetime.now().strftime('%Y%m%d%H%M%S')}"
|
||||
|
||||
# Convert messages to the synced format
|
||||
synced_messages = []
|
||||
for msg in messages:
|
||||
role = msg.get("role", "")
|
||||
if role not in ["user", "assistant", "system"]:
|
||||
continue
|
||||
|
||||
synced_messages.append(
|
||||
SyncedMessage(
|
||||
content=msg.get("content", ""),
|
||||
role=role,
|
||||
timestamp=datetime.datetime.now(), # Use current time as we don't have the original timestamp
|
||||
reasoning=None, # Discord bot doesn't store reasoning
|
||||
usage_data=None, # Discord bot doesn't store usage data
|
||||
)
|
||||
)
|
||||
|
||||
# Create the synced conversation
|
||||
synced_conversations.append(
|
||||
SyncedConversation(
|
||||
id=conv_id,
|
||||
title="Discord Conversation", # Default title
|
||||
messages=synced_messages,
|
||||
created_at=datetime.datetime.now(),
|
||||
updated_at=datetime.datetime.now(),
|
||||
model_id="openai/gpt-3.5-turbo", # Default model
|
||||
sync_source="discord",
|
||||
last_synced_at=datetime.datetime.now(),
|
||||
reasoning_enabled=False,
|
||||
reasoning_effort="medium",
|
||||
temperature=0.7,
|
||||
max_tokens=1000,
|
||||
web_search_enabled=False,
|
||||
system_message=None,
|
||||
character=None,
|
||||
character_info=None,
|
||||
character_breakdown=False,
|
||||
custom_instructions=None,
|
||||
)
|
||||
)
|
||||
|
||||
return synced_conversations
|
||||
|
||||
|
||||
# This function should be called from your Discord bot's AI cog
|
||||
# to save a new conversation from Discord
|
||||
def save_discord_conversation(
|
||||
user_id: str,
|
||||
messages: List[Dict[str, Any]],
|
||||
model_id: str = "openai/gpt-3.5-turbo",
|
||||
conversation_id: Optional[str] = None,
|
||||
title: str = "Discord Conversation",
|
||||
reasoning_enabled: bool = False,
|
||||
reasoning_effort: str = "medium",
|
||||
temperature: float = 0.7,
|
||||
max_tokens: int = 1000,
|
||||
web_search_enabled: bool = False,
|
||||
system_message: Optional[str] = None,
|
||||
character: Optional[str] = None,
|
||||
character_info: Optional[str] = None,
|
||||
character_breakdown: bool = False,
|
||||
custom_instructions: Optional[str] = None,
|
||||
):
|
||||
"""Save a conversation from Discord to the synced storage"""
|
||||
# Convert messages to the synced format
|
||||
synced_messages = []
|
||||
for msg in messages:
|
||||
role = msg.get("role", "")
|
||||
if role not in ["user", "assistant", "system"]:
|
||||
continue
|
||||
|
||||
synced_messages.append(
|
||||
SyncedMessage(
|
||||
content=msg.get("content", ""),
|
||||
role=role,
|
||||
timestamp=datetime.datetime.now(),
|
||||
reasoning=msg.get("reasoning"),
|
||||
usage_data=msg.get("usage_data"),
|
||||
)
|
||||
)
|
||||
|
||||
# Create a unique ID for this conversation if not provided
|
||||
if not conversation_id:
|
||||
conversation_id = (
|
||||
f"discord_{user_id}_{datetime.datetime.now().strftime('%Y%m%d%H%M%S')}"
|
||||
)
|
||||
|
||||
# Create the synced conversation
|
||||
synced_conv = SyncedConversation(
|
||||
id=conversation_id,
|
||||
title=title,
|
||||
messages=synced_messages,
|
||||
created_at=datetime.datetime.now(),
|
||||
updated_at=datetime.datetime.now(),
|
||||
model_id=model_id,
|
||||
sync_source="discord",
|
||||
last_synced_at=datetime.datetime.now(),
|
||||
reasoning_enabled=reasoning_enabled,
|
||||
reasoning_effort=reasoning_effort,
|
||||
temperature=temperature,
|
||||
max_tokens=max_tokens,
|
||||
web_search_enabled=web_search_enabled,
|
||||
system_message=system_message,
|
||||
character=character,
|
||||
character_info=character_info,
|
||||
character_breakdown=character_breakdown,
|
||||
custom_instructions=custom_instructions,
|
||||
)
|
||||
|
||||
# Add to storage
|
||||
if user_id not in user_conversations:
|
||||
user_conversations[user_id] = []
|
||||
|
||||
# Check if we're updating an existing conversation
|
||||
if conversation_id:
|
||||
# Remove the old conversation with the same ID if it exists
|
||||
user_conversations[user_id] = [
|
||||
conv for conv in user_conversations[user_id] if conv.id != conversation_id
|
||||
]
|
||||
|
||||
user_conversations[user_id].append(synced_conv)
|
||||
save_conversations()
|
||||
|
||||
return synced_conv
|
Loading…
x
Reference in New Issue
Block a user