@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.
- package/dist/sime-x-vue.mjs +95 -16
- package/dist/sime-x-vue.mjs.map +1 -1
- package/dist/sime-x-vue.umd.js +95 -16
- package/dist/sime-x-vue.umd.js.map +1 -1
- package/dist/style.css +109 -109
- package/package.json +1 -1
- package/types/composables/use-tts.d.ts +1 -0
package/dist/sime-x-vue.umd.js
CHANGED
|
@@ -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$
|
|
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$
|
|
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
|
-
|
|
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-
|
|
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 = {
|
|
2259
|
-
|
|
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
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
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
|
|
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.
|
|
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,
|
|
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-
|
|
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";
|