mirror of
https://github.com/Monadical-SAS/reflector.git
synced 2025-12-20 20:29:06 +00:00
get participant list, select speaker
This commit is contained in:
@@ -4,6 +4,8 @@ import useTranscript from "../../useTranscript";
|
||||
import TopicHeader from "./topicHeader";
|
||||
import TopicWords from "./topicWords";
|
||||
import TopicPlayer from "./topicPlayer";
|
||||
import getApi from "../../../../lib/getApi";
|
||||
import useParticipants from "../../useParticipants";
|
||||
|
||||
type TranscriptCorrect = {
|
||||
params: {
|
||||
@@ -22,6 +24,9 @@ export default function TranscriptCorrect(details: TranscriptCorrect) {
|
||||
const [currentTopic, setCurrentTopic] = useState("");
|
||||
const [selectedTime, setSelectedTime] = useState<TimeSlice>();
|
||||
const [topicTime, setTopicTime] = useState<TimeSlice>();
|
||||
const api = getApi();
|
||||
const participants = useParticipants(transcriptId);
|
||||
const stateSelectedSpeaker = useState<number>();
|
||||
|
||||
// TODO BE
|
||||
// Get one topic with words
|
||||
@@ -30,6 +35,14 @@ export default function TranscriptCorrect(details: TranscriptCorrect) {
|
||||
// -> use full current topic instead of topicId here
|
||||
// -> remove time calculation and setting from TopicHeader
|
||||
// -> pass in topicTime to player directly
|
||||
// Should we have participants by default, one for each speaker ?
|
||||
|
||||
const createParticipant = () => {
|
||||
api?.v1TranscriptAddParticipant({
|
||||
createParticipant: { name: "Samantha" },
|
||||
transcriptId,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="h-full grid grid-cols-2 gap-4">
|
||||
@@ -44,6 +57,8 @@ export default function TranscriptCorrect(details: TranscriptCorrect) {
|
||||
currentTopic={currentTopic}
|
||||
transcriptId={transcriptId}
|
||||
setTopicTime={setTopicTime}
|
||||
stateSelectedSpeaker={stateSelectedSpeaker}
|
||||
participants={participants}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
@@ -52,6 +67,7 @@ export default function TranscriptCorrect(details: TranscriptCorrect) {
|
||||
selectedTime={selectedTime}
|
||||
topicTime={topicTime}
|
||||
/>
|
||||
<button onClick={createParticipant}>Create</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -8,6 +8,8 @@ const TopicPlayer = ({ transcriptId, selectedTime, topicTime }) => {
|
||||
const [endSelectionCallback, setEndSelectionCallback] =
|
||||
useState<() => void>();
|
||||
|
||||
//TODO shortcuts
|
||||
|
||||
useEffect(() => {
|
||||
setEndTopicCallback(
|
||||
() =>
|
||||
@@ -29,7 +31,6 @@ const TopicPlayer = ({ transcriptId, selectedTime, topicTime }) => {
|
||||
}, [topicTime]);
|
||||
|
||||
useEffect(() => {
|
||||
console.log(endTopicCallback, "he");
|
||||
endTopicCallback &&
|
||||
mp3.media &&
|
||||
mp3.media.addEventListener("timeupdate", endTopicCallback);
|
||||
@@ -77,7 +78,6 @@ const TopicPlayer = ({ transcriptId, selectedTime, topicTime }) => {
|
||||
endSelectionCallback &&
|
||||
mp3.media &&
|
||||
mp3.media.addEventListener("timeupdate", endSelectionCallback);
|
||||
console.log(endSelectionCallback, "hi");
|
||||
return () => {
|
||||
endSelectionCallback &&
|
||||
mp3.media &&
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import useTopicWithWords from "../../useTopicWithWords";
|
||||
import WaveformLoading from "../../waveformLoading";
|
||||
|
||||
@@ -11,14 +11,21 @@ type Word = {
|
||||
|
||||
type WordBySpeaker = { speaker: number; words: Word[] }[];
|
||||
|
||||
// TODO fix selection reversed
|
||||
// TODO shortcuts
|
||||
// TODO fix key (using indexes might act up, not sure as we don't re-order per say)
|
||||
|
||||
const topicWords = ({
|
||||
setSelectedTime,
|
||||
currentTopic,
|
||||
transcriptId,
|
||||
setTopicTime,
|
||||
stateSelectedSpeaker,
|
||||
participants,
|
||||
}) => {
|
||||
const topicWithWords = useTopicWithWords(currentTopic, transcriptId);
|
||||
const [wordsBySpeaker, setWordsBySpeaker] = useState<WordBySpeaker>();
|
||||
const [selectedSpeaker, setSelectedSpeaker] = stateSelectedSpeaker;
|
||||
|
||||
useEffect(() => {
|
||||
if (topicWithWords.loading) {
|
||||
@@ -72,6 +79,7 @@ const topicWords = ({
|
||||
const focusOffset = focusIsWord
|
||||
? focusNode.textContent?.length
|
||||
: focusNode.parentNode?.lastChild?.textContent?.length;
|
||||
|
||||
if (
|
||||
correctedAnchor &&
|
||||
anchorOffset !== undefined &&
|
||||
@@ -84,20 +92,32 @@ const topicWords = ({
|
||||
correctedfocus,
|
||||
focusOffset,
|
||||
);
|
||||
setSelectedTime({
|
||||
start:
|
||||
selection.anchorNode.parentElement?.dataset["start"] ||
|
||||
(selection.anchorNode.parentElement?.nextElementSibling as any)
|
||||
?.dataset["start"] ||
|
||||
0,
|
||||
end:
|
||||
selection.focusNode.parentElement?.dataset["end"] ||
|
||||
(
|
||||
selection.focusNode.parentElement?.parentElement
|
||||
?.previousElementSibling?.lastElementChild as any
|
||||
)?.dataset ||
|
||||
0,
|
||||
});
|
||||
|
||||
if (
|
||||
!anchorIsWord &&
|
||||
!focusIsWord &&
|
||||
anchorNode.parentElement == focusNode.parentElement
|
||||
) {
|
||||
console.log(focusNode.parentElement?.dataset);
|
||||
setSelectedSpeaker(focusNode.parentElement?.dataset["speaker"]);
|
||||
setSelectedTime(undefined);
|
||||
} else {
|
||||
setSelectedSpeaker(undefined);
|
||||
setSelectedTime({
|
||||
start:
|
||||
selection.anchorNode.parentElement?.dataset["start"] ||
|
||||
(selection.anchorNode.parentElement?.nextElementSibling as any)
|
||||
?.dataset["start"] ||
|
||||
0,
|
||||
end:
|
||||
selection.focusNode.parentElement?.dataset["end"] ||
|
||||
(
|
||||
selection.focusNode.parentElement?.parentElement
|
||||
?.previousElementSibling?.lastElementChild as any
|
||||
)?.dataset ||
|
||||
0,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
if (
|
||||
@@ -112,14 +132,34 @@ const topicWords = ({
|
||||
};
|
||||
}, []);
|
||||
|
||||
if (!topicWithWords.loading && wordsBySpeaker) {
|
||||
const getSpeakerName = useCallback(
|
||||
(speakerNumber: number) => {
|
||||
return (
|
||||
participants.response.find((participant) => {
|
||||
participant.speaker == speakerNumber;
|
||||
}) || `Speaker ${speakerNumber}`
|
||||
);
|
||||
},
|
||||
[participants],
|
||||
);
|
||||
|
||||
if (!topicWithWords.loading && wordsBySpeaker && participants) {
|
||||
return (
|
||||
<div>
|
||||
{wordsBySpeaker?.map((speakerWithWords) => (
|
||||
<p>
|
||||
<span>Speaker {speakerWithWords.speaker} : </span>
|
||||
{speakerWithWords.words.map((word) => (
|
||||
<span data-start={word.start} data-end={word.end}>
|
||||
{wordsBySpeaker?.map((speakerWithWords, index) => (
|
||||
<p key={index}>
|
||||
<span
|
||||
data-speaker={speakerWithWords.speaker}
|
||||
className={
|
||||
selectedSpeaker == speakerWithWords.speaker
|
||||
? "bg-yellow-200"
|
||||
: ""
|
||||
}
|
||||
>
|
||||
{getSpeakerName(speakerWithWords.speaker)} :
|
||||
</span>
|
||||
{speakerWithWords.words.map((word, index) => (
|
||||
<span data-start={word.start} data-end={word.end} key={index}>
|
||||
{word.text}
|
||||
</span>
|
||||
))}
|
||||
|
||||
66
www/app/[domain]/transcripts/useParticipants.ts
Normal file
66
www/app/[domain]/transcripts/useParticipants.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { V1TranscriptGetParticipantsRequest } from "../../api/apis/DefaultApi";
|
||||
import { GetTranscript, Participant } from "../../api";
|
||||
import { useError } from "../../(errors)/errorContext";
|
||||
import getApi from "../../lib/getApi";
|
||||
import { shouldShowError } from "../../lib/errorUtils";
|
||||
|
||||
type ErrorParticipants = {
|
||||
error: Error;
|
||||
loading: false;
|
||||
response: any;
|
||||
};
|
||||
|
||||
type LoadingParticipants = {
|
||||
response: any;
|
||||
loading: true;
|
||||
error: false;
|
||||
};
|
||||
|
||||
type SuccessParticipants = {
|
||||
response: Participant[];
|
||||
loading: false;
|
||||
error: null;
|
||||
};
|
||||
|
||||
const useParticipants = (
|
||||
transcriptId: string,
|
||||
): ErrorParticipants | LoadingParticipants | SuccessParticipants => {
|
||||
const [response, setResponse] = useState<GetTranscript | null>(null);
|
||||
const [loading, setLoading] = useState<boolean>(true);
|
||||
const [error, setErrorState] = useState<Error | null>(null);
|
||||
const { setError } = useError();
|
||||
const api = getApi();
|
||||
|
||||
useEffect(() => {
|
||||
if (!transcriptId || !api) return;
|
||||
|
||||
setLoading(true);
|
||||
const requestParameters: V1TranscriptGetParticipantsRequest = {
|
||||
transcriptId,
|
||||
};
|
||||
api
|
||||
.v1TranscriptGetParticipants(requestParameters)
|
||||
.then((result) => {
|
||||
setResponse(result);
|
||||
setLoading(false);
|
||||
console.debug("Participants Loaded:", result);
|
||||
})
|
||||
.catch((error) => {
|
||||
const shouldShowHuman = shouldShowError(error);
|
||||
if (shouldShowHuman) {
|
||||
setError(error, "There was an error loading the participants");
|
||||
} else {
|
||||
setError(error);
|
||||
}
|
||||
setErrorState(error);
|
||||
});
|
||||
}, [transcriptId, !api]);
|
||||
|
||||
return { response, loading, error } as
|
||||
| ErrorParticipants
|
||||
| LoadingParticipants
|
||||
| SuccessParticipants;
|
||||
};
|
||||
|
||||
export default useParticipants;
|
||||
Reference in New Issue
Block a user