From 5d77b8be0c8fb593efd337bc3cf14e6b42de5bf0 Mon Sep 17 00:00:00 2001 From: Sergey Mankovsky Date: Fri, 5 Jul 2024 17:29:29 +0200 Subject: [PATCH] Separate upload file and record pages --- .../transcripts/[transcriptId]/page.tsx | 3 +- .../[transcriptId]/upload/page.tsx | 113 ++++++++++++++++++ .../[domain]/transcripts/fileUploadButton.tsx | 24 +++- www/app/[domain]/transcripts/new/page.tsx | 47 +++++--- www/app/[domain]/transcripts/recorder.tsx | 4 - 5 files changed, 162 insertions(+), 29 deletions(-) create mode 100644 www/app/[domain]/transcripts/[transcriptId]/upload/page.tsx diff --git a/www/app/[domain]/transcripts/[transcriptId]/page.tsx b/www/app/[domain]/transcripts/[transcriptId]/page.tsx index 519fe7e1..f695786d 100644 --- a/www/app/[domain]/transcripts/[transcriptId]/page.tsx +++ b/www/app/[domain]/transcripts/[transcriptId]/page.tsx @@ -27,8 +27,7 @@ export default function TranscriptDetails(details: TranscriptDetails) { const transcript = useTranscript(transcriptId); const transcriptStatus = transcript.response?.status; - const waiting = - !transcriptStatus || statusToRedirect.includes(transcriptStatus); + const waiting = statusToRedirect.includes(transcriptStatus || ""); const topics = useTopics(transcriptId); const waveform = useWaveform(transcriptId, waiting); diff --git a/www/app/[domain]/transcripts/[transcriptId]/upload/page.tsx b/www/app/[domain]/transcripts/[transcriptId]/upload/page.tsx new file mode 100644 index 00000000..c6e9eb69 --- /dev/null +++ b/www/app/[domain]/transcripts/[transcriptId]/upload/page.tsx @@ -0,0 +1,113 @@ +"use client"; +import { useEffect, useState } from "react"; +import useTranscript from "../../useTranscript"; +import { useWebSockets } from "../../useWebSockets"; +import "../../../../styles/button.css"; +import { lockWakeState, releaseWakeState } from "../../../../lib/wakeLock"; +import { useRouter } from "next/navigation"; +import useMp3 from "../../useMp3"; +import { Center, VStack, Text, Heading, Button } from "@chakra-ui/react"; +import FileUploadButton from "../../fileUploadButton"; + +type TranscriptUpload = { + params: { + transcriptId: string; + }; +}; + +const TranscriptUpload = (details: TranscriptUpload) => { + const transcript = useTranscript(details.params.transcriptId); + const [transcriptStarted, setTranscriptStarted] = useState(false); + + const webSockets = useWebSockets(details.params.transcriptId); + + let mp3 = useMp3(details.params.transcriptId, true); + + const router = useRouter(); + + const [status, setStatus] = useState( + webSockets.status.value || transcript.response?.status || "idle", + ); + + useEffect(() => { + if (!transcriptStarted && webSockets.transcriptTextLive.length !== 0) + setTranscriptStarted(true); + }, [webSockets.transcriptTextLive]); + + useEffect(() => { + //TODO HANDLE ERROR STATUS BETTER + const newStatus = + webSockets.status.value || transcript.response?.status || "idle"; + setStatus(newStatus); + if (newStatus && (newStatus == "ended" || newStatus == "error")) { + console.log(newStatus, "redirecting"); + + const newUrl = "/transcripts/" + details.params.transcriptId; + router.replace(newUrl); + } + }, [webSockets.status.value, transcript.response?.status]); + + useEffect(() => { + if (webSockets.waveform && webSockets.waveform) mp3.getNow(); + }, [webSockets.waveform, webSockets.duration]); + + useEffect(() => { + lockWakeState(); + return () => { + releaseWakeState(); + }; + }, []); + + return ( + <> + + Upload meeting +
+ + {status && status == "idle" && ( + <> + + Please select the file, supported formats: .mp3, m4a, .wav, + .mp4, .mov or .webm + + + + )} + {status && status == "uploaded" && ( + File is uploaded, processing... + )} + {(status == "recording" || status == "processing") && ( + <> + Processing your recording... + + You can safely return to the library while your file is being + processed. + + + + )} + +
+
+ + ); +}; + +export default TranscriptUpload; diff --git a/www/app/[domain]/transcripts/fileUploadButton.tsx b/www/app/[domain]/transcripts/fileUploadButton.tsx index 419245e2..3faba127 100644 --- a/www/app/[domain]/transcripts/fileUploadButton.tsx +++ b/www/app/[domain]/transcripts/fileUploadButton.tsx @@ -1,16 +1,15 @@ -import React from "react"; +import React, { useState } from "react"; import useApi from "../../lib/useApi"; -import { Button } from "@chakra-ui/react"; +import { Button, CircularProgress } from "@chakra-ui/react"; type FileUploadButton = { transcriptId: string; - disabled?: boolean; }; export default function FileUploadButton(props: FileUploadButton) { const fileInputRef = React.useRef(null); const api = useApi(); - + const [progress, setProgress] = useState(0); const triggerFileUpload = () => { fileInputRef.current?.click(); }; @@ -27,6 +26,12 @@ export default function FileUploadButton(props: FileUploadButton) { // Add other properties if required by the type definition }; + api?.httpRequest.config.interceptors.request.use((request) => { + request.onUploadProgress = (progressEvent) => { + setProgress((progressEvent.progress || 0) * 100); + }; + return request; + }); api?.v1TranscriptRecordUpload({ transcriptId: props.transcriptId, formData: uploadData, @@ -40,9 +45,16 @@ export default function FileUploadButton(props: FileUploadButton) { onClick={triggerFileUpload} colorScheme="blue" mr={2} - isDisabled={props.disabled} + isDisabled={progress > 0} > - Upload File + {progress > 0 && progress < 100 ? ( + <> + Uploading...  + + + ) : ( + <>Select File + )} { const router = useRouter(); const isAuthenticated = useFiefIsAuthenticated(); @@ -30,21 +30,29 @@ const TranscriptCreate = () => { const createTranscript = useCreateTranscript(); - const [loadingSend, setLoadingSend] = useState(false); + const [loadingRecord, setLoadingRecord] = useState(false); + const [loadingUpload, setLoadingUpload] = useState(false); const send = () => { - if (loadingSend || createTranscript.loading || permissionDenied) return; - setLoadingSend(true); + if (loadingRecord || createTranscript.loading || permissionDenied) return; + setLoadingRecord(true); + createTranscript.create({ name, target_language: targetLanguage }); + }; + + const uploadFile = () => { + if (loadingUpload || createTranscript.loading || permissionDenied) return; + setLoadingUpload(true); createTranscript.create({ name, target_language: targetLanguage }); }; useEffect(() => { + const action = loadingRecord ? "record" : "upload"; createTranscript.transcript && - router.push(`/transcripts/${createTranscript.transcript.id}/record`); + router.push(`/transcripts/${createTranscript.transcript.id}/${action}`); }, [createTranscript.transcript]); useEffect(() => { - if (createTranscript.error) setLoadingSend(false); + if (createTranscript.error) setLoadingRecord(false); }, [createTranscript.error]); const { loading, permissionOk, permissionDenied, requestPermission } = @@ -55,10 +63,7 @@ const TranscriptCreate = () => {
-

- Welcome to reflector.media -

- +

Welcome to Reflector

Reflector is a transcription and summarization pipeline that transforms audio into knowledge. @@ -101,7 +106,6 @@ const TranscriptCreate = () => { />

- - {loading ? (

Checking permissions...

) : permissionOk ? ( @@ -131,13 +134,23 @@ const TranscriptCreate = () => { Request Microphone Permission )} - + {loadingRecord ? "Loading..." : "Record Meeting"} + + + OR + +
)} diff --git a/www/app/[domain]/transcripts/recorder.tsx b/www/app/[domain]/transcripts/recorder.tsx index d583bb74..0f8b23cb 100644 --- a/www/app/[domain]/transcripts/recorder.tsx +++ b/www/app/[domain]/transcripts/recorder.tsx @@ -266,10 +266,6 @@ export default function Recorder(props: RecorderProps) { mr={2} onClick={handleRecClick} /> - {!isRecording && (window as any).chrome && (