@siact/sime-x-vue 0.0.2 → 0.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.
@@ -319,30 +319,26 @@
319
319
  const _hoisted_1 = ["data-theme"];
320
320
  const _hoisted_2 = { class: "fab-avatar-wrapper" };
321
321
  const _hoisted_3 = ["src"];
322
- const _hoisted_4 = {
323
- key: 0,
324
- class: "listening-badge"
325
- };
326
- const _hoisted_5 = { class: "header-left" };
327
- const _hoisted_6 = { class: "logo-icon" };
328
- const _hoisted_7 = ["src"];
329
- const _hoisted_8 = { class: "title" };
330
- const _hoisted_9 = { class: "actions" };
331
- const _hoisted_10 = ["title"];
332
- const _hoisted_11 = {
322
+ const _hoisted_4 = { class: "header-left" };
323
+ const _hoisted_5 = { class: "logo-icon" };
324
+ const _hoisted_6 = ["src"];
325
+ const _hoisted_7 = { class: "title" };
326
+ const _hoisted_8 = { class: "actions" };
327
+ const _hoisted_9 = ["title"];
328
+ const _hoisted_10 = {
333
329
  key: 0,
334
330
  class: "voice-indicator"
335
331
  };
332
+ const _hoisted_11 = ["title"];
336
333
  const _hoisted_12 = ["title"];
337
- const _hoisted_13 = ["title"];
338
- const _hoisted_14 = {
334
+ const _hoisted_13 = {
339
335
  width: "16",
340
336
  height: "16",
341
337
  viewBox: "0 0 24 24",
342
338
  fill: "none"
343
339
  };
344
- const _hoisted_15 = ["d"];
345
- const _hoisted_16 = ["src"];
340
+ const _hoisted_14 = ["d"];
341
+ const _hoisted_15 = ["src"];
346
342
  const _sfc_main = /* @__PURE__ */ vue.defineComponent({
347
343
  __name: "sime-x",
348
344
  props: {
@@ -354,13 +350,15 @@
354
350
  wakeWords: {},
355
351
  modelPath: {}
356
352
  },
357
- emits: ["start-transcribing", "stop-transcribing"],
353
+ emits: ["start-transcribing", "stop-transcribing", "wakeUp"],
358
354
  setup(__props, { emit: __emit }) {
359
355
  const props = __props;
360
356
  const emit = __emit;
361
357
  const aiChatbotX = injectStrict(AiChatbotXKey);
362
358
  const chatbotUrl = vue.ref("");
363
359
  const voiceStatus = vue.ref("standby");
360
+ const wakeAnimating = vue.ref(false);
361
+ const wakeResponses = ["在呢", "在的", "我在", "您好", "在呢,请说"];
364
362
  const transcriptionText = vue.ref("");
365
363
  const isTranscribing = vue.ref(false);
366
364
  const isProcessing = vue.ref(false);
@@ -369,7 +367,6 @@
369
367
  const fabRef = vue.ref(null);
370
368
  const positionReady = vue.ref(false);
371
369
  let detector = null;
372
- let transcriber = null;
373
370
  const isInitializing = vue.ref(false);
374
371
  const initError = vue.ref("");
375
372
  const getSystemTheme = () => {
@@ -431,10 +428,15 @@
431
428
  detector.setWakeWords(wakeWords);
432
429
  detector.onWake(() => {
433
430
  console.log("[VoiceDetector] 检测到唤醒词");
434
- voiceStatus.value = "wake";
435
- transcriptionText.value = "";
436
- isTranscribing.value = false;
437
- startTranscribing();
431
+ wakeAnimating.value = true;
432
+ playWakeResponse();
433
+ emit("wakeUp", true);
434
+ aiChatbotX.weak();
435
+ aiChatbotX.openDialog();
436
+ setTimeout(() => {
437
+ wakeAnimating.value = false;
438
+ }, 1500);
439
+ voiceStatus.value = "listening";
438
440
  });
439
441
  detector.onError((error) => {
440
442
  console.error("[VoiceDetector] 错误:", error);
@@ -462,110 +464,30 @@
462
464
  isInitializing.value = false;
463
465
  }
464
466
  };
465
- function initTranscriber() {
466
- if (transcriber) return;
467
+ const playWakeResponse = () => {
467
468
  try {
468
- const { appId, apiKey, websocketUrl } = aiChatbotX.voiceConfig();
469
- if (!appId || !apiKey || !websocketUrl) {
470
- initError.value = "未配置语音配置";
471
- voiceStatus.value = "standby";
472
- isTranscribing.value = false;
469
+ if (typeof window === "undefined" || !window.speechSynthesis) {
470
+ console.warn("[TTS] SpeechSynthesis API 不可用");
473
471
  return;
474
472
  }
475
- transcriber = new webVoiceKit.SpeechTranscriberStandalone({
476
- appId,
477
- apiKey,
478
- websocketUrl,
479
- autoStop: {
480
- enabled: true,
481
- silenceTimeoutMs: 3e3,
482
- noSpeechTimeoutMs: 5e3,
483
- maxDurationMs: 6e4
484
- }
485
- });
486
- transcriber.onResult((result) => {
487
- transcriptionText.value = result.transcript;
488
- });
489
- transcriber.onAutoStop(async () => {
490
- console.log("[Transcriber] Auto Stop");
491
- const currentText = transcriptionText.value;
492
- await stopTranscribing();
493
- if (!currentText || !currentText.trim()) {
494
- console.log("[Transcriber] No transcription text, returning to listening");
495
- transcriptionText.value = "";
496
- voiceStatus.value = "listening";
497
- return;
498
- }
499
- isProcessing.value = true;
500
- transcriptionText.value = currentText;
501
- try {
502
- const commands = await aiChatbotX.hostCommads();
503
- const result = await aiChatbotX.recognition(currentText, commands);
504
- if (result?.data?.intent === "command" && result?.data?.matchedCommands) {
505
- const matchedCommands = result.data.matchedCommands;
506
- for (const cmd of matchedCommands) {
507
- try {
508
- const args = cmd.parameters ? Object.values(cmd.parameters) : [];
509
- const cmdResult = await aiChatbotX.executeCommand(cmd.name, args);
510
- console.log(`Command ${cmd.name} executed successfully:`, cmdResult);
511
- } catch (error) {
512
- console.error(`Failed to execute command ${cmd.name}:`, error);
513
- }
514
- }
515
- } else {
516
- aiChatbotX.appendMessage(currentText);
517
- toggleDialog(true);
518
- }
519
- } finally {
520
- isProcessing.value = false;
521
- transcriptionText.value = "";
522
- voiceStatus.value = "listening";
523
- }
524
- });
525
- transcriber.onError((error) => {
526
- console.error("[Transcriber] Error:", error);
527
- stopTranscribing();
528
- transcriptionText.value = "转写错误";
529
- setTimeout(() => {
530
- transcriptionText.value = "";
531
- voiceStatus.value = "listening";
532
- }, 2e3);
533
- });
534
- console.log("[Transcriber] 初始化成功");
535
- } catch (error) {
536
- console.error("[Transcriber] 初始化失败:", error);
537
- voiceStatus.value = "standby";
538
- initError.value = error instanceof Error ? error.message : "转写初始化失败";
539
- }
540
- }
541
- const startTranscribing = async () => {
542
- if (!transcriber) {
543
- initTranscriber();
544
- if (!transcriber) return;
545
- }
546
- try {
547
- emit("start-transcribing");
548
- await transcriber.start();
549
- isTranscribing.value = true;
550
- transcriptionText.value = "";
473
+ const text = wakeResponses[Math.floor(Math.random() * wakeResponses.length)];
474
+ const utterance = new SpeechSynthesisUtterance(text);
475
+ utterance.lang = "zh-CN";
476
+ utterance.rate = 1;
477
+ utterance.pitch = 0.8;
478
+ utterance.volume = 0.9;
479
+ const voices = window.speechSynthesis.getVoices();
480
+ const maleVoice = voices.find((v) => v.lang.startsWith("zh") && /male|男/i.test(v.name));
481
+ const zhVoice = maleVoice || voices.find((v) => v.lang.startsWith("zh"));
482
+ if (zhVoice) {
483
+ utterance.voice = zhVoice;
484
+ }
485
+ window.speechSynthesis.speak(utterance);
551
486
  } catch (error) {
552
- console.error("[Transcriber] 启动失败:", error);
553
- transcriptionText.value = "转写启动失败";
554
- setTimeout(() => {
555
- transcriptionText.value = "";
556
- }, 2e3);
487
+ console.error("[TTS] 播报失败:", error);
557
488
  }
558
489
  };
559
490
  const stopTranscribing = async () => {
560
- if (transcriber && transcriber.isActive()) {
561
- try {
562
- await transcriber.stop();
563
- isTranscribing.value = false;
564
- emit("stop-transcribing");
565
- } catch (error) {
566
- console.error("[Transcriber] 停止失败:", error);
567
- }
568
- }
569
491
  };
570
492
  const toggleVoiceMode = async (targetState) => {
571
493
  const permission = await ensureMicrophonePermission();
@@ -731,6 +653,7 @@
731
653
  positionReady.value = false;
732
654
  visible.value = false;
733
655
  isCollapsed.value = false;
656
+ emit("wakeUp", false);
734
657
  }
735
658
  };
736
659
  const handleIframeLoad = (event) => {
@@ -758,16 +681,6 @@
758
681
  console.error("[VoiceDetector] 清理失败:", error);
759
682
  }
760
683
  }
761
- if (transcriber) {
762
- try {
763
- if (transcriber.isActive()) {
764
- await transcriber.stop();
765
- }
766
- transcriber = null;
767
- } catch (error) {
768
- console.error("[Transcriber] 清理失败:", error);
769
- }
770
- }
771
684
  });
772
685
  aiChatbotX?.registerVoiceMethods({
773
686
  start: () => toggleVoiceMode(true),
@@ -812,7 +725,10 @@
812
725
  }, null, 12, _hoisted_3),
813
726
  vue.createVNode(vue.Transition, { name: "indicator-fade" }, {
814
727
  default: vue.withCtx(() => [
815
- voiceStatus.value === "listening" ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_4, [..._cache[3] || (_cache[3] = [
728
+ voiceStatus.value === "listening" ? (vue.openBlock(), vue.createElementBlock("div", {
729
+ key: 0,
730
+ class: vue.normalizeClass(["listening-badge", { "wake-active": wakeAnimating.value }])
731
+ }, [..._cache[3] || (_cache[3] = [
816
732
  vue.createElementVNode("div", { class: "listening-waves" }, [
817
733
  vue.createElementVNode("div", { class: "wave wave-1" }),
818
734
  vue.createElementVNode("div", { class: "wave wave-2" }),
@@ -837,7 +753,7 @@
837
753
  })
838
754
  ])
839
755
  ], -1)
840
- ])])) : vue.createCommentVNode("", true)
756
+ ])], 2)) : vue.createCommentVNode("", true)
841
757
  ]),
