Skip to content

Commit c4b48b4

Browse files
committed
feat: add support for retrying transcriptions
1 parent cf7e13a commit c4b48b4

6 files changed

Lines changed: 371 additions & 140 deletions

File tree

apps/desktop/src/i18n/locales/en.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -527,7 +527,8 @@
527527
"pauseAudio": "Pause audio",
528528
"playAudio": "Play audio",
529529
"downloadAudio": "Download Audio",
530-
"delete": "Delete"
530+
"delete": "Delete",
531+
"retry": "Retry transcription"
531532
},
532533
"dialog": {
533534
"title": "Transcription Details"
@@ -538,7 +539,9 @@
538539
"downloaded": "Audio file downloaded",
539540
"downloadFailed": "Failed to download audio file",
540541
"loadAudioFailed": "Failed to load audio file",
541-
"copied": "Copied to clipboard"
542+
"copied": "Copied to clipboard",
543+
"retrySuccess": "Transcription retried successfully",
544+
"retryFailed": "Failed to retry transcription"
542545
},
543546
"search": {
544547
"placeholder": "Search transcriptions..."

apps/desktop/src/main/managers/recording-manager.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -779,9 +779,12 @@ export class RecordingManager extends EventEmitter {
779779
transcript: transcription,
780780
})
781781
.catch((error) => {
782-
logger.main.warn("Failed to paste transcription via native helper", {
783-
error: error instanceof Error ? error.message : String(error),
784-
});
782+
logger.main.warn(
783+
"Failed to paste transcription via native helper",
784+
{
785+
error: error instanceof Error ? error.message : String(error),
786+
},
787+
);
785788
});
786789
}
787790
} catch (error) {

apps/desktop/src/renderer/main/pages/settings/history/index.tsx

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ import {
2323
Trash2,
2424
MicOff,
2525
Search,
26+
RotateCcw,
27+
Loader2,
2628
} from "lucide-react";
2729
import { Input } from "@/components/ui/input";
2830
import { toast } from "sonner";
@@ -80,10 +82,12 @@ interface HistoryTableCardProps {
8082
onPlay: (transcriptionId: number) => void;
8183
onDownload: (transcriptionId: number) => void;
8284
onDelete: (id: number) => void;
85+
onRetry: (id: number) => void;
8386
hovered: number | null;
8487
setHovered: (id: number | null) => void;
8588
currentPlayingId: number | null;
8689
isPlaying: boolean;
90+
retryingId: number | null;
8791
}
8892

8993
function HistoryTableCard({
@@ -92,9 +96,11 @@ function HistoryTableCard({
9296
onPlay,
9397
onDownload,
9498
onDelete,
99+
onRetry,
95100
setHovered,
96101
currentPlayingId,
97102
isPlaying,
103+
retryingId,
98104
}: HistoryTableCardProps) {
99105
const { t } = useTranslation();
100106
const [selectedText, setSelectedText] = useState<string | null>(null);
@@ -222,6 +228,29 @@ function HistoryTableCard({
222228
</Tooltip>
223229
</TooltipProvider>
224230
)}
231+
{item.audioFile && (
232+
<TooltipProvider>
233+
<Tooltip>
234+
<TooltipTrigger asChild>
235+
<Button
236+
size="icon"
237+
variant="ghost"
238+
disabled={retryingId === item.id}
239+
onClick={() => onRetry(item.id)}
240+
>
241+
{retryingId === item.id ? (
242+
<Loader2 className="w-4 h-4 animate-spin" />
243+
) : (
244+
<RotateCcw className="w-4 h-4" />
245+
)}
246+
</Button>
247+
</TooltipTrigger>
248+
<TooltipContent>
249+
<p>{t("settings.history.actions.retry")}</p>
250+
</TooltipContent>
251+
</Tooltip>
252+
</TooltipProvider>
253+
)}
225254
<TooltipProvider>
226255
<Tooltip>
227256
<TooltipTrigger asChild>
@@ -296,6 +325,22 @@ export default function HistorySettingsPage() {
296325
},
297326
});
298327

328+
const [retryingId, setRetryingId] = useState<number | null>(null);
329+
330+
const retryTranscriptionMutation =
331+
api.transcriptions.retryTranscription.useMutation({
332+
onSuccess: () => {
333+
utils.transcriptions.getTranscriptions.invalidate();
334+
toast.success(t("settings.history.toast.retrySuccess"));
335+
setRetryingId(null);
336+
},
337+
onError: (error) => {
338+
console.error("Error retrying transcription:", error);
339+
toast.error(t("settings.history.toast.retryFailed"));
340+
setRetryingId(null);
341+
},
342+
});
343+
299344
const downloadAudioMutation =
300345
api.transcriptions.downloadAudioFile.useMutation({
301346
onSuccess: () => {
@@ -358,6 +403,11 @@ export default function HistorySettingsPage() {
358403
downloadAudioMutation.mutate({ transcriptionId });
359404
}
360405

406+
function handleRetry(id: number) {
407+
setRetryingId(id);
408+
retryTranscriptionMutation.mutate({ id });
409+
}
410+
361411
function handleDelete(id: number) {
362412
deleteTranscriptionMutation.mutate({ id });
363413
}
@@ -420,10 +470,12 @@ export default function HistorySettingsPage() {
420470
onPlay={handlePlayAudio}
421471
onDownload={handleDownload}
422472
onDelete={handleDelete}
473+
onRetry={handleRetry}
423474
hovered={hovered}
424475
setHovered={setHovered}
425476
currentPlayingId={audioPlayer.currentPlayingId}
426477
isPlaying={audioPlayer.isPlaying}
478+
retryingId={retryingId}
427479
/>
428480
</>
429481
)}
@@ -440,10 +492,12 @@ export default function HistorySettingsPage() {
440492
onPlay={handlePlayAudio}
441493
onDownload={handleDownload}
442494
onDelete={handleDelete}
495+
onRetry={handleRetry}
443496
hovered={hovered}
444497
setHovered={setHovered}
445498
currentPlayingId={audioPlayer.currentPlayingId}
446499
isPlaying={audioPlayer.isPlaying}
500+
retryingId={retryingId}
447501
/>
448502
</>
449503
)}
@@ -460,10 +514,12 @@ export default function HistorySettingsPage() {
460514
onPlay={handlePlayAudio}
461515
onDownload={handleDownload}
462516
onDelete={handleDelete}
517+
onRetry={handleRetry}
463518
hovered={hovered}
464519
setHovered={setHovered}
465520
currentPlayingId={audioPlayer.currentPlayingId}
466521
isPlaying={audioPlayer.isPlaying}
522+
retryingId={retryingId}
467523
/>
468524
</>
469525
)}

apps/desktop/src/services/platform/native-bridge-service.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,10 @@ class NativeBridgeTimeoutError extends Error {
124124
}
125125

126126
class NativeBridgeHelperUnavailableError extends Error {
127-
constructor(message: string, public readonly method: string) {
127+
constructor(
128+
message: string,
129+
public readonly method: string,
130+
) {
128131
super(message);
129132
this.name = "NativeBridgeHelperUnavailableError";
130133
}
@@ -575,7 +578,10 @@ export class NativeBridge extends EventEmitter {
575578
platform: process.platform,
576579
});
577580

578-
const error = new NativeBridgeHelperUnavailableError(errorMessage, method);
581+
const error = new NativeBridgeHelperUnavailableError(
582+
errorMessage,
583+
method,
584+
);
579585
this.telemetryService?.captureException(error, {
580586
source: "native_helper",
581587
stage: "rpc_helper_unavailable",

0 commit comments

Comments
 (0)