A Python chat program supporting multiple LLM providers (Google Gemini, OpenAI, Anthropic) with runtime model switching, streaming responses, and a web UI that supports document uploads (PDF/txt/md) with retrieval-augmented question answering.
| Provider | Models | Free tier |
|---|---|---|
| Google Gemini | gemini-3.1-flash-lite, gemini-2.5-flash, ... |
aistudio.google.com |
| OpenAI | gpt-4o, gpt-4o-mini, ... |
platform.openai.com |
| Anthropic | claude-opus-4-7, claude-sonnet-4-6, ... |
console.anthropic.com |
Python 3.10+
-
Create and activate a virtual environment:
python3.10 -m venv venv source venv/bin/activate -
Install dependencies:
pip install -r requirements.txt
-
Copy
.env.exampleto.envand fill in your keys:cp .env.example .env
PROVIDER=gemini # gemini | openai | anthropic GEMINI_API_KEY=your_key OPENAI_API_KEY=your_key ANTHROPIC_API_KEY=your_key MODEL= # leave blank to use the default for the provider SYSTEM_PROMPT=You are a helpful assistant.You only need the API key for the provider(s) you plan to use.
# activate the venv first if not already active
source venv/bin/activate
python main.py # CLI mode (default)
python main.py --mode web # web UI in your browser (Streamlit)Type your message and press Enter. Use Ctrl+C or Ctrl+D to quit.
Switch models at runtime:
/model # show current provider and model
/model openai/gpt-4o # switch to OpenAI GPT-4o
/model anthropic/claude-opus-4-7 # switch to Anthropic Claude
/model gemini/gemini-2.5-flash # switch back to Gemini
Switching starts a fresh conversation (history is cleared).
python main.py --mode web launches a Streamlit app in your browser. The sidebar lets you pick a provider, set the model, edit the system prompt, apply changes, or clear the conversation. Responses stream as they are generated.
Attach .pdf, .txt, or .md files from the sidebar to ask questions about them. Documents are chunked and embedded in memory using Gemini's gemini-embedding-001; on each message, the top excerpts most relevant to your question are retrieved and sent along with it.
- Requires
GEMINI_API_KEYin.envfor embeddings, regardless of which chat provider you're using. - Uncheck "Use uploaded documents in answers" to skip retrieval without removing the indexed files.
- Click ✕ next to a filename to remove it from the index.
- Indexed documents do not persist across app restarts.
- Removing a file or unchecking the box after the model has already answered with documents will clear the conversation, so the model can't continue referencing them from earlier turns. A toast notifies you when this happens.
python -m pytest # run all tests
python -m pytest tests/test_foo.py::test_bar # run a single testmain.py # entry point; --mode cli|web dispatch
app.py # Streamlit web UI
chat.py # ChatSession: thin wrapper over provider
config.py # shared constants (providers, defaults, RAG knobs)
rag.py # file extraction, chunking, embeddings, retrieval
providers/
base.py # BaseProvider ABC (send + send_stream)
gemini.py # GeminiProvider
openai.py # OpenAIProvider
anthropic.py # AnthropicProvider
__init__.py # create_provider() factory
tests/
test_chat.py
test_main.py
test_rag.py
test_providers_*.py