Coverage-Hotspots (providers 100 %, chat-Pfade), Key-Sanitize in Commands/CLI, Test-Buffer (-b), mypy-Overrides, CONTRIBUTING/SECURITY, .env.example und gitignore-Verfeinerung. CI-Safety prüft lokale .env nur wenn getrackt.
🤖 chatpy
Interaktiver CLI-Chat für OpenRouter, Groq, NVIDIA NIM und lokale OpenAI-kompatible Server (Ollama, LM Studio, vLLM) – OpenAI-kompatibel.
Version: 2.1.0 · Changelog
Dokumentation
| Dokument | Inhalt |
|---|---|
| docs/ | Index & Lesepfade |
| Getting Started | Tutorial (~10–15 Min): Setup → erster Chat |
| Changelog | Versionshistorie |
| User-Guide | Setup, CLI, Slash-Commands, Workflows |
| Architektur | Module, Flows, Free-Tier-Schutz |
| Konfiguration | ENV, .runtime/, Settings |
| Entwicklung | Tests, Coverage, Konventionen |
| CONTRIBUTING | Mitwirken, PR-Checkliste |
| SECURITY | Keys, Sanitize, Meldungen |
Schnellstart
Ausführliches Tutorial: docs/getting-started.md.
# 1. .env mit mindestens einem API-Key (oder Local-URL) anlegen
echo 'OPENROUTER_API_KEY=sk-or-...' > .env
echo 'GROQ_API_KEY=gsk_...' >> .env
echo 'NVIDIA_API_KEY=nvapi-...' >> .env
# optional lokal: OPENAI_COMPAT_BASE_URL=http://127.0.0.1:11434/v1
# 2. Umgebung (empfohlen: mise – siehe mise.toml)
mise trust # einmalig, falls Trust-Prompt
mise install # Python 3.12
mise run install # pip install -e . → .venv
# 3. Starten
mise run chat
# oder: python -m chatpy
# oder: .venv/bin/python chat.py (Root-Launcher)
Ohne mise:
python3 -m venv .venv
.venv/bin/pip install -e .
python -m chatpy
CLI-Argumente
Nicht-interaktive Nutzung – alle interaktiven Prompts werden übersprungen:
# Einfache Frage
python -m chatpy --provider groq --no-stream "Was ist Python?"
# Pipe-Eingabe
echo "Erkläre Quantencomputing" | python -m chatpy --provider nvidia
# Code-Modus mit Temperatur
python -m chatpy --code --temp 0.3 --language de "Schreibe Hello World in Rust"
| Argument | Beschreibung |
|---|---|
--provider {openrouter,groq,nvidia,local} |
Provider ohne Auswahl-Menü setzen |
--model MODEL |
Modell per ID oder Name (z. B. llama-3.1-8b-instant) |
--temperature FLOAT, --temp FLOAT |
Temperatur (wird auf 0.0–2.0 begrenzt) |
--stream / --no-stream |
Streaming an/aus |
--language {de,en}, --lang {de,en} |
Sprache für System-Prompts |
--code |
Code-Modus aktivieren |
--reasoning |
Gedankengänge des Modells sichtbar machen |
--system-prompt TEXT |
Benutzerdefinierter System-Prompt |
--system-prompt-file PATH |
System-Prompt aus Datei |
--session NAME |
Session beim Start laden |
--file / -f PATH|URL |
Datei oder URL als Kontext (mehrfach) |
--json |
Antwort als JSON |
--quiet / -q |
Weniger Banner |
--list-models |
Modelle anzeigen und beenden |
--help |
Hilfe anzeigen |
--version |
Version anzeigen |
MESSAGE |
Einmalige Nachricht (nicht-interaktiv, als letztes Argument) |
Exit-Codes (Pipe/Einmal): 0 OK, 1 Key/Config, 2 API-Fehler.
Interaktive Befehle
Im interaktiven Chat (ohne einmalige Message bzw. Pipe) stehen folgende Befehle zur
Verfügung (--provider/--model überspringen nur die Auswahlmenüs):
| Befehl | Beschreibung |
|---|---|
/provider |
Provider wechseln |
/model |
Modell wechseln |
/temp 0.7 |
Temperatur setzen (0.0–2.0) |
/language de|en |
Sprache umschalten |
/stream on|off |
Streaming ein/aus |
/reasoning on|off |
Gedankengänge anzeigen/verbergen |
/code on|off |
Code-Modus ein/aus |
/system [prompt] |
System-Prompt setzen (ohne Argument = Default) |
/prompt save <name> |
Aktuellen Prompt als Template speichern |
/prompt load <name> |
Template laden und aktivieren |
/prompt list |
Alle gespeicherten Templates anzeigen |
/prompt delete <name> |
Template löschen |
/context [n] |
Kontext anzeigen; optional Fenster (1–50) setzen |
/context tokens N |
Token-Budget Kontext (0 = aus) |
/maxtokens N |
max_tokens pro Request |
/model [suche] |
Modell + optionaler Filter |
/retry |
Letzte User-Nachricht erneut senden |
/undo |
Letzten Austausch entfernen |
/last |
Letzte Assistant-Antwort anzeigen |
/sessions |
Gespeicherte Sessions listen |
/session show|delete <name> |
Session-Metadaten / löschen |
/theme dark|light|none |
Terminal-Theme |
/clear |
Terminal leeren |
/reset |
Chat-Verlauf löschen |
/export [name] |
Als Markdown exportieren |
/export json [name] |
Als JSON exportieren |
/file <pfad> / /web <url> |
Anhang für nächste Nachricht |
/attach / /attach clear |
Anhang-Buffer listen / leeren |
/save [name] |
Session speichern (ohne Name → Zeitstempel) |
/load [name] |
Session laden (Nachrichten + Settings) |
/stats |
Statistiken anzeigen |
/gen |
API-Modell & Generation-ID der letzten Antwort |
/reload |
Modell-Listen neu laden |
/help |
Hilfe anzeigen |
/exit, /quit |
Beenden |
Mehrzeilig: mit """ … """. Optional: readline-History (Pfeil-hoch) und Tab-Complete für Slash-Commands.
Inline-Datei: @./pfad.py · CLI: -f PATH|URL (mehrfach).
Provider
| Provider | Modell-Liste | Limit (Free-Tier) |
|---|---|---|
| OpenRouter | Dynamisch (nur :free-Modelle, Preis 0) |
20 RPM / 50–1000 RPD |
| Groq | Dynamisch | 30 RPM / ~14k RPD |
| NVIDIA NIM | Dynamisch | 1000 Requests/Tag |
OpenRouter – garantiert kostenlos
OpenRouter kann Modellpreise ändern oder auf andere Endpoints ausweichen. Deshalb:
- Kein Cache: Free-Modell-Liste wird bei jedem Start frisch von der API geladen (Preisänderungen rutschen nie durch).
openrouter/free-Router deaktiviert: Es werden ausschließlich explizite:free-Modelle verwendet.max_price: 0: Jeder OpenRouter-Request sendetprovider.max_pricemit0($/Mio Tokens). OpenRouter lehnt den Request ab, sobald kein 0-Preis-Endpoint verfügbar ist – eine Abrechnung ist damit technisch unmöglich (Default:OPENROUTER_MAX_PRICE=0).- Kosten-Guard: Nicht-
:free-Modelle werden inchat()blockiert, bevor ein API-Call passiert. - Kosten-Audit:
usage.costaus jeder Antwort wird protokolliert; Abweichungen > 0 lösen eine Warnung aus und tauchen in/statsundchat_history.jsonauf.
Empfehlung gegen unerklärte Restbeträge (z. B. Fallback/Testing anderer Tools): API-Key rotieren und unter https://openrouter.ai/settings/credits eine Spend Control / Kreditlimit setzen.
Konfiguration
.env
OPENROUTER_API_KEY=sk-or-...
GROQ_API_KEY=gsk_...
NVIDIA_API_KEY=nvapi-...
MAX_TOKENS=2048
DEFAULT_TEMPERATURE=0.7
DEFAULT_STREAM=true
DEFAULT_LANGUAGE=de
DEFAULT_PROVIDER=openrouter
Theme
Das Theme wird in chat_settings.json gesetzt. Verfügbare Werte:
dark– Dunkles Terminal-Theme (Standard)light– Helles Terminal-Themenone– Keine Farben (für einfache Terminals)
{
"theme": "dark",
"temperature": 0.7,
"...": "..."
}
Prompt-Templates
Templates sind benannte, persistente System-Prompts. Sie werden in chat_settings.json gespeichert.
# Aktuellen Prompt speichern
/system Du bist ein Python-Experte. Antworte mit Code.
/prompt save python-dev
# Später laden
/prompt load python-dev
# Alle Templates anzeigen
/prompt list
# Löschen
/prompt delete python-dev
Templates und /system-Prompts nutzen dieselbe Variable – ein mit /prompt load geladener Prompt überschreibt den aktuellen /system-Prompt und umgekehrt.
Dateien
| Pfad | Zweck |
|---|---|
chatpy/ |
Installierbares Package (Module, Fallback-JSON) |
chat.py |
Dünner Root-Launcher |
pyproject.toml |
Package + Console-Script chatpy |
mise.toml |
mise: Python 3.12, .venv, Tasks |
.runtime/ |
Laufzeit-JSONs (Settings, History, Caches; gitignored) |
tests/ |
Unittest-Suite (~456 Tests; Live unter tests/live/) |
requirements.txt |
Runtime-Deps (Spiegel von pyproject.toml) |
Setup
# mise (empfohlen)
mise trust && mise install && mise run install
# ohne mise
python3 -m venv .venv
.venv/bin/pip install -e .
Laufzeitdaten landen unter .runtime/ (Override: CHATPY_DATA_DIR).
Tests
# Alle Tests
mise run test
# oder
make test
# Einzelne Test-Datei
.venv/bin/python -m unittest tests.test_client
# Mit Detail-Ausgabe
.venv/bin/python -m unittest discover -s tests -v
# Live-Tests (echte Keys, Free-Tier; unter tests/live/)
RUN_LIVE_TESTS=1 .venv/bin/python -m unittest discover -s tests/live -v
Coverage (Test-Metriken)
Zeilen- und Branch-Abdeckung pro Modul (chatpy/*). coverage.py ist eine
optionale Dev-Abhängigkeit (nicht in den Runtime-Deps).
# einmalig Dev-Tools installieren
mise run install-dev
# Terminal-Report (Stmts / Miss / Branch / Cover / Missing)
mise run test-cov
# oder
make test-cov
# zusätzlich HTML unter htmlcov/index.html
mise run test-cov-html