A lightweight, production-ready AI chatbot backend that serves as an interactive portfolio assistant. Built with FastAPI + WebSocket for real-time streaming responses, powered by LLM inference via OpenRouter.
┌──────────────────────────────────────────────────────────────────┐
│ Client (Browser) │
│ WebSocket: /ws/chat │
└────────────────────────────┬─────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────────┐
│ FastAPI Application │
│ │
│ ┌────────────┐ ┌──────────────┐ ┌──────────────────────────┐ │
│ │ WebSocket │──│ Orchestrator │──│ LLM Provider (OpenRouter) │ │
│ │ Handler │ │ (ReAct Loop) │ │ Streaming + Tool Calling │ │
│ └────────────┘ └──────┬───────┘ └──────────────────────────┘ │
│ │ │
│ ┌──────────┴──────────┐ │
│ │ │ │
│ ┌─────▼─────┐ ┌─────────▼──────────┐ │
│ │ Tools │ │ Session Service │ │
│ │ • Time │ │ (SQLite + WAL) │ │
│ │ • Meeting │ └────────────────────┘ │
│ │ • MCP │ │
│ └────────────┘ │
└──────────────────────────────────────────────────────────────────┘
Key design choices:
|split|), rare typos with corrections, and casual toneapp/
├── main.py # FastAPI entry point, lifespan, health check
├── config.py # Environment settings (Pydantic)
├── database.py # SQLite init (WAL mode, session + message tables)
├── session.py # Session hashing, creation, resume, message persistence
├── orchestrator.py # ReAct loop, LLM streaming, tool dispatch
├── llm.py # OpenRouter API streaming client
├── tools.py # Tool definitions + native/MCP execution
├── websocket.py # WebSocket endpoint + connection manager
└── prompts/
└── system.txt # System prompt with structured resume knowledge
tests/
├── test_tools.py # Tool execution unit tests
└── test_websocket.py # WebSocket protocol integration tests
Create a .env file:
OPENROUTER_API_KEY=sk-or-v1-your-key-here
COMPOSIO_API_KEY=ak_your-composio-key
| Variable | Required | Description |
|---|---|---|
OPENROUTER_API_KEY |
Yes | API key for OpenRouter LLM access |
COMPOSIO_API_KEY |
Yes | API key for Composio external tool execution |
# Install dependencies
uv sync
# Start the server
uv run uvicorn app.main:app --host 0.0.0.0 --port 8000
# Or with hot reload for development
uv run uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload
uv run pytest tests/ -v
docker compose up --build
ws://localhost:8000/ws/chat
CLIENT SERVER
│ │
│──── text: "Hello" ───────────▶│
│ │
│◀── json: {type: "status", ──│ ← typing indicator
│ action: "typing"} │
│ │
│◀── text: "Hey bro!" ────────│ ← streamed response chunks
│◀── text: "|split|" ─────────│ ← burst separator
│◀── text: "What's up?" ──────│
│ │
│◀── json: {type: "status", ──│ ← generation complete
│ action: "idle"} │
│◀── json: {type: ──│ ← turn complete signal
│ "turn_complete"} │
│ │
│ (60s idle) │
│◀── text: "You still there?" ─│ ← idle nudge
curl http://localhost:8000/health
# {"status": "healthy", "active_websockets": 0}
| Tool | Type | Description |
|---|---|---|
get_current_time |
Native | Returns current IST date/time |
schedule_meeting |
Native | Generates pre-filled Calendly link |
| External tools | MCP | Routed to Composio API with retry logic |
MIT