virtual-human-cf 1.3.0 → 1.5.0
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 +148 -65
- package/dist/api/request.d.ts +2 -0
- package/dist/api/screen.d.ts +13 -0
- package/dist/components/VirtualHumanEventAdapter.vue.d.ts +8 -3
- package/dist/style.css +1 -1
- package/dist/virtual-human-cf.es.js +2061 -161
- package/dist/virtual-human-cf.umd.js +6 -1
- package/package.json +6 -2
- package/src/api/request.ts +22 -0
- package/src/api/screen.ts +36 -0
- package/src/components/VirtualHumanEventAdapter.vue +29 -0
- package/src/components/VirtualHumanPersona.vue +3 -0
- package/tsconfig.json +6 -2
- package/vite.config.ts +6 -1
package/README.md
CHANGED
|
@@ -12,26 +12,67 @@
|
|
|
12
12
|
- 响应式设计
|
|
13
13
|
|
|
14
14
|
## 更新日志
|
|
15
|
-
### 1.2.0
|
|
16
|
-
- 新增VirtualHumanEventAdapter组件controlEvent事件,用于数字人播放周期控制指令通知
|
|
17
|
-
```javascript
|
|
18
|
-
<VirtualHumanEventAdapter
|
|
19
|
-
v-if="activeScreenClientId"
|
|
20
|
-
@controlEvent="onControlEvent"
|
|
21
|
-
/>
|
|
22
|
-
const onControlEvent = (event) => {
|
|
23
|
-
console.log(event);
|
|
24
|
-
// play 初次开始播放
|
|
25
|
-
// resume 恢复播放
|
|
26
|
-
// pause 暂停播放
|
|
27
|
-
// stop 停止播放
|
|
28
|
-
// tts_complete 文本转语音完成,不代表本地播放完成
|
|
29
|
-
}
|
|
30
|
-
```
|
|
31
15
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
16
|
+
### 1.5.0
|
|
17
|
+
- 新增VirtualHumanEventAdapter组件对外暴露play方法
|
|
18
|
+
|
|
19
|
+
```javascript
|
|
20
|
+
<VirtualHumanEventAdapter
|
|
21
|
+
v-if="activeScreenClientId"
|
|
22
|
+
@controlEvent="onControlEvent"
|
|
23
|
+
ref="adapterRef"
|
|
24
|
+
/>
|
|
25
|
+
const adapterRef = ref(null);
|
|
26
|
+
|
|
27
|
+
// 底部有使用demo,这里不重复
|
|
28
|
+
// 播放
|
|
29
|
+
adapterRef.value.play().then(() => {}).catch(() => {});
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
### 1.4.0
|
|
33
|
+
- 新增VirtualHumanEventAdapter组件对外暴露pause、resume、stop方法
|
|
34
|
+
|
|
35
|
+
```javascript
|
|
36
|
+
<VirtualHumanEventAdapter
|
|
37
|
+
v-if="activeScreenClientId"
|
|
38
|
+
@controlEvent="onControlEvent"
|
|
39
|
+
ref="adapterRef"
|
|
40
|
+
/>
|
|
41
|
+
const adapterRef = ref(null);
|
|
42
|
+
|
|
43
|
+
// 底部有使用demo,这里不重复
|
|
44
|
+
// 暂停播放
|
|
45
|
+
adapterRef.value.pause().then(() => {}).catch(() => {});
|
|
46
|
+
// 恢复播放
|
|
47
|
+
adapterRef.value.resume().then(() => {}).catch(() => {});
|
|
48
|
+
// 停止播放
|
|
49
|
+
adapterRef.value.stop().then(() => {}).catch(() => {});
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### 1.2.0
|
|
54
|
+
|
|
55
|
+
- 新增VirtualHumanEventAdapter组件controlEvent事件,用于数字人播放周期控制指令通知
|
|
56
|
+
|
|
57
|
+
```javascript
|
|
58
|
+
<VirtualHumanEventAdapter
|
|
59
|
+
v-if="activeScreenClientId"
|
|
60
|
+
@controlEvent="onControlEvent"
|
|
61
|
+
/>
|
|
62
|
+
const onControlEvent = (event) => {
|
|
63
|
+
console.log(event);
|
|
64
|
+
// play 初次开始播放
|
|
65
|
+
// resume 恢复播放
|
|
66
|
+
// pause 暂停播放
|
|
67
|
+
// stop 停止播放
|
|
68
|
+
// tts_complete 文本转语音完成,不代表本地播放完成
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### 1.0.10
|
|
73
|
+
|
|
74
|
+
- 新增VirtualHumanPersona组件styles属性,用于控制视频容器 宽高 绝对定位位置等
|
|
75
|
+
|
|
35
76
|
## 安装
|
|
36
77
|
|
|
37
78
|
```bash
|
|
@@ -43,9 +84,9 @@ npm install virtual-human-cf
|
|
|
43
84
|
### 全局注册
|
|
44
85
|
|
|
45
86
|
```javascript
|
|
46
|
-
import { createApp } from
|
|
47
|
-
import App from
|
|
48
|
-
import VirtualHumanCF from
|
|
87
|
+
import { createApp } from "vue";
|
|
88
|
+
import App from "./App.vue";
|
|
89
|
+
import VirtualHumanCF from "virtual-human-cf";
|
|
49
90
|
|
|
50
91
|
const app = createApp(App);
|
|
51
92
|
app.use(VirtualHumanCF);
|
|
@@ -54,7 +95,10 @@ app.use(VirtualHumanCF);
|
|
|
54
95
|
### 按需导入
|
|
55
96
|
|
|
56
97
|
```javascript
|
|
57
|
-
import {
|
|
98
|
+
import {
|
|
99
|
+
VirtualHumanPersona,
|
|
100
|
+
VirtualHumanEventAdapter,
|
|
101
|
+
} from "virtual-human-cf";
|
|
58
102
|
```
|
|
59
103
|
|
|
60
104
|
## 组件说明
|
|
@@ -65,24 +109,24 @@ import { VirtualHumanPersona, VirtualHumanEventAdapter } from 'virtual-human-cf'
|
|
|
65
109
|
|
|
66
110
|
#### Props
|
|
67
111
|
|
|
68
|
-
| 属性
|
|
69
|
-
|
|
70
|
-
| videoSrc
|
|
71
|
-
| visible
|
|
72
|
-
| isPlaying
|
|
73
|
-
| muted
|
|
74
|
-
| isDark
|
|
75
|
-
| screenClientId | String
|
|
76
|
-
| wsUrl
|
|
77
|
-
| styles
|
|
112
|
+
| 属性 | 类型 | 默认值 | 必填 | 说明 |
|
|
113
|
+
| -------------- | ------- | ------ | ---- | ------------------------------------------------- |
|
|
114
|
+
| videoSrc | String | - | 是 | 视频源 URL |
|
|
115
|
+
| visible | Boolean | true | 否 | 是否可见 |
|
|
116
|
+
| isPlaying | Boolean | false | 否 | 是否正在播放 |
|
|
117
|
+
| muted | Boolean | true | 否 | 是否静音 |
|
|
118
|
+
| isDark | Boolean | false | 否 | 是否暗黑模式 |
|
|
119
|
+
| screenClientId | String | - | 否 | 屏幕客户端 ID |
|
|
120
|
+
| wsUrl | String | - | 否 | WebSocket 连接地址 |
|
|
121
|
+
| styles | Object | - | 否 | 组件样式,包含 width、height、left、bottom 等属性 |
|
|
78
122
|
|
|
79
123
|
#### Events
|
|
80
124
|
|
|
81
|
-
| 事件名
|
|
82
|
-
|
|
125
|
+
| 事件名 | 说明 | 回调参数 |
|
|
126
|
+
| ---------------- | ------------ | ----------------- |
|
|
83
127
|
| update:isPlaying | 播放状态变更 | 播放状态(Boolean) |
|
|
84
|
-
| update:visible
|
|
85
|
-
| ended
|
|
128
|
+
| update:visible | 可见性变更 | 可见状态(Boolean) |
|
|
129
|
+
| ended | 播放结束 | - |
|
|
86
130
|
|
|
87
131
|
#### 示例
|
|
88
132
|
|
|
@@ -102,25 +146,25 @@ import { VirtualHumanPersona, VirtualHumanEventAdapter } from 'virtual-human-cf'
|
|
|
102
146
|
</template>
|
|
103
147
|
|
|
104
148
|
<script setup>
|
|
105
|
-
import { ref } from
|
|
106
|
-
import { VirtualHumanPersona } from
|
|
149
|
+
import { ref } from "vue";
|
|
150
|
+
import { VirtualHumanPersona } from "virtual-human-cf";
|
|
107
151
|
|
|
108
|
-
const videoUrl = ref(
|
|
152
|
+
const videoUrl = ref("https://example.com/video.mp4");
|
|
109
153
|
const playing = ref(false);
|
|
110
|
-
const clientId = ref(
|
|
111
|
-
const websocketUrl = ref(
|
|
154
|
+
const clientId = ref("screen-123");
|
|
155
|
+
const websocketUrl = ref("ws://localhost:8080/ws");
|
|
112
156
|
const styles = ref({
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
})
|
|
157
|
+
width: "400px",
|
|
158
|
+
height: "500px",
|
|
159
|
+
left: "16px",
|
|
160
|
+
bottom: "16px",
|
|
161
|
+
});
|
|
118
162
|
const onPlayingChange = (isPlaying) => {
|
|
119
|
-
console.log(
|
|
163
|
+
console.log("播放状态改变:", isPlaying);
|
|
120
164
|
};
|
|
121
165
|
|
|
122
166
|
const onEnded = () => {
|
|
123
|
-
console.log(
|
|
167
|
+
console.log("播放结束");
|
|
124
168
|
};
|
|
125
169
|
</script>
|
|
126
170
|
```
|
|
@@ -131,27 +175,37 @@ const onEnded = () => {
|
|
|
131
175
|
|
|
132
176
|
#### Props
|
|
133
177
|
|
|
134
|
-
| 属性
|
|
135
|
-
|
|
136
|
-
| screenClientId | String | -
|
|
137
|
-
| wsUrl
|
|
178
|
+
| 属性 | 类型 | 默认值 | 必填 | 说明 |
|
|
179
|
+
| -------------- | ------ | ------ | ---- | ------------------ |
|
|
180
|
+
| screenClientId | String | - | 是 | 屏幕客户端 ID |
|
|
181
|
+
| wsUrl | String | - | 是 | WebSocket 连接地址 |
|
|
138
182
|
|
|
139
183
|
#### Events
|
|
140
184
|
|
|
141
|
-
| 事件名
|
|
142
|
-
|
|
143
|
-
| connected
|
|
144
|
-
| eventNotifaction | 自定义事件接收器
|
|
145
|
-
| end
|
|
146
|
-
| pause
|
|
147
|
-
| error
|
|
148
|
-
| playComplete
|
|
149
|
-
| controlEvent
|
|
185
|
+
| 事件名 | 说明 | 回调参数 |
|
|
186
|
+
| ---------------- | ------------------------------------ | -------- |
|
|
187
|
+
| connected | WebSocket 连接成功 | - |
|
|
188
|
+
| eventNotifaction | 自定义事件接收器 | 载荷数据 |
|
|
189
|
+
| end | 数字人对话结束 | 载荷数据 |
|
|
190
|
+
| pause | 暂停播放 | 载荷数据 |
|
|
191
|
+
| error | 错误事件 | 错误信息 |
|
|
192
|
+
| playComplete | 播放完成,数字人对话结束,关闭数字人 | - |
|
|
193
|
+
| controlEvent | 数字人控制事件 | 载荷数据 |
|
|
194
|
+
|
|
195
|
+
#### refs
|
|
196
|
+
|
|
197
|
+
| 方法名 | 说明 | 回调参数 |
|
|
198
|
+
| ------ | -------- | -------- |
|
|
199
|
+
| play | 播放 |Promise<boolean> |
|
|
200
|
+
| pause | 暂停播放 |Promise<boolean> |
|
|
201
|
+
| resume | 恢复播放 |Promise<boolean> |
|
|
202
|
+
| stop | 停止播放 |Promise<boolean> |
|
|
203
|
+
|
|
150
204
|
|
|
151
205
|
```js
|
|
152
206
|
// eventNotifaction 载荷数据
|
|
153
207
|
{
|
|
154
|
-
|
|
208
|
+
|
|
155
209
|
"type": "send_event",
|
|
156
210
|
// 自定义事件名称
|
|
157
211
|
"event": "heightlight",
|
|
@@ -182,6 +236,7 @@ tts_complete 文本转语音完成,不代表本地播放完成
|
|
|
182
236
|
@controlEvent="onControlEvent"
|
|
183
237
|
@end="onEnd"
|
|
184
238
|
@error="onError"
|
|
239
|
+
ref="adapterRef"
|
|
185
240
|
>
|
|
186
241
|
<div>其他内容</div>
|
|
187
242
|
</VirtualHumanEventAdapter>
|
|
@@ -212,6 +267,34 @@ const onEnd = (payload) => {
|
|
|
212
267
|
const onError = (error) => {
|
|
213
268
|
console.error('错误:', error);
|
|
214
269
|
};
|
|
270
|
+
|
|
271
|
+
const adapterRef = ref(null);
|
|
272
|
+
const controlFunc = () => {
|
|
273
|
+
// 播放
|
|
274
|
+
adapterRef.value.play().then(res => {
|
|
275
|
+
// res boolean true 播放成功 false 播放失败
|
|
276
|
+
}).catch((error) => {
|
|
277
|
+
console.error('播放失败:', error);
|
|
278
|
+
});
|
|
279
|
+
// 暂停播放
|
|
280
|
+
adapterRef.value.pause().then(res => {
|
|
281
|
+
// res boolean true 暂停成功 false 暂停失败
|
|
282
|
+
}).catch((error) => {
|
|
283
|
+
console.error('暂停播放失败:', error);
|
|
284
|
+
});
|
|
285
|
+
// 恢复播放
|
|
286
|
+
adapterRef.value.resume().then(res => {
|
|
287
|
+
// res boolean true 恢复成功 false 恢复失败
|
|
288
|
+
}).catch((error) => {
|
|
289
|
+
console.error('恢复播放失败:', error);
|
|
290
|
+
});
|
|
291
|
+
// 停止播放
|
|
292
|
+
adapterRef.value.stop().then(res => {
|
|
293
|
+
// res boolean true 停止成功 false 停止失败
|
|
294
|
+
}).catch((error) => {
|
|
295
|
+
console.error('停止播放失败:', error);
|
|
296
|
+
});
|
|
297
|
+
}
|
|
215
298
|
</script>
|
|
216
299
|
```
|
|
217
300
|
|
|
@@ -235,7 +318,7 @@ const onError = (error) => {
|
|
|
235
318
|
@update:visible="onPersonaVisibleUpdate"
|
|
236
319
|
@ended="onVideoEnded"
|
|
237
320
|
/>
|
|
238
|
-
|
|
321
|
+
|
|
239
322
|
<VirtualHumanEventAdapter
|
|
240
323
|
:screen-client-id="activeScreenClientId"
|
|
241
324
|
:ws-url="websocketUrl"
|
|
@@ -315,4 +398,4 @@ npm run build
|
|
|
315
398
|
|
|
316
399
|
## 许可证
|
|
317
400
|
|
|
318
|
-
MIT
|
|
401
|
+
MIT
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface ScreenConfig {
|
|
2
|
+
id?: number;
|
|
3
|
+
name: string;
|
|
4
|
+
screenClientId: string;
|
|
5
|
+
createTime?: string;
|
|
6
|
+
updateTime?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare const getScreenList: () => Promise<ScreenConfig[]>;
|
|
9
|
+
export declare const getScreenById: (id: number) => Promise<ScreenConfig>;
|
|
10
|
+
export declare const createScreen: (data: ScreenConfig) => Promise<boolean>;
|
|
11
|
+
export declare const updateScreen: (id: number, data: ScreenConfig) => Promise<boolean>;
|
|
12
|
+
export declare const deleteScreen: (id: number) => Promise<boolean>;
|
|
13
|
+
export declare const controlScreen: (screenClientId: string, action: "play" | "pause" | "stop" | "resume") => Promise<boolean>;
|
|
@@ -10,9 +10,14 @@ declare const __VLS_component: import('vue').DefineComponent<import('vue').Extra
|
|
|
10
10
|
type: StringConstructor;
|
|
11
11
|
required: true;
|
|
12
12
|
};
|
|
13
|
-
}>, {
|
|
14
|
-
|
|
13
|
+
}>, {
|
|
14
|
+
play: () => Promise<boolean>;
|
|
15
|
+
pause: () => Promise<boolean>;
|
|
16
|
+
resume: () => Promise<boolean>;
|
|
17
|
+
stop: () => Promise<boolean>;
|
|
18
|
+
}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
|
|
15
19
|
pause: (...args: any[]) => void;
|
|
20
|
+
error: (...args: any[]) => void;
|
|
16
21
|
eventNotifaction: (...args: any[]) => void;
|
|
17
22
|
controlEvent: (...args: any[]) => void;
|
|
18
23
|
end: (...args: any[]) => void;
|
|
@@ -28,8 +33,8 @@ declare const __VLS_component: import('vue').DefineComponent<import('vue').Extra
|
|
|
28
33
|
required: true;
|
|
29
34
|
};
|
|
30
35
|
}>> & Readonly<{
|
|
31
|
-
onError?: ((...args: any[]) => any) | undefined;
|
|
32
36
|
onPause?: ((...args: any[]) => any) | undefined;
|
|
37
|
+
onError?: ((...args: any[]) => any) | undefined;
|
|
33
38
|
onEventNotifaction?: ((...args: any[]) => any) | undefined;
|
|
34
39
|
onControlEvent?: ((...args: any[]) => any) | undefined;
|
|
35
40
|
onEnd?: ((...args: any[]) => any) | undefined;
|
package/dist/style.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
.fade-enter-active[data-v-
|
|
1
|
+
.fade-enter-active[data-v-02ec3645],.fade-leave-active[data-v-02ec3645]{transition:opacity .5s ease,transform .5s ease}.fade-enter-from[data-v-02ec3645],.fade-leave-to[data-v-02ec3645]{opacity:0;transform:translateY(10px)}.virtual-human-container[data-v-02ec3645]{position:fixed;z-index:2147483647;overflow:visible}.video-wrapper[data-v-02ec3645]{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-02ec3645]:hover{border-color:#409eff}.virtual-human-container.is-dark .video-wrapper[data-v-02ec3645]{background:#1f2937;box-shadow:0 10px 25px #00000080}.persona-video[data-v-02ec3645]{width:100%;height:100%;object-fit:cover;transform-origin:center;transition:transform .1s ease-out}.resize-handle[data-v-02ec3645]{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-02ec3645]{opacity:1;pointer-events:auto}.resize-handle[data-v-02ec3645]:hover{background:#000000b3;border-color:#fff}.resize-handle.top-left[data-v-02ec3645]{top:10px;left:10px;cursor:nwse-resize}.resize-handle.top-right[data-v-02ec3645]{top:10px;right:10px;cursor:nesw-resize}.resize-handle.bottom-left[data-v-02ec3645]{bottom:10px;left:10px;cursor:nesw-resize}.resize-handle.bottom-right[data-v-02ec3645]{bottom:10px;right:10px;cursor:nwse-resize}.overlay[data-v-02ec3645]{position:absolute;top:1rem;right:1rem;z-index:10}.status-badge[data-v-02ec3645]{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-02ec3645]{background:#ef4444cc}.status-badge.playing[data-v-02ec3645]{background:#22c55ecc}.dot[data-v-02ec3645]{width:6px;height:6px;border-radius:50%;background-color:#fff}@keyframes pulse-02ec3645{0%,to{opacity:1}50%{opacity:.5}}.animate-pulse[data-v-02ec3645]{animation:pulse-02ec3645 2s cubic-bezier(.4,0,.6,1) infinite}
|