@sage-rsc/talking-head-react 1.0.63 → 1.0.64
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 +2 -2
- package/dist/index.js +144 -138
- package/package.json +1 -1
- package/src/components/TalkingHeadAvatar.jsx +52 -46
package/package.json
CHANGED
|
@@ -442,22 +442,22 @@ const TalkingHeadAvatar = forwardRef(({
|
|
|
442
442
|
|
|
443
443
|
// Save remaining text from speechQueue before clearing it
|
|
444
444
|
let remainingText = '';
|
|
445
|
-
if (talkingHead.speechQueue && talkingHead.speechQueue.length > 0) {
|
|
445
|
+
if (talkingHead.speechQueue && talkingHead.speechQueue.length > 0 && pausedSpeechRef.current) {
|
|
446
446
|
// Extract text from remaining queue items
|
|
447
447
|
const remainingParts = talkingHead.speechQueue
|
|
448
|
-
.filter(item => item.text) // Only get items with text
|
|
448
|
+
.filter(item => item && item.text) // Only get items with text
|
|
449
449
|
.map(item => item.text)
|
|
450
450
|
.join(' ');
|
|
451
451
|
|
|
452
|
-
if (remainingParts) {
|
|
452
|
+
if (remainingParts && remainingParts.trim()) {
|
|
453
453
|
remainingText = remainingParts.trim();
|
|
454
454
|
}
|
|
455
455
|
}
|
|
456
456
|
|
|
457
|
-
//
|
|
458
|
-
if (
|
|
457
|
+
// Always save progress for resume (even if no remaining text, we'll resume from beginning)
|
|
458
|
+
if (pausedSpeechRef.current) {
|
|
459
459
|
speechProgressRef.current = {
|
|
460
|
-
remainingText: remainingText,
|
|
460
|
+
remainingText: remainingText || null,
|
|
461
461
|
originalText: pausedSpeechRef.current.text,
|
|
462
462
|
options: pausedSpeechRef.current.options
|
|
463
463
|
};
|
|
@@ -477,49 +477,55 @@ const TalkingHeadAvatar = forwardRef(({
|
|
|
477
477
|
}, []);
|
|
478
478
|
|
|
479
479
|
const resumeSpeaking = useCallback(async () => {
|
|
480
|
-
if (talkingHeadRef.current
|
|
481
|
-
|
|
480
|
+
if (!talkingHeadRef.current || !isPaused) {
|
|
481
|
+
return;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// Determine what text to speak - use remaining text if available, otherwise full text
|
|
485
|
+
let textToSpeak = '';
|
|
486
|
+
let optionsToUse = {};
|
|
487
|
+
|
|
488
|
+
if (speechProgressRef.current && speechProgressRef.current.remainingText) {
|
|
489
|
+
// Resume from where we paused - speak only the remaining text
|
|
490
|
+
textToSpeak = speechProgressRef.current.remainingText;
|
|
491
|
+
optionsToUse = speechProgressRef.current.options || {};
|
|
492
|
+
// Clear progress after using it
|
|
493
|
+
speechProgressRef.current = { remainingText: null, originalText: null, options: null };
|
|
494
|
+
} else if (pausedSpeechRef.current && pausedSpeechRef.current.text) {
|
|
495
|
+
// Fallback: if no progress tracked, resume from beginning
|
|
496
|
+
textToSpeak = pausedSpeechRef.current.text;
|
|
497
|
+
optionsToUse = pausedSpeechRef.current.options || {};
|
|
498
|
+
} else {
|
|
499
|
+
// Nothing to resume
|
|
500
|
+
console.warn('Resume called but no paused speech found');
|
|
501
|
+
setIsPaused(false);
|
|
502
|
+
isPausedRef.current = false;
|
|
503
|
+
return;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
// Clear pause state before speaking
|
|
507
|
+
setIsPaused(false);
|
|
508
|
+
isPausedRef.current = false;
|
|
509
|
+
|
|
510
|
+
// Resume audio context
|
|
511
|
+
await resumeAudioContext();
|
|
512
|
+
|
|
513
|
+
// Prepare speak options
|
|
514
|
+
const speakOptions = {
|
|
515
|
+
...optionsToUse,
|
|
516
|
+
lipsyncLang: optionsToUse.lipsyncLang || defaultAvatarConfig.lipsyncLang || 'en'
|
|
517
|
+
};
|
|
518
|
+
|
|
519
|
+
// Use speakText method which will set up the onSpeechEnd callback again
|
|
520
|
+
try {
|
|
521
|
+
await speakText(textToSpeak, speakOptions);
|
|
522
|
+
} catch (error) {
|
|
523
|
+
console.error('Error resuming speech:', error);
|
|
524
|
+
// Reset pause state on error
|
|
482
525
|
setIsPaused(false);
|
|
483
526
|
isPausedRef.current = false;
|
|
484
|
-
|
|
485
|
-
// Resume audio context
|
|
486
|
-
await resumeAudioContext();
|
|
487
|
-
|
|
488
|
-
// Determine what text to speak - use remaining text if available, otherwise full text
|
|
489
|
-
let textToSpeak = '';
|
|
490
|
-
let optionsToUse = {};
|
|
491
|
-
|
|
492
|
-
if (speechProgressRef.current && speechProgressRef.current.remainingText) {
|
|
493
|
-
// Resume from where we paused - speak only the remaining text
|
|
494
|
-
textToSpeak = speechProgressRef.current.remainingText;
|
|
495
|
-
optionsToUse = speechProgressRef.current.options || {};
|
|
496
|
-
// Clear progress after using it
|
|
497
|
-
speechProgressRef.current = { remainingText: null, originalText: null, options: null };
|
|
498
|
-
} else if (pausedSpeechRef.current && pausedSpeechRef.current.text) {
|
|
499
|
-
// Fallback: if no progress tracked, resume from beginning
|
|
500
|
-
textToSpeak = pausedSpeechRef.current.text;
|
|
501
|
-
optionsToUse = pausedSpeechRef.current.options || {};
|
|
502
|
-
} else {
|
|
503
|
-
// Nothing to resume
|
|
504
|
-
return;
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
// Prepare speak options
|
|
508
|
-
const speakOptions = {
|
|
509
|
-
...optionsToUse,
|
|
510
|
-
lipsyncLang: optionsToUse.lipsyncLang || defaultAvatarConfig.lipsyncLang || 'en'
|
|
511
|
-
};
|
|
512
|
-
|
|
513
|
-
// Use speakText method which will set up the onSpeechEnd callback again
|
|
514
|
-
if (talkingHeadRef.current.lipsync && Object.keys(talkingHeadRef.current.lipsync).length > 0) {
|
|
515
|
-
if (talkingHeadRef.current.setSlowdownRate) {
|
|
516
|
-
talkingHeadRef.current.setSlowdownRate(1.05);
|
|
517
|
-
}
|
|
518
|
-
// Call speakText which will handle everything including onSpeechEnd
|
|
519
|
-
await speakText(textToSpeak, speakOptions);
|
|
520
|
-
}
|
|
521
527
|
}
|
|
522
|
-
}, [resumeAudioContext, isPaused, speakText]);
|
|
528
|
+
}, [resumeAudioContext, isPaused, speakText, defaultAvatarConfig]);
|
|
523
529
|
|
|
524
530
|
const setMood = useCallback((mood) => {
|
|
525
531
|
if (talkingHeadRef.current) {
|