842
758
  _: 1
843
759
  })
@@ -871,17 +787,17 @@
871
787
  class: "x-dialog-header",
872
788
  onMousedown: vue.withModifiers(startDrag, ["stop"])
873
789
  }, [
874
- vue.createElementVNode("div", _hoisted_5, [
875
- vue.createElementVNode("div", _hoisted_6, [
790
+ vue.createElementVNode("div", _hoisted_4, [
791
+ vue.createElementVNode("div", _hoisted_5, [
876
792
  vue.createElementVNode("img", {
877
793
  src: __props.xLogo ? __props.xLogo : "/sime.png",
878
794
  alt: "assistant",
879
795
  class: "logo"
880
- }, null, 8, _hoisted_7)
796
+ }, null, 8, _hoisted_6)
881
797
  ]),
882
- vue.createElementVNode("span", _hoisted_8, vue.toDisplayString(__props.xTitle), 1)
798
+ vue.createElementVNode("span", _hoisted_7, vue.toDisplayString(__props.xTitle), 1)
883
799
  ]),
884
- vue.createElementVNode("div", _hoisted_9, [
800
+ vue.createElementVNode("div", _hoisted_8, [
885
801
  vue.createElementVNode("button", {
886
802
  class: "action-btn theme-btn",
887
803
  title: "开启新对话",
@@ -945,8 +861,8 @@
945
861
  "stroke-linejoin": "round"
946
862
  })
947
863
  ], -1)),
948
- voiceStatus.value !== "standby" ? (vue.openBlock(), vue.createElementBlock("span", _hoisted_11)) : vue.createCommentVNode("", true)
949
- ], 10, _hoisted_10),
864
+ voiceStatus.value !== "standby" ? (vue.openBlock(), vue.createElementBlock("span", _hoisted_10)) : vue.createCommentVNode("", true)
865
+ ], 10, _hoisted_9),
950
866
  vue.createElementVNode("button", {
951
867
  class: "action-btn theme-btn",
952
868
  onClick: vue.withModifiers(cycleTheme, ["stop"]),
@@ -970,22 +886,22 @@
970
886
  fill: "currentColor"
971
887
  })
