mirror of
https://github.com/Monadical-SAS/reflector.git
synced 2025-12-21 04:39: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 TopicHeader from "./topicHeader";
|
||||||
import TopicWords from "./topicWords";
|
import TopicWords from "./topicWords";
|
||||||
import TopicPlayer from "./topicPlayer";
|
import TopicPlayer from "./topicPlayer";
|
||||||
|
import getApi from "../../../../lib/getApi";
|
||||||
|
import useParticipants from "../../useParticipants";
|
||||||
|
|
||||||
type TranscriptCorrect = {
|
type TranscriptCorrect = {
|
||||||
params: {
|
params: {
|
||||||
@@ -22,6 +24,9 @@ export default function TranscriptCorrect(details: TranscriptCorrect) {
|
|||||||
const [currentTopic, setCurrentTopic] = useState("");
|
const [currentTopic, setCurrentTopic] = useState("");
|
||||||
const [selectedTime, setSelectedTime] = useState<TimeSlice>();
|
const [selectedTime, setSelectedTime] = useState<TimeSlice>();
|
||||||
const [topicTime, setTopicTime] = useState<TimeSlice>();
|
const [topicTime, setTopicTime] = useState<TimeSlice>();
|
||||||
|
const api = getApi();
|
||||||
|
const participants = useParticipants(transcriptId);
|
||||||
|
const stateSelectedSpeaker = useState<number>();
|
||||||
|
|
||||||
// TODO BE
|
// TODO BE
|
||||||
// Get one topic with words
|
// Get one topic with words
|
||||||
@@ -30,6 +35,14 @@ export default function TranscriptCorrect(details: TranscriptCorrect) {
|
|||||||
// -> use full current topic instead of topicId here
|
// -> use full current topic instead of topicId here
|
||||||
// -> remove time calculation and setting from TopicHeader
|
// -> remove time calculation and setting from TopicHeader
|
||||||
// -> pass in topicTime to player directly
|
// -> 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 (
|
return (
|
||||||
<div className="h-full grid grid-cols-2 gap-4">
|
<div className="h-full grid grid-cols-2 gap-4">
|
||||||
@@ -44,6 +57,8 @@ export default function TranscriptCorrect(details: TranscriptCorrect) {
|
|||||||
currentTopic={currentTopic}
|
currentTopic={currentTopic}
|
||||||
transcriptId={transcriptId}
|
transcriptId={transcriptId}
|
||||||
setTopicTime={setTopicTime}
|
setTopicTime={setTopicTime}
|
||||||
|
stateSelectedSpeaker={stateSelectedSpeaker}
|
||||||
|
participants={participants}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@@ -52,6 +67,7 @@ export default function TranscriptCorrect(details: TranscriptCorrect) {
|
|||||||
selectedTime={selectedTime}
|
selectedTime={selectedTime}
|
||||||
topicTime={topicTime}
|
topicTime={topicTime}
|
||||||
/>
|
/>
|
||||||
|
<button onClick={createParticipant}>Create</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ const TopicPlayer = ({ transcriptId, selectedTime, topicTime }) => {
|
|||||||
const [endSelectionCallback, setEndSelectionCallback] =
|
const [endSelectionCallback, setEndSelectionCallback] =
|
||||||
useState<() => void>();
|
useState<() => void>();
|
||||||
|
|
||||||
|
//TODO shortcuts
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setEndTopicCallback(
|
setEndTopicCallback(
|
||||||
() =>
|
() =>
|
||||||
@@ -29,7 +31,6 @@ const TopicPlayer = ({ transcriptId, selectedTime, topicTime }) => {
|
|||||||
}, [topicTime]);
|
}, [topicTime]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log(endTopicCallback, "he");
|
|
||||||
endTopicCallback &&
|
endTopicCallback &&
|
||||||
mp3.media &&
|
mp3.media &&
|
||||||
mp3.media.addEventListener("timeupdate", endTopicCallback);
|
mp3.media.addEventListener("timeupdate", endTopicCallback);
|
||||||
@@ -77,7 +78,6 @@ const TopicPlayer = ({ transcriptId, selectedTime, topicTime }) => {
|
|||||||
endSelectionCallback &&
|
endSelectionCallback &&
|
||||||
mp3.media &&
|
mp3.media &&
|
||||||
mp3.media.addEventListener("timeupdate", endSelectionCallback);
|
mp3.media.addEventListener("timeupdate", endSelectionCallback);
|
||||||
console.log(endSelectionCallback, "hi");
|
|
||||||
return () => {
|
return () => {
|
||||||
endSelectionCallback &&
|
endSelectionCallback &&
|
||||||
mp3.media &&
|
mp3.media &&
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useEffect, useState } from "react";
|
import { useCallback, useEffect, useState } from "react";
|
||||||
import useTopicWithWords from "../../useTopicWithWords";
|
import useTopicWithWords from "../../useTopicWithWords";
|
||||||
import WaveformLoading from "../../waveformLoading";
|
import WaveformLoading from "../../waveformLoading";
|
||||||
|
|
||||||
@@ -11,14 +11,21 @@ type Word = {
|
|||||||
|
|
||||||
type WordBySpeaker = { speaker: number; words: 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 = ({
|
const topicWords = ({
|
||||||
setSelectedTime,
|
setSelectedTime,
|
||||||
currentTopic,
|
currentTopic,
|
||||||
transcriptId,
|
transcriptId,
|
||||||
setTopicTime,
|
setTopicTime,
|
||||||
|
stateSelectedSpeaker,
|
||||||
|
participants,
|
||||||
}) => {
|
}) => {
|
||||||
const topicWithWords = useTopicWithWords(currentTopic, transcriptId);
|
const topicWithWords = useTopicWithWords(currentTopic, transcriptId);
|
||||||
const [wordsBySpeaker, setWordsBySpeaker] = useState<WordBySpeaker>();
|
const [wordsBySpeaker, setWordsBySpeaker] = useState<WordBySpeaker>();
|
||||||
|
const [selectedSpeaker, setSelectedSpeaker] = stateSelectedSpeaker;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (topicWithWords.loading) {
|
if (topicWithWords.loading) {
|
||||||
@@ -72,6 +79,7 @@ const topicWords = ({
|
|||||||
const focusOffset = focusIsWord
|
const focusOffset = focusIsWord
|
||||||
? focusNode.textContent?.length
|
? focusNode.textContent?.length
|
||||||
: focusNode.parentNode?.lastChild?.textContent?.length;
|
: focusNode.parentNode?.lastChild?.textContent?.length;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
correctedAnchor &&
|
correctedAnchor &&
|
||||||
anchorOffset !== undefined &&
|
anchorOffset !== undefined &&
|
||||||
@@ -84,20 +92,32 @@ const topicWords = ({
|
|||||||
correctedfocus,
|
correctedfocus,
|
||||||
focusOffset,
|
focusOffset,
|
||||||
);
|
);
|
||||||
setSelectedTime({
|
|
||||||
start:
|
if (
|
||||||
selection.anchorNode.parentElement?.dataset["start"] ||
|
!anchorIsWord &&
|
||||||
(selection.anchorNode.parentElement?.nextElementSibling as any)
|
!focusIsWord &&
|
||||||
?.dataset["start"] ||
|
anchorNode.parentElement == focusNode.parentElement
|
||||||
0,
|
) {
|
||||||
end:
|
console.log(focusNode.parentElement?.dataset);
|
||||||
selection.focusNode.parentElement?.dataset["end"] ||
|
setSelectedSpeaker(focusNode.parentElement?.dataset["speaker"]);
|
||||||
(
|
setSelectedTime(undefined);
|
||||||
selection.focusNode.parentElement?.parentElement
|
} else {
|
||||||
?.previousElementSibling?.lastElementChild as any
|
setSelectedSpeaker(undefined);
|
||||||
)?.dataset ||
|
setSelectedTime({
|
||||||
0,
|
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 (
|
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 (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{wordsBySpeaker?.map((speakerWithWords) => (
|
{wordsBySpeaker?.map((speakerWithWords, index) => (
|
||||||
<p>
|
<p key={index}>
|
||||||
<span>Speaker {speakerWithWords.speaker} : </span>
|
<span
|
||||||
{speakerWithWords.words.map((word) => (
|
data-speaker={speakerWithWords.speaker}
|
||||||
<span data-start={word.start} data-end={word.end}>
|
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}
|
{word.text}
|
||||||
</span>
|
</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