@siact/sime-x-vue 0.0.20 → 0.0.22

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.
@@ -107,7 +107,7 @@
107
107
  const _hoisted_10$2 = { class: "ai-chat__messages-inner" };
108
108
  const _hoisted_11$2 = { class: "ai-chat__message-content" };
109
109
  const _hoisted_12$2 = ["innerHTML"];
110
- const _hoisted_13$1 = {
110
+ const _hoisted_13$2 = {
111
111
  key: 1,
112
112
  class: "ai-chat__reasoning"
113
113
  };
@@ -470,7 +470,7 @@
470
470
  innerHTML: renderMarkdown(part.text)
471
471
  }, null, 8, _hoisted_12$2)
472
472
  ])
473
- ], 2)) : part.type === "reasoning" ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_13$1, [
473
+ ], 2)) : part.type === "reasoning" ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_13$2, [
474
474
  vue.createElementVNode("button", {
475
475
  class: "ai-chat__reasoning-trigger",
476
476
  onClick: ($event) => toggleReasoning(message.id)
@@ -1465,7 +1465,7 @@
1465
1465
  };
1466
1466
  const _hoisted_11$1 = { class: "input-bar" };
1467
1467
  const _hoisted_12$1 = ["disabled"];
1468
- const _hoisted_13 = ["disabled"];
1468
+ const _hoisted_13$1 = ["disabled"];
1469
1469
  const _hoisted_14 = {
1470
1470
  key: 0,
1471
1471
  class: "btn-spinner",
@@ -1513,7 +1513,15 @@
1513
1513
  }
1514
1514
  };
1515
1515
  const test = () => {
1516
- aiChatbotX.speakText("你好,世界,今天是想起五天气横扫的缺点");
1516
+ [
1517
+ "1你好,世界,今天是想起五天气横扫的缺点",
1518
+ "2你好,世界,今天是想起五天气横扫的缺点",
1519
+ "3你好,世界,今天是想起五天气横扫的缺点"
1520
+ ].forEach((text, index) => {
1521
+ setTimeout(() => {
1522
+ aiChatbotX.speakText(text);
1523
+ }, index * 1e3);
1524
+ });
1517
1525
  };
1518
1526
  const test1 = () => {
1519
1527
  aiChatbotX.abortInvoke();
@@ -1672,14 +1680,14 @@
1672
1680
  "stroke-linejoin": "round"
1673
1681
  }, null, -1)
1674
1682
  ])]))
1675
- ], 8, _hoisted_13)
1683
+ ], 8, _hoisted_13$1)
1676
1684
  ])
1677
1685
  ]);
1678
1686
  };
1679
1687
  }
1680
1688
  });
1681
1689
 
1682
- const commandTest = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["__scopeId", "data-v-2d2cea1f"]]);
1690
+ const commandTest = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["__scopeId", "data-v-36096054"]]);
1683
1691
 
1684
1692
  class CommandManager {
1685
1693
  commands = /* @__PURE__ */ new Map();
@@ -1923,6 +1931,37 @@
1923
1931
  console.error("[TTS] speak 失败:", err);
1924
1932
  }
1925
1933
  };
