Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# OpenAI API Configuration
OPENAI_API_KEY=your_openai_api_key_here

# Optional: Set default OpenAI models
DEFAULT_OPENAI_MODEL_A=gpt-4o
DEFAULT_OPENAI_MODEL_B=gpt-4.1
2 changes: 2 additions & 0 deletions Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ name = "pypi"
[packages]
requests = "*"
rich = "*"
openai = "*"
python-dotenv = "*"

[dev-packages]

Expand Down
330 changes: 316 additions & 14 deletions Pipfile.lock

Large diffs are not rendered by default.

46 changes: 39 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,30 +1,42 @@
# InfiniChat
InfiniChat is a command-line application that simulates conversations between two LLMs running locally using Ollama. Just for fun really - I find it interesting to watch the chats! You can have them flesh out ideas, debate things, argue, or just give vague prompts and see what topics they spiral in to.

InfiniChat is a command-line application that simulates conversations between two LLMs. It now supports both local Ollama models and OpenAI API models, giving you the flexibility to choose your preferred AI provider. Just for fun really - I find it interesting to watch the chats! You can have them flesh out ideas, debate things, argue, or just give vague prompts and see what topics they spiral in to.

<p align="center">
<img src="https://github.com/richstokes/InfiniChat/blob/main/screenshot.png?raw=true" width="95%" alt="InfiniChat Screenshot">
</p>

## Features

- **Multi-Provider Support**: Works with both local Ollama and OpenAI API models
- **Full Conversation History**: Models maintain a record of the entire conversation, enabling more coherent interactions
- **Streaming Responses**: Real-time streaming of model outputs with live display
- **Attractive Terminal UI**: Rich text formatting with color-coded speakers and panels
- **Debate Mode**: Set a specific topic for the models to debate, with one arguing "for" and the other "against"
- **Conversation Saving**: Automatically saves transcripts of conversations
- **Environment Configuration**: Easy setup with .env file support

## Requirements

