# Voice — Real-time Voice Assistant A single-container voice assistant built on LiveKit Agents. Speaks and listens in real time using Azure Speech (STT + TTS) with models hosted by OpenWebUI (xNAS) for reasoning. ## Architecture One Docker container runs four processes via supervisord: 1. **LiveKit server** — open-source WebRTC media transport (port 7880 TCP, 7882 UDP muxed media) 2. **Voice agent** — Python LiveKit Agents pipeline: Azure STT → LLM (OpenWebUI) → Azure TTS 3. **Web frontend** — static HTML served by nginx (port 9178 by default) 4. **Media server** — FastAPI music library/player coordinator (port 8093 internal, proxied at /media/api/) ``` Browser ──WebRTC──► LiveKit Server ──audio──► Agent ▲ │ └────────── audio ◄────────────────────────────┘ Azure STT → LLM (OpenWebUI) → Azure TTS Browser ──HTTP──► nginx /media/api/ ──► Media server ──► yt-dlp/ffmpeg ──► ./media └────── audio element ◄── /media/files/ (nginx static, Range) ──────────┘ ``` ## Quick Start ```bash # 1. Set your Azure Speech key (already in ~/.hermes/.env as AZURE_SPEECH) export AZURE_SPEECH_KEY=$(grep '^AZURE_SPEECH=' ~/.hermes/.env | cut -d= -f2) # 2. Build and start docker compose up --build -d # 3. Open the web UI (self-signed cert: accept the browser warning once) # https://:9178 ``` LAN access requires firewall rules: `9178/tcp` (UI + signaling), `7882/udp` (WebRTC media), `7881/tcp` (media TCP fallback). ## Ports | Port | Protocol | Service | Access | |-------|----------|----------------------|--------------| | 7880 | TCP | LiveKit HTTP/WS | internal only (proxied via nginx at /livekit/) | | 7881 | TCP | LiveKit RTC media (TCP fallback) | LAN | | 7882 | UDP | LiveKit RTC media (muxed) | LAN | | 8093 | TCP | Media server (library, player state, stream proxy) | internal only (proxied via nginx at /media/api/) | | 9178 | TCP | Web frontend (HTTPS) | LAN | ## Configuration All config lives in `.env` (git-ignored). See `.env.example` for the full list. Key variables: - `AZURE_SPEECH_KEY` — Azure Speech resource key - `AZURE_SPEECH_REGION` — default `eastus` - `AZURE_TTS_VOICE` — default voice (`en-US-Ava:DragonHDOmniLatestNeural`) - `LLM_BASE_URL` — OpenAI-compatible endpoint (default `http://192.168.86.2:3005/api`, OpenWebUI) - `LLM_MODEL` — default model (default `qwen2.5-vl-3b`; switchable live from the web UI) - `LLM_API_KEY` — OpenWebUI API key (bears `sk-…`) - `YTDLP_COOKIES` — optional path to a cookies.txt inside the container (e.g. `/data/media/cookies.txt`) for reliable YouTube downloads ## Media Player Hope can play music on the web UI's media player: YouTube Music search → yt-dlp download → ffmpeg transcode to mp3 → nginx static streaming (HTTP Range) back to the browser's `