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 {