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 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
- ### 1.0.10
33
- - 新增VirtualHumanPersona组件styles属性,用于控制视频容器 宽高 绝对定位位置等
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 'vue';
47
- import App from './App.vue';
48
- import VirtualHumanCF from 'virtual-human-cf';
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 { VirtualHumanPersona, VirtualHumanEventAdapter } from 'virtual-human-cf';
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 | String | - | 是 | 视频源 URL |
71
- | visible | Boolean | true | 否 | 是否可见 |
72
- | isPlaying | Boolean | false | 否 | 是否正在播放 |
73
- | muted | Boolean | true | 否 | 是否静音 |
74
- | isDark | Boolean | false | 否 | 是否暗黑模式 |
75
- | screenClientId | String | - | 否 | 屏幕客户端 ID |
76
- | wsUrl | String | - | 否 | WebSocket 连接地址 |
77
- | styles | Object | - | 否 | 组件样式,包含 width、height、left、bottom 等属性 |
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 | 可见性变更 | 可见状态(Boolean) |
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 'vue';
106
- import { VirtualHumanPersona } from 'virtual-human-cf';
149
+ import { ref } from "vue";
150
+ import { VirtualHumanPersona } from "virtual-human-cf";
107
151
 
108
- const videoUrl = ref('https://example.com/video.mp4');
152
+ const videoUrl = ref("https://example.com/video.mp4");
109
153
  const playing = ref(false);
110
- const clientId = ref('screen-123');
111
- const websocketUrl = ref('ws://localhost:8080/ws');
154
+ const clientId = ref("screen-123");
155
+ const websocketUrl = ref("ws://localhost:8080/ws");
112
156
  const styles = ref({
113
- width:'400px',
114
- height:'500px',
115
- left: '16px',
116
- bottom:'16px'
117
- })
157
+ width: "400px",
158
+ height: "500px",
159
+ left: "16px",
160
+ bottom: "16px",
161
+ });
118
162
  const onPlayingChange = (isPlaying) => {
119
- console.log('播放状态改变:', isPlaying);
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 | - | 是 | 屏幕客户端 ID |
137
- | wsUrl | String | - | 是 | WebSocket 连接地址 |
178
+ | 属性 | 类型 | 默认值 | 必填 | 说明 |
179
+ | -------------- | ------ | ------ | ---- | ------------------ |
180
+ | screenClientId | String | - | 是 | 屏幕客户端 ID |
181
+ | wsUrl | String | - | 是 | WebSocket 连接地址 |
138
182
 
139
183
  #### Events
140
184
 
141
- | 事件名 | 说明 | 回调参数 |
142
- |--------|------|----------|
143
- | connected | WebSocket 连接成功 | - |
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,2 @@
1
+ declare const request: import('axios').AxiosInstance;
2
+ export default request;
@@ -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
- }>, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
14
- error: (...args: any[]) => void;
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-bf23f155],.fade-leave-active[data-v-bf23f155]{transition:opacity .5s ease,transform .5s ease}.fade-enter-from[data-v-bf23f155],.fade-leave-to[data-v-bf23f155]{opacity:0;transform:translateY(10px)}.virtual-human-container[data-v-bf23f155]{position:fixed;z-index:2147483647;overflow:visible}.video-wrapper[data-v-bf23f155]{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-bf23f155]:hover{border-color:#409eff}.virtual-human-container.is-dark .video-wrapper[data-v-bf23f155]{background:#1f2937;box-shadow:0 10px 25px #00000080}.persona-video[data-v-bf23f155]{width:100%;height:100%;object-fit:cover;transform-origin:center;transition:transform .1s ease-out}.resize-handle[data-v-bf23f155]{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-bf23f155]{opacity:1;pointer-events:auto}.resize-handle[data-v-bf23f155]:hover{background:#000000b3;border-color:#fff}.resize-handle.top-left[data-v-bf23f155]{top:10px;left:10px;cursor:nwse-resize}.resize-handle.top-right[data-v-bf23f155]{top:10px;right:10px;cursor:nesw-resize}.resize-handle.bottom-left[data-v-bf23f155]{bottom:10px;left:10px;cursor:nesw-resize}.resize-handle.bottom-right[data-v-bf23f155]{bottom:10px;right:10px;cursor:nwse-resize}.overlay[data-v-bf23f155]{position:absolute;top:1rem;right:1rem;z-index:10}.status-badge[data-v-bf23f155]{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-bf23f155]{background:#ef4444cc}.status-badge.playing[data-v-bf23f155]{background:#22c55ecc}.dot[data-v-bf23f155]{width:6px;height:6px;border-radius:50%;background-color:#fff}@keyframes pulse-bf23f155{0%,to{opacity:1}50%{opacity:.5}}.animate-pulse[data-v-bf23f155]{animation:pulse-bf23f155 2s cubic-bezier(.4,0,.6,1) infinite}
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}