# ============================================================ # Hold Slayer Gateway Configuration # ============================================================ # Copy to .env and fill in your values. This is the app's own .env for a bare # `uvicorn main:app` run — see .env.compose.example for the Docker stack. # --- Database (required) --- DATABASE_URL=postgresql+asyncpg://holdslayer:@localhost:5432/holdslayer # --- Auth: Casdoor SSO + owner-minted PATs (owner-only) --- # The browser signs in via Casdoor (short-lived JWT); MCP/CLI clients use # owner-minted PATs (hs_pat_…). Both resolve to a User gated to OWNER_NAME. # # Two supported configurations, enforced at startup: # 1. CASDOOR_ENABLED=true + endpoint/client_id/client_secret/OWNER_NAME set # 2. CASDOOR_ENABLED=false + HOST=127.0.0.1 (dev-owner mode, loopback ONLY) # SSO-off with an off-loopback HOST is refused — it would resolve every request # to the dev owner, open to the network. CASDOOR_ENABLED=true CASDOOR_ENDPOINT=https://id.example.com CASDOOR_CLIENT_ID= CASDOOR_CLIENT_SECRET= CASDOOR_ORG_NAME= CASDOOR_APP_NAME=hold-slayer # The owner's Casdoor username — the only identity allowed on any surface. OWNER_NAME= # Public base URL the browser reaches (drives OAuth discovery + the Casdoor # redirect_uri). Blank derives it from the request headers. PUBLIC_BASE_URL= # --- SIP Trunk --- # The mock engine must be requested explicitly; an unconfigured trunk # without USE_MOCK_SIP=true refuses to start. USE_MOCK_SIP=false SIP_TRUNK_HOST=sip.yourprovider.com SIP_TRUNK_PORT=5060 SIP_TRUNK_USERNAME=your_sip_username SIP_TRUNK_PASSWORD=your_sip_password SIP_TRUNK_TRANSPORT=udp # Your phone number on the trunk (E.164) SIP_TRUNK_DID=+15551234567 # --- Gateway SIP Listener --- # Port for devices (softphones/hardphones) to register to GATEWAY_SIP_HOST=0.0.0.0 GATEWAY_SIP_PORT=5060 GATEWAY_SIP_DOMAIN=gateway.local # --- Speaches STT --- SPEACHES_URL=http://localhost:22070 SPEACHES_MODEL=whisper-large-v3 # --- Rhema TTS (OpenAI-compatible /v1/audio/speech) --- # Must NOT point at this app's own port (default PORT=8000) — set a real # endpoint or TTS requests loop back into the gateway. TTS_BASE_URL=http://localhost:8001 TTS_MODEL=speaches-ai/Kokoro-82M-v1.0-ONNX TTS_VOICE=af_heart TTS_API_KEY= TTS_TIMEOUT=30.0 TTS_SAMPLE_RATE=16000 # --- Audio Classifier --- # Thresholds for hold music detection (0.0 - 1.0) CLASSIFIER_MUSIC_THRESHOLD=0.7 CLASSIFIER_SPEECH_THRESHOLD=0.6 CLASSIFIER_SILENCE_THRESHOLD=0.85 # Analysis window in seconds CLASSIFIER_WINDOW_SECONDS=3.0 # --- LLM (OpenAI-compatible API) --- # Ollama, LM Studio, vLLM, or OpenAI — any OpenAI-compatible endpoint LLM_BASE_URL=http://localhost:11434/v1 LLM_MODEL=llama3 LLM_API_KEY=not-needed LLM_TIMEOUT=30.0 LLM_MAX_TOKENS=1024 LLM_TEMPERATURE=0.3 # --- AI Receptionist (inbound calls) --- RECEPTIONIST_ENABLED=true RECEPTIONIST_LISTEN_TIMEOUT_S=15.0 RECEPTIONIST_END_OF_UTTERANCE_SILENCE_S=1.2 RECEPTIONIST_MESSAGE_MAX_SECONDS=90 # --- Hold Slayer --- # Default device to transfer to when human detected DEFAULT_TRANSFER_DEVICE=sip_phone # Max hold time before giving up (seconds) MAX_HOLD_TIME=7200 # How often to check classification while on hold (seconds) HOLD_CHECK_INTERVAL=2.0 # --- Notifications --- # SMS notification number (optional) NOTIFY_SMS_NUMBER=+15559876543 # --- Server --- HOST=0.0.0.0 PORT=8000 DEBUG=false LOG_LEVEL=info # Log rendering: "text" (human-readable) or "json" (one object per line, for # Loki/Alloy). The Docker image sets json; text is the default for local dev. LOG_FORMAT=text # --- Safety --- # Max simultaneous calls the gateway will place (REST + MCP) MAX_CONCURRENT_CALLS=4