export default function useTranscribe()

in projects/deliberation_at_scale/packages/frontend/hooks/useTranscribe.ts [17:120]


export default function useTranscribe(options?: UseTranscribeOptions) {
    const { whisperOptions, chunkDurationMs = DEFAULT_TRANSCRIPTION_CHUNK_DURATION_MS } = options ?? {};
    const { roomId, participantId } = useRoom();
    const { authSession } = useProfile();
    const [chunkStartTime, setChunkStartTime] = useState<Dayjs>(dayjs());
    const onTranscribe = useRef<(blob: Blob) => Promise<UseWhisperTranscript> | undefined>();
    const { transcript, startRecording, pauseRecording, resetRecordings } = useWhisper({
        streaming: true,
        autoStart: ENABLE_AUTO_START_TRANSCRIPTION,
        removeSilence: true,
        timeSlice: DEFAULT_TRANSCRIPTION_TIME_SLICE_MS,
        ...whisperOptions,
        onTranscribe: (blob: Blob) => {
            const emptyResult = new Promise<UseWhisperTranscript>((resolve) => {
                resolve({
                    blob,
                    text: '',
                });
            });

            return onTranscribe.current?.(blob) ?? emptyResult;
        },
    });

    // handle automatic chunking
    useEffect(() => {

        // disable chunking if chunkDurationMs is not set
        if (!chunkDurationMs) {
            return;
        }

        const chunkInterval = setInterval(() => {
            setChunkStartTime(dayjs());
            resetRecordings();
        }, chunkDurationMs);

        return () => {
            clearInterval(chunkInterval);
        };
    }, [chunkDurationMs, resetRecordings, setChunkStartTime]);

    // handle changes to the callback depending on variables
    useEffect(() => {
        onTranscribe.current = async (blob: Blob) => {
            const base64Content = await new Promise<string | ArrayBuffer | null>(
                (resolve) => {
                    const reader = new FileReader();
                    reader.onloadend = () => resolve(reader.result);
                    reader.readAsDataURL(blob);
                }
            );
            const accessToken = authSession?.access_token;

            // guard: check if all required variables are present
            if (!accessToken || !roomId || !participantId || !chunkStartTime) {
                return {
                    blob,
                    text: '',
                };
            }

            const body = {
                content: base64Content,
                roomId,
                participantId,
                chunkStartTime: chunkStartTime.toISOString(),
            };
            const options = {
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': `Bearer ${accessToken}`,
                },
            };

            const response = await axios.post(
                NEXT_PUBLIC_TRANSCRIBE_API_URL,
                body,
                options
            );
            const {
                text = '',
                error
            } = await response.data;

            if (error) {
                // eslint-disable-next-line no-console
                console.error(`An error occurred while transcribing:`, error);
            }

            return {
                blob,
                text,
            };
        };
    }, [roomId, participantId, authSession, chunkStartTime]);

    return {
        transcript,
        startRecording,
        pauseRecording,
        resetRecordings,
    };
}