@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/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, getCurrentInstance } from 'vue';
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, ElIcon, ElDialog, ElDropdown, ElDropdownMenu, ElDropdownItem, ElMessageBox, ElTooltip, ElSelect, ElOption } from 'element-plus';
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, VideoPause, Promotion, Loading, SuccessFilled, CircleCloseFilled, ChatDotRound, Cpu, Cellphone, Link, Folder, Headset, Film, Monitor, DataAnalysis, Document, Notebook, Picture, Close, Paperclip, RefreshRight, MoreFilled, User, DocumentCopy, ArrowUp, CopyDocument, Download, FullScreen } from '@element-plus/icons-vue';
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$h = ["innerHTML"];
1530
- var _sfc_main$h = /* @__PURE__ */ defineComponent({
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$h);
1553
+ }, null, 8, _hoisted_1$i);
1554
1554
  };
1555
1555
  }
1556
1556
  });
1557
1557
 
1558
- const _hoisted_1$g = {
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$g = /* @__PURE__ */ defineComponent({
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$h, {
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$g, [
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$f = {
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$f = /* @__PURE__ */ defineComponent({
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$f, [
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$g, {
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$h, {
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$e = { class: "fv-bubble-list" };
1882
- var _sfc_main$e = /* @__PURE__ */ defineComponent({
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$e, [
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$f, mergeProps({
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 = ["value", "placeholder", "disabled", "readonly"];
2120
- const _hoisted_7$4 = {
2121
- key: 1,
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 _hoisted_8$3 = {
2125
- key: 2,
2262
+ const _hoisted_10$2 = {
2263
+ key: 4,
2126
2264
  class: "fv-sender-actions"
2127
2265
  };
2128
- const _hoisted_9$2 = {
2266
+ const _hoisted_11$2 = {
2129
2267
  key: 0,
2130
2268
  class: "fv-sender-action-left"
2131
2269
  };
2132
- const _hoisted_10$2 = {
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
- function onSpeechClick() {
2323
- console.warn("useRecord \u672A\u63A5\u5165,Task 15 \u63A5\u7EBF");
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
- createElementVNode(
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, _hoisted_6$5),
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", _hoisted_7$4, [
2761
+ hasActionListSlot.value ? (openBlock(), createElementBlock("div", _hoisted_9$2, [
2408
2762
  renderSlot(_ctx.$slots, "action-list")
2409
- ])) : (openBlock(), createElementBlock("div", _hoisted_8$3, [
2410
- _ctx.$slots["action-left"] ? (openBlock(), createElementBlock("div", _hoisted_9$2, [
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;\u5426\u5219\u53D1\u9001\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(unref(VideoPause))
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", _hoisted_10$2, [
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$h, {
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$h, {
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 = { class: "fv-ai-chat-header" };
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
- createElementVNode("div", _hoisted_1, [
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$f as FvBubble, _sfc_main$e as FvBubbleList, _sfc_main$4 as FvConversations, _sfc_main$b as FvEditorSender, _sfc_main$6 as FvFilesCard, _sfc_main$h 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$g as FvTypewriter, _sfc_main$8 as FvWelcome, OpenAIAdapter, XRequest, createLocalStorageAdapter, createMemoryAdapter, createMessageTree, createSSEParser, useChat, useMessages, useRecord, useSend, useXStream, version };
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 };