mirror of
https://github.com/Monadical-SAS/reflector.git
synced 2026-02-04 09:56:47 +00:00
feat: mixdown optional (#834)
* optional mixdown * optional mixdown --------- Co-authored-by: Igor Loskutov <igor.loskutoff@gmail.com>
This commit is contained in:
@@ -302,10 +302,10 @@ export default function RoomsList() {
|
||||
return;
|
||||
}
|
||||
|
||||
const platform: "whereby" | "daily" | null =
|
||||
const platform: "whereby" | "daily" =
|
||||
room.platform === "whereby" || room.platform === "daily"
|
||||
? room.platform
|
||||
: null;
|
||||
: "daily";
|
||||
|
||||
const roomData = {
|
||||
name: room.name,
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
import { useError } from "../../../../(errors)/errorContext";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { Box, Grid } from "@chakra-ui/react";
|
||||
import { parseNonEmptyString } from "../../../../lib/utils";
|
||||
|
||||
export type TranscriptCorrect = {
|
||||
params: Promise<{
|
||||
@@ -25,8 +26,7 @@ export type TranscriptCorrect = {
|
||||
|
||||
export default function TranscriptCorrect(props: TranscriptCorrect) {
|
||||
const params = use(props.params);
|
||||
|
||||
const { transcriptId } = params;
|
||||
const transcriptId = parseNonEmptyString(params.transcriptId);
|
||||
|
||||
const updateTranscriptMutation = useTranscriptUpdate();
|
||||
const transcript = useTranscriptGet(transcriptId);
|
||||
|
||||
@@ -9,7 +9,9 @@ import React, { useEffect, useState, use } from "react";
|
||||
import FinalSummary from "./finalSummary";
|
||||
import TranscriptTitle from "../transcriptTitle";
|
||||
import Player from "../player";
|
||||
import { useWebSockets } from "../useWebSockets";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { parseNonEmptyString } from "../../../lib/utils";
|
||||
import {
|
||||
Box,
|
||||
Flex,
|
||||
@@ -30,7 +32,7 @@ type TranscriptDetails = {
|
||||
|
||||
export default function TranscriptDetails(details: TranscriptDetails) {
|
||||
const params = use(details.params);
|
||||
const transcriptId = params.transcriptId;
|
||||
const transcriptId = parseNonEmptyString(params.transcriptId);
|
||||
const router = useRouter();
|
||||
const statusToRedirect = [
|
||||
"idle",
|
||||
@@ -49,6 +51,7 @@ export default function TranscriptDetails(details: TranscriptDetails) {
|
||||
transcriptId,
|
||||
waiting || mp3.audioDeleted === true,
|
||||
);
|
||||
useWebSockets(transcriptId);
|
||||
const useActiveTopic = useState<Topic | null>(null);
|
||||
const [finalSummaryElement, setFinalSummaryElement] =
|
||||
useState<HTMLDivElement | null>(null);
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
} from "@chakra-ui/react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useTranscriptGet } from "../../../../lib/apiHooks";
|
||||
import { parseNonEmptyString } from "../../../../lib/utils";
|
||||
|
||||
type TranscriptProcessing = {
|
||||
params: Promise<{
|
||||
@@ -19,7 +20,7 @@ type TranscriptProcessing = {
|
||||
|
||||
export default function TranscriptProcessing(details: TranscriptProcessing) {
|
||||
const params = use(details.params);
|
||||
const transcriptId = params.transcriptId;
|
||||
const transcriptId = parseNonEmptyString(params.transcriptId);
|
||||
const router = useRouter();
|
||||
|
||||
const transcript = useTranscriptGet(transcriptId);
|
||||
|
||||
@@ -12,6 +12,7 @@ import { Box, Text, Grid, Heading, VStack, Flex } from "@chakra-ui/react";
|
||||
import LiveTrancription from "../../liveTranscription";
|
||||
import { useTranscriptGet } from "../../../../lib/apiHooks";
|
||||
import { TranscriptStatus } from "../../../../lib/transcript";
|
||||
import { parseNonEmptyString } from "../../../../lib/utils";
|
||||
|
||||
type TranscriptDetails = {
|
||||
params: Promise<{
|
||||
@@ -21,13 +22,14 @@ type TranscriptDetails = {
|
||||
|
||||
const TranscriptRecord = (details: TranscriptDetails) => {
|
||||
const params = use(details.params);
|
||||
const transcript = useTranscriptGet(params.transcriptId);
|
||||
const transcriptId = parseNonEmptyString(params.transcriptId);
|
||||
const transcript = useTranscriptGet(transcriptId);
|
||||
const [transcriptStarted, setTranscriptStarted] = useState(false);
|
||||
const useActiveTopic = useState<Topic | null>(null);
|
||||
|
||||
const webSockets = useWebSockets(params.transcriptId);
|
||||
const webSockets = useWebSockets(transcriptId);
|
||||
|
||||
const mp3 = useMp3(params.transcriptId, true);
|
||||
const mp3 = useMp3(transcriptId, true);
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import useMp3 from "../../useMp3";
|
||||
import { Center, VStack, Text, Heading } from "@chakra-ui/react";
|
||||
import FileUploadButton from "../../fileUploadButton";
|
||||
import { useTranscriptGet } from "../../../../lib/apiHooks";
|
||||
import { parseNonEmptyString } from "../../../../lib/utils";
|
||||
|
||||
type TranscriptUpload = {
|
||||
params: Promise<{
|
||||
@@ -16,12 +17,13 @@ type TranscriptUpload = {
|
||||
|
||||
const TranscriptUpload = (details: TranscriptUpload) => {
|
||||
const params = use(details.params);
|
||||
const transcript = useTranscriptGet(params.transcriptId);
|
||||
const transcriptId = parseNonEmptyString(params.transcriptId);
|
||||
const transcript = useTranscriptGet(transcriptId);
|
||||
const [transcriptStarted, setTranscriptStarted] = useState(false);
|
||||
|
||||
const webSockets = useWebSockets(params.transcriptId);
|
||||
const webSockets = useWebSockets(transcriptId);
|
||||
|
||||
const mp3 = useMp3(params.transcriptId, true);
|
||||
const mp3 = useMp3(transcriptId, true);
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useState } from "react";
|
||||
import type { components } from "../../reflector-api";
|
||||
import { parseMaybeNonEmptyString } from "../../lib/utils";
|
||||
|
||||
type UpdateTranscript = components["schemas"]["UpdateTranscript"];
|
||||
type GetTranscriptWithParticipants =
|
||||
@@ -32,7 +33,7 @@ const TranscriptTitle = (props: TranscriptTitle) => {
|
||||
const [isEditing, setIsEditing] = useState(false);
|
||||
const updateTranscriptMutation = useTranscriptUpdate();
|
||||
const participantsQuery = useTranscriptParticipants(
|
||||
props.transcript?.id || null,
|
||||
props.transcript?.id ? parseMaybeNonEmptyString(props.transcript.id) : null,
|
||||
);
|
||||
|
||||
const updateTitle = async (newTitle: string, transcriptId: string) => {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useTranscriptGet } from "../../lib/apiHooks";
|
||||
import { parseMaybeNonEmptyString } from "../../lib/utils";
|
||||
import { useAuth } from "../../lib/AuthProvider";
|
||||
import { API_URL } from "../../lib/apiClient";
|
||||
|
||||
@@ -27,7 +28,7 @@ const useMp3 = (transcriptId: string, waiting?: boolean): Mp3Response => {
|
||||
data: transcript,
|
||||
isLoading: transcriptMetadataLoading,
|
||||
error: transcriptError,
|
||||
} = useTranscriptGet(later ? null : transcriptId);
|
||||
} = useTranscriptGet(later ? null : parseMaybeNonEmptyString(transcriptId));
|
||||
|
||||
const [serviceWorker, setServiceWorker] =
|
||||
useState<ServiceWorkerRegistration | null>(null);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { components } from "../../reflector-api";
|
||||
type Participant = components["schemas"]["Participant"];
|
||||
import { useTranscriptParticipants } from "../../lib/apiHooks";
|
||||
import { parseMaybeNonEmptyString } from "../../lib/utils";
|
||||
|
||||
type ErrorParticipants = {
|
||||
error: Error;
|
||||
@@ -32,7 +33,7 @@ const useParticipants = (transcriptId: string): UseParticipants => {
|
||||
isLoading: loading,
|
||||
error,
|
||||
refetch,
|
||||
} = useTranscriptParticipants(transcriptId || null);
|
||||
} = useTranscriptParticipants(parseMaybeNonEmptyString(transcriptId));
|
||||
|
||||
// Type-safe return based on state
|
||||
if (error) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { components } from "../../reflector-api";
|
||||
import { useTranscriptTopicsWithWordsPerSpeaker } from "../../lib/apiHooks";
|
||||
import { parseMaybeNonEmptyString } from "../../lib/utils";
|
||||
|
||||
type GetTranscriptTopicWithWordsPerSpeaker =
|
||||
components["schemas"]["GetTranscriptTopicWithWordsPerSpeaker"];
|
||||
@@ -38,7 +39,7 @@ const useTopicWithWords = (
|
||||
error,
|
||||
refetch,
|
||||
} = useTranscriptTopicsWithWordsPerSpeaker(
|
||||
transcriptId || null,
|
||||
parseMaybeNonEmptyString(transcriptId),
|
||||
topicId || null,
|
||||
);
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useTranscriptTopics } from "../../lib/apiHooks";
|
||||
import type { components } from "../../reflector-api";
|
||||
import { parseMaybeNonEmptyString } from "../../lib/utils";
|
||||
|
||||
type GetTranscriptTopic = components["schemas"]["GetTranscriptTopic"];
|
||||
|
||||
@@ -10,7 +11,11 @@ type TranscriptTopics = {
|
||||
};
|
||||
|
||||
const useTopics = (id: string): TranscriptTopics => {
|
||||
const { data: topics, isLoading: loading, error } = useTranscriptTopics(id);
|
||||
const {
|
||||
data: topics,
|
||||
isLoading: loading,
|
||||
error,
|
||||
} = useTranscriptTopics(parseMaybeNonEmptyString(id));
|
||||
|
||||
return {
|
||||
topics: topics || null,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { components } from "../../reflector-api";
|
||||
import { useTranscriptWaveform } from "../../lib/apiHooks";
|
||||
import { parseMaybeNonEmptyString } from "../../lib/utils";
|
||||
|
||||
type AudioWaveform = components["schemas"]["AudioWaveform"];
|
||||
|
||||
@@ -14,7 +15,7 @@ const useWaveform = (id: string, skip: boolean): AudioWaveFormResponse => {
|
||||
data: waveform,
|
||||
isLoading: loading,
|
||||
error,
|
||||
} = useTranscriptWaveform(skip ? null : id);
|
||||
} = useTranscriptWaveform(skip ? null : parseMaybeNonEmptyString(id));
|
||||
|
||||
return {
|
||||
waveform: waveform || null,
|
||||
|
||||
@@ -7,6 +7,12 @@ type GetTranscriptSegmentTopic =
|
||||
components["schemas"]["GetTranscriptSegmentTopic"];
|
||||
import { useQueryClient } from "@tanstack/react-query";
|
||||
import { $api, WEBSOCKET_URL } from "../../lib/apiClient";
|
||||
import {
|
||||
invalidateTranscript,
|
||||
invalidateTranscriptTopics,
|
||||
invalidateTranscriptWaveform,
|
||||
} from "../../lib/apiHooks";
|
||||
import { NonEmptyString } from "../../lib/utils";
|
||||
|
||||
export type UseWebSockets = {
|
||||
transcriptTextLive: string;
|
||||
@@ -369,15 +375,10 @@ export const useWebSockets = (transcriptId: string | null): UseWebSockets => {
|
||||
});
|
||||
console.debug("TOPIC event:", message.data);
|
||||
// Invalidate topics query to sync with WebSocket data
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: $api.queryOptions(
|
||||
"get",
|
||||
"/v1/transcripts/{transcript_id}/topics",
|
||||
{
|
||||
params: { path: { transcript_id: transcriptId } },
|
||||
},
|
||||
).queryKey,
|
||||
});
|
||||
invalidateTranscriptTopics(
|
||||
queryClient,
|
||||
transcriptId as NonEmptyString,
|
||||
);
|
||||
break;
|
||||
|
||||
case "FINAL_SHORT_SUMMARY":
|
||||
@@ -388,15 +389,7 @@ export const useWebSockets = (transcriptId: string | null): UseWebSockets => {
|
||||
if (message.data) {
|
||||
setFinalSummary(message.data);
|
||||
// Invalidate transcript query to sync summary
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: $api.queryOptions(
|
||||
"get",
|
||||
"/v1/transcripts/{transcript_id}",
|
||||
{
|
||||
params: { path: { transcript_id: transcriptId } },
|
||||
},
|
||||
).queryKey,
|
||||
});
|
||||
invalidateTranscript(queryClient, transcriptId as NonEmptyString);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -405,15 +398,7 @@ export const useWebSockets = (transcriptId: string | null): UseWebSockets => {
|
||||
if (message.data) {
|
||||
setTitle(message.data.title);
|
||||
// Invalidate transcript query to sync title
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: $api.queryOptions(
|
||||
"get",
|
||||
"/v1/transcripts/{transcript_id}",
|
||||
{
|
||||
params: { path: { transcript_id: transcriptId } },
|
||||
},
|
||||
).queryKey,
|
||||
});
|
||||
invalidateTranscript(queryClient, transcriptId as NonEmptyString);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -424,6 +409,10 @@ export const useWebSockets = (transcriptId: string | null): UseWebSockets => {
|
||||
);
|
||||
if (message.data) {
|
||||
setWaveForm(message.data.waveform);
|
||||
invalidateTranscriptWaveform(
|
||||
queryClient,
|
||||
transcriptId as NonEmptyString,
|
||||
);
|
||||
}
|
||||
break;
|
||||
case "DURATION":
|
||||
|
||||
@@ -26,7 +26,7 @@ import { useRouter } from "next/navigation";
|
||||
import { formatDateTime, formatStartedAgo } from "../lib/timeUtils";
|
||||
import MeetingMinimalHeader from "../components/MeetingMinimalHeader";
|
||||
import { NonEmptyString } from "../lib/utils";
|
||||
import { MeetingId } from "../lib/types";
|
||||
import { MeetingId, assertMeetingId } from "../lib/types";
|
||||
|
||||
type Meeting = components["schemas"]["Meeting"];
|
||||
|
||||
@@ -315,7 +315,9 @@ export default function MeetingSelection({
|
||||
variant="outline"
|
||||
colorScheme="red"
|
||||
size="md"
|
||||
onClick={() => handleEndMeeting(meeting.id)}
|
||||
onClick={() =>
|
||||
handleEndMeeting(assertMeetingId(meeting.id))
|
||||
}
|
||||
loading={deactivateMeetingMutation.isPending}
|
||||
>
|
||||
<Icon as={LuX} me={2} />
|
||||
@@ -460,7 +462,9 @@ export default function MeetingSelection({
|
||||
variant="outline"
|
||||
colorScheme="red"
|
||||
size="md"
|
||||
onClick={() => handleEndMeeting(meeting.id)}
|
||||
onClick={() =>
|
||||
handleEndMeeting(assertMeetingId(meeting.id))
|
||||
}
|
||||
loading={deactivateMeetingMutation.isPending}
|
||||
>
|
||||
<Icon as={LuX} me={2} />
|
||||
|
||||
@@ -6,6 +6,7 @@ import { QueryClient, useQueryClient } from "@tanstack/react-query";
|
||||
import type { components } from "../reflector-api";
|
||||
import { useAuth } from "./AuthProvider";
|
||||
import { MeetingId } from "./types";
|
||||
import { NonEmptyString } from "./utils";
|
||||
|
||||
/*
|
||||
* XXX error types returned from the hooks are not always correct; declared types are ValidationError but real type could be string or any other
|
||||
@@ -103,7 +104,7 @@ export function useTranscriptProcess() {
|
||||
});
|
||||
}
|
||||
|
||||
export function useTranscriptGet(transcriptId: string | null) {
|
||||
export function useTranscriptGet(transcriptId: NonEmptyString | null) {
|
||||
return $api.useQuery(
|
||||
"get",
|
||||
"/v1/transcripts/{transcript_id}",
|
||||
@@ -120,6 +121,16 @@ export function useTranscriptGet(transcriptId: string | null) {
|
||||
);
|
||||
}
|
||||
|
||||
export const invalidateTranscript = (
|
||||
queryClient: QueryClient,
|
||||
transcriptId: NonEmptyString,
|
||||
) =>
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: $api.queryOptions("get", "/v1/transcripts/{transcript_id}", {
|
||||
params: { path: { transcript_id: transcriptId } },
|
||||
}).queryKey,
|
||||
});
|
||||
|
||||
export function useRoomGet(roomId: string | null) {
|
||||
const { isAuthenticated } = useAuthReady();
|
||||
|
||||
@@ -297,7 +308,7 @@ export function useTranscriptUploadAudio() {
|
||||
);
|
||||
}
|
||||
|
||||
export function useTranscriptWaveform(transcriptId: string | null) {
|
||||
export function useTranscriptWaveform(transcriptId: NonEmptyString | null) {
|
||||
return $api.useQuery(
|
||||
"get",
|
||||
"/v1/transcripts/{transcript_id}/audio/waveform",
|
||||
@@ -312,7 +323,21 @@ export function useTranscriptWaveform(transcriptId: string | null) {
|
||||
);
|
||||
}
|
||||
|
||||
export function useTranscriptMP3(transcriptId: string | null) {
|
||||
export const invalidateTranscriptWaveform = (
|
||||
queryClient: QueryClient,
|
||||
transcriptId: NonEmptyString,
|
||||
) =>
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: $api.queryOptions(
|
||||
"get",
|
||||
"/v1/transcripts/{transcript_id}/audio/waveform",
|
||||
{
|
||||
params: { path: { transcript_id: transcriptId } },
|
||||
},
|
||||
).queryKey,
|
||||
});
|
||||
|
||||
export function useTranscriptMP3(transcriptId: NonEmptyString | null) {
|
||||
const { isAuthenticated } = useAuthReady();
|
||||
|
||||
return $api.useQuery(
|
||||
@@ -329,7 +354,7 @@ export function useTranscriptMP3(transcriptId: string | null) {
|
||||
);
|
||||
}
|
||||
|
||||
export function useTranscriptTopics(transcriptId: string | null) {
|
||||
export function useTranscriptTopics(transcriptId: NonEmptyString | null) {
|
||||
return $api.useQuery(
|
||||
"get",
|
||||
"/v1/transcripts/{transcript_id}/topics",
|
||||
@@ -344,7 +369,23 @@ export function useTranscriptTopics(transcriptId: string | null) {
|
||||
);
|
||||
}
|
||||
|
||||
export function useTranscriptTopicsWithWords(transcriptId: string | null) {
|
||||
export const invalidateTranscriptTopics = (
|
||||
queryClient: QueryClient,
|
||||
transcriptId: NonEmptyString,
|
||||
) =>
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: $api.queryOptions(
|
||||
"get",
|
||||
"/v1/transcripts/{transcript_id}/topics",
|
||||
{
|
||||
params: { path: { transcript_id: transcriptId } },
|
||||
},
|
||||
).queryKey,
|
||||
});
|
||||
|
||||
export function useTranscriptTopicsWithWords(
|
||||
transcriptId: NonEmptyString | null,
|
||||
) {
|
||||
const { isAuthenticated } = useAuthReady();
|
||||
|
||||
return $api.useQuery(
|
||||
@@ -362,7 +403,7 @@ export function useTranscriptTopicsWithWords(transcriptId: string | null) {
|
||||
}
|
||||
|
||||
export function useTranscriptTopicsWithWordsPerSpeaker(
|
||||
transcriptId: string | null,
|
||||
transcriptId: NonEmptyString | null,
|
||||
topicId: string | null,
|
||||
) {
|
||||
const { isAuthenticated } = useAuthReady();
|
||||
@@ -384,7 +425,7 @@ export function useTranscriptTopicsWithWordsPerSpeaker(
|
||||
);
|
||||
}
|
||||
|
||||
export function useTranscriptParticipants(transcriptId: string | null) {
|
||||
export function useTranscriptParticipants(transcriptId: NonEmptyString | null) {
|
||||
const { isAuthenticated } = useAuthReady();
|
||||
|
||||
return $api.useQuery(
|
||||
|
||||
Reference in New Issue
Block a user