UNPKG

react-native-executorch

Version:

An easy way to run AI models in React Native with ExecuTorch

144 lines (141 loc) 4.65 kB
"use strict"; import { useCallback, useEffect, useState } from 'react'; import { TextToSpeechModule } from '../../modules/natural_language_processing/TextToSpeechModule'; import { RnExecutorchErrorCode } from '../../errors/ErrorCodes'; import { RnExecutorchError, parseUnknownError } from '../../errors/errorUtils'; /** * React hook for managing Text to Speech instance. * @category Hooks * @param TextToSpeechProps - Configuration object containing `model` source, `voice` and optional `preventLoad`. * @returns Ready to use Text to Speech model. */ export const useTextToSpeech = ({ model, voice, preventLoad = false }) => { const [error, setError] = useState(null); const [isReady, setIsReady] = useState(false); const [isGenerating, setIsGenerating] = useState(false); const [downloadProgress, setDownloadProgress] = useState(0); const [moduleInstance, setModuleInstance] = useState(null); useEffect(() => { if (preventLoad) return; let active = true; setDownloadProgress(0); setError(null); setIsReady(false); TextToSpeechModule.fromModelName({ model, voice }, setDownloadProgress).then(mod => { if (!active) { mod.delete(); return; } setModuleInstance(prev => { prev?.delete(); return mod; }); setIsReady(true); }).catch(err => { if (active) setError(parseUnknownError(err)); }); return () => { active = false; setModuleInstance(prev => { prev?.delete(); return null; }); }; // eslint-disable-next-line react-hooks/exhaustive-deps }, [model.modelName, model.durationPredictorSource, model.synthesizerSource, voice?.voiceSource, voice?.extra, preventLoad]); // Shared guard for all generation methods const guardReady = useCallback(methodName => { if (!isReady || !moduleInstance) throw new RnExecutorchError(RnExecutorchErrorCode.ModuleNotLoaded, `The model is currently not loaded. Please load the model before calling ${methodName}().`); if (isGenerating) throw new RnExecutorchError(RnExecutorchErrorCode.ModelGenerating, 'The model is currently generating. Please wait until previous model run is complete.'); return moduleInstance; }, [isReady, isGenerating, moduleInstance]); const forward = async input => { const instance = guardReady('forward'); try { setIsGenerating(true); return await instance.forward(input.text ?? '', input.speed ?? 1.0); } finally { setIsGenerating(false); } }; const forwardFromPhonemes = async input => { const instance = guardReady('forwardFromPhonemes'); try { setIsGenerating(true); return await instance.forwardFromPhonemes(input.phonemes ?? '', input.speed ?? 1.0); } finally { setIsGenerating(false); } }; const stream = useCallback(async input => { const instance = guardReady('stream'); setIsGenerating(true); try { if (input.text) { // If the initial text does not end with an end of sentence character, // we add an artificial dot to improve output's quality. instance.streamInsert(input.text + ('.?!;'.includes(input.text.trim().slice(-1)) ? '' : '.')); } await input.onBegin?.(); for await (const audio of instance.stream({ speed: input.speed ?? 1.0, stopAutomatically: input.stopAutomatically ?? true })) { if (input.onNext) { await input.onNext(audio); } } } finally { await input.onEnd?.(); setIsGenerating(false); } }, [guardReady]); const streamFromPhonemes = useCallback(async input => { const instance = guardReady('streamFromPhonemes'); setIsGenerating(true); try { await input.onBegin?.(); for await (const audio of instance.streamFromPhonemes({ phonemes: input.phonemes ?? '', speed: input.speed ?? 1.0 })) { if (input.onNext) { await input.onNext(audio); } } } finally { await input.onEnd?.(); setIsGenerating(false); } }, [guardReady]); const streamInsert = useCallback(text => { if (moduleInstance) { moduleInstance.streamInsert(text); } }, [moduleInstance]); const streamStop = useCallback((instant = true) => { if (moduleInstance) { moduleInstance.streamStop(instant); } }, [moduleInstance]); return { error, isReady, isGenerating, forward, forwardFromPhonemes, stream, streamFromPhonemes, streamInsert, streamStop, downloadProgress }; }; //# sourceMappingURL=useTextToSpeech.js.map