@fv-ui/ai-chat 0.1.1 → 0.2.0
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/README.md +746 -741
- package/dist/index.d.ts +27 -12
- package/dist/style.css +1 -1
- package/es/index.mjs +432 -149
- package/lib/index.js +432 -149
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -1542,8 +1542,8 @@
|
|
|
1542
1542
|
}
|
|
1543
1543
|
}
|
|
1544
1544
|
|
|
1545
|
-
const _hoisted_1$
|
|
1546
|
-
var _sfc_main$
|
|
1545
|
+
const _hoisted_1$i = ["innerHTML"];
|
|
1546
|
+
var _sfc_main$i = /* @__PURE__ */ vue.defineComponent({
|
|
1547
1547
|
...{ name: "FvMarkdown" },
|
|
1548
1548
|
__name: "index",
|
|
1549
1549
|
props: {
|
|
@@ -1566,12 +1566,12 @@
|
|
|
1566
1566
|
return vue.openBlock(), vue.createElementBlock("div", {
|
|
1567
1567
|
class: "fv-xmarkdown markdown-body",
|
|
1568
1568
|
innerHTML: html.value
|
|
1569
|
-
}, null, 8, _hoisted_1$
|
|
1569
|
+
}, null, 8, _hoisted_1$i);
|
|
1570
1570
|
};
|
|
1571
1571
|
}
|
|
1572
1572
|
});
|
|
1573
1573
|
|
|
1574
|
-
const _hoisted_1$
|
|
1574
|
+
const _hoisted_1$h = {
|
|
1575
1575
|
key: 1,
|
|
1576
1576
|
class: "fv-typewriter-text"
|
|
1577
1577
|
};
|
|
@@ -1579,7 +1579,7 @@
|
|
|
1579
1579
|
key: 0,
|
|
1580
1580
|
class: "fv-typewriter-suffix"
|
|
1581
1581
|
};
|
|
1582
|
-
var _sfc_main$
|
|
1582
|
+
var _sfc_main$h = /* @__PURE__ */ vue.defineComponent({
|
|
1583
1583
|
...{ name: "FvTypewriter" },
|
|
1584
1584
|
__name: "index",
|
|
1585
1585
|
props: {
|
|
@@ -1669,11 +1669,11 @@
|
|
|
1669
1669
|
},
|
|
1670
1670
|
[
|
|
1671
1671
|
vue.createCommentVNode(" markdown \u6A21\u5F0F:suffix \u4E0D\u8FFD\u52A0(element-plus-x \u884C\u4E3A),isTyping \u900F\u4F20\u7ED9 XMarkdown \u4F5C\u6837\u5F0F\u94A9\u5B50 "),
|
|
1672
|
-
__props.isMarkdown ? (vue.openBlock(), vue.createBlock(_sfc_main$
|
|
1672
|
+
__props.isMarkdown ? (vue.openBlock(), vue.createBlock(_sfc_main$i, {
|
|
1673
1673
|
key: 0,
|
|
1674
1674
|
content: renderedContent.value,
|
|
1675
1675
|
"is-typing": isTyping.value
|
|
1676
|
-
}, null, 8, ["content", "is-typing"])) : (vue.openBlock(), vue.createElementBlock("span", _hoisted_1$
|
|
1676
|
+
}, null, 8, ["content", "is-typing"])) : (vue.openBlock(), vue.createElementBlock("span", _hoisted_1$h, [
|
|
1677
1677
|
vue.createTextVNode(
|
|
1678
1678
|
vue.toDisplayString(renderedContent.value),
|
|
1679
1679
|
1
|
|
@@ -1708,7 +1708,7 @@
|
|
|
1708
1708
|
}
|
|
1709
1709
|
});
|
|
1710
1710
|
|
|
1711
|
-
const _hoisted_1$
|
|
1711
|
+
const _hoisted_1$g = {
|
|
1712
1712
|
key: 0,
|
|
1713
1713
|
class: "fv-bubble-avatar"
|
|
1714
1714
|
};
|
|
@@ -1729,7 +1729,7 @@
|
|
|
1729
1729
|
key: 1,
|
|
1730
1730
|
class: "fv-bubble-footer"
|
|
1731
1731
|
};
|
|
1732
|
-
var _sfc_main$
|
|
1732
|
+
var _sfc_main$g = /* @__PURE__ */ vue.defineComponent({
|
|
1733
1733
|
...{ name: "FvBubble" },
|
|
1734
1734
|
__name: "index",
|
|
1735
1735
|
props: {
|
|
@@ -1796,7 +1796,7 @@
|
|
|
1796
1796
|
},
|
|
1797
1797
|
[
|
|
1798
1798
|
vue.createCommentVNode(" \u5934\u50CF:placement \u540C\u7F18\u6392\u5217(end \u7ECF row-reverse \u7FFB\u8F6C\u5230\u53F3\u4FA7),#avatar \u63D2\u69FD\u4F18\u5148 "),
|
|
1799
|
-
_ctx.$slots.avatar || __props.avatar || __props.avatarIcon ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1$
|
|
1799
|
+
_ctx.$slots.avatar || __props.avatar || __props.avatarIcon ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1$g, [
|
|
1800
1800
|
_ctx.$slots.avatar ? vue.renderSlot(_ctx.$slots, "avatar", {}, void 0, void 0, 0) : (vue.openBlock(), vue.createBlock(vue.unref(elementPlus.ElAvatar), {
|
|
1801
1801
|
key: 1,
|
|
1802
1802
|
size: __props.avatarSize || void 0,
|
|
@@ -1854,7 +1854,7 @@
|
|
|
1854
1854
|
{ key: 2 },
|
|
1855
1855
|
[
|
|
1856
1856
|
vue.createCommentVNode(" typing \u900F\u4F20 Typewriter;\u975E typing:isMarkdown \u2192 XMarkdown,\u5426\u5219\u7EAF\u6587\u672C "),
|
|
1857
|
-
vue.createVNode(_sfc_main$
|
|
1857
|
+
vue.createVNode(_sfc_main$h, {
|
|
1858
1858
|
ref_key: "twRef",
|
|
1859
1859
|
ref: twRef,
|
|
1860
1860
|
content: __props.content,
|
|
@@ -1868,7 +1868,7 @@
|
|
|
1868
1868
|
],
|
|
1869
1869
|
2112
|
|
1870
1870
|
/* STABLE_FRAGMENT, DEV_ROOT_FRAGMENT */
|
|
1871
|
-
)) : __props.isMarkdown ? (vue.openBlock(), vue.createBlock(_sfc_main$
|
|
1871
|
+
)) : __props.isMarkdown ? (vue.openBlock(), vue.createBlock(_sfc_main$i, {
|
|
1872
1872
|
key: 3,
|
|
1873
1873
|
content: __props.content
|
|
1874
1874
|
}, null, 8, ["content"])) : (vue.openBlock(), vue.createElementBlock(
|
|
@@ -1894,8 +1894,8 @@
|
|
|
1894
1894
|
}
|
|
1895
1895
|
});
|
|
1896
1896
|
|
|
1897
|
-
const _hoisted_1$
|
|
1898
|
-
var _sfc_main$
|
|
1897
|
+
const _hoisted_1$f = { class: "fv-bubble-list" };
|
|
1898
|
+
var _sfc_main$f = /* @__PURE__ */ vue.defineComponent({
|
|
1899
1899
|
...{ name: "FvBubbleList" },
|
|
1900
1900
|
__name: "index",
|
|
1901
1901
|
props: {
|
|
@@ -1995,7 +1995,7 @@
|
|
|
1995
1995
|
}));
|
|
1996
1996
|
__expose({ scrollToTop, scrollToBottom, scrollToBubble });
|
|
1997
1997
|
return (_ctx, _cache) => {
|
|
1998
|
-
return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$
|
|
1998
|
+
return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$f, [
|
|
1999
1999
|
vue.createElementVNode(
|
|
2000
2000
|
"div",
|
|
2001
2001
|
{
|
|
@@ -2010,7 +2010,7 @@
|
|
|
2010
2010
|
vue.Fragment,
|
|
2011
2011
|
null,
|
|
2012
2012
|
vue.renderList(__props.list, (item, index) => {
|
|
2013
|
-
return vue.openBlock(), vue.createBlock(_sfc_main$
|
|
2013
|
+
return vue.openBlock(), vue.createBlock(_sfc_main$g, vue.mergeProps({
|
|
2014
2014
|
key: item.key,
|
|
2015
2015
|
ref_for: true,
|
|
2016
2016
|
ref: (el) => setBubbleRef(el, index)
|
|
@@ -2118,6 +2118,139 @@
|
|
|
2118
2118
|
}
|
|
2119
2119
|
});
|
|
2120
2120
|
|
|
2121
|
+
const _hoisted_1$e = {
|
|
2122
|
+
class: "fv-stop-icon",
|
|
2123
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2124
|
+
viewBox: "0 0 24 24",
|
|
2125
|
+
width: "1em",
|
|
2126
|
+
height: "1em",
|
|
2127
|
+
"aria-hidden": "true",
|
|
2128
|
+
focusable: "false"
|
|
2129
|
+
};
|
|
2130
|
+
var _sfc_main$e = /* @__PURE__ */ vue.defineComponent({
|
|
2131
|
+
...{ name: "FvStopIcon" },
|
|
2132
|
+
__name: "StopIcon",
|
|
2133
|
+
setup(__props) {
|
|
2134
|
+
return (_ctx, _cache) => {
|
|
2135
|
+
return vue.openBlock(), vue.createElementBlock("svg", _hoisted_1$e, [..._cache[0] || (_cache[0] = [
|
|
2136
|
+
vue.createElementVNode(
|
|
2137
|
+
"rect",
|
|
2138
|
+
{
|
|
2139
|
+
x: "5.5",
|
|
2140
|
+
y: "5.5",
|
|
2141
|
+
width: "13",
|
|
2142
|
+
height: "13",
|
|
2143
|
+
rx: "2.5",
|
|
2144
|
+
fill: "currentColor"
|
|
2145
|
+
},
|
|
2146
|
+
null,
|
|
2147
|
+
-1
|
|
2148
|
+
/* CACHED */
|
|
2149
|
+
)
|
|
2150
|
+
])]);
|
|
2151
|
+
};
|
|
2152
|
+
}
|
|
2153
|
+
});
|
|
2154
|
+
|
|
2155
|
+
function getSpeechRecognitionCtor() {
|
|
2156
|
+
if (typeof window === "undefined") return void 0;
|
|
2157
|
+
const w = window;
|
|
2158
|
+
const ctor = w.SpeechRecognition ?? w.webkitSpeechRecognition;
|
|
2159
|
+
return typeof ctor === "function" ? ctor : void 0;
|
|
2160
|
+
}
|
|
2161
|
+
function useRecord() {
|
|
2162
|
+
const isRecording = vue.ref(false);
|
|
2163
|
+
const text = vue.ref("");
|
|
2164
|
+
const audioUrl = vue.ref(null);
|
|
2165
|
+
const error = vue.ref(null);
|
|
2166
|
+
let mediaStream = null;
|
|
2167
|
+
let mediaRecorder = null;
|
|
2168
|
+
let chunks = [];
|
|
2169
|
+
let recognition = null;
|
|
2170
|
+
let finalText = "";
|
|
2171
|
+
function revokeAudioUrl() {
|
|
2172
|
+
if (audioUrl.value) {
|
|
2173
|
+
URL.revokeObjectURL(audioUrl.value);
|
|
2174
|
+
audioUrl.value = null;
|
|
2175
|
+
}
|
|
2176
|
+
}
|
|
2177
|
+
async function start() {
|
|
2178
|
+
if (isRecording.value) return;
|
|
2179
|
+
error.value = null;
|
|
2180
|
+
text.value = "";
|
|
2181
|
+
finalText = "";
|
|
2182
|
+
chunks = [];
|
|
2183
|
+
revokeAudioUrl();
|
|
2184
|
+
if (typeof MediaRecorder === "undefined" || !navigator.mediaDevices?.getUserMedia) {
|
|
2185
|
+
error.value = new Error("\u5F53\u524D\u73AF\u5883\u4E0D\u652F\u6301\u97F3\u9891\u5F55\u5236");
|
|
2186
|
+
return;
|
|
2187
|
+
}
|
|
2188
|
+
try {
|
|
2189
|
+
mediaStream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
2190
|
+
} catch (e) {
|
|
2191
|
+
error.value = e instanceof Error ? e : new Error(String(e));
|
|
2192
|
+
return;
|
|
2193
|
+
}
|
|
2194
|
+
mediaRecorder = new MediaRecorder(mediaStream);
|
|
2195
|
+
mediaRecorder.ondataavailable = (e) => {
|
|
2196
|
+
if (e.data && e.data.size > 0) chunks.push(e.data);
|
|
2197
|
+
};
|
|
2198
|
+
mediaRecorder.onstop = () => {
|
|
2199
|
+
if (chunks.length > 0) {
|
|
2200
|
+
const blob = new Blob(chunks, { type: mediaRecorder?.mimeType || "audio/webm" });
|
|
2201
|
+
audioUrl.value = URL.createObjectURL(blob);
|
|
2202
|
+
}
|
|
2203
|
+
mediaStream?.getTracks().forEach((t) => t.stop());
|
|
2204
|
+
mediaStream = null;
|
|
2205
|
+
};
|
|
2206
|
+
const SRCtor = getSpeechRecognitionCtor();
|
|
2207
|
+
if (SRCtor) {
|
|
2208
|
+
try {
|
|
2209
|
+
recognition = new SRCtor();
|
|
2210
|
+
recognition.continuous = true;
|
|
2211
|
+
recognition.interimResults = true;
|
|
2212
|
+
recognition.onresult = (event) => {
|
|
2213
|
+
let interim = "";
|
|
2214
|
+
for (let i = event.resultIndex; i < event.results.length; i++) {
|
|
2215
|
+
const r = event.results[i];
|
|
2216
|
+
if (r.isFinal) finalText += r[0].transcript;
|
|
2217
|
+
else interim += r[0].transcript;
|
|
2218
|
+
}
|
|
2219
|
+
text.value = finalText + interim;
|
|
2220
|
+
};
|
|
2221
|
+
recognition.onerror = (ev) => {
|
|
2222
|
+
error.value = new Error(`\u8BED\u97F3\u8BC6\u522B\u9519\u8BEF: ${ev?.error ?? "unknown"}`);
|
|
2223
|
+
};
|
|
2224
|
+
recognition.start();
|
|
2225
|
+
} catch {
|
|
2226
|
+
recognition = null;
|
|
2227
|
+
}
|
|
2228
|
+
}
|
|
2229
|
+
mediaRecorder.start();
|
|
2230
|
+
isRecording.value = true;
|
|
2231
|
+
}
|
|
2232
|
+
function stop() {
|
|
2233
|
+
if (!isRecording.value) return;
|
|
2234
|
+
isRecording.value = false;
|
|
2235
|
+
try {
|
|
2236
|
+
recognition?.stop();
|
|
2237
|
+
} catch {
|
|
2238
|
+
}
|
|
2239
|
+
recognition = null;
|
|
2240
|
+
try {
|
|
2241
|
+
if (mediaRecorder && mediaRecorder.state !== "inactive") mediaRecorder.stop();
|
|
2242
|
+
} catch {
|
|
2243
|
+
}
|
|
2244
|
+
}
|
|
2245
|
+
if (vue.getCurrentInstance()) {
|
|
2246
|
+
vue.onBeforeUnmount(() => {
|
|
2247
|
+
stop();
|
|
2248
|
+
revokeAudioUrl();
|
|
2249
|
+
});
|
|
2250
|
+
}
|
|
2251
|
+
return { start, stop, isRecording, text, audioUrl, error };
|
|
2252
|
+
}
|
|
2253
|
+
|
|
2121
2254
|
const _hoisted_1$d = {
|
|
2122
2255
|
key: 0,
|
|
2123
2256
|
class: "fv-sender-header"
|
|
@@ -2132,24 +2265,38 @@
|
|
|
2132
2265
|
key: 0,
|
|
2133
2266
|
class: "fv-sender-prefix"
|
|
2134
2267
|
};
|
|
2135
|
-
const _hoisted_6$5 =
|
|
2136
|
-
|
|
2137
|
-
|
|
2268
|
+
const _hoisted_6$5 = {
|
|
2269
|
+
class: "fv-sender-recording-wave",
|
|
2270
|
+
"aria-hidden": "true"
|
|
2271
|
+
};
|
|
2272
|
+
const _hoisted_7$4 = { class: "fv-sender-recording-duration" };
|
|
2273
|
+
const _hoisted_8$3 = ["value", "placeholder", "disabled", "readonly"];
|
|
2274
|
+
const _hoisted_9$2 = {
|
|
2275
|
+
key: 3,
|
|
2138
2276
|
class: "fv-sender-actions"
|
|
2139
2277
|
};
|
|
2140
|
-
const
|
|
2141
|
-
key:
|
|
2278
|
+
const _hoisted_10$2 = {
|
|
2279
|
+
key: 4,
|
|
2142
2280
|
class: "fv-sender-actions"
|
|
2143
2281
|
};
|
|
2144
|
-
const
|
|
2282
|
+
const _hoisted_11$2 = {
|
|
2145
2283
|
key: 0,
|
|
2146
2284
|
class: "fv-sender-action-left"
|
|
2147
2285
|
};
|
|
2148
|
-
const
|
|
2286
|
+
const _hoisted_12$2 = {
|
|
2287
|
+
class: "fv-sender-stop-ring",
|
|
2288
|
+
"aria-hidden": "true"
|
|
2289
|
+
};
|
|
2290
|
+
const _hoisted_13$2 = ["rx"];
|
|
2291
|
+
const _hoisted_14$2 = {
|
|
2149
2292
|
key: 1,
|
|
2150
2293
|
class: "fv-sender-footer"
|
|
2151
2294
|
};
|
|
2152
2295
|
const ROW_HEIGHT = 22;
|
|
2296
|
+
const WAVE_BARS = 48;
|
|
2297
|
+
const RING_HEAD = 10;
|
|
2298
|
+
const RING_TAIL = 40;
|
|
2299
|
+
const RING_LAYERS = 6;
|
|
2153
2300
|
var _sfc_main$d = /* @__PURE__ */ vue.defineComponent({
|
|
2154
2301
|
...{ name: "FvSender" },
|
|
2155
2302
|
__name: "index",
|
|
@@ -2163,6 +2310,8 @@
|
|
|
2163
2310
|
disabled: { type: Boolean, required: false, default: false },
|
|
2164
2311
|
readOnly: { type: Boolean, required: false, default: false },
|
|
2165
2312
|
clearable: { type: Boolean, required: false, default: false },
|
|
2313
|
+
round: { type: Boolean, required: false, default: true },
|
|
2314
|
+
shadow: { type: Boolean, required: false, default: false },
|
|
2166
2315
|
inputWidth: { type: String, required: false, default: "" },
|
|
2167
2316
|
variant: { type: String, required: false, default: "default" },
|
|
2168
2317
|
submitBtnDisabled: { type: Boolean, required: false, default: false },
|
|
@@ -2335,11 +2484,136 @@
|
|
|
2335
2484
|
for (const f of Array.from(files)) emit("paste-file", f);
|
|
2336
2485
|
}
|
|
2337
2486
|
}
|
|
2338
|
-
|
|
2339
|
-
|
|
2487
|
+
const { start: startRecord, stop: stopRecord, isRecording, text: recordText, error: recordError } = useRecord();
|
|
2488
|
+
async function exitRecordingFocusInput() {
|
|
2489
|
+
await vue.nextTick();
|
|
2490
|
+
focus("end");
|
|
2491
|
+
}
|
|
2492
|
+
function insertTextAtCursor(insert) {
|
|
2493
|
+
if (!insert) return;
|
|
2494
|
+
const el = textareaRef.value;
|
|
2495
|
+
const pos = el?.selectionStart ?? value.value.length;
|
|
2496
|
+
const next = value.value.slice(0, pos) + insert + value.value.slice(el?.selectionEnd ?? pos);
|
|
2497
|
+
setValue(next);
|
|
2498
|
+
vue.nextTick(() => {
|
|
2499
|
+
const t = textareaRef.value;
|
|
2500
|
+
if (t) t.setSelectionRange(pos + insert.length, pos + insert.length);
|
|
2501
|
+
});
|
|
2502
|
+
}
|
|
2503
|
+
async function onSpeechClick() {
|
|
2504
|
+
if (isRecording.value) return;
|
|
2505
|
+
await startRecord();
|
|
2506
|
+
if (recordError.value) {
|
|
2507
|
+
elementPlus.ElMessage.error(recordError.value.message || "\u65E0\u6CD5\u8BBF\u95EE\u9EA6\u514B\u98CE");
|
|
2508
|
+
return;
|
|
2509
|
+
}
|
|
2510
|
+
emit("recording-change", true);
|
|
2511
|
+
}
|
|
2512
|
+
async function onRecordConfirm() {
|
|
2513
|
+
stopRecord();
|
|
2514
|
+
emit("recording-change", false);
|
|
2515
|
+
insertTextAtCursor(recordText.value);
|
|
2516
|
+
await exitRecordingFocusInput();
|
|
2340
2517
|
}
|
|
2518
|
+
async function onRecordCancel() {
|
|
2519
|
+
stopRecord();
|
|
2520
|
+
emit("recording-change", false);
|
|
2521
|
+
await exitRecordingFocusInput();
|
|
2522
|
+
}
|
|
2523
|
+
function onRecordingKeydown(e) {
|
|
2524
|
+
if (e.key === "Escape") {
|
|
2525
|
+
e.preventDefault();
|
|
2526
|
+
onRecordCancel();
|
|
2527
|
+
}
|
|
2528
|
+
}
|
|
2529
|
+
const waveLevels = vue.ref(Array(WAVE_BARS).fill(0.04));
|
|
2530
|
+
let audioCtx = null;
|
|
2531
|
+
let analyserSource = null;
|
|
2532
|
+
let waveRafId = 0;
|
|
2533
|
+
function normalizeRms(rms) {
|
|
2534
|
+
const scaled = Math.pow(rms * 10, 1.5);
|
|
2535
|
+
return Math.min(1, Math.max(0.04, scaled));
|
|
2536
|
+
}
|
|
2537
|
+
async function startWaveVisualizer() {
|
|
2538
|
+
if (typeof AudioContext === "undefined" || !navigator.mediaDevices?.getUserMedia) return;
|
|
2539
|
+
try {
|
|
2540
|
+
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
2541
|
+
audioCtx = new AudioContext();
|
|
2542
|
+
analyserSource = audioCtx.createMediaStreamSource(stream);
|
|
2543
|
+
const analyser = audioCtx.createAnalyser();
|
|
2544
|
+
analyser.minDecibels = -45;
|
|
2545
|
+
analyserSource.connect(analyser);
|
|
2546
|
+
const timeData = new Uint8Array(analyser.fftSize);
|
|
2547
|
+
const processFrame = () => {
|
|
2548
|
+
analyser.getByteTimeDomainData(timeData);
|
|
2549
|
+
let sumSquares = 0;
|
|
2550
|
+
for (let i = 0; i < timeData.length; i++) {
|
|
2551
|
+
const v = (timeData[i] - 128) / 128;
|
|
2552
|
+
sumSquares += v * v;
|
|
2553
|
+
}
|
|
2554
|
+
const level = normalizeRms(Math.sqrt(sumSquares / timeData.length));
|
|
2555
|
+
waveLevels.value = [...waveLevels.value.slice(1), level];
|
|
2556
|
+
waveRafId = requestAnimationFrame(processFrame);
|
|
2557
|
+
};
|
|
2558
|
+
waveRafId = requestAnimationFrame(processFrame);
|
|
2559
|
+
stream.getTracks().forEach((t) => t.addEventListener("ended", () => stopWaveVisualizer()));
|
|
2560
|
+
analyserSourceStream = stream;
|
|
2561
|
+
} catch {
|
|
2562
|
+
}
|
|
2563
|
+
}
|
|
2564
|
+
let analyserSourceStream = null;
|
|
2565
|
+
function stopWaveVisualizer() {
|
|
2566
|
+
cancelAnimationFrame(waveRafId);
|
|
2567
|
+
waveRafId = 0;
|
|
2568
|
+
analyserSource?.disconnect();
|
|
2569
|
+
analyserSource = null;
|
|
2570
|
+
analyserSourceStream?.getTracks().forEach((t) => t.stop());
|
|
2571
|
+
analyserSourceStream = null;
|
|
2572
|
+
audioCtx?.close().catch(() => {
|
|
2573
|
+
});
|
|
2574
|
+
audioCtx = null;
|
|
2575
|
+
waveLevels.value = Array(WAVE_BARS).fill(0.04);
|
|
2576
|
+
}
|
|
2577
|
+
vue.watch(isRecording, (rec) => {
|
|
2578
|
+
if (rec) startWaveVisualizer();
|
|
2579
|
+
else stopWaveVisualizer();
|
|
2580
|
+
});
|
|
2581
|
+
const recordSeconds = vue.ref(0);
|
|
2582
|
+
let recordTimer = null;
|
|
2583
|
+
vue.watch(isRecording, (rec) => {
|
|
2584
|
+
if (rec) {
|
|
2585
|
+
recordSeconds.value = 0;
|
|
2586
|
+
recordTimer = setInterval(() => {
|
|
2587
|
+
recordSeconds.value++;
|
|
2588
|
+
}, 1e3);
|
|
2589
|
+
} else if (recordTimer) {
|
|
2590
|
+
clearInterval(recordTimer);
|
|
2591
|
+
recordTimer = null;
|
|
2592
|
+
}
|
|
2593
|
+
});
|
|
2594
|
+
const recordDuration = vue.computed(() => {
|
|
2595
|
+
const m = Math.floor(recordSeconds.value / 60);
|
|
2596
|
+
const s = recordSeconds.value % 60;
|
|
2597
|
+
return `${m}:${String(s).padStart(2, "0")}`;
|
|
2598
|
+
});
|
|
2599
|
+
vue.onBeforeUnmount(() => {
|
|
2600
|
+
stopWaveVisualizer();
|
|
2601
|
+
if (recordTimer) clearInterval(recordTimer);
|
|
2602
|
+
});
|
|
2341
2603
|
const inputDisabled = vue.computed(() => props.disabled || props.loading);
|
|
2342
2604
|
const inputReadonly = vue.computed(() => props.readOnly);
|
|
2605
|
+
const ringLayers = vue.computed(
|
|
2606
|
+
() => Array.from({ length: RING_LAYERS }, (_, i) => {
|
|
2607
|
+
const len = RING_HEAD + RING_TAIL * i / (RING_LAYERS - 1);
|
|
2608
|
+
const alpha = 0.9 * Math.pow(0.72, i);
|
|
2609
|
+
return {
|
|
2610
|
+
style: {
|
|
2611
|
+
"--ring-len": len.toFixed(2),
|
|
2612
|
+
"--ring-alpha": alpha.toFixed(3)
|
|
2613
|
+
}
|
|
2614
|
+
};
|
|
2615
|
+
})
|
|
2616
|
+
);
|
|
2343
2617
|
const slots = vue.useSlots();
|
|
2344
2618
|
const hasActionListSlot = vue.computed(() => !!slots["action-list"]);
|
|
2345
2619
|
__expose({ submit, cancel, clear, focus, blur, openHeader, closeHeader });
|
|
@@ -2347,7 +2621,7 @@
|
|
|
2347
2621
|
return vue.openBlock(), vue.createElementBlock(
|
|
2348
2622
|
"div",
|
|
2349
2623
|
{
|
|
2350
|
-
class: vue.normalizeClass(["fv-sender", [`variant-${__props.variant}`, { "is-disabled": __props.disabled, "is-loading": __props.loading, "is-focused": isFocused.value }]])
|
|
2624
|
+
class: vue.normalizeClass(["fv-sender", [`variant-${__props.variant}`, { "is-disabled": __props.disabled, "is-loading": __props.loading, "is-focused": isFocused.value, "has-shadow": __props.shadow }]])
|
|
2351
2625
|
},
|
|
2352
2626
|
[
|
|
2353
2627
|
vue.createCommentVNode(" \u5934\u90E8:#header \u63D2\u69FD,openHeader/closeHeader \u63A7\u5236 "),
|
|
@@ -2365,9 +2639,89 @@
|
|
|
2365
2639
|
_ctx.$slots.prefix ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_5$7, [
|
|
2366
2640
|
vue.renderSlot(_ctx.$slots, "prefix")
|
|
2367
2641
|
])) : vue.createCommentVNode("v-if", true),
|
|
2368
|
-
vue.
|
|
2642
|
+
vue.createCommentVNode(" \u8BED\u97F3\u5F55\u97F3\u4E2D:\u8F93\u5165\u533A\u539F\u4F4D\u66FF\u6362\u4E3A\u5F55\u97F3\u6761(\u53D6\u6D88/\u6CE2\u5F62+\u65F6\u957F/\u786E\u8BA4);Esc \u53D6\u6D88 "),
|
|
2643
|
+
vue.unref(isRecording) ? (vue.openBlock(), vue.createElementBlock(
|
|
2369
2644
|
"div",
|
|
2370
2645
|
{
|
|
2646
|
+
key: 1,
|
|
2647
|
+
class: "fv-sender-recording",
|
|
2648
|
+
tabindex: "-1",
|
|
2649
|
+
onKeydown: onRecordingKeydown
|
|
2650
|
+
},
|
|
2651
|
+
[
|
|
2652
|
+
vue.createVNode(vue.unref(elementPlus.ElButton), {
|
|
2653
|
+
class: "fv-sender-recording-cancel",
|
|
2654
|
+
text: "",
|
|
2655
|
+
circle: "",
|
|
2656
|
+
"aria-label": "\u53D6\u6D88\u5F55\u97F3",
|
|
2657
|
+
onClick: onRecordCancel
|
|
2658
|
+
}, {
|
|
2659
|
+
default: vue.withCtx(() => [
|
|
2660
|
+
vue.createVNode(vue.unref(elementPlus.ElIcon), null, {
|
|
2661
|
+
default: vue.withCtx(() => [
|
|
2662
|
+
vue.createVNode(vue.unref(ElementPlusIconsVue.Close))
|
|
2663
|
+
]),
|
|
2664
|
+
_: 1
|
|
2665
|
+
/* STABLE */
|
|
2666
|
+
})
|
|
2667
|
+
]),
|
|
2668
|
+
_: 1
|
|
2669
|
+
/* STABLE */
|
|
2670
|
+
}),
|
|
2671
|
+
vue.createElementVNode("div", _hoisted_6$5, [
|
|
2672
|
+
(vue.openBlock(true), vue.createElementBlock(
|
|
2673
|
+
vue.Fragment,
|
|
2674
|
+
null,
|
|
2675
|
+
vue.renderList(waveLevels.value, (lv, i) => {
|
|
2676
|
+
return vue.openBlock(), vue.createElementBlock(
|
|
2677
|
+
"span",
|
|
2678
|
+
{
|
|
2679
|
+
key: i,
|
|
2680
|
+
class: "fv-sender-recording-bar",
|
|
2681
|
+
style: vue.normalizeStyle({ height: `${Math.round(lv * 100)}%` })
|
|
2682
|
+
},
|
|
2683
|
+
null,
|
|
2684
|
+
4
|
|
2685
|
+
/* STYLE */
|
|
2686
|
+
);
|
|
2687
|
+
}),
|
|
2688
|
+
128
|
|
2689
|
+
/* KEYED_FRAGMENT */
|
|
2690
|
+
))
|
|
2691
|
+
]),
|
|
2692
|
+
vue.createElementVNode(
|
|
2693
|
+
"span",
|
|
2694
|
+
_hoisted_7$4,
|
|
2695
|
+
vue.toDisplayString(recordDuration.value),
|
|
2696
|
+
1
|
|
2697
|
+
/* TEXT */
|
|
2698
|
+
),
|
|
2699
|
+
vue.createVNode(vue.unref(elementPlus.ElButton), {
|
|
2700
|
+
class: "fv-sender-recording-confirm",
|
|
2701
|
+
type: "primary",
|
|
2702
|
+
circle: "",
|
|
2703
|
+
"aria-label": "\u786E\u8BA4\u5F55\u97F3",
|
|
2704
|
+
onClick: onRecordConfirm
|
|
2705
|
+
}, {
|
|
2706
|
+
default: vue.withCtx(() => [
|
|
2707
|
+
vue.createVNode(vue.unref(elementPlus.ElIcon), null, {
|
|
2708
|
+
default: vue.withCtx(() => [
|
|
2709
|
+
vue.createVNode(vue.unref(ElementPlusIconsVue.Check))
|
|
2710
|
+
]),
|
|
2711
|
+
_: 1
|
|
2712
|
+
/* STABLE */
|
|
2713
|
+
})
|
|
2714
|
+
]),
|
|
2715
|
+
_: 1
|
|
2716
|
+
/* STABLE */
|
|
2717
|
+
})
|
|
2718
|
+
],
|
|
2719
|
+
32
|
|
2720
|
+
/* NEED_HYDRATION */
|
|
2721
|
+
)) : (vue.openBlock(), vue.createElementBlock(
|
|
2722
|
+
"div",
|
|
2723
|
+
{
|
|
2724
|
+
key: 2,
|
|
2371
2725
|
class: "fv-sender-input",
|
|
2372
2726
|
style: vue.normalizeStyle(__props.inputWidth && __props.variant === "default" ? { width: __props.inputWidth } : void 0)
|
|
2373
2727
|
},
|
|
@@ -2387,7 +2741,7 @@
|
|
|
2387
2741
|
onPaste,
|
|
2388
2742
|
onFocus: _cache[0] || (_cache[0] = ($event) => isFocused.value = true),
|
|
2389
2743
|
onBlur: onTextareaBlur
|
|
2390
|
-
}, null, 40,
|
|
2744
|
+
}, null, 40, _hoisted_8$3),
|
|
2391
2745
|
vue.createCommentVNode(" \u6307\u4EE4\u5F39\u6846:\u5185\u7F6E el-popover,\u5B9A\u4F4D\u6309 triggerPopover* \u7CFB\u5217 "),
|
|
2392
2746
|
vue.createVNode(vue.unref(elementPlus.ElPopover), {
|
|
2393
2747
|
visible: triggerVisible.value && __props.triggerStrings.length > 0,
|
|
@@ -2418,12 +2772,12 @@
|
|
|
2418
2772
|
],
|
|
2419
2773
|
4
|
|
2420
2774
|
/* STYLE */
|
|
2421
|
-
),
|
|
2775
|
+
)),
|
|
2422
2776
|
vue.createCommentVNode(" \u64CD\u4F5C\u533A:#action-list \u5B58\u5728\u65F6\u5168\u81EA\u5B9A\u4E49,\u9690\u85CF\u5185\u7F6E\u6309\u94AE;#action-left \u7F6E\u4E8E\u64CD\u4F5C\u680F\u5DE6\u4FA7(\u4E0E\u63D0\u4EA4\u6309\u94AE\u540C\u884C) "),
|
|
2423
|
-
hasActionListSlot.value ? (vue.openBlock(), vue.createElementBlock("div",
|
|
2777
|
+
hasActionListSlot.value ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_9$2, [
|
|
2424
2778
|
vue.renderSlot(_ctx.$slots, "action-list")
|
|
2425
|
-
])) : (vue.openBlock(), vue.createElementBlock("div",
|
|
2426
|
-
_ctx.$slots["action-left"] ? (vue.openBlock(), vue.createElementBlock("div",
|
|
2779
|
+
])) : (vue.openBlock(), vue.createElementBlock("div", _hoisted_10$2, [
|
|
2780
|
+
_ctx.$slots["action-left"] ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_11$2, [
|
|
2427
2781
|
vue.renderSlot(_ctx.$slots, "action-left")
|
|
2428
2782
|
])) : vue.createCommentVNode("v-if", true),
|
|
2429
2783
|
__props.clearable && value.value ? (vue.openBlock(), vue.createBlock(vue.unref(elementPlus.ElButton), {
|
|
@@ -2446,7 +2800,7 @@
|
|
|
2446
2800
|
_: 1
|
|
2447
2801
|
/* STABLE */
|
|
2448
2802
|
}, 8, ["disabled"])) : vue.createCommentVNode("v-if", true),
|
|
2449
|
-
__props.allowSpeech ? (vue.openBlock(), vue.createBlock(vue.unref(elementPlus.ElButton), {
|
|
2803
|
+
__props.allowSpeech && !vue.unref(isRecording) ? (vue.openBlock(), vue.createBlock(vue.unref(elementPlus.ElButton), {
|
|
2450
2804
|
key: 2,
|
|
2451
2805
|
class: "fv-sender-speech",
|
|
2452
2806
|
text: "",
|
|
@@ -2466,29 +2820,49 @@
|
|
|
2466
2820
|
_: 1
|
|
2467
2821
|
/* STABLE */
|
|
2468
2822
|
}, 8, ["disabled"])) : vue.createCommentVNode("v-if", true),
|
|
2469
|
-
vue.createCommentVNode(" loading \u2192 \u505C\u6B62\u6309\u94AE
|
|
2823
|
+
vue.createCommentVNode(" loading \u2192 \u505C\u6B62\u6309\u94AE:SVG \u5149\u5E26\u6CBF\u8FB9\u6846\u5300\u901F\u6D41\u8F6C,\u65B9/\u5706\u6309\u94AE\u5747\u9002\u7528 "),
|
|
2470
2824
|
__props.loading ? (vue.openBlock(), vue.createBlock(vue.unref(elementPlus.ElButton), {
|
|
2471
2825
|
key: 3,
|
|
2472
2826
|
class: "fv-sender-stop",
|
|
2473
2827
|
type: "primary",
|
|
2828
|
+
circle: __props.round,
|
|
2474
2829
|
"aria-label": "\u505C\u6B62",
|
|
2475
2830
|
onClick: cancel
|
|
2476
2831
|
}, {
|
|
2477
2832
|
default: vue.withCtx(() => [
|
|
2478
2833
|
vue.createVNode(vue.unref(elementPlus.ElIcon), null, {
|
|
2479
2834
|
default: vue.withCtx(() => [
|
|
2480
|
-
vue.createVNode(
|
|
2835
|
+
vue.createVNode(_sfc_main$e)
|
|
2481
2836
|
]),
|
|
2482
2837
|
_: 1
|
|
2483
2838
|
/* STABLE */
|
|
2484
|
-
})
|
|
2839
|
+
}),
|
|
2840
|
+
vue.createCommentVNode('\r\n \u6CBF\u8FB9\u6846\u6D41\u8F6C\u7684\u6E10\u53D8\u5149\u5E26(\u8682\u8681\u7EBF\u539F\u7406,pathLength=100 \u5F52\u4E00\u5468\u957F,dashoffset \u5300\u901F\u5E73\u79FB)\u3002\r\n \u6E10\u53D8\u96BE\u70B9:linearGradient \u6CBF\u76F4\u7EBF\u8DEF\u5F84\u5B9A\u4E49,\u65E0\u6CD5\u6CBF\u95ED\u5408\u6298\u7EBF\u5468\u957F\u6E10\u53D8 \u2014\u2014\r\n \u6545\u7528 6 \u5C42\u957F\u77ED/\u900F\u660E\u5EA6\u53CC\u9012\u51CF\u7684\u540C\u76F8\u4F4D dash \u53E0\u52A0,\u79BB\u6563\u9636\u68AF\u903C\u8FD1\u8FDE\u7EED\u6E10\u53D8:\r\n \u6BCF\u5C42\u957F\u5EA6\u4F9D\u6B21\u9012\u589E(\u5E26\u5934\u6700\u77ED\u6700\u5B9E,\u5E26\u5C3E\u6700\u957F\u6700\u865A),\u900F\u660E\u5EA6\u4F9D\u6B21\u9012\u51CF,\r\n \u53E0\u52A0\u540E\u7684\u900F\u660E\u5EA6\u5256\u9762\u4E3A\u591A\u7EA7\u53F0\u9636 \u2192 \u8FD0\u52A8\u4E2D\u8BFB\u4F5C"\u5934\u4EAE\u5C3E\u9690"\u7684\u8FDE\u7EED\u62D6\u5F71\u3002\r\n \u5C42\u6570\u7531 RING_LAYERS \u5E38\u91CF\u9A71\u52A8,\u900F\u660E\u5EA6\u63D2\u503C\u5728 CSS \u91CC\u6309 --ring-alpha \u53D8\u91CF\u7B97\u3002\r\n '),
|
|
2841
|
+
(vue.openBlock(), vue.createElementBlock("svg", _hoisted_12$2, [
|
|
2842
|
+
(vue.openBlock(true), vue.createElementBlock(
|
|
2843
|
+
vue.Fragment,
|
|
2844
|
+
null,
|
|
2845
|
+
vue.renderList(ringLayers.value, (layer, i) => {
|
|
2846
|
+
return vue.openBlock(), vue.createElementBlock("rect", {
|
|
2847
|
+
key: i,
|
|
2848
|
+
class: "fv-sender-stop-ring-rect",
|
|
2849
|
+
style: vue.normalizeStyle(layer.style),
|
|
2850
|
+
rx: __props.round ? "50%" : 2.5,
|
|
2851
|
+
pathLength: "100"
|
|
2852
|
+
}, null, 12, _hoisted_13$2);
|
|
2853
|
+
}),
|
|
2854
|
+
128
|
|
2855
|
+
/* KEYED_FRAGMENT */
|
|
2856
|
+
))
|
|
2857
|
+
]))
|
|
2485
2858
|
]),
|
|
2486
2859
|
_: 1
|
|
2487
2860
|
/* STABLE */
|
|
2488
|
-
})) : (vue.openBlock(), vue.createBlock(vue.unref(elementPlus.ElButton), {
|
|
2861
|
+
}, 8, ["circle"])) : (vue.openBlock(), vue.createBlock(vue.unref(elementPlus.ElButton), {
|
|
2489
2862
|
key: 4,
|
|
2490
2863
|
class: "fv-sender-submit",
|
|
2491
2864
|
type: "primary",
|
|
2865
|
+
circle: __props.round,
|
|
2492
2866
|
disabled: !submitable(),
|
|
2493
2867
|
"aria-label": "\u53D1\u9001",
|
|
2494
2868
|
onClick: doSubmit
|
|
@@ -2504,13 +2878,13 @@
|
|
|
2504
2878
|
]),
|
|
2505
2879
|
_: 1
|
|
2506
2880
|
/* STABLE */
|
|
2507
|
-
}, 8, ["disabled"]))
|
|
2881
|
+
}, 8, ["circle", "disabled"]))
|
|
2508
2882
|
]))
|
|
2509
2883
|
]),
|
|
2510
2884
|
vue.createCommentVNode(" /fv-sender-row ")
|
|
2511
2885
|
]),
|
|
2512
2886
|
vue.createCommentVNode(" \u5E95\u90E8 "),
|
|
2513
|
-
_ctx.$slots.footer ? (vue.openBlock(), vue.createElementBlock("div",
|
|
2887
|
+
_ctx.$slots.footer ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_14$2, [
|
|
2514
2888
|
vue.renderSlot(_ctx.$slots, "footer")
|
|
2515
2889
|
])) : vue.createCommentVNode("v-if", true)
|
|
2516
2890
|
],
|
|
@@ -5815,7 +6189,7 @@ ${fileParts.join("\n")}` });
|
|
|
5815
6189
|
"auto-collapse": __props.autoCollapse
|
|
5816
6190
|
}, {
|
|
5817
6191
|
content: vue.withCtx(() => [
|
|
5818
|
-
vue.createVNode(_sfc_main$
|
|
6192
|
+
vue.createVNode(_sfc_main$i, {
|
|
5819
6193
|
content: __props.message.reasoning ?? ""
|
|
5820
6194
|
}, null, 8, ["content"])
|
|
5821
6195
|
]),
|
|
@@ -5830,7 +6204,7 @@ ${fileParts.join("\n")}` });
|
|
|
5830
6204
|
vue.toDisplayString(__props.message.error || "\u751F\u6210\u5931\u8D25"),
|
|
5831
6205
|
1
|
|
5832
6206
|
/* TEXT */
|
|
5833
|
-
)) : __props.message.content ? (vue.openBlock(), vue.createBlock(_sfc_main$
|
|
6207
|
+
)) : __props.message.content ? (vue.openBlock(), vue.createBlock(_sfc_main$i, {
|
|
5834
6208
|
key: 1,
|
|
5835
6209
|
content: __props.message.content
|
|
5836
6210
|
}, null, 8, ["content"])) : __props.message.status === "pending" || __props.message.status === "streaming" ? (vue.openBlock(), vue.createElementBlock("span", _hoisted_12, [
|
|
@@ -6401,7 +6775,10 @@ ${fileParts.join("\n")}` });
|
|
|
6401
6775
|
}
|
|
6402
6776
|
});
|
|
6403
6777
|
|
|
6404
|
-
const _hoisted_1 = {
|
|
6778
|
+
const _hoisted_1 = {
|
|
6779
|
+
key: 0,
|
|
6780
|
+
class: "fv-ai-chat-header"
|
|
6781
|
+
};
|
|
6405
6782
|
const _hoisted_2 = { class: "fv-ai-chat-title" };
|
|
6406
6783
|
const _hoisted_3 = { class: "fv-ai-chat-body" };
|
|
6407
6784
|
const _hoisted_4 = { class: "fv-ai-chat-footer" };
|
|
@@ -6416,7 +6793,10 @@ ${fileParts.join("\n")}` });
|
|
|
6416
6793
|
adapter: { type: Object, required: false, default: void 0 },
|
|
6417
6794
|
messages: { type: Array, required: false, default: void 0 },
|
|
6418
6795
|
title: { type: String, required: false, default: "" },
|
|
6796
|
+
showHeader: { type: Boolean, required: false, default: false },
|
|
6797
|
+
centerWelcome: { type: Boolean, required: false, default: true },
|
|
6419
6798
|
placeholder: { type: String, required: false, default: "" },
|
|
6799
|
+
senderShadow: { type: Boolean, required: false, default: true },
|
|
6420
6800
|
suggestions: { type: Array, required: false, default: () => [] },
|
|
6421
6801
|
features: { type: Object, required: false, default: () => ({}) },
|
|
6422
6802
|
allowAttachments: { type: Boolean, required: false, default: false },
|
|
@@ -6464,6 +6844,7 @@ ${fileParts.join("\n")}` });
|
|
|
6464
6844
|
const { send, stop: stopChat, regenerate: regenerateChat, msgs, isLoading } = chat;
|
|
6465
6845
|
const nodeTable = chat.messages;
|
|
6466
6846
|
const chain = chat.chain;
|
|
6847
|
+
const isCenterWelcome = vue.computed(() => props.centerWelcome && chain.value.length === 0);
|
|
6467
6848
|
let flushTimer = null;
|
|
6468
6849
|
vue.watch(chain, (c) => {
|
|
6469
6850
|
if (flushTimer) clearTimeout(flushTimer);
|
|
@@ -6629,11 +7010,11 @@ ${fileParts.join("\n")}` });
|
|
|
6629
7010
|
return vue.openBlock(), vue.createElementBlock(
|
|
6630
7011
|
"div",
|
|
6631
7012
|
{
|
|
6632
|
-
class: vue.normalizeClass(["fv-ai-chat", { "is-dark": isDark.value }])
|
|
7013
|
+
class: vue.normalizeClass(["fv-ai-chat", { "is-dark": isDark.value, "is-center-welcome": isCenterWelcome.value }])
|
|
6633
7014
|
},
|
|
6634
7015
|
[
|
|
6635
7016
|
vue.createCommentVNode(" \u9876\u680F:\u6807\u9898 + \u6A21\u578B\u9009\u62E9\u5668(models \u6709\u503C\u65F6 multiple) "),
|
|
6636
|
-
vue.
|
|
7017
|
+
__props.showHeader ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1, [
|
|
6637
7018
|
vue.createElementVNode(
|
|
6638
7019
|
"div",
|
|
6639
7020
|
_hoisted_2,
|
|
@@ -6669,7 +7050,7 @@ ${fileParts.join("\n")}` });
|
|
|
6669
7050
|
_: 1
|
|
6670
7051
|
/* STABLE */
|
|
6671
7052
|
}, 8, ["modelValue"])) : vue.createCommentVNode("v-if", true)
|
|
6672
|
-
]),
|
|
7053
|
+
])) : vue.createCommentVNode("v-if", true),
|
|
6673
7054
|
vue.createCommentVNode(" \u6D88\u606F\u533A:\u7A7A\u65F6 Welcome + Prompts(AiMessages \u5185\u7F6E);\u5F00\u542F artifacts \u65F6\u53F3\u4FA7\u62FC\u9884\u89C8\u9762\u677F "),
|
|
6674
7055
|
vue.createElementVNode("div", _hoisted_3, [
|
|
6675
7056
|
vue.createVNode(_sfc_main$2, {
|
|
@@ -6720,6 +7101,7 @@ ${fileParts.join("\n")}` });
|
|
|
6720
7101
|
vue.createVNode(_sfc_main$d, {
|
|
6721
7102
|
placeholder: __props.placeholder,
|
|
6722
7103
|
loading: vue.unref(isLoading),
|
|
7104
|
+
shadow: __props.senderShadow,
|
|
6723
7105
|
variant: "updown",
|
|
6724
7106
|
maxlength: 8e3,
|
|
6725
7107
|
"allow-empty-submit": __props.allowAttachments && !!pendingFiles.value.length,
|
|
@@ -6764,7 +7146,7 @@ ${fileParts.join("\n")}` });
|
|
|
6764
7146
|
]),
|
|
6765
7147
|
key: "2"
|
|
6766
7148
|
} : void 0
|
|
6767
|
-
]), 1032, ["placeholder", "loading", "allow-empty-submit"])
|
|
7149
|
+
]), 1032, ["placeholder", "loading", "shadow", "allow-empty-submit"])
|
|
6768
7150
|
])
|
|
6769
7151
|
],
|
|
6770
7152
|
2
|
|
@@ -6895,105 +7277,6 @@ ${fileParts.join("\n")}` });
|
|
|
6895
7277
|
});
|
|
6896
7278
|
}
|
|
6897
7279
|
|
|
6898
|
-
function getSpeechRecognitionCtor() {
|
|
6899
|
-
if (typeof window === "undefined") return void 0;
|
|
6900
|
-
const w = window;
|
|
6901
|
-
const ctor = w.SpeechRecognition ?? w.webkitSpeechRecognition;
|
|
6902
|
-
return typeof ctor === "function" ? ctor : void 0;
|
|
6903
|
-
}
|
|
6904
|
-
function useRecord() {
|
|
6905
|
-
const isRecording = vue.ref(false);
|
|
6906
|
-
const text = vue.ref("");
|
|
6907
|
-
const audioUrl = vue.ref(null);
|
|
6908
|
-
const error = vue.ref(null);
|
|
6909
|
-
let mediaStream = null;
|
|
6910
|
-
let mediaRecorder = null;
|
|
6911
|
-
let chunks = [];
|
|
6912
|
-
let recognition = null;
|
|
6913
|
-
let finalText = "";
|
|
6914
|
-
function revokeAudioUrl() {
|
|
6915
|
-
if (audioUrl.value) {
|
|
6916
|
-
URL.revokeObjectURL(audioUrl.value);
|
|
6917
|
-
audioUrl.value = null;
|
|
6918
|
-
}
|
|
6919
|
-
}
|
|
6920
|
-
async function start() {
|
|
6921
|
-
if (isRecording.value) return;
|
|
6922
|
-
error.value = null;
|
|
6923
|
-
text.value = "";
|
|
6924
|
-
finalText = "";
|
|
6925
|
-
chunks = [];
|
|
6926
|
-
revokeAudioUrl();
|
|
6927
|
-
if (typeof MediaRecorder === "undefined" || !navigator.mediaDevices?.getUserMedia) {
|
|
6928
|
-
error.value = new Error("\u5F53\u524D\u73AF\u5883\u4E0D\u652F\u6301\u97F3\u9891\u5F55\u5236");
|
|
6929
|
-
return;
|
|
6930
|
-
}
|
|
6931
|
-
try {
|
|
6932
|
-
mediaStream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
6933
|
-
} catch (e) {
|
|
6934
|
-
error.value = e instanceof Error ? e : new Error(String(e));
|
|
6935
|
-
return;
|
|
6936
|
-
}
|
|
6937
|
-
mediaRecorder = new MediaRecorder(mediaStream);
|
|
6938
|
-
mediaRecorder.ondataavailable = (e) => {
|
|
6939
|
-
if (e.data && e.data.size > 0) chunks.push(e.data);
|
|
6940
|
-
};
|
|
6941
|
-
mediaRecorder.onstop = () => {
|
|
6942
|
-
if (chunks.length > 0) {
|
|
6943
|
-
const blob = new Blob(chunks, { type: mediaRecorder?.mimeType || "audio/webm" });
|
|
6944
|
-
audioUrl.value = URL.createObjectURL(blob);
|
|
6945
|
-
}
|
|
6946
|
-
mediaStream?.getTracks().forEach((t) => t.stop());
|
|
6947
|
-
mediaStream = null;
|
|
6948
|
-
};
|
|
6949
|
-
const SRCtor = getSpeechRecognitionCtor();
|
|
6950
|
-
if (SRCtor) {
|
|
6951
|
-
try {
|
|
6952
|
-
recognition = new SRCtor();
|
|
6953
|
-
recognition.continuous = true;
|
|
6954
|
-
recognition.interimResults = true;
|
|
6955
|
-
recognition.onresult = (event) => {
|
|
6956
|
-
let interim = "";
|
|
6957
|
-
for (let i = event.resultIndex; i < event.results.length; i++) {
|
|
6958
|
-
const r = event.results[i];
|
|
6959
|
-
if (r.isFinal) finalText += r[0].transcript;
|
|
6960
|
-
else interim += r[0].transcript;
|
|
6961
|
-
}
|
|
6962
|
-
text.value = finalText + interim;
|
|
6963
|
-
};
|
|
6964
|
-
recognition.onerror = (ev) => {
|
|
6965
|
-
error.value = new Error(`\u8BED\u97F3\u8BC6\u522B\u9519\u8BEF: ${ev?.error ?? "unknown"}`);
|
|
6966
|
-
};
|
|
6967
|
-
recognition.start();
|
|
6968
|
-
} catch {
|
|
6969
|
-
recognition = null;
|
|
6970
|
-
}
|
|
6971
|
-
}
|
|
6972
|
-
mediaRecorder.start();
|
|
6973
|
-
isRecording.value = true;
|
|
6974
|
-
}
|
|
6975
|
-
function stop() {
|
|
6976
|
-
if (!isRecording.value) return;
|
|
6977
|
-
isRecording.value = false;
|
|
6978
|
-
try {
|
|
6979
|
-
recognition?.stop();
|
|
6980
|
-
} catch {
|
|
6981
|
-
}
|
|
6982
|
-
recognition = null;
|
|
6983
|
-
try {
|
|
6984
|
-
if (mediaRecorder && mediaRecorder.state !== "inactive") mediaRecorder.stop();
|
|
6985
|
-
} catch {
|
|
6986
|
-
}
|
|
6987
|
-
}
|
|
6988
|
-
if (vue.getCurrentInstance()) {
|
|
6989
|
-
vue.onBeforeUnmount(() => {
|
|
6990
|
-
stop();
|
|
6991
|
-
revokeAudioUrl();
|
|
6992
|
-
});
|
|
6993
|
-
}
|
|
6994
|
-
return { start, stop, isRecording, text, audioUrl, error };
|
|
6995
|
-
}
|
|
6996
|
-
|
|
6997
7280
|
class DetOmsError extends Error {
|
|
6998
7281
|
constructor(message, code) {
|
|
6999
7282
|
super(message);
|
|
@@ -7196,18 +7479,18 @@ ${fileParts.join("\n")}` });
|
|
|
7196
7479
|
exports.FvAiMessage = _sfc_main$3;
|
|
7197
7480
|
exports.FvAiMessages = _sfc_main$2;
|
|
7198
7481
|
exports.FvAttachments = _sfc_main$5;
|
|
7199
|
-
exports.FvBubble = _sfc_main$
|
|
7200
|
-
exports.FvBubbleList = _sfc_main$
|
|
7482
|
+
exports.FvBubble = _sfc_main$g;
|
|
7483
|
+
exports.FvBubbleList = _sfc_main$f;
|
|
7201
7484
|
exports.FvConversations = _sfc_main$4;
|
|
7202
7485
|
exports.FvEditorSender = _sfc_main$b;
|
|
7203
7486
|
exports.FvFilesCard = _sfc_main$6;
|
|
7204
|
-
exports.FvMarkdown = _sfc_main$
|
|
7487
|
+
exports.FvMarkdown = _sfc_main$i;
|
|
7205
7488
|
exports.FvMentionSender = _sfc_main$c;
|
|
7206
7489
|
exports.FvPrompts = _sfc_main$7;
|
|
7207
7490
|
exports.FvSender = _sfc_main$d;
|
|
7208
7491
|
exports.FvThinking = _sfc_main$a;
|
|
7209
7492
|
exports.FvThoughtChain = _sfc_main$9;
|
|
7210
|
-
exports.FvTypewriter = _sfc_main$
|
|
7493
|
+
exports.FvTypewriter = _sfc_main$h;
|
|
7211
7494
|
exports.FvWelcome = _sfc_main$8;
|
|
7212
7495
|
exports.OpenAIAdapter = OpenAIAdapter;
|
|
7213
7496
|
exports.XRequest = XRequest;
|