972
888
  ], -1)
973
- ])], 8, _hoisted_12),
889
+ ])], 8, _hoisted_11),
974
890
  vue.createElementVNode("button", {
975
891
  class: "action-btn collapse-btn",
976
892
  onClick: vue.withModifiers(toggleCollapse, ["stop"]),
977
893
  title: isCollapsed.value ? "展开" : "折叠"
978
894
  }, [
979
- (vue.openBlock(), vue.createElementBlock("svg", _hoisted_14, [
895
+ (vue.openBlock(), vue.createElementBlock("svg", _hoisted_13, [
980
896
  vue.createElementVNode("path", {
981
897
  d: isCollapsed.value ? "M18 15L12 9L6 15" : "M6 9L12 15L18 9",
982
898
  stroke: "currentColor",
983
899
  "stroke-width": "2",
984
900
  "stroke-linecap": "round",
985
901
  "stroke-linejoin": "round"
986
- }, null, 8, _hoisted_15)
902
+ }, null, 8, _hoisted_14)
987
903
  ]))
988
- ], 8, _hoisted_13),
904
+ ], 8, _hoisted_12),
989
905
  vue.createElementVNode("button", {
990
906
  class: "action-btn minimize-btn",
991
907
  onClick: _cache[2] || (_cache[2] = vue.withModifiers(($event) => toggleDialog(false), ["stop"])),
@@ -1018,7 +934,7 @@
1018
934
  allow: "microphone",
1019
935
  frameborder: "0",
1020
936
  onLoad: handleIframeLoad
1021
- }, null, 40, _hoisted_16)
937
+ }, null, 40, _hoisted_15)
1022
938
  ], 6)
1023
939
  ], 38)
1024
940
  ]),
@@ -1029,7 +945,7 @@
1029
945
  }
1030
946
  });
1031
947
 
1032
- const simeX = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-d8f992b0"]]);
948
+ const simeX = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-73306d13"]]);
1033
949
 
1034
950
  exports.AiChatbotProvider = _sfc_main$3;
1035
951
  exports.AiChatbotX = simeX;