@siact/sime-x-vue 0.0.17 → 0.0.19

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.
@@ -106,7 +106,7 @@ const _hoisted_9$2 = ["onClick"];
106
106
  const _hoisted_10$2 = { class: "ai-chat__messages-inner" };
107
107
  const _hoisted_11$2 = { class: "ai-chat__message-content" };
108
108
  const _hoisted_12$2 = ["innerHTML"];
109
- const _hoisted_13$2 = {
109
+ const _hoisted_13$1 = {
110
110
  key: 1,
111
111
  class: "ai-chat__reasoning"
112
112
  };
@@ -469,7 +469,7 @@ const _sfc_main$3 = /* @__PURE__ */ defineComponent({
469
469
  innerHTML: renderMarkdown(part.text)
470
470
  }, null, 8, _hoisted_12$2)
471
471
  ])
472
- ], 2)) : part.type === "reasoning" ? (openBlock(), createElementBlock("div", _hoisted_13$2, [
472
+ ], 2)) : part.type === "reasoning" ? (openBlock(), createElementBlock("div", _hoisted_13$1, [
473
473
  createElementVNode("button", {
474
474
  class: "ai-chat__reasoning-trigger",
475
475
  onClick: ($event) => toggleReasoning(message.id)
@@ -1464,7 +1464,7 @@ const _hoisted_10$1 = {
1464
1464
  };
1465
1465
  const _hoisted_11$1 = { class: "input-bar" };
1466
1466
  const _hoisted_12$1 = ["disabled"];
1467
- const _hoisted_13$1 = ["disabled"];
1467
+ const _hoisted_13 = ["disabled"];
1468
1468
  const _hoisted_14 = {
1469
1469
  key: 0,
1470
1470
  class: "btn-spinner",
@@ -1511,6 +1511,12 @@ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
1511
1511
  scrollToBottom: () => {
1512
1512
  }
1513
1513
  };
1514
+ const test = () => {
1515
+ aiChatbotX.invokeText("你好");
1516
+ };
1517
+ const test1 = () => {
1518
+ aiChatbotX.abortInvoke();
1519
+ };
1514
1520
  const endpoint = `/sime/proxy/organizations/${aiChatbotX.organizationId()}/agents/${props.agentId}/stream-invoke`;
1515
1521
  const agent = useAgentInvoke({
1516
1522
  endpoint,
@@ -1549,6 +1555,8 @@ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
1549
1555
  class: "command-test",
1550
1556
  "data-theme": currentTheme$1
1551
1557
  }, [
1558
+ createElementVNode("button", { onClick: test }, "测试"),
1559
+ createElementVNode("button", { onClick: test1 }, "测试1"),
1552
1560
  createVNode(Transition, { name: "bubble-fade" }, {
1553
1561
  default: withCtx(() => [
1554
1562
  unref(showBubble) ? (openBlock(), createElementBlock("div", {
@@ -1663,14 +1671,14 @@ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
1663
1671
  "stroke-linejoin": "round"
1664
1672
  }, null, -1)
1665
1673
  ])]))
1666
- ], 8, _hoisted_13$1)
1674
+ ], 8, _hoisted_13)
1667
1675
  ])
1668
1676
  ]);
1669
1677
  };
1670
1678
  }
1671
1679
  });
1672
1680
 
1673
- const commandTest = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["__scopeId", "data-v-5c7468c4"]]);
1681
+ const commandTest = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["__scopeId", "data-v-93ed98f5"]]);
1674
1682
 
1675
1683
  class CommandManager {
1676
1684
  commands = /* @__PURE__ */ new Map();
@@ -1731,7 +1739,8 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
1731
1739
  __name: "sime-provider",
1732
1740
  props: {
1733
1741
  appToken: {},
1734
- organizationId: {}
1742
+ organizationId: {},
1743
+ projectId: {}
1735
1744
  },
1736
1745
  setup(__props) {
1737
1746
  const props = __props;
@@ -1742,6 +1751,9 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
1742
1751
  });
1743
1752
  const stopBroadcastRef = shallowRef(async () => {
1744
1753
  });
1754
+ const voiceAssistantRef = shallowRef(
1755
+ null
1756
+ );
1745
1757
  provide(AiChatbotXKey, {
1746
1758
  appToken: () => props.appToken,
1747
1759
  organizationId: () => props.organizationId,
@@ -1753,6 +1765,9 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
1753
1765
  if (methods.start) startListeningRef.value = methods.start;
1754
1766
  if (methods.stop) stopListeningRef.value = methods.stop;
1755
1767
  },
1768
+ registerVoiceAssistant: (methods) => {
1769
+ voiceAssistantRef.value = methods;
1770
+ },
1756
1771
  getCommads: async () => commandManager.value.getCommands(),
1757
1772
  registerCommand: (cmd) => {
1758
1773
  commandManager.value.registerCommand(cmd);
@@ -1762,6 +1777,12 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
1762
1777
  },
1763
1778
  async executeCommand(commandName, args = []) {
1764
1779
  return await commandManager.value.executeCommand(commandName, args);
1780
+ },
1781
+ invokeText: async (text) => {
1782
+ voiceAssistantRef.value?.agentInvoke(text);
1783
+ },
1784
+ abortInvoke: () => {
1785
+ voiceAssistantRef.value?.agentAbort();
1765
1786
  }
1766
1787
  });
