@sage-rsc/talking-head-react 1.0.41 → 1.0.42
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.js
CHANGED
|
@@ -5251,10 +5251,10 @@ class Se {
|
|
|
5251
5251
|
let u = "", l = "", c = 0, d = [], g = [];
|
|
5252
5252
|
const y = Array.from(this.segmenter.segment(t), (x) => x.segment);
|
|
5253
5253
|
for (let x = 0; x < y.length; x++) {
|
|
5254
|
-
const v = x === y.length - 1,
|
|
5254
|
+
const v = x === y.length - 1, C = y[x].match(r);
|
|
5255
5255
|
let p = y[x].match(s);
|
|
5256
5256
|
const E = y[x].match(h), z = y[x].match(o);
|
|
5257
|
-
if (p && !v && !E && y[x + 1].match(s) && (p = !1), i && (u += y[x]),
|
|
5257
|
+
if (p && !v && !E && y[x + 1].match(s) && (p = !1), i && (u += y[x]), C && (!n || n.every((I) => x < I[0] || x > I[1])) && (l += y[x]), (z || p || v) && (l.length && (l = this.lipsyncPreProcessText(l, a), l.length && d.push({
|
|
5258
5258
|
mark: c,
|
|
5259
5259
|
word: l
|
|
5260
5260
|
})), u.length && (g.push({
|
|
@@ -5385,10 +5385,10 @@ class Se {
|
|
|
5385
5385
|
let y = 0.6 + this.convertRange(g, [0, u], [0, 0.4]);
|
|
5386
5386
|
if (u = Math.min(u, c.visemes.length * 200), d > 0)
|
|
5387
5387
|
for (let x = 0; x < c.visemes.length; x++) {
|
|
5388
|
-
const v = a + c.times[x] / d * u,
|
|
5388
|
+
const v = a + c.times[x] / d * u, C = c.durations[x] / d * u;
|
|
5389
5389
|
o.push({
|
|
5390
5390
|
template: { name: "viseme" },
|
|
5391
|
-
ts: [v - Math.min(60, 2 *
|
|
5391
|
+
ts: [v - Math.min(60, 2 * C / 3), v + Math.min(25, C / 2), v + C + Math.min(60, C / 2)],
|
|
5392
5392
|
vs: {
|
|
5393
5393
|
["viseme_" + c.visemes[x]]: [null, c.visemes[x] === "PP" || c.visemes[x] === "FF" ? 0.9 : y, 0]
|
|
5394
5394
|
}
|
|
@@ -5496,8 +5496,8 @@ class Se {
|
|
|
5496
5496
|
});
|
|
5497
5497
|
}
|
|
5498
5498
|
}
|
|
5499
|
-
const
|
|
5500
|
-
this.audioPlaylist.push({ anim:
|
|
5499
|
+
const C = [...t.anim, ...v];
|
|
5500
|
+
this.audioPlaylist.push({ anim: C, audio: d }), this.onSubtitles = t.onSubtitles || null, this.resetLips(), t.mood && this.setMood(t.mood), this.playAudio(), s.onend = () => {
|
|
5501
5501
|
e();
|
|
5502
5502
|
}, s.onerror = (p) => {
|
|
5503
5503
|
console.error("Speech synthesis error:", p.error), i(p.error);
|
|
@@ -6189,7 +6189,7 @@ class Se {
|
|
|
6189
6189
|
t === null && (t = h), e === null && (e = a), N.copy(this.armature.quaternion), N.multiply(this.poseTarget.props["Hips.quaternion"]), N.multiply(this.poseTarget.props["Spine.quaternion"]), N.multiply(this.poseTarget.props["Spine1.quaternion"]), N.multiply(this.poseTarget.props["Spine2.quaternion"]), N.multiply(this.poseTarget.props["Neck.quaternion"]), N.multiply(this.poseTarget.props["Head.quaternion"]), T.setFromQuaternion(N);
|
|
6190
6190
|
let u = T.x / (40 / 24), l = T.y / (9 / 4), c = Math.min(0.4, Math.max(-0.4, this.camera.rotation.x)), d = Math.min(0.4, Math.max(-0.4, this.camera.rotation.y)), g = Math.max(window.innerWidth - h, h), y = Math.max(window.innerHeight - a, a), x = this.convertRange(e, [a - y, a + y], [-0.3, 0.6]) - u + c, v = this.convertRange(t, [h - g, h + g], [-0.8, 0.8]) - l + d;
|
|
6191
6191
|
x = Math.min(0.6, Math.max(-0.3, x)), v = Math.min(0.8, Math.max(-0.8, v));
|
|
6192
|
-
let
|
|
6192
|
+
let C = (Math.random() - 0.5) / 4, p = (Math.random() - 0.5) / 4;
|
|
6193
6193
|
if (i) {
|
|
6194
6194
|
let E = this.animQueue.findIndex((I) => I.template.name === "lookat");
|
|
6195
6195
|
E !== -1 && this.animQueue.splice(E, 1);
|
|
@@ -6197,9 +6197,9 @@ class Se {
|
|
|
6197
6197
|
name: "lookat",
|
|
6198
6198
|
dt: [750, i],
|
|
6199
6199
|
vs: {
|
|
6200
|
-
bodyRotateX: [x +
|
|
6200
|
+
bodyRotateX: [x + C],
|
|
6201
6201
|
bodyRotateY: [v + p],
|
|
6202
|
-
eyesRotateX: [-3 *
|
|
6202
|
+
eyesRotateX: [-3 * C + 0.1],
|
|
6203
6203
|
eyesRotateY: [-5 * p],
|
|
6204
6204
|
browInnerUp: [[0, 0.7]],
|
|
6205
6205
|
mouthLeft: [[0, 0.7]],
|
|
@@ -6577,7 +6577,7 @@ class Se {
|
|
|
6577
6577
|
const x = t.iterations || 10;
|
|
6578
6578
|
if (e)
|
|
6579
6579
|
for (let v = 0; v < x; v++) {
|
|
6580
|
-
let
|
|
6580
|
+
let C = !1;
|
|
6581
6581
|
for (let p = 0, E = y.length; p < E; p++) {
|
|
6582
6582
|
const z = y[p].bone;
|
|
6583
6583
|
z.matrixWorld.decompose(h, a, u), a.invert(), o.setFromMatrixPosition(g.matrixWorld), r.subVectors(o, h), r.applyQuaternion(a), r.normalize(), s.subVectors(e, h), s.applyQuaternion(a), s.normalize();
|
|
@@ -6590,9 +6590,9 @@ class Se {
|
|
|
6590
6590
|
y[p].maxx !== void 0 ? y[p].maxx : 1 / 0,
|
|
6591
6591
|
y[p].maxy !== void 0 ? y[p].maxy : 1 / 0,
|
|
6592
6592
|
y[p].maxz !== void 0 ? y[p].maxz : 1 / 0
|
|
6593
|
-
))), z.updateMatrixWorld(!0),
|
|
6593
|
+
))), z.updateMatrixWorld(!0), C = !0);
|
|
6594
6594
|
}
|
|
6595
|
-
if (!
|
|
6595
|
+
if (!C) break;
|
|
6596
6596
|
}
|
|
6597
6597
|
n && y.forEach((v) => {
|
|
6598
6598
|
this.poseTarget.props[v.link + ".quaternion"].copy(v.bone.quaternion), this.poseTarget.props[v.link + ".quaternion"].t = this.animClock, this.poseTarget.props[v.link + ".quaternion"].d = n;
|
|
@@ -6685,7 +6685,7 @@ const ke = ye(({
|
|
|
6685
6685
|
style: y = {},
|
|
6686
6686
|
animations: x = {}
|
|
6687
6687
|
}, v) => {
|
|
6688
|
-
const
|
|
6688
|
+
const C = X(null), p = X(null), [E, z] = re(!0), [I, D] = re(null), [P, J] = re(!1), Y = xe(), S = n || Y.service;
|
|
6689
6689
|
let F;
|
|
6690
6690
|
S === "browser" ? F = {
|
|
6691
6691
|
service: "browser",
|
|
@@ -6726,9 +6726,9 @@ const ke = ye(({
|
|
|
6726
6726
|
lipsyncModules: ["en"],
|
|
6727
6727
|
cameraView: u
|
|
6728
6728
|
}, Q = M(async () => {
|
|
6729
|
-
if (!(!
|
|
6729
|
+
if (!(!C.current || p.current))
|
|
6730
6730
|
try {
|
|
6731
|
-
if (z(!0), D(null), p.current = new Se(
|
|
6731
|
+
if (z(!0), D(null), p.current = new Se(C.current, V), p.current.controls && (p.current.controls.enableRotate = !1, p.current.controls.enableZoom = !1, p.current.controls.enablePan = !1, p.current.controls.enableDamping = !1), x && Object.keys(x).length > 0 && (p.current.customAnimations = x), await p.current.showAvatar(W, (U) => {
|
|
6732
6732
|
if (U.lengthComputable) {
|
|
6733
6733
|
const O = Math.min(100, Math.round(U.loaded / U.total * 100));
|
|
6734
6734
|
c(O);
|
|
@@ -6745,11 +6745,11 @@ const ke = ye(({
|
|
|
6745
6745
|
console.warn("Error setting full body mode on initialization:", U);
|
|
6746
6746
|
}
|
|
6747
6747
|
p.current && p.current.controls && (p.current.controls.enableRotate = !1, p.current.controls.enableZoom = !1, p.current.controls.enablePan = !1, p.current.controls.enableDamping = !1, p.current.controls.update()), z(!1), J(!0), l(p.current);
|
|
6748
|
-
const
|
|
6748
|
+
const H = () => {
|
|
6749
6749
|
document.visibilityState === "visible" ? p.current?.start() : p.current?.stop();
|
|
6750
6750
|
};
|
|
6751
|
-
return document.addEventListener("visibilitychange",
|
|
6752
|
-
document.removeEventListener("visibilitychange",
|
|
6751
|
+
return document.addEventListener("visibilitychange", H), () => {
|
|
6752
|
+
document.removeEventListener("visibilitychange", H);
|
|
6753
6753
|
};
|
|
6754
6754
|
} catch (L) {
|
|
6755
6755
|
console.error("Error initializing TalkingHead:", L), D(L.message || "Failed to initialize avatar"), z(!1), d(L);
|
|
@@ -6758,17 +6758,17 @@ const ke = ye(({
|
|
|
6758
6758
|
he(() => (Q(), () => {
|
|
6759
6759
|
p.current && (p.current.stop(), p.current.dispose(), p.current = null);
|
|
6760
6760
|
}), [Q]), he(() => {
|
|
6761
|
-
if (!
|
|
6761
|
+
if (!C.current || !p.current) return;
|
|
6762
6762
|
const L = new ResizeObserver((U) => {
|
|
6763
6763
|
for (const O of U)
|
|
6764
6764
|
p.current && p.current.onResize && p.current.onResize();
|
|
6765
6765
|
});
|
|
6766
|
-
L.observe(
|
|
6767
|
-
const
|
|
6766
|
+
L.observe(C.current);
|
|
6767
|
+
const H = () => {
|
|
6768
6768
|
p.current && p.current.onResize && p.current.onResize();
|
|
6769
6769
|
};
|
|
6770
|
-
return window.addEventListener("resize",
|
|
6771
|
-
L.disconnect(), window.removeEventListener("resize",
|
|
6770
|
+
return window.addEventListener("resize", H), () => {
|
|
6771
|
+
L.disconnect(), window.removeEventListener("resize", H);
|
|
6772
6772
|
};
|
|
6773
6773
|
}, [P]);
|
|
6774
6774
|
const q = M(async () => {
|
|
@@ -6778,22 +6778,22 @@ const ke = ye(({
|
|
|
6778
6778
|
} catch (L) {
|
|
6779
6779
|
console.warn("Failed to resume audio context:", L);
|
|
6780
6780
|
}
|
|
6781
|
-
}, []), le = M(async (L,
|
|
6781
|
+
}, []), le = M(async (L, H = {}) => {
|
|
6782
6782
|
if (p.current && P)
|
|
6783
6783
|
try {
|
|
6784
6784
|
await q();
|
|
6785
6785
|
const U = {
|
|
6786
|
-
...
|
|
6787
|
-
lipsyncLang:
|
|
6786
|
+
...H,
|
|
6787
|
+
lipsyncLang: H.lipsyncLang || W.lipsyncLang || "en"
|
|
6788
6788
|
};
|
|
6789
|
-
if (
|
|
6789
|
+
if (H.onSpeechEnd && p.current) {
|
|
6790
6790
|
const O = p.current, ne = O.onAudioEnd;
|
|
6791
6791
|
let $ = null, pe = 0;
|
|
6792
6792
|
const ze = 600, Ce = () => {
|
|
6793
6793
|
if (pe++, pe > ze) {
|
|
6794
6794
|
$ && (clearInterval($), $ = null);
|
|
6795
6795
|
try {
|
|
6796
|
-
|
|
6796
|
+
H.onSpeechEnd();
|
|
6797
6797
|
} catch (ge) {
|
|
6798
6798
|
console.error("Error in onSpeechEnd callback:", ge);
|
|
6799
6799
|
}
|
|
@@ -6801,19 +6801,19 @@ const ke = ye(({
|
|
|
6801
6801
|
}
|
|
6802
6802
|
O && (!O.isSpeaking || O.isSpeaking === !1) && (!O.audioPlaylist || O.audioPlaylist.length === 0) && (!O.isAudioPlaying || O.isAudioPlaying === !1) && ($ && (clearInterval($), $ = null), setTimeout(() => {
|
|
6803
6803
|
try {
|
|
6804
|
-
|
|
6804
|
+
H.onSpeechEnd();
|
|
6805
6805
|
} catch (ge) {
|
|
6806
6806
|
console.error("Error in onSpeechEnd callback:", ge);
|
|
6807
6807
|
}
|
|
6808
|
-
},
|
|
6808
|
+
}, 10));
|
|
6809
6809
|
};
|
|
6810
6810
|
setTimeout(() => {
|
|
6811
|
-
$ = setInterval(Ce,
|
|
6812
|
-
},
|
|
6811
|
+
$ = setInterval(Ce, 50);
|
|
6812
|
+
}, 100);
|
|
6813
6813
|
}
|
|
6814
6814
|
p.current.lipsync && Object.keys(p.current.lipsync).length > 0 ? (p.current.setSlowdownRate && p.current.setSlowdownRate(1.05), p.current.speakText(L, U)) : setTimeout(async () => {
|
|
6815
6815
|
await q(), p.current && p.current.lipsync && (p.current.setSlowdownRate && p.current.setSlowdownRate(1.05), p.current.speakText(L, U));
|
|
6816
|
-
},
|
|
6816
|
+
}, 100);
|
|
6817
6817
|
} catch (U) {
|
|
6818
6818
|
console.error("Error speaking text:", U), D(U.message || "Failed to speak text");
|
|
6819
6819
|
}
|
|
@@ -6823,7 +6823,7 @@ const ke = ye(({
|
|
|
6823
6823
|
p.current && p.current.setMood(L);
|
|
6824
6824
|
}, []), b = M((L) => {
|
|
6825
6825
|
p.current && p.current.setSlowdownRate && p.current.setSlowdownRate(L);
|
|
6826
|
-
}, []), R = M((L,
|
|
6826
|
+
}, []), R = M((L, H = !1) => {
|
|
6827
6827
|
if (p.current && p.current.playAnimation) {
|
|
6828
6828
|
if (x && x[L] && (L = x[L]), p.current.setShowFullAvatar)
|
|
6829
6829
|
try {
|
|
@@ -6833,7 +6833,7 @@ const ke = ye(({
|
|
|
6833
6833
|
}
|
|
6834
6834
|
if (L.includes("."))
|
|
6835
6835
|
try {
|
|
6836
|
-
p.current.playAnimation(L, null, 10, 0, 0.01,
|
|
6836
|
+
p.current.playAnimation(L, null, 10, 0, 0.01, H);
|
|
6837
6837
|
} catch (O) {
|
|
6838
6838
|
console.warn(`Failed to play ${L}:`, O);
|
|
6839
6839
|
try {
|
|
@@ -6847,7 +6847,7 @@ const ke = ye(({
|
|
|
6847
6847
|
let ne = !1;
|
|
6848
6848
|
for (const $ of O)
|
|
6849
6849
|
try {
|
|
6850
|
-
p.current.playAnimation(L + $, null, 10, 0, 0.01,
|
|
6850
|
+
p.current.playAnimation(L + $, null, 10, 0, 0.01, H), ne = !0;
|
|
6851
6851
|
break;
|
|
6852
6852
|
} catch {
|
|
6853
6853
|
}
|
|
@@ -6878,8 +6878,8 @@ const ke = ye(({
|
|
|
6878
6878
|
if (p.current && p.current.setShowFullAvatar && p.current.setBodyMovement)
|
|
6879
6879
|
try {
|
|
6880
6880
|
p.current.setShowFullAvatar(!0), p.current.setBodyMovement(L);
|
|
6881
|
-
} catch (
|
|
6882
|
-
console.warn("Error setting body movement:",
|
|
6881
|
+
} catch (H) {
|
|
6882
|
+
console.warn("Error setting body movement:", H);
|
|
6883
6883
|
}
|
|
6884
6884
|
},
|
|
6885
6885
|
setMovementIntensity: (L) => p.current?.setMovementIntensity(L),
|
|
@@ -6895,8 +6895,8 @@ const ke = ye(({
|
|
|
6895
6895
|
if (p.current && p.current.setShowFullAvatar && p.current.playReaction)
|
|
6896
6896
|
try {
|
|
6897
6897
|
p.current.setShowFullAvatar(!0), p.current.playReaction(L);
|
|
6898
|
-
} catch (
|
|
6899
|
-
console.warn("Error playing reaction:",
|
|
6898
|
+
} catch (H) {
|
|
6899
|
+
console.warn("Error playing reaction:", H);
|
|
6900
6900
|
}
|
|
6901
6901
|
},
|
|
6902
6902
|
playCelebration: () => {
|
|
@@ -6911,8 +6911,8 @@ const ke = ye(({
|
|
|
6911
6911
|
if (p.current && p.current.setShowFullAvatar)
|
|
6912
6912
|
try {
|
|
6913
6913
|
p.current.setShowFullAvatar(L);
|
|
6914
|
-
} catch (
|
|
6915
|
-
console.warn("Error setting showFullAvatar:",
|
|
6914
|
+
} catch (H) {
|
|
6915
|
+
console.warn("Error setting showFullAvatar:", H);
|
|
6916
6916
|
}
|
|
6917
6917
|
},
|
|
6918
6918
|
lockAvatarPosition: () => {
|
|
@@ -6945,7 +6945,7 @@ const ke = ye(({
|
|
|
6945
6945
|
/* @__PURE__ */ se(
|
|
6946
6946
|
"div",
|
|
6947
6947
|
{
|
|
6948
|
-
ref:
|
|
6948
|
+
ref: C,
|
|
6949
6949
|
className: "talking-head-viewer",
|
|
6950
6950
|
style: {
|
|
6951
6951
|
width: "100%",
|
|
@@ -6992,7 +6992,7 @@ const $e = ye(({
|
|
|
6992
6992
|
style: s = {},
|
|
6993
6993
|
avatarConfig: o = {}
|
|
6994
6994
|
}, r) => {
|
|
6995
|
-
const h = X(null), a = X(null), [u, l] = re(!0), [c, d] = re(null), [g, y] = re(!1), x = xe(), v = o.ttsService || x.service,
|
|
6995
|
+
const h = X(null), a = X(null), [u, l] = re(!0), [c, d] = re(null), [g, y] = re(!1), x = xe(), v = o.ttsService || x.service, C = v === "browser" ? {
|
|
6996
6996
|
endpoint: "",
|
|
6997
6997
|
apiKey: null,
|
|
6998
6998
|
defaultVoice: "Google US English"
|
|
@@ -7008,7 +7008,7 @@ const $e = ye(({
|
|
|
7008
7008
|
body: "F",
|
|
7009
7009
|
avatarMood: "neutral",
|
|
7010
7010
|
ttsLang: v === "browser" ? "en-US" : "en",
|
|
7011
|
-
ttsVoice: o.ttsVoice ||
|
|
7011
|
+
ttsVoice: o.ttsVoice || C.defaultVoice,
|
|
7012
7012
|
lipsyncLang: "en",
|
|
7013
7013
|
// English lip-sync
|
|
7014
7014
|
showFullAvatar: !0,
|
|
@@ -7017,8 +7017,8 @@ const $e = ye(({
|
|
|
7017
7017
|
movementIntensity: 0.5,
|
|
7018
7018
|
...o
|
|
7019
7019
|
}, E = {
|
|
7020
|
-
ttsEndpoint:
|
|
7021
|
-
ttsApikey:
|
|
7020
|
+
ttsEndpoint: C.endpoint,
|
|
7021
|
+
ttsApikey: C.apiKey,
|
|
7022
7022
|
ttsService: v,
|
|
7023
7023
|
lipsyncModules: ["en"],
|
|
7024
7024
|
cameraView: "upper"
|
|
@@ -7253,7 +7253,7 @@ const et = ye(({
|
|
|
7253
7253
|
onQuestionAnswer: s,
|
|
7254
7254
|
onCurriculumComplete: o,
|
|
7255
7255
|
onCustomAction: r
|
|
7256
|
-
}), d = X(null), g = X(null), y = X(null), x = X(null), v = X(null),
|
|
7256
|
+
}), d = X(null), g = X(null), y = X(null), x = X(null), v = X(null), C = X(null), p = X(null), E = X(B?.curriculum || {
|
|
7257
7257
|
title: "Default Curriculum",
|
|
7258
7258
|
description: "No curriculum data provided",
|
|
7259
7259
|
language: "en",
|
|
@@ -7325,7 +7325,7 @@ const et = ye(({
|
|
|
7325
7325
|
} catch {
|
|
7326
7326
|
u.current.playCelebration();
|
|
7327
7327
|
}
|
|
7328
|
-
const w = E.current || { modules: [] }, L = w.modules[l.current.currentModuleIndex],
|
|
7328
|
+
const w = E.current || { modules: [] }, L = w.modules[l.current.currentModuleIndex], H = l.current.currentLessonIndex < (L?.lessons?.length || 0) - 1, U = l.current.currentModuleIndex < (w.modules?.length || 0) - 1, O = H || U, ne = z.current || { lipsyncLang: "en" };
|
|
7329
7329
|
O ? u.current.speakText(R, {
|
|
7330
7330
|
lipsyncLang: ne.lipsyncLang,
|
|
7331
7331
|
onSpeechEnd: () => {
|
|
@@ -7365,7 +7365,7 @@ const et = ye(({
|
|
|
7365
7365
|
questionIndex: l.current.currentQuestionIndex,
|
|
7366
7366
|
totalQuestions: l.current.totalQuestions,
|
|
7367
7367
|
question: R
|
|
7368
|
-
}), u.current && R) {
|
|
7368
|
+
}), u.current && u.current.isReady && R) {
|
|
7369
7369
|
if (u.current.setMood("curious"), e.questionStart)
|
|
7370
7370
|
try {
|
|
7371
7371
|
u.current.playAnimation(e.questionStart, !0);
|
|
@@ -7374,10 +7374,13 @@ const et = ye(({
|
|
|
7374
7374
|
}
|
|
7375
7375
|
const w = z.current || { lipsyncLang: "en" };
|
|
7376
7376
|
R.type === "code_test" ? u.current.speakText(`Let's test your coding skills! Here's your first challenge: ${R.question}`, { lipsyncLang: w.lipsyncLang }) : R.type === "multiple_choice" ? u.current.speakText(`Now let me ask you some questions. Here's the first one: ${R.question}`, { lipsyncLang: w.lipsyncLang }) : R.type === "true_false" ? u.current.speakText(`Let's start with some true or false questions. First question: ${R.question}`, { lipsyncLang: w.lipsyncLang }) : u.current.speakText(`Now let me ask you some questions. Here's the first one: ${R.question}`, { lipsyncLang: w.lipsyncLang });
|
|
7377
|
-
} else if (u.current) {
|
|
7377
|
+
} else if (u.current && u.current.isReady) {
|
|
7378
7378
|
const w = z.current || { lipsyncLang: "en" };
|
|
7379
7379
|
u.current.speakText("Now let me ask you some questions to test your understanding.", { lipsyncLang: w.lipsyncLang });
|
|
7380
|
-
}
|
|
7380
|
+
} else
|
|
7381
|
+
setTimeout(() => {
|
|
7382
|
+
C.current && C.current();
|
|
7383
|
+
}, 100);
|
|
7381
7384
|
}, [e.questionStart, I, D]), F = M(() => {
|
|
7382
7385
|
const b = I();
|
|
7383
7386
|
if (l.current.currentQuestionIndex < (b?.questions?.length || 0) - 1) {
|
|
@@ -7425,8 +7428,8 @@ const et = ye(({
|
|
|
7425
7428
|
const b = I();
|
|
7426
7429
|
let R = null;
|
|
7427
7430
|
if (b?.avatar_script && b?.body) {
|
|
7428
|
-
const w = b.avatar_script.trim(), L = b.body.trim(),
|
|
7429
|
-
R = `${w}${
|
|
7431
|
+
const w = b.avatar_script.trim(), L = b.body.trim(), H = w.match(/[.!?]$/) ? " " : ". ";
|
|
7432
|
+
R = `${w}${H}${L}`;
|
|
7430
7433
|
} else
|
|
7431
7434
|
R = b?.avatar_script || b?.body || null;
|
|
7432
7435
|
if (u.current && u.current.isReady && R) {
|
|
@@ -7435,8 +7438,8 @@ const et = ye(({
|
|
|
7435
7438
|
if (e.teaching)
|
|
7436
7439
|
try {
|
|
7437
7440
|
u.current.playAnimation(e.teaching, !0), w = !0;
|
|
7438
|
-
} catch (
|
|
7439
|
-
console.warn("Failed to play teaching animation:",
|
|
7441
|
+
} catch (H) {
|
|
7442
|
+
console.warn("Failed to play teaching animation:", H);
|
|
7440
7443
|
}
|
|
7441
7444
|
w || u.current.setBodyMovement("gesturing");
|
|
7442
7445
|
const L = z.current || { lipsyncLang: "en" };
|
|
@@ -7452,7 +7455,7 @@ const et = ye(({
|
|
|
7452
7455
|
}), u.current.speakText(R, {
|
|
7453
7456
|
lipsyncLang: L.lipsyncLang,
|
|
7454
7457
|
onSpeechEnd: () => {
|
|
7455
|
-
l.current.isTeaching = !1, b.questions && b.questions.length > 0 ?
|
|
7458
|
+
l.current.isTeaching = !1, b.questions && b.questions.length > 0 ? C.current && C.current() : y.current && y.current();
|
|
7456
7459
|
}
|
|
7457
7460
|
});
|
|
7458
7461
|
}
|
|
@@ -7474,9 +7477,9 @@ const et = ye(({
|
|
|
7474
7477
|
u.current.setBodyMovement("happy");
|
|
7475
7478
|
}
|
|
7476
7479
|
u.current.setBodyMovement("gesturing");
|
|
7477
|
-
const L = R.type === "code_test" ? `Great job! Your code passed all the tests! ${R.explanation || ""}` : `Excellent! That's correct! ${R.explanation || ""}`,
|
|
7480
|
+
const L = R.type === "code_test" ? `Great job! Your code passed all the tests! ${R.explanation || ""}` : `Excellent! That's correct! ${R.explanation || ""}`, H = z.current || { lipsyncLang: "en" };
|
|
7478
7481
|
u.current.speakText(L, {
|
|
7479
|
-
lipsyncLang:
|
|
7482
|
+
lipsyncLang: H.lipsyncLang,
|
|
7480
7483
|
onSpeechEnd: () => {
|
|
7481
7484
|
x.current && x.current();
|
|
7482
7485
|
}
|
|
@@ -7489,9 +7492,9 @@ const et = ye(({
|
|
|
7489
7492
|
u.current.setBodyMovement("idle");
|
|
7490
7493
|
}
|
|
7491
7494
|
u.current.setBodyMovement("gesturing");
|
|
7492
|
-
const L = R.type === "code_test" ? `Your code didn't pass all the tests. ${R.explanation || "Try again!"}` : `Not quite right, but don't worry! ${R.explanation || ""} Let's move on to the next question.`,
|
|
7495
|
+
const L = R.type === "code_test" ? `Your code didn't pass all the tests. ${R.explanation || "Try again!"}` : `Not quite right, but don't worry! ${R.explanation || ""} Let's move on to the next question.`, H = z.current || { lipsyncLang: "en" };
|
|
7493
7496
|
u.current.speakText(L, {
|
|
7494
|
-
lipsyncLang:
|
|
7497
|
+
lipsyncLang: H.lipsyncLang,
|
|
7495
7498
|
onSpeechEnd: () => {
|
|
7496
7499
|
x.current && x.current();
|
|
7497
7500
|
}
|
|
@@ -7534,10 +7537,10 @@ const et = ye(({
|
|
|
7534
7537
|
const R = I(), w = R?.avatar_script || R?.body;
|
|
7535
7538
|
h && w && setTimeout(() => {
|
|
7536
7539
|
d.current && d.current();
|
|
7537
|
-
},
|
|
7540
|
+
}, 10);
|
|
7538
7541
|
}, [h, I]);
|
|
7539
7542
|
He(() => {
|
|
7540
|
-
d.current = V, g.current = W, y.current = J, x.current = F, v.current = Y,
|
|
7543
|
+
d.current = V, g.current = W, y.current = J, x.current = F, v.current = Y, C.current = S, p.current = Q;
|
|
7541
7544
|
}), fe(a, () => ({
|
|
7542
7545
|
// Curriculum control methods
|
|
7543
7546
|
startTeaching: V,
|
package/package.json
CHANGED
|
@@ -279,7 +279,8 @@ const CurriculumLearning = forwardRef(({
|
|
|
279
279
|
});
|
|
280
280
|
}
|
|
281
281
|
|
|
282
|
-
|
|
282
|
+
// Ensure avatar is ready before speaking
|
|
283
|
+
if (avatarRef.current && avatarRef.current.isReady && firstQuestion) {
|
|
283
284
|
avatarRef.current.setMood("curious");
|
|
284
285
|
|
|
285
286
|
// Play custom animation if available
|
|
@@ -303,9 +304,16 @@ const CurriculumLearning = forwardRef(({
|
|
|
303
304
|
} else {
|
|
304
305
|
avatarRef.current.speakText(`Now let me ask you some questions. Here's the first one: ${firstQuestion.question}`, { lipsyncLang: config.lipsyncLang });
|
|
305
306
|
}
|
|
306
|
-
} else if (avatarRef.current) {
|
|
307
|
+
} else if (avatarRef.current && avatarRef.current.isReady) {
|
|
307
308
|
const config = defaultAvatarConfigRef.current || { lipsyncLang: 'en' };
|
|
308
309
|
avatarRef.current.speakText("Now let me ask you some questions to test your understanding.", { lipsyncLang: config.lipsyncLang });
|
|
310
|
+
} else {
|
|
311
|
+
// Avatar not ready yet, retry after a short delay
|
|
312
|
+
setTimeout(() => {
|
|
313
|
+
if (startQuestionsRef.current) {
|
|
314
|
+
startQuestionsRef.current();
|
|
315
|
+
}
|
|
316
|
+
}, 100);
|
|
309
317
|
}
|
|
310
318
|
}, [animations.questionStart, getCurrentLesson, getCurrentQuestion]);
|
|
311
319
|
|
|
@@ -671,7 +679,7 @@ const CurriculumLearning = forwardRef(({
|
|
|
671
679
|
if (startTeachingRef.current) {
|
|
672
680
|
startTeachingRef.current();
|
|
673
681
|
}
|
|
674
|
-
},
|
|
682
|
+
}, 10);
|
|
675
683
|
}
|
|
676
684
|
}, [autoStart, getCurrentLesson]);
|
|
677
685
|
|
|
@@ -289,7 +289,7 @@ const TalkingHeadAvatar = forwardRef(({
|
|
|
289
289
|
// This is because onAudioEnd is only for streaming mode
|
|
290
290
|
let checkInterval = null;
|
|
291
291
|
let checkCount = 0;
|
|
292
|
-
const maxChecks = 600; // 60 seconds max (
|
|
292
|
+
const maxChecks = 600; // 60 seconds max (50ms intervals for faster detection)
|
|
293
293
|
|
|
294
294
|
const checkSpeechFinished = () => {
|
|
295
295
|
checkCount++;
|
|
@@ -317,21 +317,21 @@ const TalkingHeadAvatar = forwardRef(({
|
|
|
317
317
|
checkInterval = null;
|
|
318
318
|
}
|
|
319
319
|
|
|
320
|
-
// Small delay to ensure everything is settled
|
|
320
|
+
// Small delay to ensure everything is settled - reduced for faster transitions
|
|
321
321
|
setTimeout(() => {
|
|
322
322
|
try {
|
|
323
323
|
options.onSpeechEnd();
|
|
324
324
|
} catch (e) {
|
|
325
325
|
console.error('Error in onSpeechEnd callback:', e);
|
|
326
326
|
}
|
|
327
|
-
},
|
|
327
|
+
}, 10);
|
|
328
328
|
}
|
|
329
329
|
};
|
|
330
330
|
|
|
331
|
-
// Start checking after a
|
|
331
|
+
// Start checking after a minimal delay (to allow speech to start)
|
|
332
332
|
setTimeout(() => {
|
|
333
|
-
checkInterval = setInterval(checkSpeechFinished,
|
|
334
|
-
},
|
|
333
|
+
checkInterval = setInterval(checkSpeechFinished, 50);
|
|
334
|
+
}, 100);
|
|
335
335
|
}
|
|
336
336
|
|
|
337
337
|
if (talkingHeadRef.current.lipsync && Object.keys(talkingHeadRef.current.lipsync).length > 0) {
|
|
@@ -348,7 +348,7 @@ const TalkingHeadAvatar = forwardRef(({
|
|
|
348
348
|
}
|
|
349
349
|
talkingHeadRef.current.speakText(textToSpeak, speakOptions);
|
|
350
350
|
}
|
|
351
|
-
},
|
|
351
|
+
}, 100);
|
|
352
352
|
}
|
|
353
353
|
} catch (err) {
|
|
354
354
|
console.error('Error speaking text:', err);
|