Initial commit: Javis project

This commit is contained in:
Javis committed 2026-09-21 21:44:00 +02:00
commit 435c645f36
164 files changed
+35279

No files matched your search

+90
View File
@@ -0,0 +1,90 @@
"""Slave-local configuration: master address, credentials, audio devices.
Persisted to ``%LOCALAPPDATA%/JavisSlave/slave_config.json`` (or
``~/.javis-slave/slave_config.json`` on non-Windows). Set
``JAVIS_SLAVE_CONFIG_DIR`` to override (useful for systemd services).
"""
from __future__ import annotations
import json
import os
import uuid
from dataclasses import asdict, dataclass, field
from pathlib import Path
from typing import Optional
def config_dir() -> Path:
override = os.environ.get("JAVIS_SLAVE_CONFIG_DIR")
if override:
return Path(override).expanduser()
base = os.environ.get("LOCALAPPDATA")
if base:
return Path(base) / "JavisSlave"
return Path.home() / ".javis-slave"
def config_path() -> Path:
return config_dir() / "slave_config.json"
@dataclass
class WakeWordSettings:
"""Wake-word block received from the master."""
model: str = "hey_jarvis"
threshold: float = 0.5
vad_threshold: float = 0.5
silence_ms: int = 800
@dataclass
class SlaveConfig:
device_id: str = field(default_factory=lambda: str(uuid.uuid4()))
device_name: str = ""
master_host: str = ""
master_port: int = 8765
api_key: str = ""
room: Optional[str] = None # cached; refreshed from master
input_device: Optional[int] = None
output_device: Optional[int] = None
input_gain: float = 1.0
sample_rate: int = 16000
wake_word: WakeWordSettings = field(default_factory=WakeWordSettings)
# Local MCP control server bind (review A-6: was hardcoded to 127.0.0.1,
# unreachable by remote controllers). 0.0.0.0 lets other devices reach it.
api_host: str = "0.0.0.0"
api_port: int = 8766
@property
def paired(self) -> bool:
return bool(self.master_host and self.api_key)
@property
def base_url(self) -> str:
return f"http://{self.master_host}:{self.master_port}"
def load_config() -> SlaveConfig:
path = config_path()
cfg = SlaveConfig()
if path.exists():
try:
raw = json.loads(path.read_text(encoding="utf-8"))
ww_raw = raw.pop("wake_word", {}) or {}
for key, val in raw.items():
if hasattr(cfg, key) and key != "wake_word":
setattr(cfg, key, val)
for key, val in ww_raw.items():
if hasattr(cfg.wake_word, key):
setattr(cfg.wake_word, key, val)
except Exception: # noqa: BLE001
pass
return cfg
def save_config(cfg: SlaveConfig) -> None:
path = config_path()
path.parent.mkdir(parents=True, exist_ok=True)
tmp = path.with_suffix(".tmp")
tmp.write_text(json.dumps(asdict(cfg), indent=2), encoding="utf-8")
tmp.replace(path)