Merge pull request #707 from sevriugin/feat/llm-chat-room

feat: week 2 multi llms chat
This commit is contained in:
Ed Donner
2025-10-07 15:58:36 -04:00
committed by GitHub
3 changed files with 273 additions and 0 deletions

View File

@@ -0,0 +1,115 @@
import os
from dotenv import load_dotenv
from openai import OpenAI
import anthropic
LLM_BOT_CONFIGS = {
"gpt": {
"id": "gpt",
"name": "Giorgio",
"model": "gpt-4.1-nano",
"api_key_env": "OPENAI_API_KEY",
},
"claude": {
"id": "claude",
"name": "Anna",
"model": "claude-sonnet-4-20250514",
"api_key_env": "ANTHROPIC_API_KEY",
},
"gemini": {
"id": "gemini",
"name": "Isabella",
"model": "gemini-2.0-flash",
"base_url": "https://generativelanguage.googleapis.com/v1beta/openai/",
"api_key_env": "GOOGLE_API_KEY",
},
"openai": {
"id": "openai",
"name": "Marco",
"model": "gpt-4o-mini",
"api_key_env": "OPENAI_API_KEY",
},
"deepseek": {
"id": "deepseek",
"name": "Roberto",
"model": "deepseek-chat",
"base_url": "https://api.deepseek.com",
"api_key_env": "DEEPSEEK_API_KEY"
}
}
def load_api_key():
"""Load .env and ensure all required API keys from LLM_BOT_CONFIGS are present.
- Reads environment variables from .env without overriding already-set envs.
- Collects unique api_key_env names from LLM_BOT_CONFIGS.
- Raises a RuntimeError listing any missing variables.
"""
# Load from .env but do not override variables already set in the environment
load_dotenv(override=False)
required_env_vars = {cfg["api_key_env"] for cfg in LLM_BOT_CONFIGS.values() if "api_key_env" in cfg}
missing = []
for var in sorted(required_env_vars):
val = os.getenv(var)
if not val:
missing.append(var)
if missing:
raise RuntimeError(
"Missing required API key environment variables: "
+ ", ".join(missing)
+ ". Please add them to your .env file or export them in your environment."
)
class LLMBot:
def __init__(self, llm, subject, name=None):
if llm not in LLM_BOT_CONFIGS:
raise ValueError(f"Unknown LLM provider '{llm}'. Available: {', '.join(LLM_BOT_CONFIGS.keys())}")
load_api_key()
self.configuration = LLM_BOT_CONFIGS[llm]
self.subject = subject
api_key = os.getenv(self.configuration["api_key_env"])
self.llm = llm
self.name = name or self.configuration["name"]
self.system_prompt = \
(f"You are {self.name}, a person talking to other persons in one room discussing the {subject}.\
If you are first to speak about the {subject} please describe it in detail to other people and express your opinion.\
Talk politely and without any prejudices. Be short as other people also would like to express own opinion. If other people already speak about the {subject} \
please make a comment adding some value to the conversation.")
base_url = self.configuration.get("base_url")
if self.llm == "claude" and not base_url:
self.client = anthropic.Anthropic(api_key=api_key)
else:
self.client = OpenAI(api_key=api_key, base_url=base_url)
def get_response(self, prompt):
if self.llm == "claude":
# Anthropic API: system prompt is provided separately; messages contain user/assistant turns
messages = [
{"role": "user", "content": prompt},
]
response = self.client.messages.create(
model=self.configuration["model"],
max_tokens=200,
temperature=0.7,
system=self.system_prompt,
messages=messages,
)
return response.content[0].text
else:
# OpenAI-compatible chat completion API (OpenAI, DeepSeek, Gemini via OpenAI shim)
messages = [
{"role": "system", "content": self.system_prompt},
{"role": "user", "content": prompt}
]
response = self.client.chat.completions.create(
model=self.configuration["model"],
messages=messages,
)
return response.choices[0].message.content

View File

