fix: split Foundry prepare and transcription timeouts
This commit is contained in:
1 parent
4dc0246022
commit
0421ced5be
3 files changed
+36
-39
No files matched your search
@@ -62,7 +62,7 @@ impl FoundryLocalWhisperAsr {
|
||||
self.language_hint.as_deref()
|
||||
}
|
||||
|
||||
pub async fn transcribe(&self) -> Result<RawTranscript> {
|
||||
pub async fn transcribe(&self, audio_timeout: std::time::Duration) -> Result<RawTranscript> {
|
||||
let pcm = self.buffer.lock().clone();
|
||||
if pcm.is_empty() {
|
||||
return Ok(RawTranscript {
|
||||
@@ -71,14 +71,18 @@ impl FoundryLocalWhisperAsr {
|
||||
});
|
||||
}
|
||||
|
||||
let result = self.transcribe_inner(&pcm).await;
|
||||
let result = self.transcribe_inner(&pcm, audio_timeout).await;
|
||||
if result.is_ok() {
|
||||
self.buffer.lock().clear();
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
async fn transcribe_inner(&self, pcm: &[u8]) -> Result<RawTranscript> {
|
||||
async fn transcribe_inner(
|
||||
&self,
|
||||
pcm: &[u8],
|
||||
audio_timeout: std::time::Duration,
|
||||
) -> Result<RawTranscript> {
|
||||
let duration_ms = pcm_duration_ms(pcm);
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
@@ -95,7 +99,12 @@ impl FoundryLocalWhisperAsr {
|
||||
let wav_file = TempWavFile::create(pcm)?;
|
||||
let text = self
|
||||
.runtime
|
||||
.transcribe_audio_file(&self.model_alias, self.language_hint(), wav_file.path())
|
||||
.transcribe_audio_file(
|
||||
&self.model_alias,
|
||||
self.language_hint(),
|
||||
wav_file.path(),
|
||||
audio_timeout,
|
||||
)
|
||||
.await
|
||||
.with_context(|| {
|
||||
format!(
|
||||
|
||||
@@ -129,6 +129,7 @@ mod imp {
|
||||
alias: &str,
|
||||
language_hint: Option<&str>,
|
||||
audio_path: &Path,
|
||||
audio_timeout: std::time::Duration,
|
||||
) -> Result<String> {
|
||||
let _lifecycle = self.lifecycle.lock().await;
|
||||
self.cancel_prepare.store(false, Ordering::SeqCst);
|
||||
@@ -140,9 +141,14 @@ mod imp {
|
||||
if let Some(language_hint) = normalized_language_hint(language_hint) {
|
||||
client = client.language(language_hint);
|
||||
}
|
||||
let result = client
|
||||
.transcribe(audio_path)
|
||||
let result = tokio::time::timeout(audio_timeout, client.transcribe(audio_path))
|
||||
.await
|
||||
.with_context(|| {
|
||||
format!(
|
||||
"transcribe audio with Foundry model {alias} timed out after {} seconds",
|
||||
audio_timeout.as_secs()
|
||||
)
|
||||
})?
|
||||
.with_context(|| format!("transcribe audio with Foundry model {alias}"))?;
|
||||
Ok(result.text)
|
||||
}
|
||||
@@ -448,6 +454,7 @@ impl FoundryLocalRuntime {
|
||||
alias: &str,
|
||||
_language_hint: Option<&str>,
|
||||
_audio_path: &std::path::Path,
|
||||
_audio_timeout: std::time::Duration,
|
||||
) -> anyhow::Result<String> {
|
||||
anyhow::bail!("Foundry Local Whisper is only available on Windows: {alias}");
|
||||
}
|
||||
|
||||
@@ -1716,13 +1716,15 @@ async fn end_session(inner: &Arc<Inner>) -> Result<(), String> {
|
||||
#[cfg(target_os = "windows")]
|
||||
ActiveAsr::FoundryLocalWhisper(local) => {
|
||||
debug_assert!(!uses_global_timeout);
|
||||
let timeout_duration = foundry_transcribe_timeout_duration();
|
||||
match tokio::time::timeout(timeout_duration, local.transcribe()).await {
|
||||
Ok(Ok(r)) => {
|
||||
match local
|
||||
.transcribe(foundry_audio_transcribe_timeout_duration())
|
||||
.await
|
||||
{
|
||||
Ok(r) => {
|
||||
schedule_foundry_local_asr_release(inner, current_session_id);
|
||||
r
|
||||
}
|
||||
Ok(Err(e)) => {
|
||||
Err(e) => {
|
||||
log::error!("[coord] Foundry Local Whisper transcribe failed: {e:#}");
|
||||
emit_capsule(
|
||||
inner,
|
||||
@@ -1737,26 +1739,6 @@ async fn end_session(inner: &Arc<Inner>) -> Result<(), String> {
|
||||
schedule_capsule_idle(inner, CAPSULE_AUTO_HIDE_DELAY_MS);
|
||||
return Err(e.to_string());
|
||||
}
|
||||
Err(_) => {
|
||||
log::error!(
|
||||
"[coord] Foundry Local Whisper timeout after {} seconds",
|
||||
FOUNDRY_LOCAL_TRANSCRIBE_TIMEOUT_SECS
|
||||
);
|
||||
local.cancel();
|
||||
schedule_foundry_local_asr_release(inner, current_session_id);
|
||||
emit_capsule(
|
||||
inner,
|
||||
CapsuleState::Error,
|
||||
0.0,
|
||||
elapsed,
|
||||
Some("本地识别超时".to_string()),
|
||||
None,
|
||||
);
|
||||
restore_prepared_windows_ime_session(inner, current_session_id);
|
||||
inner.state.lock().phase = SessionPhase::Idle;
|
||||
schedule_capsule_idle(inner, CAPSULE_AUTO_HIDE_DELAY_MS);
|
||||
return Err("foundry local timeout".to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(target_os = "macos")]
|
||||
@@ -3256,11 +3238,13 @@ mod tests {
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
#[test]
|
||||
fn foundry_transcribe_has_finite_extended_timeout() {
|
||||
let timeout = foundry_transcribe_timeout_duration();
|
||||
fn foundry_audio_transcribe_timeout_is_separate_from_prepare() {
|
||||
let timeout = foundry_audio_transcribe_timeout_duration();
|
||||
|
||||
assert!(timeout > std::time::Duration::from_secs(COORDINATOR_GLOBAL_TIMEOUT_SECS));
|
||||
assert!(timeout <= std::time::Duration::from_secs(15 * 60));
|
||||
assert_eq!(
|
||||
timeout,
|
||||
std::time::Duration::from_secs(COORDINATOR_GLOBAL_TIMEOUT_SECS)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -3579,11 +3563,8 @@ const CAPSULE_AUTO_HIDE_DELAY_MS: u64 = 2000;
|
||||
const COORDINATOR_GLOBAL_TIMEOUT_SECS: u64 = 15;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
const FOUNDRY_LOCAL_TRANSCRIBE_TIMEOUT_SECS: u64 = 10 * 60;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
fn foundry_transcribe_timeout_duration() -> std::time::Duration {
|
||||
std::time::Duration::from_secs(FOUNDRY_LOCAL_TRANSCRIBE_TIMEOUT_SECS)
|
||||
fn foundry_audio_transcribe_timeout_duration() -> std::time::Duration {
|
||||
std::time::Duration::from_secs(COORDINATOR_GLOBAL_TIMEOUT_SECS)
|
||||
}
|
||||
|
||||
/// begin_session 中各 await 之间的 cancel race 检查结果。
|
||||
|
||||
Reference in new issue
Block a user