# ============================================================
# CARELY DEVICE CONFIGURATION
# ============================================================

# --- Device Identity ---
DEVICE_ID=carely-proto-001

# --- Pipeline Mode ---
# text = local STT → LocalAgent → local TTS  (v2 default)
# audio = send raw WAV to webhook → receive audio back → play directly (legacy n8n only)
PIPELINE_MODE=text

# --- Local Agent (n8n-free mode) ---
# KEYLESS build, IDENTICAL behavior to keyed: the local agent runs (prompt + tools +
# per-turn analysis) but with NO local key — its OpenAI calls route through the broker's
# chat-completions proxy (base_url). STT/TTS also go through the broker. The key lives
# only on Netlify, so downloaders run exactly like the keyed dev build.
LOCAL_AGENT_ENABLED=true
OPENAI_API_KEY=
# --- STT: direct Groq (bypasses Netlify) ---
# Paste the SAME Groq key that's already in your Netlify env vars here. When this is
# set, speech-to-text goes STRAIGHT to Groq (whisper-large-v3-turbo) instead of through
# the Netlify function — killing the cold-start hangs (1.4s one turn, 14s the next).
# Groq is always-on (no serverless spin-down), so STT stays a consistent ~1-2s.
# Same model + same ar/en/fr guard as the broker path — output is identical, just fast.
# Leave EMPTY to keep the keyless broker path (what the public download ships with).
GROQ_API_KEY=
# Google OAuth token file — created by running: python3 authorize_google.py
# The OAuth client config is stored at: ~/.config/carely/google_oauth_client.json
# GOOGLE_CREDENTIALS_FILE removed — broker mode
# SerpAPI key for web search tool
SERPAPI_API_KEY=
# Forgot-password emails are sent by n8n using its own Gmail OAuth2 credential.
# Python never sends email directly — the fields below are not used.
# GMAIL_ADDRESS=(unused)
# GMAIL_APP_PASSWORD=(unused)

# --- n8n Webhook URLs ---
# Local n8n (default). When switching to cloud, replace localhost URLs below with your cloud URLs.
# See N8N_CLOUD_MIGRATION.md for step-by-step instructions.
N8N_SIGNUP_WEBHOOK=http://localhost:5678/webhook/carely/signup
N8N_ANA2_WEBHOOK=http://localhost:5678/webhook/carely/ana2
N8N_FORGOT_PASSWORD_WEBHOOK=http://localhost:5678/webhook/carely/forgot-password

# --- Network / Webhook (legacy — unused when LOCAL_AGENT_ENABLED=true) ---
WEBHOOK_URL=
AUDIO_WEBHOOK_URL=
WEBHOOK_TIMEOUT_S=60
WEBHOOK_MAX_RETRIES=2
WEBHOOK_RETRY_BACKOFF_MS=500
# Optional auth token for n8n:
WEBHOOK_AUTH_TOKEN=

# --- Audio Devices ---
# PipeWire device names (use `pw-cli list-objects Node` to find)
AUDIO_INPUT_DEVICE=default
AUDIO_OUTPUT_DEVICE=default

# --- VAD ---
# Software mic gain: boosts quiet/distant speech BEFORE STT + the wake model so soft
# calls transcribe cleanly and trigger the wake word without the patient raising their
# voice. 1.0 = off. 3.0 lifts a soft ~0.024 RMS call into the clean ~0.07 band; raise
# toward 4-5 for a far/quiet mic, lower to 1.5-2 if a loud speaker ever distorts.
AUDIO_INPUT_GAIN=5.5
VAD_AGGRESSIVENESS=3
# How much audio to keep "warm" before speech onset, so the first word is never clipped
# (covers the gap between pressing the orb and capture starting). Now actually wired in.
VAD_PREROLL_MS=500
VAD_SPEECH_START_MS=150
# Grace period: how long the patient can PAUSE mid-sentence before we treat it as "done".
# Bumped 900 -> 1300ms so a short "…let me add one more thing" pause no longer cuts them
# off. Costs ~0.4s extra before each reply starts; worth it to stop clipping the patient.
VAD_SILENCE_END_MS=1800
VAD_MIN_SPEECH_MS=500
VAD_MAX_UTTERANCE_MS=12000

# --- STT (whisper.cpp) ---
WHISPER_MODEL_PATH=/opt/assistant/models/whisper/ggml-small.bin
WHISPER_BINARY_PATH=/opt/assistant/bin/whisper-cli
WHISPER_THREADS=4
WHISPER_LANGUAGE=auto
WHISPER_BEAM_SIZE=3

# --- TTS (Piper + edge-tts + espeak fallback) ---
PIPER_BINARY_PATH=/opt/assistant/bin/piper
PIPER_VOICE_EN=/opt/assistant/models/piper/en_US-lessac-medium.onnx
PIPER_VOICE_AR=/opt/assistant/models/piper/ar_JO-kareem-medium.onnx
PIPER_DEFAULT_VOICE=en
# --- Patient profile (LOCAL ONLY — never sent to Google Sheets / the cloud) ---
# Primary language the AI greets in (ar | en | fr). STT still auto-detects, so the patient
# can slip into another of the three languages mid-conversation.
CARELY_LANGUAGE=ar
# Arabic dialect for premium ElevenLabs voice: levantine | syrian | egyptian | saudi |
# jordanian | tunisian. Ignored on the free/basic tier (uses the standard voice).
CARELY_DIALECT=

