virtual-human-cf 1.0.3 → 1.0.4

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/style.css CHANGED
@@ -1 +1 @@
1
- .fade-enter-active[data-v-54e42f84],.fade-leave-active[data-v-54e42f84]{transition:opacity .5s ease,transform .5s ease}.fade-enter-from[data-v-54e42f84],.fade-leave-to[data-v-54e42f84]{opacity:0;transform:translateY(10px)}.virtual-human-container[data-v-54e42f84]{position:fixed;left:16px;bottom:16px;width:400px;height:500px;z-index:2147483647;overflow:visible}.video-wrapper[data-v-54e42f84]{position:relative;width:400px;height:500px;border-radius:1rem;overflow:hidden;box-shadow:0 10px 25px #0000001a;background:#fff;transition:background-color .3s ease,box-shadow .3s ease}.virtual-human-container.is-dark .video-wrapper[data-v-54e42f84]{background:#1f2937;box-shadow:0 10px 25px #00000080}.persona-video[data-v-54e42f84]{width:100%;height:100%;object-fit:cover;transform-origin:center;transition:transform .1s ease-out}.resize-handle[data-v-54e42f84]{position:absolute;width:20px;height:20px;background:#00000080;border:2px solid rgba(255,255,255,.8);border-radius:4px;cursor:pointer;z-index:20;transition:background .2s,border-color .2s}.resize-handle[data-v-54e42f84]:hover{background:#000000b3;border-color:#fff}.resize-handle.top-left[data-v-54e42f84]{top:-10px;left:-10px;cursor:nwse-resize}.resize-handle.top-right[data-v-54e42f84]{top:-10px;right:-10px;cursor:nesw-resize}.resize-handle.bottom-left[data-v-54e42f84]{bottom:-10px;left:-10px;cursor:nesw-resize}.resize-handle.bottom-right[data-v-54e42f84]{bottom:-10px;right:-10px;cursor:nwse-resize}.overlay[data-v-54e42f84]{position:absolute;top:1rem;right:1rem;z-index:10}.status-badge[data-v-54e42f84]{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-54e42f84]{background:#ef4444cc}.status-badge.playing[data-v-54e42f84]{background:#22c55ecc}.dot[data-v-54e42f84]{width:6px;height:6px;border-radius:50%;background-color:#fff}@keyframes pulse-54e42f84{0%,to{opacity:1}50%{opacity:.5}}.animate-pulse[data-v-54e42f84]{animation:pulse-54e42f84 2s cubic-bezier(.4,0,.6,1) infinite}
1
+ .fade-enter-active[data-v-19d39d2e],.fade-leave-active[data-v-19d39d2e]{transition:opacity .5s ease,transform .5s ease}.fade-enter-from[data-v-19d39d2e],.fade-leave-to[data-v-19d39d2e]{opacity:0;transform:translateY(10px)}.virtual-human-container[data-v-19d39d2e]{position:fixed;left:16px;bottom:16px;width:400px;height:500px;z-index:2147483647;overflow:visible}.video-wrapper[data-v-19d39d2e]{position:relative;width:400px;height:500px;border-radius:1rem;overflow:hidden;box-shadow:0 10px 25px #0000001a;background:#fff;transition:background-color .3s ease,box-shadow .3s ease}.virtual-human-container.is-dark .video-wrapper[data-v-19d39d2e]{background:#1f2937;box-shadow:0 10px 25px #00000080}.persona-video[data-v-19d39d2e]{width:100%;height:100%;object-fit:cover;transform-origin:center;transition:transform .1s ease-out}.resize-handle[data-v-19d39d2e]{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;transition:opacity .3s ease,background .2s,border-color .2s}.video-wrapper:hover .resize-handle[data-v-19d39d2e]{opacity:1}.resize-handle[data-v-19d39d2e]:hover{background:#000000b3;border-color:#fff}.resize-handle.top-left[data-v-19d39d2e]{top:10px;left:10px;cursor:nwse-resize}.resize-handle.top-right[data-v-19d39d2e]{top:10px;right:10px;cursor:nesw-resize}.resize-handle.bottom-left[data-v-19d39d2e]{bottom:10px;left:10px;cursor:nesw-resize}.resize-handle.bottom-right[data-v-19d39d2e]{bottom:10px;right:10px;cursor:nwse-resize}.overlay[data-v-19d39d2e]{position:absolute;top:1rem;right:1rem;z-index:10}.status-badge[data-v-19d39d2e]{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-19d39d2e]{background:#ef4444cc}.status-badge.playing[data-v-19d39d2e]{background:#22c55ecc}.dot[data-v-19d39d2e]{width:6px;height:6px;border-radius:50%;background-color:#fff}@keyframes pulse-19d39d2e{0%,to{opacity:1}50%{opacity:.5}}.animate-pulse[data-v-19d39d2e]{animation:pulse-19d39d2e 2s cubic-bezier(.4,0,.6,1) infinite}
@@ -70,7 +70,7 @@ const j = ["src", "muted"], G = { class: "overlay" }, K = {
70
70
  }
71
71
  }, c = (r) => {
72
72
  const { type: e, action: a } = r;
73
- e === "control" && (a === "play" ? (s("update:isPlaying", !0), s("update:visible", !0)) : a === "pause" ? s("update:isPlaying", !1) : a === "stop" && (s("update:isPlaying", !1), s("update:visible", !1), l.value && (l.value.currentTime = 0)));
73
+ e === "control" && (a === "play" || a === "resume" ? (s("update:isPlaying", !0), s("update:visible", !0)) : a === "pause" ? s("update:isPlaying", !1) : a === "stop" && (s("update:isPlaying", !1), s("update:visible", !1), l.value && (l.value.currentTime = 0)));
74
74
  };
75
75
  z(() => t.screenClientId, () => {
76
76
  t.screenClientId && t.wsUrl && u();
@@ -170,7 +170,7 @@ const j = ["src", "muted"], G = { class: "overlay" }, K = {
170
170
  for (const [s, l] of P)
171
171
  t[s] = l;
172
172
  return t;
173
- }, ee = /* @__PURE__ */ _(Z, [["__scopeId", "data-v-54e42f84"]]), te = /* @__PURE__ */ T({
173
+ }, ee = /* @__PURE__ */ _(Z, [["__scopeId", "data-v-19d39d2e"]]), te = /* @__PURE__ */ T({
174
174
  __name: "VirtualHumanEventAdapter",
175
175
  props: {
176
176
  // 屏幕客户端ID
@@ -212,6 +212,7 @@ const j = ["src", "muted"], G = { class: "overlay" }, K = {
212
212
  if (n)
213
213
  switch (o) {
214
214
  case "play":
215
+ case "resume":
215
216
  n.state === "suspended" && n.resume();
216
217
  break;
217
218
  case "pause":
@@ -1 +1 @@
1
- (function(p,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],e):(p=typeof globalThis<"u"?globalThis:p||self,e(p.VirtualHumanCf={},p.Vue))})(this,function(p,e){"use strict";const z=["src","muted"],N={class:"overlay"},T={key:0,class:"status-badge paused"},R={key:1,class:"status-badge playing"},I=((c,V)=>{const n=c.__vccOpts||c;for(const[s,r]of V)n[s]=r;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(c,{emit:V}){const n=c,s=V,r=e.ref(null),v=e.ref(null),o=e.ref(null),g=e.ref(!1),E=e.ref(1),S=e.ref(!1),h=e.ref(null),b=e.ref(0),H=e.ref(0),l=e.ref(1),d=()=>{if(o.value&&o.value.close(),!(!n.wsUrl||!n.screenClientId))try{const i=new URL(n.wsUrl);i.searchParams.append("sessionId",n.screenClientId+"-persona"),o.value=new WebSocket(i.toString()),o.value.onopen=()=>{g.value=!0,console.log(`[VirtualHumanPersona] Connected to ${n.wsUrl} for session ${n.screenClientId}-persona`)},o.value.onmessage=t=>{try{const a=JSON.parse(t.data);u(a)}catch(a){console.error("[VirtualHumanPersona] Failed to parse message:",t.data,a)}},o.value.onerror=t=>{console.error("[VirtualHumanPersona] WebSocket error:",t)},o.value.onclose=()=>{g.value=!1,console.log("[VirtualHumanPersona] WebSocket disconnected")}}catch(i){console.error("[VirtualHumanPersona] Failed to initialize WebSocket:",i)}},u=i=>{const{type:t,action:a}=i;t==="control"&&(a==="play"?(s("update:isPlaying",!0),s("update:visible",!0)):a==="pause"?s("update:isPlaying",!1):a==="stop"&&(s("update:isPlaying",!1),s("update:visible",!1),r.value&&(r.value.currentTime=0)))};e.watch(()=>n.screenClientId,()=>{n.screenClientId&&n.wsUrl&&d()}),e.watch(()=>n.wsUrl,()=>{n.screenClientId&&n.wsUrl&&d()}),e.watch(()=>n.isPlaying,i=>{r.value&&(i?r.value.play().catch(t=>console.error("Video play failed:",t)):r.value.pause())});const k=()=>{n.isPlaying||s("update:isPlaying",!0)},y=()=>{n.isPlaying&&s("update:isPlaying",!1)},P=()=>{s("update:isPlaying",!1),s("ended")},m=(i,t)=>{S.value=!0,h.value=i,l.value=E.value;const a="clientX"in t?t.clientX:t.touches[0].clientX,C="clientY"in t?t.clientY:t.touches[0].clientY;b.value=a,H.value=C,document.addEventListener("mousemove",w),document.addEventListener("mouseup",f),document.addEventListener("touchmove",w),document.addEventListener("touchend",f)},w=i=>{if(!S.value||!v.value)return;const t="clientX"in i?i.clientX:i.touches[0].clientX,a="clientY"in i?i.clientY:i.touches[0].clientY,C=t-b.value,U=a-H.value,x=v.value.getBoundingClientRect(),W=.5,X=2;let B=l.value;const A=Math.min(x.width,x.height);h.value==="bottom-right"?B=l.value+(C+U)/A:h.value==="bottom-left"?B=l.value+(-C+U)/A:h.value==="top-right"?B=l.value+(C-U)/A:h.value==="top-left"&&(B=l.value+(-C-U)/A),E.value=Math.max(W,Math.min(X,B))},f=()=>{S.value=!1,h.value=null,document.removeEventListener("mousemove",w),document.removeEventListener("mouseup",f),document.removeEventListener("touchmove",w),document.removeEventListener("touchend",f)};return e.onMounted(()=>{n.isPlaying&&r.value&&r.value.play().catch(i=>console.error("Video play failed:",i)),n.screenClientId&&n.wsUrl&&d()}),e.onUnmounted(()=>{o.value&&o.value.close()}),(i,t)=>(e.openBlock(),e.createBlock(e.Transition,{name:"fade"},{default:e.withCtx(()=>[c.visible?(e.openBlock(),e.createElementBlock("div",{key:0,class:e.normalizeClass(["virtual-human-container",{"is-dark":c.isDark}])},[e.createElementVNode("div",{class:"video-wrapper",ref_key:"wrapperRef",ref:v,style:e.normalizeStyle({transform:`scale(${E.value})`,transformOrigin:"left bottom"})},[e.createElementVNode("video",{ref_key:"videoRef",ref:r,src:c.videoSrc,class:"persona-video",muted:c.muted,playsinline:"",loop:"",onPlay:k,onPause:y,onEnded:P},null,40,z),c.visible?(e.openBlock(),e.createElementBlock("div",{key:0,class:"resize-handle top-left",onMousedown:t[0]||(t[0]=a=>m("top-left",a)),onTouchstart:t[1]||(t[1]=a=>m("top-left",a))},null,32)):e.createCommentVNode("",!0),c.visible?(e.openBlock(),e.createElementBlock("div",{key:1,class:"resize-handle top-right",onMousedown:t[2]||(t[2]=a=>m("top-right",a)),onTouchstart:t[3]||(t[3]=a=>m("top-right",a))},null,32)):e.createCommentVNode("",!0),c.visible?(e.openBlock(),e.createElementBlock("div",{key:2,class:"resize-handle bottom-left",onMousedown:t[4]||(t[4]=a=>m("bottom-left",a)),onTouchstart:t[5]||(t[5]=a=>m("bottom-left",a))},null,32)):e.createCommentVNode("",!0),c.visible?(e.openBlock(),e.createElementBlock("div",{key:3,class:"resize-handle bottom-right",onMousedown:t[6]||(t[6]=a=>m("bottom-right",a)),onTouchstart:t[7]||(t[7]=a=>m("bottom-right",a))},null,32)):e.createCommentVNode("",!0),e.createElementVNode("div",N,[c.isPlaying?(e.openBlock(),e.createElementBlock("div",R,[...t[9]||(t[9]=[e.createElementVNode("span",{class:"dot animate-pulse"},null,-1),e.createTextVNode(" 播放中 ",-1)])])):(e.openBlock(),e.createElementBlock("div",T,[...t[8]||(t[8]=[e.createElementVNode("span",{class:"dot"},null,-1),e.createTextVNode(" 暂停中 ",-1)])]))])],4)],2)):e.createCommentVNode("",!0)]),_:1}))}}),[["__scopeId","data-v-54e42f84"]]),M=e.defineComponent({__name:"VirtualHumanEventAdapter",props:{screenClientId:{type:String,required:!0},wsUrl:{type:String,required:!0}},emits:["highlight","showDialog","end","pause","connected","error"],setup(c,{emit:V}){const n=c,s=V,r=e.ref(null),v=e.ref(!1);let o=null,g=0;const E=()=>{o||(o=new(window.AudioContext||window.webkitAudioContext)({sampleRate:24e3})),o.state==="suspended"&&o.resume()},S=l=>{if(E(),!!o)try{const d=window.atob(l),u=d.length,k=new Uint8Array(u);for(let f=0;f<u;f++)k[f]=d.charCodeAt(f);const y=new Int16Array(k.buffer),P=new Float32Array(y.length);for(let f=0;f<y.length;f++)P[f]=y[f]/32768;const m=o.createBuffer(1,P.length,24e3);m.getChannelData(0).set(P);const w=o.createBufferSource();w.buffer=m,w.connect(o.destination),g<o.currentTime&&(g=o.currentTime),w.start(g),g+=m.duration}catch(d){console.error("[VirtualHumanEventAdapter] Failed to decode and play audio:",d)}},h=l=>{if(o)switch(l){case"play":o.state==="suspended"&&o.resume();break;case"pause":o.state==="running"&&o.suspend();break;case"stop":o.close(),o=null,g=0;break;default:console.warn(`[VirtualHumanEventAdapter] Unknown control action: ${l}`)}},b=()=>{r.value&&r.value.close();try{const l=new URL(n.wsUrl);l.searchParams.append("sessionId",n.screenClientId+"-event"),r.value=new WebSocket(l.toString()),r.value.onopen=()=>{v.value=!0,s("connected"),console.log(`[VirtualHumanEventAdapter] Connected to ${n.wsUrl} for session ${n.screenClientId}-event`)},r.value.onmessage=d=>{try{const u=JSON.parse(d.data);H(u)}catch(u){console.error("[VirtualHumanEventAdapter] Failed to parse message:",d.data,u)}},r.value.onerror=d=>{console.error("[VirtualHumanEventAdapter] WebSocket error:",d),s("error",d)},r.value.onclose=()=>{v.value=!1,console.log("[VirtualHumanEventAdapter] WebSocket disconnected")}}catch(l){console.error("[VirtualHumanEventAdapter] Failed to initialize WebSocket:",l),s("error",l)}},H=l=>{const{type:d,payload:u,action:k}=l;switch(console.log("msgmsg",l),d){case"audio":const y=(u==null?void 0:u.data)||l.data;y&&S(y);break;case"dialog_event":l.event&&s(l.event,l.params);break;case"control":k&&h(k);break;case"highlight":s("highlight",u);break;case"showDialog":s("showDialog",u);break;case"end":s("end",u);break;case"pause":s("pause",u);break;default:console.warn(`[VirtualHumanEventAdapter] Unknown message type: ${d}`)}};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(()=>{r.value&&r.value.close(),o&&o.close()}),(l,d)=>e.renderSlot(l.$slots,"default")}}),L={install:c=>{c.component("VirtualHumanPersona",I),c.component("VirtualHumanEventAdapter",M)}};p.VirtualHumanEventAdapter=M,p.VirtualHumanPersona=I,p.default=L,Object.defineProperties(p,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
1
+ (function(p,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],e):(p=typeof globalThis<"u"?globalThis:p||self,e(p.VirtualHumanCf={},p.Vue))})(this,function(p,e){"use strict";const z=["src","muted"],N={class:"overlay"},T={key:0,class:"status-badge paused"},R={key:1,class:"status-badge playing"},I=((c,V)=>{const n=c.__vccOpts||c;for(const[s,r]of V)n[s]=r;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(c,{emit:V}){const n=c,s=V,r=e.ref(null),v=e.ref(null),o=e.ref(null),g=e.ref(!1),E=e.ref(1),S=e.ref(!1),h=e.ref(null),b=e.ref(0),H=e.ref(0),l=e.ref(1),d=()=>{if(o.value&&o.value.close(),!(!n.wsUrl||!n.screenClientId))try{const i=new URL(n.wsUrl);i.searchParams.append("sessionId",n.screenClientId+"-persona"),o.value=new WebSocket(i.toString()),o.value.onopen=()=>{g.value=!0,console.log(`[VirtualHumanPersona] Connected to ${n.wsUrl} for session ${n.screenClientId}-persona`)},o.value.onmessage=t=>{try{const a=JSON.parse(t.data);u(a)}catch(a){console.error("[VirtualHumanPersona] Failed to parse message:",t.data,a)}},o.value.onerror=t=>{console.error("[VirtualHumanPersona] WebSocket error:",t)},o.value.onclose=()=>{g.value=!1,console.log("[VirtualHumanPersona] WebSocket disconnected")}}catch(i){console.error("[VirtualHumanPersona] Failed to initialize WebSocket:",i)}},u=i=>{const{type:t,action:a}=i;t==="control"&&(a==="play"||a==="resume"?(s("update:isPlaying",!0),s("update:visible",!0)):a==="pause"?s("update:isPlaying",!1):a==="stop"&&(s("update:isPlaying",!1),s("update:visible",!1),r.value&&(r.value.currentTime=0)))};e.watch(()=>n.screenClientId,()=>{n.screenClientId&&n.wsUrl&&d()}),e.watch(()=>n.wsUrl,()=>{n.screenClientId&&n.wsUrl&&d()}),e.watch(()=>n.isPlaying,i=>{r.value&&(i?r.value.play().catch(t=>console.error("Video play failed:",t)):r.value.pause())});const k=()=>{n.isPlaying||s("update:isPlaying",!0)},y=()=>{n.isPlaying&&s("update:isPlaying",!1)},P=()=>{s("update:isPlaying",!1),s("ended")},m=(i,t)=>{S.value=!0,h.value=i,l.value=E.value;const a="clientX"in t?t.clientX:t.touches[0].clientX,C="clientY"in t?t.clientY:t.touches[0].clientY;b.value=a,H.value=C,document.addEventListener("mousemove",w),document.addEventListener("mouseup",f),document.addEventListener("touchmove",w),document.addEventListener("touchend",f)},w=i=>{if(!S.value||!v.value)return;const t="clientX"in i?i.clientX:i.touches[0].clientX,a="clientY"in i?i.clientY:i.touches[0].clientY,C=t-b.value,U=a-H.value,x=v.value.getBoundingClientRect(),W=.5,X=2;let B=l.value;const A=Math.min(x.width,x.height);h.value==="bottom-right"?B=l.value+(C+U)/A:h.value==="bottom-left"?B=l.value+(-C+U)/A:h.value==="top-right"?B=l.value+(C-U)/A:h.value==="top-left"&&(B=l.value+(-C-U)/A),E.value=Math.max(W,Math.min(X,B))},f=()=>{S.value=!1,h.value=null,document.removeEventListener("mousemove",w),document.removeEventListener("mouseup",f),document.removeEventListener("touchmove",w),document.removeEventListener("touchend",f)};return e.onMounted(()=>{n.isPlaying&&r.value&&r.value.play().catch(i=>console.error("Video play failed:",i)),n.screenClientId&&n.wsUrl&&d()}),e.onUnmounted(()=>{o.value&&o.value.close()}),(i,t)=>(e.openBlock(),e.createBlock(e.Transition,{name:"fade"},{default:e.withCtx(()=>[c.visible?(e.openBlock(),e.createElementBlock("div",{key:0,class:e.normalizeClass(["virtual-human-container",{"is-dark":c.isDark}])},[e.createElementVNode("div",{class:"video-wrapper",ref_key:"wrapperRef",ref:v,style:e.normalizeStyle({transform:`scale(${E.value})`,transformOrigin:"left bottom"})},[e.createElementVNode("video",{ref_key:"videoRef",ref:r,src:c.videoSrc,class:"persona-video",muted:c.muted,playsinline:"",loop:"",onPlay:k,onPause:y,onEnded:P},null,40,z),c.visible?(e.openBlock(),e.createElementBlock("div",{key:0,class:"resize-handle top-left",onMousedown:t[0]||(t[0]=a=>m("top-left",a)),onTouchstart:t[1]||(t[1]=a=>m("top-left",a))},null,32)):e.createCommentVNode("",!0),c.visible?(e.openBlock(),e.createElementBlock("div",{key:1,class:"resize-handle top-right",onMousedown:t[2]||(t[2]=a=>m("top-right",a)),onTouchstart:t[3]||(t[3]=a=>m("top-right",a))},null,32)):e.createCommentVNode("",!0),c.visible?(e.openBlock(),e.createElementBlock("div",{key:2,class:"resize-handle bottom-left",onMousedown:t[4]||(t[4]=a=>m("bottom-left",a)),onTouchstart:t[5]||(t[5]=a=>m("bottom-left",a))},null,32)):e.createCommentVNode("",!0),c.visible?(e.openBlock(),e.createElementBlock("div",{key:3,class:"resize-handle bottom-right",onMousedown:t[6]||(t[6]=a=>m("bottom-right",a)),onTouchstart:t[7]||(t[7]=a=>m("bottom-right",a))},null,32)):e.createCommentVNode("",!0),e.createElementVNode("div",N,[c.isPlaying?(e.openBlock(),e.createElementBlock("div",R,[...t[9]||(t[9]=[e.createElementVNode("span",{class:"dot animate-pulse"},null,-1),e.createTextVNode(" 播放中 ",-1)])])):(e.openBlock(),e.createElementBlock("div",T,[...t[8]||(t[8]=[e.createElementVNode("span",{class:"dot"},null,-1),e.createTextVNode(" 暂停中 ",-1)])]))])],4)],2)):e.createCommentVNode("",!0)]),_:1}))}}),[["__scopeId","data-v-19d39d2e"]]),M=e.defineComponent({__name:"VirtualHumanEventAdapter",props:{screenClientId:{type:String,required:!0},wsUrl:{type:String,required:!0}},emits:["highlight","showDialog","end","pause","connected","error"],setup(c,{emit:V}){const n=c,s=V,r=e.ref(null),v=e.ref(!1);let o=null,g=0;const E=()=>{o||(o=new(window.AudioContext||window.webkitAudioContext)({sampleRate:24e3})),o.state==="suspended"&&o.resume()},S=l=>{if(E(),!!o)try{const d=window.atob(l),u=d.length,k=new Uint8Array(u);for(let f=0;f<u;f++)k[f]=d.charCodeAt(f);const y=new Int16Array(k.buffer),P=new Float32Array(y.length);for(let f=0;f<y.length;f++)P[f]=y[f]/32768;const m=o.createBuffer(1,P.length,24e3);m.getChannelData(0).set(P);const w=o.createBufferSource();w.buffer=m,w.connect(o.destination),g<o.currentTime&&(g=o.currentTime),w.start(g),g+=m.duration}catch(d){console.error("[VirtualHumanEventAdapter] Failed to decode and play audio:",d)}},h=l=>{if(o)switch(l){case"play":case"resume":o.state==="suspended"&&o.resume();break;case"pause":o.state==="running"&&o.suspend();break;case"stop":o.close(),o=null,g=0;break;default:console.warn(`[VirtualHumanEventAdapter] Unknown control action: ${l}`)}},b=()=>{r.value&&r.value.close();try{const l=new URL(n.wsUrl);l.searchParams.append("sessionId",n.screenClientId+"-event"),r.value=new WebSocket(l.toString()),r.value.onopen=()=>{v.value=!0,s("connected"),console.log(`[VirtualHumanEventAdapter] Connected to ${n.wsUrl} for session ${n.screenClientId}-event`)},r.value.onmessage=d=>{try{const u=JSON.parse(d.data);H(u)}catch(u){console.error("[VirtualHumanEventAdapter] Failed to parse message:",d.data,u)}},r.value.onerror=d=>{console.error("[VirtualHumanEventAdapter] WebSocket error:",d),s("error",d)},r.value.onclose=()=>{v.value=!1,console.log("[VirtualHumanEventAdapter] WebSocket disconnected")}}catch(l){console.error("[VirtualHumanEventAdapter] Failed to initialize WebSocket:",l),s("error",l)}},H=l=>{const{type:d,payload:u,action:k}=l;switch(console.log("msgmsg",l),d){case"audio":const y=(u==null?void 0:u.data)||l.data;y&&S(y);break;case"dialog_event":l.event&&s(l.event,l.params);break;case"control":k&&h(k);break;case"highlight":s("highlight",u);break;case"showDialog":s("showDialog",u);break;case"end":s("end",u);break;case"pause":s("pause",u);break;default:console.warn(`[VirtualHumanEventAdapter] Unknown message type: ${d}`)}};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(()=>{r.value&&r.value.close(),o&&o.close()}),(l,d)=>e.renderSlot(l.$slots,"default")}}),L={install:c=>{c.component("VirtualHumanPersona",I),c.component("VirtualHumanEventAdapter",M)}};p.VirtualHumanEventAdapter=M,p.VirtualHumanPersona=I,p.default=L,Object.defineProperties(p,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "virtual-human-cf",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "Vue3 Digital Human Component Package by cf ",
5
5
  "main": "dist/virtual-human-cf.umd.js",
6
6
  "module": "dist/virtual-human-cf.es.js",
@@ -79,6 +79,7 @@ const handleControlMessage = (action: string) => {
79
79
  if (!audioContext) return;
80
80
  switch (action) {
81
81
  case 'play':
82
+ case 'resume':
82
83
  if (audioContext.state === 'suspended') {
83
84
  audioContext.resume();
84
85
  }
@@ -163,7 +163,7 @@ const connectWebSocket = () => {
163
163
  const handleMessage = (msg: any) => {
164
164
  const { type, action } = msg;
165
165
  if (type === 'control') {
166
- if (action === 'play') {
166
+ if (action === 'play' || action === 'resume') {
167
167
  emit('update:isPlaying', true);
168
168
  emit('update:visible', true);
169
169
  } else if (action === 'pause') {
@@ -345,7 +345,12 @@ onUnmounted(() => {
345
345
  border-radius: 4px;
346
346
  cursor: pointer;
347
347
  z-index: 20;
348
- transition: background 0.2s, border-color 0.2s;
348
+ opacity: 0;
349
+ transition: opacity 0.3s ease, background 0.2s, border-color 0.2s;
350
+ }
351
+
352
+ .video-wrapper:hover .resize-handle {
353
+ opacity: 1;
349
354
  }
350
355
 
351
356
  .resize-handle:hover {
@@ -354,26 +359,26 @@ onUnmounted(() => {
354
359
  }
355
360
 
356
361
  .resize-handle.top-left {
357
- top: -10px;
358
- left: -10px;
362
+ top: 10px;
363
+ left: 10px;
359
364
  cursor: nwse-resize;
360
365
  }
361
366
 
362
367
  .resize-handle.top-right {
363
- top: -10px;
364
- right: -10px;
368
+ top: 10px;
369
+ right: 10px;
365
370
  cursor: nesw-resize;
366
371
  }
367
372
 
368
373
  .resize-handle.bottom-left {
369
- bottom: -10px;
370
- left: -10px;
374
+ bottom: 10px;
375
+ left: 10px;
371
376
  cursor: nesw-resize;
372
377
  }
373
378
 
374
379
  .resize-handle.bottom-right {
375
- bottom: -10px;
376
- right: -10px;
380
+ bottom: 10px;
381
+ right: 10px;
377
382
  cursor: nwse-resize;
378
383
  }
379
384