@siact/sime-x-vue 0.0.2 → 0.0.3

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();
@@ -758,16 +680,6 @@
758
680
  console.error("[VoiceDetector] 清理失败:", error);
759
681
  }
760
682
  }
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
683
  });
772
684
  aiChatbotX?.registerVoiceMethods({
773
685
  start: () => toggleVoiceMode(true),
@@ -812,7 +724,10 @@
812
724
  }, null, 12, _hoisted_3),
813
725
  vue.createVNode(vue.Transition, { name: "indicator-fade" }, {
814
726
  default: vue.withCtx(() => [
815
- voiceStatus.value === "listening" ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_4, [..._cache[3] || (_cache[3] = [
727
+ voiceStatus.value === "listening" ? (vue.openBlock(), vue.createElementBlock("div", {
728
+ key: 0,
729
+ class: vue.normalizeClass(["listening-badge", { "wake-active": wakeAnimating.value }])
730
+ }, [..._cache[3] || (_cache[3] = [
816
731
  vue.createElementVNode("div", { class: "listening-waves" }, [
817
732
  vue.createElementVNode("div", { class: "wave wave-1" }),
818
733
  vue.createElementVNode("div", { class: "wave wave-2" }),
@@ -837,7 +752,7 @@
837
752
  })
838
753
  ])
839
754
  ], -1)
840
- ])])) : vue.createCommentVNode("", true)
755
+ ])], 2)) : vue.createCommentVNode("", true)
841
756
  ]),
842
757
  _: 1
843
758
  })
@@ -871,17 +786,17 @@
871
786
  class: "x-dialog-header",
872
787
  onMousedown: vue.withModifiers(startDrag, ["stop"])
873
788
  }, [
874
- vue.createElementVNode("div", _hoisted_5, [
875
- vue.createElementVNode("div", _hoisted_6, [
789
+ vue.createElementVNode("div", _hoisted_4, [
790
+ vue.createElementVNode("div", _hoisted_5, [
876
791
  vue.createElementVNode("img", {
877
792
  src: __props.xLogo ? __props.xLogo : "/sime.png",
878
793
  alt: "assistant",
879
794
  class: "logo"
880
- }, null, 8, _hoisted_7)
795
+ }, null, 8, _hoisted_6)
881
796
  ]),
882
- vue.createElementVNode("span", _hoisted_8, vue.toDisplayString(__props.xTitle), 1)
797
+ vue.createElementVNode("span", _hoisted_7, vue.toDisplayString(__props.xTitle), 1)
883
798
  ]),
884
- vue.createElementVNode("div", _hoisted_9, [
799
+ vue.createElementVNode("div", _hoisted_8, [
885
800
  vue.createElementVNode("button", {
886
801
  class: "action-btn theme-btn",
887
802
  title: "开启新对话",
@@ -945,8 +860,8 @@
945
860
  "stroke-linejoin": "round"
946
861
  })
947
862
  ], -1)),
948
- voiceStatus.value !== "standby" ? (vue.openBlock(), vue.createElementBlock("span", _hoisted_11)) : vue.createCommentVNode("", true)
949
- ], 10, _hoisted_10),
863
+ voiceStatus.value !== "standby" ? (vue.openBlock(), vue.createElementBlock("span", _hoisted_10)) : vue.createCommentVNode("", true)
864
+ ], 10, _hoisted_9),
950
865
  vue.createElementVNode("button", {
951
866
  class: "action-btn theme-btn",
952
867
  onClick: vue.withModifiers(cycleTheme, ["stop"]),
@@ -970,22 +885,22 @@
970
885
  fill: "currentColor"
971
886
  })
972
887
  ], -1)
973
- ])], 8, _hoisted_12),
888
+ ])], 8, _hoisted_11),
974
889
  vue.createElementVNode("button", {
975
890
  class: "action-btn collapse-btn",
976
891
  onClick: vue.withModifiers(toggleCollapse, ["stop"]),
977
892
  title: isCollapsed.value ? "展开" : "折叠"
978
893
  }, [
979
- (vue.openBlock(), vue.createElementBlock("svg", _hoisted_14, [
894
+ (vue.openBlock(), vue.createElementBlock("svg", _hoisted_13, [
980
895
  vue.createElementVNode("path", {
981
896
  d: isCollapsed.value ? "M18 15L12 9L6 15" : "M6 9L12 15L18 9",
982
897
  stroke: "currentColor",
983
898
  "stroke-width": "2",
984
899
  "stroke-linecap": "round",
985
900
  "stroke-linejoin": "round"
986
- }, null, 8, _hoisted_15)
901
+ }, null, 8, _hoisted_14)
987
902
  ]))
988
- ], 8, _hoisted_13),
903
+ ], 8, _hoisted_12),
989
904
  vue.createElementVNode("button", {
990
905
  class: "action-btn minimize-btn",
991
906
  onClick: _cache[2] || (_cache[2] = vue.withModifiers(($event) => toggleDialog(false), ["stop"])),
@@ -1018,7 +933,7 @@
1018
933
  allow: "microphone",
1019
934
  frameborder: "0",
1020
935
  onLoad: handleIframeLoad
1021
- }, null, 40, _hoisted_16)
936
+ }, null, 40, _hoisted_15)
1022
937
  ], 6)
1023
938
  ], 38)
1024
939
  ]),
@@ -1029,7 +944,7 @@
1029
944
  }
1030
945
  });
1031
946
 
1032
- const simeX = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-d8f992b0"]]);
947
+ const simeX = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-732b3a72"]]);
1033
948
 
1034
949
  exports.AiChatbotProvider = _sfc_main$3;
1035
950
  exports.AiChatbotX = simeX;