fix(windows): 收口录音会话失败态 (#66)

Co-authored-by: Cooper-X-Oak <Cooper-X-Oak@users.noreply.github.com>
This commit is contained in:
Cooper OakandCooper-X-Oak authored and GitHub committed 2026-04-30 14:25:43 +08:00
1 parent 61177eafc3
commit 848cfc35c8
1 file changed
+68
@@ -326,6 +326,20 @@ async fn begin_session(inner: &Arc<Inner>) -> Result<(), String> {
return Ok(());
}
if let Err(message) = ensure_asr_credentials() {
log::warn!("[coord] ASR credential gate failed: {message}");
emit_capsule(
inner,
CapsuleState::Error,
0.0,
0,
Some(message.clone()),
None,
);
inner.state.lock().phase = SessionPhase::Idle;
return Err(message);
}
if let Err(message) = ensure_microphone_permission(inner) {
log::warn!("[coord] microphone permission gate failed: {message}");
emit_capsule(
@@ -556,12 +570,45 @@ async fn end_session(inner: &Arc<Inner>) -> Result<(), String> {
};
// ASR 完成后 cancel 检查:用户在 transcribe 进行中按 Esc 时,这里就会命中。
// 优先级高于 empty 检查 — 用户取消 → 静默丢弃,不写失败历史也不弹错误胶囊。
if inner.state.lock().cancelled {
log::info!("[coord] cancel detected after ASR — discarding transcript");
inner.state.lock().phase = SessionPhase::Idle;
return Ok(());
}
// ASR 返回空转写护栏(来自 PR #66):写一条 emptyTranscript 失败历史 + 错误胶囊,
// 与 main 上其它 error 路径保持一致(带 schedule_capsule_idle 让胶囊自动消失)。
if raw.text.trim().is_empty() {
let session = DictationSession {
id: Uuid::new_v4().to_string(),
created_at: Utc::now().to_rfc3339(),
raw_transcript: raw.text.clone(),
final_text: String::new(),
mode: inner.prefs.get().default_mode,
app_bundle_id: None,
app_name: None,
insert_status: InsertStatus::Failed,
error_code: Some("emptyTranscript".to_string()),
duration_ms: Some(raw.duration_ms),
dictionary_entry_count: Some(enabled_phrases(inner).len() as u32),
};
if let Err(e) = inner.history.append(session) {
log::error!("[coord] history append failed: {e}");
}
emit_capsule(
inner,
CapsuleState::Error,
0.0,
elapsed,
Some("ASR returned empty transcript".to_string()),
None,
);
inner.state.lock().phase = SessionPhase::Idle;
schedule_capsule_idle(inner, CAPSULE_AUTO_HIDE_DELAY_MS);
return Err("ASR returned empty transcript".to_string());
}
emit_capsule(inner, CapsuleState::Polishing, 0.0, elapsed, None, None);
let prefs = inner.prefs.get();
@@ -720,6 +767,27 @@ fn ensure_microphone_permission(inner: &Arc<Inner>) -> Result<(), String> {
}
}
fn ensure_asr_credentials() -> Result<(), String> {
let active_asr = CredentialsVault::get_active_asr();
if active_asr == "whisper" {
let api_key = CredentialsVault::get(CredentialAccount::AsrApiKey)
.ok()
.flatten()
.unwrap_or_default();
if api_key.trim().is_empty() {
return Err("请先在设置中填写 Whisper ASR API Key".to_string());
}
return Ok(());
}
let creds = read_volc_credentials();
if creds.app_id.trim().is_empty() || creds.access_token.trim().is_empty() {
Err("请先在设置中填写火山引擎 ASR App Key 和 Access Key".to_string())
} else {
Ok(())
}
}
async fn polish_or_passthrough(
raw: &RawTranscript,
mode: PolishMode,