notes: done 状态也能 ↻ 重跑;有 transcript 自动跳过 ASR 只重跑 LLM
deploy notes / build-and-deploy (push) Successful in 1m40s

- 前端 retry 按钮去掉 status==failed 限制,总显示(中间态 disabled)
- backend process_recording 启动时看 transcript 有没有,有就直接 cleaning 起步,
  省 30 分钟录音那个 2-3 分钟的 ASR 切片串行
This commit is contained in:
Fam Zheng
2026-05-18 01:44:11 +01:00
parent e072109e91
commit 3e478228dd
2 changed files with 36 additions and 21 deletions
+6 -1
View File
@@ -79,7 +79,12 @@
<span>{{ statusLabel(selected.status) }}</span> <span>{{ statusLabel(selected.status) }}</span>
<span>· {{ fmtSize(selected.size_bytes) }}</span> <span>· {{ fmtSize(selected.size_bytes) }}</span>
<span>· {{ selected.created_at }}</span> <span>· {{ selected.created_at }}</span>
<button v-if="selected.status === 'failed'" class="retry-btn" @click="retry"> 重试</button> <button
class="retry-btn"
:disabled="['pending','transcribing','cleaning','summarizing'].includes(selected.status)"
:title="selected.transcript ? '已有 transcript,只重跑 LLM 润色 + 纪要' : '重新 ASR + 润色 + 纪要'"
@click="retry"
> 重跑</button>
<button class="danger-btn" @click="remove">删除</button> <button class="danger-btn" @click="remove">删除</button>
</div> </div>
<div v-if="selected.status === 'done'" class="feishu-row"> <div v-if="selected.status === 'done'" class="feishu-row">
+30 -20
View File
@@ -436,35 +436,45 @@ async fn upload_recording(
} }
async fn process_recording(s: AppState, id: i64) { 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 path = s.blobs_dir.join(id.to_string());
let filename: String = { // 取已有的 transcript(让 retry 跳过 ASR 直接 cleanup + summary
let (filename, existing_transcript): (String, Option<String>) = {
let conn = s.db.lock().unwrap(); let conn = s.db.lock().unwrap();
conn.query_row( conn.query_row(
"SELECT filename FROM recordings WHERE id = ?1", "SELECT filename, transcript FROM recordings WHERE id = ?1",
params![id], params![id],
|r| r.get(0), |r| Ok((r.get::<_, String>(0)?, r.get::<_, Option<String>>(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);
// ASRmultipart POSTOpenAI Whisper 风格 let transcript = if has_transcript {
let transcript = match call_asr(&s, &path, &filename).await { tracing::info!(%id, "transcript exists, skip ASR");
Ok(t) => t, existing_transcript.unwrap()
Err(e) => { } else {
tracing::error!(%id, error = %e, "ASR failed"); set_status(&s, id, "transcribing", None, None);
set_status(&s, id, "failed", None, Some(&format!("ASR: {e}"))); match call_asr(&s, &path, &filename).await {
return; 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 // 不管走哪条都进 cleaning
{ set_status(&s, id, "cleaning", None, None);
let conn = s.db.lock().unwrap();
let _ = conn.execute(
"UPDATE recordings SET transcript = ?1, status = 'cleaning' WHERE id = ?2",
params![&transcript, id],
);
}
// LLM cleanup:分段 + 去口语 + 润色 + 高亮(失败也继续 summary,不阻塞) // LLM cleanup:分段 + 去口语 + 润色 + 高亮(失败也继续 summary,不阻塞)
match call_llm_cleanup(&s, &transcript).await { match call_llm_cleanup(&s, &transcript).await {