@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/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, 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
+ 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$h = ["innerHTML"];
1523
- var _sfc_main$h = /* @__PURE__ */ defineComponent({
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$h);
1553
+ }, null, 8, _hoisted_1$i);
1547
1554
  };
1548
1555
  }
1549
1556
  });
1550
1557
 
1551
- const _hoisted_1$g = {
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$g = /* @__PURE__ */ defineComponent({
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$h, {
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$g, [
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$f = {
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$f = /* @__PURE__ */ defineComponent({
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$f, [
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$g, {
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$h, {
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$e = { class: "fv-bubble-list" };
1875
- var _sfc_main$e = /* @__PURE__ */ defineComponent({
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$e, [
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$f, mergeProps({
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 = ["value", "placeholder", "disabled", "readonly"];
2113
- const _hoisted_7$4 = {
2114
- 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,
2115
2260
  class: "fv-sender-actions"
2116
2261
  };
2117
- const _hoisted_8$3 = {
2118
- key: 2,
2262
+ const _hoisted_10$2 = {
2263
+ key: 4,
2119
2264
  class: "fv-sender-actions"
2120
2265
  };
2121
- const _hoisted_9$2 = {
2266
+ const _hoisted_11$2 = {
2122
2267
  key: 0,
2123
2268
  class: "fv-sender-action-left"
2124
2269
  };
2125
- 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 = {
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
- function onSpeechClick() {
2316
- 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();
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
- 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(
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, _hoisted_6$5),
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", _hoisted_7$4, [
2761
+ hasActionListSlot.value ? (openBlock(), createElementBlock("div", _hoisted_9$2, [
2401
2762
  renderSlot(_ctx.$slots, "action-list")
2402
- ])) : (openBlock(), createElementBlock("div", _hoisted_8$3, [
2403
- _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, [
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;\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 "),
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(unref(VideoPause))
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", _hoisted_10$2, [
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$h, {
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$h, {
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 = { class: "fv-ai-chat-header" };
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
- createElementVNode("div", _hoisted_1, [
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$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 };