diff --git a/apps/notes/frontend/src/App.vue b/apps/notes/frontend/src/App.vue index e263243..38b56bb 100644 --- a/apps/notes/frontend/src/App.vue +++ b/apps/notes/frontend/src/App.vue @@ -79,7 +79,12 @@ {{ statusLabel(selected.status) }} · {{ fmtSize(selected.size_bytes) }} · {{ selected.created_at }} - +
diff --git a/apps/notes/src/main.rs b/apps/notes/src/main.rs index f2d27e3..f7b6f71 100644 --- a/apps/notes/src/main.rs +++ b/apps/notes/src/main.rs @@ -436,35 +436,45 @@ async fn upload_recording( } async fn process_recording(s: AppState, id: i64) { - set_status(&s, id, "transcribing", None, None); let path = s.blobs_dir.join(id.to_string()); - let filename: String = { + // 取已有的 transcript(让 retry 跳过 ASR 直接 cleanup + summary) + let (filename, existing_transcript): (String, Option) = { let conn = s.db.lock().unwrap(); conn.query_row( - "SELECT filename FROM recordings WHERE id = ?1", + "SELECT filename, transcript FROM recordings WHERE id = ?1", params![id], - |r| r.get(0), + |r| Ok((r.get::<_, String>(0)?, r.get::<_, Option>(1)?)), ) - .unwrap_or_else(|_| "audio".to_string()) + .unwrap_or_else(|_| ("audio".to_string(), None)) }; + let has_transcript = existing_transcript + .as_deref() + .map(|t| !t.trim().is_empty()) + .unwrap_or(false); - // ASR:multipart POST,OpenAI Whisper 风格 - let transcript = match call_asr(&s, &path, &filename).await { - Ok(t) => t, - Err(e) => { - tracing::error!(%id, error = %e, "ASR failed"); - set_status(&s, id, "failed", None, Some(&format!("ASR: {e}"))); - return; + let transcript = if has_transcript { + tracing::info!(%id, "transcript exists, skip ASR"); + existing_transcript.unwrap() + } else { + set_status(&s, id, "transcribing", None, None); + match call_asr(&s, &path, &filename).await { + Ok(t) => { + let conn = s.db.lock().unwrap(); + let _ = conn.execute( + "UPDATE recordings SET transcript = ?1, status = 'cleaning' WHERE id = ?2", + params![&t, id], + ); + t + } + Err(e) => { + tracing::error!(%id, error = %e, "ASR failed"); + set_status(&s, id, "failed", None, Some(&format!("ASR: {e}"))); + return; + } } }; - // 写 transcript,进入 cleaning - { - let conn = s.db.lock().unwrap(); - let _ = conn.execute( - "UPDATE recordings SET transcript = ?1, status = 'cleaning' WHERE id = ?2", - params![&transcript, id], - ); - } + // 不管走哪条都进 cleaning + set_status(&s, id, "cleaning", None, None); // LLM cleanup:分段 + 去口语 + 润色 + 高亮(失败也继续 summary,不阻塞) match call_llm_cleanup(&s, &transcript).await {