diff --git a/backend/api_server.py b/backend/api_server.py index 2107bdd..03e11f7 100644 --- a/backend/api_server.py +++ b/backend/api_server.py @@ -73,8 +73,15 @@ class APIServer: original_state_cb = self.controller.on_state_changed def on_state_changed(state: str, message: str): + # Isolate the upstream callback so a failure there (e.g. a + # broken stdout pipe in main_headless) cannot propagate into + # _set_state and tear down engine init / reload_engine / + # apply_settings request handling. if original_state_cb: - original_state_cb(state, message) + try: + original_state_cb(state, message) + except Exception: + pass self._broadcast_control({"type": "state_changed", "state": state, "message": message}) self.controller.on_state_changed = on_state_changed @@ -273,6 +280,7 @@ class APIServer: data = resp.json() ctrl.config.set('remote.auth_token', data.get('token', '')) ctrl.config.set('remote.server_url', req.server_url) + ctrl.config.set('remote.email', req.email) return {"status": "ok", "token": data.get('token', '')} else: raise HTTPException(status_code=resp.status_code, detail=resp.text) diff --git a/backend/main_headless.py b/backend/main_headless.py index 4be921e..666e1a7 100644 --- a/backend/main_headless.py +++ b/backend/main_headless.py @@ -75,10 +75,16 @@ def main(): # Create controller and initialize controller = AppController(config=config) - # Wire a state callback that prints the ready event + # Wire a state callback that prints state events for the parent + # process to read. Stdout writes can fail with EINVAL on Windows + # when the parent stops reading the sidecar pipe; swallow those + # so the engine state machine isn't taken down by a logging path. def on_state_changed(state, message): event = {"event": "state", "state": state, "message": message} - print(json.dumps(event), flush=True) + try: + print(json.dumps(event), flush=True) + except (OSError, ValueError): + pass controller.on_state_changed = on_state_changed diff --git a/config/default_config.yaml b/config/default_config.yaml index 6ab33eb..ce5b7f4 100644 --- a/config/default_config.yaml +++ b/config/default_config.yaml @@ -72,6 +72,7 @@ remote: mode: byok # local | managed | byok server_url: "https://transcribe.shadowdao.com" # Proxy server URL for managed mode auth_token: "" # JWT stored after login (managed mode) + email: "" # Email of the logged-in managed-mode account (for UI display) byok_api_key: "" # Deepgram API key for BYOK mode deepgram_model: nova-2 # Deepgram model to use language: en-US # Language code diff --git a/src/lib/components/Settings.svelte b/src/lib/components/Settings.svelte index d876310..83a0566 100644 --- a/src/lib/components/Settings.svelte +++ b/src/lib/components/Settings.svelte @@ -44,6 +44,7 @@ let byokApiKey = $state(""); let managedEmail = $state(""); let managedPassword = $state(""); + let managedLoggedIn = $state(false); let autoCheckUpdates = $state(true); let isCloudMode = $derived(remoteMode === "managed" || remoteMode === "byok"); @@ -131,6 +132,8 @@ remoteMode = cfg.remote.mode; remoteServerUrl = cfg.remote.server_url; byokApiKey = cfg.remote.byok_api_key ?? ""; + managedEmail = cfg.remote.email ?? ""; + managedLoggedIn = !!(cfg.remote.auth_token && cfg.remote.email); autoCheckUpdates = cfg.updates.auto_check; }); @@ -268,12 +271,29 @@ server_url: remoteServerUrl || MANAGED_SERVER_URL, }); loginMessage = "Logged in successfully!"; + managedPassword = ""; + managedLoggedIn = true; + await configStore.fetchConfig(); } catch (err) { console.error("Login failed:", err); loginMessage = "Login failed. Check your email and password."; } } + async function handleManagedLogout() { + try { + await configStore.updateConfig({ + remote: { auth_token: "", email: "" }, + }); + managedLoggedIn = false; + managedPassword = ""; + loginMessage = ""; + } catch (err) { + console.error("Logout failed:", err); + loginMessage = `Error: ${err}`; + } + } + const CAPTION_SERVER = "https://caption.shadowdao.com"; function generateRandomName(): string { @@ -489,34 +509,44 @@ {/if} {#if remoteMode === "managed"}
+ ✓ Logged in + as {managedEmail} +
+ + {:else} ++ Don't have an account? Sign up here +
+ {/if} {#if loginMessage}{loginMessage}
{/if} -- Don't have an account? Sign up here -