🗣️ feat: Edge TTS engine (#3358)

* feat: MS Edge TTS

* feat: Edge TTS; fix: STT hook
This commit is contained in:
Marco Beretta 2024-08-07 20:15:41 +02:00 committed by GitHub
parent 01a88991ab
commit b390ba781f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 379 additions and 129 deletions

View file

@ -68,6 +68,7 @@
"lodash": "^4.17.21", "lodash": "^4.17.21",
"lucide-react": "^0.394.0", "lucide-react": "^0.394.0",
"match-sorter": "^6.3.4", "match-sorter": "^6.3.4",
"msedge-tts": "^1.3.4",
"rc-input-number": "^7.4.2", "rc-input-number": "^7.4.2",
"react": "^18.2.0", "react": "^18.2.0",
"react-avatar-editor": "^13.0.2", "react-avatar-editor": "^13.0.2",

View file

@ -15,9 +15,13 @@ const EngineTTSDropdown: React.FC<EngineTTSDropdownProps> = ({ external }) => {
const endpointOptions = external const endpointOptions = external
? [ ? [
{ value: 'browser', display: localize('com_nav_browser') }, { value: 'browser', display: localize('com_nav_browser') },
{ value: 'edge', display: localize('com_nav_edge') },
{ value: 'external', display: localize('com_nav_external') }, { value: 'external', display: localize('com_nav_external') },
] ]
: [{ value: 'browser', display: localize('com_nav_browser') }]; : [
{ value: 'browser', display: localize('com_nav_browser') },
{ value: 'edge', display: localize('com_nav_edge') },
];
const handleSelect = (value: string) => { const handleSelect = (value: string) => {
setEngineTTS(value); setEngineTTS(value);

View file

@ -1,64 +1,31 @@
import React, { useMemo, useEffect, useState } from 'react'; import React, { useEffect, useState, useMemo } from 'react';
import { useRecoilState } from 'recoil'; import { useRecoilState } from 'recoil';
import Dropdown from '~/components/ui/DropdownNoState'; import Dropdown from '~/components/ui/DropdownNoState';
import { useVoicesQuery } from '~/data-provider'; import { useLocalize, useTextToSpeech } from '~/hooks';
import { useLocalize } from '~/hooks';
import store from '~/store'; import store from '~/store';
const getLocalVoices = (): Promise<SpeechSynthesisVoice[]> => {
return new Promise((resolve) => {
const voices = speechSynthesis.getVoices();
console.log('voices', voices);
if (voices.length) {
resolve(voices);
} else {
speechSynthesis.onvoiceschanged = () => resolve(speechSynthesis.getVoices());
}
});
};
type VoiceOption = {
value: string;
display: string;
};
export default function VoiceDropdown() { export default function VoiceDropdown() {
const localize = useLocalize(); const localize = useLocalize();
const [voice, setVoice] = useRecoilState(store.voice); const [voice, setVoice] = useRecoilState(store.voice);
const { voices } = useTextToSpeech();
const [voiceOptions, setVoiceOptions] = useState([]);
const [engineTTS] = useRecoilState(store.engineTTS); const [engineTTS] = useRecoilState(store.engineTTS);
const [cloudBrowserVoices] = useRecoilState(store.cloudBrowserVoices);
const externalTextToSpeech = engineTTS === 'external';
const { data: externalVoices = [] } = useVoicesQuery();
const [localVoices, setLocalVoices] = useState<SpeechSynthesisVoice[]>([]);
useEffect(() => { useEffect(() => {
if (!externalTextToSpeech) { async function fetchVoices() {
getLocalVoices().then(setLocalVoices); const options = await voices();
} setVoiceOptions(options);
}, [externalTextToSpeech]);
useEffect(() => { if (!voice && options.length > 0) {
if (voice) { setVoice(options[0]);
return; }
} }
if (externalTextToSpeech && externalVoices.length) { fetchVoices();
setVoice(externalVoices[0]); // eslint-disable-next-line react-hooks/exhaustive-deps
} else if (!externalTextToSpeech && localVoices.length) { }, [engineTTS]);
setVoice(localVoices[0].name);
}
}, [voice, setVoice, externalTextToSpeech, externalVoices, localVoices]);
const voiceOptions: VoiceOption[] = useMemo(() => { const memoizedVoiceOptions = useMemo(() => voiceOptions, [voiceOptions]);
if (externalTextToSpeech) {
return externalVoices.map((v) => ({ value: v, display: v }));
} else {
return localVoices
.filter((v) => cloudBrowserVoices || v.localService === true)
.map((v) => ({ value: v.name, display: v.name }));
}
}, [externalTextToSpeech, externalVoices, localVoices, cloudBrowserVoices]);
return ( return (
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
@ -66,7 +33,7 @@ export default function VoiceDropdown() {
<Dropdown <Dropdown
value={voice} value={voice}
onChange={setVoice} onChange={setVoice}
options={voiceOptions} options={memoizedVoiceOptions}
sizeClasses="min-w-[200px] !max-w-[400px] [--anchor-max-width:400px]" sizeClasses="min-w-[200px] !max-w-[400px] [--anchor-max-width:400px]"
anchor="bottom start" anchor="bottom start"
testId="VoiceDropdown" testId="VoiceDropdown"

View file

@ -1,4 +1,4 @@
import React, { FC, useContext, useState } from 'react'; import React, { FC } from 'react';
import { import {
Listbox, Listbox,
ListboxButton, ListboxButton,

View file

@ -1,19 +1,25 @@
import { useRecoilState } from 'recoil'; import { useRecoilState } from 'recoil';
import store from '~/store'; import store from '~/store';
export enum AudioEndpoints { export enum STTEndpoints {
browser = 'browser', browser = 'browser',
external = 'external', external = 'external',
} }
export enum TTSEndpoints {
browser = 'browser',
edge = 'edge',
external = 'external',
}
const useGetAudioSettings = () => { const useGetAudioSettings = () => {
const [engineSTT] = useRecoilState<string>(store.engineSTT); const [engineSTT] = useRecoilState<string>(store.engineSTT);
const [engineTTS] = useRecoilState<string>(store.engineTTS); const [engineTTS] = useRecoilState<string>(store.engineTTS);
const externalSpeechToText = engineSTT === AudioEndpoints.external; const speechToTextEndpoint: STTEndpoints = engineSTT as STTEndpoints;
const externalTextToSpeech = engineTTS === AudioEndpoints.external; const textToSpeechEndpoint: TTSEndpoints = engineTTS as TTSEndpoints;
return { externalSpeechToText, externalTextToSpeech }; return { speechToTextEndpoint, textToSpeechEndpoint };
}; };
export default useGetAudioSettings; export default useGetAudioSettings;

View file

@ -4,8 +4,9 @@ import useSpeechToTextExternal from './useSpeechToTextExternal';
import useGetAudioSettings from './useGetAudioSettings'; import useGetAudioSettings from './useGetAudioSettings';
const useSpeechToText = (handleTranscriptionComplete: (text: string) => void) => { const useSpeechToText = (handleTranscriptionComplete: (text: string) => void) => {
const { externalSpeechToText } = useGetAudioSettings(); const { speechToTextEndpoint } = useGetAudioSettings();
const [animatedText, setAnimatedText] = useState(''); const [animatedText, setAnimatedText] = useState('');
const externalSpeechToText = speechToTextEndpoint === 'external';
const { const {
isListening: speechIsListeningBrowser, isListening: speechIsListeningBrowser,

View file

@ -9,7 +9,8 @@ const useSpeechToTextBrowser = () => {
const { showToast } = useToastContext(); const { showToast } = useToastContext();
const [languageSTT] = useRecoilState<string>(store.languageSTT); const [languageSTT] = useRecoilState<string>(store.languageSTT);
const [autoTranscribeAudio] = useRecoilState<boolean>(store.autoTranscribeAudio); const [autoTranscribeAudio] = useRecoilState<boolean>(store.autoTranscribeAudio);
const { externalSpeechToText } = useGetAudioSettings(); const { speechToTextEndpoint } = useGetAudioSettings();
const isBrowserSTTEnabled = speechToTextEndpoint === 'browser';
const [isListening, setIsListening] = useState(false); const [isListening, setIsListening] = useState(false);
const { const {
@ -51,7 +52,7 @@ const useSpeechToTextBrowser = () => {
useEffect(() => { useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => { const handleKeyDown = (e: KeyboardEvent) => {
if (e.shiftKey && e.altKey && e.code === 'KeyL' && !externalSpeechToText) { if (e.shiftKey && e.altKey && e.code === 'KeyL' && !isBrowserSTTEnabled) {
toggleListening(); toggleListening();
} }
}; };

View file

@ -7,7 +7,8 @@ import useGetAudioSettings from './useGetAudioSettings';
const useSpeechToTextExternal = (onTranscriptionComplete: (text: string) => void) => { const useSpeechToTextExternal = (onTranscriptionComplete: (text: string) => void) => {
const { showToast } = useToastContext(); const { showToast } = useToastContext();
const { externalSpeechToText } = useGetAudioSettings(); const { speechToTextEndpoint } = useGetAudioSettings();
const isExternalSTTEnabled = speechToTextEndpoint === 'external';
const [speechToText] = useRecoilState<boolean>(store.speechToText); const [speechToText] = useRecoilState<boolean>(store.speechToText);
const [autoTranscribeAudio] = useRecoilState<boolean>(store.autoTranscribeAudio); const [autoTranscribeAudio] = useRecoilState<boolean>(store.autoTranscribeAudio);
const [autoSendText] = useRecoilState(store.autoSendText); const [autoSendText] = useRecoilState(store.autoSendText);
@ -194,7 +195,7 @@ const useSpeechToTextExternal = (onTranscriptionComplete: (text: string) => void
}; };
const handleKeyDown = async (e: KeyboardEvent) => { const handleKeyDown = async (e: KeyboardEvent) => {
if (e.shiftKey && e.altKey && e.code === 'KeyL' && !externalSpeechToText) { if (e.shiftKey && e.altKey && e.code === 'KeyL' && isExternalSTTEnabled) {
if (!window.MediaRecorder) { if (!window.MediaRecorder) {
showToast({ message: 'MediaRecorder is not supported in this browser', status: 'error' }); showToast({ message: 'MediaRecorder is not supported in this browser', status: 'error' });
return; return;

View file

@ -3,30 +3,67 @@ import { parseTextParts } from 'librechat-data-provider';
import type { TMessage } from 'librechat-data-provider'; import type { TMessage } from 'librechat-data-provider';
import useTextToSpeechExternal from './useTextToSpeechExternal'; import useTextToSpeechExternal from './useTextToSpeechExternal';
import useTextToSpeechBrowser from './useTextToSpeechBrowser'; import useTextToSpeechBrowser from './useTextToSpeechBrowser';
import { usePauseGlobalAudio } from '../Audio';
import useGetAudioSettings from './useGetAudioSettings'; import useGetAudioSettings from './useGetAudioSettings';
import useTextToSpeechEdge from './useTextToSpeechEdge';
import { usePauseGlobalAudio } from '../Audio';
const useTextToSpeech = (message: TMessage, isLast: boolean, index = 0) => { const useTextToSpeech = (message?: TMessage, isLast = false, index = 0) => {
const { externalTextToSpeech } = useGetAudioSettings(); const { textToSpeechEndpoint } = useGetAudioSettings();
const { pauseGlobalAudio } = usePauseGlobalAudio(index);
const audioRef = useRef<HTMLAudioElement | null>(null);
const { const {
generateSpeechLocal: generateSpeechLocal, generateSpeechLocal,
cancelSpeechLocal: cancelSpeechLocal, cancelSpeechLocal,
isSpeaking: isSpeakingLocal, isSpeaking: isSpeakingLocal,
voices: voicesLocal,
} = useTextToSpeechBrowser(); } = useTextToSpeechBrowser();
const { const {
generateSpeechExternal: generateSpeechExternal, generateSpeechEdge,
cancelSpeechEdge,
isSpeaking: isSpeakingEdge,
voices: voicesEdge,
} = useTextToSpeechEdge();
const {
generateSpeechExternal,
cancelSpeech: cancelSpeechExternal, cancelSpeech: cancelSpeechExternal,
isSpeaking: isSpeakingExternal, isSpeaking: isSpeakingExternal,
isLoading: isLoading, isLoading: isLoadingExternal,
audioRef, audioRef: audioRefExternal,
} = useTextToSpeechExternal(message.messageId, isLast, index); voices: voicesExternal,
const { pauseGlobalAudio } = usePauseGlobalAudio(index); } = useTextToSpeechExternal(message?.messageId || '', isLast, index);
const generateSpeech = externalTextToSpeech ? generateSpeechExternal : generateSpeechLocal; let generateSpeech, cancelSpeech, isSpeaking, isLoading, voices;
const cancelSpeech = externalTextToSpeech ? cancelSpeechExternal : cancelSpeechLocal;
const isSpeaking = externalTextToSpeech ? isSpeakingExternal : isSpeakingLocal; switch (textToSpeechEndpoint) {
case 'external':
generateSpeech = generateSpeechExternal;
cancelSpeech = cancelSpeechExternal;
isSpeaking = isSpeakingExternal;
isLoading = isLoadingExternal;
if (audioRefExternal) {
audioRef.current = audioRefExternal.current;
}
voices = voicesExternal;
break;
case 'edge':
generateSpeech = generateSpeechEdge;
cancelSpeech = cancelSpeechEdge;
isSpeaking = isSpeakingEdge;
isLoading = false;
voices = voicesEdge;
break;
case 'browser':
default:
generateSpeech = generateSpeechLocal;
cancelSpeech = cancelSpeechLocal;
isSpeaking = isSpeakingLocal;
isLoading = false;
voices = voicesLocal;
break;
}
const isMouseDownRef = useRef(false); const isMouseDownRef = useRef(false);
const timerRef = useRef<number | undefined>(undefined); const timerRef = useRef<number | undefined>(undefined);
@ -52,7 +89,6 @@ const useTextToSpeech = (message: TMessage, isLast: boolean, index = 0) => {
const toggleSpeech = () => { const toggleSpeech = () => {
if (isSpeaking) { if (isSpeaking) {
console.log('canceling message audio speech');
cancelSpeech(); cancelSpeech();
pauseGlobalAudio(); pauseGlobalAudio();
} else { } else {
@ -69,6 +105,7 @@ const useTextToSpeech = (message: TMessage, isLast: boolean, index = 0) => {
toggleSpeech, toggleSpeech,
isSpeaking, isSpeaking,
isLoading, isLoading,
voices,
audioRef, audioRef,
}; };
}; };

View file

@ -2,6 +2,11 @@ import { useRecoilState } from 'recoil';
import { useState } from 'react'; import { useState } from 'react';
import store from '~/store'; import store from '~/store';
interface VoiceOption {
value: string;
display: string;
}
function useTextToSpeechBrowser() { function useTextToSpeechBrowser() {
const [cloudBrowserVoices] = useRecoilState(store.cloudBrowserVoices); const [cloudBrowserVoices] = useRecoilState(store.cloudBrowserVoices);
const [isSpeaking, setIsSpeaking] = useState(false); const [isSpeaking, setIsSpeaking] = useState(false);
@ -32,7 +37,30 @@ function useTextToSpeechBrowser() {
setIsSpeaking(false); setIsSpeaking(false);
}; };
return { generateSpeechLocal, cancelSpeechLocal, isSpeaking }; const voices = (): Promise<VoiceOption[]> => {
return new Promise((resolve) => {
const getAndMapVoices = () => {
const availableVoices = speechSynthesis
.getVoices()
.filter((v) => cloudBrowserVoices || v.localService === true);
const voiceOptions: VoiceOption[] = availableVoices.map((v) => ({
value: v.name,
display: v.name,
}));
resolve(voiceOptions);
};
if (speechSynthesis.getVoices().length) {
getAndMapVoices();
} else {
speechSynthesis.onvoiceschanged = getAndMapVoices;
}
});
};
return { generateSpeechLocal, cancelSpeechLocal, isSpeaking, voices };
} }
export default useTextToSpeechBrowser; export default useTextToSpeechBrowser;

View file

@ -0,0 +1,201 @@
import { useRecoilState } from 'recoil';
import { useState, useCallback, useRef, useEffect } from 'react';
import { MsEdgeTTS, OUTPUT_FORMAT } from 'msedge-tts';
import { useToastContext } from '~/Providers';
import useLocalize from '~/hooks/useLocalize';
import store from '~/store';
interface Voice {
value: string;
display: string;
}
interface UseTextToSpeechEdgeReturn {
generateSpeechEdge: (text: string) => Promise<void>;
cancelSpeechEdge: () => void;
isSpeaking: boolean;
voices: () => Promise<Voice[]>;
}
function useTextToSpeechEdge(): UseTextToSpeechEdgeReturn {
const localize = useLocalize();
const [isSpeaking, setIsSpeaking] = useState<boolean>(false);
const [voiceName] = useRecoilState<string>(store.voice);
const ttsRef = useRef<MsEdgeTTS | null>(null);
const audioElementRef = useRef<HTMLAudioElement | null>(null);
const mediaSourceRef = useRef<MediaSource | null>(null);
const sourceBufferRef = useRef<SourceBuffer | null>(null);
const pendingBuffers = useRef<Uint8Array[]>([]);
const { showToast } = useToastContext();
const initializeTTS = useCallback(async (): Promise<void> => {
if (!ttsRef.current) {
ttsRef.current = new MsEdgeTTS();
}
try {
await ttsRef.current.setMetadata(voiceName, OUTPUT_FORMAT.AUDIO_24KHZ_48KBITRATE_MONO_MP3);
} catch (error) {
console.error('Error initializing TTS:', error);
showToast({
message: localize('com_nav_tts_init_error', (error as Error).message),
status: 'error',
});
}
}, [voiceName, showToast, localize]);
const onSourceOpen = useCallback((): void => {
if (!sourceBufferRef.current && mediaSourceRef.current) {
try {
sourceBufferRef.current = mediaSourceRef.current.addSourceBuffer('audio/mpeg');
sourceBufferRef.current.addEventListener('updateend', appendNextBuffer);
} catch (error) {
console.error('Error adding source buffer:', error);
showToast({
message: localize('com_nav_source_buffer_error'),
status: 'error',
});
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [showToast, localize]);
const initializeMediaSource = useCallback(async (): Promise<void> => {
return new Promise<void>((resolve) => {
if (!mediaSourceRef.current) {
mediaSourceRef.current = new MediaSource();
audioElementRef.current = new Audio();
audioElementRef.current.src = URL.createObjectURL(mediaSourceRef.current);
}
const mediaSource = mediaSourceRef.current;
if (mediaSource.readyState === 'open') {
onSourceOpen();
resolve();
} else {
const onSourceOpenWrapper = (): void => {
onSourceOpen();
resolve();
mediaSource.removeEventListener('sourceopen', onSourceOpenWrapper);
};
mediaSource.addEventListener('sourceopen', onSourceOpenWrapper);
}
});
}, [onSourceOpen]);
const appendNextBuffer = useCallback((): void => {
if (
sourceBufferRef.current &&
!sourceBufferRef.current.updating &&
pendingBuffers.current.length > 0
) {
const nextBuffer = pendingBuffers.current.shift();
if (nextBuffer) {
try {
sourceBufferRef.current.appendBuffer(nextBuffer);
} catch (error) {
console.error('Error appending buffer:', error);
showToast({
message: localize('com_nav_buffer_append_error'),
status: 'error',
});
pendingBuffers.current.unshift(nextBuffer);
}
}
}
}, [showToast, localize]);
const generateSpeechEdge = useCallback(
async (text: string): Promise<void> => {
try {
await initializeTTS();
await initializeMediaSource();
if (!ttsRef.current || !audioElementRef.current) {
throw new Error('TTS or Audio element not initialized');
}
setIsSpeaking(true);
pendingBuffers.current = [];
const readable = await ttsRef.current.toStream(text);
readable.on('data', (chunk: Buffer) => {
pendingBuffers.current.push(new Uint8Array(chunk));
appendNextBuffer();
});
readable.on('end', () => {
if (mediaSourceRef.current && mediaSourceRef.current.readyState === 'open') {
mediaSourceRef.current.endOfStream();
}
});
audioElementRef.current.onended = () => {
setIsSpeaking(false);
};
await audioElementRef.current.play();
} catch (error) {
console.error('Error generating speech:', error);
showToast({
message: localize('com_nav_audio_play_error', (error as Error).message),
status: 'error',
});
setIsSpeaking(false);
}
},
[initializeTTS, initializeMediaSource, appendNextBuffer, showToast, localize],
);
const cancelSpeechEdge = useCallback((): void => {
try {
if (audioElementRef.current) {
audioElementRef.current.pause();
audioElementRef.current.currentTime = 0;
}
if (mediaSourceRef.current && mediaSourceRef.current.readyState === 'open') {
mediaSourceRef.current.endOfStream();
}
pendingBuffers.current = [];
setIsSpeaking(false);
} catch (error) {
console.error('Error cancelling speech:', error);
showToast({
message: localize('com_nav_speech_cancel_error'),
status: 'error',
});
}
}, [showToast, localize]);
const voices = useCallback(async (): Promise<Voice[]> => {
if (!ttsRef.current) {
ttsRef.current = new MsEdgeTTS();
}
try {
const voicesList = await ttsRef.current.getVoices();
return voicesList.map((v) => ({
value: v.ShortName,
display: v.FriendlyName,
}));
} catch (error) {
console.error('Error fetching voices:', error);
showToast({
message: localize('com_nav_voices_fetch_error'),
status: 'error',
});
return [];
}
}, [showToast, localize]);
useEffect(() => {
return () => {
if (mediaSourceRef.current) {
URL.revokeObjectURL(audioElementRef.current?.src || '');
}
};
}, []);
return { generateSpeechEdge, cancelSpeechEdge, isSpeaking, voices };
}
export default useTextToSpeechEdge;

View file

@ -1,6 +1,6 @@
import { useRecoilValue } from 'recoil'; import { useRecoilValue } from 'recoil';
import { useState, useMemo, useRef, useCallback, useEffect } from 'react'; import { useState, useMemo, useRef, useCallback, useEffect } from 'react';
import { useTextToSpeechMutation } from '~/data-provider'; import { useTextToSpeechMutation, useVoicesQuery } from '~/data-provider';
import useAudioRef from '~/hooks/Audio/useAudioRef'; import useAudioRef from '~/hooks/Audio/useAudioRef';
import useLocalize from '~/hooks/useLocalize'; import useLocalize from '~/hooks/useLocalize';
import { useToastContext } from '~/Providers'; import { useToastContext } from '~/Providers';
@ -178,7 +178,18 @@ function useTextToSpeechExternal(messageId: string, isLast: boolean, index = 0)
return isLocalSpeaking || (isLast && globalIsPlaying); return isLocalSpeaking || (isLast && globalIsPlaying);
}, [isLocalSpeaking, globalIsPlaying, isLast]); }, [isLocalSpeaking, globalIsPlaying, isLast]);
return { generateSpeechExternal, cancelSpeech, isLoading, isSpeaking, audioRef }; const useVoices = () => {
return useVoicesQuery().data ?? [];
};
return {
generateSpeechExternal,
cancelSpeech,
isLoading,
isSpeaking,
audioRef,
voices: useVoices,
};
} }
export default useTextToSpeechExternal; export default useTextToSpeechExternal;

View file

@ -657,8 +657,17 @@ export default {
com_nav_audio_play_error: 'Error playing audio: {0}', com_nav_audio_play_error: 'Error playing audio: {0}',
com_nav_audio_process_error: 'Error processing audio: {0}', com_nav_audio_process_error: 'Error processing audio: {0}',
com_nav_long_audio_warning: 'Longer texts will take longer to process.', com_nav_long_audio_warning: 'Longer texts will take longer to process.',
com_nav_tts_init_error: 'Failed to initialize text-to-speech: {0}',
com_nav_source_buffer_error: 'Error setting up audio playback. Please refresh the page.',
com_nav_media_source_init_error:
'Unable to prepare audio player. Please check your browser settings.',
com_nav_buffer_append_error: 'Problem with audio streaming. The playback may be interrupted.',
com_nav_speech_cancel_error: 'Unable to stop audio playback. You may need to refresh the page.',
com_nav_voices_fetch_error:
'Could not retrieve voice options. Please check your internet connection.',
com_nav_engine: 'Engine', com_nav_engine: 'Engine',
com_nav_browser: 'Browser', com_nav_browser: 'Browser',
com_nav_edge: 'Edge',
com_nav_external: 'External', com_nav_external: 'External',
com_nav_delete_cache_storage: 'Delete TTS cache storage', com_nav_delete_cache_storage: 'Delete TTS cache storage',
com_nav_enable_cache_tts: 'Enable cache TTS', com_nav_enable_cache_tts: 'Enable cache TTS',

89
package-lock.json generated
View file

@ -1157,6 +1157,7 @@
"lodash": "^4.17.21", "lodash": "^4.17.21",
"lucide-react": "^0.394.0", "lucide-react": "^0.394.0",
"match-sorter": "^6.3.4", "match-sorter": "^6.3.4",
"msedge-tts": "^1.3.4",
"rc-input-number": "^7.4.2", "rc-input-number": "^7.4.2",
"react": "^18.2.0", "react": "^18.2.0",
"react-avatar-editor": "^13.0.2", "react-avatar-editor": "^13.0.2",
@ -12399,7 +12400,6 @@
"version": "5.4.1", "version": "5.4.1",
"resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz",
"integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==",
"dev": true,
"dependencies": { "dependencies": {
"bn.js": "^4.0.0", "bn.js": "^4.0.0",
"inherits": "^2.0.1", "inherits": "^2.0.1",
@ -12410,8 +12410,7 @@
"node_modules/asn1.js/node_modules/bn.js": { "node_modules/asn1.js/node_modules/bn.js": {
"version": "4.12.0", "version": "4.12.0",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA=="
"dev": true
}, },
"node_modules/assert": { "node_modules/assert": {
"version": "2.1.0", "version": "2.1.0",
@ -12898,8 +12897,7 @@
"node_modules/bn.js": { "node_modules/bn.js": {
"version": "5.2.1", "version": "5.2.1",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz",
"integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ=="
"dev": true
}, },
"node_modules/body-parser": { "node_modules/body-parser": {
"version": "1.20.2", "version": "1.20.2",
@ -13031,8 +13029,7 @@
"node_modules/brorand": { "node_modules/brorand": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
"integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w=="
"dev": true
}, },
"node_modules/browser-resolve": { "node_modules/browser-resolve": {
"version": "2.0.0", "version": "2.0.0",
@ -13047,7 +13044,6 @@
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
"integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==",
"dev": true,
"dependencies": { "dependencies": {
"buffer-xor": "^1.0.3", "buffer-xor": "^1.0.3",
"cipher-base": "^1.0.0", "cipher-base": "^1.0.0",
@ -13061,7 +13057,6 @@
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz",
"integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==",
"dev": true,
"dependencies": { "dependencies": {
"browserify-aes": "^1.0.4", "browserify-aes": "^1.0.4",
"browserify-des": "^1.0.0", "browserify-des": "^1.0.0",
@ -13072,7 +13067,6 @@
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz",
"integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==",
"dev": true,
"dependencies": { "dependencies": {
"cipher-base": "^1.0.1", "cipher-base": "^1.0.1",
"des.js": "^1.0.0", "des.js": "^1.0.0",
@ -13084,7 +13078,6 @@
"version": "4.1.0", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz",
"integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==",
"dev": true,
"dependencies": { "dependencies": {
"bn.js": "^5.0.0", "bn.js": "^5.0.0",
"randombytes": "^2.0.1" "randombytes": "^2.0.1"
@ -13094,7 +13087,6 @@
"version": "4.2.2", "version": "4.2.2",
"resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.2.tgz", "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.2.tgz",
"integrity": "sha512-1rudGyeYY42Dk6texmv7c4VcQ0EsvVbLwZkA+AQB7SxvXxmcD93jcHie8bzecJ+ChDlmAm2Qyu0+Ccg5uhZXCg==", "integrity": "sha512-1rudGyeYY42Dk6texmv7c4VcQ0EsvVbLwZkA+AQB7SxvXxmcD93jcHie8bzecJ+ChDlmAm2Qyu0+Ccg5uhZXCg==",
"dev": true,
"dependencies": { "dependencies": {
"bn.js": "^5.2.1", "bn.js": "^5.2.1",
"browserify-rsa": "^4.1.0", "browserify-rsa": "^4.1.0",
@ -13114,7 +13106,6 @@
"version": "3.6.2", "version": "3.6.2",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
"dev": true,
"dependencies": { "dependencies": {
"inherits": "^2.0.3", "inherits": "^2.0.3",
"string_decoder": "^1.1.1", "string_decoder": "^1.1.1",
@ -13254,8 +13245,7 @@
"node_modules/buffer-xor": { "node_modules/buffer-xor": {
"version": "1.0.3", "version": "1.0.3",
"resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz",
"integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ=="
"dev": true
}, },
"node_modules/builtin-modules": { "node_modules/builtin-modules": {
"version": "3.3.0", "version": "3.3.0",
@ -13552,7 +13542,6 @@
"version": "1.0.4", "version": "1.0.4",
"resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
"integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==",
"dev": true,
"dependencies": { "dependencies": {
"inherits": "^2.0.1", "inherits": "^2.0.1",
"safe-buffer": "^5.0.1" "safe-buffer": "^5.0.1"
@ -14141,7 +14130,6 @@
"version": "4.0.4", "version": "4.0.4",
"resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz",
"integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==",
"dev": true,
"dependencies": { "dependencies": {
"bn.js": "^4.1.0", "bn.js": "^4.1.0",
"elliptic": "^6.5.3" "elliptic": "^6.5.3"
@ -14150,14 +14138,12 @@
"node_modules/create-ecdh/node_modules/bn.js": { "node_modules/create-ecdh/node_modules/bn.js": {
"version": "4.12.0", "version": "4.12.0",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA=="
"dev": true
}, },
"node_modules/create-hash": { "node_modules/create-hash": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
"integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
"dev": true,
"dependencies": { "dependencies": {
"cipher-base": "^1.0.1", "cipher-base": "^1.0.1",
"inherits": "^2.0.1", "inherits": "^2.0.1",
@ -14170,7 +14156,6 @@
"version": "1.1.7", "version": "1.1.7",
"resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
"integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
"dev": true,
"dependencies": { "dependencies": {
"cipher-base": "^1.0.3", "cipher-base": "^1.0.3",
"create-hash": "^1.1.0", "create-hash": "^1.1.0",
@ -14257,7 +14242,6 @@
"version": "3.12.0", "version": "3.12.0",
"resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz",
"integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==",
"dev": true,
"dependencies": { "dependencies": {
"browserify-cipher": "^1.0.0", "browserify-cipher": "^1.0.0",
"browserify-sign": "^4.0.0", "browserify-sign": "^4.0.0",
@ -14725,7 +14709,6 @@
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz",
"integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==",
"dev": true,
"dependencies": { "dependencies": {
"inherits": "^2.0.1", "inherits": "^2.0.1",
"minimalistic-assert": "^1.0.0" "minimalistic-assert": "^1.0.0"
@ -14807,7 +14790,6 @@
"version": "5.0.3", "version": "5.0.3",
"resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
"integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==",
"dev": true,
"dependencies": { "dependencies": {
"bn.js": "^4.1.0", "bn.js": "^4.1.0",
"miller-rabin": "^4.0.0", "miller-rabin": "^4.0.0",
@ -14817,8 +14799,7 @@
"node_modules/diffie-hellman/node_modules/bn.js": { "node_modules/diffie-hellman/node_modules/bn.js": {
"version": "4.12.0", "version": "4.12.0",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA=="
"dev": true
}, },
"node_modules/digest-fetch": { "node_modules/digest-fetch": {
"version": "1.3.0", "version": "1.3.0",
@ -15017,7 +14998,6 @@
"version": "6.5.4", "version": "6.5.4",
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz",
"integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==",
"dev": true,
"dependencies": { "dependencies": {
"bn.js": "^4.11.9", "bn.js": "^4.11.9",
"brorand": "^1.1.0", "brorand": "^1.1.0",
@ -15031,8 +15011,7 @@
"node_modules/elliptic/node_modules/bn.js": { "node_modules/elliptic/node_modules/bn.js": {
"version": "4.12.0", "version": "4.12.0",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA=="
"dev": true
}, },
"node_modules/emittery": { "node_modules/emittery": {
"version": "0.13.1", "version": "0.13.1",
@ -15929,7 +15908,6 @@
"version": "1.0.3", "version": "1.0.3",
"resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz",
"integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==",
"dev": true,
"dependencies": { "dependencies": {
"md5.js": "^1.3.4", "md5.js": "^1.3.4",
"safe-buffer": "^5.1.1" "safe-buffer": "^5.1.1"
@ -17534,7 +17512,6 @@
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz",
"integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==",
"dev": true,
"dependencies": { "dependencies": {
"inherits": "^2.0.4", "inherits": "^2.0.4",
"readable-stream": "^3.6.0", "readable-stream": "^3.6.0",
@ -17548,7 +17525,6 @@
"version": "3.6.2", "version": "3.6.2",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
"dev": true,
"dependencies": { "dependencies": {
"inherits": "^2.0.3", "inherits": "^2.0.3",
"string_decoder": "^1.1.1", "string_decoder": "^1.1.1",
@ -17562,7 +17538,6 @@
"version": "1.1.7", "version": "1.1.7",
"resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz",
"integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==",
"dev": true,
"dependencies": { "dependencies": {
"inherits": "^2.0.3", "inherits": "^2.0.3",
"minimalistic-assert": "^1.0.1" "minimalistic-assert": "^1.0.1"
@ -17771,7 +17746,6 @@
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
"integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==",
"dev": true,
"dependencies": { "dependencies": {
"hash.js": "^1.0.3", "hash.js": "^1.0.3",
"minimalistic-assert": "^1.0.0", "minimalistic-assert": "^1.0.0",
@ -19038,6 +19012,15 @@
"node": ">=10" "node": ">=10"
} }
}, },
"node_modules/isomorphic-ws": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz",
"integrity": "sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==",
"license": "MIT",
"peerDependencies": {
"ws": "*"
}
},
"node_modules/istanbul-lib-coverage": { "node_modules/istanbul-lib-coverage": {
"version": "3.2.2", "version": "3.2.2",
"resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz",
@ -21295,7 +21278,6 @@
"version": "1.3.5", "version": "1.3.5",
"resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
"integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==",
"dev": true,
"dependencies": { "dependencies": {
"hash-base": "^3.0.0", "hash-base": "^3.0.0",
"inherits": "^2.0.1", "inherits": "^2.0.1",
@ -22152,7 +22134,6 @@
"version": "4.0.1", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz",
"integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==",
"dev": true,
"dependencies": { "dependencies": {
"bn.js": "^4.0.0", "bn.js": "^4.0.0",
"brorand": "^1.0.1" "brorand": "^1.0.1"
@ -22164,8 +22145,7 @@
"node_modules/miller-rabin/node_modules/bn.js": { "node_modules/miller-rabin/node_modules/bn.js": {
"version": "4.12.0", "version": "4.12.0",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA=="
"dev": true
}, },
"node_modules/mime": { "node_modules/mime": {
"version": "3.0.0", "version": "3.0.0",
@ -22228,14 +22208,12 @@
"node_modules/minimalistic-assert": { "node_modules/minimalistic-assert": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
"integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A=="
"dev": true
}, },
"node_modules/minimalistic-crypto-utils": { "node_modules/minimalistic-crypto-utils": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz",
"integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg=="
"dev": true
}, },
"node_modules/minimatch": { "node_modules/minimatch": {
"version": "3.1.2", "version": "3.1.2",
@ -22506,6 +22484,21 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
}, },
"node_modules/msedge-tts": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/msedge-tts/-/msedge-tts-1.3.4.tgz",
"integrity": "sha512-0dj86Gg9VzdOJZVCkSSK/O5Eg0NM9W5p8LsXAEPe7qUmsvdAugPUTcPwt9tyz4GThAzAFBBu554kevH8StLEHQ==",
"license": "MIT",
"dependencies": {
"axios": "^1.5.0",
"buffer": "^6.0.3",
"crypto-browserify": "^3.12.0",
"isomorphic-ws": "^5.0.0",
"process": "^0.11.10",
"stream-browserify": "^3.0.0",
"ws": "^8.14.1"
}
},
"node_modules/multer": { "node_modules/multer": {
"version": "1.4.5-lts.1", "version": "1.4.5-lts.1",
"resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.1.tgz", "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.1.tgz",
@ -23527,7 +23520,6 @@
"version": "5.1.6", "version": "5.1.6",
"resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz",
"integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==",
"dev": true,
"dependencies": { "dependencies": {
"asn1.js": "^5.2.0", "asn1.js": "^5.2.0",
"browserify-aes": "^1.0.0", "browserify-aes": "^1.0.0",
@ -23795,7 +23787,6 @@
"version": "3.1.2", "version": "3.1.2",
"resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz",
"integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==",
"dev": true,
"dependencies": { "dependencies": {
"create-hash": "^1.1.2", "create-hash": "^1.1.2",
"create-hmac": "^1.1.4", "create-hmac": "^1.1.4",
@ -25521,7 +25512,6 @@
"version": "4.0.3", "version": "4.0.3",
"resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz",
"integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==",
"dev": true,
"dependencies": { "dependencies": {
"bn.js": "^4.1.0", "bn.js": "^4.1.0",
"browserify-rsa": "^4.0.0", "browserify-rsa": "^4.0.0",
@ -25534,8 +25524,7 @@
"node_modules/public-encrypt/node_modules/bn.js": { "node_modules/public-encrypt/node_modules/bn.js": {
"version": "4.12.0", "version": "4.12.0",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA=="
"dev": true
}, },
"node_modules/pump": { "node_modules/pump": {
"version": "3.0.0", "version": "3.0.0",
@ -25652,7 +25641,6 @@
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
"integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
"dev": true,
"dependencies": { "dependencies": {
"safe-buffer": "^5.1.0" "safe-buffer": "^5.1.0"
} }
@ -25661,7 +25649,6 @@
"version": "1.0.4", "version": "1.0.4",
"resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz",
"integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==",
"dev": true,
"dependencies": { "dependencies": {
"randombytes": "^2.0.5", "randombytes": "^2.0.5",
"safe-buffer": "^5.1.0" "safe-buffer": "^5.1.0"
@ -26632,7 +26619,6 @@
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz",
"integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==",
"dev": true,
"dependencies": { "dependencies": {
"hash-base": "^3.0.0", "hash-base": "^3.0.0",
"inherits": "^2.0.1" "inherits": "^2.0.1"
@ -27085,7 +27071,6 @@
"version": "2.4.11", "version": "2.4.11",
"resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
"integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
"dev": true,
"dependencies": { "dependencies": {
"inherits": "^2.0.1", "inherits": "^2.0.1",
"safe-buffer": "^5.0.1" "safe-buffer": "^5.0.1"
@ -27489,7 +27474,6 @@
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz",
"integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==",
"dev": true,
"dependencies": { "dependencies": {
"inherits": "~2.0.4", "inherits": "~2.0.4",
"readable-stream": "^3.5.0" "readable-stream": "^3.5.0"
@ -27499,7 +27483,6 @@
"version": "3.6.2", "version": "3.6.2",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
"dev": true,
"dependencies": { "dependencies": {
"inherits": "^2.0.3", "inherits": "^2.0.3",
"string_decoder": "^1.1.1", "string_decoder": "^1.1.1",