Chatnificent
Minimally complete
Maximally hackable
Python · AI / LLM Chat App Framework
Streaming UI, multi-user sessions, persistent history, and tool calling — out of the box. Swap any pillar (LLM, storage, auth, UI) when the defaults aren’t enough.
Minimally complete
import chatnificent as chat
app = chat.Chatnificent()
app.run()
You only need to pip install openai and set
OPENAI_API_KEY to immediately start
talking to GPT.
Maximally hackable
import chatnificent as chat
app = chat.Chatnificent(
# OpenAI, Gemini, Ollama, OpenRouter, ...
llm=chat.llm.Anthropic(
model="claude-opus-4",
system="You are a witty pirate.",
),
# or File, InMemory, your own
store=chat.store.SQLite("chats.db"),
# or Anonymous, or your own
auth=chat.auth.SingleUser("elias"),
# plain Python functions become tools
tools=chat.tools.PythonTool([get_weather, search_web]),
layout=chat.layout.Default(
brand="Acme",
welcome_message="Ahoy, matey!",
# bind UI widgets to LLM kwargs
controls=[
chat.layout.Control(
id="temp",
llm_param="temperature",
cast=float, ...,
),
chat.layout.Control(
id="voice",
llm_param="voice", ...,
),
],
),
)
if __name__ == "__main__":
app.run()
Every pillar is a constructor argument — swap providers, persistence, auth, tools, or UI without writing a line of plumbing. Subclass any of them when config isn’t enough.
Examples
33 live apps
Every example is a single Python file you can run with uv run --script <file>.py —
dependencies are declared inline, no project setup, no install steps. Each one runs standalone, and
this site mounts the same unmodified scripts under /chat/<example>/ on one
Starlette app.
Start here
Tools & agents
Tool calling
Register a plain Python function as a tool — schemas are inferred from type hints and the docstring. Zero boilerplate.
Multi-tool agent
Several tools, one agent loop — the model picks which ones to call across multiple turns to finish a task end-to-end.
OpenAI Cookbook port
The classic "How to call functions with chat models" recipe, ported to Chatnificent — the agent loop, streaming, and persistence come for free.
QR code tool
A tool that returns a real file: the model calls it, the framework persists the PNG and renders the QR code inline.
Images
OpenAI image — simple
Every prompt becomes a PNG via OpenAI's images.generate endpoint, persisted and rendered inline in the same bubble.
OpenAI image variations
Generate several variations of a prompt in one turn and compare them side-by-side with a tabbed, CSS-only UI.
OpenAI image studio
Multi-turn image editing on the Responses API — keep refining the same image with follow-up messages and watch each edit stream in.
Gemini image — simple
The same artifact recipe wired to Google's Gemini image model — same four overrides, different provider.
Gemini image — advanced
A live "studio" panel above the composer — pick model, aspect ratio, resolution, and thinking level — each control feeds straight into the API call.
Gemini text + illustration
Write a short story with one model, then illustrate it with another — two independent calls stitched into a single assistant message.
Audio & video
OpenAI TTS — simple
Every user message becomes a spoken clip via OpenAI's audio.speech endpoint, embedded as a native <audio> player.
OpenAI TTS — advanced
Stream a normal chat reply, then append an audio player that reads it aloud — text and speech land in the same bubble, single turn.
Gemini TTS — simple
Chat, then listen — Gemini answers in text, then a second call narrates it. Voice is reshuffled each turn from the 30-voice roster.
Gemini TTS — advanced
A Gemini-only superpower: render a two-speaker dialog into one stitched WAV with named speakers and distinct voices, in a single API call.
Gemini music — simple
Generate a 30-second MP3 from a text prompt using Gemini's Lyria 3 model — lyrics + audio returned together.
Gemini music — advanced
Same Lyria 3 recipe, plus: paste an image URL in your prompt and it's fetched and passed alongside the text as inspiration.
Gemini video — simple
Generate a 4-second clip via Veo 3.1 Fast — the async long-running operation is polled inside the LLM pillar, so the chat UI doesn't notice.
Search
Web search
Gemini with Google Search grounding — the raw response is saved as-is, then parsed into search-result cards at render time.
Interactive search
Three knobs — reasoning effort, domain restriction, search type — wired straight into the OpenAI Responses API as live UI controls.
Website search
Restrict OpenAI's hosted web search to a single site (default: Wikipedia) — point it at your docs or a news source to build a domain-scoped assistant.
Files & artifacts
File serving — simple
The canonical Artifact recipe with no provider SDK — the four overrides every file-producing example builds on.
File serving — advanced
Multiple file types — SVG, WAV, text — interleaved with prose in a single assistant turn; the engine picks the right embed per MIME type.
Export to PDF — simple
After every reply, render the full conversation as a PDF and append a download link to the same streamed message — no second turn.
Export to PDF — advanced
On-demand export with structured outputs (Pydantic) — a typed cover page + full transcript, triggered by an "Export PDF" button.
Conversation state
Auto title
Replace the default "first 30 chars" sidebar title with a model-generated one, written right after the first exchange.
Conversation summary
Append a fresh summary to a sidecar file after each turn and surface it in a collapsible block above the composer.
Per-user memory
Anthropic's native memory tool, scoped per user — a ContextVar + tiny Auth subclass keeps each visitor's memory private and thread-safe.
Multi-chat mode
One app, four conversation modes — pick a pill before your first message and that conversation is locked to that mode forever.
UI & display
UI interactions
Bind dropdowns, sliders, and toggles to LLM call kwargs — values are stored per-user and injected silently into the next request.
Usage display
Surface token counts and cost per turn by reading the raw API response at render time — the canonical history stays clean.
Display redaction
Mask emails, phone numbers, and card numbers in the visible transcript while keeping the stored conversation fully intact.