A self-hosted, containerized NVR (Network Video Recorder) that performs real-time Speech-to-Text on RTSP streams.
| Component | Technology |
|---|---|
| Frontend | Svelte 5 + TailwindCSS v4 (Vite) |
| Backend | Python 3.11 + FastAPI + SQLModel |
| Database | SQLite |
| AI Engine | WhisperLive (external WebSocket) |
| Container | Docker + Docker Compose |
# Clone the repository
git clone https://github.com/yourusername/TheWallflower.git
cd TheWallflower
# Copy and customize environment (optional)
cp .env.example .env
# Start the services
docker compose up -d
# View logs
docker compose logs -f
The web UI will be available at http://localhost:8080
For GPU-accelerated Whisper inference, uncomment the GPU section in docker-compose.yml:
whisper-live:
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities: [gpu]
Backend:
cd backend
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
uvicorn app.main:app --reload --port 8000
Frontend:
cd frontend
npm install
npm run dev
┌─────────────────────────────────────────────────────────────────┐
│ TheWallflower │
├─────────────────────────────────────────────────────────────────┤
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Frontend │ │ Backend │ │ WhisperLive │ │
│ │ (Svelte 5) │◄──►│ (FastAPI) │◄──►│ (GPU/CPU) │ │
│ └──────────────┘ └──────┬───────┘ └──────────────┘ │
│ │ │
│ ┌──────▼───────┐ │
│ │ SQLite │ │
│ │ (streams.db)│ │
│ └──────────────┘ │
├─────────────────────────────────────────────────────────────────┤
│ RTSP Cameras │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Camera1 │ │ Camera2 │ │ Camera3 │ ... │
│ └─────────┘ └─────────┘ └─────────┘ │
└─────────────────────────────────────────────────────────────────┘
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/streams |
List all stream configurations |
| POST | /api/streams |
Create a new stream |
| GET | /api/streams/{id} |
Get a specific stream |
| PATCH | /api/streams/{id} |
Update a stream |
| DELETE | /api/streams/{id} |
Delete a stream |
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/streams/{id}/start |
Start a stream worker |
| POST | /api/streams/{id}/stop |
Stop a stream worker |
| POST | /api/streams/{id}/restart |
Restart a stream worker |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/streams/{id}/status |
Get status of a specific stream |
| GET | /api/status |
Get status of all streams |
| GET | /api/streams/{id}/transcripts |
Get recent transcripts |
| GET | /api/health |
Health check |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/video/{id} |
MJPEG video stream |
| GET | /api/snapshot/{id} |
Single JPEG snapshot |
| Variable | Default | Description |
|---|---|---|
PORT |
8080 |
External port for web UI |
LOG_LEVEL |
INFO |
Logging level (DEBUG, INFO, WARNING, ERROR) |
WORKERS |
1 |
Number of uvicorn workers |
WHISPER_MODEL |
base.en |
Whisper model to use |
DATABASE_URL |
sqlite:///data/thewallflower.db |
Database connection string |
JPEG_QUALITY |
80 |
MJPEG stream quality (1-100) |
See .env.example for all available options.
Streams are configured via the web UI. Each stream has:
| Field | Type | Description |
|---|---|---|
| name | string | Display name for the stream |
| rtsp_url | string | RTSP URL of the camera |
| whisper_enabled | boolean | Enable speech-to-text |
| face_detection_enabled | boolean | Enable face detection (future) |
TheWallflower/
├── backend/
│ ├── app/
│ │ ├── __init__.py
│ │ ├── main.py # FastAPI application
│ │ ├── config.py # Environment configuration
│ │ ├── db.py # Database setup
│ │ ├── models.py # SQLModel schemas
│ │ ├── processors.py # Frame processors (MJPEG, snapshots)
│ │ ├── stream_manager.py # Worker lifecycle management
│ │ └── worker.py # Stream worker (video/audio)
│ └── requirements.txt
├── frontend/
│ ├── src/
│ │ ├── App.svelte # Main dashboard
│ │ └── lib/
│ │ ├── components/ # StreamCard, SettingsModal
│ │ └── services/ # API client
│ └── package.json
├── docker-compose.yml
├── Dockerfile
├── docker-entrypoint.sh
└── .env.example
MIT License - see LICENSE for details.
Contributions are welcome! Please read CONTRIBUTING.md for guidelines.