@fv-ui/ai-chat 0.1.0 → 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 +441 -151
- package/lib/index.js +441 -151
- package/package.json +80 -80
package/es/index.mjs
CHANGED
|
@@ -1,12 +1,19 @@
|
|
|
1
|
-
import { defineComponent, computed, openBlock, createElementBlock, ref, watch, onBeforeUnmount, normalizeClass, createCommentVNode, createBlock, createTextVNode, toDisplayString, normalizeStyle, renderSlot, unref, createElementVNode, Fragment, renderList, createVNode, isRef, nextTick, onMounted, mergeProps, createSlots, withCtx, Transition, useSlots, normalizeProps, guardReactiveProps, reactive, resolveDynamicComponent, markRaw, withModifiers
|
|
1
|
+
import { defineComponent, computed, openBlock, createElementBlock, ref, watch, onBeforeUnmount, normalizeClass, createCommentVNode, createBlock, createTextVNode, toDisplayString, normalizeStyle, renderSlot, unref, createElementVNode, Fragment, renderList, createVNode, isRef, nextTick, onMounted, mergeProps, createSlots, withCtx, Transition, getCurrentInstance, useSlots, normalizeProps, guardReactiveProps, reactive, resolveDynamicComponent, markRaw, withModifiers } from 'vue';
|
|
2
2
|
import MarkdownIt from 'markdown-it';
|
|
3
3
|
import mdKatex from '@vscode/markdown-it-katex';
|
|
4
4
|
import DOMPurify from 'dompurify';
|
|
5
5
|
import Prism$1 from 'prismjs';
|
|
6
|
-
import { ElAvatar, ElButton, ElPopover,
|
|
6
|
+
import { ElAvatar, ElButton, ElIcon, ElPopover, ElMessage, ElDialog, ElDropdown, ElDropdownMenu, ElDropdownItem, ElMessageBox, ElTooltip, ElSelect, ElOption } from 'element-plus';
|
|
7
7
|
import * as ElementPlusIconsVue from '@element-plus/icons-vue';
|
|
8
|
-
import { ArrowDown, Delete, Microphone,
|
|
8
|
+
import { ArrowDown, Close, Check, Delete, Microphone, Promotion, VideoPause, Loading, SuccessFilled, CircleCloseFilled, ChatDotRound, Cpu, Cellphone, Link, Folder, Headset, Film, Monitor, DataAnalysis, Document, Notebook, Picture, Paperclip, RefreshRight, MoreFilled, User, DocumentCopy, ArrowUp, CopyDocument, Download, FullScreen } from '@element-plus/icons-vue';
|
|
9
9
|
|
|
10
|
+
function unwrapPlugin(plugin) {
|
|
11
|
+
const candidate = plugin && typeof plugin === "object" && "default" in plugin ? plugin.default : plugin;
|
|
12
|
+
if (typeof candidate !== "function") {
|
|
13
|
+
throw new TypeError("[XMarkdown] \u65E0\u6548\u7684 markdown-it \u63D2\u4EF6:\u9884\u671F\u51FD\u6570,\u6536\u5230 " + typeof candidate);
|
|
14
|
+
}
|
|
15
|
+
return candidate;
|
|
16
|
+
}
|
|
10
17
|
function createMarkdownInstance(options) {
|
|
11
18
|
const md = new MarkdownIt({
|
|
12
19
|
html: true,
|
|
@@ -14,9 +21,9 @@ function createMarkdownInstance(options) {
|
|
|
14
21
|
linkify: true,
|
|
15
22
|
highlight: options?.highlight
|
|
16
23
|
});
|
|
17
|
-
md.use(mdKatex);
|
|
24
|
+
md.use(unwrapPlugin(mdKatex));
|
|
18
25
|
if (options?.mdPlugins) {
|
|
19
|
-
for (const p of options.mdPlugins) md.use(p);
|
|
26
|
+
for (const p of options.mdPlugins) md.use(unwrapPlugin(p));
|
|
20
27
|
}
|
|
21
28
|
return md;
|
|
22
29
|
}
|
|
@@ -1519,8 +1526,8 @@ function prismHighlight(str, lang) {
|
|
|
1519
1526
|
}
|
|
1520
1527
|
}
|
|
1521
1528
|
|
|
1522
|
-
const _hoisted_1$
|
|
1523
|
-
var _sfc_main$
|
|
1529
|
+
const _hoisted_1$i = ["innerHTML"];
|
|
1530
|
+
var _sfc_main$i = /* @__PURE__ */ defineComponent({
|
|
1524
1531
|
...{ name: "FvMarkdown" },
|
|
1525
1532
|
__name: "index",
|
|
1526
1533
|
props: {
|
|
@@ -1543,12 +1550,12 @@ var _sfc_main$h = /* @__PURE__ */ defineComponent({
|
|
|
1543
1550
|
return openBlock(), createElementBlock("div", {
|
|
1544
1551
|
class: "fv-xmarkdown markdown-body",
|
|
1545
1552
|
innerHTML: html.value
|
|
1546
|
-
}, null, 8, _hoisted_1$
|
|
1553
|
+
}, null, 8, _hoisted_1$i);
|
|
1547
1554
|
};
|
|
1548
1555
|
}
|
|
1549
1556
|
});
|
|
1550
1557
|
|
|
1551
|
-
const _hoisted_1$
|
|
1558
|
+
const _hoisted_1$h = {
|
|
1552
1559
|
key: 1,
|
|
1553
1560
|
class: "fv-typewriter-text"
|
|
1554
1561
|
};
|
|
@@ -1556,7 +1563,7 @@ const _hoisted_2$f = {
|
|
|
1556
1563
|
key: 0,
|
|
1557
1564
|
class: "fv-typewriter-suffix"
|
|
1558
1565
|
};
|
|
1559
|
-
var _sfc_main$
|
|
1566
|
+
var _sfc_main$h = /* @__PURE__ */ defineComponent({
|
|
1560
1567
|
...{ name: "FvTypewriter" },
|
|
1561
1568
|
__name: "index",
|
|
1562
1569
|
props: {
|
|
@@ -1646,11 +1653,11 @@ var _sfc_main$g = /* @__PURE__ */ defineComponent({
|
|
|
1646
1653
|
},
|
|
1647
1654
|
[
|
|
1648
1655
|
createCommentVNode(" markdown \u6A21\u5F0F:suffix \u4E0D\u8FFD\u52A0(element-plus-x \u884C\u4E3A),isTyping \u900F\u4F20\u7ED9 XMarkdown \u4F5C\u6837\u5F0F\u94A9\u5B50 "),
|
|
1649
|
-
__props.isMarkdown ? (openBlock(), createBlock(_sfc_main$
|
|
1656
|
+
__props.isMarkdown ? (openBlock(), createBlock(_sfc_main$i, {
|
|
1650
1657
|
key: 0,
|
|
1651
1658
|
content: renderedContent.value,
|
|
1652
1659
|
"is-typing": isTyping.value
|
|
1653
|
-
}, null, 8, ["content", "is-typing"])) : (openBlock(), createElementBlock("span", _hoisted_1$
|
|
1660
|
+
}, null, 8, ["content", "is-typing"])) : (openBlock(), createElementBlock("span", _hoisted_1$h, [
|
|
1654
1661
|
createTextVNode(
|
|
1655
1662
|
toDisplayString(renderedContent.value),
|
|
1656
1663
|
1
|
|
@@ -1685,7 +1692,7 @@ var _sfc_main$g = /* @__PURE__ */ defineComponent({
|
|
|
1685
1692
|
}
|
|
1686
1693
|
});
|
|
1687
1694
|
|
|
1688
|
-
const _hoisted_1$
|
|
1695
|
+
const _hoisted_1$g = {
|
|
1689
1696
|
key: 0,
|
|
1690
1697
|
class: "fv-bubble-avatar"
|
|
1691
1698
|
};
|
|
@@ -1706,7 +1713,7 @@ const _hoisted_6$6 = {
|
|
|
1706
1713
|
key: 1,
|
|
1707
1714
|
class: "fv-bubble-footer"
|
|
1708
1715
|
};
|
|
1709
|
-
var _sfc_main$
|
|
1716
|
+
var _sfc_main$g = /* @__PURE__ */ defineComponent({
|
|
1710
1717
|
...{ name: "FvBubble" },
|
|
1711
1718
|
__name: "index",
|
|
1712
1719
|
props: {
|
|
@@ -1773,7 +1780,7 @@ var _sfc_main$f = /* @__PURE__ */ defineComponent({
|
|
|
1773
1780
|
},
|
|
1774
1781
|
[
|
|
1775
1782
|
createCommentVNode(" \u5934\u50CF:placement \u540C\u7F18\u6392\u5217(end \u7ECF row-reverse \u7FFB\u8F6C\u5230\u53F3\u4FA7),#avatar \u63D2\u69FD\u4F18\u5148 "),
|
|
1776
|
-
_ctx.$slots.avatar || __props.avatar || __props.avatarIcon ? (openBlock(), createElementBlock("div", _hoisted_1$
|
|
1783
|
+
_ctx.$slots.avatar || __props.avatar || __props.avatarIcon ? (openBlock(), createElementBlock("div", _hoisted_1$g, [
|
|
1777
1784
|
_ctx.$slots.avatar ? renderSlot(_ctx.$slots, "avatar", {}, void 0, void 0, 0) : (openBlock(), createBlock(unref(ElAvatar), {
|
|
1778
1785
|
key: 1,
|
|
1779
1786
|
size: __props.avatarSize || void 0,
|
|
@@ -1831,7 +1838,7 @@ var _sfc_main$f = /* @__PURE__ */ defineComponent({
|
|
|
1831
1838
|
{ key: 2 },
|
|
1832
1839
|
[
|
|
1833
1840
|
createCommentVNode(" typing \u900F\u4F20 Typewriter;\u975E typing:isMarkdown \u2192 XMarkdown,\u5426\u5219\u7EAF\u6587\u672C "),
|
|
1834
|
-
createVNode(_sfc_main$
|
|
1841
|
+
createVNode(_sfc_main$h, {
|
|
1835
1842
|
ref_key: "twRef",
|
|
1836
1843
|
ref: twRef,
|
|
1837
1844
|
content: __props.content,
|
|
@@ -1845,7 +1852,7 @@ var _sfc_main$f = /* @__PURE__ */ defineComponent({
|
|
|
1845
1852
|
],
|
|
1846
1853
|
2112
|
|
1847
1854
|
/* STABLE_FRAGMENT, DEV_ROOT_FRAGMENT */
|
|
1848
|
-
)) : __props.isMarkdown ? (openBlock(), createBlock(_sfc_main$
|
|
1855
|
+
)) : __props.isMarkdown ? (openBlock(), createBlock(_sfc_main$i, {
|
|
1849
1856
|
key: 3,
|
|
1850
1857
|
content: __props.content
|
|
1851
1858
|
}, null, 8, ["content"])) : (openBlock(), createElementBlock(
|
|
@@ -1871,8 +1878,8 @@ var _sfc_main$f = /* @__PURE__ */ defineComponent({
|
|
|
1871
1878
|
}
|
|
1872
1879
|
});
|
|
1873
1880
|
|
|
1874
|
-
const _hoisted_1$
|
|
1875
|
-
var _sfc_main$
|
|
1881
|
+
const _hoisted_1$f = { class: "fv-bubble-list" };
|
|
1882
|
+
var _sfc_main$f = /* @__PURE__ */ defineComponent({
|
|
1876
1883
|
...{ name: "FvBubbleList" },
|
|
1877
1884
|
__name: "index",
|
|
1878
1885
|
props: {
|
|
@@ -1972,7 +1979,7 @@ var _sfc_main$e = /* @__PURE__ */ defineComponent({
|
|
|
1972
1979
|
}));
|
|
1973
1980
|
__expose({ scrollToTop, scrollToBottom, scrollToBubble });
|
|
1974
1981
|
return (_ctx, _cache) => {
|
|
1975
|
-
return openBlock(), createElementBlock("div", _hoisted_1$
|
|
1982
|
+
return openBlock(), createElementBlock("div", _hoisted_1$f, [
|
|
1976
1983
|
createElementVNode(
|
|
1977
1984
|
"div",
|
|
1978
1985
|
{
|
|
@@ -1987,7 +1994,7 @@ var _sfc_main$e = /* @__PURE__ */ defineComponent({
|
|
|
1987
1994
|
Fragment,
|
|
1988
1995
|
null,
|
|
1989
1996
|
renderList(__props.list, (item, index) => {
|
|
1990
|
-
return openBlock(), createBlock(_sfc_main$
|
|
1997
|
+
return openBlock(), createBlock(_sfc_main$g, mergeProps({
|
|
1991
1998
|
key: item.key,
|
|
1992
1999
|
ref_for: true,
|
|
1993
2000
|
ref: (el) => setBubbleRef(el, index)
|
|
@@ -2095,6 +2102,139 @@ var _sfc_main$e = /* @__PURE__ */ defineComponent({
|
|
|
2095
2102
|
}
|
|
2096
2103
|
});
|
|
2097
2104
|
|
|
2105
|
+
const _hoisted_1$e = {
|
|
2106
|
+
class: "fv-stop-icon",
|
|
2107
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2108
|
+
viewBox: "0 0 24 24",
|
|
2109
|
+
width: "1em",
|
|
2110
|
+
height: "1em",
|
|
2111
|
+
"aria-hidden": "true",
|
|
2112
|
+
focusable: "false"
|
|
2113
|
+
};
|
|
2114
|
+
var _sfc_main$e = /* @__PURE__ */ defineComponent({
|
|
2115
|
+
...{ name: "FvStopIcon" },
|
|
2116
|
+
__name: "StopIcon",
|
|
2117
|
+
setup(__props) {
|
|
2118
|
+
return (_ctx, _cache) => {
|
|
2119
|
+
return openBlock(), createElementBlock("svg", _hoisted_1$e, [..._cache[0] || (_cache[0] = [
|
|
2120
|
+
createElementVNode(
|
|
2121
|
+
"rect",
|
|
2122
|
+
{
|
|
2123
|
+
x: "5.5",
|
|
2124
|
+
y: "5.5",
|
|
2125
|
+
width: "13",
|
|
2126
|
+
height: "13",
|
|
2127
|
+
rx: "2.5",
|
|
2128
|
+
fill: "currentColor"
|
|
2129
|
+
},
|
|
2130
|
+
null,
|
|
2131
|
+
-1
|
|
2132
|
+
/* CACHED */
|
|
2133
|
+
)
|
|
2134
|
+
])]);
|
|
2135
|
+
};
|
|
2136
|
+
}
|
|
2137
|
+
});
|
|
2138
|
+
|
|
2139
|
+
function getSpeechRecognitionCtor() {
|
|
2140
|
+
if (typeof window === "undefined") return void 0;
|
|
2141
|
+
const w = window;
|
|
2142
|
+
const ctor = w.SpeechRecognition ?? w.webkitSpeechRecognition;
|
|
2143
|
+
return typeof ctor === "function" ? ctor : void 0;
|
|
2144
|
+
}
|
|
2145
|
+
function useRecord() {
|
|
2146
|
+
const isRecording = ref(false);
|
|
2147
|
+
const text = ref("");
|
|
2148
|
+
const audioUrl = ref(null);
|
|
2149
|
+
const error = ref(null);
|
|
2150
|
+
let mediaStream = null;
|
|
2151
|
+
let mediaRecorder = null;
|
|
2152
|
+
let chunks = [];
|
|
2153
|
+
let recognition = null;
|
|
2154
|
+
let finalText = "";
|
|
2155
|
+
function revokeAudioUrl() {
|
|
2156
|
+
if (audioUrl.value) {
|
|
2157
|
+
URL.revokeObjectURL(audioUrl.value);
|
|
2158
|
+
audioUrl.value = null;
|
|
2159
|
+
}
|
|
2160
|
+
}
|
|
2161
|
+
async function start() {
|
|
2162
|
+
if (isRecording.value) return;
|
|
2163
|
+
error.value = null;
|
|
2164
|
+
text.value = "";
|
|
2165
|
+
finalText = "";
|
|
2166
|
+
chunks = [];
|
|
2167
|
+
revokeAudioUrl();
|
|
2168
|
+
if (typeof MediaRecorder === "undefined" || !navigator.mediaDevices?.getUserMedia) {
|
|
2169
|
+
error.value = new Error("\u5F53\u524D\u73AF\u5883\u4E0D\u652F\u6301\u97F3\u9891\u5F55\u5236");
|
|
2170
|
+
return;
|
|
2171
|
+
}
|
|
2172
|
+
try {
|
|
2173
|
+
mediaStream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
2174
|
+
} catch (e) {
|
|
2175
|
+
error.value = e instanceof Error ? e : new Error(String(e));
|
|
2176
|
+
return;
|
|
2177
|
+
}
|
|
2178
|
+
mediaRecorder = new MediaRecorder(mediaStream);
|
|
2179
|
+
mediaRecorder.ondataavailable = (e) => {
|
|
2180
|
+
if (e.data && e.data.size > 0) chunks.push(e.data);
|
|
2181
|
+
};
|
|
2182
|
+
mediaRecorder.onstop = () => {
|
|
2183
|
+
if (chunks.length > 0) {
|
|
2184
|
+
const blob = new Blob(chunks, { type: mediaRecorder?.mimeType || "audio/webm" });
|
|
2185
|
+
audioUrl.value = URL.createObjectURL(blob);
|
|
2186
|
+
}
|
|
2187
|
+
mediaStream?.getTracks().forEach((t) => t.stop());
|
|
2188
|
+
mediaStream = null;
|
|
2189
|
+
};
|
|
2190
|
+
const SRCtor = getSpeechRecognitionCtor();
|
|
2191
|
+
if (SRCtor) {
|
|
2192
|
+
try {
|
|
2193
|
+
recognition = new SRCtor();
|
|
2194
|
+
recognition.continuous = true;
|
|
2195
|
+
recognition.interimResults = true;
|
|
2196
|
+
recognition.onresult = (event) => {
|
|
2197
|
+
let interim = "";
|
|
2198
|
+
for (let i = event.resultIndex; i < event.results.length; i++) {
|
|
2199
|
+
const r = event.results[i];
|
|
2200
|
+
if (r.isFinal) finalText += r[0].transcript;
|
|
2201
|
+
else interim += r[0].transcript;
|
|
2202
|
+
}
|
|
2203
|
+
text.value = finalText + interim;
|
|
2204
|
+
};
|
|
2205
|
+
recognition.onerror = (ev) => {
|
|
2206
|
+
error.value = new Error(`\u8BED\u97F3\u8BC6\u522B\u9519\u8BEF: ${ev?.error ?? "unknown"}`);
|
|
2207
|
+
};
|
|
2208
|
+
recognition.start();
|
|
2209
|
+
} catch {
|
|
2210
|
+
recognition = null;
|
|
2211
|
+
}
|
|
2212
|
+
}
|
|
2213
|
+
mediaRecorder.start();
|
|
2214
|
+
isRecording.value = true;
|
|
2215
|
+
}
|
|
2216
|
+
function stop() {
|
|
2217
|
+
if (!isRecording.value) return;
|
|
2218
|
+
isRecording.value = false;
|
|
2219
|
+
try {
|
|
2220
|
+
recognition?.stop();
|
|
2221
|
+
} catch {
|
|
2222
|
+
}
|
|
2223
|
+
recognition = null;
|
|
2224
|
+
try {
|
|
2225
|
+
if (mediaRecorder && mediaRecorder.state !== "inactive") mediaRecorder.stop();
|
|
2226
|
+
} catch {
|
|
2227
|
+
}
|
|
2228
|
+
}
|
|
2229
|
+
if (getCurrentInstance()) {
|
|
2230
|
+
onBeforeUnmount(() => {
|
|
2231
|
+
stop();
|
|
2232
|
+
revokeAudioUrl();
|
|
2233
|
+
});
|
|
2234
|
+
}
|
|
2235
|
+
return { start, stop, isRecording, text, audioUrl, error };
|
|
2236
|
+
}
|
|
2237
|
+
|
|
2098
2238
|
const _hoisted_1$d = {
|
|
2099
2239
|
key: 0,
|
|
2100
2240
|
class: "fv-sender-header"
|
|
@@ -2109,24 +2249,38 @@ const _hoisted_5$7 = {
|
|
|
2109
2249
|
key: 0,
|
|
2110
2250
|
class: "fv-sender-prefix"
|
|
2111
2251
|
};
|
|
2112
|
-
const _hoisted_6$5 =
|
|
2113
|
-
|
|
2114
|
-
|
|
2252
|
+
const _hoisted_6$5 = {
|
|
2253
|
+
class: "fv-sender-recording-wave",
|
|
2254
|
+
"aria-hidden": "true"
|
|
2255
|
+
};
|
|
2256
|
+
const _hoisted_7$4 = { class: "fv-sender-recording-duration" };
|
|
2257
|
+
const _hoisted_8$3 = ["value", "placeholder", "disabled", "readonly"];
|
|
2258
|
+
const _hoisted_9$2 = {
|
|
2259
|
+
key: 3,
|
|
2115
2260
|
class: "fv-sender-actions"
|
|
2116
2261
|
};
|
|
2117
|
-
const
|
|
2118
|
-
key:
|
|
2262
|
+
const _hoisted_10$2 = {
|
|
2263
|
+
key: 4,
|
|
2119
2264
|
class: "fv-sender-actions"
|
|
2120
2265
|
};
|
|
2121
|
-
const
|
|
2266
|
+
const _hoisted_11$2 = {
|
|
2122
2267
|
key: 0,
|
|
2123
2268
|
class: "fv-sender-action-left"
|
|
2124
2269
|
};
|
|
2125
|
-
const
|
|
2270
|
+
const _hoisted_12$2 = {
|
|
2271
|
+
class: "fv-sender-stop-ring",
|
|
2272
|
+
"aria-hidden": "true"
|
|
2273
|
+
};
|
|
2274
|
+
const _hoisted_13$2 = ["rx"];
|
|
2275
|
+
const _hoisted_14$2 = {
|
|
2126
2276
|
key: 1,
|
|
2127
2277
|
class: "fv-sender-footer"
|
|
2128
2278
|
};
|
|
2129
2279
|
const ROW_HEIGHT = 22;
|
|
2280
|
+
const WAVE_BARS = 48;
|
|
2281
|
+
const RING_HEAD = 10;
|
|
2282
|
+
const RING_TAIL = 40;
|
|
2283
|
+
const RING_LAYERS = 6;
|
|
2130
2284
|
var _sfc_main$d = /* @__PURE__ */ defineComponent({
|
|
2131
2285
|
...{ name: "FvSender" },
|
|
2132
2286
|
__name: "index",
|
|
@@ -2140,6 +2294,8 @@ var _sfc_main$d = /* @__PURE__ */ defineComponent({
|
|
|
2140
2294
|
disabled: { type: Boolean, required: false, default: false },
|
|
2141
2295
|
readOnly: { type: Boolean, required: false, default: false },
|
|
2142
2296
|
clearable: { type: Boolean, required: false, default: false },
|
|
2297
|
+
round: { type: Boolean, required: false, default: true },
|
|
2298
|
+
shadow: { type: Boolean, required: false, default: false },
|
|
2143
2299
|
inputWidth: { type: String, required: false, default: "" },
|
|
2144
2300
|
variant: { type: String, required: false, default: "default" },
|
|
2145
2301
|
submitBtnDisabled: { type: Boolean, required: false, default: false },
|
|
@@ -2312,11 +2468,136 @@ var _sfc_main$d = /* @__PURE__ */ defineComponent({
|
|
|
2312
2468
|
for (const f of Array.from(files)) emit("paste-file", f);
|
|
2313
2469
|
}
|
|
2314
2470
|
}
|
|
2315
|
-
|
|
2316
|
-
|
|
2471
|
+
const { start: startRecord, stop: stopRecord, isRecording, text: recordText, error: recordError } = useRecord();
|
|
2472
|
+
async function exitRecordingFocusInput() {
|
|
2473
|
+
await nextTick();
|
|
2474
|
+
focus("end");
|
|
2475
|
+
}
|
|
2476
|
+
function insertTextAtCursor(insert) {
|
|
2477
|
+
if (!insert) return;
|
|
2478
|
+
const el = textareaRef.value;
|
|
2479
|
+
const pos = el?.selectionStart ?? value.value.length;
|
|
2480
|
+
const next = value.value.slice(0, pos) + insert + value.value.slice(el?.selectionEnd ?? pos);
|
|
2481
|
+
setValue(next);
|
|
2482
|
+
nextTick(() => {
|
|
2483
|
+
const t = textareaRef.value;
|
|
2484
|
+
if (t) t.setSelectionRange(pos + insert.length, pos + insert.length);
|
|
2485
|
+
});
|
|
2486
|
+
}
|
|
2487
|
+
async function onSpeechClick() {
|
|
2488
|
+
if (isRecording.value) return;
|
|
2489
|
+
await startRecord();
|
|
2490
|
+
if (recordError.value) {
|
|
2491
|
+
ElMessage.error(recordError.value.message || "\u65E0\u6CD5\u8BBF\u95EE\u9EA6\u514B\u98CE");
|
|
2492
|
+
return;
|
|
2493
|
+
}
|
|
2494
|
+
emit("recording-change", true);
|
|
2495
|
+
}
|
|
2496
|
+
async function onRecordConfirm() {
|
|
2497
|
+
stopRecord();
|
|
2498
|
+
emit("recording-change", false);
|
|
2499
|
+
insertTextAtCursor(recordText.value);
|
|
2500
|
+
await exitRecordingFocusInput();
|
|
2501
|
+
}
|
|
2502
|
+
async function onRecordCancel() {
|
|
2503
|
+
stopRecord();
|
|
2504
|
+
emit("recording-change", false);
|
|
2505
|
+
await exitRecordingFocusInput();
|
|
2317
2506
|
}
|
|
2507
|
+
function onRecordingKeydown(e) {
|
|
2508
|
+
if (e.key === "Escape") {
|
|
2509
|
+
e.preventDefault();
|
|
2510
|
+
onRecordCancel();
|
|
2511
|
+
}
|
|
2512
|
+
}
|
|
2513
|
+
const waveLevels = ref(Array(WAVE_BARS).fill(0.04));
|
|
2514
|
+
let audioCtx = null;
|
|
2515
|
+
let analyserSource = null;
|
|
2516
|
+
let waveRafId = 0;
|
|
2517
|
+
function normalizeRms(rms) {
|
|
2518
|
+
const scaled = Math.pow(rms * 10, 1.5);
|
|
2519
|
+
return Math.min(1, Math.max(0.04, scaled));
|
|
2520
|
+
}
|
|
2521
|
+
async function startWaveVisualizer() {
|
|
2522
|
+
if (typeof AudioContext === "undefined" || !navigator.mediaDevices?.getUserMedia) return;
|
|
2523
|
+
try {
|
|
2524
|
+
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
2525
|
+
audioCtx = new AudioContext();
|
|
2526
|
+
analyserSource = audioCtx.createMediaStreamSource(stream);
|
|
2527
|
+
const analyser = audioCtx.createAnalyser();
|
|
2528
|
+
analyser.minDecibels = -45;
|
|
2529
|
+
analyserSource.connect(analyser);
|
|
2530
|
+
const timeData = new Uint8Array(analyser.fftSize);
|
|
2531
|
+
const processFrame = () => {
|
|
2532
|
+
analyser.getByteTimeDomainData(timeData);
|
|
2533
|
+
let sumSquares = 0;
|
|
2534
|
+
for (let i = 0; i < timeData.length; i++) {
|
|
2535
|
+
const v = (timeData[i] - 128) / 128;
|
|
2536
|
+
sumSquares += v * v;
|
|
2537
|
+
}
|
|
2538
|
+
const level = normalizeRms(Math.sqrt(sumSquares / timeData.length));
|
|
2539
|
+
waveLevels.value = [...waveLevels.value.slice(1), level];
|
|
2540
|
+
waveRafId = requestAnimationFrame(processFrame);
|
|
2541
|
+
};
|
|
2542
|
+
waveRafId = requestAnimationFrame(processFrame);
|
|
2543
|
+
stream.getTracks().forEach((t) => t.addEventListener("ended", () => stopWaveVisualizer()));
|
|
2544
|
+
analyserSourceStream = stream;
|
|
2545
|
+
} catch {
|
|
2546
|
+
}
|
|
2547
|
+
}
|
|
2548
|
+
let analyserSourceStream = null;
|
|
2549
|
+
function stopWaveVisualizer() {
|
|
2550
|
+
cancelAnimationFrame(waveRafId);
|
|
2551
|
+
waveRafId = 0;
|
|
2552
|
+
analyserSource?.disconnect();
|
|
2553
|
+
analyserSource = null;
|
|
2554
|
+
analyserSourceStream?.getTracks().forEach((t) => t.stop());
|
|
2555
|
+
analyserSourceStream = null;
|
|
2556
|
+
audioCtx?.close().catch(() => {
|
|
2557
|
+
});
|
|
2558
|
+
audioCtx = null;
|
|
2559
|
+
waveLevels.value = Array(WAVE_BARS).fill(0.04);
|
|
2560
|
+
}
|
|
2561
|
+
watch(isRecording, (rec) => {
|
|
2562
|
+
if (rec) startWaveVisualizer();
|
|
2563
|
+
else stopWaveVisualizer();
|
|
2564
|
+
});
|
|
2565
|
+
const recordSeconds = ref(0);
|
|
2566
|
+
let recordTimer = null;
|
|
2567
|
+
watch(isRecording, (rec) => {
|
|
2568
|
+
if (rec) {
|
|
2569
|
+
recordSeconds.value = 0;
|
|
2570
|
+
recordTimer = setInterval(() => {
|
|
2571
|
+
recordSeconds.value++;
|
|
2572
|
+
}, 1e3);
|
|
2573
|
+
} else if (recordTimer) {
|
|
2574
|
+
clearInterval(recordTimer);
|
|
2575
|
+
recordTimer = null;
|
|
2576
|
+
}
|
|
2577
|
+
});
|
|
2578
|
+
const recordDuration = computed(() => {
|
|
2579
|
+
const m = Math.floor(recordSeconds.value / 60);
|
|
2580
|
+
const s = recordSeconds.value % 60;
|
|
2581
|
+
return `${m}:${String(s).padStart(2, "0")}`;
|
|
2582
|
+
});
|
|
2583
|
+
onBeforeUnmount(() => {
|
|
2584
|
+
stopWaveVisualizer();
|
|
2585
|
+
if (recordTimer) clearInterval(recordTimer);
|
|
2586
|
+
});
|
|
2318
2587
|
const inputDisabled = computed(() => props.disabled || props.loading);
|
|
2319
2588
|
const inputReadonly = computed(() => props.readOnly);
|
|
2589
|
+
const ringLayers = computed(
|
|
2590
|
+
() => Array.from({ length: RING_LAYERS }, (_, i) => {
|
|
2591
|
+
const len = RING_HEAD + RING_TAIL * i / (RING_LAYERS - 1);
|
|
2592
|
+
const alpha = 0.9 * Math.pow(0.72, i);
|
|
2593
|
+
return {
|
|
2594
|
+
style: {
|
|
2595
|
+
"--ring-len": len.toFixed(2),
|
|
2596
|
+
"--ring-alpha": alpha.toFixed(3)
|
|
2597
|
+
}
|
|
2598
|
+
};
|
|
2599
|
+
})
|
|
2600
|
+
);
|
|
2320
2601
|
const slots = useSlots();
|
|
2321
2602
|
const hasActionListSlot = computed(() => !!slots["action-list"]);
|
|
2322
2603
|
__expose({ submit, cancel, clear, focus, blur, openHeader, closeHeader });
|
|
@@ -2324,7 +2605,7 @@ var _sfc_main$d = /* @__PURE__ */ defineComponent({
|
|
|
2324
2605
|
return openBlock(), createElementBlock(
|
|
2325
2606
|
"div",
|
|
2326
2607
|
{
|
|
2327
|
-
class: normalizeClass(["fv-sender", [`variant-${__props.variant}`, { "is-disabled": __props.disabled, "is-loading": __props.loading, "is-focused": isFocused.value }]])
|
|
2608
|
+
class: normalizeClass(["fv-sender", [`variant-${__props.variant}`, { "is-disabled": __props.disabled, "is-loading": __props.loading, "is-focused": isFocused.value, "has-shadow": __props.shadow }]])
|
|
2328
2609
|
},
|
|
2329
2610
|
[
|
|
2330
2611
|
createCommentVNode(" \u5934\u90E8:#header \u63D2\u69FD,openHeader/closeHeader \u63A7\u5236 "),
|
|
@@ -2342,9 +2623,89 @@ var _sfc_main$d = /* @__PURE__ */ defineComponent({
|
|
|
2342
2623
|
_ctx.$slots.prefix ? (openBlock(), createElementBlock("div", _hoisted_5$7, [
|
|
2343
2624
|
renderSlot(_ctx.$slots, "prefix")
|
|
2344
2625
|
])) : createCommentVNode("v-if", true),
|
|
2345
|
-
|
|
2626
|
+
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 "),
|
|
2627
|
+
unref(isRecording) ? (openBlock(), createElementBlock(
|
|
2346
2628
|
"div",
|
|
2347
2629
|
{
|
|
2630
|
+
key: 1,
|
|
2631
|
+
class: "fv-sender-recording",
|
|
2632
|
+
tabindex: "-1",
|
|
2633
|
+
onKeydown: onRecordingKeydown
|
|
2634
|
+
},
|
|
2635
|
+
[
|
|
2636
|
+
createVNode(unref(ElButton), {
|
|
2637
|
+
class: "fv-sender-recording-cancel",
|
|
2638
|
+
text: "",
|
|
2639
|
+
circle: "",
|
|
2640
|
+
"aria-label": "\u53D6\u6D88\u5F55\u97F3",
|
|
2641
|
+
onClick: onRecordCancel
|
|
2642
|
+
}, {
|
|
2643
|
+
default: withCtx(() => [
|
|
2644
|
+
createVNode(unref(ElIcon), null, {
|
|
2645
|
+
default: withCtx(() => [
|
|
2646
|
+
createVNode(unref(Close))
|
|
2647
|
+
]),
|
|
2648
|
+
_: 1
|
|
2649
|
+
/* STABLE */
|
|
2650
|
+
})
|
|
2651
|
+
]),
|
|
2652
|
+
_: 1
|
|
2653
|
+
/* STABLE */
|
|
2654
|
+
}),
|
|
2655
|
+
createElementVNode("div", _hoisted_6$5, [
|
|
2656
|
+
(openBlock(true), createElementBlock(
|
|
2657
|
+
Fragment,
|
|
2658
|
+
null,
|
|
2659
|
+
renderList(waveLevels.value, (lv, i) => {
|
|
2660
|
+
return openBlock(), createElementBlock(
|
|
2661
|
+
"span",
|
|
2662
|
+
{
|
|
2663
|
+
key: i,
|
|
2664
|
+
class: "fv-sender-recording-bar",
|
|
2665
|
+
style: normalizeStyle({ height: `${Math.round(lv * 100)}%` })
|
|
2666
|
+
},
|
|
2667
|
+
null,
|
|
2668
|
+
4
|
|
2669
|
+
/* STYLE */
|
|
2670
|
+
);
|
|
2671
|
+
}),
|
|
2672
|
+
128
|
|
2673
|
+
/* KEYED_FRAGMENT */
|
|
2674
|
+
))
|
|
2675
|
+
]),
|
|
2676
|
+
createElementVNode(
|
|
2677
|
+
"span",
|
|
2678
|
+
_hoisted_7$4,
|
|
2679
|
+
toDisplayString(recordDuration.value),
|
|
2680
|
+
1
|
|
2681
|
+
/* TEXT */
|
|
2682
|
+
),
|
|
2683
|
+
createVNode(unref(ElButton), {
|
|
2684
|
+
class: "fv-sender-recording-confirm",
|
|
2685
|
+
type: "primary",
|
|
2686
|
+
circle: "",
|
|
2687
|
+
"aria-label": "\u786E\u8BA4\u5F55\u97F3",
|
|
2688
|
+
onClick: onRecordConfirm
|
|
2689
|
+
}, {
|
|
2690
|
+
default: withCtx(() => [
|
|
2691
|
+
createVNode(unref(ElIcon), null, {
|
|
2692
|
+
default: withCtx(() => [
|
|
2693
|
+
createVNode(unref(Check))
|
|
2694
|
+
]),
|
|
2695
|
+
_: 1
|
|
2696
|
+
/* STABLE */
|
|
2697
|
+
})
|
|
2698
|
+
]),
|
|
2699
|
+
_: 1
|
|
2700
|
+
/* STABLE */
|
|
2701
|
+
})
|
|
2702
|
+
],
|
|
2703
|
+
32
|
|
2704
|
+
/* NEED_HYDRATION */
|
|
2705
|
+
)) : (openBlock(), createElementBlock(
|
|
2706
|
+
"div",
|
|
2707
|
+
{
|
|
2708
|
+
key: 2,
|
|
2348
2709
|
class: "fv-sender-input",
|
|
2349
2710
|
style: normalizeStyle(__props.inputWidth && __props.variant === "default" ? { width: __props.inputWidth } : void 0)
|
|
2350
2711
|
},
|
|
@@ -2364,7 +2725,7 @@ var _sfc_main$d = /* @__PURE__ */ defineComponent({
|
|
|
2364
2725
|
onPaste,
|
|
2365
2726
|
onFocus: _cache[0] || (_cache[0] = ($event) => isFocused.value = true),
|
|
2366
2727
|
onBlur: onTextareaBlur
|
|
2367
|
-
}, null, 40,
|
|
2728
|
+
}, null, 40, _hoisted_8$3),
|
|
2368
2729
|
createCommentVNode(" \u6307\u4EE4\u5F39\u6846:\u5185\u7F6E el-popover,\u5B9A\u4F4D\u6309 triggerPopover* \u7CFB\u5217 "),
|
|
2369
2730
|
createVNode(unref(ElPopover), {
|
|
2370
2731
|
visible: triggerVisible.value && __props.triggerStrings.length > 0,
|
|
@@ -2395,12 +2756,12 @@ var _sfc_main$d = /* @__PURE__ */ defineComponent({
|
|
|
2395
2756
|
],
|
|
2396
2757
|
4
|
|
2397
2758
|
/* STYLE */
|
|
2398
|
-
),
|
|
2759
|
+
)),
|
|
2399
2760
|
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) "),
|
|
2400
|
-
hasActionListSlot.value ? (openBlock(), createElementBlock("div",
|
|
2761
|
+
hasActionListSlot.value ? (openBlock(), createElementBlock("div", _hoisted_9$2, [
|
|
2401
2762
|
renderSlot(_ctx.$slots, "action-list")
|
|
2402
|
-
])) : (openBlock(), createElementBlock("div",
|
|
2403
|
-
_ctx.$slots["action-left"] ? (openBlock(), createElementBlock("div",
|
|
2763
|
+
])) : (openBlock(), createElementBlock("div", _hoisted_10$2, [
|
|
2764
|
+
_ctx.$slots["action-left"] ? (openBlock(), createElementBlock("div", _hoisted_11$2, [
|
|
2404
2765
|
renderSlot(_ctx.$slots, "action-left")
|
|
2405
2766
|
])) : createCommentVNode("v-if", true),
|
|
2406
2767
|
__props.clearable && value.value ? (openBlock(), createBlock(unref(ElButton), {
|
|
@@ -2423,7 +2784,7 @@ var _sfc_main$d = /* @__PURE__ */ defineComponent({
|
|
|
2423
2784
|
_: 1
|
|
2424
2785
|
/* STABLE */
|
|
2425
2786
|
}, 8, ["disabled"])) : createCommentVNode("v-if", true),
|
|
2426
|
-
__props.allowSpeech ? (openBlock(), createBlock(unref(ElButton), {
|
|
2787
|
+
__props.allowSpeech && !unref(isRecording) ? (openBlock(), createBlock(unref(ElButton), {
|
|
2427
2788
|
key: 2,
|
|
2428
2789
|
class: "fv-sender-speech",
|
|
2429
2790
|
text: "",
|
|
@@ -2443,29 +2804,49 @@ var _sfc_main$d = /* @__PURE__ */ defineComponent({
|
|
|
2443
2804
|
_: 1
|
|
2444
2805
|
/* STABLE */
|
|
2445
2806
|
}, 8, ["disabled"])) : createCommentVNode("v-if", true),
|
|
2446
|
-
createCommentVNode(" loading \u2192 \u505C\u6B62\u6309\u94AE
|
|
2807
|
+
createCommentVNode(" loading \u2192 \u505C\u6B62\u6309\u94AE:SVG \u5149\u5E26\u6CBF\u8FB9\u6846\u5300\u901F\u6D41\u8F6C,\u65B9/\u5706\u6309\u94AE\u5747\u9002\u7528 "),
|
|
2447
2808
|
__props.loading ? (openBlock(), createBlock(unref(ElButton), {
|
|
2448
2809
|
key: 3,
|
|
2449
2810
|
class: "fv-sender-stop",
|
|
2450
2811
|
type: "primary",
|
|
2812
|
+
circle: __props.round,
|
|
2451
2813
|
"aria-label": "\u505C\u6B62",
|
|
2452
2814
|
onClick: cancel
|
|
2453
2815
|
}, {
|
|
2454
2816
|
default: withCtx(() => [
|
|
2455
2817
|
createVNode(unref(ElIcon), null, {
|
|
2456
2818
|
default: withCtx(() => [
|
|
2457
|
-
createVNode(
|
|
2819
|
+
createVNode(_sfc_main$e)
|
|
2458
2820
|
]),
|
|
2459
2821
|
_: 1
|
|
2460
2822
|
/* STABLE */
|
|
2461
|
-
})
|
|
2823
|
+
}),
|
|
2824
|
+
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 '),
|
|
2825
|
+
(openBlock(), createElementBlock("svg", _hoisted_12$2, [
|
|
2826
|
+
(openBlock(true), createElementBlock(
|
|
2827
|
+
Fragment,
|
|
2828
|
+
null,
|
|
2829
|
+
renderList(ringLayers.value, (layer, i) => {
|
|
2830
|
+
return openBlock(), createElementBlock("rect", {
|
|
2831
|
+
key: i,
|
|
2832
|
+
class: "fv-sender-stop-ring-rect",
|
|
2833
|
+
style: normalizeStyle(layer.style),
|
|
2834
|
+
rx: __props.round ? "50%" : 2.5,
|
|
2835
|
+
pathLength: "100"
|
|
2836
|
+
}, null, 12, _hoisted_13$2);
|
|
2837
|
+
}),
|
|
2838
|
+
128
|
|
2839
|
+
/* KEYED_FRAGMENT */
|
|
2840
|
+
))
|
|
2841
|
+
]))
|
|
2462
2842
|
]),
|
|
2463
2843
|
_: 1
|
|
2464
2844
|
/* STABLE */
|
|
2465
|
-
})) : (openBlock(), createBlock(unref(ElButton), {
|
|
2845
|
+
}, 8, ["circle"])) : (openBlock(), createBlock(unref(ElButton), {
|
|
2466
2846
|
key: 4,
|
|
2467
2847
|
class: "fv-sender-submit",
|
|
2468
2848
|
type: "primary",
|
|
2849
|
+
circle: __props.round,
|
|
2469
2850
|
disabled: !submitable(),
|
|
2470
2851
|
"aria-label": "\u53D1\u9001",
|
|
2471
2852
|
onClick: doSubmit
|
|
@@ -2481,13 +2862,13 @@ var _sfc_main$d = /* @__PURE__ */ defineComponent({
|
|
|
2481
2862
|
]),
|
|
2482
2863
|
_: 1
|
|
2483
2864
|
/* STABLE */
|
|
2484
|
-
}, 8, ["disabled"]))
|
|
2865
|
+
}, 8, ["circle", "disabled"]))
|
|
2485
2866
|
]))
|
|
2486
2867
|
]),
|
|
2487
2868
|
createCommentVNode(" /fv-sender-row ")
|
|
2488
2869
|
]),
|
|
2489
2870
|
createCommentVNode(" \u5E95\u90E8 "),
|
|
2490
|
-
_ctx.$slots.footer ? (openBlock(), createElementBlock("div",
|
|
2871
|
+
_ctx.$slots.footer ? (openBlock(), createElementBlock("div", _hoisted_14$2, [
|
|
2491
2872
|
renderSlot(_ctx.$slots, "footer")
|
|
2492
2873
|
])) : createCommentVNode("v-if", true)
|
|
2493
2874
|
],
|
|
@@ -5792,7 +6173,7 @@ var _sfc_main$3 = /* @__PURE__ */ defineComponent({
|
|
|
5792
6173
|
"auto-collapse": __props.autoCollapse
|
|
5793
6174
|
}, {
|
|
5794
6175
|
content: withCtx(() => [
|
|
5795
|
-
createVNode(_sfc_main$
|
|
6176
|
+
createVNode(_sfc_main$i, {
|
|
5796
6177
|
content: __props.message.reasoning ?? ""
|
|
5797
6178
|
}, null, 8, ["content"])
|
|
5798
6179
|
]),
|
|
@@ -5807,7 +6188,7 @@ var _sfc_main$3 = /* @__PURE__ */ defineComponent({
|
|
|
5807
6188
|
toDisplayString(__props.message.error || "\u751F\u6210\u5931\u8D25"),
|
|
5808
6189
|
1
|
|
5809
6190
|
/* TEXT */
|
|
5810
|
-
)) : __props.message.content ? (openBlock(), createBlock(_sfc_main$
|
|
6191
|
+
)) : __props.message.content ? (openBlock(), createBlock(_sfc_main$i, {
|
|
5811
6192
|
key: 1,
|
|
5812
6193
|
content: __props.message.content
|
|
5813
6194
|
}, null, 8, ["content"])) : __props.message.status === "pending" || __props.message.status === "streaming" ? (openBlock(), createElementBlock("span", _hoisted_12, [
|
|
@@ -6378,7 +6759,10 @@ var _sfc_main$1 = /* @__PURE__ */ defineComponent({
|
|
|
6378
6759
|
}
|
|
6379
6760
|
});
|
|
6380
6761
|
|
|
6381
|
-
const _hoisted_1 = {
|
|
6762
|
+
const _hoisted_1 = {
|
|
6763
|
+
key: 0,
|
|
6764
|
+
class: "fv-ai-chat-header"
|
|
6765
|
+
};
|
|
6382
6766
|
const _hoisted_2 = { class: "fv-ai-chat-title" };
|
|
6383
6767
|
const _hoisted_3 = { class: "fv-ai-chat-body" };
|
|
6384
6768
|
const _hoisted_4 = { class: "fv-ai-chat-footer" };
|
|
@@ -6393,7 +6777,10 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
6393
6777
|
adapter: { type: Object, required: false, default: void 0 },
|
|
6394
6778
|
messages: { type: Array, required: false, default: void 0 },
|
|
6395
6779
|
title: { type: String, required: false, default: "" },
|
|
6780
|
+
showHeader: { type: Boolean, required: false, default: false },
|
|
6781
|
+
centerWelcome: { type: Boolean, required: false, default: true },
|
|
6396
6782
|
placeholder: { type: String, required: false, default: "" },
|
|
6783
|
+
senderShadow: { type: Boolean, required: false, default: true },
|
|
6397
6784
|
suggestions: { type: Array, required: false, default: () => [] },
|
|
6398
6785
|
features: { type: Object, required: false, default: () => ({}) },
|
|
6399
6786
|
allowAttachments: { type: Boolean, required: false, default: false },
|
|
@@ -6441,6 +6828,7 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
6441
6828
|
const { send, stop: stopChat, regenerate: regenerateChat, msgs, isLoading } = chat;
|
|
6442
6829
|
const nodeTable = chat.messages;
|
|
6443
6830
|
const chain = chat.chain;
|
|
6831
|
+
const isCenterWelcome = computed(() => props.centerWelcome && chain.value.length === 0);
|
|
6444
6832
|
let flushTimer = null;
|
|
6445
6833
|
watch(chain, (c) => {
|
|
6446
6834
|
if (flushTimer) clearTimeout(flushTimer);
|
|
@@ -6606,11 +6994,11 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
6606
6994
|
return openBlock(), createElementBlock(
|
|
6607
6995
|
"div",
|
|
6608
6996
|
{
|
|
6609
|
-
class: normalizeClass(["fv-ai-chat", { "is-dark": isDark.value }])
|
|
6997
|
+
class: normalizeClass(["fv-ai-chat", { "is-dark": isDark.value, "is-center-welcome": isCenterWelcome.value }])
|
|
6610
6998
|
},
|
|
6611
6999
|
[
|
|
6612
7000
|
createCommentVNode(" \u9876\u680F:\u6807\u9898 + \u6A21\u578B\u9009\u62E9\u5668(models \u6709\u503C\u65F6 multiple) "),
|
|
6613
|
-
|
|
7001
|
+
__props.showHeader ? (openBlock(), createElementBlock("div", _hoisted_1, [
|
|
6614
7002
|
createElementVNode(
|
|
6615
7003
|
"div",
|
|
6616
7004
|
_hoisted_2,
|
|
@@ -6646,7 +7034,7 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
6646
7034
|
_: 1
|
|
6647
7035
|
/* STABLE */
|
|
6648
7036
|
}, 8, ["modelValue"])) : createCommentVNode("v-if", true)
|
|
6649
|
-
]),
|
|
7037
|
+
])) : createCommentVNode("v-if", true),
|
|
6650
7038
|
createCommentVNode(" \u6D88\u606F\u533A:\u7A7A\u65F6 Welcome + Prompts(AiMessages \u5185\u7F6E);\u5F00\u542F artifacts \u65F6\u53F3\u4FA7\u62FC\u9884\u89C8\u9762\u677F "),
|
|
6651
7039
|
createElementVNode("div", _hoisted_3, [
|
|
6652
7040
|
createVNode(_sfc_main$2, {
|
|
@@ -6697,6 +7085,7 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
6697
7085
|
createVNode(_sfc_main$d, {
|
|
6698
7086
|
placeholder: __props.placeholder,
|
|
6699
7087
|
loading: unref(isLoading),
|
|
7088
|
+
shadow: __props.senderShadow,
|
|
6700
7089
|
variant: "updown",
|
|
6701
7090
|
maxlength: 8e3,
|
|
6702
7091
|
"allow-empty-submit": __props.allowAttachments && !!pendingFiles.value.length,
|
|
@@ -6741,7 +7130,7 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
6741
7130
|
]),
|
|
6742
7131
|
key: "2"
|
|
6743
7132
|
} : void 0
|
|
6744
|
-
]), 1032, ["placeholder", "loading", "allow-empty-submit"])
|
|
7133
|
+
]), 1032, ["placeholder", "loading", "shadow", "allow-empty-submit"])
|
|
6745
7134
|
])
|
|
6746
7135
|
],
|
|
6747
7136
|
2
|
|
@@ -6872,105 +7261,6 @@ function XRequest(url, options = {}) {
|
|
|
6872
7261
|
});
|
|
6873
7262
|
}
|
|
6874
7263
|
|
|
6875
|
-
function getSpeechRecognitionCtor() {
|
|
6876
|
-
if (typeof window === "undefined") return void 0;
|
|
6877
|
-
const w = window;
|
|
6878
|
-
const ctor = w.SpeechRecognition ?? w.webkitSpeechRecognition;
|
|
6879
|
-
return typeof ctor === "function" ? ctor : void 0;
|
|
6880
|
-
}
|
|
6881
|
-
function useRecord() {
|
|
6882
|
-
const isRecording = ref(false);
|
|
6883
|
-
const text = ref("");
|
|
6884
|
-
const audioUrl = ref(null);
|
|
6885
|
-
const error = ref(null);
|
|
6886
|
-
let mediaStream = null;
|
|
6887
|
-
let mediaRecorder = null;
|
|
6888
|
-
let chunks = [];
|
|
6889
|
-
let recognition = null;
|
|
6890
|
-
let finalText = "";
|
|
6891
|
-
function revokeAudioUrl() {
|
|
6892
|
-
if (audioUrl.value) {
|
|
6893
|
-
URL.revokeObjectURL(audioUrl.value);
|
|
6894
|
-
audioUrl.value = null;
|
|
6895
|
-
}
|
|
6896
|
-
}
|
|
6897
|
-
async function start() {
|
|
6898
|
-
if (isRecording.value) return;
|
|
6899
|
-
error.value = null;
|
|
6900
|
-
text.value = "";
|
|
6901
|
-
finalText = "";
|
|
6902
|
-
chunks = [];
|
|
6903
|
-
revokeAudioUrl();
|
|
6904
|
-
if (typeof MediaRecorder === "undefined" || !navigator.mediaDevices?.getUserMedia) {
|
|
6905
|
-
error.value = new Error("\u5F53\u524D\u73AF\u5883\u4E0D\u652F\u6301\u97F3\u9891\u5F55\u5236");
|
|
6906
|
-
return;
|
|
6907
|
-
}
|
|
6908
|
-
try {
|
|
6909
|
-
mediaStream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
6910
|
-
} catch (e) {
|
|
6911
|
-
error.value = e instanceof Error ? e : new Error(String(e));
|
|
6912
|
-
return;
|
|
6913
|
-
}
|
|
6914
|
-
mediaRecorder = new MediaRecorder(mediaStream);
|
|
6915
|
-
mediaRecorder.ondataavailable = (e) => {
|
|
6916
|
-
if (e.data && e.data.size > 0) chunks.push(e.data);
|
|
6917
|
-
};
|
|
6918
|
-
mediaRecorder.onstop = () => {
|
|
6919
|
-
if (chunks.length > 0) {
|
|
6920
|
-
const blob = new Blob(chunks, { type: mediaRecorder?.mimeType || "audio/webm" });
|
|
6921
|
-
audioUrl.value = URL.createObjectURL(blob);
|
|
6922
|
-
}
|
|
6923
|
-
mediaStream?.getTracks().forEach((t) => t.stop());
|
|
6924
|
-
mediaStream = null;
|
|
6925
|
-
};
|
|
6926
|
-
const SRCtor = getSpeechRecognitionCtor();
|
|
6927
|
-
if (SRCtor) {
|
|
6928
|
-
try {
|
|
6929
|
-
recognition = new SRCtor();
|
|
6930
|
-
recognition.continuous = true;
|
|
6931
|
-
recognition.interimResults = true;
|
|
6932
|
-
recognition.onresult = (event) => {
|
|
6933
|
-
let interim = "";
|
|
6934
|
-
for (let i = event.resultIndex; i < event.results.length; i++) {
|
|
6935
|
-
const r = event.results[i];
|
|
6936
|
-
if (r.isFinal) finalText += r[0].transcript;
|
|
6937
|
-
else interim += r[0].transcript;
|
|
6938
|
-
}
|
|
6939
|
-
text.value = finalText + interim;
|
|
6940
|
-
};
|
|
6941
|
-
recognition.onerror = (ev) => {
|
|
6942
|
-
error.value = new Error(`\u8BED\u97F3\u8BC6\u522B\u9519\u8BEF: ${ev?.error ?? "unknown"}`);
|
|
6943
|
-
};
|
|
6944
|
-
recognition.start();
|
|
6945
|
-
} catch {
|
|
6946
|
-
recognition = null;
|
|
6947
|
-
}
|
|
6948
|
-
}
|
|
6949
|
-
mediaRecorder.start();
|
|
6950
|
-
isRecording.value = true;
|
|
6951
|
-
}
|
|
6952
|
-
function stop() {
|
|
6953
|
-
if (!isRecording.value) return;
|
|
6954
|
-
isRecording.value = false;
|
|
6955
|
-
try {
|
|
6956
|
-
recognition?.stop();
|
|
6957
|
-
} catch {
|
|
6958
|
-
}
|
|
6959
|
-
recognition = null;
|
|
6960
|
-
try {
|
|
6961
|
-
if (mediaRecorder && mediaRecorder.state !== "inactive") mediaRecorder.stop();
|
|
6962
|
-
} catch {
|
|
6963
|
-
}
|
|
6964
|
-
}
|
|
6965
|
-
if (getCurrentInstance()) {
|
|
6966
|
-
onBeforeUnmount(() => {
|
|
6967
|
-
stop();
|
|
6968
|
-
revokeAudioUrl();
|
|
6969
|
-
});
|
|
6970
|
-
}
|
|
6971
|
-
return { start, stop, isRecording, text, audioUrl, error };
|
|
6972
|
-
}
|
|
6973
|
-
|
|
6974
7264
|
class DetOmsError extends Error {
|
|
6975
7265
|
constructor(message, code) {
|
|
6976
7266
|
super(message);
|
|
@@ -7166,4 +7456,4 @@ function createMemoryAdapter() {
|
|
|
7166
7456
|
|
|
7167
7457
|
const version = "0.1.0";
|
|
7168
7458
|
|
|
7169
|
-
export { DetOmsChatAdapter, DetOmsError, _sfc_main$1 as FvAiArtifacts, _sfc_main as FvAiChat, _sfc_main$3 as FvAiMessage, _sfc_main$2 as FvAiMessages, _sfc_main$5 as FvAttachments, _sfc_main$
|
|
7459
|
+
export { DetOmsChatAdapter, DetOmsError, _sfc_main$1 as FvAiArtifacts, _sfc_main as FvAiChat, _sfc_main$3 as FvAiMessage, _sfc_main$2 as FvAiMessages, _sfc_main$5 as FvAttachments, _sfc_main$g as FvBubble, _sfc_main$f as FvBubbleList, _sfc_main$4 as FvConversations, _sfc_main$b as FvEditorSender, _sfc_main$6 as FvFilesCard, _sfc_main$i as FvMarkdown, _sfc_main$c as FvMentionSender, _sfc_main$7 as FvPrompts, _sfc_main$d as FvSender, _sfc_main$a as FvThinking, _sfc_main$9 as FvThoughtChain, _sfc_main$h as FvTypewriter, _sfc_main$8 as FvWelcome, OpenAIAdapter, XRequest, createLocalStorageAdapter, createMemoryAdapter, createMessageTree, createSSEParser, useChat, useMessages, useRecord, useSend, useXStream, version };
|