"""Persistent settings storage for the Streamlit app. All settings (API keys, model roles) are stored in the browser's localStorage via raw JS eval. Nothing is saved on the server. """ from __future__ import annotations import json import streamlit as st _LS_KEY = "scider_settings" # All provider key field names _KEY_FIELDS = ("gemini_api_key", "openai_api_key", "anthropic_api_key", "s2_api_key") def _ls_get() -> dict | None: """Read settings from browser localStorage via JS eval.""" try: from streamlit_js_eval import streamlit_js_eval raw = streamlit_js_eval( js_expressions=f"JSON.parse(localStorage.getItem('{_LS_KEY}') || 'null')", key="_ls_get", ) if isinstance(raw, dict): return raw if isinstance(raw, str): return json.loads(raw) except Exception: pass return None def _ls_set(settings: dict) -> None: """Write settings to browser localStorage via JS eval.""" try: from streamlit_js_eval import streamlit_js_eval payload = json.dumps(settings, ensure_ascii=True) # Escape for JS string literal escaped = payload.replace("\\", "\\\\").replace("'", "\\'") streamlit_js_eval( js_expressions=f"localStorage.setItem('{_LS_KEY}', '{escaped}')", key="_ls_set", ) except Exception: pass def _ls_clear() -> None: """Remove settings from browser localStorage via JS eval.""" try: from streamlit_js_eval import streamlit_js_eval streamlit_js_eval( js_expressions=f"localStorage.removeItem('{_LS_KEY}')", key="_ls_clear", ) except Exception: pass def load_settings() -> dict: """Load settings from browser localStorage. Cached in session_state so we don't keep hitting JS eval on every rerun. """ if "_settings_cache" in st.session_state: return st.session_state["_settings_cache"] settings = _ls_get() if not settings or not isinstance(settings, dict): settings = {} st.session_state["_settings_cache"] = settings return settings def save_settings(settings: dict) -> None: """Save settings to browser localStorage + session_state cache.""" settings = {k: v for k, v in settings.items() if k not in {"model_provider", "api_key"}} st.session_state["_settings_cache"] = settings _ls_set(settings) def has_settings() -> bool: """Check if at least one provider API key has been configured.""" settings = load_settings() return any(settings.get(k) for k in _KEY_FIELDS) def clear_settings() -> None: """Clear all settings from localStorage and session_state.""" _ls_clear() st.session_state.pop("_settings_cache", None)