From e9e0642fef7a279eb1861c61e45afcaedb8e2d2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=89=87=E6=B2=BC=E3=81=BB=E3=81=A8=E3=82=8A?= <206570885+katanumahotori@users.noreply.github.com> Date: Fri, 26 Jun 2026 20:46:22 +0900 Subject: [PATCH] fix(history): fall back to raw transcript when polished text is empty + copy button on raw panel When polishing returns an empty finalText (errorCode stays null), the History "Copy" button copied an empty string, so the raw transcript that is still visible in the UI could not be recovered. Re-transcribe does not apply here (ASR succeeded; polish is what failed). - onCopy: fall back to rawTranscript when finalText is blank - raw panel: add a dedicated copy button (shown only when rawTranscript exists) - reuse existing common.copy / common.copied, no new i18n; frontend-only Complements #653 (polish identical to raw); independent of the in-progress history re-polish work (#666/#694). No backend/IPC changes. Co-Authored-By: Claude Opus 4.8 (1M context) --- openless-all/app/src/pages/History.tsx | 31 ++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/openless-all/app/src/pages/History.tsx b/openless-all/app/src/pages/History.tsx index f2e40741..dcbfaca2 100644 --- a/openless-all/app/src/pages/History.tsx +++ b/openless-all/app/src/pages/History.tsx @@ -48,6 +48,7 @@ export function History() { const [loadError, setLoadError] = useState(null); const [actionError, setActionError] = useState(null); const [justCopied, setJustCopied] = useState(false); + const [justCopiedRaw, setJustCopiedRaw] = useState(false); // 「重新转录」进行中:禁用按钮 + 显示「转录中…」,避免重复点击发起多次 ASR。 const [retranscribing, setRetranscribing] = useState(false); // 录音文件 lazily-detected missing 状态:retention / 条数 cap 清理后磁盘上 wav @@ -160,7 +161,9 @@ export function History() { if (!navigator.clipboard?.writeText) { throw new Error('clipboard unavailable'); } - await navigator.clipboard.writeText(item.finalText); + // 润色失败/未产出时 finalText 为空,回退到原文,避免「复制」按钮复制空字符串 + // 导致原文无法从 UI 取回(polish 失败时仍能拿到识别原文)。 + await navigator.clipboard.writeText(item.finalText.trim() ? item.finalText : item.rawTranscript); setActionError(null); setJustCopied(true); window.setTimeout(() => setJustCopied(false), 1500); @@ -170,6 +173,23 @@ export function History() { } }; + // 原文(识别结果)单独复制:润色失败或用户只想要未润色文本时使用。 + const onCopyRaw = async () => { + if (!item) return; + try { + if (!navigator.clipboard?.writeText) { + throw new Error('clipboard unavailable'); + } + await navigator.clipboard.writeText(item.rawTranscript); + setActionError(null); + setJustCopiedRaw(true); + window.setTimeout(() => setJustCopiedRaw(false), 1500); + } catch (error) { + console.error('[history] failed to copy raw transcript', error); + setActionError(t('history.copyFailed', { err: errorMessage(error) })); + } + }; + const onExportAudio = async () => { if (!item || !item.hasAudioRecording) return; try { @@ -377,7 +397,14 @@ export function History() { )}
- {t('history.rawLabel')} +
+ {t('history.rawLabel')} + {item.rawTranscript && ( + void onCopyRaw()}> + {justCopiedRaw ? t('common.copied') : t('common.copy')} + + )} +

{item.rawTranscript || t('history.rawEmpty')}