@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/es/index.mjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
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
10
|
function unwrapPlugin(plugin) {
|
|
11
11
|
const candidate = plugin && typeof plugin === "object" && "default" in plugin ? plugin.default : plugin;
|
|
@@ -1526,8 +1526,8 @@ function prismHighlight(str, lang) {
|
|
|
1526
1526
|
}
|
|
1527
1527
|
}
|
|
1528
1528
|
|
|
1529
|
-
const _hoisted_1$
|
|
1530
|
-
var _sfc_main$
|
|
1529
|
+
const _hoisted_1$i = ["innerHTML"];
|
|
1530
|
+
var _sfc_main$i = /* @__PURE__ */ defineComponent({
|
|
1531
1531
|
...{ name: "FvMarkdown" },
|
|
1532
1532
|
__name: "index",
|
|
1533
1533
|
props: {
|
|
@@ -1550,12 +1550,12 @@ var _sfc_main$h = /* @__PURE__ */ defineComponent({
|
|
|
1550
1550
|
return openBlock(), createElementBlock("div", {
|
|
1551
1551
|
class: "fv-xmarkdown markdown-body",
|
|
1552
1552
|
innerHTML: html.value
|
|
1553
|
-
}, null, 8, _hoisted_1$
|
|
1553
|
+
}, null, 8, _hoisted_1$i);
|
|
1554
1554
|
};
|
|
1555
1555
|
}
|
|
1556
1556
|
});
|
|
1557
1557
|
|
|
1558
|
-
const _hoisted_1$
|
|
1558
|
+
const _hoisted_1$h = {
|
|
1559
1559
|
key: 1,
|
|
1560
1560
|
class: "fv-typewriter-text"
|
|
1561
1561
|
};
|
|
@@ -1563,7 +1563,7 @@ const _hoisted_2$f = {
|
|
|
1563
1563
|
key: 0,
|
|
1564
1564
|
class: "fv-typewriter-suffix"
|
|
1565
1565
|
};
|
|
1566
|
-
var _sfc_main$
|
|
1566
|
+
var _sfc_main$h = /* @__PURE__ */ defineComponent({
|
|
1567
1567
|
...{ name: "FvTypewriter" },
|
|
1568
1568
|
__name: "index",
|
|
1569
1569
|
props: {
|
|
@@ -1653,11 +1653,11 @@ var _sfc_main$g = /* @__PURE__ */ defineComponent({
|
|
|
1653
1653
|
},
|
|
1654
1654
|
[
|
|
1655
1655
|
createCommentVNode(" markdown \u6A21\u5F0F:suffix \u4E0D\u8FFD\u52A0(element-plus-x \u884C\u4E3A),isTyping \u900F\u4F20\u7ED9 XMarkdown \u4F5C\u6837\u5F0F\u94A9\u5B50 "),
|
|
1656
|
-
__props.isMarkdown ? (openBlock(), createBlock(_sfc_main$
|
|
1656
|
+
__props.isMarkdown ? (openBlock(), createBlock(_sfc_main$i, {
|
|
1657
1657
|
key: 0,
|
|
1658
1658
|
content: renderedContent.value,
|
|
1659
1659
|
"is-typing": isTyping.value
|
|
1660
|
-
}, null, 8, ["content", "is-typing"])) : (openBlock(), createElementBlock("span", _hoisted_1$
|
|
1660
|
+
}, null, 8, ["content", "is-typing"])) : (openBlock(), createElementBlock("span", _hoisted_1$h, [
|
|
1661
1661
|
createTextVNode(
|
|
1662
1662
|
toDisplayString(renderedContent.value),
|
|
1663
1663
|
1
|
|
@@ -1692,7 +1692,7 @@ var _sfc_main$g = /* @__PURE__ */ defineComponent({
|
|
|
1692
1692
|
}
|
|
1693
1693
|
});
|
|
1694
1694
|
|
|
1695
|
-
const _hoisted_1$
|
|
1695
|
+
const _hoisted_1$g = {
|
|
1696
1696
|
key: 0,
|
|
1697
1697
|
class: "fv-bubble-avatar"
|
|
1698
1698
|
};
|
|
@@ -1713,7 +1713,7 @@ const _hoisted_6$6 = {
|
|
|
1713
1713
|
key: 1,
|
|
1714
1714
|
class: "fv-bubble-footer"
|
|
1715
1715
|
};
|
|
1716
|
-
var _sfc_main$
|
|
1716
|
+
var _sfc_main$g = /* @__PURE__ */ defineComponent({
|
|
1717
1717
|
...{ name: "FvBubble" },
|
|
1718
1718
|
__name: "index",
|
|
1719
1719
|
props: {
|
|
@@ -1780,7 +1780,7 @@ var _sfc_main$f = /* @__PURE__ */ defineComponent({
|
|
|
1780
1780
|
},
|
|
1781
1781
|
[
|
|
1782
1782
|
createCommentVNode(" \u5934\u50CF:placement \u540C\u7F18\u6392\u5217(end \u7ECF row-reverse \u7FFB\u8F6C\u5230\u53F3\u4FA7),#avatar \u63D2\u69FD\u4F18\u5148 "),
|
|
1783
|
-
_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, [
|
|
1784
1784
|
_ctx.$slots.avatar ? renderSlot(_ctx.$slots, "avatar", {}, void 0, void 0, 0) : (openBlock(), createBlock(unref(ElAvatar), {
|
|
1785
1785
|
key: 1,
|
|
1786
1786
|
size: __props.avatarSize || void 0,
|
|
@@ -1838,7 +1838,7 @@ var _sfc_main$f = /* @__PURE__ */ defineComponent({
|
|
|
1838
1838
|
{ key: 2 },
|
|
1839
1839
|
[
|
|
1840
1840
|
createCommentVNode(" typing \u900F\u4F20 Typewriter;\u975E typing:isMarkdown \u2192 XMarkdown,\u5426\u5219\u7EAF\u6587\u672C "),
|
|
1841
|
-
createVNode(_sfc_main$
|
|
1841
|
+
createVNode(_sfc_main$h, {
|
|
1842
1842
|
ref_key: "twRef",
|
|
1843
1843
|
ref: twRef,
|
|
1844
1844
|
content: __props.content,
|
|
@@ -1852,7 +1852,7 @@ var _sfc_main$f = /* @__PURE__ */ defineComponent({
|
|
|
1852
1852
|
],
|
|
1853
1853
|
2112
|
|
1854
1854
|
/* STABLE_FRAGMENT, DEV_ROOT_FRAGMENT */
|
|
1855
|
-
)) : __props.isMarkdown ? (openBlock(), createBlock(_sfc_main$
|
|
1855
|
+
)) : __props.isMarkdown ? (openBlock(), createBlock(_sfc_main$i, {
|
|
1856
1856
|
key: 3,
|
|
1857
1857
|
content: __props.content
|
|
1858
1858
|
}, null, 8, ["content"])) : (openBlock(), createElementBlock(
|
|
@@ -1878,8 +1878,8 @@ var _sfc_main$f = /* @__PURE__ */ defineComponent({
|
|
|
1878
1878
|
}
|
|
1879
1879
|
});
|
|
1880
1880
|
|
|
1881
|
-
const _hoisted_1$
|
|
1882
|
-
var _sfc_main$
|
|
1881
|
+
const _hoisted_1$f = { class: "fv-bubble-list" };
|
|
1882
|
+
var _sfc_main$f = /* @__PURE__ */ defineComponent({
|
|
1883
1883
|
...{ name: "FvBubbleList" },
|
|
1884
1884
|
__name: "index",
|
|
1885
1885
|
props: {
|
|
@@ -1979,7 +1979,7 @@ var _sfc_main$e = /* @__PURE__ */ defineComponent({
|
|
|
1979
1979
|
}));
|
|
1980
1980
|
__expose({ scrollToTop, scrollToBottom, scrollToBubble });
|
|
1981
1981
|
return (_ctx, _cache) => {
|
|
1982
|
-
return openBlock(), createElementBlock("div", _hoisted_1$
|
|
1982
|
+
return openBlock(), createElementBlock("div", _hoisted_1$f, [
|
|
1983
1983
|
createElementVNode(
|
|
1984
1984
|
"div",
|
|
1985
1985
|
{
|
|
@@ -1994,7 +1994,7 @@ var _sfc_main$e = /* @__PURE__ */ defineComponent({
|
|
|
1994
1994
|
Fragment,
|
|
1995
1995
|
null,
|
|
1996
1996
|
renderList(__props.list, (item, index) => {
|
|
1997
|
-
return openBlock(), createBlock(_sfc_main$
|
|
1997
|
+
return openBlock(), createBlock(_sfc_main$g, mergeProps({
|
|
1998
1998
|
key: item.key,
|
|
1999
1999
|
ref_for: true,
|
|
2000
2000
|
ref: (el) => setBubbleRef(el, index)
|
|
@@ -2102,6 +2102,139 @@ var _sfc_main$e = /* @__PURE__ */ defineComponent({
|
|
|
2102
2102
|
}
|
|
2103
2103
|
});
|
|
2104
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
|
+
|
|
2105
2238
|
const _hoisted_1$d = {
|
|
2106
2239
|
key: 0,
|
|
2107
2240
|
class: "fv-sender-header"
|
|
@@ -2116,24 +2249,38 @@ const _hoisted_5$7 = {
|
|
|
2116
2249
|
key: 0,
|
|
2117
2250
|
class: "fv-sender-prefix"
|
|
2118
2251
|
};
|
|
2119
|
-
const _hoisted_6$5 =
|
|
2120
|
-
|
|
2121
|
-
|
|
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,
|
|
2122
2260
|
class: "fv-sender-actions"
|
|
2123
2261
|
};
|
|
2124
|
-
const
|
|
2125
|
-
key:
|
|
2262
|
+
const _hoisted_10$2 = {
|
|
2263
|
+
key: 4,
|
|
2126
2264
|
class: "fv-sender-actions"
|
|
2127
2265
|
};
|
|
2128
|
-
const
|
|
2266
|
+
const _hoisted_11$2 = {
|
|
2129
2267
|
key: 0,
|
|
2130
2268
|
class: "fv-sender-action-left"
|
|
2131
2269
|
};
|
|
2132
|
-
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 = {
|
|
2133
2276
|
key: 1,
|
|
2134
2277
|
class: "fv-sender-footer"
|
|
2135
2278
|
};
|
|
2136
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;
|
|
2137
2284
|
var _sfc_main$d = /* @__PURE__ */ defineComponent({
|
|
2138
2285
|
...{ name: "FvSender" },
|
|
2139
2286
|
__name: "index",
|
|
@@ -2147,6 +2294,8 @@ var _sfc_main$d = /* @__PURE__ */ defineComponent({
|
|
|
2147
2294
|
disabled: { type: Boolean, required: false, default: false },
|
|
2148
2295
|
readOnly: { type: Boolean, required: false, default: false },
|
|
2149
2296
|
clearable: { type: Boolean, required: false, default: false },
|
|
2297
|
+
round: { type: Boolean, required: false, default: true },
|
|
2298
|
+
shadow: { type: Boolean, required: false, default: false },
|
|
2150
2299
|
inputWidth: { type: String, required: false, default: "" },
|
|
2151
2300
|
variant: { type: String, required: false, default: "default" },
|
|
2152
2301
|
submitBtnDisabled: { type: Boolean, required: false, default: false },
|
|
@@ -2319,11 +2468,136 @@ var _sfc_main$d = /* @__PURE__ */ defineComponent({
|
|
|
2319
2468
|
for (const f of Array.from(files)) emit("paste-file", f);
|
|
2320
2469
|
}
|
|
2321
2470
|
}
|
|
2322
|
-
|
|
2323
|
-
|
|
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();
|
|
2324
2501
|
}
|
|
2502
|
+
async function onRecordCancel() {
|
|
2503
|
+
stopRecord();
|
|
2504
|
+
emit("recording-change", false);
|
|
2505
|
+
await exitRecordingFocusInput();
|
|
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
|
+
});
|
|
2325
2587
|
const inputDisabled = computed(() => props.disabled || props.loading);
|
|
2326
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
|
+
);
|
|
2327
2601
|
const slots = useSlots();
|
|
2328
2602
|
const hasActionListSlot = computed(() => !!slots["action-list"]);
|
|
2329
2603
|
__expose({ submit, cancel, clear, focus, blur, openHeader, closeHeader });
|
|
@@ -2331,7 +2605,7 @@ var _sfc_main$d = /* @__PURE__ */ defineComponent({
|
|
|
2331
2605
|
return openBlock(), createElementBlock(
|
|
2332
2606
|
"div",
|
|
2333
2607
|
{
|
|
2334
|
-
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 }]])
|
|
2335
2609
|
},
|
|
2336
2610
|
[
|
|
2337
2611
|
createCommentVNode(" \u5934\u90E8:#header \u63D2\u69FD,openHeader/closeHeader \u63A7\u5236 "),
|
|
@@ -2349,9 +2623,89 @@ var _sfc_main$d = /* @__PURE__ */ defineComponent({
|
|
|
2349
2623
|
_ctx.$slots.prefix ? (openBlock(), createElementBlock("div", _hoisted_5$7, [
|
|
2350
2624
|
renderSlot(_ctx.$slots, "prefix")
|
|
2351
2625
|
])) : createCommentVNode("v-if", true),
|
|
2352
|
-
|
|
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(
|
|
2353
2628
|
"div",
|
|
2354
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,
|
|
2355
2709
|
class: "fv-sender-input",
|
|
2356
2710
|
style: normalizeStyle(__props.inputWidth && __props.variant === "default" ? { width: __props.inputWidth } : void 0)
|
|
2357
2711
|
},
|
|
@@ -2371,7 +2725,7 @@ var _sfc_main$d = /* @__PURE__ */ defineComponent({
|
|
|
2371
2725
|
onPaste,
|
|
2372
2726
|
onFocus: _cache[0] || (_cache[0] = ($event) => isFocused.value = true),
|
|
2373
2727
|
onBlur: onTextareaBlur
|
|
2374
|
-
}, null, 40,
|
|
2728
|
+
}, null, 40, _hoisted_8$3),
|
|
2375
2729
|
createCommentVNode(" \u6307\u4EE4\u5F39\u6846:\u5185\u7F6E el-popover,\u5B9A\u4F4D\u6309 triggerPopover* \u7CFB\u5217 "),
|
|
2376
2730
|
createVNode(unref(ElPopover), {
|
|
2377
2731
|
visible: triggerVisible.value && __props.triggerStrings.length > 0,
|
|
@@ -2402,12 +2756,12 @@ var _sfc_main$d = /* @__PURE__ */ defineComponent({
|
|
|
2402
2756
|
],
|
|
2403
2757
|
4
|
|
2404
2758
|
/* STYLE */
|
|
2405
|
-
),
|
|
2759
|
+
)),
|
|
2406
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) "),
|
|
2407
|
-
hasActionListSlot.value ? (openBlock(), createElementBlock("div",
|
|
2761
|
+
hasActionListSlot.value ? (openBlock(), createElementBlock("div", _hoisted_9$2, [
|
|
2408
2762
|
renderSlot(_ctx.$slots, "action-list")
|
|
2409
|
-
])) : (openBlock(), createElementBlock("div",
|
|
2410
|
-
_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, [
|
|
2411
2765
|
renderSlot(_ctx.$slots, "action-left")
|
|
2412
2766
|
])) : createCommentVNode("v-if", true),
|
|
2413
2767
|
__props.clearable && value.value ? (openBlock(), createBlock(unref(ElButton), {
|
|
@@ -2430,7 +2784,7 @@ var _sfc_main$d = /* @__PURE__ */ defineComponent({
|
|
|
2430
2784
|
_: 1
|
|
2431
2785
|
/* STABLE */
|
|
2432
2786
|
}, 8, ["disabled"])) : createCommentVNode("v-if", true),
|
|
2433
|
-
__props.allowSpeech ? (openBlock(), createBlock(unref(ElButton), {
|
|
2787
|
+
__props.allowSpeech && !unref(isRecording) ? (openBlock(), createBlock(unref(ElButton), {
|
|
2434
2788
|
key: 2,
|
|
2435
2789
|
class: "fv-sender-speech",
|
|
2436
2790
|
text: "",
|
|
@@ -2450,29 +2804,49 @@ var _sfc_main$d = /* @__PURE__ */ defineComponent({
|
|
|
2450
2804
|
_: 1
|
|
2451
2805
|
/* STABLE */
|
|
2452
2806
|
}, 8, ["disabled"])) : createCommentVNode("v-if", true),
|
|
2453
|
-
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 "),
|
|
2454
2808
|
__props.loading ? (openBlock(), createBlock(unref(ElButton), {
|
|
2455
2809
|
key: 3,
|
|
2456
2810
|
class: "fv-sender-stop",
|
|
2457
2811
|
type: "primary",
|
|
2812
|
+
circle: __props.round,
|
|
2458
2813
|
"aria-label": "\u505C\u6B62",
|
|
2459
2814
|
onClick: cancel
|
|
2460
2815
|
}, {
|
|
2461
2816
|
default: withCtx(() => [
|
|
2462
2817
|
createVNode(unref(ElIcon), null, {
|
|
2463
2818
|
default: withCtx(() => [
|
|
2464
|
-
createVNode(
|
|
2819
|
+
createVNode(_sfc_main$e)
|
|
2465
2820
|
]),
|
|
2466
2821
|
_: 1
|
|
2467
2822
|
/* STABLE */
|
|
2468
|
-
})
|
|
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
|
+
]))
|
|
2469
2842
|
]),
|
|
2470
2843
|
_: 1
|
|
2471
2844
|
/* STABLE */
|
|
2472
|
-
})) : (openBlock(), createBlock(unref(ElButton), {
|
|
2845
|
+
}, 8, ["circle"])) : (openBlock(), createBlock(unref(ElButton), {
|
|
2473
2846
|
key: 4,
|
|
2474
2847
|
class: "fv-sender-submit",
|
|
2475
2848
|
type: "primary",
|
|
2849
|
+
circle: __props.round,
|
|
2476
2850
|
disabled: !submitable(),
|
|
2477
2851
|
"aria-label": "\u53D1\u9001",
|
|
2478
2852
|
onClick: doSubmit
|
|
@@ -2488,13 +2862,13 @@ var _sfc_main$d = /* @__PURE__ */ defineComponent({
|
|
|
2488
2862
|
]),
|
|
2489
2863
|
_: 1
|
|
2490
2864
|
/* STABLE */
|
|
2491
|
-
}, 8, ["disabled"]))
|
|
2865
|
+
}, 8, ["circle", "disabled"]))
|
|
2492
2866
|
]))
|
|
2493
2867
|
]),
|
|
2494
2868
|
createCommentVNode(" /fv-sender-row ")
|
|
2495
2869
|
]),
|
|
2496
2870
|
createCommentVNode(" \u5E95\u90E8 "),
|
|
2497
|
-
_ctx.$slots.footer ? (openBlock(), createElementBlock("div",
|
|
2871
|
+
_ctx.$slots.footer ? (openBlock(), createElementBlock("div", _hoisted_14$2, [
|
|
2498
2872
|
renderSlot(_ctx.$slots, "footer")
|
|
2499
2873
|
])) : createCommentVNode("v-if", true)
|
|
2500
2874
|
],
|
|
@@ -5799,7 +6173,7 @@ var _sfc_main$3 = /* @__PURE__ */ defineComponent({
|
|
|
5799
6173
|
"auto-collapse": __props.autoCollapse
|
|
5800
6174
|
}, {
|
|
5801
6175
|
content: withCtx(() => [
|
|
5802
|
-
createVNode(_sfc_main$
|
|
6176
|
+
createVNode(_sfc_main$i, {
|
|
5803
6177
|
content: __props.message.reasoning ?? ""
|
|
5804
6178
|
}, null, 8, ["content"])
|
|
5805
6179
|
]),
|
|
@@ -5814,7 +6188,7 @@ var _sfc_main$3 = /* @__PURE__ */ defineComponent({
|
|
|
5814
6188
|
toDisplayString(__props.message.error || "\u751F\u6210\u5931\u8D25"),
|
|
5815
6189
|
1
|
|
5816
6190
|
/* TEXT */
|
|
5817
|
-
)) : __props.message.content ? (openBlock(), createBlock(_sfc_main$
|
|
6191
|
+
)) : __props.message.content ? (openBlock(), createBlock(_sfc_main$i, {
|
|
5818
6192
|
key: 1,
|
|
5819
6193
|
content: __props.message.content
|
|
5820
6194
|
}, null, 8, ["content"])) : __props.message.status === "pending" || __props.message.status === "streaming" ? (openBlock(), createElementBlock("span", _hoisted_12, [
|
|
@@ -6385,7 +6759,10 @@ var _sfc_main$1 = /* @__PURE__ */ defineComponent({
|
|
|
6385
6759
|
}
|
|
6386
6760
|
});
|
|
6387
6761
|
|
|
6388
|
-
const _hoisted_1 = {
|
|
6762
|
+
const _hoisted_1 = {
|
|
6763
|
+
key: 0,
|
|
6764
|
+
class: "fv-ai-chat-header"
|
|
6765
|
+
};
|
|
6389
6766
|
const _hoisted_2 = { class: "fv-ai-chat-title" };
|
|
6390
6767
|
const _hoisted_3 = { class: "fv-ai-chat-body" };
|
|
6391
6768
|
const _hoisted_4 = { class: "fv-ai-chat-footer" };
|
|
@@ -6400,7 +6777,10 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
6400
6777
|
adapter: { type: Object, required: false, default: void 0 },
|
|
6401
6778
|
messages: { type: Array, required: false, default: void 0 },
|
|
6402
6779
|
title: { type: String, required: false, default: "" },
|
|
6780
|
+
showHeader: { type: Boolean, required: false, default: false },
|
|
6781
|
+
centerWelcome: { type: Boolean, required: false, default: true },
|
|
6403
6782
|
placeholder: { type: String, required: false, default: "" },
|
|
6783
|
+
senderShadow: { type: Boolean, required: false, default: true },
|
|
6404
6784
|
suggestions: { type: Array, required: false, default: () => [] },
|
|
6405
6785
|
features: { type: Object, required: false, default: () => ({}) },
|
|
6406
6786
|
allowAttachments: { type: Boolean, required: false, default: false },
|
|
@@ -6448,6 +6828,7 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
6448
6828
|
const { send, stop: stopChat, regenerate: regenerateChat, msgs, isLoading } = chat;
|
|
6449
6829
|
const nodeTable = chat.messages;
|
|
6450
6830
|
const chain = chat.chain;
|
|
6831
|
+
const isCenterWelcome = computed(() => props.centerWelcome && chain.value.length === 0);
|
|
6451
6832
|
let flushTimer = null;
|
|
6452
6833
|
watch(chain, (c) => {
|
|
6453
6834
|
if (flushTimer) clearTimeout(flushTimer);
|
|
@@ -6613,11 +6994,11 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
6613
6994
|
return openBlock(), createElementBlock(
|
|
6614
6995
|
"div",
|
|
6615
6996
|
{
|
|
6616
|
-
class: normalizeClass(["fv-ai-chat", { "is-dark": isDark.value }])
|
|
6997
|
+
class: normalizeClass(["fv-ai-chat", { "is-dark": isDark.value, "is-center-welcome": isCenterWelcome.value }])
|
|
6617
6998
|
},
|
|
6618
6999
|
[
|
|
6619
7000
|
createCommentVNode(" \u9876\u680F:\u6807\u9898 + \u6A21\u578B\u9009\u62E9\u5668(models \u6709\u503C\u65F6 multiple) "),
|
|
6620
|
-
|
|
7001
|
+
__props.showHeader ? (openBlock(), createElementBlock("div", _hoisted_1, [
|
|
6621
7002
|
createElementVNode(
|
|
6622
7003
|
"div",
|
|
6623
7004
|
_hoisted_2,
|
|
@@ -6653,7 +7034,7 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
6653
7034
|
_: 1
|
|
6654
7035
|
/* STABLE */
|
|
6655
7036
|
}, 8, ["modelValue"])) : createCommentVNode("v-if", true)
|
|
6656
|
-
]),
|
|
7037
|
+
])) : createCommentVNode("v-if", true),
|
|
6657
7038
|
createCommentVNode(" \u6D88\u606F\u533A:\u7A7A\u65F6 Welcome + Prompts(AiMessages \u5185\u7F6E);\u5F00\u542F artifacts \u65F6\u53F3\u4FA7\u62FC\u9884\u89C8\u9762\u677F "),
|
|
6658
7039
|
createElementVNode("div", _hoisted_3, [
|
|
6659
7040
|
createVNode(_sfc_main$2, {
|
|
@@ -6704,6 +7085,7 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
6704
7085
|
createVNode(_sfc_main$d, {
|
|
6705
7086
|
placeholder: __props.placeholder,
|
|
6706
7087
|
loading: unref(isLoading),
|
|
7088
|
+
shadow: __props.senderShadow,
|
|
6707
7089
|
variant: "updown",
|
|
6708
7090
|
maxlength: 8e3,
|
|
6709
7091
|
"allow-empty-submit": __props.allowAttachments && !!pendingFiles.value.length,
|
|
@@ -6748,7 +7130,7 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
6748
7130
|
]),
|
|
6749
7131
|
key: "2"
|
|
6750
7132
|
} : void 0
|
|
6751
|
-
]), 1032, ["placeholder", "loading", "allow-empty-submit"])
|
|
7133
|
+
]), 1032, ["placeholder", "loading", "shadow", "allow-empty-submit"])
|
|
6752
7134
|
])
|
|
6753
7135
|
],
|
|
6754
7136
|
2
|
|
@@ -6879,105 +7261,6 @@ function XRequest(url, options = {}) {
|
|
|
6879
7261
|
});
|
|
6880
7262
|
}
|
|
6881
7263
|
|
|
6882
|
-
function getSpeechRecognitionCtor() {
|
|
6883
|
-
if (typeof window === "undefined") return void 0;
|
|
6884
|
-
const w = window;
|
|
6885
|
-
const ctor = w.SpeechRecognition ?? w.webkitSpeechRecognition;
|
|
6886
|
-
return typeof ctor === "function" ? ctor : void 0;
|
|
6887
|
-
}
|
|
6888
|
-
function useRecord() {
|
|
6889
|
-
const isRecording = ref(false);
|
|
6890
|
-
const text = ref("");
|
|
6891
|
-
const audioUrl = ref(null);
|
|
6892
|
-
const error = ref(null);
|
|
6893
|
-
let mediaStream = null;
|
|
6894
|
-
let mediaRecorder = null;
|
|
6895
|
-
let chunks = [];
|
|
6896
|
-
let recognition = null;
|
|
6897
|
-
let finalText = "";
|
|
6898
|
-
function revokeAudioUrl() {
|
|
6899
|
-
if (audioUrl.value) {
|
|
6900
|
-
URL.revokeObjectURL(audioUrl.value);
|
|
6901
|
-
audioUrl.value = null;
|
|
6902
|
-
}
|
|
6903
|
-
}
|
|
6904
|
-
async function start() {
|
|
6905
|
-
if (isRecording.value) return;
|
|
6906
|
-
error.value = null;
|
|
6907
|
-
text.value = "";
|
|
6908
|
-
finalText = "";
|
|
6909
|
-
chunks = [];
|
|
6910
|
-
revokeAudioUrl();
|
|
6911
|
-
if (typeof MediaRecorder === "undefined" || !navigator.mediaDevices?.getUserMedia) {
|
|
6912
|
-
error.value = new Error("\u5F53\u524D\u73AF\u5883\u4E0D\u652F\u6301\u97F3\u9891\u5F55\u5236");
|
|
6913
|
-
return;
|
|
6914
|
-
}
|
|
6915
|
-
try {
|
|
6916
|
-
mediaStream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
6917
|
-
} catch (e) {
|
|
6918
|
-
error.value = e instanceof Error ? e : new Error(String(e));
|
|
6919
|
-
return;
|
|
6920
|
-
}
|
|
6921
|
-
mediaRecorder = new MediaRecorder(mediaStream);
|
|
6922
|
-
mediaRecorder.ondataavailable = (e) => {
|
|
6923
|
-
if (e.data && e.data.size > 0) chunks.push(e.data);
|
|
6924
|
-
};
|
|
6925
|
-
mediaRecorder.onstop = () => {
|
|
6926
|
-
if (chunks.length > 0) {
|
|
6927
|
-
const blob = new Blob(chunks, { type: mediaRecorder?.mimeType || "audio/webm" });
|
|
6928
|
-
audioUrl.value = URL.createObjectURL(blob);
|
|
6929
|
-
}
|
|
6930
|
-
mediaStream?.getTracks().forEach((t) => t.stop());
|
|
6931
|
-
mediaStream = null;
|
|
6932
|
-
};
|
|
6933
|
-
const SRCtor = getSpeechRecognitionCtor();
|
|
6934
|
-
if (SRCtor) {
|
|
6935
|
-
try {
|
|
6936
|
-
recognition = new SRCtor();
|
|
6937
|
-
recognition.continuous = true;
|
|
6938
|
-
recognition.interimResults = true;
|
|
6939
|
-
recognition.onresult = (event) => {
|
|
6940
|
-
let interim = "";
|
|
6941
|
-
for (let i = event.resultIndex; i < event.results.length; i++) {
|
|
6942
|
-
const r = event.results[i];
|
|
6943
|
-
if (r.isFinal) finalText += r[0].transcript;
|
|
6944
|
-
else interim += r[0].transcript;
|
|
6945
|
-
}
|
|
6946
|
-
text.value = finalText + interim;
|
|
6947
|
-
};
|
|
6948
|
-
recognition.onerror = (ev) => {
|
|
6949
|
-
error.value = new Error(`\u8BED\u97F3\u8BC6\u522B\u9519\u8BEF: ${ev?.error ?? "unknown"}`);
|
|
6950
|
-
};
|
|
6951
|
-
recognition.start();
|
|
6952
|
-
} catch {
|
|
6953
|
-
recognition = null;
|
|
6954
|
-
}
|
|
6955
|
-
}
|
|
6956
|
-
mediaRecorder.start();
|
|
6957
|
-
isRecording.value = true;
|
|
6958
|
-
}
|
|
6959
|
-
function stop() {
|
|
6960
|
-
if (!isRecording.value) return;
|
|
6961
|
-
isRecording.value = false;
|
|
6962
|
-
try {
|
|
6963
|
-
recognition?.stop();
|
|
6964
|
-
} catch {
|
|
6965
|
-
}
|
|
6966
|
-
recognition = null;
|
|
6967
|
-
try {
|
|
6968
|
-
if (mediaRecorder && mediaRecorder.state !== "inactive") mediaRecorder.stop();
|
|
6969
|
-
} catch {
|
|
6970
|
-
}
|
|
6971
|
-
}
|
|
6972
|
-
if (getCurrentInstance()) {
|
|
6973
|
-
onBeforeUnmount(() => {
|
|
6974
|
-
stop();
|
|
6975
|
-
revokeAudioUrl();
|
|
6976
|
-
});
|
|
6977
|
-
}
|
|
6978
|
-
return { start, stop, isRecording, text, audioUrl, error };
|
|
6979
|
-
}
|
|
6980
|
-
|
|
6981
7264
|
class DetOmsError extends Error {
|
|
6982
7265
|
constructor(message, code) {
|
|
6983
7266
|
super(message);
|
|
@@ -7173,4 +7456,4 @@ function createMemoryAdapter() {
|
|
|
7173
7456
|
|
|
7174
7457
|
const version = "0.1.0";
|
|
7175
7458
|
|
|
7176
|
-
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 };
|