@lobehub/tts
Version:
A high-quality & reliable TTS React Hooks library
68 lines (66 loc) • 2.03 kB
JavaScript
import { useStreamAudioPlayer } from "../hooks/useStreamAudioPlayer.mjs";
import { splitTextIntoSegments } from "../../core/utils/splitTextIntoSegments.mjs";
import { useCallback, useEffect, useState } from "react";
import useSWR from "swr";
//#region src/react/useTTS/index.ts
const useTTS = (key, text, fetchTTS, { onError, onSuccess, onFinish, onStart, onStop, ...restSWRConfig } = {}) => {
const [shouldFetch, setShouldFetch] = useState(false);
const [isGlobalLoading, setIsGlobalLoading] = useState(false);
const [index, setIndex] = useState(0);
const [textArray, setTextArray] = useState([]);
const { load, reset, ...restAudio } = useStreamAudioPlayer();
const handleReset = useCallback((newText = []) => {
setShouldFetch(false);
setIsGlobalLoading(false);
reset();
setIndex(0);
setTextArray(newText);
}, []);
const handleStop = useCallback(() => {
onStop?.();
handleReset([]);
}, [handleReset]);
const { isLoading, error, mutate } = useSWR(shouldFetch && textArray?.length > 0 ? [key, textArray?.[index]].join("-") : null, async () => await fetchTTS(textArray[index]), {
onError: (err, ...rest) => {
onError?.(err, ...rest);
console.error("Error useTTS:", err);
handleReset();
},
onSuccess: (data, ...rest) => {
onSuccess?.(data, ...rest);
load(data);
if (index < textArray.length - 1) setIndex(index + 1);
else {
onFinish?.([...restAudio.arrayBuffers, data].filter(Boolean), ...rest);
setShouldFetch(false);
setIsGlobalLoading(false);
}
},
...restSWRConfig
});
const handleStart = useCallback(() => {
if (!text || isLoading) return;
onStart?.();
reset();
setShouldFetch(true);
setIsGlobalLoading(true);
}, [text, isLoading]);
useEffect(() => {
handleReset(splitTextIntoSegments(text));
return () => {
handleReset();
};
}, [text]);
return {
audio: restAudio,
canStart: !isLoading && !!text,
error,
isGlobalLoading,
isLoading,
mutate,
start: handleStart,
stop: handleStop
};
};
//#endregion
export { useTTS };