@sage-rsc/talking-head-react 1.0.45 → 1.0.46

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sage-rsc/talking-head-react",
3
- "version": "1.0.45",
3
+ "version": "1.0.46",
4
4
  "description": "A reusable React component for 3D talking avatars with lip-sync and text-to-speech",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",
@@ -308,6 +308,23 @@ const TalkingHeadAvatar = forwardRef(({
308
308
  checkInterval = setInterval(checkSpeechFinished, 50);
309
309
  }
310
310
 
311
+ // Also check if speech queue is empty and not speaking (meaning all sentences processed)
312
+ // This handles the case where text was split into sentences but all are processed
313
+ const speechQueueEmpty = !talkingHead.speechQueue || talkingHead.speechQueue.length === 0;
314
+
315
+ if (talkingHead && !talkingHead.isSpeaking && speechQueueEmpty &&
316
+ (!talkingHead.audioPlaylist || talkingHead.audioPlaylist.length === 0) &&
317
+ (!talkingHead.isAudioPlaying || talkingHead.isAudioPlaying === false)) {
318
+ // All speech has finished (all sentences processed and audio finished)
319
+ clearInterval(waitForAudioStart);
320
+ try {
321
+ options.onSpeechEnd();
322
+ } catch (e) {
323
+ console.error('Error in onSpeechEnd callback:', e);
324
+ }
325
+ return;
326
+ }
327
+
311
328
  // Timeout if audio doesn't start within reasonable time
312
329
  if (waitForAudioStartCount * 50 > maxWaitForAudioStart) {
313
330
  clearInterval(waitForAudioStart);
@@ -317,7 +334,9 @@ const TalkingHeadAvatar = forwardRef(({
317
334
  // Still waiting for API, but assume it will start soon
318
335
  audioStarted = true;
319
336
  checkInterval = setInterval(checkSpeechFinished, 50);
320
- } else {
337
+ } else if (talkingHead && !talkingHead.isSpeaking && speechQueueEmpty &&
338
+ (!talkingHead.audioPlaylist || talkingHead.audioPlaylist.length === 0) &&
339
+ (!talkingHead.isAudioPlaying || talkingHead.isAudioPlaying === false)) {
321
340
  // Speech never started or finished immediately, call callback
322
341
  try {
323
342
  options.onSpeechEnd();
@@ -353,10 +372,14 @@ const TalkingHeadAvatar = forwardRef(({
353
372
  // 1. Not speaking OR speech queue is empty
354
373
  // 2. Audio playlist is empty (no more audio to play)
355
374
  // 3. Not currently playing audio
375
+ // 4. Speech queue is empty (all sentences have been processed)
376
+ const speechQueueEmpty = !talkingHead.speechQueue || talkingHead.speechQueue.length === 0;
377
+
356
378
  const isFinished = talkingHead &&
357
379
  (!talkingHead.isSpeaking || talkingHead.isSpeaking === false) &&
358
380
  (!talkingHead.audioPlaylist || talkingHead.audioPlaylist.length === 0) &&
359
- (!talkingHead.isAudioPlaying || talkingHead.isAudioPlaying === false);
381
+ (!talkingHead.isAudioPlaying || talkingHead.isAudioPlaying === false) &&
382
+ speechQueueEmpty;
360
383
 
361
384
  if (isFinished) {
362
385
  if (checkInterval) {