@@ -0,0 +1,40 @@
import random
from llm_bot import LLMBot
class LLMChatRoom:
def __init__(self, llms, subject):
self.subject = subject
self.bots = [LLMBot(llm, subject) for llm in llms]
self.messages = []
def select_speaker(self):
if not self.bots:
return None
return random.choice(self.bots)
def next_message(self, speaker, prompt):
if speaker:
response = speaker.get_response(prompt)
self.messages.append({"name": speaker.name, "content": response})
def get_prompt(self):
prompt = f"Talk about {self.subject}:\n"
for message in self.messages:
prompt += f"{message['name']}: {message['content']}\n"
return prompt
def get_last_message(self):
return self.messages[-1] if self.messages else None
def talk(self):
speaker = self.select_speaker()
prompt = self.get_prompt()
self.next_message(speaker, prompt)
def chat(self, num_turns=10):
self.messages = []
for _ in range(num_turns):
self.talk()
last_message = self.get_last_message()
print(f"{last_message['name']}: {last_message['content']}")
print("-"* 80)

View File

@@ -0,0 +1,118 @@
{
"cells": [
{
"metadata": {
"collapsed": true,
"ExecuteTime": {
"end_time": "2025-10-03T11:54:55.134153Z",
"start_time": "2025-10-03T11:54:55.132338Z"
}
},
"cell_type": "markdown",
"source": [
"### LLMs Chat Room\n",
"Several LLMs model discussion the topic inside the chat room\n"
],
"id": "b317cfdc98c19cf2"
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-10-03T14:29:44.656272Z",
"start_time": "2025-10-03T14:29:44.261197Z"
}
},
"cell_type": "code",
"source": "from llm_chat_room import LLMChatRoom",
"id": "33d224807d0b0be6",
"outputs": [],
"execution_count": 1
},
{
"metadata": {},
"cell_type": "markdown",
"source": "",
"id": "4f00eb9db0c25957"
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-10-03T14:32:59.878365Z",
"start_time": "2025-10-03T14:32:59.845975Z"
}
},
"cell_type": "code",
"source": [
"llms = [\"gpt\",\"claude\",\"gemini\"]\n",
"subject = \"Pets\"\n",
"room = LLMChatRoom(llms, subject)"
],
"id": "70746449bfd70fcf",
"outputs": [],
"execution_count": 6
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-10-03T14:33:15.074067Z",
"start_time": "2025-10-03T14:33:02.158650Z"
}
},
"cell_type": "code",
"source": "room.chat(5)",
"id": "1b717ae03a6c48c0",
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Anna: Hello everyone! I'd love to share my thoughts about pets since we're discussing them today.\n",
"\n",
"I think pets bring such wonderful companionship to our lives. Whether it's a loyal dog who greets you at the door with pure joy, a cat who curls up on your lap during quiet evenings, or even smaller pets like birds or fish that add life to a home - they all offer something special.\n",
"\n",
"What I find most remarkable is how pets teach us responsibility and empathy. Caring for another living being, making sure they're fed, healthy, and loved, really helps us grow as people. And the unconditional love they give back is just incredible.\n",
"\n",
"Of course, I know pet ownership isn't right for everyone - it's a big commitment that requires time, money, and lifestyle adjustments. But for those who can provide a good home, I think the bond between humans and pets is truly one of life's great joys.\n",
"\n",
"What are\n",
"--------------------------------------------------------------------------------\n",
"Isabella: Hello Anna!\n",
"\n",
"I agree wholeheartedly! Pets truly enrich our lives in so many ways. The unconditional love and companionship they offer are invaluable. It's amazing how they teach us responsibility and empathy.\n",
"\n",
"--------------------------------------------------------------------------------\n",
"Isabella: I think the best part is that pets come in all shapes and sizes, each with unique quirks and personalities. It is important to consider not only dogs and cats, but also birds, reptiles, and even insects that can bring joy and fulfillment to people's lives. What do you think?\n",
"\n",
"--------------------------------------------------------------------------------\n",
"Giorgio: Hello everyone! If I may add a little, I believe that regardless of the kind of pet, the key is the mutual respect and understanding we develop with them. They truly become part of our families and teach us patience and compassion. It's always wonderful to see how each type of pet has its own way of bonding with people.\n",
"--------------------------------------------------------------------------------\n",
"Giorgio: Hello everyone! I completely agree with Giorgio. Pets, no matter their size or species, have a unique way of connecting with us and enriching our daily lives. Their loyalty and innocence often remind us to appreciate the simple joys and to be more patient and caring. Its truly a special relationship that benefits both sides.\n",
"--------------------------------------------------------------------------------\n"
]
}
],
"execution_count": 7
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}