fix: google anti-bot flag + persistent/safe settings apply + TTS engine wiring
- Chrome: --disable-blink-features=AutomationControlled (+ ko-KR) so Google shows results, not the /sorry/ automation block. - Settings persist to /data/jarvis-settings.json (survives recreate; entrypoint re-merges it) AND the runtime config; apply restarts via a DETACHED process so the HTTP response isn't dropped when the bridge restarts. - Bridge reads tts_engine from the settings config so the TTS-engine choice actually applies.
This commit is contained in:
@@ -90,7 +90,20 @@ STT_LANGUAGE = os.environ.get("STT_LANGUAGE", "ko").strip() or None
|
||||
# TTS engine: "melo" (MeloTTS Korean speaker, the warm worker) is the primary
|
||||
# voice; Piper is kept as a fallback if the worker is unreachable. Set
|
||||
# TTS_ENGINE=piper to disable MeloTTS entirely.
|
||||
TTS_ENGINE = os.environ.get("TTS_ENGINE", "melo").strip().lower()
|
||||
def _tts_engine_setting() -> str:
|
||||
"""TTS engine: settings-UI value (runtime config JSON) wins, else env, else
|
||||
melo. Read at startup; the settings UI restarts the bridge on apply."""
|
||||
try:
|
||||
_cp = os.environ.get("JARVIS_CONFIG_PATH", "/app/config/jarvis.json")
|
||||
_v = json.loads(open(_cp, encoding="utf-8").read()).get("tts_engine")
|
||||
if _v:
|
||||
return str(_v).strip().lower()
|
||||
except Exception:
|
||||
pass
|
||||
return os.environ.get("TTS_ENGINE", "melo").strip().lower()
|
||||
|
||||
|
||||
TTS_ENGINE = _tts_engine_setting()
|
||||
MELO_WORKER_URL = os.environ.get("MELO_WORKER_URL", "http://127.0.0.1:8770")
|
||||
MELO_TIMEOUT = float(os.environ.get("MELO_TIMEOUT", "30"))
|
||||
# When MeloTTS is the engine, do NOT silently fall back to the English Piper
|
||||
|
||||
@@ -37,6 +37,12 @@ def _config_path() -> Path:
|
||||
return Path(p).expanduser() if p else (Path.home() / ".config" / "jarvis" / "config.json")
|
||||
|
||||
|
||||
def _persist_path() -> Path:
|
||||
"""Persistent overrides on the data volume — survive container recreate.
|
||||
entrypoint.sh merges this back onto the env-rendered config at startup."""
|
||||
return Path(os.environ.get("JARVIS_SETTINGS_PATH") or "/data/jarvis-settings.json")
|
||||
|
||||
|
||||
def _read_config() -> Dict[str, Any]:
|
||||
try:
|
||||
return json.loads(_config_path().read_text("utf-8"))
|
||||
@@ -67,8 +73,8 @@ def _ollama_models() -> list[str]:
|
||||
return []
|
||||
|
||||
|
||||
def _save(updates: Dict[str, Any]) -> None:
|
||||
cfg = _read_config()
|
||||
def _coerce(updates: Dict[str, Any]) -> Dict[str, Any]:
|
||||
clean: Dict[str, Any] = {}
|
||||
for k, v in updates.items():
|
||||
if k not in _KEYS:
|
||||
continue
|
||||
@@ -84,22 +90,41 @@ def _save(updates: Dict[str, Any]) -> None:
|
||||
continue
|
||||
elif k == "llm_thinking_enabled":
|
||||
v = str(v).lower() in ("1", "true", "on", "yes")
|
||||
cfg[k] = v
|
||||
p = _config_path()
|
||||
p.parent.mkdir(parents=True, exist_ok=True)
|
||||
p.write_text(json.dumps(cfg, ensure_ascii=False, indent=2), "utf-8")
|
||||
clean[k] = v
|
||||
return clean
|
||||
|
||||
|
||||
def _write_merge(path: Path, clean: Dict[str, Any]) -> None:
|
||||
cur: Dict[str, Any] = {}
|
||||
try:
|
||||
cur = json.loads(path.read_text("utf-8"))
|
||||
except Exception:
|
||||
cur = {}
|
||||
cur.update(clean)
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text(json.dumps(cur, ensure_ascii=False, indent=2), "utf-8")
|
||||
|
||||
|
||||
def _save(updates: Dict[str, Any]) -> None:
|
||||
clean = _coerce(updates)
|
||||
# 1) persistent overrides (survive `docker compose up` recreate)
|
||||
_write_merge(_persist_path(), clean)
|
||||
# 2) runtime config so a bridge/worker restart picks it up immediately
|
||||
_write_merge(_config_path(), clean)
|
||||
|
||||
|
||||
def _apply() -> str:
|
||||
# Restart the bridge (re-reads config) and the TTS worker (picks up speed).
|
||||
out = []
|
||||
for prog in ("melo-worker", "bridge"):
|
||||
# Restart melo + bridge AFTER this response is sent. Detached (new session)
|
||||
# so the bridge being killed mid-restart doesn't drop the restart itself,
|
||||
# and the HTTP client still receives this response.
|
||||
try:
|
||||
r = subprocess.run(["supervisorctl", "restart", prog], capture_output=True, text=True, timeout=30)
|
||||
out.append(f"{prog}: {(r.stdout or r.stderr).strip()}")
|
||||
subprocess.Popen(
|
||||
["sh", "-c", "sleep 1; supervisorctl restart melo-worker bridge"],
|
||||
start_new_session=True,
|
||||
)
|
||||
return "1초 후 브리지/TTS 워커가 재시작되어 반영됩니다."
|
||||
except Exception as e: # pragma: no cover
|
||||
out.append(f"{prog}: {e}")
|
||||
return " | ".join(out)
|
||||
return str(e)
|
||||
|
||||
|
||||
_PAGE = """<!doctype html><html lang=ko><head><meta charset=utf-8>
|
||||
|
||||
@@ -47,6 +47,22 @@ chmod 600 /root/.vnc/passwd
|
||||
# --- Render jarvis brain config from template ---
|
||||
envsubst < /app/docker/jarvis-config.template.json > /app/config/jarvis.json
|
||||
export JARVIS_CONFIG_PATH=/app/config/jarvis.json
|
||||
# Merge persistent settings from the settings UI (on the /data volume) on top of
|
||||
# the env-rendered config, so changes survive container recreate.
|
||||
if [ -f /data/jarvis-settings.json ]; then
|
||||
python3 - <<'PY' || true
|
||||
import json
|
||||
try:
|
||||
base = json.load(open("/app/config/jarvis.json"))
|
||||
ov = json.load(open("/data/jarvis-settings.json"))
|
||||
if isinstance(base, dict) and isinstance(ov, dict):
|
||||
base.update(ov)
|
||||
json.dump(base, open("/app/config/jarvis.json", "w"), ensure_ascii=False, indent=2)
|
||||
print("[entrypoint] merged persistent settings overrides")
|
||||
except Exception as e:
|
||||
print(f"[entrypoint] settings merge skipped: {e}")
|
||||
PY
|
||||
fi
|
||||
|
||||
# --- Ensure the Piper voice exists (best effort) ---
|
||||
bash /app/docker/download-piper.sh || echo "[entrypoint] piper download failed; TTS may be unavailable"
|
||||
|
||||
@@ -14,6 +14,9 @@ export DISPLAY=:1
|
||||
exec google-chrome \
|
||||
--no-sandbox --no-first-run --disable-dev-shm-usage \
|
||||
--test-type \
|
||||
--disable-blink-features=AutomationControlled \
|
||||
--disable-features=AutomationControlled \
|
||||
--lang=ko-KR \
|
||||
--disable-infobars \
|
||||
--no-default-browser-check \
|
||||
--disable-translate \
|
||||
|
||||
Reference in New Issue
Block a user