Files
home-voice-assistant/satellite/notifier.py
Cosmo e4e7529063 feat(notifier): push state events to Smart Home Tablet overlay
Adds a thin HTTP bridge so the tablet at https://tablet.digital-home.site
shows a Siri-style overlay reflecting the current assistant state
(wake / command / response / idle / error). Non-fatal: if the tablet
is offline or TABLET_URL/VOICE_API_KEY are unset, events are silently
skipped and the assistant keeps working.

- satellite/notifier.py — POST /api/voice/event with bearer token,
  reused requests.Session for keep-alive, 1.5s timeout
- satellite/modes.py — emits wake on activation, command after STT,
  response after LLM, idle on timeout
- satellite/llm.py — emits error on gateway connection/timeout/HTTP
- .env.example documents TABLET_URL and VOICE_API_KEY

Tablet side (separate repo smart-home-tablet, commit 51c3d60) exposes
POST /api/voice/event + GET /api/voice/stream (SSE) and renders a
full-screen overlay in components/VoiceOverlay.tsx.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 12:43:01 +00:00

61 lines
1.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
Tablet notifier — пересылает состояния ассистента в Smart Home Tablet
(https://tablet.digital-home.site/api/voice/event).
Планшет показывает оверлей (Siri-blob, распознанный текст, ответ).
Не критичный слой: любые сетевые ошибки глотаются, ассистент продолжает
работать даже если планшет оффлайн / не настроен.
Активируется только когда заполнены TABLET_URL и VOICE_API_KEY в .env.
"""
import os
import requests
from .config import log
TABLET_URL = os.getenv("TABLET_URL", "").rstrip("/")
VOICE_API_KEY = os.getenv("VOICE_API_KEY", "")
# Переиспользуем HTTP сессию (keep-alive) для минимума latency
_session = requests.Session()
_ENABLED = bool(TABLET_URL and VOICE_API_KEY)
if _ENABLED:
print(f"🔔 Notifier: планшет {TABLET_URL}")
else:
print("🔕 Notifier: отключён (нет TABLET_URL или VOICE_API_KEY в .env)")
def _send(event: str, **payload):
if not _ENABLED:
return
try:
_session.post(
f"{TABLET_URL}/api/voice/event",
json={"event": event, **payload},
headers={"Authorization": f"Bearer {VOICE_API_KEY}"},
timeout=1.5,
)
except requests.RequestException:
log.debug("Tablet notify failed (non-fatal)", exc_info=True)
def wake(agent_id: str):
_send("wake", agent=agent_id)
def command(text: str, agent_id: str):
_send("command", text=text, agent=agent_id)
def response(text: str, agent_id: str):
_send("response", text=text, agent=agent_id)
def idle():
_send("idle")
def error(text: str, agent_id: str = "cosmo"):
_send("error", text=text, agent=agent_id)