@sage-rsc/talking-head-react 1.7.8 → 1.7.9
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/dist/index.cjs +3 -3
- package/dist/index.js +633 -624
- package/package.json +1 -1
- package/src/components/SimpleTalkingAvatar.jsx +59 -4
- package/src/lib/talkinghead.mjs +4 -0
package/package.json
CHANGED
|
@@ -777,10 +777,26 @@ const SimpleTalkingAvatar = forwardRef(({
|
|
|
777
777
|
isMidSentence: audioPlaylist.length > 0
|
|
778
778
|
};
|
|
779
779
|
|
|
780
|
-
//
|
|
781
|
-
//
|
|
782
|
-
talkingHeadRef.current.
|
|
780
|
+
// IMPORTANT: Save speech queue BEFORE pausing if audio is playing
|
|
781
|
+
// We need to preserve it so remaining text continues after trimmed audio
|
|
782
|
+
const wasAudioPlaying = talkingHeadRef.current.isAudioPlaying || false;
|
|
783
|
+
const savedSpeechQueue = wasAudioPlaying ? [...(talkingHeadRef.current.speechQueue || [])] : null;
|
|
784
|
+
|
|
785
|
+
// Pause and get trimmed buffer if available
|
|
786
|
+
// pauseSpeaking() clears audioPlaylist but doesn't clear speechQueue
|
|
783
787
|
const pausedAudioData = talkingHeadRef.current.pauseSpeaking();
|
|
788
|
+
|
|
789
|
+
// If we have trimmed buffer, restore speech queue for continuation
|
|
790
|
+
// Otherwise, clear it (normal pause behavior)
|
|
791
|
+
if (pausedAudioData && pausedAudioData.audio && savedSpeechQueue) {
|
|
792
|
+
// Restore speech queue so remaining text continues after trimmed audio
|
|
793
|
+
talkingHeadRef.current.speechQueue.length = 0;
|
|
794
|
+
talkingHeadRef.current.speechQueue.push(...savedSpeechQueue);
|
|
795
|
+
} else {
|
|
796
|
+
// No trimmed buffer, clear speech queue normally
|
|
797
|
+
talkingHeadRef.current.speechQueue.length = 0;
|
|
798
|
+
}
|
|
799
|
+
|
|
784
800
|
pausedAudioDataRef.current = pausedAudioData; // Store trimmed buffer for exact resume
|
|
785
801
|
setIsPaused(true);
|
|
786
802
|
isPausedRef.current = true;
|
|
@@ -803,8 +819,47 @@ const SimpleTalkingAvatar = forwardRef(({
|
|
|
803
819
|
|
|
804
820
|
// If we have trimmed audio data from pause, resume from exact position
|
|
805
821
|
if (pausedAudioDataRef.current && pausedAudioDataRef.current.audio) {
|
|
822
|
+
// Ensure speaking state is set for animations to continue
|
|
823
|
+
isSpeakingRef.current = true;
|
|
824
|
+
|
|
825
|
+
// Restore animation group if it was set
|
|
826
|
+
const originalOptions = speechProgressRef.current?.options || pausedSpeechRef.current?.options || {};
|
|
827
|
+
const animationGroup = originalOptions.animationGroup || autoAnimationGroup;
|
|
828
|
+
if (animationGroup) {
|
|
829
|
+
currentAnimationGroupRef.current = animationGroup;
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
// Ensure remaining text is in speech queue so it continues after trimmed buffer
|
|
833
|
+
const remainingText = speechProgressRef.current?.remainingText;
|
|
834
|
+
if (remainingText && talkingHeadRef.current.speechQueue) {
|
|
835
|
+
// Re-add remaining text to speech queue so it continues after trimmed audio
|
|
836
|
+
// Split into sentences and add to queue
|
|
837
|
+
const sentences = remainingText.split(/[.!?]+/).filter(s => s.trim().length > 0);
|
|
838
|
+
sentences.forEach(sentence => {
|
|
839
|
+
talkingHeadRef.current.speechQueue.push({
|
|
840
|
+
text: sentence.trim(),
|
|
841
|
+
options: originalOptions
|
|
842
|
+
});
|
|
843
|
+
});
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
// Mark as speaking so audio continues and speech queue processes
|
|
847
|
+
talkingHeadRef.current.isSpeaking = true;
|
|
848
|
+
|
|
806
849
|
// Resume with trimmed buffer (exact position)
|
|
850
|
+
// After trimmed buffer finishes, playAudio will call startSpeaking() which processes speechQueue
|
|
807
851
|
await talkingHeadRef.current.playAudio(false, pausedAudioDataRef.current);
|
|
852
|
+
|
|
853
|
+
// Continue animations if animation group is set
|
|
854
|
+
// Start immediately and they will continue as long as isSpeakingRef is true
|
|
855
|
+
if (animationGroup && !originalOptions.skipAnimation) {
|
|
856
|
+
// Reset animation queue for smooth continuation
|
|
857
|
+
animationQueueRef.current = [];
|
|
858
|
+
playedAnimationsRef.current = [];
|
|
859
|
+
// Start playing animations immediately
|
|
860
|
+
playRandomAnimation(animationGroup);
|
|
861
|
+
}
|
|
862
|
+
|
|
808
863
|
pausedAudioDataRef.current = null; // Clear after use
|
|
809
864
|
return;
|
|
810
865
|
}
|
|
@@ -828,7 +883,7 @@ const SimpleTalkingAvatar = forwardRef(({
|
|
|
828
883
|
isPausedRef.current = false;
|
|
829
884
|
pausedAudioDataRef.current = null;
|
|
830
885
|
}
|
|
831
|
-
}, [isPaused, speakText, resumeAudioContext]);
|
|
886
|
+
}, [isPaused, speakText, resumeAudioContext, autoAnimationGroup, playRandomAnimation]);
|
|
832
887
|
|
|
833
888
|
// Stop speaking
|
|
834
889
|
const stopSpeaking = useCallback(() => {
|
package/src/lib/talkinghead.mjs
CHANGED
|
@@ -3773,6 +3773,8 @@ class TalkingHead {
|
|
|
3773
3773
|
this.audioSpeechSource.disconnect();
|
|
3774
3774
|
this.audioStartTime = null;
|
|
3775
3775
|
this.currentAudioItem = null;
|
|
3776
|
+
// Ensure isSpeaking is true so startSpeaking() processes the queue after trimmed audio
|
|
3777
|
+
this.isSpeaking = true;
|
|
3776
3778
|
this.playAudio(true);
|
|
3777
3779
|
}, { once: true });
|
|
3778
3780
|
|
|
@@ -3853,6 +3855,8 @@ class TalkingHead {
|
|
|
3853
3855
|
this.audioSpeechSource.disconnect();
|
|
3854
3856
|
this.audioStartTime = null;
|
|
3855
3857
|
this.currentAudioItem = null;
|
|
3858
|
+
// Ensure isSpeaking is true so startSpeaking() processes the queue
|
|
3859
|
+
this.isSpeaking = true;
|
|
3856
3860
|
this.playAudio(true);
|
|
3857
3861
|
}, { once: true });
|
|
3858
3862
|
|