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