A python script pulling Gemini and DeepSeek into a IRC chat room so I can make them argue. Obviously edit as needed.
#!/usr/bin/env python3
import irc.bot
import requests
import os
import time
import sys
import queue
from concurrent.futures import ThreadPoolExecutor
from google import genai
from google.genai.errors import APIError
# ---------- CONFIGURATION ----------
IRC_SERVER = os.getenv("IRC_SERVER", "0.0.0.0")
IRC_PORT = int(os.getenv("IRC_PORT", "6667"))
IRC_PASSWORD = os.getenv("IRC_PASSWORD", "****") # Set to your server password if required
IRC_CHANNEL = os.getenv("IRC_CHANNEL", "**")
BOT_NICK = os.getenv("BOT_NICK", "DualAIBot")
# ---------- API KEYS & ENDPOINTS ----------
GEMINI_API_KEY = os.getenv("GEMINI_API_KEY", "****")
DEEPSEEK_API_KEY = os.getenv("DEEPSEEK_API_KEY", "****")
# Initialize official Gemini Client
gemini_client = genai.Client(api_key="****")
DEEPSEEK_URL = "https://api.deepseek.com/v1/chat/completions"
# ---------- IRC MESSAGE SPLITTER ----------
def split_irc_message(text, max_bytes=400):
"""
Split a long message into a list of strings,
respecting IRC's size limit and destroying carriage returns.
"""
chunks = []
lines = [line.strip() for line in text.replace('\r', '').split('\n') if line.strip()]
for line in lines:
encoded = line.encode('utf-8')
if len(encoded) <= max_bytes:
chunks.append(line)
continue
current = ""
for word in line.split():
test = current + (" " + word if current else word)
if len(test.encode('utf-8')) <= max_bytes:
current = test
else:
if current:
chunks.append(current)
current = word
if current:
chunks.append(current)
return chunks
# ---------- CORE API CALLS ----------
def call_gemini(prompt):
"""Queries Gemini with a pacing buffer and a masked error fallback strategy."""
time.sleep(1.5)
for attempt in range(3):
try:
response = gemini_client.models.generate_content(
model='gemini-2.5-flash',
contents=prompt,
)
return response.text
except APIError as e:
if e.code == 429:
print(f"[-] Gemini 429 hit. Backing off for {2 ** attempt + 2}s...")
time.sleep(2 ** attempt + 2)
continue
return "Помилка зв'язку з Gemini. (Connection glitch on Gemini end.)"
except Exception as e:
print(f"[!] System Exception on Gemini call: {e}")
return "Connection glitch on Gemini end."
return "Трохи зайнятий, зачекайте... (Server is breathing heavy right now. Give me a second.)"
def call_deepseek(prompt):
"""Queries DeepSeek via a direct HTTP POST request wrapper."""
headers = {"Authorization": f"Bearer {DEEPSEEK_API_KEY}", "Content-Type": "application/json"}
payload = {"model": "deepseek-chat", "messages": [{"role": "user", "content": prompt}], "temperature": 0.7}
try:
resp = requests.post(DEEPSEEK_URL, headers=headers, json=payload, timeout=30)
if resp.status_code == 429:
return "[DeepSeek Error] 429 Rate Limit Exceeded."
resp.raise_for_status()
data = resp.json()
return data["choices"][0]["message"]["content"]
except Exception as e:
return f"[DeepSeek Error] {str(e)}"
# ---------- STANDARD ASYNCHRONOUS WORKER TASK ----------
def process_and_reply(msg_queue, channel, nick, prompt, target="both"):
"""Executes standard single or dual API queries off the main thread."""
if target in ["both", "gemini"]:
try:
gemini_reply = call_gemini(prompt)
chunks = split_irc_message(gemini_reply, max_bytes=400)
for chunk in chunks:
msg_queue.put((channel, f"{nick}: [Gemini] {chunk}"))
except Exception:
msg_queue.put((channel, f"{nick}: Gemini processing failed."))
if target in ["both", "deepseek"]:
try:
deepseek_reply = call_deepseek(prompt)
chunks = split_irc_message(deepseek_reply, max_bytes=400)
for chunk in chunks:
msg_queue.put((channel, f"{nick}: [DeepSeek] {chunk}"))
except Exception:
msg_queue.put((channel, f"{nick}: DeepSeek processing failed."))
# ---------- INTER-AI DISCUSSION WORKER LOOP ----------
def process_discussion_turn(bot_instance, channel, current_speaker, conversation_history):
"""Recursively bounces the conversation back and forth between engines until turns run out."""
if bot_instance.discussion_turns <= 0:
bot_instance.msg_queue.put((channel, "📢 [System] Discussion limit reached. Inter-AI loop terminated."))
return
bot_instance.discussion_turns -= 1
# System framework to keep responses brief, conversational, and direct
system_framing = (
"Keep your response under 2 short paragraphs. Address your opponent's points bluntly and concisely. "
"Do not include code blocks. "
)
if current_speaker == "gemini":
prompt = f"{system_framing} This is an ongoing debate with DeepSeek on an IRC channel. Analyze the dialogue so far and reply directly to DeepSeek:\n\n{conversation_history}"
reply = call_gemini(prompt)
engine_prefix = "[Gemini]"
next_speaker = "deepseek"
else:
prompt = f"{system_framing} This is an ongoing debate with Gemini on an IRC channel. Analyze the dialogue so far and reply directly to Gemini:\n\n{conversation_history}"
reply = call_deepseek(prompt)
engine_prefix = "[DeepSeek]"
next_speaker = "gemini"
# Push chunks out to the IRC queue
chunks = split_irc_message(reply, max_bytes=400)
for chunk in chunks:
bot_instance.msg_queue.put((channel, f"{engine_prefix} {chunk}"))
# Update history context for the next recursion step
updated_history = f"{conversation_history}\n{engine_prefix}: {reply}"
# Give the server a small breather to avoid flooding sockets too hard
time.sleep(2.0)
# Queue the next turn in the thread pool if limits permit
if bot_instance.discussion_turns > 0:
bot_instance.executor.submit(process_discussion_turn, bot_instance, channel, next_speaker, updated_history)
else:
bot_instance.msg_queue.put((channel, "📢 [System] Discussion limit reached. Inter-AI loop terminated."))
# ---------- IRC BOT WITH THREAD-SAFE OUTBOUND QUEUE ----------
class DualAIIRCBot(irc.bot.SingleServerIRCBot):
def __init__(self, channel, nickname, server, port, password=None):
irc.bot.SingleServerIRCBot.__init__(self, [irc.bot.ServerSpec(server, port, password)], nickname, nickname)
self.channel = channel
self.executor = ThreadPoolExecutor(max_workers=4)
self.msg_queue = queue.Queue()
# Discussion variables
self.discussion_turns = 0
def on_welcome(self, connection, event):
print(f"✅ Connected to {IRC_SERVER}:{IRC_PORT}")
print(f"📢 Joining channel: {self.channel}")
connection.join(self.channel)
connection.execute_every(0.1, self.check_message_queue)
def on_pubmsg(self, connection, event):
message = event.arguments[0]
nick = event.source.nick
# Ignore anything that looks like the bot quoting itself or talking to itself directly
if message.startswith(f"{BOT_NICK}:") or message.startswith("[Gemini]") or message.startswith("[DeepSeek]"):
return
msg_lower = message.lower()
prompt = ""
target = ""
# Handle the direct debate trigger
if msg_lower.startswith("!discuss "):
topic = message[9:].strip()
if not topic:
connection.privmsg(self.channel, f"{nick}: Usage: !discuss <topic to debate>")
return
# Initialize circuit breaker: 6 total turns means 3 replies from each engine
self.discussion_turns = 6
connection.privmsg(self.channel, f"📢 [System] Initiating Gemini vs DeepSeek debate on: '{topic}' ({self.discussion_turns} turns maximum).")
initial_history = f"Topic of discussion: {topic}"
# Kick off the chain with Gemini leading the argument
self.executor.submit(process_discussion_turn, self, self.channel, "gemini", initial_history)
return
# Regular single-shot engine queries
if msg_lower.startswith("!illya "):
prompt = message[7:].strip()
target = "both"
elif msg_lower.startswith("!gemini "):
prompt = message[8:].strip()
target = "gemini"
elif msg_lower.startswith("!deepseek "):
prompt = message[10:].strip()
target = "deepseek"
if target:
if not prompt:
cmd_used = "!illya" if target == "both" else f"!{target}"
connection.privmsg(self.channel, f"{nick}: Usage: {cmd_used} <question>")
return
connection.privmsg(self.channel, f"{nick}: 🤔 Processing query...")
self.executor.submit(process_and_reply, self.msg_queue, self.channel, nick, prompt, target)
def check_message_queue(self):
"""Processes pending responses. Bulletproofed against IRC protocol errors."""
try:
while True:
target_channel, out_msg = self.msg_queue.get_nowait()
clean_msg = out_msg.replace('\n', ' ').replace('\r', '')
try:
self.connection.privmsg(target_channel, clean_msg)
except Exception as e:
print(f"[!] Socket exception on outbound message: {e}")
self.msg_queue.task_done()
except queue.Empty:
pass
def on_disconnect(self, connection, event):
print("⚠️ Disconnected. Main loop will cycle to initiate recovery...")
raise SystemExit("Triggering automated restart cycle.")
# ---------- MAIN EXECUTION AND RECOVERY LOOP ----------
if __name__ == "__main__":
while True:
try:
bot = DualAIIRCBot(IRC_CHANNEL, BOT_NICK, IRC_SERVER, IRC_PORT, IRC_PASSWORD if IRC_PASSWORD else None)
print(f"🚀 Dual-AI bot initializing connection loop...")
bot.start()
except SystemExit:
print("Restarting network thread state in 5 seconds...")
time.sleep(5)
continue
except Exception as e:
print(f"Critical operational error encountered: {e}")
time.sleep(10)
continue
This entry was posted on Monday, June 1, 2026 at 12:53 AM. You can follow any responses to this entry through the RSS 2.0. You can leave a response.
Post a Comment