Bookmark and Share

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

Unlocked LG G3 VS985 4g LTE, AT&T APN settings that work

If you bought a Verizon branded, unlocked GSM LG G3 VS985 4g LTE phone and can't get mobile data or MMS to work on AT&T - here are the settings you need.

Compiling mongodb with ssl support

It only took me ten hours! Let me save you some pain. I found a nice script for doing this here: http://brakertech.com/howto-make-mongo-ssl-on-ubuntu-12-04/ and modified it slightly to work on Ubuntu Saucy like so:

#!/bin/bash
RELEASE=saucy
ARCH=amd64
BASE=$PWD
VERSION=2.5.5
apt-get -y install git-core build-essential scons libssl-dev

# Grab the source code.
git clone git://github.com/mongodb/mongo.git
cd mongo
git checkout r$VERSION

# Build it with SSL enabled and mostly statically.
scons install --64 --ssl --release --no-glibc-check --prefix=$BASE/opt/mongo

mkdir $BASE/opt

# Pack it up.
cd $BASE/opt
tar czvf mongo-$VERSION-$RELEASE-$ARCH.tgz mongo/bin

This uses a development version of mongodb, as older versions have dependency ish. If you're running saucy x64 I can save you pain and time: https://drive.google.com/file/d/0B7BiEI3PiFYZNFdpQlQ3RU8yNmc/edit?usp=sharing


Play and Backup DVDs - on Windows or Linux

libdvdcss is an open source tool to decrypt CSS encrypted DVD's. This allows you to play or backup a standard DVD on your computer. This package includes a windows installer and .deb installers for Linux i386 and amd64:

libdvdcss_1.2.10-0.2.zip
libdvdcss_1.2.10-0.2.zip.torrent

Parents can dig Linux's free teaching games

Free teaching games are a nerdly parents friend. Luckily, Linux abounds with them. Today I bring you numpty physics. "Harness gravity with your crayon and set about creating blocks, ramps, levers, pulleys and whatever else you fancy to get the little red thing to the little yellow thing."


Debian and Ubuntu users can: apt-get install numptyphysics

Other system users see here

Logging into your SSH server with your Android.



Why not log into your machine using your Android while sitting at your doctor's office? Giggle with nerdly joy as you perform system updates, install software, reboot your machine, or make it play random media files to scare your roommates.

First you'll need to have SSH server set up and running on your home machine. A primer on that can be found here.

Next up, grab the ConnectBot app.

Log in, and delight in the command line fun!

Encrypting Gtalk, Facebook & other XMPP IM's on Android



Xabber is a neat little XMPP client for Android with built in OTR support, allowing you to encrypt your messages. Simply install the app, configure your accounts, and enable OTR support under settings, security, OTR.