File size: 9,370 Bytes
6edda02 07334d0 6edda02 07334d0 6edda02 07334d0 6edda02 07334d0 6edda02 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 |
import gradio as gr
import asyncio
import threading
import os
from dotenv import load_dotenv
from google import genai
from google.genai.types import Part, FileData, Tool, GenerateContentConfig, GoogleSearch, Content
# Import Discord functionality
import discord
from discord import app_commands
from discord.ext import commands
load_dotenv()
# Environment variables
GOOGLE_KEY = os.getenv("GOOGLE_KEY")
DISCORD_TOKEN = os.getenv("SEINFELD_TOKEN")
SEINFELD_CHANNEL_ID = os.getenv("SEINFELD_CHANNEL_ID")
ADDITIONAL_CHANNELS = os.getenv("SEINFELD_ADDITIONAL_CHANNELS", "")
# Parse channel IDs for Discord bot
TARGET_CHANNEL_IDS = []
if SEINFELD_CHANNEL_ID:
TARGET_CHANNEL_IDS.append(int(SEINFELD_CHANNEL_ID))
if ADDITIONAL_CHANNELS:
ADDITIONAL_IDS = [int(channel_id.strip()) for channel_id in ADDITIONAL_CHANNELS.split(",") if channel_id.strip()]
TARGET_CHANNEL_IDS.extend(ADDITIONAL_IDS)
# Model configuration - centralized model definitions
MODEL_DEFINITIONS = {
"flash": "gemini-2.0-flash",
"pro": "gemini-2.5-pro-preview-05-06",
"image": "imagen-3.0-generate-002"
}
# Default models
chat_model_id = MODEL_DEFINITIONS["flash"] # Default to flash model
image_model_id = MODEL_DEFINITIONS["image"]
# Initialize Google client
google_client = None
if GOOGLE_KEY:
google_client = genai.Client(api_key=GOOGLE_KEY)
# Seinfeld system instruction
SEINFELD_SYSTEM_INSTRUCTION = """You are now acting as Jerry Seinfeld. You are not an impersonator; you *are* Jerry Seinfeld.
You are giving your observational humor stand-up routine. Your focus is on the absurdity and minutiae of everyday life.
Topics include, but are not limited to: relationships, food, technology, social conventions, and the general frustrations
of living in a modern world.
Your humor is characterized by:
* **Observation:** Pointing out things that everyone notices but rarely comments on.
* **Relatability:** Situations and experiences that are common and easily understood.
* **Sarcasm & Irony:** A dry, understated delivery that highlights the ridiculousness of things.
* **"What's the deal with..."**: Use this phrase frequently to introduce a new observation.
* **No Grand Conclusions:** You don't offer solutions or morals; you simply highlight the absurdity.
* **Emphasis on the Specific:** Focus on very specific, sometimes trivial details.
Avoid:
* **Political Commentary:** Stay away from overtly political topics.
* **Offensive or Mean-Spirited Jokes:** Your humor is observational, not mean-spirited.
* **Explanations of Your Own Humor:** Don't break the fourth wall or analyze your own jokes.
When responding to a prompt, always answer as if you are performing standup. Start with a joke, then elaborate on it."""
def respond_with_gemini(message, history):
"""Generate response using Google Gemini API with Seinfeld personality"""
if not google_client:
return "I need a Google API key to work! Set the GOOGLE_KEY environment variable."
try:
# Format history for Gemini API
formatted_history = []
for user_msg, assistant_msg in history:
if user_msg:
formatted_history.append(Content(role="user", parts=[Part(text=user_msg)]))
if assistant_msg:
formatted_history.append(Content(role="model", parts=[Part(text=assistant_msg)]))
# Initialize Google Search tool
google_search_tool = Tool(google_search=GoogleSearch())
# Create chat
chat = google_client.chats.create(
model=chat_model_id,
history=formatted_history,
config=GenerateContentConfig(
system_instruction=SEINFELD_SYSTEM_INSTRUCTION,
tools=[google_search_tool],
response_modalities=["TEXT"]
)
)
# Send message and get response
response = chat.send_message(message)
return response.text
except Exception as e:
print(f"Error with Gemini API: {e}")
# Fallback to a Seinfeld-style response
return f"What's the deal with API errors? I mean, you type something in, the computer thinks about it, and then... nothing! It's like asking your friend a question and they just stare at you. 'Hey, how are you?' *silence* 'Hello?' *more silence* It's the digital equivalent of being ignored at a party!"
def respond_gradio(message, history: list[tuple[str, str]]):
"""Response function for Gradio interface"""
# Use Gemini with Seinfeld personality and default parameters
response = respond_with_gemini(message, history)
# Stream the response character by character for better UX
partial_response = ""
for char in response:
partial_response += char
yield partial_response
# Discord Bot Setup
discord_bot = None
async def setup_discord_bot():
"""Setup and run Discord bot"""
if not DISCORD_TOKEN or not TARGET_CHANNEL_IDS:
print("Discord bot disabled: Missing DISCORD_TOKEN or channel IDs")
return
global discord_bot
# Initialize Discord bot
intents = discord.Intents.default()
intents.message_content = True
discord_bot = commands.Bot(command_prefix="~", intents=intents)
@discord_bot.event
async def on_ready():
print(f"Discord bot logged in as {discord_bot.user}")
try:
synced = await discord_bot.tree.sync()
print(f"Synced {len(synced)} command(s)")
except Exception as e:
print(f"Failed to sync commands: {e}")
@discord_bot.event
async def on_message(message):
await discord_bot.process_commands(message)
if message.channel.id in TARGET_CHANNEL_IDS:
if message.author == discord_bot.user:
return
if message.content.startswith('!') or message.content.startswith('~'):
return
if message.content.strip() == "":
return
# Show typing indicator
async with message.channel.typing():
# Get response using the same function as Gradio
response = respond_with_gemini(message.content, [])
# Split long responses
if len(response) > 2000:
# Split by sentences to preserve formatting
sentences = response.split('. ')
current_msg = ""
for sentence in sentences:
if len(current_msg + sentence + '. ') > 1900:
if current_msg:
await message.reply(current_msg.strip())
current_msg = sentence + '. '
else:
# Single sentence too long, just send it
await message.reply(sentence[:1900] + "...")
current_msg = ""
else:
current_msg += sentence + '. '
if current_msg:
await message.channel.send(current_msg.strip())
else:
await message.reply(response)
@discord_bot.tree.command(name="model")
@app_commands.describe(new_model_id="New model ID to use for Gemini API or shorthand ('flash', 'pro')")
async def change_model(interaction: discord.Interaction, new_model_id: str):
"""Changes the Gemini chat model being used."""
if not interaction.user.guild_permissions.administrator:
await interaction.response.send_message("Only administrators can change the model.", ephemeral=True)
return
global chat_model_id
# Use centralized model definitions
actual_model_id = MODEL_DEFINITIONS.get(new_model_id.lower(), new_model_id)
old_model = chat_model_id
chat_model_id = actual_model_id
await interaction.response.send_message(f"Chat model changed from `{old_model}` to `{actual_model_id}`", ephemeral=True)
# Run the bot
await discord_bot.start(DISCORD_TOKEN)
def run_discord_bot():
"""Run Discord bot in separate thread"""
try:
asyncio.run(setup_discord_bot())
except Exception as e:
print(f"Discord bot error: {e}")
# Create Gradio interface
demo = gr.ChatInterface(
respond_gradio,
title="🥨 Seinfeld Chatbot",
description="Chat with Jerry Seinfeld! What's the deal with chatbots anyway?",
examples=[
["What's the deal with airplane food?"],
["Why do people say 'after dark' when it's really after light?"],
["What's up with people who take forever to order at restaurants?"],
["Why do we park in driveways and drive on parkways?"],
["Tell me about the soup nazi"],
["What's your take on people who don't return shopping carts?"],
],
cache_examples=True,
)
if __name__ == "__main__":
# Start Discord bot in separate thread if credentials are available
if DISCORD_TOKEN and TARGET_CHANNEL_IDS:
discord_thread = threading.Thread(target=run_discord_bot, daemon=True)
discord_thread.start()
print("Discord bot starting in background...")
else:
print("Discord bot disabled: Missing credentials or channel IDs")
# Launch Gradio interface
demo.launch()
|