@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.
- package/dist/sime-x-vue.mjs +59 -144
- package/dist/sime-x-vue.mjs.map +1 -1
- package/dist/sime-x-vue.umd.js +58 -143
- package/dist/sime-x-vue.umd.js.map +1 -1
- package/dist/style.css +127 -75
- package/package.json +1 -1
- package/types/components/sime-x.vue.d.ts +2 -0
package/dist/sime-x-vue.umd.js
CHANGED
|
@@ -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
|
-
|
|
324
|
-
|
|
325
|
-
};
|
|
326
|
-
const
|
|
327
|
-
const
|
|
328
|
-
const
|
|
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 =
|
|
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
|
|
345
|
-
const
|
|
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
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
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
|
-
|
|
466
|
-
if (transcriber) return;
|
|
467
|
+
const playWakeResponse = () => {
|
|
467
468
|
try {
|
|
468
|
-
|
|
469
|
-
|
|
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
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
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("[
|
|
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",
|
|
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",
|
|
875
|
-
vue.createElementVNode("div",
|
|
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,
|
|
795
|
+
}, null, 8, _hoisted_6)
|
|
881
796
|
]),
|
|
882
|
-
vue.createElementVNode("span",
|
|
797
|
+
vue.createElementVNode("span", _hoisted_7, vue.toDisplayString(__props.xTitle), 1)
|
|
883
798
|
]),
|
|
884
|
-
vue.createElementVNode("div",
|
|
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",
|
|
949
|
-
], 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,
|
|
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",
|
|
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,
|
|
901
|
+
}, null, 8, _hoisted_14)
|
|
987
902
|
]))
|
|
988
|
-
], 8,
|
|
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,
|
|
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-
|
|
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;
|