1767
1788
  return (_ctx, _cache) => {
@@ -1777,8 +1798,47 @@ function useTTS(getVoiceConfig) {
1777
1798
  let initPromise = null;
1778
1799
  let audioCtx = null;
1779
1800
  let sentenceBuffer = "";
1780
- const sentenceDelimiters = /[。!?;\n.!?;]/;
1781
- const stripMarkdown = (text) => text.replace(/```[\s\S]*?```/g, "").replace(/\|[^\n]*\|/g, "").replace(/#{1,6}\s*/g, "").replace(/\*\*(.*?)\*\*/g, "$1").replace(/\*(.*?)\*/g, "$1").replace(/`([^`]*)`/g, "$1").replace(/\[([^\]]*)\]\([^)]*\)/g, "$1").replace(/^[-*+]\s+/gm, "").replace(/^>\s+/gm, "").replace(/\s*\+\s*/g, "加").replace(/\s*-\s*/g, "减").replace(/\s*×\s*/g, "乘").replace(/\s*÷\s*/g, "除").replace(/\s*=\s*/g, "等于").replace(/(\d)\.(\d)/g, "$1点$2").replace(/\n{2,}/g, "。").replace(/\n/g, ",").trim();
1801
+ const SENTENCE_DELIMITERS = /[。!?;\n!?;]/;
1802
+ const LEADING_WEAK_PUNCTUATION = /^[\s,、;:,.!?。]+/;
1803
+ const TRAILING_SENTENCE_PUNCTUATION = /[。!?.!?;;]$/;
1804
+ const findSentenceBoundary = (text) => {
1805
+ for (let i = 0; i < text.length; i++) {
1806
+ const char = text[i];
1807
+ if (SENTENCE_DELIMITERS.test(char)) {
1808
+ return i;
1809
+ }
1810
+ }
1811
+ return -1;
1812
+ };
1813
+ const normalizeNumbers = (text) => {
1814
+ return text.replace(/(-?\d[\d,]*\.?\d*)\s*%/g, (_, num) => {
1815
+ const cleanNum = num.replace(/,/g, "");
1816
+ const n = parseFloat(cleanNum);
1817
+ const spoken = cleanNum.replace(".", "点");
1818
+ if (n < 0) return `负百分之${spoken.replace("-", "")}`;
1819
+ return `百分之${spoken}`;
1820
+ }).replace(/(-?\d[\d,]*)\.(\d+)/g, (_, intPart, decPart) => {
1821
+ const cleanInt = intPart.replace(/,/g, "");
1822
+ if (cleanInt.startsWith("-")) {
1823
+ return `负${cleanInt.slice(1)}点${decPart}`;
1824
+ }
1825
+ return `${cleanInt}点${decPart}`;
1826
+ }).replace(/-(\d)/g, "负$1");
1827
+ };
1828
+ const stripMarkdown = (text) => {
1829
+ let result = text.replace(/```[\s\S]*?```/g, "").replace(/\|[^\n]*\|/g, "").replace(/#{1,6}\s*/g, "").replace(/\*\*(.*?)\*\*/g, "$1").replace(/\*(.*?)\*/g, "$1").replace(/`([^`]*)`/g, "$1").replace(/\[([^\]]*)\]\([^)]*\)/g, "$1").replace(/^[-*+]\s+/gm, "").replace(/^>\s+/gm, "");
1830
+ result = normalizeNumbers(result);
1831
+ result = result.replace(/\s*\+\s*(?=\d)/g, "加").replace(/\s*\+\s*/g, "加").replace(/\s*-\s*(?=\d)/g, "减").replace(/\s*-\s*/g, "减").replace(/\s*×\s*/g, "乘").replace(/\s*÷\s*/g, "除").replace(/\s*=\s*/g, "等于").replace(/\n{2,}/g, "。").replace(/\n/g, ",").trim();
1832
+ return result;
1833
+ };
1834
+ const normalizeSpeakText = (text, options) => {
1835
+ const clean = stripMarkdown(text).replace(LEADING_WEAK_PUNCTUATION, "").trim();
1836
+ if (!clean) return "";
1837
+ if (options?.isFinalChunk && !TRAILING_SENTENCE_PUNCTUATION.test(clean)) {
1838
+ return `${clean}。`;
1839
+ }
1840
+ return clean;
1841
+ };
1782
1842
  const warmUpAudio = () => {
1783
1843
  if (!audioCtx || audioCtx.state === "closed") {
1784
1844
  try {
@@ -1847,7 +1907,7 @@ function useTTS(getVoiceConfig) {
1847
1907
  return initPromise;
1848
1908
  };
1849
1909
  const speak = async (text) => {
1850
- const clean = stripMarkdown(text);
1910
+ const clean = normalizeSpeakText(text);
1851
1911
  if (!clean.trim()) return;
1852
1912
  hasPendingAudio.value = true;
1853
1913
  const tts = await ensureInstance();
@@ -1861,17 +1921,20 @@ function useTTS(getVoiceConfig) {
1861
1921
  const feed = (delta) => {
1862
1922
  sentenceBuffer += delta;
1863
1923
  while (true) {
1864
- const match = sentenceBuffer.match(sentenceDelimiters);
1865
- if (!match || match.index === void 0) break;
1866
- const sentence = sentenceBuffer.slice(0, match.index + 1).trim();
1867
- sentenceBuffer = sentenceBuffer.slice(match.index + 1);
1924
+ const boundaryIndex = findSentenceBoundary(sentenceBuffer);
1925
+ if (boundaryIndex === -1) break;
1926
+ const sentence = sentenceBuffer.slice(0, boundaryIndex + 1).trim();
1927
+ sentenceBuffer = sentenceBuffer.slice(boundaryIndex + 1);
1868
1928
  if (sentence.length > 0) speak(sentence);
1869
1929
  }
1870
1930
  };
1871
1931
  const flush = () => {
1872
1932
  const remaining = sentenceBuffer.trim();
1873
1933
  sentenceBuffer = "";
1874
- if (remaining.length > 0) speak(remaining);
1934
+ if (remaining.length > 0) {
1935
+ const clean = normalizeSpeakText(remaining, { isFinalChunk: true });
1936
+ if (clean) void speak(clean);
1937
+ }
1875
1938
  };
1876
1939
  const stop = () => {
1877
1940
  sentenceBuffer = "";
@@ -2187,12 +2250,8 @@ const _hoisted_10 = {
2187
2250
  key: 2,
2188
2251
  class: "agent-text"
2189
2252
  };
2190
- const _hoisted_11 = {
2191
- key: 0,
2192
- class: "status-pill"
2193
- };
2194
- const _hoisted_12 = { class: "fab-avatar-wrapper" };
2195
- const _hoisted_13 = ["src"];
2253
+ const _hoisted_11 = { class: "fab-avatar-wrapper" };
2254
+ const _hoisted_12 = ["src"];
2196
2255
  const currentTheme = "dark";
2197
2256
  const _sfc_main = /* @__PURE__ */ defineComponent({
2198
2257
  __name: "voice-assistant",
@@ -2281,13 +2340,17 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
2281
2340
  tts.warmUpAudio();
2282
2341
  await voice.toggleVoiceMode(targetState);
2283
2342
  };
2284
- const { voiceStatus, transcriptionText, wakeAnimating, isTranscribing } = voice;
2343
+ const { voiceStatus, wakeAnimating, isTranscribing } = voice;
2285
2344
  const { isInvoking, currentTextContent, currentToolParts, executingTools, hasAnyContent, toolDisplayName } = agent;
2286
2345
  aiChatbotX?.registerVoiceMethods({
2287
2346
  stopBroadcast: async () => interruptCurrentResponse(),
2288
2347
  start: () => toggleVoiceMode(true),
2289
2348
  stop: () => toggleVoiceMode(false)
2290
2349
  });
2350
+ aiChatbotX?.registerVoiceAssistant({
2351
+ agentInvoke: agent.invoke,
2352
+ agentAbort: agent.abort
2353
+ });
2291
2354
  onBeforeUnmount(async () => {
2292
2355
  bubble.destroy();
2293
2356
  agent.abort();
@@ -2375,15 +2438,14 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
2375
2438
  class: "assistant-fab",
2376
2439
  onClick: _cache[0] || (_cache[0] = ($event) => toggleVoiceMode())
2377
2440
  }, [
2378
- unref(transcriptionText) || unref(isInvoking) ? (openBlock(), createElementBlock("div", _hoisted_11, toDisplayString(unref(isInvoking) ? "正在思考中..." : unref(transcriptionText)), 1)) : createCommentVNode("", true),
2379
- createElementVNode("div", _hoisted_12, [
2441
+ createElementVNode("div", _hoisted_11, [
2380
2442
  createElementVNode("img", {
2381
2443
  src: __props.xLogo ? __props.xLogo : "/x.png",
2382
2444
  alt: "voice assistant",
2383
2445
  style: normalizeStyle({
2384
2446
  width: `${__props.xSize?.width || 88}px`
2385
2447
  })
2386
- }, null, 12, _hoisted_13),
2448
+ }, null, 12, _hoisted_12),
2387
2449
  createVNode(Transition, { name: "indicator-fade" }, {
2388
2450
  default: withCtx(() => [
2389
2451
  unref(voiceStatus) === "listening" ? (openBlock(), createElementBlock("div", {
@@ -2425,7 +2487,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
2425
2487
  }
2426
2488
  });
2427
2489
 
2428
- const voiceAssistant = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-59d72f34"]]);
2490
+ const voiceAssistant = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-d1d9b351"]]);
2429
2491
 
2430
2492
  var clientCommandKey = /* @__PURE__ */ ((clientCommandKey2) => {
2431
2493
  clientCommandKey2["SET_THEME"] = "SiMeAgent_setTheme";