@siact/sime-x-vue 0.0.8 → 0.0.10

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.
@@ -49,6 +49,8 @@
49
49
  });
50
50
  const stopListeningRef = vue.shallowRef(async () => {
51
51
  });
52
+ const stopBroadcastRef = vue.shallowRef(async () => {
53
+ });
52
54
  const toggleCollapseRef = vue.shallowRef(async () => {
53
55
  });
54
56
  const openDialogRef = vue.shallowRef(async () => {
@@ -62,12 +64,14 @@
62
64
  voiceConfig: () => props.voiceConfig || { appId: "", apiKey: "", websocketUrl: "" },
63
65
  startListening: () => startListeningRef.value(),
64
66
  stopListening: () => stopListeningRef.value(),
67
+ stopBroadcast: () => stopBroadcastRef.value(),
65
68
  toggleCollapse: () => toggleCollapseRef.value(),
66
69
  openDialog: () => openDialogRef.value(),
67
70
  closeDialog: () => closeDialogRef.value(),
68
71
  registerVoiceMethods: (methods) => {
69
72
  startListeningRef.value = methods.start;
70
73
  stopListeningRef.value = methods.stop;
74
+ if (methods.stopBroadcast) stopBroadcastRef.value = methods.stopBroadcast;
71
75
  toggleCollapseRef.value = methods.toggleCollapse;
72
76
  openDialogRef.value = methods.openDialog;
73
77
  closeDialogRef.value = methods.closeDialog;
@@ -999,6 +1003,7 @@
999
1003
 
1000
1004
  function useTTS(getVoiceConfig) {
1001
1005
  const isSpeaking = vue.ref(false);
1006
+ const hasPendingAudio = vue.ref(false);
1002
1007
  let instance = null;
1003
1008
  let initPromise = null;
1004
1009
  let audioCtx = null;
@@ -1034,9 +1039,9 @@
1034
1039
  apiSecret: vc.apiSecret,
1035
1040
  websocketUrl: vc.ttsWebsocketUrl || "wss://tts-api.xfyun.cn/v2/tts",
1036
1041
  vcn: vc.ttsVcn || "xiaoyan",
1037
- speed: 60,
1038
- volume: 50,
1039
- pitch: 50,
1042
+ speed: vc.speed || 55,
1043
+ volume: vc.volume || 90,
1044
+ pitch: vc.pitch || 50,
1040
1045
  aue: "raw",
1041
1046
  auf: "audio/L16;rate=16000",
1042
1047
  tte: "UTF8",
@@ -1049,6 +1054,7 @@
1049
1054
  });
1050
1055
  tts.onQueueEmpty(() => {
1051
1056
  isSpeaking.value = false;
1057
+ hasPendingAudio.value = false;
1052
1058
  onQueueEmptyCb?.();
1053
1059
  });
1054
1060
  tts.onError((err) => {
@@ -1074,6 +1080,7 @@
1074
1080
  const speak = async (text) => {
1075
1081
  const clean = stripMarkdown(text);
1076
1082
  if (!clean.trim()) return;
1083
+ hasPendingAudio.value = true;
1077
1084
  const tts = await ensureInstance();
1078
1085
  if (!tts) return;
1079
1086
  try {
@@ -1100,6 +1107,7 @@
1100
1107
  const stop = () => {
1101
1108
  sentenceBuffer = "";
1102
1109
  isSpeaking.value = false;
1110
+ hasPendingAudio.value = false;
1103
1111
  if (instance) {
1104
1112
  try {
1105
1113
  instance.stop();
@@ -1129,6 +1137,7 @@
1129
1137
  };
1130
1138
  return {
1131
1139
  isSpeaking,
1140
+ hasPendingAudio,
1132
1141
  warmUpAudio,
1133
1142
  speak,
1134
1143
  feed,
@@ -1144,7 +1153,14 @@
1144
1153
  const fadingOut = vue.ref(false);
1145
1154
  const stackRef = vue.ref(null);
1146
1155
  let dismissTimer = null;
1147
- const show = vue.computed(() => visible.value && !fadingOut.value);
1156
+ const hasOpened = vue.ref(false);
1157
+ const isTTSActive = () => !!(options.isSpeaking?.value || options.hasPendingAudio?.value);
1158
+ const isBusy = () => !!(options.isInvoking?.value || isTTSActive());
1159
+ const show = vue.computed(() => {
1160
+ if (!hasOpened.value) return false;
1161
+ if (isTTSActive()) return true;
1162
+ return visible.value && !fadingOut.value;
1163
+ });
1148
1164
  const style = vue.computed(() => ({
1149
1165
  width: options.bubbleSize?.width || void 0,
1150
1166
  maxHeight: options.bubbleSize?.maxHeight || void 0
@@ -1153,6 +1169,7 @@
1153
1169
  cancelDismiss();
1154
1170
  fadingOut.value = false;
1155
1171
  visible.value = true;
1172
+ hasOpened.value = true;
1156
1173
  };
1157
1174
  const cancelDismiss = () => {
1158
1175
  if (dismissTimer) {
@@ -1162,21 +1179,39 @@
1162
1179
  };
1163
1180
  const scheduleDismiss = () => {
1164
1181
  cancelDismiss();
1165
- if (options.isSpeaking?.value) return;
1166
- if (options.isInvoking?.value) return;
1182
+ if (isBusy()) return;
1167
1183
  const delay = options.dismissDelay ?? 4e3;
1168
1184
  dismissTimer = setTimeout(() => {
1185
+ if (isBusy()) return;
1169
1186
  fadingOut.value = true;
1170
1187
  setTimeout(() => {
1188
+ if (isBusy()) {
1189
+ fadingOut.value = false;
1190
+ return;
1191
+ }
1171
1192
  visible.value = false;
1172
1193
  fadingOut.value = false;
1194
+ hasOpened.value = false;
1173
1195
  }, 400);
1174
1196
  }, delay);
1175
1197
  };
1198
+ const watchTTSRef = (ttsRef) => {
1199
+ vue.watch(ttsRef, (active) => {
1200
+ if (active && hasOpened.value) {
1201
+ cancelDismiss();
1202
+ if (fadingOut.value) fadingOut.value = false;
1203
+ } else if (!active && hasOpened.value && !isBusy()) {
1204
+ scheduleDismiss();
1205
+ }
1206
+ });
1207
+ };
1208
+ if (options.isSpeaking) watchTTSRef(options.isSpeaking);
1209
+ if (options.hasPendingAudio) watchTTSRef(options.hasPendingAudio);
1176
1210
  const hide = () => {
1177
1211
  cancelDismiss();
1178
1212
  fadingOut.value = false;
1179
1213
  visible.value = false;
1214
+ hasOpened.value = false;
1180
1215
  };
1181
1216
  const scrollToBottom = () => {
1182
1217
  vue.nextTick(() => {
@@ -1806,7 +1841,7 @@
1806
1841
  const processedToolResults = /* @__PURE__ */ new Set();
1807
1842
  abortController = new AbortController();
1808
1843
  const commands = await aiChatbotX.hostCommads();
1809
- const historyToSend = conversationHistory.value.length > 0 ? [...conversationHistory.value] : void 0;
1844
+ conversationHistory.value.length > 0 ? [...conversationHistory.value] : void 0;
1810
1845
  try {
1811
1846
  const response = await fetch(options.endpoint.value, {
1812
1847
  method: "POST",
@@ -1814,8 +1849,8 @@
1814
1849
  body: JSON.stringify({
1815
1850
  input: content,
1816
1851
  projectId: options.projectId || "",
1817
- commands: commands.length > 0 ? commands : void 0,
1818
- messages: historyToSend
1852
+ commands: commands.length > 0 ? commands : void 0
1853
+ // messages: historyToSend,
1819
1854
  }),
1820
1855
  signal: abortController.signal
1821
1856
  });
@@ -1994,7 +2029,7 @@
1994
2029
  const endpoint = vue.computed(() => {
1995
2030
  return props.invokeUrl || "http://localhost:3001/agent/zyy55sw40nrl801056m0o/stream-invoke";
1996
2031
  });
1997
- const wakeResponses = ["您好"];
2032
+ const wakeResponses = ["在呢"];
1998
2033
  const tts = useTTS(getVoiceConfig);
1999
2034
  const bubbleBridge = {
2000
2035
  open: () => {
@@ -2023,6 +2058,7 @@
2023
2058
  const bubble = useBubble({
2024
2059
  dismissDelay: props.bubbleDismissDelay,
2025
2060
  isSpeaking: tts.isSpeaking,
2061
+ hasPendingAudio: tts.hasPendingAudio,
2026
2062
  isInvoking: agent.isInvoking,
2027
2063
  bubbleSize: props.bubbleSize
2028
2064
  });
@@ -2030,11 +2066,6 @@
2030
2066
  bubbleBridge.scheduleDismiss = bubble.scheduleDismiss;
2031
2067
  bubbleBridge.scrollToBottom = bubble.scrollToBottom;
2032
2068
  const { show: showBubble, style: bubbleStyle, stackRef: bubbleStackRef } = bubble;
2033
- tts.setOnQueueEmpty(() => {
2034
- if (!agent.isInvoking.value) {
2035
- bubble.scheduleDismiss();
2036
- }
2037
- });
2038
2069
  const interruptCurrentResponse = () => {
2039
2070
  agent.abort();
2040
2071
  agent.resetState();
@@ -2059,11 +2090,12 @@
2059
2090
  tts.warmUpAudio();
2060
2091
  await voice.toggleVoiceMode(targetState);
2061
2092
  };
2062
- const { voiceStatus, transcriptionText, wakeAnimating } = voice;
2093
+ const { voiceStatus, transcriptionText, wakeAnimating, isTranscribing } = voice;
2063
2094
  const { isInvoking, currentTextContent, currentToolParts, executingTools, hasAnyContent, toolDisplayName } = agent;
2064
2095
  aiChatbotX?.registerVoiceMethods({
2065
2096
  start: () => toggleVoiceMode(true),
2066
2097
  stop: () => toggleVoiceMode(false),
2098
+ stopBroadcast: async () => interruptCurrentResponse(),
2067
2099
  openDialog: async () => Promise.resolve(),
2068
2100
  closeDialog: async () => Promise.resolve(),
2069
2101
  toggleCollapse: async () => Promise.resolve()
@@ -2168,7 +2200,7 @@
2168
2200
  default: vue.withCtx(() => [
2169
2201
  vue.unref(voiceStatus) === "listening" ? (vue.openBlock(), vue.createElementBlock("div", {
2170
2202
  key: 0,
2171
- class: vue.normalizeClass(["listening-badge", { "wake-active": vue.unref(wakeAnimating) }])
2203
+ class: vue.normalizeClass(["listening-badge", { "wake-active": vue.unref(wakeAnimating) || vue.unref(isTranscribing) || vue.unref(isInvoking) }])
2172
2204
  }, [..._cache[5] || (_cache[5] = [
2173
2205
  vue.createElementVNode("div", { class: "listening-waves" }, [
2174
2206
  vue.createElementVNode("div", { class: "wave wave-1" }),
@@ -2205,7 +2237,7 @@
2205
2237
  }
2206
2238
  });
2207
2239
 
2208
- const voiceAssistant = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-9e420a26"]]);
2240
+ const voiceAssistant = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-77c6ae95"]]);
2209
2241
 
2210
2242
  exports.AiChatbotProvider = _sfc_main$4;
2211
2243
  exports.AiChatbotVoiceAssistant = voiceAssistant;