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>
This commit is contained in:
60
satellite/notifier.py
Normal file
60
satellite/notifier.py
Normal file
@@ -0,0 +1,60 @@
|
||||
"""
|
||||
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)
|
||||
Reference in New Issue
Block a user