@memori.ai/memori-react 7.7.0 → 7.8.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +34 -0
- package/dist/components/Avatar/Avatar.js +2 -2
- package/dist/components/Avatar/Avatar.js.map +1 -1
- package/dist/components/Avatar/AvatarView/AvatarComponent/avatarComponent.d.ts +2 -0
- package/dist/components/Avatar/AvatarView/AvatarComponent/avatarComponent.js +2 -2
- package/dist/components/Avatar/AvatarView/AvatarComponent/avatarComponent.js.map +1 -1
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/fullbodyAvatar.d.ts +2 -0
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/fullbodyAvatar.js +1 -1
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/fullbodyAvatar.js.map +1 -1
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.d.ts +3 -1
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.js +77 -50
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.js.map +1 -1
- package/dist/components/Avatar/AvatarView/index.d.ts +3 -1
- package/dist/components/Avatar/AvatarView/index.js +2 -2
- package/dist/components/Avatar/AvatarView/index.js.map +1 -1
- package/dist/components/MemoriWidget/MemoriWidget.js +127 -113
- package/dist/components/MemoriWidget/MemoriWidget.js.map +1 -1
- package/dist/components/layouts/ZoomedFullBody.js +1 -8
- package/dist/components/layouts/ZoomedFullBody.js.map +1 -1
- package/dist/components/layouts/zoomed-full-body.css +6 -2
- package/dist/context/visemeContext.d.ts +1 -0
- package/dist/context/visemeContext.js +19 -9
- package/dist/context/visemeContext.js.map +1 -1
- package/dist/styles.css +0 -1
- package/esm/components/Avatar/Avatar.js +2 -2
- package/esm/components/Avatar/Avatar.js.map +1 -1
- package/esm/components/Avatar/AvatarView/AvatarComponent/avatarComponent.d.ts +2 -0
- package/esm/components/Avatar/AvatarView/AvatarComponent/avatarComponent.js +2 -2
- package/esm/components/Avatar/AvatarView/AvatarComponent/avatarComponent.js.map +1 -1
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/fullbodyAvatar.d.ts +2 -0
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/fullbodyAvatar.js +1 -1
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/fullbodyAvatar.js.map +1 -1
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.d.ts +3 -1
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.js +81 -53
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.js.map +1 -1
- package/esm/components/Avatar/AvatarView/index.d.ts +3 -1
- package/esm/components/Avatar/AvatarView/index.js +2 -2
- package/esm/components/Avatar/AvatarView/index.js.map +1 -1
- package/esm/components/MemoriWidget/MemoriWidget.js +127 -113
- package/esm/components/MemoriWidget/MemoriWidget.js.map +1 -1
- package/esm/components/layouts/ZoomedFullBody.js +1 -8
- package/esm/components/layouts/ZoomedFullBody.js.map +1 -1
- package/esm/components/layouts/zoomed-full-body.css +6 -2
- package/esm/context/visemeContext.d.ts +1 -0
- package/esm/context/visemeContext.js +20 -10
- package/esm/context/visemeContext.js.map +1 -1
- package/esm/styles.css +0 -1
- package/package.json +1 -1
- package/src/components/Avatar/Avatar.stories.tsx +5 -7
- package/src/components/Avatar/Avatar.tsx +3 -1
- package/src/components/Avatar/AvatarView/AvatarComponent/avatarComponent.tsx +13 -0
- package/src/components/Avatar/AvatarView/AvatarComponent/components/fullbodyAvatar.tsx +3 -1
- package/src/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.tsx +116 -65
- package/src/components/Avatar/AvatarView/AvatarView.stories.tsx +12 -36
- package/src/components/Avatar/AvatarView/index.tsx +6 -0
- package/src/components/MemoriWidget/MemoriWidget.tsx +164 -136
- package/src/components/layouts/ZoomedFullBody.test.tsx +1 -1
- package/src/components/layouts/ZoomedFullBody.tsx +4 -9
- package/src/components/layouts/zoomed-full-body.css +6 -2
- package/src/context/visemeContext.tsx +104 -70
- package/src/index.stories.tsx +23 -21
- package/src/styles.css +0 -1
- package/dist/components/AttachmentMediaModal/AttachmentMediaModal.d.ts +0 -14
- package/dist/components/AttachmentMediaModal/AttachmentMediaModal.js +0 -66
- package/dist/components/AttachmentMediaModal/AttachmentMediaModal.js.map +0 -1
- package/dist/components/Avatar/AvatarView/components/controls.d.ts +0 -23
- package/dist/components/Avatar/AvatarView/components/controls.js +0 -55
- package/dist/components/Avatar/AvatarView/components/controls.js.map +0 -1
- package/dist/components/Avatar/AvatarView/components/fullbodyAvatar.d.ts +0 -19
- package/dist/components/Avatar/AvatarView/components/fullbodyAvatar.js +0 -61
- package/dist/components/Avatar/AvatarView/components/fullbodyAvatar.js.map +0 -1
- package/dist/components/Avatar/AvatarView/components/halfbodyAvatar.d.ts +0 -9
- package/dist/components/Avatar/AvatarView/components/halfbodyAvatar.js +0 -39
- package/dist/components/Avatar/AvatarView/components/halfbodyAvatar.js.map +0 -1
- package/dist/components/Avatar/AvatarView/components/loader.d.ts +0 -5
- package/dist/components/Avatar/AvatarView/components/loader.js +0 -12
- package/dist/components/Avatar/AvatarView/components/loader.js.map +0 -1
- package/dist/components/Avatar/AvatarView/utils/useMouthSpeaking.d.ts +0 -2
- package/dist/components/Avatar/AvatarView/utils/useMouthSpeaking.js +0 -68
- package/dist/components/Avatar/AvatarView/utils/useMouthSpeaking.js.map +0 -1
- package/dist/components/AvatarView/components/avatar.d.ts +0 -9
- package/dist/components/AvatarView/components/avatar.js +0 -35
- package/dist/components/AvatarView/components/avatar.js.map +0 -1
- package/dist/components/AvatarView/components/fullbodyAvatar.d.ts +0 -10
- package/dist/components/AvatarView/components/fullbodyAvatar.js +0 -62
- package/dist/components/AvatarView/components/fullbodyAvatar.js.map +0 -1
- package/dist/components/AvatarView/components/loader.d.ts +0 -5
- package/dist/components/AvatarView/components/loader.js +0 -12
- package/dist/components/AvatarView/components/loader.js.map +0 -1
- package/dist/components/AvatarView/index.d.ts +0 -17
- package/dist/components/AvatarView/index.js +0 -35
- package/dist/components/AvatarView/index.js.map +0 -1
- package/dist/components/AvatarView/utils/useEyeBlink.d.ts +0 -2
- package/dist/components/AvatarView/utils/useEyeBlink.js +0 -40
- package/dist/components/AvatarView/utils/useEyeBlink.js.map +0 -1
- package/dist/components/AvatarView/utils/useHeadMovement.d.ts +0 -2
- package/dist/components/AvatarView/utils/useHeadMovement.js +0 -53
- package/dist/components/AvatarView/utils/useHeadMovement.js.map +0 -1
- package/dist/components/AvatarView/utils/useLoadingMorphAnim.d.ts +0 -2
- package/dist/components/AvatarView/utils/useLoadingMorphAnim.js +0 -34
- package/dist/components/AvatarView/utils/useLoadingMorphAnim.js.map +0 -1
- package/dist/components/AvatarView/utils/useMouthSpeaking.d.ts +0 -2
- package/dist/components/AvatarView/utils/useMouthSpeaking.js +0 -60
- package/dist/components/AvatarView/utils/useMouthSpeaking.js.map +0 -1
- package/dist/components/AvatarView/utils/useSmile.d.ts +0 -2
- package/dist/components/AvatarView/utils/useSmile.js +0 -30
- package/dist/components/AvatarView/utils/useSmile.js.map +0 -1
- package/dist/components/AvatarView/utils/utils.d.ts +0 -13
- package/dist/components/AvatarView/utils/utils.js +0 -42
- package/dist/components/AvatarView/utils/utils.js.map +0 -1
- package/dist/components/ImageUpload/ImageUpload.css +0 -168
- package/dist/components/ImageUpload/ImageUpload.d.ts +0 -28
- package/dist/components/ImageUpload/ImageUpload.js +0 -163
- package/dist/components/ImageUpload/ImageUpload.js.map +0 -1
- package/dist/components/layouts/Default.d.ts +0 -17
- package/dist/components/layouts/Default.js +0 -8
- package/dist/components/layouts/Default.js.map +0 -1
- package/dist/components/ui/Message.d.ts +0 -17
- package/dist/components/ui/Message.js +0 -13
- package/dist/components/ui/Message.js.map +0 -1
- package/esm/components/AttachmentMediaModal/AttachmentMediaModal.d.ts +0 -14
- package/esm/components/AttachmentMediaModal/AttachmentMediaModal.js +0 -63
- package/esm/components/AttachmentMediaModal/AttachmentMediaModal.js.map +0 -1
- package/esm/components/Avatar/AvatarView/components/controls.d.ts +0 -23
- package/esm/components/Avatar/AvatarView/components/controls.js +0 -52
- package/esm/components/Avatar/AvatarView/components/controls.js.map +0 -1
- package/esm/components/Avatar/AvatarView/components/fullbodyAvatar.d.ts +0 -19
- package/esm/components/Avatar/AvatarView/components/fullbodyAvatar.js +0 -57
- package/esm/components/Avatar/AvatarView/components/fullbodyAvatar.js.map +0 -1
- package/esm/components/Avatar/AvatarView/components/halfbodyAvatar.d.ts +0 -9
- package/esm/components/Avatar/AvatarView/components/halfbodyAvatar.js +0 -35
- package/esm/components/Avatar/AvatarView/components/halfbodyAvatar.js.map +0 -1
- package/esm/components/Avatar/AvatarView/components/loader.d.ts +0 -5
- package/esm/components/Avatar/AvatarView/components/loader.js +0 -9
- package/esm/components/Avatar/AvatarView/components/loader.js.map +0 -1
- package/esm/components/Avatar/AvatarView/utils/useMouthSpeaking.d.ts +0 -2
- package/esm/components/Avatar/AvatarView/utils/useMouthSpeaking.js +0 -65
- package/esm/components/Avatar/AvatarView/utils/useMouthSpeaking.js.map +0 -1
- package/esm/components/AvatarView/components/avatar.d.ts +0 -9
- package/esm/components/AvatarView/components/avatar.js +0 -31
- package/esm/components/AvatarView/components/avatar.js.map +0 -1
- package/esm/components/AvatarView/components/fullbodyAvatar.d.ts +0 -10
- package/esm/components/AvatarView/components/fullbodyAvatar.js +0 -58
- package/esm/components/AvatarView/components/fullbodyAvatar.js.map +0 -1
- package/esm/components/AvatarView/components/loader.d.ts +0 -5
- package/esm/components/AvatarView/components/loader.js +0 -9
- package/esm/components/AvatarView/components/loader.js.map +0 -1
- package/esm/components/AvatarView/index.d.ts +0 -17
- package/esm/components/AvatarView/index.js +0 -31
- package/esm/components/AvatarView/index.js.map +0 -1
- package/esm/components/AvatarView/utils/useEyeBlink.d.ts +0 -2
- package/esm/components/AvatarView/utils/useEyeBlink.js +0 -37
- package/esm/components/AvatarView/utils/useEyeBlink.js.map +0 -1
- package/esm/components/AvatarView/utils/useHeadMovement.d.ts +0 -2
- package/esm/components/AvatarView/utils/useHeadMovement.js +0 -50
- package/esm/components/AvatarView/utils/useHeadMovement.js.map +0 -1
- package/esm/components/AvatarView/utils/useLoadingMorphAnim.d.ts +0 -2
- package/esm/components/AvatarView/utils/useLoadingMorphAnim.js +0 -31
- package/esm/components/AvatarView/utils/useLoadingMorphAnim.js.map +0 -1
- package/esm/components/AvatarView/utils/useMouthSpeaking.d.ts +0 -2
- package/esm/components/AvatarView/utils/useMouthSpeaking.js +0 -57
- package/esm/components/AvatarView/utils/useMouthSpeaking.js.map +0 -1
- package/esm/components/AvatarView/utils/useSmile.d.ts +0 -2
- package/esm/components/AvatarView/utils/useSmile.js +0 -27
- package/esm/components/AvatarView/utils/useSmile.js.map +0 -1
- package/esm/components/AvatarView/utils/utils.d.ts +0 -13
- package/esm/components/AvatarView/utils/utils.js +0 -33
- package/esm/components/AvatarView/utils/utils.js.map +0 -1
- package/esm/components/ImageUpload/ImageUpload.css +0 -168
- package/esm/components/ImageUpload/ImageUpload.d.ts +0 -28
- package/esm/components/ImageUpload/ImageUpload.js +0 -160
- package/esm/components/ImageUpload/ImageUpload.js.map +0 -1
- package/esm/components/layouts/Default.d.ts +0 -17
- package/esm/components/layouts/Default.js +0 -5
- package/esm/components/layouts/Default.js.map +0 -1
- package/esm/components/ui/Message.d.ts +0 -17
- package/esm/components/ui/Message.js +0 -10
- package/esm/components/ui/Message.js.map +0 -1
|
@@ -543,19 +543,14 @@ const MemoriWidget = ({
|
|
|
543
543
|
const [hideEmissions, setHideEmissions] = useState(false);
|
|
544
544
|
|
|
545
545
|
const {
|
|
546
|
+
updateCurrentViseme,
|
|
546
547
|
startProcessing,
|
|
547
|
-
|
|
548
|
+
resetAndStartProcessing,
|
|
549
|
+
isProcessing,
|
|
548
550
|
addViseme,
|
|
551
|
+
stopProcessing,
|
|
549
552
|
resetVisemeQueue,
|
|
550
|
-
isProcessing,
|
|
551
553
|
} = useViseme();
|
|
552
|
-
const audioContextRef = useRef<AudioContext | null>(null);
|
|
553
|
-
const speechSynthesizerRef = useRef<speechSdk.SpeechSynthesizer | null>(null);
|
|
554
|
-
const audioDestinationRef = useRef<speechSdk.SpeakerAudioDestination | null>(
|
|
555
|
-
null
|
|
556
|
-
);
|
|
557
|
-
const currentSpeechRef = useRef<{ cancel: () => void } | null>(null);
|
|
558
|
-
|
|
559
554
|
|
|
560
555
|
useEffect(() => {
|
|
561
556
|
setIsPlayingAudio(!!speechSynthesizer);
|
|
@@ -1890,167 +1885,204 @@ const MemoriWidget = ({
|
|
|
1890
1885
|
const e = new CustomEvent('MemoriEndSpeak');
|
|
1891
1886
|
document.dispatchEvent(e);
|
|
1892
1887
|
};
|
|
1893
|
-
const initializeAudioContext = useCallback(() => {
|
|
1894
|
-
if (!audioContextRef.current || audioContextRef.current.state === 'closed') {
|
|
1895
|
-
audioContextRef.current = new (window.AudioContext || (window as any).webkitAudioContext)() as unknown as IAudioContext;
|
|
1896
|
-
}
|
|
1897
|
-
return audioContextRef.current;
|
|
1898
|
-
}, []);
|
|
1899
|
-
|
|
1900
|
-
const initializeSpeechSynthesizer = useCallback((audioConfig: speechSdk.AudioConfig) => {
|
|
1901
|
-
if (!speechSynthesizerRef.current && AZURE_COGNITIVE_SERVICES_TTS_KEY) {
|
|
1902
|
-
const speechConfig = speechSdk.SpeechConfig.fromSubscription(
|
|
1903
|
-
AZURE_COGNITIVE_SERVICES_TTS_KEY,
|
|
1904
|
-
'eastus'
|
|
1905
|
-
);
|
|
1906
|
-
speechSynthesizerRef.current = new speechSdk.SpeechSynthesizer(speechConfig, audioConfig);
|
|
1907
|
-
}
|
|
1908
|
-
return speechSynthesizerRef.current;
|
|
1909
|
-
}, []);
|
|
1910
|
-
|
|
1911
|
-
const stopCurrentSpeech = useCallback(() => {
|
|
1912
|
-
if (currentSpeechRef.current) {
|
|
1913
|
-
currentSpeechRef.current.cancel();
|
|
1914
|
-
currentSpeechRef.current = null;
|
|
1915
|
-
}
|
|
1916
|
-
if (audioContextRef.current) {
|
|
1917
|
-
audioContextRef.current.suspend();
|
|
1918
|
-
}
|
|
1919
|
-
if (audioDestinationRef.current) {
|
|
1920
|
-
audioDestinationRef.current.pause();
|
|
1921
|
-
}
|
|
1922
|
-
setIsPlayingAudio(false);
|
|
1923
|
-
stopProcessing();
|
|
1924
|
-
resetVisemeQueue();
|
|
1925
|
-
}, []);
|
|
1926
1888
|
|
|
1927
|
-
const speak =
|
|
1889
|
+
const speak = (text: string): void => {
|
|
1928
1890
|
if (!AZURE_COGNITIVE_SERVICES_TTS_KEY || preview) {
|
|
1929
1891
|
emitEndSpeakEvent();
|
|
1930
1892
|
return;
|
|
1931
1893
|
}
|
|
1932
|
-
|
|
1933
1894
|
stopListening();
|
|
1934
|
-
|
|
1895
|
+
// stopAudio();
|
|
1935
1896
|
|
|
1936
|
-
if (preview
|
|
1937
|
-
|
|
1897
|
+
if (preview) return;
|
|
1898
|
+
|
|
1899
|
+
if (muteSpeaker || speakerMuted) {
|
|
1900
|
+
memoriSpeaking = false;
|
|
1938
1901
|
setMemoriTyping(false);
|
|
1902
|
+
|
|
1939
1903
|
emitEndSpeakEvent();
|
|
1904
|
+
|
|
1905
|
+
// trigger start continuous listening if set, see MemoriChat
|
|
1940
1906
|
if (continuousSpeech) {
|
|
1941
1907
|
setListeningTimeout();
|
|
1942
1908
|
}
|
|
1943
1909
|
return;
|
|
1944
1910
|
}
|
|
1945
1911
|
|
|
1946
|
-
|
|
1947
|
-
const audioContext = initializeAudioContext();
|
|
1948
|
-
await audioContext.resume();
|
|
1912
|
+
if (audioDestination) audioDestination.pause();
|
|
1949
1913
|
|
|
1950
|
-
|
|
1951
|
-
|
|
1914
|
+
let isSafari =
|
|
1915
|
+
window.navigator.userAgent.includes('Safari') &&
|
|
1916
|
+
!window.navigator.userAgent.includes('Chrome');
|
|
1917
|
+
let isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent);
|
|
1918
|
+
if ((audioContext.state as string) === 'interrupted') {
|
|
1919
|
+
audioContext.resume().then(() => speak(text));
|
|
1920
|
+
return;
|
|
1921
|
+
}
|
|
1922
|
+
if (audioContext.state === 'closed') {
|
|
1923
|
+
audioContext = new AudioContext();
|
|
1924
|
+
let buffer = audioContext.createBuffer(1, 10000, 22050);
|
|
1925
|
+
let source = audioContext.createBufferSource();
|
|
1926
|
+
source.buffer = buffer;
|
|
1927
|
+
source.connect(audioContext.destination);
|
|
1928
|
+
} else if (audioContext.state === 'suspended') {
|
|
1929
|
+
stopAudio();
|
|
1930
|
+
|
|
1931
|
+
audioContext = new AudioContext();
|
|
1932
|
+
let buffer = audioContext.createBuffer(1, 10000, 22050);
|
|
1933
|
+
let source = audioContext.createBufferSource();
|
|
1934
|
+
source.buffer = buffer;
|
|
1935
|
+
source.connect(audioContext.destination);
|
|
1936
|
+
}
|
|
1937
|
+
|
|
1938
|
+
if (!speechSynthesizer) {
|
|
1939
|
+
if (!isIOS) {
|
|
1940
|
+
audioDestination = new speechSdk.SpeakerAudioDestination();
|
|
1952
1941
|
}
|
|
1942
|
+
let audioConfig =
|
|
1943
|
+
speechSdk.AudioConfig.fromSpeakerOutput(audioDestination);
|
|
1944
|
+
speechSynthesizer = new speechSdk.SpeechSynthesizer(
|
|
1945
|
+
speechConfig,
|
|
1946
|
+
audioConfig
|
|
1947
|
+
);
|
|
1948
|
+
}
|
|
1953
1949
|
|
|
1954
|
-
|
|
1955
|
-
|
|
1950
|
+
const source = audioContext.createBufferSource();
|
|
1951
|
+
source.addEventListener('ended', () => {
|
|
1952
|
+
setIsPlayingAudio(false);
|
|
1953
|
+
memoriSpeaking = false;
|
|
1954
|
+
});
|
|
1955
|
+
audioDestination.onAudioEnd = () => {
|
|
1956
|
+
setIsPlayingAudio(false);
|
|
1957
|
+
memoriSpeaking = false;
|
|
1958
|
+
source.disconnect();
|
|
1956
1959
|
|
|
1957
|
-
|
|
1960
|
+
emitEndSpeakEvent();
|
|
1958
1961
|
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
console.log('viseme added')
|
|
1963
|
-
};
|
|
1964
|
-
}
|
|
1965
|
-
startProcessing();
|
|
1966
|
-
|
|
1967
|
-
const textToSpeak = escapeHTML(stripMarkdown(stripEmojis(stripHTML(stripOutputTags(text)))));
|
|
1968
|
-
|
|
1969
|
-
const ssml = `
|
|
1970
|
-
<speak version="1.0"
|
|
1971
|
-
xmlns="http://www.w3.org/2001/10/synthesis"
|
|
1972
|
-
xmlns:mstts="https://www.w3.org/2001/mstts"
|
|
1973
|
-
xml:lang="${getCultureCodeByLanguage(userLang)}">
|
|
1974
|
-
<voice name="${getTTSVoice(userLang)}">
|
|
1975
|
-
<s>${replaceTextWithPhonemes(textToSpeak, userLang.toLowerCase())}</s>
|
|
1976
|
-
</voice>
|
|
1977
|
-
</speak>
|
|
1978
|
-
`;
|
|
1979
|
-
|
|
1980
|
-
const speakPromise = new Promise<speechSdk.SpeechSynthesisResult>((resolve, reject) => {
|
|
1981
|
-
speechSynthesizer?.speakSsmlAsync(
|
|
1982
|
-
ssml,
|
|
1983
|
-
result => resolve(result),
|
|
1984
|
-
error => reject(error)
|
|
1985
|
-
);
|
|
1986
|
-
});
|
|
1962
|
+
// trigger start continuous listening if set
|
|
1963
|
+
onEndSpeakStartListen();
|
|
1964
|
+
};
|
|
1987
1965
|
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
speechSynthesizer?.close();
|
|
1991
|
-
audioDestinationRef.current?.pause();
|
|
1992
|
-
}
|
|
1993
|
-
};
|
|
1966
|
+
// Add this before starting new speech synthesis
|
|
1967
|
+
resetVisemeQueue();
|
|
1994
1968
|
|
|
1995
|
-
|
|
1969
|
+
// Set up the viseme event handler
|
|
1970
|
+
speechSynthesizer.visemeReceived = function (_, e) {
|
|
1971
|
+
addViseme(e.visemeId, e.audioOffset);
|
|
1972
|
+
};
|
|
1996
1973
|
|
|
1997
|
-
|
|
1974
|
+
const textToSpeak = escapeHTML(
|
|
1975
|
+
stripMarkdown(stripEmojis(stripHTML(stripOutputTags(text))))
|
|
1976
|
+
);
|
|
1998
1977
|
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
1978
|
+
speechSynthesizer.speakSsmlAsync(
|
|
1979
|
+
`<speak version="1.0" xmlns="http://www.w3.org/2001/10/synthesis" xmlns:mstts="https://www.w3.org/2001/mstts" xmlns:emo="http://www.w3.org/2009/10/emotionml" xml:lang="${getCultureCodeByLanguage(
|
|
1980
|
+
userLang
|
|
1981
|
+
)}"><voice name="${getTTSVoice(userLang)}"><s>${replaceTextWithPhonemes(
|
|
1982
|
+
textToSpeak,
|
|
1983
|
+
userLang.toLowerCase()
|
|
1984
|
+
)}</s></voice></speak>`,
|
|
1985
|
+
result => {
|
|
1986
|
+
if (result) {
|
|
1987
|
+
setIsPlayingAudio(true);
|
|
1988
|
+
memoriSpeaking = true;
|
|
2004
1989
|
|
|
2005
|
-
|
|
2006
|
-
|
|
1990
|
+
try {
|
|
1991
|
+
// Decode the audio data
|
|
1992
|
+
audioContext!.decodeAudioData(result.audioData, function (buffer) {
|
|
1993
|
+
console.log('decoded');
|
|
1994
|
+
const currentSource = audioContext!.createBufferSource();
|
|
1995
|
+
currentSource.buffer = buffer;
|
|
1996
|
+
currentSource.connect(audioContext!.destination);
|
|
1997
|
+
startProcessing();
|
|
1998
|
+
currentSource.start();
|
|
1999
|
+
|
|
2000
|
+
currentSource.onended = () => {
|
|
2001
|
+
console.log('ended');
|
|
2002
|
+
setIsPlayingAudio(false);
|
|
2003
|
+
memoriSpeaking = false;
|
|
2004
|
+
stopProcessing();
|
|
2005
|
+
resetVisemeQueue();
|
|
2006
|
+
emitEndSpeakEvent();
|
|
2007
|
+
};
|
|
2008
|
+
});
|
|
2009
|
+
|
|
2010
|
+
// Handle the audio context state changes
|
|
2011
|
+
audioContext.onstatechange = () => {
|
|
2012
|
+
if (
|
|
2013
|
+
audioContext.state === 'suspended' ||
|
|
2014
|
+
audioContext.state === 'closed'
|
|
2015
|
+
) {
|
|
2016
|
+
console.log('suspended');
|
|
2017
|
+
source.disconnect();
|
|
2018
|
+
setIsPlayingAudio(false);
|
|
2019
|
+
stopProcessing();
|
|
2020
|
+
resetVisemeQueue();
|
|
2021
|
+
memoriSpeaking = false;
|
|
2022
|
+
emitEndSpeakEvent();
|
|
2023
|
+
} else if ((audioContext.state as string) === 'interrupted') {
|
|
2024
|
+
console.log('interrupted');
|
|
2025
|
+
stopProcessing();
|
|
2026
|
+
resetVisemeQueue();
|
|
2027
|
+
|
|
2028
|
+
audioContext.resume();
|
|
2029
|
+
}
|
|
2030
|
+
};
|
|
2031
|
+
} catch (e) {
|
|
2032
|
+
console.warn('speak error: ', e);
|
|
2033
|
+
window.speechSynthesis.speak(new SpeechSynthesisUtterance(text));
|
|
2034
|
+
setIsPlayingAudio(false);
|
|
2035
|
+
memoriSpeaking = false;
|
|
2036
|
+
stopProcessing();
|
|
2037
|
+
resetVisemeQueue();
|
|
2038
|
+
|
|
2039
|
+
if (speechSynthesizer) {
|
|
2040
|
+
speechSynthesizer.close();
|
|
2041
|
+
speechSynthesizer = null;
|
|
2042
|
+
}
|
|
2043
|
+
emitEndSpeakEvent();
|
|
2044
|
+
}
|
|
2045
|
+
} else {
|
|
2046
|
+
audioContext.resume();
|
|
2007
2047
|
stopProcessing();
|
|
2008
2048
|
resetVisemeQueue();
|
|
2009
|
-
|
|
2049
|
+
setIsPlayingAudio(false);
|
|
2050
|
+
memoriSpeaking = false;
|
|
2010
2051
|
emitEndSpeakEvent();
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2052
|
+
}
|
|
2053
|
+
},
|
|
2054
|
+
error => {
|
|
2055
|
+
console.error('speak:', error);
|
|
2056
|
+
window.speechSynthesis.speak(new SpeechSynthesisUtterance(text));
|
|
2057
|
+
setIsPlayingAudio(false);
|
|
2058
|
+
memoriSpeaking = false;
|
|
2017
2059
|
stopProcessing();
|
|
2018
2060
|
resetVisemeQueue();
|
|
2019
|
-
|
|
2061
|
+
emitEndSpeakEvent();
|
|
2020
2062
|
}
|
|
2021
|
-
|
|
2022
|
-
console.error('Speech synthesis error:', error);
|
|
2023
|
-
stopProcessing();
|
|
2024
|
-
resetVisemeQueue();
|
|
2025
|
-
// Fallback to browser's speech synthesis
|
|
2026
|
-
const utterance = new SpeechSynthesisUtterance(text);
|
|
2027
|
-
window.speechSynthesis.speak(utterance);
|
|
2028
|
-
} finally {
|
|
2029
|
-
setMemoriTyping(false);
|
|
2030
|
-
}
|
|
2031
|
-
}, [initializeAudioContext, initializeSpeechSynthesizer, stopCurrentSpeech]);
|
|
2063
|
+
);
|
|
2032
2064
|
|
|
2033
|
-
|
|
2065
|
+
setMemoriTyping(false);
|
|
2066
|
+
};
|
|
2067
|
+
const stopAudio = () => {
|
|
2034
2068
|
setIsPlayingAudio(false);
|
|
2035
2069
|
memoriSpeaking = false;
|
|
2036
2070
|
try {
|
|
2037
|
-
if (
|
|
2038
|
-
|
|
2039
|
-
|
|
2071
|
+
if (speechSynthesizer) {
|
|
2072
|
+
speechSynthesizer.close();
|
|
2073
|
+
speechSynthesizer = null;
|
|
2040
2074
|
}
|
|
2041
|
-
if (
|
|
2042
|
-
|
|
2075
|
+
if (audioContext.state !== 'closed') {
|
|
2076
|
+
audioContext.close();
|
|
2043
2077
|
}
|
|
2044
|
-
if (
|
|
2045
|
-
|
|
2046
|
-
|
|
2078
|
+
if (audioDestination) {
|
|
2079
|
+
audioDestination.pause();
|
|
2080
|
+
audioDestination.close();
|
|
2047
2081
|
}
|
|
2048
|
-
stopCurrentSpeech();
|
|
2049
2082
|
} catch (e) {
|
|
2050
2083
|
console.debug('stopAudio error: ', e);
|
|
2051
2084
|
}
|
|
2052
|
-
}
|
|
2053
|
-
|
|
2085
|
+
};
|
|
2054
2086
|
|
|
2055
2087
|
/**
|
|
2056
2088
|
* Focus on the chat input on mount
|
|
@@ -2214,12 +2246,6 @@ const MemoriWidget = ({
|
|
|
2214
2246
|
useEffect(() => {
|
|
2215
2247
|
return () => {
|
|
2216
2248
|
resetUIEffects();
|
|
2217
|
-
if (speechSynthesizerRef.current) {
|
|
2218
|
-
speechSynthesizerRef.current.close();
|
|
2219
|
-
}
|
|
2220
|
-
if (audioContextRef.current) {
|
|
2221
|
-
audioContextRef.current.close();
|
|
2222
|
-
}
|
|
2223
2249
|
};
|
|
2224
2250
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2225
2251
|
}, []);
|
|
@@ -2973,7 +2999,9 @@ const MemoriWidget = ({
|
|
|
2973
2999
|
|
|
2974
3000
|
const showFullHistory =
|
|
2975
3001
|
showOnlyLastMessages === undefined
|
|
2976
|
-
? layout !== 'TOTEM' &&
|
|
3002
|
+
? layout !== 'TOTEM' &&
|
|
3003
|
+
layout !== 'WEBSITE_ASSISTANT' &&
|
|
3004
|
+
layout !== 'HIDDEN_CHAT'
|
|
2977
3005
|
: !showOnlyLastMessages;
|
|
2978
3006
|
|
|
2979
3007
|
const headerProps: HeaderProps = {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React
|
|
1
|
+
import React from 'react';
|
|
2
2
|
import Spin from '../ui/Spin';
|
|
3
3
|
import { LayoutProps } from '../MemoriWidget/MemoriWidget';
|
|
4
4
|
|
|
@@ -21,20 +21,15 @@ const ZoomedFullBodyLayout: React.FC<LayoutProps> = ({
|
|
|
21
21
|
loading = false,
|
|
22
22
|
poweredBy,
|
|
23
23
|
}) => {
|
|
24
|
-
useEffect(() => {
|
|
25
|
-
document.body.style.overflow = 'hidden';
|
|
26
|
-
return () => {
|
|
27
|
-
document.body.style.overflow = '';
|
|
28
|
-
};
|
|
29
|
-
}, []);
|
|
30
|
-
|
|
31
24
|
return (
|
|
32
25
|
<>
|
|
33
26
|
{integrationStyle}
|
|
34
27
|
{integrationBackground}
|
|
35
28
|
|
|
36
29
|
<Spin className="memori-spin--zoomed-full-body" spinning={loading}>
|
|
37
|
-
{showInstruct && ChangeMode && changeModeProps &&
|
|
30
|
+
{showInstruct && ChangeMode && changeModeProps && (
|
|
31
|
+
<ChangeMode {...changeModeProps} />
|
|
32
|
+
)}
|
|
38
33
|
|
|
39
34
|
{Header && headerProps && <Header {...headerProps} />}
|
|
40
35
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
.memori-spin--zoomed-full-body {
|
|
2
|
-
height:
|
|
2
|
+
height: 100vh !important;
|
|
3
3
|
}
|
|
4
4
|
|
|
5
5
|
.memori--powered-by-custom {
|
|
@@ -13,4 +13,8 @@
|
|
|
13
13
|
|
|
14
14
|
.memori--grid-column--zoomed-full-body {
|
|
15
15
|
max-height: calc(100% - 80px) !important;
|
|
16
|
-
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.memori.memori-widget.memori-layout-zoomed_full_body .memori--grid {
|
|
19
|
+
height: calc(100% - 25px);
|
|
20
|
+
}
|
|
@@ -1,9 +1,16 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import React, {
|
|
2
|
+
createContext,
|
|
3
|
+
useContext,
|
|
4
|
+
useRef,
|
|
5
|
+
useCallback,
|
|
6
|
+
useState,
|
|
7
|
+
useEffect,
|
|
8
|
+
} from 'react';
|
|
9
|
+
|
|
10
|
+
type Viseme = {
|
|
11
|
+
name: string;
|
|
12
|
+
weight: number;
|
|
13
|
+
startTime: number;
|
|
7
14
|
endTime: number;
|
|
8
15
|
};
|
|
9
16
|
|
|
@@ -13,6 +20,7 @@ interface VisemeContextType {
|
|
|
13
20
|
startProcessing: () => void;
|
|
14
21
|
stopProcessing: () => void;
|
|
15
22
|
resetVisemeQueue: () => void;
|
|
23
|
+
resetAndStartProcessing: () => void;
|
|
16
24
|
isProcessing: boolean;
|
|
17
25
|
}
|
|
18
26
|
|
|
@@ -44,80 +52,98 @@ const VISEME_MAP: { [key: number]: string } = {
|
|
|
44
52
|
21: 'viseme_PP', // y (closest match, could be debated)
|
|
45
53
|
};
|
|
46
54
|
|
|
47
|
-
const DEFAULT_VISEME_DURATION = 0.04 //0; // Reduced from 0.4 for smoother transitions
|
|
48
|
-
const VISEME_OVERLAP = 0.
|
|
49
|
-
const SMOOTHING_FACTOR = 0.35 // New constant for weight smoothing
|
|
50
|
-
const TIME_OFFSET
|
|
51
|
-
const PRELOAD_TIME =
|
|
55
|
+
const DEFAULT_VISEME_DURATION = 0.04; //0; // Reduced from 0.4 for smoother transitions
|
|
56
|
+
const VISEME_OVERLAP = 0.15; // Slightly increased from 0.04 for more overlap
|
|
57
|
+
const SMOOTHING_FACTOR = 0.35; // New constant for weight smoothing
|
|
58
|
+
const TIME_OFFSET = -0.04; // Adjust this value as needed (in seconds)
|
|
59
|
+
const PRELOAD_TIME = 1; // Preload visemes 0.5 seconds in advance
|
|
52
60
|
|
|
53
|
-
export const VisemeProvider: React.FC<{ children: React.ReactNode }> = ({
|
|
61
|
+
export const VisemeProvider: React.FC<{ children: React.ReactNode }> = ({
|
|
62
|
+
children,
|
|
63
|
+
}) => {
|
|
54
64
|
const visemeQueueRef = useRef<Viseme[]>([]);
|
|
55
65
|
const startTimeRef = useRef<number | null>(null);
|
|
56
66
|
const [isProcessing, setIsProcessing] = useState(false);
|
|
57
67
|
const lastVisemeRef = useRef<Viseme | null>(null);
|
|
58
68
|
|
|
59
|
-
const addViseme = useCallback(
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
69
|
+
const addViseme = useCallback(
|
|
70
|
+
(visemeId: number, audioOffset: number) => {
|
|
71
|
+
const visemeName = VISEME_MAP[visemeId] || 'viseme_sil';
|
|
72
|
+
const startTime = audioOffset / 10000000 + TIME_OFFSET;
|
|
73
|
+
const endTime = startTime + DEFAULT_VISEME_DURATION;
|
|
74
|
+
const newViseme: Viseme = {
|
|
75
|
+
name: visemeName,
|
|
76
|
+
weight: 0,
|
|
77
|
+
startTime,
|
|
78
|
+
endTime,
|
|
79
|
+
};
|
|
80
|
+
visemeQueueRef.current.push(newViseme);
|
|
81
|
+
|
|
82
|
+
if (!isProcessing) {
|
|
83
|
+
startProcessing();
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
[isProcessing]
|
|
87
|
+
);
|
|
75
88
|
|
|
76
|
-
const updateCurrentViseme = useCallback(
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
const elapsedTime = currentTime - startTimeRef.current + PRELOAD_TIME
|
|
83
|
-
|
|
84
|
-
// Remove expired visemes
|
|
85
|
-
visemeQueueRef.current = visemeQueueRef.current.filter(v => v.endTime > elapsedTime);
|
|
86
|
-
|
|
87
|
-
const currentViseme = visemeQueueRef.current.find(v =>
|
|
88
|
-
v.startTime <= elapsedTime && v.endTime > elapsedTime - VISEME_OVERLAP
|
|
89
|
-
);
|
|
90
|
-
|
|
91
|
-
if (currentViseme) {
|
|
92
|
-
console.log('CurrentViseme Found!')
|
|
93
|
-
const visemeProgress = (elapsedTime - currentViseme.startTime) / (currentViseme.endTime - currentViseme.startTime);
|
|
94
|
-
const targetWeight = Math.sin(Math.PI * Math.min(visemeProgress, 1));
|
|
95
|
-
|
|
96
|
-
// Smooth the weight transition
|
|
97
|
-
const smoothedWeight = lastVisemeRef.current
|
|
98
|
-
? lastVisemeRef.current.weight + (targetWeight - lastVisemeRef.current.weight) * SMOOTHING_FACTOR
|
|
99
|
-
: targetWeight;
|
|
100
|
-
|
|
101
|
-
const updatedViseme = { ...currentViseme, weight: smoothedWeight };
|
|
102
|
-
lastVisemeRef.current = updatedViseme;
|
|
103
|
-
return updatedViseme;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// Gradually reduce weight when no viseme is active
|
|
107
|
-
if (lastVisemeRef.current) {
|
|
108
|
-
const reducedWeight = lastVisemeRef.current.weight * (1 - SMOOTHING_FACTOR);
|
|
109
|
-
if (reducedWeight > 0.01) {
|
|
110
|
-
lastVisemeRef.current = { ...lastVisemeRef.current, weight: reducedWeight };
|
|
111
|
-
return lastVisemeRef.current;
|
|
89
|
+
const updateCurrentViseme = useCallback(
|
|
90
|
+
(currentTime: number): Viseme | null => {
|
|
91
|
+
if (!isProcessing || startTimeRef.current === null) {
|
|
92
|
+
console.log('StartTimeRef not set');
|
|
93
|
+
return null;
|
|
112
94
|
}
|
|
113
|
-
}
|
|
114
95
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
96
|
+
const elapsedTime = currentTime - startTimeRef.current + PRELOAD_TIME;
|
|
97
|
+
|
|
98
|
+
// Remove expired visemes
|
|
99
|
+
visemeQueueRef.current = visemeQueueRef.current.filter(
|
|
100
|
+
v => v.endTime > elapsedTime
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
const currentViseme = visemeQueueRef.current.find(
|
|
104
|
+
v =>
|
|
105
|
+
v.startTime <= elapsedTime && v.endTime > elapsedTime - VISEME_OVERLAP
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
if (currentViseme) {
|
|
109
|
+
console.log('CurrentViseme Found!');
|
|
110
|
+
const visemeProgress =
|
|
111
|
+
(elapsedTime - currentViseme.startTime) /
|
|
112
|
+
(currentViseme.endTime - currentViseme.startTime);
|
|
113
|
+
const targetWeight = Math.sin(Math.PI * Math.min(visemeProgress, 1));
|
|
114
|
+
|
|
115
|
+
// Smooth the weight transition
|
|
116
|
+
const smoothedWeight = lastVisemeRef.current
|
|
117
|
+
? lastVisemeRef.current.weight +
|
|
118
|
+
(targetWeight - lastVisemeRef.current.weight) * SMOOTHING_FACTOR
|
|
119
|
+
: targetWeight;
|
|
120
|
+
|
|
121
|
+
const updatedViseme = { ...currentViseme, weight: smoothedWeight };
|
|
122
|
+
lastVisemeRef.current = updatedViseme;
|
|
123
|
+
return updatedViseme;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Gradually reduce weight when no viseme is active
|
|
127
|
+
if (lastVisemeRef.current) {
|
|
128
|
+
const reducedWeight =
|
|
129
|
+
lastVisemeRef.current.weight * (1 - SMOOTHING_FACTOR);
|
|
130
|
+
if (reducedWeight > 0.01) {
|
|
131
|
+
lastVisemeRef.current = {
|
|
132
|
+
...lastVisemeRef.current,
|
|
133
|
+
weight: reducedWeight,
|
|
134
|
+
};
|
|
135
|
+
return lastVisemeRef.current;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
lastVisemeRef.current = null;
|
|
140
|
+
return null;
|
|
141
|
+
},
|
|
142
|
+
[isProcessing]
|
|
143
|
+
);
|
|
118
144
|
|
|
119
145
|
const startProcessing = useCallback(() => {
|
|
120
|
-
if (isProcessing) return;
|
|
146
|
+
// if (isProcessing) return;
|
|
121
147
|
startTimeRef.current = performance.now() / 1000;
|
|
122
148
|
setIsProcessing(true);
|
|
123
149
|
}, [isProcessing]);
|
|
@@ -133,11 +159,19 @@ export const VisemeProvider: React.FC<{ children: React.ReactNode }> = ({ childr
|
|
|
133
159
|
lastVisemeRef.current = null;
|
|
134
160
|
}, []);
|
|
135
161
|
|
|
162
|
+
const resetAndStartProcessing = useCallback(() => {
|
|
163
|
+
stopProcessing();
|
|
164
|
+
resetVisemeQueue();
|
|
165
|
+
startTimeRef.current = performance.now() / 1000;
|
|
166
|
+
setIsProcessing(true);
|
|
167
|
+
}, [stopProcessing, resetVisemeQueue]);
|
|
168
|
+
|
|
136
169
|
const contextValue = {
|
|
137
170
|
addViseme,
|
|
138
171
|
updateCurrentViseme,
|
|
139
172
|
startProcessing,
|
|
140
173
|
stopProcessing,
|
|
174
|
+
resetAndStartProcessing,
|
|
141
175
|
resetVisemeQueue,
|
|
142
176
|
isProcessing,
|
|
143
177
|
};
|
|
@@ -155,4 +189,4 @@ export const useViseme = (): VisemeContextType => {
|
|
|
155
189
|
throw new Error('useViseme must be used within a VisemeProvider');
|
|
156
190
|
}
|
|
157
191
|
return context;
|
|
158
|
-
};
|
|
192
|
+
};
|