diff --git a/enjoy/src/renderer/components/medias/media-loading-modal.tsx b/enjoy/src/renderer/components/medias/media-loading-modal.tsx index a67d52b9..60e04e4a 100644 --- a/enjoy/src/renderer/components/medias/media-loading-modal.tsx +++ b/enjoy/src/renderer/components/medias/media-loading-modal.tsx @@ -9,11 +9,15 @@ import { AlertDialogFooter, AlertDialogOverlay, Button, + Tabs, + TabsContent, + TabsList, + TabsTrigger, } from "@renderer/components/ui"; import { CheckCircleIcon, LoaderIcon, XCircleIcon } from "lucide-react"; import { t } from "i18next"; import { useNavigate } from "react-router-dom"; -import { TranscriptionCreateForm } from "../transcriptions"; +import { TranscriptionCreateForm, TranscriptionsList } from "../transcriptions"; export const MediaLoadingModal = () => { const navigate = useNavigate(); @@ -46,21 +50,35 @@ export const MediaLoadingModal = () => { {t("transcribedSuccessfully")} ) : ( - { - generateTranscription({ - originalText: data.text, - language: data.language, - service: data.service as WhisperConfigType["service"], - isolate: data.isolate, - }); - }} - onCancel={() => navigate(-1)} - transcribing={transcribing} - transcribingProgress={transcribingProgress} - transcribingOutput={transcribingOutput} - /> + + + {t("transcribe")} + {t("download")} + + + { + generateTranscription({ + originalText: data.text, + language: data.language, + service: data.service as WhisperConfigType["service"], + isolate: data.isolate, + }); + }} + onCancel={() => navigate(-1)} + transcribing={transcribing} + transcribingProgress={transcribingProgress} + transcribingOutput={transcribingOutput} + /> + + + + + ) ) : ( <> diff --git a/enjoy/src/renderer/components/medias/media-transcription-generate-button.tsx b/enjoy/src/renderer/components/medias/media-transcription-generate-button.tsx index 1500f28c..6d64262e 100644 --- a/enjoy/src/renderer/components/medias/media-transcription-generate-button.tsx +++ b/enjoy/src/renderer/components/medias/media-transcription-generate-button.tsx @@ -9,10 +9,17 @@ import { AlertDialogContent, AlertDialogTitle, AlertDialogDescription, + Tabs, + TabsContent, + TabsList, + TabsTrigger, toast, } from "@renderer/components/ui"; import { LoaderIcon } from "lucide-react"; -import { TranscriptionCreateForm } from "../transcriptions"; +import { + TranscriptionCreateForm, + TranscriptionsList, +} from "@renderer/components"; export const MediaTranscriptionGenerateButton = (props: { children: React.ReactNode; @@ -57,27 +64,42 @@ export const MediaTranscriptionGenerateButton = (props: { - setOpen(false)} - onSubmit={(data) => { - generateTranscription({ - originalText: data.text, - language: data.language, - service: data.service as WhisperConfigType["service"], - isolate: data.isolate, - }) - .then(() => { - setOpen(false); - }) - .catch((e) => { - toast.error(e.message); - }); - }} - originalText="" - transcribing={transcribing} - transcribingProgress={transcribingProgress} - transcribingOutput={transcribingOutput} - /> + + + {t("transcribe")} + {t("download")} + + + setOpen(false)} + onSubmit={(data) => { + generateTranscription({ + originalText: data.text, + language: data.language, + service: data.service as WhisperConfigType["service"], + isolate: data.isolate, + }) + .then(() => { + setOpen(false); + }) + .catch((e) => { + toast.error(e.message); + }); + }} + originalText="" + transcribing={transcribing} + transcribingProgress={transcribingProgress} + transcribingOutput={transcribingOutput} + /> + + + setOpen(false)} + /> + + ); diff --git a/enjoy/src/renderer/components/transcriptions/index.ts b/enjoy/src/renderer/components/transcriptions/index.ts index 80439023..91600570 100644 --- a/enjoy/src/renderer/components/transcriptions/index.ts +++ b/enjoy/src/renderer/components/transcriptions/index.ts @@ -1,2 +1,3 @@ export * from "./transcription-create-form"; export * from "./transcription-edit-button"; +export * from "./transcriptions-list"; diff --git a/enjoy/src/renderer/components/transcriptions/transcriptions-list.tsx b/enjoy/src/renderer/components/transcriptions/transcriptions-list.tsx new file mode 100644 index 00000000..f3dda832 --- /dev/null +++ b/enjoy/src/renderer/components/transcriptions/transcriptions-list.tsx @@ -0,0 +1,157 @@ +import { + AppSettingsProviderContext, + MediaPlayerProviderContext, +} from "@renderer/context"; +import { useContext, useEffect, useState } from "react"; +import { LoaderSpin } from "@renderer/components"; +import { + Button, + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, + toast, +} from "@renderer/components/ui"; +import { t } from "i18next"; +import { formatDateTime } from "@renderer/lib/utils"; +import { + CheckCircleIcon, + ChevronLeftIcon, + ChevronRightIcon, + DownloadCloudIcon, +} from "lucide-react"; + +export const TranscriptionsList = (props: { + media: AudioType | VideoType; + transcription?: TranscriptionType; + onFinish?: () => void; +}) => { + const { media, transcription, onFinish } = props; + const { webApi, EnjoyApp } = useContext(AppSettingsProviderContext); + const [transcriptions, setTranscriptions] = useState([]); + const [loading, setLoading] = useState(false); + const [nextPage, setNextPage] = useState(1); + const [currentPage, setCurrentPage] = useState(1); + + const fetchTranscriptions = async (params: { page: number }) => { + const { page = currentPage } = params; + setLoading(true); + webApi + .transcriptions({ + targetMd5: media.md5, + items: 10, + page, + }) + .then(({ transcriptions, next, page }) => { + setTranscriptions(transcriptions); + setCurrentPage(page); + setNextPage(next); + }) + .finally(() => { + setLoading(false); + }); + }; + + const handleDownload = (tr: TranscriptionType) => { + EnjoyApp.transcriptions + .update(transcription.id, { + state: "finished", + result: tr.result, + engine: tr.engine, + model: tr.model, + language: tr.language || media.language, + }) + .then(() => { + onFinish?.(); + }) + .catch((err) => { + toast.error(err.message); + }); + }; + + useEffect(() => { + fetchTranscriptions({ page: 1 }); + }, [media]); + + if (loading) { + return ; + } + + if (!transcriptions.length) { + return ( +
+ {t("noData")} +
+ ); + } + + return ( +
+ + + + ID + {t("model")} + {t("language")} + {t("date")} + {t("actions")} + + + + {transcriptions.map((tr) => ( + + + {tr.id.split("-")[0]} + + +
{tr.engine}
+
{tr.model}
+
+ + {tr.language || "-"} + + + {formatDateTime(tr.createdAt)} + + + {transcription?.id === tr.id ? ( + + ) : ( + + )} + +
+ ))} +
+
+ +
+ + {currentPage} + +
+
+ ); +}; diff --git a/enjoy/src/types/transcription.d.ts b/enjoy/src/types/transcription.d.ts index 96441326..827dce7d 100644 --- a/enjoy/src/types/transcription.d.ts +++ b/enjoy/src/types/transcription.d.ts @@ -8,6 +8,8 @@ type TranscriptionType = { model: string; language?: string; result: AlignmentResult & { original?: string }; + createdAt: string; + updatedAt: string; }; type TranscriptionResultSegmentType = {