@sage-rsc/talking-head-react 1.0.28 → 1.0.30
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/{fbxAnimationLoader-BAdAJQ7P.cjs → fbxAnimationLoader-BG4X_1Qa.cjs} +1 -1
- package/dist/{fbxAnimationLoader-xd44uqKF.js → fbxAnimationLoader-CO1F6v-w.js} +1 -1
- package/dist/index-BFQNNYmP.cjs +13 -0
- package/dist/{index-zMY6cyU2.js → index-V_d1NQ-5.js} +1031 -1031
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/src/components/CurriculumLearning.jsx +57 -29
- package/src/lib/talkinghead.mjs +1 -1
- package/dist/index-Dx7mDKJm.cjs +0 -13
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const i=require("./index-
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const i=require("./index-BFQNNYmP.cjs");exports.CurriculumLearning=i.CurriculumLearning;exports.TalkingHeadAvatar=i.TalkingHeadAvatar;exports.TalkingHeadComponent=i.TalkingHeadComponent;exports.animations=i.animations;exports.getActiveTTSConfig=i.getActiveTTSConfig;exports.getAnimation=i.getAnimation;exports.getVoiceOptions=i.getVoiceOptions;exports.hasAnimation=i.hasAnimation;
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useRef, useEffect, forwardRef, useImperativeHandle, useCallback } from 'react';
|
|
1
|
+
import React, { useRef, useEffect, useLayoutEffect, forwardRef, useImperativeHandle, useCallback } from 'react';
|
|
2
2
|
import TalkingHeadAvatar from './TalkingHeadAvatar';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -55,6 +55,9 @@ const CurriculumLearning = forwardRef(({
|
|
|
55
55
|
const startTeachingRef = useRef(null);
|
|
56
56
|
const nextLessonRef = useRef(null);
|
|
57
57
|
const completeLessonRef = useRef(null);
|
|
58
|
+
const nextQuestionRef = useRef(null);
|
|
59
|
+
const completeCurriculumRef = useRef(null);
|
|
60
|
+
const startQuestionsRef = useRef(null);
|
|
58
61
|
|
|
59
62
|
// Update callbacks ref when they change
|
|
60
63
|
useEffect(() => {
|
|
@@ -127,7 +130,7 @@ const CurriculumLearning = forwardRef(({
|
|
|
127
130
|
let feedbackMessage = `Congratulations! You've completed this lesson`;
|
|
128
131
|
if (stateRef.current.totalQuestions > 0) {
|
|
129
132
|
feedbackMessage += ` with a score of ${stateRef.current.score} out of ${stateRef.current.totalQuestions} (${percentage}%). `;
|
|
130
|
-
|
|
133
|
+
} else {
|
|
131
134
|
feedbackMessage += `! `;
|
|
132
135
|
}
|
|
133
136
|
|
|
@@ -185,20 +188,22 @@ const CurriculumLearning = forwardRef(({
|
|
|
185
188
|
}, 1000);
|
|
186
189
|
}
|
|
187
190
|
});
|
|
188
|
-
|
|
191
|
+
} else {
|
|
189
192
|
// This is the last lesson, complete curriculum instead
|
|
190
193
|
avatarRef.current.speakText(feedbackMessage, {
|
|
191
194
|
lipsyncLang: defaultAvatarConfig.lipsyncLang,
|
|
192
195
|
onSpeechEnd: () => {
|
|
193
196
|
// Add a small delay after speech ends for natural flow
|
|
194
197
|
setTimeout(() => {
|
|
195
|
-
|
|
198
|
+
if (completeCurriculumRef.current) {
|
|
199
|
+
completeCurriculumRef.current();
|
|
200
|
+
}
|
|
196
201
|
}, 1000);
|
|
197
202
|
}
|
|
198
203
|
});
|
|
199
204
|
}
|
|
200
205
|
}
|
|
201
|
-
}, [animations.lessonComplete, curriculum,
|
|
206
|
+
}, [animations.lessonComplete, curriculum, defaultAvatarConfig]);
|
|
202
207
|
|
|
203
208
|
// Complete entire curriculum
|
|
204
209
|
const completeCurriculum = useCallback(() => {
|
|
@@ -208,8 +213,8 @@ const CurriculumLearning = forwardRef(({
|
|
|
208
213
|
modules: curriculum.modules.length,
|
|
209
214
|
totalLessons: curriculum.modules.reduce((sum, mod) => sum + mod.lessons.length, 0)
|
|
210
215
|
});
|
|
211
|
-
|
|
212
|
-
|
|
216
|
+
|
|
217
|
+
if (avatarRef.current) {
|
|
213
218
|
avatarRef.current.setMood("celebrating");
|
|
214
219
|
if (animations.curriculumComplete) {
|
|
215
220
|
try {
|
|
@@ -262,7 +267,7 @@ const CurriculumLearning = forwardRef(({
|
|
|
262
267
|
avatarRef.current.speakText(`Now let me ask you some questions. Here's the first one: ${firstQuestion.question}`, { lipsyncLang: defaultAvatarConfig.lipsyncLang });
|
|
263
268
|
} else if (firstQuestion.type === 'true_false') {
|
|
264
269
|
avatarRef.current.speakText(`Let's start with some true or false questions. First question: ${firstQuestion.question}`, { lipsyncLang: defaultAvatarConfig.lipsyncLang });
|
|
265
|
-
|
|
270
|
+
} else {
|
|
266
271
|
avatarRef.current.speakText(`Now let me ask you some questions. Here's the first one: ${firstQuestion.question}`, { lipsyncLang: defaultAvatarConfig.lipsyncLang });
|
|
267
272
|
}
|
|
268
273
|
} else if (avatarRef.current) {
|
|
@@ -291,14 +296,14 @@ const CurriculumLearning = forwardRef(({
|
|
|
291
296
|
}
|
|
292
297
|
|
|
293
298
|
if (avatarRef.current && nextQuestionObj) {
|
|
294
|
-
|
|
299
|
+
avatarRef.current.setMood("happy");
|
|
295
300
|
avatarRef.current.setBodyMovement("idle");
|
|
296
301
|
|
|
297
302
|
// Play custom animation if available
|
|
298
303
|
if (animations.nextQuestion) {
|
|
299
|
-
|
|
304
|
+
try {
|
|
300
305
|
avatarRef.current.playAnimation(animations.nextQuestion, true);
|
|
301
|
-
|
|
306
|
+
} catch (error) {
|
|
302
307
|
console.warn('Failed to play nextQuestion animation:', error);
|
|
303
308
|
}
|
|
304
309
|
}
|
|
@@ -323,9 +328,12 @@ const CurriculumLearning = forwardRef(({
|
|
|
323
328
|
}
|
|
324
329
|
}
|
|
325
330
|
} else {
|
|
326
|
-
|
|
331
|
+
// Use ref to avoid circular dependency
|
|
332
|
+
if (completeLessonRef.current) {
|
|
333
|
+
completeLessonRef.current();
|
|
334
|
+
}
|
|
327
335
|
}
|
|
328
|
-
}, [animations.nextQuestion, getCurrentLesson,
|
|
336
|
+
}, [animations.nextQuestion, getCurrentLesson, getCurrentQuestion, defaultAvatarConfig]);
|
|
329
337
|
|
|
330
338
|
// Move to next lesson
|
|
331
339
|
const nextLesson = useCallback(() => {
|
|
@@ -358,9 +366,11 @@ const CurriculumLearning = forwardRef(({
|
|
|
358
366
|
}, 500);
|
|
359
367
|
}
|
|
360
368
|
} else {
|
|
361
|
-
|
|
369
|
+
if (completeCurriculumRef.current) {
|
|
370
|
+
completeCurriculumRef.current();
|
|
371
|
+
}
|
|
362
372
|
}
|
|
363
|
-
}, [curriculum
|
|
373
|
+
}, [curriculum]);
|
|
364
374
|
|
|
365
375
|
// Start teaching the lesson
|
|
366
376
|
const startTeaching = useCallback(() => {
|
|
@@ -406,7 +416,10 @@ const CurriculumLearning = forwardRef(({
|
|
|
406
416
|
setTimeout(() => {
|
|
407
417
|
stateRef.current.isTeaching = false;
|
|
408
418
|
if (currentLesson.questions && currentLesson.questions.length > 0) {
|
|
409
|
-
|
|
419
|
+
// Use ref to avoid circular dependency
|
|
420
|
+
if (startQuestionsRef.current) {
|
|
421
|
+
startQuestionsRef.current();
|
|
422
|
+
}
|
|
410
423
|
} else {
|
|
411
424
|
// No questions, complete the lesson using ref to avoid circular dependency
|
|
412
425
|
if (completeLessonRef.current) {
|
|
@@ -415,7 +428,7 @@ const CurriculumLearning = forwardRef(({
|
|
|
415
428
|
}
|
|
416
429
|
}, 8000);
|
|
417
430
|
}
|
|
418
|
-
}, [animations.teaching, getCurrentLesson,
|
|
431
|
+
}, [animations.teaching, getCurrentLesson, defaultAvatarConfig]);
|
|
419
432
|
|
|
420
433
|
// Handle answer selection
|
|
421
434
|
const handleAnswerSelect = useCallback((answer) => {
|
|
@@ -456,7 +469,9 @@ const CurriculumLearning = forwardRef(({
|
|
|
456
469
|
onSpeechEnd: () => {
|
|
457
470
|
// Add a small delay after speech ends for natural flow
|
|
458
471
|
setTimeout(() => {
|
|
459
|
-
|
|
472
|
+
if (nextQuestionRef.current) {
|
|
473
|
+
nextQuestionRef.current();
|
|
474
|
+
}
|
|
460
475
|
}, 500);
|
|
461
476
|
}
|
|
462
477
|
});
|
|
@@ -480,16 +495,20 @@ const CurriculumLearning = forwardRef(({
|
|
|
480
495
|
onSpeechEnd: () => {
|
|
481
496
|
// Add a small delay after speech ends for natural flow
|
|
482
497
|
setTimeout(() => {
|
|
483
|
-
|
|
498
|
+
if (nextQuestionRef.current) {
|
|
499
|
+
nextQuestionRef.current();
|
|
500
|
+
}
|
|
484
501
|
}, 500);
|
|
485
502
|
}
|
|
486
503
|
});
|
|
487
504
|
}
|
|
488
505
|
} else {
|
|
489
506
|
// If avatar not ready, move to next question immediately
|
|
490
|
-
|
|
507
|
+
if (nextQuestionRef.current) {
|
|
508
|
+
nextQuestionRef.current();
|
|
509
|
+
}
|
|
491
510
|
}
|
|
492
|
-
}, [animations.correct, animations.incorrect, getCurrentQuestion, checkAnswer,
|
|
511
|
+
}, [animations.correct, animations.incorrect, getCurrentQuestion, checkAnswer, defaultAvatarConfig]);
|
|
493
512
|
|
|
494
513
|
// Handle code test result submission
|
|
495
514
|
const handleCodeTestResult = useCallback((testResult) => {
|
|
@@ -530,8 +549,10 @@ const CurriculumLearning = forwardRef(({
|
|
|
530
549
|
});
|
|
531
550
|
|
|
532
551
|
// Handle answer using the same logic as regular questions
|
|
533
|
-
|
|
534
|
-
|
|
552
|
+
if (handleAnswerSelectRef.current) {
|
|
553
|
+
handleAnswerSelectRef.current(codeTestAnswer);
|
|
554
|
+
}
|
|
555
|
+
}, [getCurrentQuestion, checkAnswer, defaultAvatarConfig]);
|
|
535
556
|
|
|
536
557
|
// Reset curriculum
|
|
537
558
|
const resetCurriculum = useCallback(() => {
|
|
@@ -546,23 +567,30 @@ const CurriculumLearning = forwardRef(({
|
|
|
546
567
|
stateRef.current.totalQuestions = 0;
|
|
547
568
|
}, []);
|
|
548
569
|
|
|
549
|
-
// Handle avatar ready callback
|
|
570
|
+
// Handle avatar ready callback - use ref to avoid circular dependency
|
|
550
571
|
const handleAvatarReady = useCallback((talkingHead) => {
|
|
551
572
|
console.log('Avatar is ready!', talkingHead);
|
|
552
573
|
const currentLesson = getCurrentLesson();
|
|
553
574
|
if (autoStart && currentLesson?.avatar_script) {
|
|
554
575
|
setTimeout(() => {
|
|
555
|
-
|
|
576
|
+
if (startTeachingRef.current) {
|
|
577
|
+
startTeachingRef.current();
|
|
578
|
+
}
|
|
556
579
|
}, 1000);
|
|
557
580
|
}
|
|
558
|
-
}, [autoStart, getCurrentLesson
|
|
581
|
+
}, [autoStart, getCurrentLesson]);
|
|
559
582
|
|
|
560
|
-
//
|
|
561
|
-
|
|
583
|
+
// Set refs after all functions are defined - use useLayoutEffect for synchronous execution
|
|
584
|
+
// This ensures refs are set before React commits the render, avoiding initialization errors
|
|
585
|
+
useLayoutEffect(() => {
|
|
562
586
|
startTeachingRef.current = startTeaching;
|
|
563
587
|
nextLessonRef.current = nextLesson;
|
|
564
588
|
completeLessonRef.current = completeLesson;
|
|
565
|
-
|
|
589
|
+
nextQuestionRef.current = nextQuestion;
|
|
590
|
+
completeCurriculumRef.current = completeCurriculum;
|
|
591
|
+
startQuestionsRef.current = startQuestions;
|
|
592
|
+
handleAnswerSelectRef.current = handleAnswerSelect;
|
|
593
|
+
});
|
|
566
594
|
|
|
567
595
|
// Expose methods via ref (for external control)
|
|
568
596
|
useImperativeHandle(ref, () => ({
|
package/src/lib/talkinghead.mjs
CHANGED
|
@@ -3248,7 +3248,7 @@ class TalkingHead {
|
|
|
3248
3248
|
const module = LIPSYNC_MODULES[langLower];
|
|
3249
3249
|
|
|
3250
3250
|
if (module && module[className]) {
|
|
3251
|
-
|
|
3251
|
+
this.lipsync[lang] = new module[className];
|
|
3252
3252
|
console.log(`Loaded lip-sync module for ${lang}`);
|
|
3253
3253
|
} else {
|
|
3254
3254
|
console.warn(`Lip-sync module for ${lang} not found. Available modules:`, Object.keys(LIPSYNC_MODULES));
|