1934
+ const speakAndWait = async (text) => {
1935
+ const clean = normalizeSpeakText(text);
1936
+ if (!clean.trim()) return;
1937
+ hasPendingAudio.value = true;
1938
+ const ttsInst = await ensureInstance();
1939
+ if (!ttsInst) {
1940
+ hasPendingAudio.value = false;
1941
+ return;
1942
+ }
1943
+ return new Promise((resolve) => {
1944
+ let settled = false;
1945
+ const settle = () => {
1946
+ if (settled) return;
1947
+ settled = true;
1948
+ clearTimeout(safetyTimer);
1949
+ onQueueEmptyCb = null;
1950
+ resolve();
1951
+ };
1952
+ const safetyTimer = setTimeout(() => {
1953
+ console.warn("[TTS] speakAndWait 安全超时,强制 resolve");
1954
+ settle();
1955
+ }, 6e4);
1956
+ onQueueEmptyCb = settle;
1957
+ try {
1958
+ ttsInst.speak(clean);
1959
+ } catch (err) {
1960
+ console.error("[TTS] speak 失败:", err);
1961
+ settle();
1962
+ }
1963
+ });
1964
+ };
1926
1965
  const feed = (delta) => {
1927
1966
  sentenceBuffer += delta;
1928
1967
  while (true) {
@@ -1945,6 +1984,11 @@
1945
1984
  sentenceBuffer = "";
1946
1985
  isSpeaking.value = false;
1947
1986
  hasPendingAudio.value = false;
1987
+ if (onQueueEmptyCb) {
1988
+ const cb = onQueueEmptyCb;
1989
+ onQueueEmptyCb = null;
1990
+ cb();
1991
+ }
1948
1992
  if (instance) {
1949
1993
  try {
1950
1994
  instance.stop();
@@ -1977,6 +2021,7 @@
1977
2021
  hasPendingAudio,
1978
2022
  warmUpAudio,
1979
2023
  speak,
2024
+ speakAndWait,
1980
2025
  feed,
1981
2026
  flush,
1982
2027
  stop,
@@ -2255,8 +2300,12 @@
2255
2300
  key: 2,
2256
2301
  class: "agent-text"
2257
2302
  };
2258
- const _hoisted_11 = { class: "fab-avatar-wrapper" };
2259
- const _hoisted_12 = ["src"];
2303
+ const _hoisted_11 = {
2304
+ key: 0,
2305
+ class: "status-pill"
2306
+ };
2307
+ const _hoisted_12 = { class: "fab-avatar-wrapper" };
2308
+ const _hoisted_13 = ["src"];
2260
2309
  const currentTheme = "dark";
2261
2310
  const _sfc_main = /* @__PURE__ */ vue.defineComponent({
2262
2311
  __name: "voice-assistant",
@@ -2327,10 +2376,39 @@
2327
2376
  tts.stop();
2328
2377
  bubble.hide();
2329
2378
  };
2379
+ const speakQueue = [];
2380
+ let isProcessingSpeakQueue = false;
2381
+ const processSpeakQueue = async () => {
2382
+ if (isProcessingSpeakQueue) return;
2383
+ isProcessingSpeakQueue = true;
2384
+ tts.hasPendingAudio.value = true;
2385
+ while (speakQueue.length > 0) {
2386
+ const text = speakQueue.shift();
2387
+ bubble.open();
2388
+ agent.currentTextContent.value = text;
2389
+ try {
2390
+ await tts.speakAndWait(text);
2391
+ } catch (e) {
2392
+ console.error("[speakQueue] 播报失败:", e);
2393
+ }
2394
+ if (speakQueue.length > 0) {
2395
+ tts.hasPendingAudio.value = true;
2396
+ }
2397
+ }
2398
+ isProcessingSpeakQueue = false;
2399
+ tts.hasPendingAudio.value = false;
2400
+ bubble.scheduleDismiss();
2401
+ };
2330
2402
  const speakTextWithBubble = (text) => {
2331
- bubble.open();
2332
- agent.currentTextContent.value = text;
2333
- tts.speak(text);
2403
+ speakQueue.push(text);
2404
+ if (!isProcessingSpeakQueue) {
2405
+ processSpeakQueue();
2406
+ }
2407
+ };
2408
+ const stopSpeak = () => {
2409
+ speakQueue.length = 0;
2410
+ isProcessingSpeakQueue = false;
2411
+ tts.stop();
2334
2412
  };
2335
2413
  const voice = useVoiceRecognition({
2336
2414
  modelPath: props.modelPath,
@@ -2350,7 +2428,7 @@
2350
2428
  tts.warmUpAudio();
2351
2429
  await voice.toggleVoiceMode(targetState);
2352
2430
  };
2353
- const { voiceStatus, wakeAnimating, isTranscribing } = voice;
2431
+ const { voiceStatus, transcriptionText, wakeAnimating, isTranscribing } = voice;
2354
2432
  const { isInvoking, currentTextContent, currentToolParts, executingTools, hasAnyContent, toolDisplayName } = agent;
2355
2433
  aiChatbotX?.registerVoiceMethods({
2356
2434
  stopBroadcast: async () => interruptCurrentResponse(),
@@ -2361,7 +2439,7 @@
2361
2439
  agentInvoke: agent.invoke,
2362
2440
  agentAbort: agent.abort,
2363
2441
  speakText: speakTextWithBubble,
2364
- stopSpeak: tts.stop
2442
+ stopSpeak
2365
2443
  });
2366
2444
  vue.onBeforeUnmount(async () => {
2367
2445
  bubble.destroy();
@@ -2450,14 +2528,15 @@
2450
2528
  class: "assistant-fab",
2451
2529
  onClick: _cache[0] || (_cache[0] = ($event) => toggleVoiceMode())
2452
2530
  }, [
2453
- vue.createElementVNode("div", _hoisted_11, [
2531
+ vue.unref(transcriptionText) || vue.unref(isInvoking) ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_11, vue.toDisplayString(vue.unref(isInvoking) ? "正在思考中..." : vue.unref(transcriptionText)), 1)) : vue.createCommentVNode("", true),
2532
+ vue.createElementVNode("div", _hoisted_12, [
2454
2533
  vue.createElementVNode("img", {
2455
2534
  src: __props.xLogo ? __props.xLogo : "/x.png",
2456
2535
  alt: "voice assistant",
2457
2536
  style: vue.normalizeStyle({
2458
2537
  width: `${__props.xSize?.width || 88}px`
2459
2538
  })
2460
- }, null, 12, _hoisted_12),
2539
+ }, null, 12, _hoisted_13),
2461
2540
  vue.createVNode(vue.Transition, { name: "indicator-fade" }, {
2462
2541
  default: vue.withCtx(() => [
2463
2542
  vue.unref(voiceStatus) === "listening" ? (vue.openBlock(), vue.createElementBlock("div", {
@@ -2499,7 +2578,7 @@
2499
2578
  }
2500
2579
  });
2501
2580
 
2502
- const voiceAssistant = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-5f5506a2"]]);
2581
+ const voiceAssistant = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-d15c792e"]]);
2503
2582
 
2504
2583
  var clientCommandKey = /* @__PURE__ */ ((clientCommandKey2) => {
2505
2584
  clientCommandKey2["SET_THEME"] = "SiMeAgent_setTheme";