- Python 3.+
- [Ollama](https://ollama.com/download) installed and running
- Required models (`llama3:latest` and `gemma3:12b` by default) pulled in Ollama
- A "non-trivial" amount of RAM. This uses 30GB+ on my Macbook.
- **For Ollama models**:
- [Ollama](https://ollama.com/) installed and running locally
- Local models pulled (e.g., `ollama pull llama3:latest`)
- **For OpenAI models**:
- OpenAI API key (set as environment variable `OPENAI_API_KEY`)
- Internet connection for API calls
- **Mixed usage**: Both requirements above for respective models

## Installation

```bash
# Install dependencies
pipenv install

# For OpenAI models only:
# Copy the example environment file and configure your API key
cp .env.example .env
# Edit .env file and add your OpenAI API key
```

## Usage
Expand All @@ -50,15 +62,29 @@ InfiniChat supports the following command-line arguments:
| `--stats` | Show message history statistics in panel titles | False |
| `--history_limit` | Number of messages to keep in conversation history for each model before summarizing and trimming. Turn this down if messages gradually start to take longer to generate | 100 |
| `--delay` | Delay in seconds between streaming chunks (for slower, more readable streaming) | 0.0 |
| `--model_a` | Name of the first AI model to use | llama3:latest |
| `--model_b` | Name of the second AI model to use | gemma3:12b |
| `--model_a` | Name of the first AI model to use (auto-detected based on client type if not specified) | gpt-4o (OpenAI) / llama3:latest (Ollama) |
| `--model_b` | Name of the second AI model to use (auto-detected based on client type if not specified) | gpt-4.1 (OpenAI) / gemma3:12b (Ollama) |
| `--client_a` | Type of client to use for model A (`ollama` or `openai`) | ollama |
| `--client_b` | Type of client to use for model B (`ollama` or `openai`) | ollama |
| `--debate_topic "Pizza is a vegetable"` | Topic to debate, model A will be "for" the topic, model B will be "against" | None |
| `--model_a_prompt "Your custom prompt"` | Custom system prompt for model A (overrides default from `prompts.py`) | None |
| `--model_b_prompt "Your custom prompt"` | Custom system prompt for model B (overrides default from `prompts.py`) | None |

### Examples

Run with custom settings:
#### Basic Usage
```bash
# Default: Two Ollama models (requires Ollama installation)
pipenv run python app.py

# Two OpenAI models
pipenv run python app.py --client_a openai --client_b openai

# Mixed: Ollama model A and OpenAI model B
pipenv run python app.py --client_a ollama --client_b openai
```

#### Advanced Usage
```bash
# Run with 2000 conversation turns!
pipenv run python app.py --max_turns 2000
Expand All @@ -75,9 +101,15 @@ pipenv run python app.py --delay 0.1
# Use different models
pipenv run python app.py --model_a qwen:latest --model_b deepseek-r1:latest

# Use different OpenAI models
pipenv run python app.py --client_a openai --client_b openai --model_a gpt-4o --model_b gpt-4.1

# Start a debate
pipenv run python app.py --debate_topic "Coffee is better than tea"

# Debate mode with mixed models
pipenv run python app.py --client_a ollama --client_b openai --debate_topic "Will artificial intelligence replace humans?"

# Use custom prompts for both models
pipenv run python app.py --model_a_prompt "You are a cheerful assistant who loves to help people" --model_b_prompt "You are a serious academic who prefers formal language"

Expand Down
72 changes: 50 additions & 22 deletions app.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from llm_client import OllamaClient
from llm_client import OllamaClient, OpenAIClient
from console_utils import console
from prompts import *
from rich.panel import Panel
Expand All @@ -11,11 +11,16 @@
import sys
import time

# Default Ollama models
# MODEL_A_NAME = "deepseek-r1:latest"
# MODEL_A_NAME = "qwen:latest"
MODEL_A_NAME = "llama3:latest"
MODEL_B_NAME = "gemma3:12b"

# Default OpenAI models
OPENAI_MODEL_A_NAME = "gpt-4o"
OPENAI_MODEL_B_NAME = "gpt-4.1"

# Style for client A - blue theme
CLIENT_A_STYLE = "bold blue"
CLIENT_A_PANEL_STYLE = "blue"
Expand Down Expand Up @@ -386,14 +391,28 @@ def display_chunk(chunk):
parser.add_argument(
"--model_a",
type=str,
default="llama3:latest",
help="Name of the first AI model to use",
default="",
help="Name of the first AI model to use (auto-detected based on client type if not specified)",
)
parser.add_argument(
"--model_b",
type=str,
default="gemma3:12b",
help="Name of the second AI model to use",
default="",
help="Name of the second AI model to use (auto-detected based on client type if not specified)",
)
parser.add_argument(
"--client_a",
type=str,
choices=["ollama", "openai"],
default="ollama",
help="Type of client to use for model A (ollama or openai)",
)
parser.add_argument(
"--client_b",
type=str,
choices=["ollama", "openai"],
default="ollama",
help="Type of client to use for model B (ollama or openai)",
)
parser.add_argument(
"--stats",
Expand All @@ -420,6 +439,13 @@ def display_chunk(chunk):
)
args = parser.parse_args()

# Auto-detect model names based on client type if not specified
if not args.model_a:
args.model_a = OPENAI_MODEL_A_NAME if args.client_a == "openai" else MODEL_A_NAME

if not args.model_b:
args.model_b = OPENAI_MODEL_B_NAME if args.client_b == "openai" else MODEL_B_NAME

if args.debate_topic:
console.print(
f"[bold yellow]Debate mode enabled! Topic: {args.debate_topic}[/bold yellow]"
Expand All @@ -442,22 +468,24 @@ def display_chunk(chunk):
console.print("[bold green]Using custom prompt for Model B[/bold green]")

# Initialize clients with parsed arguments
client_A = OllamaClient(
model_name=args.model_a,
debug_mode=args.debug,
show_json=args.show_json,
system_prompt=MODEL_A_PROMPT,
history_limit=args.history_limit,
log_history=args.log_history,
)
client_B = OllamaClient(
model_name=args.model_b,
debug_mode=args.debug,
show_json=args.show_json,
system_prompt=MODEL_B_PROMPT,
history_limit=args.history_limit,
log_history=args.log_history,
)
def create_client(client_type, model_name, system_prompt):
"""Create a client based on the specified type."""
client_args = {
"model_name": model_name,
"debug_mode": args.debug,
"show_json": args.show_json,
"system_prompt": system_prompt,
"history_limit": args.history_limit,
"log_history": args.log_history,
}

if client_type == "openai":
return OpenAIClient(**client_args)
else: # default to ollama
return OllamaClient(**client_args)

client_A = create_client(args.client_a, args.model_a, MODEL_A_PROMPT)
client_B = create_client(args.client_b, args.model_b, MODEL_B_PROMPT)

# Print welcome message
console.print("")
Expand All @@ -481,7 +509,7 @@ def display_chunk(chunk):

# Save the conversation history to a file
output_file = "conversation_history.txt"
with open(output_file, "w") as f:
with open(output_file, "w", encoding="utf-8") as f:
f.write(conversation_history)

# Confirm save with nice formatting
Expand Down
Loading