Merge branch 'main' of github.com:Monadical-SAS/reflector into sara/feat-speaker-reassign

This commit is contained in:
Sara
2024-01-02 19:20:56 +01:00
77 changed files with 3827 additions and 4588 deletions

View File

@@ -66,18 +66,18 @@ export default function TranscriptBrowser() {
<></>
)}
{item.sourceLanguage ? (
{item.source_language ? (
<div className="inline-block bg-blue-500 text-white px-2 py-1 rounded-full text-xs font-semibold">
{item.sourceLanguage}
{item.source_language}
</div>
) : (
<></>
)}
</div>
<div className="text-xs text-gray-700">
{new Date(item.createdAt).toLocaleDateString("en-US")}
{new Date(item.created_at).toLocaleDateString("en-US")}
</div>
<div className="text-sm">{item.shortSummary}</div>
<div className="text-sm">{item.short_summary}</div>
</div>
</div>
))}

View File

@@ -19,6 +19,7 @@ import { Providers } from "../providers";
const poppins = Poppins({ subsets: ["latin"], weight: ["200", "400", "600"] });
export const metadata: Metadata = {
metadataBase: new URL(process.env.DEV_URL || "https://reflector.media"),
title: {
template: "%s Reflector",
default: "Reflector - AI-Powered Meeting Transcriptions by Monadical",
@@ -55,12 +56,6 @@ export const metadata: Metadata = {
shortcut: "/r-icon.png",
apple: "/r-icon.png",
},
viewport: {
width: "device-width",
initialScale: 1,
maximumScale: 1,
},
robots: { index: false, follow: false, noarchive: true, noimageindex: true },
};

View File

@@ -8,7 +8,7 @@ import useTopicWithWords from "../../useTopicWithWords";
import ParticipantList from "./participantList";
import { GetTranscriptTopic } from "../../../../api";
import { SelectedText, selectedTextIsTimeSlice } from "./types";
import getApi from "../../../../lib/getApi";
import useApi from "../../../../lib/useApi";
import useTranscript from "../../useTranscript";
import { useError } from "../../../../(errors)/errorContext";
import { useRouter } from "next/navigation";
@@ -23,7 +23,7 @@ export type TranscriptCorrect = {
export default function TranscriptCorrect({
params: { transcriptId },
}: TranscriptCorrect) {
const api = getApi();
const api = useApi();
const transcript = useTranscript(transcriptId);
const stateCurrentTopic = useState<GetTranscriptTopic>();
const [currentTopic, _sct] = stateCurrentTopic;
@@ -37,10 +37,7 @@ export default function TranscriptCorrect({
const markAsDone = () => {
if (transcript.response && !transcript.response.reviewed) {
api
?.v1TranscriptUpdate({
transcriptId,
updateTranscript: { reviewed: true },
})
?.v1TranscriptUpdate(transcriptId, { reviewed: true })
.then(() => {
router.push(`/transcripts/${transcriptId}`);
})
@@ -75,7 +72,7 @@ export default function TranscriptCorrect({
currentTopic
? {
start: currentTopic?.timestamp,
end: currentTopic?.timestamp + currentTopic?.duration,
end: currentTopic?.timestamp + (currentTopic?.duration || 0),
}
: undefined
}

View File

@@ -2,7 +2,7 @@ import { faArrowTurnDown, faSpinner } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { ChangeEvent, useEffect, useRef, useState } from "react";
import { Participant } from "../../../../api";
import getApi from "../../../../lib/getApi";
import useApi from "../../../../lib/useApi";
import { UseParticipants } from "../../useParticipants";
import { selectedTextIsSpeaker, selectedTextIsTimeSlice } from "./types";
import { useError } from "../../../../(errors)/errorContext";
@@ -31,7 +31,7 @@ const ParticipantList = ({
topicWithWords,
stateSelectedText,
}: ParticipantList) => {
const api = getApi();
const api = useApi();
const { setError } = useError();
const [loading, setLoading] = useState(false);
const [participantInput, setParticipantInput] = useState("");
@@ -123,13 +123,10 @@ const ParticipantList = ({
setLoading(true);
try {
await api?.v1TranscriptAssignSpeaker({
speakerAssignment: {
participant: participant.id,
timestampFrom: selectedText.start,
timestampTo: selectedText.end,
},
transcriptId,
await api?.v1TranscriptAssignSpeaker(transcriptId, {
participant: participant.id,
timestamp_from: selectedText.start,
timestamp_to: selectedText.end,
});
onSuccess();
} catch (error) {
@@ -145,12 +142,9 @@ const ParticipantList = ({
setLoading(true);
if (participantTo.speaker) {
try {
await api?.v1TranscriptMergeSpeaker({
transcriptId,
speakerMerge: {
speakerFrom: speakerFrom,
speakerTo: participantTo.speaker,
},
await api?.v1TranscriptMergeSpeaker(transcriptId, {
speaker_from: speakerFrom,
speaker_to: participantTo.speaker,
});
onSuccess();
} catch (error) {
@@ -159,11 +153,11 @@ const ParticipantList = ({
}
} else {
try {
await api?.v1TranscriptUpdateParticipant({
await api?.v1TranscriptUpdateParticipant(
transcriptId,
participantId: participantTo.id,
updateParticipant: { speaker: speakerFrom },
});
participantTo.id,
{ speaker: speakerFrom },
);
onSuccess();
} catch (error) {
setError(error, "There was an error merging (update)");
@@ -189,12 +183,8 @@ const ParticipantList = ({
if (participant && participant.name !== participantInput) {
setLoading(true);
api
?.v1TranscriptUpdateParticipant({
participantId: participant.id,
transcriptId,
updateParticipant: {
name: participantInput,
},
?.v1TranscriptUpdateParticipant(participant.id, transcriptId, {
name: participantInput,
})
.then(() => {
participants.refetch();
@@ -212,12 +202,9 @@ const ParticipantList = ({
) {
setLoading(true);
api
?.v1TranscriptAddParticipant({
createParticipant: {
name: participantInput,
speaker: selectedText,
},
transcriptId,
?.v1TranscriptAddParticipant(transcriptId, {
name: participantInput,
speaker: selectedText,
})
.then(() => {
participants.refetch();
@@ -235,12 +222,12 @@ const ParticipantList = ({
) {
setLoading(true);
try {
const participant = await api?.v1TranscriptAddParticipant({
createParticipant: {
const participant = await api?.v1TranscriptAddParticipant(
transcriptId,
{
name: participantInput,
},
transcriptId,
});
);
setLoading(false);
assignTo(participant)().catch(() => {
// error and loading are handled by assignTo catch
@@ -253,11 +240,8 @@ const ParticipantList = ({
} else if (action == "Create") {
setLoading(true);
api
?.v1TranscriptAddParticipant({
createParticipant: {
name: participantInput,
},
transcriptId,
?.v1TranscriptAddParticipant(transcriptId, {
name: participantInput,
})
.then(() => {
participants.refetch();
@@ -277,10 +261,7 @@ const ParticipantList = ({
if (loading || participants.loading || topicWithWords.loading) return;
setLoading(true);
api
?.v1TranscriptDeleteParticipant({
transcriptId,
participantId,
})
?.v1TranscriptDeleteParticipant(transcriptId, participantId)
.then(() => {
participants.refetch();
setLoading(false);

View File

@@ -9,9 +9,7 @@ import {
Kbd,
Skeleton,
SkeletonCircle,
chakra,
Flex,
Center,
} from "@chakra-ui/react";
import { ChevronLeftIcon, ChevronRightIcon } from "@chakra-ui/icons";

View File

@@ -11,7 +11,6 @@ import {
WrapItem,
Kbd,
Skeleton,
chakra,
} from "@chakra-ui/react";
type TopicPlayer = {

View File

@@ -3,14 +3,7 @@ import WaveformLoading from "../../waveformLoading";
import { UseParticipants } from "../../useParticipants";
import { UseTopicWithWords } from "../../useTopicWithWords";
import { TimeSlice, selectedTextIsTimeSlice } from "./types";
import {
BoxProps,
Box,
Container,
Text,
chakra,
Spinner,
} from "@chakra-ui/react";
import { BoxProps, Box, Container, Text, Spinner } from "@chakra-ui/react";
type TopicWordsProps = {
stateSelectedText: [
@@ -167,7 +160,7 @@ const topicWords = ({
maxW={{ lg: "container.md" }}
{...chakraProps}
>
{topicWithWords.response.wordsPerSpeaker.map(
{topicWithWords.response.words_per_speaker?.map(
(speakerWithWords, index) => (
<Text key={index} className="mb-2 last:mb-0">
<Box

View File

@@ -17,6 +17,7 @@ import Player from "../player";
import WaveformLoading from "../waveformLoading";
import { useRouter } from "next/navigation";
import { featureEnabled } from "../../domainContext";
import { toShareMode } from "../../../lib/shareMode";
type TranscriptDetails = {
params: {
@@ -37,7 +38,7 @@ export default function TranscriptDetails(details: TranscriptDetails) {
useEffect(() => {
const statusToRedirect = ["idle", "recording", "processing"];
if (statusToRedirect.includes(transcript.response?.status)) {
if (statusToRedirect.includes(transcript.response?.status || "")) {
const newUrl = "/transcripts/" + details.params.transcriptId + "/record";
// Shallow redirection does not work on NextJS 13
// https://github.com/vercel/next.js/discussions/48110
@@ -88,7 +89,7 @@ export default function TranscriptDetails(details: TranscriptDetails) {
<Player
topics={topics?.topics || []}
useActiveTopic={useActiveTopic}
waveform={waveform.waveform.data}
waveform={waveform.waveform}
media={mp3.media}
mediaDuration={transcript.response.duration}
/>
@@ -108,10 +109,10 @@ export default function TranscriptDetails(details: TranscriptDetails) {
<div className="w-full h-full grid grid-rows-layout-one grid-cols-1 gap-2 lg:gap-4">
<section className=" bg-blue-400/20 rounded-lg md:rounded-xl p-2 md:px-4 h-full">
{transcript.response.longSummary ? (
{transcript.response.long_summary ? (
<FinalSummary
fullTranscript={fullTranscript}
summary={transcript.response.longSummary}
summary={transcript.response.long_summary}
transcriptId={transcript.response.id}
openZulipModal={() => setShowModal(true)}
/>
@@ -139,9 +140,9 @@ export default function TranscriptDetails(details: TranscriptDetails) {
</div>
<div className="flex-grow max-w-full">
<ShareLink
transcriptId={transcript?.response?.id}
userId={transcript?.response?.userId}
shareMode={transcript?.response?.shareMode}
transcriptId={transcript.response.id}
userId={transcript.response.user_id}
shareMode={toShareMode(transcript.response.share_mode)}
/>
</div>
</section>

View File

@@ -62,8 +62,9 @@ const TranscriptRecord = (details: TranscriptDetails) => {
//TODO if has no topic and is error, get back to new
if (
statusToRedirect.includes(transcript.response?.status) ||
statusToRedirect.includes(webSockets.status.value)
transcript.response?.status &&
(statusToRedirect.includes(transcript.response?.status) ||
statusToRedirect.includes(webSockets.status.value))
) {
const newUrl = "/transcripts/" + details.params.transcriptId;
// Shallow redirection does not work on NextJS 13
@@ -75,10 +76,8 @@ const TranscriptRecord = (details: TranscriptDetails) => {
}, [webSockets.status.value, transcript.response?.status]);
useEffect(() => {
if (webSockets.duration) {
mp3.getNow();
}
}, [webSockets.duration]);
if (transcript.response?.status === "ended") mp3.getNow();
}, [transcript.response]);
useEffect(() => {
lockWakeState();
@@ -112,6 +111,7 @@ const TranscriptRecord = (details: TranscriptDetails) => {
}}
getAudioStream={getAudioStream}
audioDevices={audioDevices}
transcriptId={details.params.transcriptId}
/>
)}

View File

@@ -1,48 +1,32 @@
import { useEffect, useState } from "react";
import {
DefaultApi,
V1TranscriptsCreateRequest,
} from "../../api/apis/DefaultApi";
import { GetTranscript } from "../../api";
import { useState } from "react";
import { useError } from "../../(errors)/errorContext";
import getApi from "../../lib/getApi";
import { GetTranscript, CreateTranscript } from "../../api";
import useApi from "../../lib/useApi";
type CreateTranscript = {
response: GetTranscript | null;
type UseTranscript = {
transcript: GetTranscript | null;
loading: boolean;
error: Error | null;
create: (params: V1TranscriptsCreateRequest["createTranscript"]) => void;
create: (transcriptCreationDetails: CreateTranscript) => void;
};
const useCreateTranscript = (): CreateTranscript => {
const [response, setResponse] = useState<GetTranscript | null>(null);
const useCreateTranscript = (): UseTranscript => {
const [transcript, setTranscript] = useState<GetTranscript | null>(null);
const [loading, setLoading] = useState<boolean>(false);
const [error, setErrorState] = useState<Error | null>(null);
const { setError } = useError();
const api = getApi();
const api = useApi();
const create = (params: V1TranscriptsCreateRequest["createTranscript"]) => {
const create = (transcriptCreationDetails: CreateTranscript) => {
if (loading || !api) return;
setLoading(true);
const requestParameters: V1TranscriptsCreateRequest = {
createTranscript: {
name: params.name || "Unnamed Transcript", // Default
targetLanguage: params.targetLanguage || "en", // Default
},
};
console.debug(
"POST - /v1/transcripts/ - Requesting new transcription creation",
requestParameters,
);
api
.v1TranscriptsCreate(requestParameters)
.then((result) => {
setResponse(result);
.v1TranscriptsCreate(transcriptCreationDetails)
.then((transcript) => {
setTranscript(transcript);
setLoading(false);
console.debug("New transcript created:", result);
})
.catch((err) => {
setError(
@@ -54,7 +38,7 @@ const useCreateTranscript = (): CreateTranscript => {
});
};
return { response, loading, error, create };
return { transcript, loading, error, create };
};
export default useCreateTranscript;

View File

@@ -0,0 +1,50 @@
import React from "react";
import useApi from "../../lib/useApi";
import { Body_transcript_record_upload_v1_transcripts__transcript_id__record_upload_post } from "../../api";
type FileUploadButton = {
transcriptId: string;
};
export default function FileUploadButton(props: FileUploadButton) {
const fileInputRef = React.useRef<HTMLInputElement>(null);
const api = useApi();
const triggerFileUpload = () => {
fileInputRef.current?.click();
};
const handleFileUpload = (event: React.ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0];
if (file) {
console.log("Calling api.v1TranscriptRecordUpload()...");
// Create an object of the expected type
const uploadData = {
file: file,
// Add other properties if required by the type definition
};
api?.v1TranscriptRecordUpload(props.transcriptId, uploadData);
}
};
return (
<>
<button
className="bg-blue-400 hover:bg-blue-500 focus-visible:bg-blue-500 text-white ml-2 md:ml:4 md:h-[78px] md:min-w-[100px] text-lg"
onClick={triggerFileUpload}
>
Upload File
</button>
<input
type="file"
ref={fileInputRef}
style={{ display: "none" }}
onChange={handleFileUpload}
/>
</>
);
}

View File

@@ -2,8 +2,9 @@ import { useRef, useState } from "react";
import React from "react";
import Markdown from "react-markdown";
import "../../styles/markdown.css";
import getApi from "../../lib/getApi";
import { featureEnabled } from "../domainContext";
import { UpdateTranscript } from "../../api";
import useApi from "../../lib/useApi";
type FinalSummaryProps = {
summary: string;
@@ -19,17 +20,17 @@ export default function FinalSummary(props: FinalSummaryProps) {
const [isEditMode, setIsEditMode] = useState(false);
const [preEditSummary, setPreEditSummary] = useState(props.summary);
const [editedSummary, setEditedSummary] = useState(props.summary);
const api = getApi();
const updateSummary = async (newSummary: string, transcriptId: string) => {
if (!api) return;
try {
const updatedTranscript = await api.v1TranscriptUpdate({
const api = useApi();
const requestBody: UpdateTranscript = {
long_summary: newSummary,
};
const updatedTranscript = await api?.v1TranscriptUpdate(
transcriptId,
updateTranscript: {
longSummary: newSummary,
},
});
requestBody,
);
console.log("Updated long summary:", updatedTranscript);
} catch (err) {
console.error("Failed to update long summary:", err);

View File

@@ -18,7 +18,7 @@ const TranscriptCreate = () => {
const isAuthenticated = useFiefIsAuthenticated();
const requireLogin = featureEnabled("requireLogin");
const [name, setName] = useState<string>();
const [name, setName] = useState<string>("");
const nameChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setName(event.target.value);
};
@@ -35,13 +35,13 @@ const TranscriptCreate = () => {
const send = () => {
if (loadingSend || createTranscript.loading || permissionDenied) return;
setLoadingSend(true);
createTranscript.create({ name, targetLanguage });
createTranscript.create({ name, target_language: targetLanguage });
};
useEffect(() => {
createTranscript.response &&
router.push(`/transcripts/${createTranscript.response.id}/record`);
}, [createTranscript.response]);
createTranscript.transcript &&
router.push(`/transcripts/${createTranscript.transcript.id}/record`);
}, [createTranscript.transcript]);
useEffect(() => {
if (createTranscript.error) setLoadingSend(false);
@@ -58,6 +58,7 @@ const TranscriptCreate = () => {
<h1 className="text-2xl font-bold mb-2">
Welcome to reflector.media
</h1>
<button>Test upload</button>
<p>
Reflector is a transcription and summarization pipeline that
transforms audio into knowledge.

View File

@@ -14,7 +14,7 @@ type PlayerProps = {
Topic | null,
React.Dispatch<React.SetStateAction<Topic | null>>,
];
waveform: AudioWaveform["data"];
waveform: AudioWaveform;
media: HTMLMediaElement;
mediaDuration: number;
};

View File

@@ -12,6 +12,7 @@ import AudioInputsDropdown from "./audioInputsDropdown";
import { Option } from "react-dropdown";
import { waveSurferStyles } from "../../styles/recorder";
import { useError } from "../../(errors)/errorContext";
import FileUploadButton from "./fileUploadButton";
type RecorderProps = {
setStream: React.Dispatch<React.SetStateAction<MediaStream | null>>;
@@ -19,6 +20,7 @@ type RecorderProps = {
onRecord?: () => void;
getAudioStream: (deviceId) => Promise<MediaStream | null>;
audioDevices: Option[];
transcriptId: string;
};
export default function Recorder(props: RecorderProps) {
@@ -307,6 +309,11 @@ export default function Recorder(props: RecorderProps) {
>
{isRecording ? "Stop" : "Record"}
</button>
<FileUploadButton
transcriptId={props.transcriptId}
></FileUploadButton>
{!isRecording && (
<button
className={`${

View File

@@ -1,6 +1,5 @@
import React, { useState, useRef, useEffect, use } from "react";
import { featureEnabled } from "../domainContext";
import getApi from "../../lib/getApi";
import { useFiefUserinfo } from "@fief/fief/nextjs/react";
import SelectSearch from "react-select-search";
import "react-select-search/style.css";
@@ -8,11 +7,13 @@ import "../../styles/button.css";
import "../../styles/form.scss";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faSpinner } from "@fortawesome/free-solid-svg-icons";
import { UpdateTranscript } from "../../api";
import { ShareMode, toShareMode } from "../../lib/shareMode";
import useApi from "../../lib/useApi";
type ShareLinkProps = {
transcriptId: string;
userId: string | null;
shareMode: string;
shareMode: ShareMode;
};
const ShareLink = (props: ShareLinkProps) => {
@@ -21,10 +22,10 @@ const ShareLink = (props: ShareLinkProps) => {
const [currentUrl, setCurrentUrl] = useState<string>("");
const requireLogin = featureEnabled("requireLogin");
const [isOwner, setIsOwner] = useState(false);
const [shareMode, setShareMode] = useState(props.shareMode);
const [shareMode, setShareMode] = useState<ShareMode>(props.shareMode);
const [shareLoading, setShareLoading] = useState(false);
const userinfo = useFiefUserinfo();
const api = getApi();
const api = useApi();
useEffect(() => {
setCurrentUrl(window.location.href);
@@ -48,15 +49,19 @@ const ShareLink = (props: ShareLinkProps) => {
};
const updateShareMode = async (selectedShareMode: string) => {
if (!api) return;
if (!api)
throw new Error("ShareLink's API should always be ready at this point");
setShareLoading(true);
const updatedTranscript = await api.v1TranscriptUpdate({
transcriptId: props.transcriptId,
updateTranscript: {
shareMode: selectedShareMode,
},
});
setShareMode(updatedTranscript.shareMode);
const requestBody: UpdateTranscript = {
share_mode: toShareMode(selectedShareMode),
};
const updatedTranscript = await api.v1TranscriptUpdate(
props.transcriptId,
requestBody,
);
setShareMode(toShareMode(updatedTranscript.share_mode));
setShareLoading(false);
};
const privacyEnabled = featureEnabled("privacy");
@@ -89,7 +94,7 @@ const ShareLink = (props: ShareLinkProps) => {
{ name: "Secure", value: "semi-private" },
{ name: "Public", value: "public" },
]}
value={shareMode}
value={shareMode?.toString()}
onChange={updateShareMode}
closeOnSelect={true}
/>

View File

@@ -1,5 +1,6 @@
import { useState } from "react";
import getApi from "../../lib/getApi";
import { UpdateTranscript } from "../../api";
import useApi from "../../lib/useApi";
type TranscriptTitle = {
title: string;
@@ -10,17 +11,19 @@ const TranscriptTitle = (props: TranscriptTitle) => {
const [displayedTitle, setDisplayedTitle] = useState(props.title);
const [preEditTitle, setPreEditTitle] = useState(props.title);
const [isEditing, setIsEditing] = useState(false);
const api = getApi();
const api = useApi();
const updateTitle = async (newTitle: string, transcriptId: string) => {
if (!api) return;
try {
const updatedTranscript = await api.v1TranscriptUpdate({
const requestBody: UpdateTranscript = {
title: newTitle,
};
const api = useApi();
const updatedTranscript = await api?.v1TranscriptUpdate(
transcriptId,
updateTranscript: {
title: newTitle,
},
});
requestBody,
);
console.log("Updated transcript:", updatedTranscript);
} catch (err) {
console.error("Failed to update transcript:", err);

View File

@@ -1,6 +1,6 @@
import { useContext, useEffect, useState } from "react";
import { DomainContext } from "../domainContext";
import getApi from "../../lib/getApi";
import getApi from "../../lib/useApi";
import { useFiefAccessTokenInfo } from "@fief/fief/build/esm/nextjs/react";
export type Mp3Response = {

View File

@@ -1,8 +1,7 @@
import { useEffect, useState } from "react";
import { V1TranscriptGetParticipantsRequest } from "../../api/apis/DefaultApi";
import { GetTranscript, Participant } from "../../api";
import { Participant } from "../../api";
import { useError } from "../../(errors)/errorContext";
import getApi from "../../lib/getApi";
import useApi from "../../lib/useApi";
import { shouldShowError } from "../../lib/errorUtils";
type ErrorParticipants = {
@@ -34,7 +33,7 @@ const useParticipants = (transcriptId: string): UseParticipants => {
const [loading, setLoading] = useState<boolean>(true);
const [error, setErrorState] = useState<Error | null>(null);
const { setError } = useError();
const api = getApi();
const api = useApi();
const [count, setCount] = useState(0);
const refetch = () => {
@@ -49,11 +48,8 @@ const useParticipants = (transcriptId: string): UseParticipants => {
if (!transcriptId || !api) return;
setLoading(true);
const requestParameters: V1TranscriptGetParticipantsRequest = {
transcriptId,
};
api
.v1TranscriptGetParticipants(requestParameters)
.v1TranscriptGetParticipants(transcriptId)
.then((result) => {
setResponse(result);
setLoading(false);

View File

@@ -1,15 +1,8 @@
import { useEffect, useState } from "react";
import {
V1TranscriptGetTopicsWithWordsPerSpeakerRequest,
V1TranscriptGetTopicsWithWordsRequest,
} from "../../api/apis/DefaultApi";
import {
GetTranscript,
GetTranscriptTopicWithWords,
GetTranscriptTopicWithWordsPerSpeaker,
} from "../../api";
import { GetTranscriptTopicWithWordsPerSpeaker } from "../../api";
import { useError } from "../../(errors)/errorContext";
import getApi from "../../lib/getApi";
import useApi from "../../lib/useApi";
import { shouldShowError } from "../../lib/errorUtils";
type ErrorTopicWithWords = {
@@ -37,7 +30,7 @@ export type UseTopicWithWords = { refetch: () => void } & (
);
const useTopicWithWords = (
topicId: string | null,
topicId: string | undefined,
transcriptId: string,
): UseTopicWithWords => {
const [response, setResponse] =
@@ -45,7 +38,7 @@ const useTopicWithWords = (
const [loading, setLoading] = useState<boolean>(false);
const [error, setErrorState] = useState<Error | null>(null);
const { setError } = useError();
const api = getApi();
const api = useApi();
const [count, setCount] = useState(0);
@@ -61,12 +54,9 @@ const useTopicWithWords = (
if (!transcriptId || !topicId || !api) return;
setLoading(true);
const requestParameters: V1TranscriptGetTopicsWithWordsPerSpeakerRequest = {
transcriptId,
topicId,
};
api
.v1TranscriptGetTopicsWithWordsPerSpeaker(requestParameters)
.v1TranscriptGetTopicsWithWordsPerSpeaker(transcriptId, topicId)
.then((result) => {
setResponse(result);
setLoading(false);

View File

@@ -1,10 +1,9 @@
import { useEffect, useState } from "react";
import { V1TranscriptGetTopicsRequest } from "../../api/apis/DefaultApi";
import { useError } from "../../(errors)/errorContext";
import { Topic } from "./webSocketTypes";
import getApi from "../../lib/getApi";
import useApi from "../../lib/useApi";
import { shouldShowError } from "../../lib/errorUtils";
import mockTopics from "./mockTopics.json";
import { GetTranscriptTopic } from "../../api";
type TranscriptTopics = {
@@ -18,25 +17,14 @@ const useTopics = (id: string): TranscriptTopics => {
const [loading, setLoading] = useState<boolean>(true);
const [error, setErrorState] = useState<Error | null>(null);
const { setError } = useError();
const api = getApi();
useEffect(() => {
document.onkeyup = (e) => {
if (e.key === "t" && process.env.NEXT_PUBLIC_ENV === "development") {
setTopics(mockTopics);
}
};
});
const api = useApi();
useEffect(() => {
if (!id || !api) return;
setLoading(true);
const requestParameters: V1TranscriptGetTopicsRequest = {
transcriptId: id,
};
api
.v1TranscriptGetTopics(requestParameters)
.v1TranscriptGetTopics(id)
.then((result) => {
setTopics(result);
setLoading(false);

View File

@@ -1,9 +1,8 @@
import { useEffect, useState } from "react";
import { V1TranscriptGetRequest } from "../../api/apis/DefaultApi";
import { GetTranscript } from "../../api";
import { useError } from "../../(errors)/errorContext";
import getApi from "../../lib/getApi";
import { shouldShowError } from "../../lib/errorUtils";
import useApi from "../../lib/useApi";
type ErrorTranscript = {
error: Error;
@@ -30,17 +29,15 @@ const useTranscript = (
const [loading, setLoading] = useState<boolean>(true);
const [error, setErrorState] = useState<Error | null>(null);
const { setError } = useError();
const api = getApi();
const api = useApi();
useEffect(() => {
if (!id || !api) return;
setLoading(true);
const requestParameters: V1TranscriptGetRequest = {
transcriptId: id,
};
api
.v1TranscriptGet(requestParameters)
.v1TranscriptGet(id)
.then((result) => {
setResponse(result);
setLoading(false);

View File

@@ -1,32 +1,28 @@
import { useEffect, useState } from "react";
import { GetTranscriptFromJSON, PageGetTranscript } from "../../api";
import { useError } from "../../(errors)/errorContext";
import getApi from "../../lib/getApi";
import useApi from "../../lib/useApi";
import { Page_GetTranscript_ } from "../../api";
type TranscriptList = {
response: PageGetTranscript | null;
response: Page_GetTranscript_ | null;
loading: boolean;
error: Error | null;
};
//always protected
const useTranscriptList = (page: number): TranscriptList => {
const [response, setResponse] = useState<PageGetTranscript | null>(null);
const [response, setResponse] = useState<Page_GetTranscript_ | null>(null);
const [loading, setLoading] = useState<boolean>(true);
const [error, setErrorState] = useState<Error | null>(null);
const { setError } = useError();
const api = getApi();
const api = useApi();
useEffect(() => {
if (!api) return;
setLoading(true);
api
.v1TranscriptsList({ page })
.v1TranscriptsList(page)
.then((response) => {
// issue with API layer, conversion for items is not happening
response.items = response.items.map((item) =>
GetTranscriptFromJSON(item),
);
setResponse(response);
setLoading(false);
})

View File

@@ -1,8 +1,7 @@
import { useEffect, useState } from "react";
import { V1TranscriptGetAudioWaveformRequest } from "../../api/apis/DefaultApi";
import { AudioWaveform } from "../../api";
import { useError } from "../../(errors)/errorContext";
import getApi from "../../lib/getApi";
import useApi from "../../lib/useApi";
import { shouldShowError } from "../../lib/errorUtils";
type AudioWaveFormResponse = {
@@ -16,16 +15,13 @@ const useWaveform = (id: string): AudioWaveFormResponse => {
const [loading, setLoading] = useState<boolean>(true);
const [error, setErrorState] = useState<Error | null>(null);
const { setError } = useError();
const api = getApi();
const api = useApi();
useEffect(() => {
if (!id || !api) return;
setLoading(true);
const requestParameters: V1TranscriptGetAudioWaveformRequest = {
transcriptId: id,
};
api
.v1TranscriptGetAudioWaveform(requestParameters)
.v1TranscriptGetAudioWaveform(id)
.then((result) => {
setWaveform(result);
setLoading(false);

View File

@@ -1,11 +1,8 @@
import { useEffect, useState } from "react";
import Peer from "simple-peer";
import {
DefaultApi,
V1TranscriptRecordWebrtcRequest,
} from "../../api/apis/DefaultApi";
import { useError } from "../../(errors)/errorContext";
import getApi from "../../lib/getApi";
import useApi from "../../lib/useApi";
import { RtcOffer } from "../../api";
const useWebRTC = (
stream: MediaStream | null,
@@ -13,7 +10,7 @@ const useWebRTC = (
): Peer => {
const [peer, setPeer] = useState<Peer | null>(null);
const { setError } = useError();
const api = getApi();
const api = useApi();
useEffect(() => {
if (!stream || !transcriptId) {
@@ -38,16 +35,13 @@ const useWebRTC = (
p.on("signal", (data: any) => {
if (!api) return;
if ("sdp" in data) {
const requestParameters: V1TranscriptRecordWebrtcRequest = {
transcriptId: transcriptId,
rtcOffer: {
sdp: data.sdp,
type: data.type,
},
const rtcOffer: RtcOffer = {
sdp: data.sdp,
type: data.type,
};
api
.v1TranscriptRecordWebrtc(requestParameters)
.v1TranscriptRecordWebrtc(transcriptId, rtcOffer)
.then((answer) => {
try {
p.signal(answer);

View File

@@ -2,7 +2,8 @@ import { useContext, useEffect, useState } from "react";
import { Topic, FinalSummary, Status } from "./webSocketTypes";
import { useError } from "../../(errors)/errorContext";
import { DomainContext } from "../domainContext";
import { AudioWaveform } from "../../api";
import { AudioWaveform, GetTranscriptSegmentTopic } from "../../api";
import useApi from "../../lib/useApi";
export type UseWebSockets = {
transcriptText: string;
@@ -11,7 +12,7 @@ export type UseWebSockets = {
topics: Topic[];
finalSummary: FinalSummary;
status: Status;
waveform: AudioWaveform["data"] | null;
waveform: AudioWaveform | null;
duration: number | null;
};
@@ -32,6 +33,7 @@ export const useWebSockets = (transcriptId: string | null): UseWebSockets => {
const { setError } = useError();
const { websocket_url } = useContext(DomainContext);
const api = useApi();
useEffect(() => {
if (isProcessing || textQueue.length === 0) {
@@ -57,6 +59,39 @@ export const useWebSockets = (transcriptId: string | null): UseWebSockets => {
useEffect(() => {
document.onkeyup = (e) => {
if (e.key === "a" && process.env.NEXT_PUBLIC_ENV === "development") {
const segments: GetTranscriptSegmentTopic[] = [
{
speaker: 1,
start: 0,
text: "This is the transcription of an example title",
},
{
speaker: 2,
start: 10,
text: "This is the second speaker",
},
{
speaker: 3,
start: 90,
text: "This is the third speaker",
},
{
speaker: 4,
start: 90,
text: "This is the fourth speaker",
},
{
speaker: 5,
start: 123,
text: "This is the fifth speaker",
},
{
speaker: 6,
start: 300,
text: "This is the sixth speaker",
},
];
setTranscriptText("Lorem Ipsum");
setTopics([
{
@@ -67,39 +102,6 @@ export const useWebSockets = (transcriptId: string | null): UseWebSockets => {
title: "Topic 1: Introduction to Quantum Mechanics",
transcript:
"A brief overview of quantum mechanics and its principles.",
segments: [
{
speaker: 1,
start: 0,
text: "This is the transcription of an example title",
},
{
speaker: 2,
start: 10,
text: "This is the second speaker",
},
,
{
speaker: 3,
start: 90,
text: "This is the third speaker",
},
{
speaker: 4,
start: 90,
text: "This is the fourth speaker",
},
{
speaker: 5,
start: 123,
text: "This is the fifth speaker",
},
{
speaker: 6,
start: 300,
text: "This is the sixth speaker",
},
],
},
{
id: "2",
@@ -306,7 +308,9 @@ export const useWebSockets = (transcriptId: string | null): UseWebSockets => {
}
};
if (!transcriptId) return;
if (!transcriptId || !api) return;
api?.v1TranscriptGetWebsocketEvents(transcriptId).then((result) => {});
const url = `${websocket_url}/v1/transcripts/${transcriptId}/events`;
let ws = new WebSocket(url);
@@ -412,7 +416,9 @@ export const useWebSockets = (transcriptId: string | null): UseWebSockets => {
console.debug("WebSocket connection closed");
switch (event.code) {
case 1000: // Normal Closure:
break;
case 1005: // Closure by client FF
break;
default:
setError(
new Error(`WebSocket closed unexpectedly with code: ${event.code}`),
@@ -431,7 +437,7 @@ export const useWebSockets = (transcriptId: string | null): UseWebSockets => {
return () => {
ws.close();
};
}, [transcriptId]);
}, [transcriptId, !api]);
return {
transcriptText,