ruiyun-human 1.0.13 → 1.0.15

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.
@@ -393,15 +393,90 @@ const TTS_MAX_RETRIES = 5;
393
393
  const _sfc_main = {
394
394
  __name: "index",
395
395
  props: {
396
- humans: {
397
- type: Array,
398
- default: () => []
396
+ human: {
397
+ type: Object,
398
+ default: null
399
399
  }
400
400
  },
401
401
  emits: ["loaded", "changed", "paused", "resumed", "audio-ready"],
402
402
  setup(__props, { expose: __expose, emit: __emit }) {
403
- const TTS_URL = "http://localhost:6039";
404
- const ASR_URL = "http://localhost:6039";
403
+ const TTS_URL = "/api";
404
+ const ASR_URL = "/api";
405
+ const szrUrl = "http://116.198.239.205:8443/szrimage/";
406
+ const HUMAN_PRESETS = {
407
+ 1: {
408
+ humanId: 1,
409
+ title: "西装动漫男",
410
+ // TODO: 替换为真实资源
411
+ folder: `${szrUrl}/xiangyu-green-suit`,
412
+ folder_mobile: `${szrUrl}/xiangyu-green-suit-header`,
413
+ standby: { interval: 100, standbyNum: 11 },
414
+ speak: { interval: 30, speakNum: 0 },
415
+ humanType: 1,
416
+ timbre: 47
417
+ },
418
+ 2: {
419
+ humanId: 2,
420
+ title: "西装动漫女",
421
+ folder: `${szrUrl}/anime-woman`,
422
+ folder_mobile: `${szrUrl}/anime-woman-header`,
423
+ standby: { interval: 100, standbyNum: 1 },
424
+ speak: { interval: 30, speakNum: 75 },
425
+ humanType: 1,
426
+ timbre: 45
427
+ },
428
+ 3: {
429
+ humanId: 3,
430
+ title: "真人形象男",
431
+ folder: `${szrUrl}/real-man`,
432
+ folder_mobile: `${szrUrl}/real-man-header`,
433
+ standby: { interval: 100, standbyNum: 1 },
434
+ speak: { interval: 30, speakNum: 139 },
435
+ humanType: 1,
436
+ timbre: 47
437
+ },
438
+ 4: {
439
+ humanId: 4,
440
+ title: "真人形象女",
441
+ folder: `${szrUrl}/real-woman`,
442
+ folder_mobile: `${szrUrl}/real-woman-header`,
443
+ standby: { interval: 100, standbyNum: 2 },
444
+ speak: { interval: 40, speakNum: 139 },
445
+ humanType: 1,
446
+ timbre: 34
447
+ },
448
+ 5: {
449
+ humanId: 5,
450
+ title: "Q版形象",
451
+ folder: `${szrUrl}/xiangyu-q`,
452
+ folder_mobile: `${szrUrl}/xiangyu-q-header`,
453
+ standby: { interval: 100, standbyNum: 28 },
454
+ speak: { interval: 30, speakNum: 118 },
455
+ humanType: 1,
456
+ timbre: 47
457
+ }
458
+ };
459
+ const isMobile = () => {
460
+ if (typeof navigator === "undefined") return false;
461
+ return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|HarmonyOS/i.test(navigator.userAgent);
462
+ };
463
+ const resolveFolder = (human) => {
464
+ const finalType = human.humanType || (isMobile() ? 2 : 1);
465
+ if (finalType === 2 && human.folder_mobile) return human.folder_mobile;
466
+ return human.folder;
467
+ };
468
+ const resolveHuman = (input) => {
469
+ if (input == null) return null;
470
+ const humanId = typeof input === "number" ? input : input.humanId;
471
+ const preset = HUMAN_PRESETS[humanId];
472
+ if (!preset) {
473
+ console.error("[DigitalHuman] 未找到 humanId=", humanId, "的预设形象,可用 id:", Object.keys(HUMAN_PRESETS));
474
+ return null;
475
+ }
476
+ const merged = { ...preset, ...typeof input === "object" ? input : {} };
477
+ merged.folder = resolveFolder(merged);
478
+ return merged;
479
+ };
405
480
  const props = __props;
406
481
  const emit = __emit;
407
482
  const containerRef = vue.ref(null);
@@ -423,27 +498,38 @@ const _sfc_main = {
423
498
  standbyNum: currentHuman.value.standby.standbyNum,
424
499
  speakNum: currentHuman.value.speak.speakNum
425
500
  };
426
- for (let i = 1; i <= standbyNum; i++) {
501
+ const makeImage = (url) => {
427
502
  const image = new Image();
428
- image.src = encodeURI(`${folder}/standby/standby (${i}).png`);
429
- frames.value.standby.push(image);
503
+ image.src = encodeURI(url);
504
+ image.onload = () => {
505
+ image.__broken = false;
506
+ };
507
+ image.onerror = () => {
508
+ image.__broken = true;
509
+ console.warn("[DigitalHuman] 帧加载失败:", url);
510
+ };
511
+ return image;
512
+ };
513
+ for (let i = 1; i <= standbyNum; i++) {
514
+ frames.value.standby.push(makeImage(`${folder}/standby/standby (${i}).png`));
515
+ }
516
+ if (speakNum <= 0) {
517
+ console.warn("[DigitalHuman] 当前形象 speakNum=0,说话动画暂用待机帧替代");
518
+ frames.value.speakStart = [...frames.value.standby];
519
+ frames.value.speakLoop = [...frames.value.standby];
520
+ frames.value.speakEnd = [...frames.value.standby];
521
+ return;
430
522
  }
431
523
  const startEnd = Math.floor(speakNum * 0.6);
432
524
  const loopEnd = Math.floor(speakNum * 0.9);
433
525
  for (let i = 1; i <= startEnd; i++) {
434
- const image = new Image();
435
- image.src = encodeURI(`${folder}/speak/speak (${i}).png`);
436
- frames.value.speakStart.push(image);
526
+ frames.value.speakStart.push(makeImage(`${folder}/speak/speak (${i}).png`));
437
527
  }
438
528
  for (let i = startEnd; i <= loopEnd; i++) {
439
- const image = new Image();
440
- image.src = encodeURI(`${folder}/speak/speak (${i}).png`);
441
- frames.value.speakLoop.push(image);
529
+ frames.value.speakLoop.push(makeImage(`${folder}/speak/speak (${i}).png`));
442
530
  }
443
531
  for (let i = loopEnd; i <= speakNum; i++) {
444
- const image = new Image();
445
- image.src = encodeURI(`${folder}/speak/speak (${i}).png`);
446
- frames.value.speakEnd.push(image);
532
+ frames.value.speakEnd.push(makeImage(`${folder}/speak/speak (${i}).png`));
447
533
  }
448
534
  };
449
535
  const draw = (image) => {
@@ -604,20 +690,39 @@ const _sfc_main = {
604
690
  };
605
691
  allFrames.forEach((img) => {
606
692
  if (img.complete) {
693
+ if (!img.naturalWidth) img.__broken = true;
607
694
  checkLoaded();
608
695
  } else {
609
- img.onload = checkLoaded;
610
- img.onerror = checkLoaded;
696
+ img.onload = () => {
697
+ img.__broken = false;
698
+ checkLoaded();
699
+ };
700
+ img.onerror = () => {
701
+ img.__broken = true;
702
+ checkLoaded();
703
+ };
611
704
  }
612
705
  });
613
706
  };
614
707
  const init = () => {
615
708
  vue.nextTick(() => {
709
+ var _a, _b;
616
710
  if (!containerRef.value || !canvasRef.value) return;
617
- if (!props.humans || props.humans.length === 0) return;
618
- if (!currentHuman.value) {
619
- currentHuman.value = props.humans[0];
711
+ const rawInput = props.human;
712
+ if (!rawInput) return;
713
+ const human = resolveHuman(rawInput);
714
+ if (!human) return;
715
+ const prevType = (_a = currentHuman.value) == null ? void 0 : _a.humanType;
716
+ if (((_b = currentHuman.value) == null ? void 0 : _b.humanId) === human.humanId && prevType === human.humanType) {
717
+ Object.assign(currentHuman.value, human);
718
+ return;
620
719
  }
720
+ abortTTS();
721
+ stop();
722
+ timestamp.value = null;
723
+ frameIndex.value = 1;
724
+ currentHuman.value = human;
725
+ console.log("init", currentHuman.value);
621
726
  const canvas = canvasRef.value;
622
727
  const dpr = window.devicePixelRatio || 1;
623
728
  const width = containerRef.value.clientWidth;
@@ -694,9 +799,11 @@ const _sfc_main = {
694
799
  return pcmToWavBlob(buf);
695
800
  };
696
801
  const requestTTSAudio = async (text, signal) => {
802
+ var _a, _b;
697
803
  let lastError = null;
698
804
  for (let attempt = 1; attempt <= TTS_MAX_RETRIES; attempt++) {
699
805
  if (signal == null ? void 0 : signal.aborted) throw new DOMException("Aborted", "AbortError");
806
+ console.log("[TTS] 提交合成请求1111:", ((_a = currentHuman.value) == null ? void 0 : _a.timbre) ?? 1);
700
807
  const res = await fetch(`${TTS_URL}/web/voice/jd/text-to-speech`, {
701
808
  method: "POST",
702
809
  headers: {
@@ -704,7 +811,7 @@ const _sfc_main = {
704
811
  clientid: VOICE_CLIENT_ID,
705
812
  "tenant-id": VOICE_TENANT_ID
706
813
  },
707
- body: JSON.stringify({ text, user: TTS_USER, timbre: 47 }),
814
+ body: JSON.stringify({ text, user: TTS_USER, timbre: ((_b = currentHuman.value) == null ? void 0 : _b.timbre) ?? 1 }),
708
815
  signal
709
816
  });
710
817
  if (!res.ok) {
@@ -775,8 +882,12 @@ const _sfc_main = {
775
882
  }
776
883
  };
777
884
  const playTTS = async (text) => {
778
- var _a;
779
- if (!text || !((_a = currentHuman.value) == null ? void 0 : _a.isMuted)) return;
885
+ if (!text) return;
886
+ const latest = props.human ? resolveHuman(props.human) : null;
887
+ if (latest) {
888
+ if (!latest.isMuted) return;
889
+ Object.assign(currentHuman.value || {}, latest);
890
+ }
780
891
  abortTTS();
781
892
  ttsAbortController = new AbortController();
782
893
  const { signal } = ttsAbortController;
@@ -785,7 +896,7 @@ const _sfc_main = {
785
896
  try {
786
897
  const cleanText = text.replace(/```[\s\S]*?```/g, "").replace(/`[^`]+`/g, "").replace(/[#*_~]/g, "").replace(/\n+/g, ",").replace(/\s+/g, " ").replace(/[,。!?]{2,}/g, ",").trim();
787
898
  if (!cleanText) return;
788
- console.log("[TTS] 提交合成请求:", { text: cleanText, length: cleanText.length });
899
+ console.log("[TTS] 提交合成请求:", { human: currentHuman.value, text: cleanText, length: cleanText.length });
789
900
  const audioBlob = await requestTTSAudio(cleanText, signal);
790
901
  if (signal.aborted || currentTtsRequestId.value !== requestId) return;
791
902
  if (!audioBlob || audioBlob.size === 0) {
@@ -865,6 +976,27 @@ const _sfc_main = {
865
976
  });
866
977
  }
867
978
  };
979
+ vue.watch(
980
+ () => [props.human],
981
+ () => {
982
+ init();
983
+ },
984
+ { deep: true }
985
+ );
986
+ const switchHuman = (humanId) => {
987
+ const next = resolveHuman(humanId);
988
+ if (!next) return;
989
+ abortTTS();
990
+ stop();
991
+ timestamp.value = null;
992
+ frameIndex.value = 1;
993
+ currentHuman.value = next;
994
+ loadFrames();
995
+ waitFramesLoaded(() => {
996
+ draw(frames.value.standby[0]);
997
+ emit("changed", currentHuman.value);
998
+ });
999
+ };
868
1000
  __expose({
869
1001
  standby,
870
1002
  speak,
@@ -873,14 +1005,11 @@ const _sfc_main = {
873
1005
  resume,
874
1006
  playTTS,
875
1007
  startRecord,
876
- stopRecord
1008
+ stopRecord,
1009
+ switchHuman
877
1010
  });
878
- vue.watch(() => props.humans, (val) => {
879
- if (val && val.length > 0 && !currentHuman.value) {
880
- init();
881
- }
882
- }, { deep: true });
883
1011
  vue.onMounted(() => {
1012
+ console.log("onMounted", props.human);
884
1013
  initRecorder();
885
1014
  init();
886
1015
  });
@@ -905,7 +1034,7 @@ const _sfc_main = {
905
1034
  };
906
1035
  }
907
1036
  };
908
- const DigitalHuman = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-9379171c"]]);
1037
+ const DigitalHuman = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-ab1e5de1"]]);
909
1038
  DigitalHuman.install = (app) => app.component("DigitalHuman", DigitalHuman);
910
1039
  const components = [DemoButton, DemoInput, DigitalHuman];
911
1040
  const install = (app) => {
@@ -391,15 +391,90 @@ const TTS_MAX_RETRIES = 5;
391
391
  const _sfc_main = {
392
392
  __name: "index",
393
393
  props: {
394
- humans: {
395
- type: Array,
396
- default: () => []
394
+ human: {
395
+ type: Object,
396
+ default: null
397
397
  }
398
398
  },
399
399
  emits: ["loaded", "changed", "paused", "resumed", "audio-ready"],
400
400
  setup(__props, { expose: __expose, emit: __emit }) {
401
- const TTS_URL = "http://localhost:6039";
402
- const ASR_URL = "http://localhost:6039";
401
+ const TTS_URL = "/api";
402
+ const ASR_URL = "/api";
403
+ const szrUrl = "http://116.198.239.205:8443/szrimage/";
404
+ const HUMAN_PRESETS = {
405
+ 1: {
406
+ humanId: 1,
407
+ title: "西装动漫男",
408
+ // TODO: 替换为真实资源
409
+ folder: `${szrUrl}/xiangyu-green-suit`,
410
+ folder_mobile: `${szrUrl}/xiangyu-green-suit-header`,
411
+ standby: { interval: 100, standbyNum: 11 },
412
+ speak: { interval: 30, speakNum: 0 },
413
+ humanType: 1,
414
+ timbre: 47
415
+ },
416
+ 2: {
417
+ humanId: 2,
418
+ title: "西装动漫女",
419
+ folder: `${szrUrl}/anime-woman`,
420
+ folder_mobile: `${szrUrl}/anime-woman-header`,
421
+ standby: { interval: 100, standbyNum: 1 },
422
+ speak: { interval: 30, speakNum: 75 },
423
+ humanType: 1,
424
+ timbre: 45
425
+ },
426
+ 3: {
427
+ humanId: 3,
428
+ title: "真人形象男",
429
+ folder: `${szrUrl}/real-man`,
430
+ folder_mobile: `${szrUrl}/real-man-header`,
431
+ standby: { interval: 100, standbyNum: 1 },
432
+ speak: { interval: 30, speakNum: 139 },
433
+ humanType: 1,
434
+ timbre: 47
435
+ },
436
+ 4: {
437
+ humanId: 4,
438
+ title: "真人形象女",
439
+ folder: `${szrUrl}/real-woman`,
440
+ folder_mobile: `${szrUrl}/real-woman-header`,
441
+ standby: { interval: 100, standbyNum: 2 },
442
+ speak: { interval: 40, speakNum: 139 },
443
+ humanType: 1,
444
+ timbre: 34
445
+ },
446
+ 5: {
447
+ humanId: 5,
448
+ title: "Q版形象",
449
+ folder: `${szrUrl}/xiangyu-q`,
450
+ folder_mobile: `${szrUrl}/xiangyu-q-header`,
451
+ standby: { interval: 100, standbyNum: 28 },
452
+ speak: { interval: 30, speakNum: 118 },
453
+ humanType: 1,
454
+ timbre: 47
455
+ }
456
+ };
457
+ const isMobile = () => {
458
+ if (typeof navigator === "undefined") return false;
459
+ return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|HarmonyOS/i.test(navigator.userAgent);
460
+ };
461
+ const resolveFolder = (human) => {
462
+ const finalType = human.humanType || (isMobile() ? 2 : 1);
463
+ if (finalType === 2 && human.folder_mobile) return human.folder_mobile;
464
+ return human.folder;
465
+ };
466
+ const resolveHuman = (input) => {
467
+ if (input == null) return null;
468
+ const humanId = typeof input === "number" ? input : input.humanId;
469
+ const preset = HUMAN_PRESETS[humanId];
470
+ if (!preset) {
471
+ console.error("[DigitalHuman] 未找到 humanId=", humanId, "的预设形象,可用 id:", Object.keys(HUMAN_PRESETS));
472
+ return null;
473
+ }
474
+ const merged = { ...preset, ...typeof input === "object" ? input : {} };
475
+ merged.folder = resolveFolder(merged);
476
+ return merged;
477
+ };
403
478
  const props = __props;
404
479
  const emit = __emit;
405
480
  const containerRef = ref(null);
@@ -421,27 +496,38 @@ const _sfc_main = {
421
496
  standbyNum: currentHuman.value.standby.standbyNum,
422
497
  speakNum: currentHuman.value.speak.speakNum
423
498
  };
424
- for (let i = 1; i <= standbyNum; i++) {
499
+ const makeImage = (url) => {
425
500
  const image = new Image();
426
- image.src = encodeURI(`${folder}/standby/standby (${i}).png`);
427
- frames.value.standby.push(image);
501
+ image.src = encodeURI(url);
502
+ image.onload = () => {
503
+ image.__broken = false;
504
+ };
505
+ image.onerror = () => {
506
+ image.__broken = true;
507
+ console.warn("[DigitalHuman] 帧加载失败:", url);
508
+ };
509
+ return image;
510
+ };
511
+ for (let i = 1; i <= standbyNum; i++) {
512
+ frames.value.standby.push(makeImage(`${folder}/standby/standby (${i}).png`));
513
+ }
514
+ if (speakNum <= 0) {
515
+ console.warn("[DigitalHuman] 当前形象 speakNum=0,说话动画暂用待机帧替代");
516
+ frames.value.speakStart = [...frames.value.standby];
517
+ frames.value.speakLoop = [...frames.value.standby];
518
+ frames.value.speakEnd = [...frames.value.standby];
519
+ return;
428
520
  }
429
521
  const startEnd = Math.floor(speakNum * 0.6);
430
522
  const loopEnd = Math.floor(speakNum * 0.9);
431
523
  for (let i = 1; i <= startEnd; i++) {
432
- const image = new Image();
433
- image.src = encodeURI(`${folder}/speak/speak (${i}).png`);
434
- frames.value.speakStart.push(image);
524
+ frames.value.speakStart.push(makeImage(`${folder}/speak/speak (${i}).png`));
435
525
  }
436
526
  for (let i = startEnd; i <= loopEnd; i++) {
437
- const image = new Image();
438
- image.src = encodeURI(`${folder}/speak/speak (${i}).png`);
439
- frames.value.speakLoop.push(image);
527
+ frames.value.speakLoop.push(makeImage(`${folder}/speak/speak (${i}).png`));
440
528
  }
441
529
  for (let i = loopEnd; i <= speakNum; i++) {
442
- const image = new Image();
443
- image.src = encodeURI(`${folder}/speak/speak (${i}).png`);
444
- frames.value.speakEnd.push(image);
530
+ frames.value.speakEnd.push(makeImage(`${folder}/speak/speak (${i}).png`));
445
531
  }
446
532
  };
447
533
  const draw = (image) => {
@@ -602,20 +688,39 @@ const _sfc_main = {
602
688
  };
603
689
  allFrames.forEach((img) => {
604
690
  if (img.complete) {
691
+ if (!img.naturalWidth) img.__broken = true;
605
692
  checkLoaded();
606
693
  } else {
607
- img.onload = checkLoaded;
608
- img.onerror = checkLoaded;
694
+ img.onload = () => {
695
+ img.__broken = false;
696
+ checkLoaded();
697
+ };
698
+ img.onerror = () => {
699
+ img.__broken = true;
700
+ checkLoaded();
701
+ };
609
702
  }
610
703
  });
611
704
  };
612
705
  const init = () => {
613
706
  nextTick(() => {
707
+ var _a, _b;
614
708
  if (!containerRef.value || !canvasRef.value) return;
615
- if (!props.humans || props.humans.length === 0) return;
616
- if (!currentHuman.value) {
617
- currentHuman.value = props.humans[0];
709
+ const rawInput = props.human;
710
+ if (!rawInput) return;
711
+ const human = resolveHuman(rawInput);
712
+ if (!human) return;
713
+ const prevType = (_a = currentHuman.value) == null ? void 0 : _a.humanType;
714
+ if (((_b = currentHuman.value) == null ? void 0 : _b.humanId) === human.humanId && prevType === human.humanType) {
715
+ Object.assign(currentHuman.value, human);
716
+ return;
618
717
  }
718
+ abortTTS();
719
+ stop();
720
+ timestamp.value = null;
721
+ frameIndex.value = 1;
722
+ currentHuman.value = human;
723
+ console.log("init", currentHuman.value);
619
724
  const canvas = canvasRef.value;
620
725
  const dpr = window.devicePixelRatio || 1;
621
726
  const width = containerRef.value.clientWidth;
@@ -692,9 +797,11 @@ const _sfc_main = {
692
797
  return pcmToWavBlob(buf);
693
798
  };
694
799
  const requestTTSAudio = async (text, signal) => {
800
+ var _a, _b;
695
801
  let lastError = null;
696
802
  for (let attempt = 1; attempt <= TTS_MAX_RETRIES; attempt++) {
697
803
  if (signal == null ? void 0 : signal.aborted) throw new DOMException("Aborted", "AbortError");
804
+ console.log("[TTS] 提交合成请求1111:", ((_a = currentHuman.value) == null ? void 0 : _a.timbre) ?? 1);
698
805
  const res = await fetch(`${TTS_URL}/web/voice/jd/text-to-speech`, {
699
806
  method: "POST",
700
807
  headers: {
@@ -702,7 +809,7 @@ const _sfc_main = {
702
809
  clientid: VOICE_CLIENT_ID,
703
810
  "tenant-id": VOICE_TENANT_ID
704
811
  },
705
- body: JSON.stringify({ text, user: TTS_USER, timbre: 47 }),
812
+ body: JSON.stringify({ text, user: TTS_USER, timbre: ((_b = currentHuman.value) == null ? void 0 : _b.timbre) ?? 1 }),
706
813
  signal
707
814
  });
708
815
  if (!res.ok) {
@@ -773,8 +880,12 @@ const _sfc_main = {
773
880
  }
774
881
  };
775
882
  const playTTS = async (text) => {
776
- var _a;
777
- if (!text || !((_a = currentHuman.value) == null ? void 0 : _a.isMuted)) return;
883
+ if (!text) return;
884
+ const latest = props.human ? resolveHuman(props.human) : null;
885
+ if (latest) {
886
+ if (!latest.isMuted) return;
887
+ Object.assign(currentHuman.value || {}, latest);
888
+ }
778
889
  abortTTS();
779
890
  ttsAbortController = new AbortController();
780
891
  const { signal } = ttsAbortController;
@@ -783,7 +894,7 @@ const _sfc_main = {
783
894
  try {
784
895
  const cleanText = text.replace(/```[\s\S]*?```/g, "").replace(/`[^`]+`/g, "").replace(/[#*_~]/g, "").replace(/\n+/g, ",").replace(/\s+/g, " ").replace(/[,。!?]{2,}/g, ",").trim();
785
896
  if (!cleanText) return;
786
- console.log("[TTS] 提交合成请求:", { text: cleanText, length: cleanText.length });
897
+ console.log("[TTS] 提交合成请求:", { human: currentHuman.value, text: cleanText, length: cleanText.length });
787
898
  const audioBlob = await requestTTSAudio(cleanText, signal);
788
899
  if (signal.aborted || currentTtsRequestId.value !== requestId) return;
789
900
  if (!audioBlob || audioBlob.size === 0) {
@@ -863,6 +974,27 @@ const _sfc_main = {
863
974
  });
864
975
  }
865
976
  };
977
+ watch(
978
+ () => [props.human],
979
+ () => {
980
+ init();
981
+ },
982
+ { deep: true }
983
+ );
984
+ const switchHuman = (humanId) => {
985
+ const next = resolveHuman(humanId);
986
+ if (!next) return;
987
+ abortTTS();
988
+ stop();
989
+ timestamp.value = null;
990
+ frameIndex.value = 1;
991
+ currentHuman.value = next;
992
+ loadFrames();
993
+ waitFramesLoaded(() => {
994
+ draw(frames.value.standby[0]);
995
+ emit("changed", currentHuman.value);
996
+ });
997
+ };
866
998
  __expose({
867
999
  standby,
868
1000
  speak,
@@ -871,14 +1003,11 @@ const _sfc_main = {
871
1003
  resume,
872
1004
  playTTS,
873
1005
  startRecord,
874
- stopRecord
1006
+ stopRecord,
1007
+ switchHuman
875
1008
  });
876
- watch(() => props.humans, (val) => {
877
- if (val && val.length > 0 && !currentHuman.value) {
878
- init();
879
- }
880
- }, { deep: true });
881
1009
  onMounted(() => {
1010
+ console.log("onMounted", props.human);
882
1011
  initRecorder();
883
1012
  init();
884
1013
  });
@@ -903,7 +1032,7 @@ const _sfc_main = {
903
1032
  };
904
1033
  }
905
1034
  };
906
- const DigitalHuman = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-9379171c"]]);
1035
+ const DigitalHuman = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-ab1e5de1"]]);
907
1036
  DigitalHuman.install = (app) => app.component("DigitalHuman", DigitalHuman);
908
1037
  const components = [DemoButton, DemoInput, DigitalHuman];
909
1038
  const install = (app) => {
package/dist/style.css CHANGED
@@ -1 +1 @@
1
- .demo-btn[data-v-9a48516a]{padding:6px 14px;border-radius:4px;border:none;cursor:pointer;font-size:14px}.primary[data-v-9a48516a]{background:#409eff;color:#fff}.success[data-v-9a48516a]{background:#67c23a;color:#fff}.warning[data-v-9a48516a]{background:#e6a23c;color:#fff}.demo-input-wrap[data-v-28a3493c]{display:inline-flex;align-items:center;border:1px solid #dcdcdc;border-radius:4px;padding:0 10px}.demo-input-wrap[data-v-28a3493c]:focus-within{border-color:#409eff}.demo-input[data-v-28a3493c]{border:none;outline:none;padding:8px 6px;flex:1}.prefix[data-v-28a3493c],.suffix[data-v-28a3493c]{color:#909399}.digital-human[data-v-9379171c]{width:100%;height:100%;display:flex;align-items:center;justify-content:center}.digital-human canvas[data-v-9379171c]{max-width:100%;max-height:100%}
1
+ .demo-btn[data-v-9a48516a]{padding:6px 14px;border-radius:4px;border:none;cursor:pointer;font-size:14px}.primary[data-v-9a48516a]{background:#409eff;color:#fff}.success[data-v-9a48516a]{background:#67c23a;color:#fff}.warning[data-v-9a48516a]{background:#e6a23c;color:#fff}.demo-input-wrap[data-v-28a3493c]{display:inline-flex;align-items:center;border:1px solid #dcdcdc;border-radius:4px;padding:0 10px}.demo-input-wrap[data-v-28a3493c]:focus-within{border-color:#409eff}.demo-input[data-v-28a3493c]{border:none;outline:none;padding:8px 6px;flex:1}.prefix[data-v-28a3493c],.suffix[data-v-28a3493c]{color:#909399}.digital-human[data-v-ab1e5de1]{width:100%;height:100%;display:flex;align-items:center;justify-content:center}.digital-human canvas[data-v-ab1e5de1]{max-width:100%;max-height:100%}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ruiyun-human",
3
- "version": "1.0.13",
3
+ "version": "1.0.15",
4
4
  "type": "module",
5
5
  "description": "数字人初步实现",
6
6
  "main": "./dist/ruiyun-human.cjs.js",