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