virtual-human-cf 1.0.5 → 1.0.7
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/README.md +40 -22
- package/dist/components/VirtualHumanEventAdapter.vue.d.ts +4 -6
- package/dist/style.css +1 -1
- package/dist/virtual-human-cf.es.js +130 -135
- package/dist/virtual-human-cf.umd.js +1 -1
- package/package.json +1 -1
- package/src/components/VirtualHumanEventAdapter.vue +14 -15
- package/src/components/VirtualHumanPersona.vue +2 -0
package/README.md
CHANGED
|
@@ -113,12 +113,24 @@ const onEnded = () => {
|
|
|
113
113
|
| 事件名 | 说明 | 回调参数 |
|
|
114
114
|
|--------|------|----------|
|
|
115
115
|
| connected | WebSocket 连接成功 | - |
|
|
116
|
-
|
|
|
117
|
-
| showDialog | 显示弹窗 | 载荷数据 |
|
|
116
|
+
| eventNotifaction | 自定义事件接收器 | 载荷数据 |
|
|
118
117
|
| end | 数字人对话结束 | 载荷数据 |
|
|
119
118
|
| pause | 暂停播放 | 载荷数据 |
|
|
120
119
|
| error | 错误事件 | 错误信息 |
|
|
121
|
-
|
|
|
120
|
+
| playComplete | 播放完成,数字人对话结束,关闭数字人 | - |
|
|
121
|
+
|
|
122
|
+
```json
|
|
123
|
+
eventNotifaction => 载荷数据 :{
|
|
124
|
+
|
|
125
|
+
"type": "send_event",
|
|
126
|
+
// 自定义事件名称
|
|
127
|
+
"event": "heightlight",
|
|
128
|
+
// 自定义事件参数
|
|
129
|
+
"params": {
|
|
130
|
+
"domid": "wrap-1"
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
```
|
|
122
134
|
|
|
123
135
|
#### 示例
|
|
124
136
|
|
|
@@ -128,8 +140,8 @@ const onEnded = () => {
|
|
|
128
140
|
:screen-client-id="clientId"
|
|
129
141
|
:ws-url="websocketUrl"
|
|
130
142
|
@connected="onConnected"
|
|
131
|
-
@
|
|
132
|
-
@
|
|
143
|
+
@eventNotifaction="onEventNotifaction"
|
|
144
|
+
@playComplete="onPlayComplete"
|
|
133
145
|
@end="onEnd"
|
|
134
146
|
@error="onError"
|
|
135
147
|
>
|
|
@@ -147,12 +159,12 @@ const onConnected = () => {
|
|
|
147
159
|
console.log('WebSocket 连接成功');
|
|
148
160
|
};
|
|
149
161
|
|
|
150
|
-
const
|
|
151
|
-
console.log('
|
|
162
|
+
const onEventNotifaction = (payload) => {
|
|
163
|
+
console.log('自定义事件接收:', payload);
|
|
152
164
|
};
|
|
153
165
|
|
|
154
|
-
const
|
|
155
|
-
console.log('
|
|
166
|
+
const onPlayComplete = () => {
|
|
167
|
+
console.log('播放完成');
|
|
156
168
|
};
|
|
157
169
|
|
|
158
170
|
const onEnd = (payload) => {
|
|
@@ -174,23 +186,25 @@ const onError = (error) => {
|
|
|
174
186
|
<div class="container">
|
|
175
187
|
<VirtualHumanPersona
|
|
176
188
|
:video-src="videoUrl"
|
|
189
|
+
:visible="personaVisible"
|
|
177
190
|
:is-playing="isPlaying"
|
|
178
191
|
:muted="true"
|
|
179
192
|
:is-dark="isDarkMode"
|
|
180
|
-
:screen-client-id="
|
|
193
|
+
:screen-client-id="activeScreenClientId"
|
|
181
194
|
:ws-url="websocketUrl"
|
|
182
|
-
@update:isPlaying="
|
|
195
|
+
@update:isPlaying="onPersonaPlayingUpdate"
|
|
196
|
+
@update:visible="onPersonaVisibleUpdate"
|
|
183
197
|
@ended="onVideoEnded"
|
|
184
198
|
/>
|
|
185
199
|
|
|
186
200
|
<VirtualHumanEventAdapter
|
|
187
|
-
:screen-client-id="
|
|
201
|
+
:screen-client-id="activeScreenClientId"
|
|
188
202
|
:ws-url="websocketUrl"
|
|
189
203
|
@connected="onConnected"
|
|
190
|
-
@
|
|
191
|
-
@showDialog="onShowDialog"
|
|
204
|
+
@eventNotifaction="onEventNotifaction"
|
|
192
205
|
@end="onEnd"
|
|
193
206
|
@error="onError"
|
|
207
|
+
@playComplete="onPlayComplete"
|
|
194
208
|
/>
|
|
195
209
|
</div>
|
|
196
210
|
</template>
|
|
@@ -202,7 +216,8 @@ import { VirtualHumanPersona, VirtualHumanEventAdapter } from 'virtual-human-cf'
|
|
|
202
216
|
const videoUrl = ref('/path/to/digital-human-video.mp4');
|
|
203
217
|
const isPlaying = ref(false);
|
|
204
218
|
const isDarkMode = ref(false);
|
|
205
|
-
const
|
|
219
|
+
const personaVisible = ref(true);
|
|
220
|
+
const activeScreenClientId = ref('screen-123');
|
|
206
221
|
const websocketUrl = ref('ws://localhost:8080/ws');
|
|
207
222
|
|
|
208
223
|
const onConnected = () => {
|
|
@@ -213,19 +228,22 @@ const onVideoEnded = () => {
|
|
|
213
228
|
console.log('视频播放结束');
|
|
214
229
|
};
|
|
215
230
|
|
|
216
|
-
const onHighlight = (payload) => {
|
|
217
|
-
console.log('收到高亮指令:', payload);
|
|
218
|
-
};
|
|
219
|
-
|
|
220
|
-
const onShowDialog = (payload) => {
|
|
221
|
-
console.log('显示对话框:', payload);
|
|
222
|
-
};
|
|
223
231
|
|
|
224
232
|
const onEnd = (payload) => {
|
|
225
233
|
console.log('数字人交互结束:', payload);
|
|
226
234
|
isPlaying.value = false;
|
|
227
235
|
};
|
|
228
236
|
|
|
237
|
+
const onEventNotifaction = (payload) => {
|
|
238
|
+
console.log('自定义事件接收:', payload);
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
const onPlayComplete = () => {
|
|
242
|
+
console.log('播放完成');
|
|
243
|
+
// 关闭数字人
|
|
244
|
+
personaVisible.value = false;
|
|
245
|
+
}
|
|
246
|
+
|
|
229
247
|
const onError = (error) => {
|
|
230
248
|
console.error('发生错误:', error);
|
|
231
249
|
};
|
|
@@ -13,11 +13,10 @@ declare const __VLS_component: import('vue').DefineComponent<import('vue').Extra
|
|
|
13
13
|
}>, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
|
|
14
14
|
error: (...args: any[]) => void;
|
|
15
15
|
pause: (...args: any[]) => void;
|
|
16
|
-
|
|
17
|
-
showDialog: (...args: any[]) => void;
|
|
16
|
+
eventNotifaction: (...args: any[]) => void;
|
|
18
17
|
end: (...args: any[]) => void;
|
|
19
18
|
connected: (...args: any[]) => void;
|
|
20
|
-
|
|
19
|
+
playComplete: (...args: any[]) => void;
|
|
21
20
|
}, string, import('vue').PublicProps, Readonly<import('vue').ExtractPropTypes<{
|
|
22
21
|
screenClientId: {
|
|
23
22
|
type: StringConstructor;
|
|
@@ -30,11 +29,10 @@ declare const __VLS_component: import('vue').DefineComponent<import('vue').Extra
|
|
|
30
29
|
}>> & Readonly<{
|
|
31
30
|
onError?: ((...args: any[]) => any) | undefined;
|
|
32
31
|
onPause?: ((...args: any[]) => any) | undefined;
|
|
33
|
-
|
|
34
|
-
onShowDialog?: ((...args: any[]) => any) | undefined;
|
|
32
|
+
onEventNotifaction?: ((...args: any[]) => any) | undefined;
|
|
35
33
|
onEnd?: ((...args: any[]) => any) | undefined;
|
|
36
34
|
onConnected?: ((...args: any[]) => any) | undefined;
|
|
37
|
-
|
|
35
|
+
onPlayComplete?: ((...args: any[]) => any) | undefined;
|
|
38
36
|
}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>;
|
|
39
37
|
declare const _default: __VLS_WithTemplateSlots<typeof __VLS_component, ReturnType<typeof __VLS_template>>;
|
|
40
38
|
export default _default;
|
package/dist/style.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
.fade-enter-active[data-v-
|
|
1
|
+
.fade-enter-active[data-v-6c9e435e],.fade-leave-active[data-v-6c9e435e]{transition:opacity .5s ease,transform .5s ease}.fade-enter-from[data-v-6c9e435e],.fade-leave-to[data-v-6c9e435e]{opacity:0;transform:translateY(10px)}.virtual-human-container[data-v-6c9e435e]{position:fixed;z-index:2147483647;overflow:visible}.video-wrapper[data-v-6c9e435e]{position:relative;width:100%;height:100%;border-radius:1rem;overflow:hidden;box-shadow:0 10px 25px #0000001a;background:#fff;border:2px solid transparent;transition:background-color .3s ease,box-shadow .3s ease,border-color .3s ease}.video-wrapper[data-v-6c9e435e]:hover{border-color:#409eff}.virtual-human-container.is-dark .video-wrapper[data-v-6c9e435e]{background:#1f2937;box-shadow:0 10px 25px #00000080}.persona-video[data-v-6c9e435e]{width:100%;height:100%;object-fit:cover;transform-origin:center;transition:transform .1s ease-out}.resize-handle[data-v-6c9e435e]{position:absolute;width:20px;height:20px;background:#00000080;border:2px solid rgba(255,255,255,.8);border-radius:4px;cursor:pointer;z-index:20;opacity:0;pointer-events:none;transition:opacity .3s ease,background .2s,border-color .2s}.video-wrapper:hover .resize-handle[data-v-6c9e435e]{opacity:1;pointer-events:auto}.resize-handle[data-v-6c9e435e]:hover{background:#000000b3;border-color:#fff}.resize-handle.top-left[data-v-6c9e435e]{top:10px;left:10px;cursor:nwse-resize}.resize-handle.top-right[data-v-6c9e435e]{top:10px;right:10px;cursor:nesw-resize}.resize-handle.bottom-left[data-v-6c9e435e]{bottom:10px;left:10px;cursor:nesw-resize}.resize-handle.bottom-right[data-v-6c9e435e]{bottom:10px;right:10px;cursor:nwse-resize}.overlay[data-v-6c9e435e]{position:absolute;top:1rem;right:1rem;z-index:10}.status-badge[data-v-6c9e435e]{display:flex;align-items:center;gap:.5rem;padding:.25rem .75rem;border-radius:9999px;font-size:.75rem;font-weight:500;color:#fff;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}.status-badge.paused[data-v-6c9e435e]{background:#ef4444cc}.status-badge.playing[data-v-6c9e435e]{background:#22c55ecc}.dot[data-v-6c9e435e]{width:6px;height:6px;border-radius:50%;background-color:#fff}@keyframes pulse-6c9e435e{0%,to{opacity:1}50%{opacity:.5}}.animate-pulse[data-v-6c9e435e]{animation:pulse-6c9e435e 2s cubic-bezier(.4,0,.6,1) infinite}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defineComponent as j, ref as
|
|
1
|
+
import { defineComponent as j, ref as v, watch as X, onMounted as G, onUnmounted as K, openBlock as S, createBlock as Q, Transition as Z, withCtx as _, createElementBlock as E, normalizeStyle as ee, normalizeClass as te, createElementVNode as R, createCommentVNode as T, createTextVNode as J, renderSlot as ne } from "vue";
|
|
2
2
|
const ae = ["src", "muted"], se = { class: "overlay" }, le = {
|
|
3
3
|
key: 0,
|
|
4
4
|
class: "status-badge paused"
|
|
@@ -46,72 +46,72 @@ const ae = ["src", "muted"], se = { class: "overlay" }, le = {
|
|
|
46
46
|
}
|
|
47
47
|
},
|
|
48
48
|
emits: ["update:isPlaying", "ended", "update:visible"],
|
|
49
|
-
setup(c, { emit:
|
|
50
|
-
const t = c,
|
|
49
|
+
setup(c, { emit: W }) {
|
|
50
|
+
const t = c, i = W, r = v(null), Y = v(null), n = v(null), p = v(!1), y = v(400), g = v(500), w = v(16), z = v(16), I = v(!1), h = v(null), M = v(0), A = v(0), k = v(0), s = v(0), l = v(0), u = v(0), b = () => {
|
|
51
51
|
if (n.value && n.value.close(), !(!t.wsUrl || !t.screenClientId))
|
|
52
52
|
try {
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
const o = new URL(t.wsUrl);
|
|
54
|
+
o.searchParams.append("sessionId", t.screenClientId + "-persona"), n.value = new WebSocket(o.toString()), n.value.onopen = () => {
|
|
55
|
+
p.value = !0, console.log(`[VirtualHumanPersona] Connected to ${t.wsUrl} for session ${t.screenClientId}-persona`);
|
|
56
56
|
}, n.value.onmessage = (e) => {
|
|
57
57
|
try {
|
|
58
58
|
const a = JSON.parse(e.data);
|
|
59
|
-
|
|
59
|
+
C(a);
|
|
60
60
|
} catch (a) {
|
|
61
61
|
console.error("[VirtualHumanPersona] Failed to parse message:", e.data, a);
|
|
62
62
|
}
|
|
63
63
|
}, n.value.onerror = (e) => {
|
|
64
64
|
console.error("[VirtualHumanPersona] WebSocket error:", e);
|
|
65
65
|
}, n.value.onclose = () => {
|
|
66
|
-
|
|
66
|
+
p.value = !1, console.log("[VirtualHumanPersona] WebSocket disconnected");
|
|
67
67
|
};
|
|
68
|
-
} catch (
|
|
69
|
-
console.error("[VirtualHumanPersona] Failed to initialize WebSocket:",
|
|
68
|
+
} catch (o) {
|
|
69
|
+
console.error("[VirtualHumanPersona] Failed to initialize WebSocket:", o);
|
|
70
70
|
}
|
|
71
|
-
},
|
|
72
|
-
const { type: e, action: a } =
|
|
73
|
-
e === "control" && (a === "play" || a === "resume" ? (
|
|
71
|
+
}, C = (o) => {
|
|
72
|
+
const { type: e, action: a } = o;
|
|
73
|
+
e === "control" && (a === "play" || a === "resume" ? (i("update:isPlaying", !0), i("update:visible", !0)) : a === "pause" ? i("update:isPlaying", !1) : a === "stop" && (i("update:isPlaying", !1), i("update:visible", !1), r.value && (r.value.currentTime = 0)));
|
|
74
74
|
};
|
|
75
75
|
X(() => t.screenClientId, () => {
|
|
76
|
-
t.screenClientId && t.wsUrl &&
|
|
76
|
+
t.screenClientId && t.wsUrl && b();
|
|
77
77
|
}), X(() => t.wsUrl, () => {
|
|
78
|
-
t.screenClientId && t.wsUrl &&
|
|
79
|
-
}), X(() => t.isPlaying, (
|
|
80
|
-
|
|
78
|
+
t.screenClientId && t.wsUrl && b();
|
|
79
|
+
}), X(() => t.isPlaying, (o) => {
|
|
80
|
+
r.value && (o ? r.value.play().catch((e) => console.error("Video play failed:", e)) : r.value.pause());
|
|
81
81
|
});
|
|
82
|
-
const
|
|
83
|
-
t.isPlaying ||
|
|
82
|
+
const B = () => {
|
|
83
|
+
t.isPlaying || i("update:isPlaying", !0);
|
|
84
|
+
}, L = () => {
|
|
85
|
+
t.isPlaying && i("update:isPlaying", !1);
|
|
84
86
|
}, U = () => {
|
|
85
|
-
|
|
86
|
-
},
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
}, $ = () => {
|
|
99
|
-
z.value = !1, b.value = null, document.removeEventListener("mousemove", M), document.removeEventListener("mouseup", $), document.removeEventListener("touchmove", M), document.removeEventListener("touchend", $);
|
|
87
|
+
i("update:isPlaying", !1), i("ended");
|
|
88
|
+
}, d = (o, e) => {
|
|
89
|
+
e.preventDefault(), I.value = !0, h.value = o;
|
|
90
|
+
const a = "clientX" in e ? e.clientX : e.touches[0].clientX, P = "clientY" in e ? e.clientY : e.touches[0].clientY;
|
|
91
|
+
M.value = a, A.value = P, k.value = y.value, s.value = g.value, l.value = w.value, u.value = z.value, document.addEventListener("mousemove", $), document.addEventListener("mouseup", N), document.addEventListener("touchmove", $, { passive: !1 }), document.addEventListener("touchend", N);
|
|
92
|
+
}, $ = (o) => {
|
|
93
|
+
if (!I.value) return;
|
|
94
|
+
o.preventDefault();
|
|
95
|
+
const e = "clientX" in o ? o.clientX : o.touches[0].clientX, a = "clientY" in o ? o.clientY : o.touches[0].clientY, P = e - M.value, x = a - A.value, D = 200, F = 250, q = 800, O = 1e3;
|
|
96
|
+
let f = k.value, m = s.value, H = l.value, V = u.value;
|
|
97
|
+
h.value === "bottom-right" ? (f = k.value + P, V = u.value - x, m = s.value + x) : h.value === "bottom-left" ? (H = l.value + P, f = k.value - P, V = u.value - x, m = s.value + x) : h.value === "top-right" ? (f = k.value + P, m = s.value - x) : h.value === "top-left" && (H = l.value + P, f = k.value - P, m = s.value - x), f < D && (H !== l.value && (H -= D - f), f = D), m < F && (V !== u.value && (V -= F - m), m = F), f > q && (H !== l.value && (H += f - q), f = q), m > O && (V !== u.value && (V += m - O), m = O), y.value = f, g.value = m, w.value = H, z.value = V;
|
|
98
|
+
}, N = () => {
|
|
99
|
+
I.value = !1, h.value = null, document.removeEventListener("mousemove", $), document.removeEventListener("mouseup", N), document.removeEventListener("touchmove", $), document.removeEventListener("touchend", N);
|
|
100
100
|
};
|
|
101
101
|
return G(() => {
|
|
102
|
-
t.isPlaying &&
|
|
102
|
+
t.isPlaying && r.value && r.value.play().catch((o) => console.error("Video play failed:", o)), t.screenClientId && t.wsUrl && b();
|
|
103
103
|
}), K(() => {
|
|
104
104
|
n.value && n.value.close();
|
|
105
|
-
}), (
|
|
105
|
+
}), (o, e) => (S(), Q(Z, { name: "fade" }, {
|
|
106
106
|
default: _(() => [
|
|
107
|
-
c.visible ? (
|
|
107
|
+
c.visible ? (S(), E("div", {
|
|
108
108
|
key: 0,
|
|
109
109
|
class: te(["virtual-human-container", { "is-dark": c.isDark }]),
|
|
110
110
|
style: ee({
|
|
111
|
-
width:
|
|
112
|
-
height:
|
|
113
|
-
left:
|
|
114
|
-
bottom:
|
|
111
|
+
width: y.value + "px",
|
|
112
|
+
height: g.value + "px",
|
|
113
|
+
left: w.value + "px",
|
|
114
|
+
bottom: z.value + "px"
|
|
115
115
|
})
|
|
116
116
|
}, [
|
|
117
117
|
R("div", {
|
|
@@ -121,45 +121,47 @@ const ae = ["src", "muted"], se = { class: "overlay" }, le = {
|
|
|
121
121
|
}, [
|
|
122
122
|
R("video", {
|
|
123
123
|
ref_key: "videoRef",
|
|
124
|
-
ref:
|
|
124
|
+
ref: r,
|
|
125
125
|
src: c.videoSrc,
|
|
126
126
|
class: "persona-video",
|
|
127
127
|
muted: c.muted,
|
|
128
128
|
playsinline: "",
|
|
129
129
|
loop: "",
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
130
|
+
autoPlay: "",
|
|
131
|
+
disablePictureInPicture: "false",
|
|
132
|
+
onPlay: B,
|
|
133
|
+
onPause: L,
|
|
134
|
+
onEnded: U
|
|
133
135
|
}, null, 40, ae),
|
|
134
|
-
c.visible ? (
|
|
136
|
+
c.visible ? (S(), E("div", {
|
|
135
137
|
key: 0,
|
|
136
138
|
class: "resize-handle top-left",
|
|
137
|
-
onMousedown: e[0] || (e[0] = (a) =>
|
|
138
|
-
onTouchstart: e[1] || (e[1] = (a) =>
|
|
139
|
+
onMousedown: e[0] || (e[0] = (a) => d("top-left", a)),
|
|
140
|
+
onTouchstart: e[1] || (e[1] = (a) => d("top-left", a))
|
|
139
141
|
}, null, 32)) : T("", !0),
|
|
140
|
-
c.visible ? (
|
|
142
|
+
c.visible ? (S(), E("div", {
|
|
141
143
|
key: 1,
|
|
142
144
|
class: "resize-handle top-right",
|
|
143
|
-
onMousedown: e[2] || (e[2] = (a) =>
|
|
144
|
-
onTouchstart: e[3] || (e[3] = (a) =>
|
|
145
|
+
onMousedown: e[2] || (e[2] = (a) => d("top-right", a)),
|
|
146
|
+
onTouchstart: e[3] || (e[3] = (a) => d("top-right", a))
|
|
145
147
|
}, null, 32)) : T("", !0),
|
|
146
|
-
c.visible ? (
|
|
148
|
+
c.visible ? (S(), E("div", {
|
|
147
149
|
key: 2,
|
|
148
150
|
class: "resize-handle bottom-left",
|
|
149
|
-
onMousedown: e[4] || (e[4] = (a) =>
|
|
150
|
-
onTouchstart: e[5] || (e[5] = (a) =>
|
|
151
|
+
onMousedown: e[4] || (e[4] = (a) => d("bottom-left", a)),
|
|
152
|
+
onTouchstart: e[5] || (e[5] = (a) => d("bottom-left", a))
|
|
151
153
|
}, null, 32)) : T("", !0),
|
|
152
|
-
c.visible ? (
|
|
154
|
+
c.visible ? (S(), E("div", {
|
|
153
155
|
key: 3,
|
|
154
156
|
class: "resize-handle bottom-right",
|
|
155
|
-
onMousedown: e[6] || (e[6] = (a) =>
|
|
156
|
-
onTouchstart: e[7] || (e[7] = (a) =>
|
|
157
|
+
onMousedown: e[6] || (e[6] = (a) => d("bottom-right", a)),
|
|
158
|
+
onTouchstart: e[7] || (e[7] = (a) => d("bottom-right", a))
|
|
157
159
|
}, null, 32)) : T("", !0),
|
|
158
160
|
R("div", se, [
|
|
159
|
-
c.isPlaying ? (
|
|
161
|
+
c.isPlaying ? (S(), E("div", oe, [...e[9] || (e[9] = [
|
|
160
162
|
R("span", { class: "dot animate-pulse" }, null, -1),
|
|
161
163
|
J(" 播放中 ", -1)
|
|
162
|
-
])])) : (
|
|
164
|
+
])])) : (S(), E("div", le, [...e[8] || (e[8] = [
|
|
163
165
|
R("span", { class: "dot" }, null, -1),
|
|
164
166
|
J(" 暂停中 ", -1)
|
|
165
167
|
])]))
|
|
@@ -170,12 +172,12 @@ const ae = ["src", "muted"], se = { class: "overlay" }, le = {
|
|
|
170
172
|
_: 1
|
|
171
173
|
}));
|
|
172
174
|
}
|
|
173
|
-
}), ie = (c,
|
|
175
|
+
}), ie = (c, W) => {
|
|
174
176
|
const t = c.__vccOpts || c;
|
|
175
|
-
for (const [
|
|
176
|
-
t[
|
|
177
|
+
for (const [i, r] of W)
|
|
178
|
+
t[i] = r;
|
|
177
179
|
return t;
|
|
178
|
-
}, ue = /* @__PURE__ */ ie(re, [["__scopeId", "data-v-
|
|
180
|
+
}, ue = /* @__PURE__ */ ie(re, [["__scopeId", "data-v-6c9e435e"]]), ce = /* @__PURE__ */ j({
|
|
179
181
|
__name: "VirtualHumanEventAdapter",
|
|
180
182
|
props: {
|
|
181
183
|
// 屏幕客户端ID
|
|
@@ -189,103 +191,96 @@ const ae = ["src", "muted"], se = { class: "overlay" }, le = {
|
|
|
189
191
|
required: !0
|
|
190
192
|
}
|
|
191
193
|
},
|
|
192
|
-
emits: ["
|
|
193
|
-
setup(c, { emit:
|
|
194
|
-
const t = c,
|
|
195
|
-
let n = null,
|
|
196
|
-
const
|
|
194
|
+
emits: ["eventNotifaction", "end", "pause", "connected", "error", "playComplete"],
|
|
195
|
+
setup(c, { emit: W }) {
|
|
196
|
+
const t = c, i = W, r = v(null), Y = v(!1);
|
|
197
|
+
let n = null, p = 0, y = !1, g = 0, w = !1;
|
|
198
|
+
const z = () => {
|
|
197
199
|
n || (n = new (window.AudioContext || window.webkitAudioContext)({
|
|
198
200
|
sampleRate: 24e3
|
|
199
|
-
})), n.state === "suspended" && n.resume();
|
|
200
|
-
},
|
|
201
|
-
|
|
202
|
-
},
|
|
203
|
-
if (
|
|
201
|
+
})), n.state === "suspended" && !w && n.resume();
|
|
202
|
+
}, I = () => {
|
|
203
|
+
y && g === 0 && (i("playComplete", t.screenClientId), y = !1);
|
|
204
|
+
}, h = (s) => {
|
|
205
|
+
if (z(), !!n)
|
|
204
206
|
try {
|
|
205
|
-
const
|
|
206
|
-
for (let
|
|
207
|
-
|
|
208
|
-
const
|
|
209
|
-
for (let
|
|
210
|
-
B[
|
|
207
|
+
const l = window.atob(s), u = l.length, b = new Uint8Array(u);
|
|
208
|
+
for (let d = 0; d < u; d++)
|
|
209
|
+
b[d] = l.charCodeAt(d);
|
|
210
|
+
const C = new Int16Array(b.buffer), B = new Float32Array(C.length);
|
|
211
|
+
for (let d = 0; d < C.length; d++)
|
|
212
|
+
B[d] = C[d] / 32768;
|
|
211
213
|
const L = n.createBuffer(1, B.length, 24e3);
|
|
212
214
|
L.getChannelData(0).set(B);
|
|
213
215
|
const U = n.createBufferSource();
|
|
214
|
-
U.buffer = L, U.connect(n.destination),
|
|
215
|
-
|
|
216
|
+
U.buffer = L, U.connect(n.destination), p < n.currentTime && (p = n.currentTime), U.start(p), p += L.duration, g++, U.onended = () => {
|
|
217
|
+
g--, I();
|
|
216
218
|
};
|
|
217
|
-
} catch (
|
|
218
|
-
console.error("[VirtualHumanEventAdapter] Failed to decode and play audio:",
|
|
219
|
-
}
|
|
220
|
-
}, b = (s) => {
|
|
221
|
-
if (!(!n && s !== "stop"))
|
|
222
|
-
switch (s) {
|
|
223
|
-
case "play":
|
|
224
|
-
h = !1, w = 0, y = 0, n && n.state === "suspended" && n.resume();
|
|
225
|
-
break;
|
|
226
|
-
case "resume":
|
|
227
|
-
n && n.state === "suspended" && n.resume();
|
|
228
|
-
break;
|
|
229
|
-
case "pause":
|
|
230
|
-
n && n.state === "running" && n.suspend();
|
|
231
|
-
break;
|
|
232
|
-
case "stop":
|
|
233
|
-
n && (n.close(), n = null), y = 0, h = !1, w = 0;
|
|
234
|
-
break;
|
|
235
|
-
case "tts_complete":
|
|
236
|
-
h = !0, E();
|
|
237
|
-
break;
|
|
238
|
-
default:
|
|
239
|
-
console.warn(`[VirtualHumanEventAdapter] Unknown control action: ${s}`);
|
|
219
|
+
} catch (l) {
|
|
220
|
+
console.error("[VirtualHumanEventAdapter] Failed to decode and play audio:", l);
|
|
240
221
|
}
|
|
222
|
+
}, M = (s) => {
|
|
223
|
+
switch (s) {
|
|
224
|
+
case "play":
|
|
225
|
+
y = !1, g = 0, p = 0, w = !1, n && n.state === "suspended" && n.resume();
|
|
226
|
+
break;
|
|
227
|
+
case "resume":
|
|
228
|
+
w = !1, n && n.state === "suspended" && n.resume();
|
|
229
|
+
break;
|
|
230
|
+
case "pause":
|
|
231
|
+
w = !0, n && n.state === "running" && n.suspend();
|
|
232
|
+
break;
|
|
233
|
+
case "stop":
|
|
234
|
+
w = !1, n && (n.close(), n = null), p = 0, y = !1, g = 0;
|
|
235
|
+
break;
|
|
236
|
+
case "tts_complete":
|
|
237
|
+
y = !0, I();
|
|
238
|
+
break;
|
|
239
|
+
default:
|
|
240
|
+
console.warn(`[VirtualHumanEventAdapter] Unknown control action: ${s}`);
|
|
241
|
+
}
|
|
241
242
|
}, A = () => {
|
|
242
|
-
|
|
243
|
+
r.value && r.value.close();
|
|
243
244
|
try {
|
|
244
245
|
const s = new URL(t.wsUrl);
|
|
245
|
-
s.searchParams.append("sessionId", t.screenClientId + "-event"),
|
|
246
|
-
Y.value = !0,
|
|
247
|
-
},
|
|
246
|
+
s.searchParams.append("sessionId", t.screenClientId + "-event"), r.value = new WebSocket(s.toString()), r.value.onopen = () => {
|
|
247
|
+
Y.value = !0, i("connected"), console.log(`[VirtualHumanEventAdapter] Connected to ${t.wsUrl} for session ${t.screenClientId}-event`);
|
|
248
|
+
}, r.value.onmessage = (l) => {
|
|
248
249
|
try {
|
|
249
|
-
const
|
|
250
|
-
|
|
251
|
-
} catch (
|
|
252
|
-
console.error("[VirtualHumanEventAdapter] Failed to parse message:",
|
|
250
|
+
const u = JSON.parse(l.data);
|
|
251
|
+
k(u);
|
|
252
|
+
} catch (u) {
|
|
253
|
+
console.error("[VirtualHumanEventAdapter] Failed to parse message:", l.data, u);
|
|
253
254
|
}
|
|
254
|
-
},
|
|
255
|
-
console.error("[VirtualHumanEventAdapter] WebSocket error:",
|
|
256
|
-
},
|
|
255
|
+
}, r.value.onerror = (l) => {
|
|
256
|
+
console.error("[VirtualHumanEventAdapter] WebSocket error:", l), i("error", l);
|
|
257
|
+
}, r.value.onclose = () => {
|
|
257
258
|
Y.value = !1, console.log("[VirtualHumanEventAdapter] WebSocket disconnected");
|
|
258
259
|
};
|
|
259
260
|
} catch (s) {
|
|
260
|
-
console.error("[VirtualHumanEventAdapter] Failed to initialize WebSocket:", s),
|
|
261
|
+
console.error("[VirtualHumanEventAdapter] Failed to initialize WebSocket:", s), i("error", s);
|
|
261
262
|
}
|
|
262
|
-
},
|
|
263
|
-
const { type:
|
|
264
|
-
switch (console.log("msgmsg", s),
|
|
263
|
+
}, k = (s) => {
|
|
264
|
+
const { type: l, payload: u, action: b } = s;
|
|
265
|
+
switch (console.log("msgmsg-002", s), l) {
|
|
265
266
|
case "audio":
|
|
266
|
-
const
|
|
267
|
-
|
|
267
|
+
const C = (u == null ? void 0 : u.data) || s.data;
|
|
268
|
+
C && h(C);
|
|
268
269
|
break;
|
|
269
|
-
case "
|
|
270
|
-
s.event &&
|
|
270
|
+
case "send_event":
|
|
271
|
+
s.event && i("eventNotifaction", s);
|
|
271
272
|
break;
|
|
272
273
|
case "control":
|
|
273
|
-
|
|
274
|
-
break;
|
|
275
|
-
case "highlight":
|
|
276
|
-
l("highlight", r);
|
|
277
|
-
break;
|
|
278
|
-
case "showDialog":
|
|
279
|
-
l("showDialog", r);
|
|
274
|
+
b && M(b);
|
|
280
275
|
break;
|
|
281
276
|
case "end":
|
|
282
|
-
|
|
277
|
+
i("end", u);
|
|
283
278
|
break;
|
|
284
279
|
case "pause":
|
|
285
|
-
|
|
280
|
+
i("pause", u);
|
|
286
281
|
break;
|
|
287
282
|
default:
|
|
288
|
-
console.warn(`[VirtualHumanEventAdapter] Unknown message type: ${
|
|
283
|
+
console.warn(`[VirtualHumanEventAdapter] Unknown message type: ${l}`);
|
|
289
284
|
}
|
|
290
285
|
};
|
|
291
286
|
return X(() => t.screenClientId, () => {
|
|
@@ -295,8 +290,8 @@ const ae = ["src", "muted"], se = { class: "overlay" }, le = {
|
|
|
295
290
|
}), G(() => {
|
|
296
291
|
t.screenClientId && t.wsUrl && A();
|
|
297
292
|
}), K(() => {
|
|
298
|
-
|
|
299
|
-
}), (s,
|
|
293
|
+
r.value && r.value.close(), n && n.close();
|
|
294
|
+
}), (s, l) => ne(s.$slots, "default");
|
|
300
295
|
}
|
|
301
296
|
}), de = (c) => {
|
|
302
297
|
c.component("VirtualHumanPersona", ue), c.component("VirtualHumanEventAdapter", ce);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(
|
|
1
|
+
(function(v,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],e):(v=typeof globalThis<"u"?globalThis:v||self,e(v.VirtualHumanCf={},v.Vue))})(this,function(v,e){"use strict";const F=["src","muted"],O={class:"overlay"},j={key:0,class:"status-badge paused"},J={key:1,class:"status-badge playing"},q=((d,A)=>{const n=d.__vccOpts||d;for(const[c,i]of A)n[c]=i;return n})(e.defineComponent({__name:"VirtualHumanPersona",props:{videoSrc:{type:String,required:!0},visible:{type:Boolean,default:!1},isPlaying:{type:Boolean,default:!1},muted:{type:Boolean,default:!0},isDark:{type:Boolean,default:!1},screenClientId:{type:String,required:!1},wsUrl:{type:String,required:!1}},emits:["update:isPlaying","ended","update:visible"],setup(d,{emit:A}){const n=d,c=A,i=e.ref(null),W=e.ref(null),a=e.ref(null),y=e.ref(!1),g=e.ref(400),w=e.ref(500),h=e.ref(16),x=e.ref(16),H=e.ref(!1),b=e.ref(null),z=e.ref(0),B=e.ref(0),C=e.ref(0),l=e.ref(0),s=e.ref(0),u=e.ref(0),k=()=>{if(a.value&&a.value.close(),!(!n.wsUrl||!n.screenClientId))try{const r=new URL(n.wsUrl);r.searchParams.append("sessionId",n.screenClientId+"-persona"),a.value=new WebSocket(r.toString()),a.value.onopen=()=>{y.value=!0,console.log(`[VirtualHumanPersona] Connected to ${n.wsUrl} for session ${n.screenClientId}-persona`)},a.value.onmessage=t=>{try{const o=JSON.parse(t.data);V(o)}catch(o){console.error("[VirtualHumanPersona] Failed to parse message:",t.data,o)}},a.value.onerror=t=>{console.error("[VirtualHumanPersona] WebSocket error:",t)},a.value.onclose=()=>{y.value=!1,console.log("[VirtualHumanPersona] WebSocket disconnected")}}catch(r){console.error("[VirtualHumanPersona] Failed to initialize WebSocket:",r)}},V=r=>{const{type:t,action:o}=r;t==="control"&&(o==="play"||o==="resume"?(c("update:isPlaying",!0),c("update:visible",!0)):o==="pause"?c("update:isPlaying",!1):o==="stop"&&(c("update:isPlaying",!1),c("update:visible",!1),i.value&&(i.value.currentTime=0)))};e.watch(()=>n.screenClientId,()=>{n.screenClientId&&n.wsUrl&&k()}),e.watch(()=>n.wsUrl,()=>{n.screenClientId&&n.wsUrl&&k()}),e.watch(()=>n.isPlaying,r=>{i.value&&(r?i.value.play().catch(t=>console.error("Video play failed:",t)):i.value.pause())});const N=()=>{n.isPlaying||c("update:isPlaying",!0)},T=()=>{n.isPlaying&&c("update:isPlaying",!1)},I=()=>{c("update:isPlaying",!1),c("ended")},f=(r,t)=>{t.preventDefault(),H.value=!0,b.value=r;const o="clientX"in t?t.clientX:t.touches[0].clientX,P="clientY"in t?t.clientY:t.touches[0].clientY;z.value=o,B.value=P,C.value=g.value,l.value=w.value,s.value=h.value,u.value=x.value,document.addEventListener("mousemove",L),document.addEventListener("mouseup",M),document.addEventListener("touchmove",L,{passive:!1}),document.addEventListener("touchend",M)},L=r=>{if(!H.value)return;r.preventDefault();const t="clientX"in r?r.clientX:r.touches[0].clientX,o="clientY"in r?r.clientY:r.touches[0].clientY,P=t-z.value,U=o-B.value,R=200,X=250,Y=800,$=1e3;let m=C.value,p=l.value,E=s.value,S=u.value;b.value==="bottom-right"?(m=C.value+P,S=u.value-U,p=l.value+U):b.value==="bottom-left"?(E=s.value+P,m=C.value-P,S=u.value-U,p=l.value+U):b.value==="top-right"?(m=C.value+P,p=l.value-U):b.value==="top-left"&&(E=s.value+P,m=C.value-P,p=l.value-U),m<R&&(E!==s.value&&(E-=R-m),m=R),p<X&&(S!==u.value&&(S-=X-p),p=X),m>Y&&(E!==s.value&&(E+=m-Y),m=Y),p>$&&(S!==u.value&&(S+=p-$),p=$),g.value=m,w.value=p,h.value=E,x.value=S},M=()=>{H.value=!1,b.value=null,document.removeEventListener("mousemove",L),document.removeEventListener("mouseup",M),document.removeEventListener("touchmove",L),document.removeEventListener("touchend",M)};return e.onMounted(()=>{n.isPlaying&&i.value&&i.value.play().catch(r=>console.error("Video play failed:",r)),n.screenClientId&&n.wsUrl&&k()}),e.onUnmounted(()=>{a.value&&a.value.close()}),(r,t)=>(e.openBlock(),e.createBlock(e.Transition,{name:"fade"},{default:e.withCtx(()=>[d.visible?(e.openBlock(),e.createElementBlock("div",{key:0,class:e.normalizeClass(["virtual-human-container",{"is-dark":d.isDark}]),style:e.normalizeStyle({width:g.value+"px",height:w.value+"px",left:h.value+"px",bottom:x.value+"px"})},[e.createElementVNode("div",{class:"video-wrapper",ref_key:"wrapperRef",ref:W},[e.createElementVNode("video",{ref_key:"videoRef",ref:i,src:d.videoSrc,class:"persona-video",muted:d.muted,playsinline:"",loop:"",autoPlay:"",disablePictureInPicture:"false",onPlay:N,onPause:T,onEnded:I},null,40,F),d.visible?(e.openBlock(),e.createElementBlock("div",{key:0,class:"resize-handle top-left",onMousedown:t[0]||(t[0]=o=>f("top-left",o)),onTouchstart:t[1]||(t[1]=o=>f("top-left",o))},null,32)):e.createCommentVNode("",!0),d.visible?(e.openBlock(),e.createElementBlock("div",{key:1,class:"resize-handle top-right",onMousedown:t[2]||(t[2]=o=>f("top-right",o)),onTouchstart:t[3]||(t[3]=o=>f("top-right",o))},null,32)):e.createCommentVNode("",!0),d.visible?(e.openBlock(),e.createElementBlock("div",{key:2,class:"resize-handle bottom-left",onMousedown:t[4]||(t[4]=o=>f("bottom-left",o)),onTouchstart:t[5]||(t[5]=o=>f("bottom-left",o))},null,32)):e.createCommentVNode("",!0),d.visible?(e.openBlock(),e.createElementBlock("div",{key:3,class:"resize-handle bottom-right",onMousedown:t[6]||(t[6]=o=>f("bottom-right",o)),onTouchstart:t[7]||(t[7]=o=>f("bottom-right",o))},null,32)):e.createCommentVNode("",!0),e.createElementVNode("div",O,[d.isPlaying?(e.openBlock(),e.createElementBlock("div",J,[...t[9]||(t[9]=[e.createElementVNode("span",{class:"dot animate-pulse"},null,-1),e.createTextVNode(" 播放中 ",-1)])])):(e.openBlock(),e.createElementBlock("div",j,[...t[8]||(t[8]=[e.createElementVNode("span",{class:"dot"},null,-1),e.createTextVNode(" 暂停中 ",-1)])]))])],512)],6)):e.createCommentVNode("",!0)]),_:1}))}}),[["__scopeId","data-v-6c9e435e"]]),D=e.defineComponent({__name:"VirtualHumanEventAdapter",props:{screenClientId:{type:String,required:!0},wsUrl:{type:String,required:!0}},emits:["eventNotifaction","end","pause","connected","error","playComplete"],setup(d,{emit:A}){const n=d,c=A,i=e.ref(null),W=e.ref(!1);let a=null,y=0,g=!1,w=0,h=!1;const x=()=>{a||(a=new(window.AudioContext||window.webkitAudioContext)({sampleRate:24e3})),a.state==="suspended"&&!h&&a.resume()},H=()=>{g&&w===0&&(c("playComplete",n.screenClientId),g=!1)},b=l=>{if(x(),!!a)try{const s=window.atob(l),u=s.length,k=new Uint8Array(u);for(let f=0;f<u;f++)k[f]=s.charCodeAt(f);const V=new Int16Array(k.buffer),N=new Float32Array(V.length);for(let f=0;f<V.length;f++)N[f]=V[f]/32768;const T=a.createBuffer(1,N.length,24e3);T.getChannelData(0).set(N);const I=a.createBufferSource();I.buffer=T,I.connect(a.destination),y<a.currentTime&&(y=a.currentTime),I.start(y),y+=T.duration,w++,I.onended=()=>{w--,H()}}catch(s){console.error("[VirtualHumanEventAdapter] Failed to decode and play audio:",s)}},z=l=>{switch(l){case"play":g=!1,w=0,y=0,h=!1,a&&a.state==="suspended"&&a.resume();break;case"resume":h=!1,a&&a.state==="suspended"&&a.resume();break;case"pause":h=!0,a&&a.state==="running"&&a.suspend();break;case"stop":h=!1,a&&(a.close(),a=null),y=0,g=!1,w=0;break;case"tts_complete":g=!0,H();break;default:console.warn(`[VirtualHumanEventAdapter] Unknown control action: ${l}`)}},B=()=>{i.value&&i.value.close();try{const l=new URL(n.wsUrl);l.searchParams.append("sessionId",n.screenClientId+"-event"),i.value=new WebSocket(l.toString()),i.value.onopen=()=>{W.value=!0,c("connected"),console.log(`[VirtualHumanEventAdapter] Connected to ${n.wsUrl} for session ${n.screenClientId}-event`)},i.value.onmessage=s=>{try{const u=JSON.parse(s.data);C(u)}catch(u){console.error("[VirtualHumanEventAdapter] Failed to parse message:",s.data,u)}},i.value.onerror=s=>{console.error("[VirtualHumanEventAdapter] WebSocket error:",s),c("error",s)},i.value.onclose=()=>{W.value=!1,console.log("[VirtualHumanEventAdapter] WebSocket disconnected")}}catch(l){console.error("[VirtualHumanEventAdapter] Failed to initialize WebSocket:",l),c("error",l)}},C=l=>{const{type:s,payload:u,action:k}=l;switch(console.log("msgmsg-002",l),s){case"audio":const V=(u==null?void 0:u.data)||l.data;V&&b(V);break;case"send_event":l.event&&c("eventNotifaction",l);break;case"control":k&&z(k);break;case"end":c("end",u);break;case"pause":c("pause",u);break;default:console.warn(`[VirtualHumanEventAdapter] Unknown message type: ${s}`)}};return e.watch(()=>n.screenClientId,()=>{n.screenClientId&&n.wsUrl&&B()}),e.watch(()=>n.wsUrl,()=>{n.screenClientId&&n.wsUrl&&B()}),e.onMounted(()=>{n.screenClientId&&n.wsUrl&&B()}),e.onUnmounted(()=>{i.value&&i.value.close(),a&&a.close()}),(l,s)=>e.renderSlot(l.$slots,"default")}}),G={install:d=>{d.component("VirtualHumanPersona",q),d.component("VirtualHumanEventAdapter",D)}};v.VirtualHumanEventAdapter=D,v.VirtualHumanPersona=q,v.default=G,Object.defineProperties(v,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
|
package/package.json
CHANGED
|
@@ -18,7 +18,7 @@ const props = defineProps({
|
|
|
18
18
|
}
|
|
19
19
|
});
|
|
20
20
|
|
|
21
|
-
const emit = defineEmits(['
|
|
21
|
+
const emit = defineEmits(['eventNotifaction', 'end', 'pause', 'connected', 'error', 'playComplete']);
|
|
22
22
|
|
|
23
23
|
const ws = ref<WebSocket | null>(null);
|
|
24
24
|
const isConnected = ref(false);
|
|
@@ -28,6 +28,7 @@ let audioContext: AudioContext | null = null;
|
|
|
28
28
|
let nextStartTime = 0;
|
|
29
29
|
let isTtsComplete = false;
|
|
30
30
|
let activeSources = 0;
|
|
31
|
+
let isIntentionallyPaused = false;
|
|
31
32
|
|
|
32
33
|
const initAudioContext = () => {
|
|
33
34
|
if (!audioContext) {
|
|
@@ -35,14 +36,14 @@ const initAudioContext = () => {
|
|
|
35
36
|
sampleRate: 24000
|
|
36
37
|
});
|
|
37
38
|
}
|
|
38
|
-
if (audioContext.state === 'suspended') {
|
|
39
|
+
if (audioContext.state === 'suspended' && !isIntentionallyPaused) {
|
|
39
40
|
audioContext.resume();
|
|
40
41
|
}
|
|
41
42
|
};
|
|
42
43
|
|
|
43
44
|
const checkPlayComplete = () => {
|
|
44
45
|
if (isTtsComplete && activeSources === 0) {
|
|
45
|
-
emit('
|
|
46
|
+
emit('playComplete', props.screenClientId);
|
|
46
47
|
isTtsComplete = false;
|
|
47
48
|
}
|
|
48
49
|
};
|
|
@@ -91,27 +92,30 @@ const handleAudioMessage = (base64Data: string) => {
|
|
|
91
92
|
};
|
|
92
93
|
|
|
93
94
|
const handleControlMessage = (action: string) => {
|
|
94
|
-
if (!audioContext && action !== 'stop') return;
|
|
95
95
|
switch (action) {
|
|
96
96
|
case 'play':
|
|
97
97
|
isTtsComplete = false;
|
|
98
98
|
activeSources = 0;
|
|
99
99
|
nextStartTime = 0;
|
|
100
|
+
isIntentionallyPaused = false;
|
|
100
101
|
if (audioContext && audioContext.state === 'suspended') {
|
|
101
102
|
audioContext.resume();
|
|
102
103
|
}
|
|
103
104
|
break;
|
|
104
105
|
case 'resume':
|
|
106
|
+
isIntentionallyPaused = false;
|
|
105
107
|
if (audioContext && audioContext.state === 'suspended') {
|
|
106
108
|
audioContext.resume();
|
|
107
109
|
}
|
|
108
110
|
break;
|
|
109
111
|
case 'pause':
|
|
112
|
+
isIntentionallyPaused = true;
|
|
110
113
|
if (audioContext && audioContext.state === 'running') {
|
|
111
114
|
audioContext.suspend();
|
|
112
115
|
}
|
|
113
116
|
break;
|
|
114
117
|
case 'stop':
|
|
118
|
+
isIntentionallyPaused = false;
|
|
115
119
|
if (audioContext) {
|
|
116
120
|
audioContext.close();
|
|
117
121
|
audioContext = null;
|
|
@@ -171,32 +175,27 @@ const connectWebSocket = () => {
|
|
|
171
175
|
|
|
172
176
|
const handleMessage = (msg: any) => {
|
|
173
177
|
const { type, payload, action } = msg;
|
|
174
|
-
console.log("msgmsg",msg)
|
|
178
|
+
console.log("msgmsg-002",msg)
|
|
175
179
|
switch (type) {
|
|
180
|
+
// 接收音频
|
|
176
181
|
case 'audio':
|
|
177
182
|
const base64Data = payload?.data || msg.data;
|
|
178
183
|
if (base64Data) {
|
|
179
184
|
handleAudioMessage(base64Data);
|
|
180
185
|
}
|
|
181
186
|
break;
|
|
182
|
-
|
|
187
|
+
// 接收事件通知
|
|
188
|
+
case 'send_event':
|
|
183
189
|
if (msg.event) {
|
|
184
|
-
emit(
|
|
190
|
+
emit('eventNotifaction', msg);
|
|
185
191
|
}
|
|
186
192
|
break;
|
|
193
|
+
// 控制指令接口
|
|
187
194
|
case 'control':
|
|
188
195
|
if (action) {
|
|
189
196
|
handleControlMessage(action);
|
|
190
197
|
}
|
|
191
198
|
break;
|
|
192
|
-
case 'highlight':
|
|
193
|
-
// 触发高亮大屏某区域事件
|
|
194
|
-
emit('highlight', payload);
|
|
195
|
-
break;
|
|
196
|
-
case 'showDialog':
|
|
197
|
-
// 触发弹窗显示事件
|
|
198
|
-
emit('showDialog', payload);
|
|
199
|
-
break;
|
|
200
199
|
case 'end':
|
|
201
200
|
// 触发数字人对话结束事件
|
|
202
201
|
emit('end', payload);
|