diff --git a/openless-all/app/src-tauri/src/coordinator/llm_pipeline.rs b/openless-all/app/src-tauri/src/coordinator/llm_pipeline.rs index cc589c16..17e363fb 100644 --- a/openless-all/app/src-tauri/src/coordinator/llm_pipeline.rs +++ b/openless-all/app/src-tauri/src/coordinator/llm_pipeline.rs @@ -506,10 +506,17 @@ pub(crate) fn read_whisper_credentials() -> (String, String, String) { } pub(crate) fn read_mimo_credentials() -> (String, String, String) { - let api_key = CredentialsVault::get(CredentialAccount::AsrApiKey) - .ok() - .flatten() - .unwrap_or_default(); + let api_key = match CredentialsVault::get(CredentialAccount::AsrApiKey) { + Ok(Some(key)) if !key.trim().is_empty() => key, + Ok(_) => { + log::warn!("[coord] MiMo ASR: asr.api_key 未配置或为空"); + String::new() + } + Err(e) => { + log::error!("[coord] MiMo ASR: 读取凭据失败: {e}"); + String::new() + } + }; let base_url = CredentialsVault::get(CredentialAccount::AsrEndpoint) .ok() .flatten() diff --git a/openless-all/app/src/pages/settings/ProvidersSection.tsx b/openless-all/app/src/pages/settings/ProvidersSection.tsx index b6a2ac15..e9d453a2 100644 --- a/openless-all/app/src/pages/settings/ProvidersSection.tsx +++ b/openless-all/app/src/pages/settings/ProvidersSection.tsx @@ -623,6 +623,7 @@ function CredentialField({ label, account, placeholder, mono, mask, defaultValue const [status, setStatus] = useState('idle'); const debounceRef = useRef(null); const statusRef = useRef(null); + const mountedRef = useRef(true); useEffect(() => { let cancelled = false; @@ -652,7 +653,9 @@ function CredentialField({ label, account, placeholder, mono, mask, defaultValue }, [account]); useEffect(() => { + mountedRef.current = true; return () => { + mountedRef.current = false; if (debounceRef.current) clearTimeout(debounceRef.current); if (statusRef.current) clearTimeout(statusRef.current); }; @@ -680,13 +683,16 @@ function CredentialField({ label, account, placeholder, mono, mask, defaultValue const save = async (v: string, force = false) => { if (!loaded || (!dirty && !force)) return; + if (!mountedRef.current) return; setStatus('saving'); emitSaved('saving', t('common.saving')); try { await setCredential(account, v); + if (!mountedRef.current) return; setDirty(false); showTemporaryStatus('saved'); } catch (error) { + if (!mountedRef.current) return; console.error('[settings] failed to save credential', account, error); showTemporaryStatus('saveError'); } @@ -707,7 +713,7 @@ function CredentialField({ label, account, placeholder, mono, mask, defaultValue clearTimeout(debounceRef.current); debounceRef.current = null; } - save(value, true); + void save(value, true); }; const fillDefault = async () => {