ARABIC_TTS_BACKEND=auto
# Chunked Arabic playback: speak a long reply phrase-by-phrase so it STARTS fast instead
# of waiting for the whole clip to synthesise. 1 = on (default). If Arabic ever sounds
# choppy/mushy, set to 0 to revert to the one-shot Edge path.
TTS_CHUNK_AR=1
EDGE_TTS_BINARY_PATH=/opt/assistant/venv/bin/edge-tts
# ar-SA-ZariyahNeural = Saudi MSA female (clearest for general Arabic content)
# ar-SA-HamedNeural  = Saudi MSA male
# ar-EG-SalmaNeural  = Egyptian female (was default — sounded off on MSA)
EDGE_TTS_VOICE_AR=ar-SA-ZariyahNeural
EDGE_TTS_VOICE_FR=fr-FR-DeniseNeural
ESPEAK_VOICE_AR=ar
ESPEAK_VOICE_FR=fr
ESPEAK_BINARY_PATH=/opt/assistant/bin/espeak-ng

# --- Keyword Spotter ---
KEYWORD_SPOTTER_ENABLED=false
KEYWORD_SPOTTER_THRESHOLD=0.7

# --- Wake word ("Layla") — local, offline, zero-token ---
# Custom openWakeWord model trained on layla/laila/leila (8k samples). Path resolves relative to app root.
# The patient starts a conversation just by calling her name; nothing leaves the device until wake.
WAKE_WORD_ENABLED=true
WAKE_WORD_MODEL_PATH=models/layla.onnx
# Sensitivity (lower = more sensitive). On this mic normal-voice "Layla" scores ~0.03-0.10,
# so 0.035 catches a normal call without shouting, while general speech/noise scores ~0.001-
# 0.012 (still ~3x below), so false wakes stay unlikely. If it ever wakes on its own, raise
# back toward 0.05; if it still misses normal calls, the real fix is a retrain, not a lower
# number (below ~0.03 you start catching noise). Paired with AUDIO_INPUT_GAIN=5.5 above.
WAKE_WORD_THRESHOLD=0.035
# Diagnostics: log the peak wake score every ~2s (turn off once tuned)
WAKE_WORD_DEBUG=0
# The companion's name — used to wake her; the AI never says it aloud.
ASSISTANT_NAME=Layla

# --- Input ---
BUTTON_KEY=
EMERGENCY_KEY=f12
FORCE_STOP_KEY=enter
CANCEL_KEY=ctrl_l
LONG_PRESS_MS=1000

# --- UI ---
UI_HOST=0.0.0.0
UI_PORT=8080

# --- Logging ---
LOG_LEVEL=INFO
LOG_FILE=/var/log/carely/carely.log

# --- System ---
HEALTH_PORT=8081
WATCHDOG_INTERVAL_S=15
CRASH_LOOP_THRESHOLD=5
CRASH_LOOP_WINDOW_S=300

# --- IPC ---
IPC_SOCKET_PATH=/run/carely/audio.sock

# --- Button API ---
BUTTON_API_ENABLED=true
BUTTON_API_BEARER_TOKEN=1df6550581f8fb1a258899be5de982d08ea8ba5fa6138b6fe2a941bb279e9b8a

# ============================================================
# V2 ENGINE CONFIGURATION  (free, fully local — no API keys required)
# Uncomment the version lines below to activate V2 engines.
# ============================================================

# --- Engine version selection ---
STT_VERSION=2
# TTS_VERSION=2        # 2 = Meta MMS-TTS (activate after: pip install transformers torch)

# --- STT V2 — faster-whisper ---
# Model is downloaded once (~1.5 GB for large-v3) to FASTER_WHISPER_CACHE_DIR.
FASTER_WHISPER_MODEL=small
FASTER_WHISPER_DEVICE=cpu
FASTER_WHISPER_COMPUTE_TYPE=int8
FASTER_WHISPER_CACHE_DIR=/opt/assistant/models/faster_whisper
FASTER_WHISPER_LANGUAGE_THRESHOLD=0.7

# --- TTS V2 — Meta MMS-TTS ---
# Three small VITS models (~200 MB each) are downloaded on first use.
# Requires: pip install transformers torch   (torch ~2 GB, one-time)
# MMS_CACHE_DIR=/opt/assistant/models/mms_tts

# --- Broker (server-side Google access; no key on device) ---
# Fast path (stt/tts/chat/warm) runs on Cloudflare Workers — no cold-start, ~0.5s STT.
# Everything else it forwards to the Netlify function untouched. Rollback = swap this
# line back to the Netlify URL below.
#   Netlify (old): https://carelyai.netlify.app/.netlify/functions/sheets
CARELY_BROKER_URL=https://carely-broker.carely.workers.dev
# How often (seconds) to ping the broker so its Netlify server doesn't nap between
# turns. 60 = ping every minute (3x more often than before) to reduce cold-start hangs.
# The ping is skipped whenever a conversation is active, so it never slows a live turn.
CARELY_KEEPWARM_S=60

# Who Carely presents as: female | male. Drives first-person grammatical
# agreement in Arabic/French. Keep in step with the chosen avatar + voice.
ASSISTANT_GENDER=female
