Whisper in the ear. An anonymous AI-driven confession booth for internal teams.
Speak your truth in a candlelit 3D booth. AI listens, processes, and lets you forward anonymously or delete. Your voice is masked. Your identity never stored.
- Immersive 3D Booth β Interactive candlelit confessional built with React Three Fiber
- AI STT/TTS Agent β Whisper transcription + Edge-TTS voice response
- Voice Modulation β 5 voice masks (Warm, Robotic, Ethereal, Deep, Random) via SoX + RVC
- Anonymity Modes β Fully blind or "someone in your team" context β your choice at send-time
- Telegram Delivery β Confessions delivered via anonymous Telegram bot DM
- Moderation β AI-flagged content queued to designated moderator for review
- Forward or Delete β Send to department/person or extinguish forever
- 3 Environments β Classic booth, forest glade, rooftop at night
| Layer | Stack |
|---|---|
| Mobile | React Native + Expo |
| 3D UI | React Three Fiber + drei + Three.js |
| Backend | FastAPI + WebSocket |
| STT | OpenAI Whisper / faster-whisper |
| TTS | Edge-TTS |
| Voice Mod | SoX pitch/formant + RVC AI voice conversion |
| AI Agent | GPT-4o / Claude |
| DB | PostgreSQL + pgcrypto |
| Delivery | Telegram Bot (python-telegram-bot) |
[Enter Auri] β Pick Voice Mask β AI greets you
β
[Speak] β Voice modulated in real-time β STT transcribes
β
[AI processes] β Strips PII, categorizes, summarizes
β
[Review] β Transcription | AI Summary | Voice-masked Audio
β
[Choose] β Fully blind / "Someone in your team"
β
[Act] β Send anonymously | Forward to person | Delete
| Phase | Days | What |
|---|---|---|
| 1 | 2 | 3D Booth scene (candle, particles, rings, door) |
| 2 | 2.5 | Recording + Voice Modulation + STT |
| 3 | 2 | LLM Agent + TTS |
| 4 | 2.5 | Telegram Bot + Forward/Delete + Moderation |
| 5 | 1 | Environment variants + Haptics + Sound |
- No user accounts β anonymous device tokens only
- Audio deleted from server after transcription
- All PII stripped by LLM before storage
- Original voice never stored β only the masked version
- Encrypted at rest with pgcrypto
- Blind relay β recipient never knows who sent it
auri/
βββ backend/ FastAPI app (API, DB models, services, LiveKit agent worker)
β βββ app/
β β βββ api/v1/ REST endpoints (confessions, moderation, delivery, admin, ...)
β β βββ services/ LLM, STT, TTS, voice-mod, live settings, retention
β β βββ models/ SQLAlchemy models
β β βββ agent.py LiveKit Agents worker entrypoint (Phase 7/10.7)
β βββ alembic/ DB migrations
β βββ tests/
βββ bot/ Telegram delivery/moderation bot (python-telegram-bot)
βββ mobile/ Expo / React Native app (the confession booth UI)
βββ dashboard/ Admin/config dashboard β Vite + React + shadcn/ui (local dev only)
βββ docker-compose.yml Full local stack: db, nats, api, bot, livekit, agent, ollama
βββ Dockerfile.api / Dockerfile.agent / bot/Dockerfile
βββ Makefile Shortcuts for everything below
- Docker + Docker Compose (for Postgres, NATS, and the optional LiveKit/agent/Ollama services)
- Python 3.11+ and a virtualenv tool (the repo's own
.venvworks βpython3 -m venv .venv) - Node.js 18+ and npm
- Expo CLI (
npx expo) for the mobile app; Android Studio/SDK if you want to build/run on Android - (Optional) ngrok β needed if a real phone or an Android emulator (which cannot reach your machine's LAN IP directly) needs to reach your local backend
git clone git@github.com:tonmoy007/auri.git
cd auri
cp .env.example .envEdit .env and fill in real values β see Configuration below for what each block does. At minimum for local dev you can leave the LLM/Telegram keys as placeholders; the app degrades gracefully (LLM chain tries Ollama β Gemini β OpenAI, first configured one wins).
docker compose up -d db nats api botThis builds and starts Postgres, NATS, the FastAPI backend (http://localhost:8000), and the Telegram bot. First boot in ENVIRONMENT=development auto-creates DB tables; for anything past a quick trial, run migrations explicitly:
make db-migrate # or: cd backend && alembic upgrade headOptional services live behind Docker Compose's optional profile β nothing you don't ask for:
# Self-hosted LiveKit SFU (Phase 7) + the LiveKit Agents worker (task 10.7)
docker compose --profile optional up -d livekit agent
# Local LLM via Ollama, instead of a cloud provider
docker compose --profile optional up -d ollamaCheck everything is up: curl http://localhost:8000/health β {"status":"ok"}.
python3 -m venv .venv && source .venv/bin/activate
make install-backend
make db-migrate
make dev-backend # uvicorn --reload on :8000Point DB_HOST/DATABASE_URL at localhost (not db) when running this way β .env's defaults assume the Docker network's service name.
Requires the livekit service (self-hosted SFU) to be up first:
docker compose --profile optional up -d livekit
make dev-agent # python -m app.agent devThis is connectivity wiring only today β it authenticates against LiveKit and joins a room; the real STT/LLM/TTS conversation lands in a later task (7.3+).
make install-mobile # cd mobile && npm install
cd mobile && npx expo startPress a for Android or i for iOS. The app's build-time backend URL comes from EXPO_PUBLIC_API_URL/EXPO_PUBLIC_WS_URL (see mobile/src/config/api.ts) β but you don't need to rebuild to change it: Settings β Developer β Backend URL lets you override it live on an already-installed app (persisted via expo-secure-store, survives app restarts). This is how you point a running app at an ngrok tunnel instead of your LAN IP β useful since Android emulators can't reach your machine's real LAN IP by default (physical devices on the same Wi-Fi can, though).
cd dashboard && npm install && npm run devOpens on http://localhost:5173. Enter your backend URL and ADMIN_API_KEY (from .env) in the connection bar. From there you can:
- Config β live-edit LLM provider/model, STT model, voice-mask effect chains; changes take effect immediately, no backend restart
- Status β ngrok tunnel + self-hosted LiveKit reachability
- Build β trigger
gradlew assembleReleasefor the mobile app with a chosen backend URL baked in, and download the resulting APK
make lint # ruff + mypy (backend/bot) + eslint + tsc (mobile)
make lint-fix # auto-fix what ruff can
make test # pytest backend/ bot/ with coverage
make docker-logs # tail every running container
make clean # nuke caches, venvs, node_modules, build outputEvery commit is expected to pass lint + its own tests β see AGENTS.md for the full workflow/commit discipline this repo follows.
All configuration is environment-variable driven β .env.example (repo root) is the canonical reference, fully commented block-by-block (database, security, Telegram, admin dashboard, LLM provider chain, LiveKit, STT/TTS, observability, CORS/rate-limiting). Copy it to .env and never commit real secrets β .env is gitignored, .env.example must only ever contain placeholders.
A few settings worth knowing about specifically:
LLMService(provider="auto")tries Ollama (local/free) β Gemini β OpenAI, first non-empty reply wins. Claude is available but only via explicitprovider="claude", never part of the auto chain.- LiveKit defaults (
LIVEKIT_URL/LIVEKIT_API_KEY/LIVEKIT_API_SECRET) match the self-hostedlivekitDocker service's--devmode (devkey/secret) β no cloud account needed for local dev. - DB-backed live config β LLM provider/model,
WHISPER_MODEL, and voice-mask effect chains can be overridden at runtime via the admin dashboard/API without restarting the backend (DB-first,.env/Settings()as fallback). ADMIN_API_KEYgates every/api/v1/admin/*route (X-Admin-Api-Keyheader) β generate a real random value, don't ship the placeholder.
"Auri" β from Latin auricula (ear), auricular confession (whispered in the ear).