"""Live Voice Commands — voice-to-arm phrase trigger dispatcher. Listens to LiveGeminiSubprocess user transcripts, matches against sanad_arm.txt phrases, and fires ARM.trigger_action_by_id. Endpoints: POST /start begin polling transcripts POST /stop stop polling POST /deferred-mode?enabled toggle instant vs deferred trigger GET /status running, last heard, last action, etc. GET /triggers arm trigger history (log) """ from __future__ import annotations from fastapi import APIRouter, HTTPException router = APIRouter() def _loop(): from Project.Sanad.main import live_voice if live_voice is None: raise HTTPException(503, "LiveVoiceLoop not initialized.") return live_voice @router.get("/status") async def status(): from Project.Sanad.main import live_voice if live_voice is None: return {"available": False} return {"available": True, **live_voice.status()} @router.post("/start") async def start(): loop = _loop() await loop.start() return {"ok": True, **loop.status()} @router.post("/stop") async def stop(): loop = _loop() await loop.stop() return {"ok": True, **loop.status()} @router.post("/deferred-mode") async def set_deferred(enabled: bool): loop = _loop() loop.set_deferred(enabled) return {"ok": True, "deferred_mode": loop.deferred_mode} @router.get("/triggers") async def triggers(): loop = _loop() return { "triggers": list(loop.triggers), "total": len(loop.triggers), "dispatch_actions": len(loop.wake_dispatch), }