@seer-ai/seer-vue 0.1.0-beta.5 → 0.1.0-beta.6

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 CHANGED
@@ -65,6 +65,7 @@ async function submit() {
65
65
  <a v-if="seg.kind === 'link'" :href="seg.href" target="_blank" rel="noopener noreferrer">{{
66
66
  seg.label
67
67
  }}</a>
68
+ <img v-else-if="seg.kind === 'image'" :src="seg.href" :alt="seg.alt" loading="lazy" />
68
69
  <span v-else>{{ seg.value }}</span>
69
70
  </template>
70
71
  </p>
package/dist/content.d.ts CHANGED
@@ -5,6 +5,16 @@ export type ContentSegment = {
5
5
  kind: 'link';
6
6
  href: string;
7
7
  label: string;
8
+ } | {
9
+ kind: 'image';
10
+ href: string;
11
+ alt: string;
12
+ } | {
13
+ kind: 'price';
14
+ value: string;
15
+ } | {
16
+ kind: 'strong';
17
+ value: string;
8
18
  };
9
19
  export declare function linkAnchorLabel(prefix: string): string | null;
10
20
  export declare function toContentSegments(content: string): ContentSegment[];
package/dist/index.css CHANGED
@@ -1 +1 @@
1
- .seer-chat[data-v-f2b8b91f]{display:grid;gap:18px;max-width:720px;min-height:640px;padding:0;overflow:hidden;color:#18212f;background:radial-gradient(circle at 18% 0%,rgba(71,106,255,.14),transparent 32%),linear-gradient(180deg,#fff,#f7f9fd);border:1px solid rgba(127,143,170,.28);border-radius:28px;box-shadow:0 24px 70px #151f3429}.seer-chat__header[data-v-f2b8b91f]{display:flex;gap:16px;align-items:flex-start;justify-content:space-between;padding:22px 22px 18px;color:#fff;background:linear-gradient(135deg,#141f34f5,#243f76f0),#172033}.seer-chat__header h2[data-v-f2b8b91f]{margin:0;font-size:22px;letter-spacing:-.03em}.seer-chat__header p[data-v-f2b8b91f],.seer-chat__empty[data-v-f2b8b91f],.seer-chat__status[data-v-f2b8b91f]{margin:4px 0 0;color:#5f6f89;font-size:14px}.seer-chat__header p[data-v-f2b8b91f]{max-width:34ch;color:#ffffffb8}.seer-chat__messages[data-v-f2b8b91f]{display:grid;gap:12px;align-content:start;min-height:330px;max-height:470px;padding:18px 18px 4px;overflow-y:auto}.seer-chat__empty[data-v-f2b8b91f]{display:grid;place-items:center;min-height:260px;padding:0 28px;color:#66748a;text-align:center;border:1px dashed rgba(127,143,170,.38);border-radius:22px;background:#ffffff9e}.seer-chat__message[data-v-f2b8b91f]{display:grid;gap:6px;max-width:min(86%,520px);padding:13px 15px;border:1px solid rgba(127,143,170,.16);border-radius:18px 18px 18px 6px;background:#ffffffe0;box-shadow:0 12px 28px #151f3414}.seer-chat__message--user[data-v-f2b8b91f]{justify-self:end;color:#fff;border-color:transparent;border-radius:18px 18px 6px;background:linear-gradient(135deg,#285cff,#1d45c9);box-shadow:0 14px 30px #1f5eff3d}.seer-chat__role[data-v-f2b8b91f]{font-size:12px;font-weight:700;opacity:.75}.seer-chat__body[data-v-f2b8b91f]{display:flex;flex-direction:column}.seer-chat__line[data-v-f2b8b91f]{margin:0;white-space:pre-wrap;overflow-wrap:anywhere}.seer-chat__line[data-v-f2b8b91f]:not(:last-child){margin-bottom:5px}.seer-chat__line[data-v-f2b8b91f]:empty{height:7px}.seer-chat__link[data-v-f2b8b91f]{color:#1f5eff;font-weight:600;text-decoration:underline;text-underline-offset:2px;overflow-wrap:anywhere}.seer-chat__link[data-v-f2b8b91f]:hover{color:#173fb3}.seer-chat__message--user .seer-chat__link[data-v-f2b8b91f]{color:#fff}.seer-chat__error[data-v-f2b8b91f],.seer-chat__handoff[data-v-f2b8b91f]{margin:0 18px;padding:10px 12px;border-radius:14px}.seer-chat__error[data-v-f2b8b91f]{color:#8a1f11;background:#fff0ed}.seer-chat__handoff[data-v-f2b8b91f]{color:#704600;background:#fff7db}.seer-chat__form[data-v-f2b8b91f]{display:grid;gap:11px;margin:0 18px 18px;padding:14px;background:#fff;border:1px solid rgba(127,143,170,.26);border-radius:22px;box-shadow:0 18px 38px #151f3417}.seer-chat__label[data-v-f2b8b91f]{font-size:13px;font-weight:700}.seer-chat textarea[data-v-f2b8b91f]{width:100%;box-sizing:border-box;min-height:92px;padding:14px;color:inherit;line-height:1.55;background:#f8fafd;border:1px solid transparent;border-radius:16px;outline:none;resize:vertical;transition:background .16s ease,border-color .16s ease,box-shadow .16s ease}.seer-chat button[data-v-f2b8b91f]{color:inherit;font-weight:700;border:0;cursor:pointer;transition:transform .16s ease,box-shadow .16s ease,opacity .16s ease}.seer-chat button[data-v-f2b8b91f]:not(:disabled):hover{transform:translateY(-1px)}.seer-chat button[data-v-f2b8b91f]:disabled{cursor:not-allowed;opacity:.5}.seer-chat button[data-v-f2b8b91f]:focus-visible,.seer-chat textarea[data-v-f2b8b91f]:focus-visible{border-color:#1f5eff6b;box-shadow:0 0 0 4px #1f5eff21}.seer-chat__clear-button[data-v-f2b8b91f]{flex:0 0 auto;padding:8px 11px;color:#ffffffc7;font-size:12px;background:transparent;border:1px solid rgba(255,255,255,.18)!important;border-radius:12px}.seer-chat__clear-button[data-v-f2b8b91f]:not(:disabled):hover{color:#fff;background:#ffffff1a;box-shadow:none}.seer-chat__stop-button[data-v-f2b8b91f]{padding:8px 11px;color:#6c3b12;font-size:12px;background:#fff1df;border-radius:12px}.seer-chat__send-button[data-v-f2b8b91f]{display:inline-flex;gap:8px;align-items:center;justify-content:center;min-width:86px;padding:10px 14px;color:#fff;background:linear-gradient(135deg,#1f5eff,#173fb3);border-radius:14px;box-shadow:0 12px 24px #1f5eff38}.seer-chat__send-button[data-v-f2b8b91f]:not(:disabled):hover{box-shadow:0 14px 28px #1f5eff47}.seer-chat__hint[data-v-f2b8b91f]{margin-right:auto;color:#7a879a;font-size:12px}.seer-chat__composer-footer[data-v-f2b8b91f]{display:flex;gap:8px;align-items:center;justify-content:flex-end}
1
+ .seer-chat[data-v-dc651545]{display:grid;gap:18px;max-width:720px;min-height:640px;padding:0;overflow:hidden;color:#18212f;background:radial-gradient(circle at 18% 0%,rgba(71,106,255,.14),transparent 32%),linear-gradient(180deg,#fff,#f7f9fd);border:1px solid rgba(127,143,170,.28);border-radius:28px;box-shadow:0 24px 70px #151f3429}.seer-chat__header[data-v-dc651545]{display:flex;gap:16px;align-items:flex-start;justify-content:space-between;padding:22px 22px 18px;color:#fff;background:linear-gradient(135deg,#141f34f5,#243f76f0),#172033}.seer-chat__header h2[data-v-dc651545]{margin:0;font-size:22px;letter-spacing:-.03em}.seer-chat__header p[data-v-dc651545],.seer-chat__empty[data-v-dc651545],.seer-chat__status[data-v-dc651545]{margin:4px 0 0;color:#5f6f89;font-size:14px}.seer-chat__header p[data-v-dc651545]{max-width:34ch;color:#ffffffb8}.seer-chat__messages[data-v-dc651545]{display:grid;gap:12px;align-content:start;min-height:330px;max-height:470px;padding:18px 18px 4px;overflow-y:auto}.seer-chat__empty[data-v-dc651545]{display:grid;place-items:center;min-height:260px;padding:0 28px;color:#66748a;text-align:center;border:1px dashed rgba(127,143,170,.38);border-radius:22px;background:#ffffff9e}.seer-chat__message[data-v-dc651545]{display:grid;gap:6px;max-width:min(86%,520px);padding:13px 15px;border:1px solid rgba(127,143,170,.16);border-radius:18px 18px 18px 6px;background:#ffffffe0;box-shadow:0 12px 28px #151f3414}.seer-chat__message--user[data-v-dc651545]{justify-self:end;color:#fff;border-color:transparent;border-radius:18px 18px 6px;background:linear-gradient(135deg,#285cff,#1d45c9);box-shadow:0 14px 30px #1f5eff3d}.seer-chat__role[data-v-dc651545]{font-size:12px;font-weight:700;opacity:.75}.seer-chat__body[data-v-dc651545]{display:flex;flex-direction:column}.seer-chat__line[data-v-dc651545]{margin:0;white-space:pre-wrap;overflow-wrap:anywhere}.seer-chat__line[data-v-dc651545]:not(:last-child){margin-bottom:5px}.seer-chat__line[data-v-dc651545]:empty{height:7px}.seer-chat__strong[data-v-dc651545]{font-weight:700}.seer-chat__price[data-v-dc651545]{color:#e0331d;font-weight:600}.seer-chat__message--user .seer-chat__price[data-v-dc651545]{color:#ffe2dc}.seer-chat__link[data-v-dc651545]{color:#1f5eff;font-weight:600;text-decoration:underline;text-underline-offset:2px;overflow-wrap:anywhere}.seer-chat__link[data-v-dc651545]:hover{color:#173fb3}.seer-chat__message--user .seer-chat__link[data-v-dc651545]{color:#fff}.seer-chat__image-button[data-v-dc651545]{display:block;padding:0;background:transparent;border:0;cursor:zoom-in}.seer-chat__image-button[data-v-dc651545]:not(:disabled):hover{transform:none}.seer-chat__image[data-v-dc651545]{display:block;max-width:100%;margin:6px 0;border-radius:12px;border:1px solid rgba(127,143,170,.22);transition:filter .16s ease}.seer-chat__image-button:hover .seer-chat__image[data-v-dc651545]{filter:brightness(.96)}.seer-chat__lightbox[data-v-dc651545]{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1000;display:grid;place-items:center;padding:32px;background:#0a0f1ad1;cursor:zoom-out;animation:seer-chat__fade-in-dc651545 .14s ease}.seer-chat__lightbox-image[data-v-dc651545]{max-width:min(92vw,1200px);max-height:90vh;object-fit:contain;border-radius:12px;box-shadow:0 30px 80px #00000080}.seer-chat__lightbox-close[data-v-dc651545]{position:fixed;top:18px;right:22px;display:grid;place-items:center;width:40px;height:40px;color:#fff;font-size:26px;line-height:1;background:#ffffff24;border-radius:50%}.seer-chat__lightbox-close[data-v-dc651545]:not(:disabled):hover{background:#ffffff3d}@keyframes seer-chat__fade-in-dc651545{0%{opacity:0}to{opacity:1}}.seer-chat__error[data-v-dc651545],.seer-chat__handoff[data-v-dc651545]{margin:0 18px;padding:10px 12px;border-radius:14px}.seer-chat__error[data-v-dc651545]{color:#8a1f11;background:#fff0ed}.seer-chat__handoff[data-v-dc651545]{color:#704600;background:#fff7db}.seer-chat__form[data-v-dc651545]{display:grid;gap:11px;margin:0 18px 18px;padding:14px;background:#fff;border:1px solid rgba(127,143,170,.26);border-radius:22px;box-shadow:0 18px 38px #151f3417}.seer-chat__label[data-v-dc651545]{font-size:13px;font-weight:700}.seer-chat textarea[data-v-dc651545]{width:100%;box-sizing:border-box;min-height:92px;padding:14px;color:inherit;line-height:1.55;background:#f8fafd;border:1px solid transparent;border-radius:16px;outline:none;resize:vertical;transition:background .16s ease,border-color .16s ease,box-shadow .16s ease}.seer-chat button[data-v-dc651545]{color:inherit;font-weight:700;border:0;cursor:pointer;transition:transform .16s ease,box-shadow .16s ease,opacity .16s ease}.seer-chat button[data-v-dc651545]:not(:disabled):hover{transform:translateY(-1px)}.seer-chat button[data-v-dc651545]:disabled{cursor:not-allowed;opacity:.5}.seer-chat button[data-v-dc651545]:focus-visible,.seer-chat textarea[data-v-dc651545]:focus-visible{border-color:#1f5eff6b;box-shadow:0 0 0 4px #1f5eff21}.seer-chat__clear-button[data-v-dc651545]{flex:0 0 auto;padding:8px 11px;color:#ffffffc7;font-size:12px;background:transparent;border:1px solid rgba(255,255,255,.18)!important;border-radius:12px}.seer-chat__clear-button[data-v-dc651545]:not(:disabled):hover{color:#fff;background:#ffffff1a;box-shadow:none}.seer-chat__stop-button[data-v-dc651545]{padding:8px 11px;color:#6c3b12;font-size:12px;background:#fff1df;border-radius:12px}.seer-chat__send-button[data-v-dc651545]{display:inline-flex;gap:8px;align-items:center;justify-content:center;min-width:86px;padding:10px 14px;color:#fff;background:linear-gradient(135deg,#1f5eff,#173fb3);border-radius:14px;box-shadow:0 12px 24px #1f5eff38}.seer-chat__send-button[data-v-dc651545]:not(:disabled):hover{box-shadow:0 14px 28px #1f5eff47}.seer-chat__hint[data-v-dc651545]{margin-right:auto;color:#7a879a;font-size:12px}.seer-chat__composer-footer[data-v-dc651545]{display:flex;gap:8px;align-items:center;justify-content:flex-end}
package/dist/index.js CHANGED
@@ -1,102 +1,102 @@
1
- import { hasInjectionContext as N, inject as q, ref as w, defineComponent as L, computed as M, openBlock as v, createElementBlock as m, createElementVNode as u, toDisplayString as C, unref as _, createCommentVNode as E, Fragment as I, renderList as R, normalizeClass as B, withModifiers as O, withDirectives as K, withKeys as D, vModelText as F } from "vue";
2
- function U(e) {
3
- const n = e.fetcher ?? fetch, t = e.model ?? "seer", a = e.now ?? (() => Math.floor(Date.now() / 1e3));
4
- let l, r = 0;
1
+ import { hasInjectionContext as K, inject as D, ref as y, defineComponent as U, computed as B, onBeforeUnmount as M, openBlock as h, createElementBlock as _, createElementVNode as f, toDisplayString as C, unref as g, createCommentVNode as T, Fragment as R, renderList as I, normalizeClass as q, withModifiers as A, withDirectives as z, withKeys as F, vModelText as V } from "vue";
2
+ function X(e) {
3
+ const n = e.fetcher ?? fetch, t = e.model ?? "seer", s = e.now ?? (() => Math.floor(Date.now() / 1e3));
4
+ let r, a = 0;
5
5
  return {
6
- async chat(s, c = {}) {
7
- const f = s.stream ?? !1, h = await d(), p = {
6
+ async chat(l, i = {}) {
7
+ const c = l.stream ?? !1, o = await v(), m = {
8
8
  "Content-Type": "application/json"
9
9
  };
10
- h && (p.Authorization = `Bearer ${h}`);
11
- const g = await n(e.endpoint, {
10
+ o && (m.Authorization = `Bearer ${o}`);
11
+ const k = await n(e.endpoint, {
12
12
  method: "POST",
13
- headers: p,
14
- signal: c.signal,
13
+ headers: m,
14
+ signal: i.signal,
15
15
  body: JSON.stringify({
16
- model: s.model ?? t,
17
- messages: s.messages,
18
- stream: f,
19
- conversation_id: s.conversationId,
20
- metadata: s.metadata
16
+ model: l.model ?? t,
17
+ messages: l.messages,
18
+ stream: c,
19
+ conversation_id: l.conversationId,
20
+ metadata: l.metadata
21
21
  })
22
22
  });
23
- if (!g.ok)
24
- throw new Error(await j(g));
25
- if (f)
26
- return V(g, c.onDelta);
27
- const b = await g.json();
28
- return P(b);
23
+ if (!k.ok)
24
+ throw new Error(await P(k));
25
+ if (c)
26
+ return G(k, i.onDelta);
27
+ const w = await k.json();
28
+ return j(w);
29
29
  }
30
30
  };
31
- async function d() {
31
+ async function v() {
32
32
  if (!e.sessionEndpoint)
33
33
  return;
34
- const s = a();
35
- if (l && r - 30 > s)
36
- return l;
37
- const c = await n(e.sessionEndpoint, {
34
+ const l = s();
35
+ if (r && a - 30 > l)
36
+ return r;
37
+ const i = await n(e.sessionEndpoint, {
38
38
  method: "GET",
39
- headers: await o()
39
+ headers: await p()
40
40
  });
41
- if (!c.ok)
42
- throw new Error(await j(c));
43
- const f = await c.json();
44
- return l = f.token, r = f.expires_at, l;
41
+ if (!i.ok)
42
+ throw new Error(await P(i));
43
+ const c = await i.json();
44
+ return r = c.token, a = c.expires_at, r;
45
45
  }
46
- async function o() {
47
- const s = {};
48
- return e.challengeTokenProvider && (s["X-Seer-Challenge-Token"] = await e.challengeTokenProvider()), s;
46
+ async function p() {
47
+ const l = {};
48
+ return e.challengeTokenProvider && (l["X-Seer-Challenge-Token"] = await e.challengeTokenProvider()), l;
49
49
  }
50
50
  }
51
- function P(e) {
52
- var t, a, l;
51
+ function j(e) {
52
+ var t, s, r;
53
53
  const n = (t = e.choices) == null ? void 0 : t[0];
54
54
  return {
55
- content: ((a = n == null ? void 0 : n.message) == null ? void 0 : a.content) ?? ((l = n == null ? void 0 : n.delta) == null ? void 0 : l.content) ?? "",
55
+ content: ((s = n == null ? void 0 : n.message) == null ? void 0 : s.content) ?? ((r = n == null ? void 0 : n.delta) == null ? void 0 : r.content) ?? "",
56
56
  conversationId: e.conversation_id,
57
57
  citations: e.citations ?? [],
58
58
  handoffRequested: e.handoff_requested ?? !1,
59
59
  finishReason: n == null ? void 0 : n.finish_reason
60
60
  };
61
61
  }
62
- async function V(e, n) {
63
- var f, h, p;
62
+ async function G(e, n) {
63
+ var c, o, m;
64
64
  if (!e.body)
65
- return P({});
66
- const t = e.body.getReader(), a = new TextDecoder();
67
- let l = "", r = "", d, o = [], s = !1, c;
65
+ return j({});
66
+ const t = e.body.getReader(), s = new TextDecoder();
67
+ let r = "", a = "", v, p = [], l = !1, i;
68
68
  for (; ; ) {
69
- const { done: g, value: b } = await t.read();
70
- if (g)
69
+ const { done: k, value: w } = await t.read();
70
+ if (k)
71
71
  break;
72
- l += a.decode(b, { stream: !0 });
73
- const T = l.split(`
72
+ r += s.decode(w, { stream: !0 });
73
+ const x = r.split(`
74
74
 
75
75
  `);
76
- l = T.pop() ?? "";
77
- for (const x of T) {
78
- const S = z(x);
79
- if (!S || S === "[DONE]")
76
+ r = x.pop() ?? "";
77
+ for (const u of x) {
78
+ const E = H(u);
79
+ if (!E || E === "[DONE]")
80
80
  continue;
81
- const y = JSON.parse(S), i = (f = y.choices) == null ? void 0 : f[0], k = ((h = i == null ? void 0 : i.delta) == null ? void 0 : h.content) ?? ((p = i == null ? void 0 : i.message) == null ? void 0 : p.content) ?? "";
82
- k && (r += k, n == null || n(k)), d = y.conversation_id ?? d, o = y.citations ?? o, s = y.handoff_requested ?? s, c = (i == null ? void 0 : i.finish_reason) ?? c;
81
+ const b = JSON.parse(E), d = (c = b.choices) == null ? void 0 : c[0], S = ((o = d == null ? void 0 : d.delta) == null ? void 0 : o.content) ?? ((m = d == null ? void 0 : d.message) == null ? void 0 : m.content) ?? "";
82
+ S && (a += S, n == null || n(S)), v = b.conversation_id ?? v, p = b.citations ?? p, l = b.handoff_requested ?? l, i = (d == null ? void 0 : d.finish_reason) ?? i;
83
83
  }
84
84
  }
85
85
  return {
86
- content: r,
87
- conversationId: d,
88
- citations: o,
89
- handoffRequested: s,
90
- finishReason: c
86
+ content: a,
87
+ conversationId: v,
88
+ citations: p,
89
+ handoffRequested: l,
90
+ finishReason: i
91
91
  };
92
92
  }
93
- function z(e) {
93
+ function H(e) {
94
94
  const n = e.split(`
95
95
  `).map((t) => t.trim()).filter((t) => t.startsWith("data:")).map((t) => t.slice(5).trim());
96
96
  return n.length === 0 ? null : n.join(`
97
97
  `);
98
98
  }
99
- async function j(e) {
99
+ async function P(e) {
100
100
  let n = e.statusText || "unknown error";
101
101
  try {
102
102
  const t = await e.json();
@@ -107,111 +107,142 @@ async function j(e) {
107
107
  }
108
108
  return `seer chat request failed with status ${e.status}: ${n}`;
109
109
  }
110
- const A = /https?:\/\/[^\s)]+/g;
111
- function J(e) {
112
- return /标签|箱唛/.test(e) ? "点击下载箱唛" : /入库单|交接单/.test(e) ? "点击下载入库单" : /面单/.test(e) ? "点击下载面单" : /截图/.test(e) ? "点击查看报价截图" : /下载链接|labelUrl|下载/.test(e) ? "点击下载" : /链接/.test(e) ? "点击查看" : null;
113
- }
114
- function G(e) {
110
+ const O = /https?:\/\/[^\s)]+/g, J = /\.(png|jpe?g|gif|webp|bmp|svg)$/i, W = "单价\\s*\\d[\\d.]*\\s*[A-Za-z]+\\/kg", Y = "按当前信息为您筛选出[^\\n:]*推荐方案[^\\n:]*:", Z = "方案PK|时效最快|价格最低", $ = new RegExp(`(${W})|(${Y})|(${Z})`, "g");
111
+ function L(e) {
115
112
  const n = [];
116
- A.lastIndex = 0;
117
- let t = 0, a;
118
- for (; (a = A.exec(e)) !== null; ) {
119
- const l = a[0], r = a.index;
120
- r > t && n.push({ kind: "text", value: e.slice(t, r) });
121
- const d = e.lastIndexOf(`
122
- `, r - 1) + 1, o = J(e.slice(d, r)) ?? l;
123
- n.push({ kind: "link", href: l, label: o }), t = r + l.length;
113
+ $.lastIndex = 0;
114
+ let t = 0, s;
115
+ for (; (s = $.exec(e)) !== null; ) {
116
+ s.index > t && n.push({ kind: "text", value: e.slice(t, s.index) });
117
+ const r = s[0];
118
+ n.push(s[1] ? { kind: "price", value: r } : { kind: "strong", value: r }), t = s.index + r.length;
124
119
  }
125
120
  return t < e.length && n.push({ kind: "text", value: e.slice(t) }), n;
126
121
  }
127
- function H(e) {
122
+ const Q = /标签|箱唛|唛头|入库单|交接单|入仓单|面单|下载/;
123
+ function ee(e, n) {
124
+ if (/方案|截图|报价图|效果图|示意图|图片/.test(n))
125
+ return !0;
126
+ if (Q.test(n))
127
+ return !1;
128
+ const t = e.split(/[?#]/)[0];
129
+ return J.test(t);
130
+ }
131
+ function te(e) {
132
+ return /方案|报价|截图|PK/.test(e) ? "方案PK" : "图片";
133
+ }
134
+ function ne(e) {
135
+ return /标签|箱唛/.test(e) ? "点击下载箱唛" : /入库单|交接单/.test(e) ? "点击下载入库单" : /面单/.test(e) ? "点击下载面单" : /截图|方案/.test(e) ? "点击查看方案PK" : /下载链接|labelUrl|下载/.test(e) ? "点击下载" : /链接/.test(e) ? "点击查看" : null;
136
+ }
137
+ function se(e) {
138
+ const n = [];
139
+ O.lastIndex = 0;
140
+ let t = 0, s;
141
+ for (; (s = O.exec(e)) !== null; ) {
142
+ const r = s[0], a = s.index, v = e.lastIndexOf(`
143
+ `, a - 1) + 1, p = e.slice(v, a), l = ee(r, p);
144
+ if (a > t) {
145
+ let i = e.slice(t, a);
146
+ l && (i = i.replace(/链接([::])\s*$/, "$1")), n.push(...L(i));
147
+ }
148
+ l ? n.push({ kind: "image", href: r, alt: te(p) }) : n.push({ kind: "link", href: r, label: ne(p) ?? r }), t = a + r.length;
149
+ }
150
+ return t < e.length && n.push(...L(e.slice(t))), n;
151
+ }
152
+ function ae(e) {
128
153
  return e.split(`
129
- `).map((n) => G(n));
154
+ `).map((n) => se(n));
130
155
  }
131
- const $ = Symbol("seer-chat-options"), he = {
156
+ const N = Symbol("seer-chat-options"), Ie = {
132
157
  install(e, n) {
133
- e.provide($, n);
158
+ e.provide(N, n);
134
159
  }
135
160
  };
136
- function W(e = {}) {
137
- const t = { ...N() ? q($, void 0) : void 0, ...e };
161
+ function oe(e = {}) {
162
+ const t = { ...K() ? D(N, void 0) : void 0, ...e };
138
163
  if (!t.endpoint)
139
164
  throw new Error("Seer chat endpoint is required. Pass it to app.use() or useSeerChat().");
140
- const a = {
165
+ const s = {
141
166
  endpoint: t.endpoint,
142
167
  sessionEndpoint: t.sessionEndpoint,
143
168
  challengeTokenProvider: t.challengeTokenProvider,
144
169
  model: t.model,
145
170
  fetcher: t.fetcher
146
- }, l = U(a), r = w([]), d = w(!1), o = w(null), s = w(), c = w([]), f = w(!1);
147
- let h = null;
148
- async function p(T) {
149
- const x = T.trim();
150
- if (!x || d.value)
171
+ }, r = X(s), a = y([]), v = y(!1), p = y(null), l = y(), i = y([]), c = y(!1);
172
+ let o = null;
173
+ async function m(x) {
174
+ const u = x.trim();
175
+ if (!u || v.value)
151
176
  return;
152
- const S = { role: "user", content: x };
153
- r.value = [...r.value, S], d.value = !0, o.value = null, h = new AbortController();
154
- const y = { role: "assistant", content: "" };
155
- t.stream && (r.value = [...r.value, y]);
177
+ const E = { role: "user", content: u };
178
+ a.value = [...a.value, E], v.value = !0, p.value = null, o = new AbortController();
179
+ const b = { role: "assistant", content: "" };
180
+ t.stream && (a.value = [...a.value, b]);
156
181
  try {
157
- const i = await l.chat(
182
+ const d = await r.chat(
158
183
  {
159
- messages: r.value.filter((k) => k.content),
184
+ messages: a.value.filter((S) => S.content),
160
185
  stream: t.stream ?? !1,
161
- conversationId: s.value
186
+ conversationId: l.value
162
187
  },
163
188
  {
164
- signal: h.signal,
165
- onDelta(k) {
166
- y.content += k, r.value = [...r.value];
189
+ signal: o.signal,
190
+ onDelta(S) {
191
+ b.content += S, a.value = [...a.value];
167
192
  }
168
193
  }
169
194
  );
170
- t.stream || (r.value = [...r.value, { role: "assistant", content: i.content }]), s.value = i.conversationId, c.value = i.citations, f.value = i.handoffRequested;
171
- } catch (i) {
172
- i.name !== "AbortError" && (o.value = i instanceof Error ? i.message : String(i));
195
+ t.stream || (a.value = [...a.value, { role: "assistant", content: d.content }]), l.value = d.conversationId, i.value = d.citations, c.value = d.handoffRequested;
196
+ } catch (d) {
197
+ d.name !== "AbortError" && (p.value = d instanceof Error ? d.message : String(d));
173
198
  } finally {
174
- d.value = !1, h = null;
199
+ v.value = !1, o = null;
175
200
  }
176
201
  }
177
- function g() {
178
- r.value = [], o.value = null, s.value = void 0, c.value = [], f.value = !1;
202
+ function k() {
203
+ a.value = [], p.value = null, l.value = void 0, i.value = [], c.value = !1;
179
204
  }
180
- function b() {
181
- h == null || h.abort();
205
+ function w() {
206
+ o == null || o.abort();
182
207
  }
183
208
  return {
184
- messages: r,
185
- loading: d,
186
- error: o,
187
- conversationId: s,
188
- citations: c,
189
- handoffRequested: f,
190
- send: p,
191
- reset: g,
192
- abort: b
209
+ messages: a,
210
+ loading: v,
211
+ error: p,
212
+ conversationId: l,
213
+ citations: i,
214
+ handoffRequested: c,
215
+ send: m,
216
+ reset: k,
217
+ abort: w
193
218
  };
194
219
  }
195
- const X = {
220
+ const re = {
196
221
  class: "seer-chat",
197
222
  "aria-label": "多发货 AI 客服聊天"
198
- }, Q = { class: "seer-chat__header" }, Y = {
223
+ }, le = { class: "seer-chat__header" }, ie = {
199
224
  class: "seer-chat__messages",
200
225
  "aria-live": "polite"
201
- }, Z = {
226
+ }, ce = {
202
227
  key: 0,
203
228
  class: "seer-chat__empty"
204
- }, ee = { class: "seer-chat__role" }, te = { class: "seer-chat__body" }, ne = ["href"], se = { key: 1 }, ae = {
229
+ }, ue = { class: "seer-chat__role" }, de = { class: "seer-chat__body" }, fe = ["href"], he = ["aria-label", "onClick"], _e = ["src", "alt"], ve = {
230
+ key: 2,
231
+ class: "seer-chat__strong"
232
+ }, pe = {
233
+ key: 3,
234
+ class: "seer-chat__price"
235
+ }, me = { key: 4 }, ge = {
205
236
  key: 0,
206
237
  class: "seer-chat__status"
207
- }, oe = {
238
+ }, ke = {
208
239
  key: 1,
209
240
  class: "seer-chat__error",
210
241
  role: "alert"
211
- }, re = {
242
+ }, be = {
212
243
  key: 2,
213
244
  class: "seer-chat__handoff"
214
- }, le = ["placeholder", "disabled", "onKeydown"], ie = { class: "seer-chat__composer-footer" }, ce = ["disabled"], ue = /* @__PURE__ */ L({
245
+ }, ye = ["placeholder", "disabled", "onKeydown"], we = { class: "seer-chat__composer-footer" }, Ee = ["disabled"], Se = ["aria-label"], Ce = ["src", "alt"], xe = /* @__PURE__ */ U({
215
246
  __name: "SeerChat",
216
247
  props: {
217
248
  endpoint: {},
@@ -222,110 +253,155 @@ const X = {
222
253
  placeholder: { default: "输入你的问题,例如:美国海派怎么报价?" }
223
254
  },
224
255
  setup(e) {
225
- const n = e, t = w(""), a = W({
256
+ const n = e, t = y(""), s = oe({
226
257
  endpoint: n.endpoint,
227
258
  model: n.model,
228
259
  stream: n.stream,
229
260
  fetcher: n.fetcher
230
- }), l = M(
231
- () => t.value.trim().length > 0 && !a.loading.value
232
- );
233
- async function r() {
234
- if (!l.value)
261
+ }), r = B(
262
+ () => t.value.trim().length > 0 && !s.loading.value
263
+ ), a = y(null);
264
+ function v(c) {
265
+ c.key === "Escape" && l();
266
+ }
267
+ function p(c, o) {
268
+ a.value = { src: c, alt: o }, window.addEventListener("keydown", v);
269
+ }
270
+ function l() {
271
+ a.value = null, window.removeEventListener("keydown", v);
272
+ }
273
+ M(() => {
274
+ window.removeEventListener("keydown", v);
275
+ });
276
+ async function i() {
277
+ if (!r.value)
235
278
  return;
236
- const d = t.value;
237
- t.value = "", await a.send(d);
279
+ const c = t.value;
280
+ t.value = "", await s.send(c);
238
281
  }
239
- return (d, o) => (v(), m("section", X, [
240
- u("header", Q, [
241
- u("div", null, [
242
- u("h2", null, C(e.title), 1),
243
- o[3] || (o[3] = u("p", null, "可咨询渠道报价、时效、下单资料、入仓和售后问题。", -1))
282
+ return (c, o) => (h(), _("section", re, [
283
+ f("header", le, [
284
+ f("div", null, [
285
+ f("h2", null, C(e.title), 1),
286
+ o[3] || (o[3] = f("p", null, "可咨询渠道报价、时效、下单资料、入仓和售后问题。", -1))
244
287
  ]),
245
- u("button", {
288
+ f("button", {
246
289
  type: "button",
247
290
  class: "seer-chat__clear-button",
248
- onClick: o[0] || (o[0] = (s) => _(a).reset())
291
+ onClick: o[0] || (o[0] = (m) => g(s).reset())
249
292
  }, " 清空对话 ")
250
293
  ]),
251
- u("div", Y, [
252
- _(a).messages.value.length === 0 ? (v(), m("p", Z, " 直接输入问题即可,复杂查单或赔付问题会提示转人工。 ")) : E("", !0),
253
- (v(!0), m(I, null, R(_(a).messages.value, (s, c) => (v(), m("article", {
254
- key: `${s.role}-${c}`,
255
- class: B(["seer-chat__message", `seer-chat__message--${s.role}`])
294
+ f("div", ie, [
295
+ g(s).messages.value.length === 0 ? (h(), _("p", ce, " 直接输入问题即可,复杂查单或赔付问题会提示转人工。 ")) : T("", !0),
296
+ (h(!0), _(R, null, I(g(s).messages.value, (m, k) => (h(), _("article", {
297
+ key: `${m.role}-${k}`,
298
+ class: q(["seer-chat__message", `seer-chat__message--${m.role}`])
256
299
  }, [
257
- u("span", ee, C(s.role === "user" ? "你" : "AI 客服"), 1),
258
- u("div", te, [
259
- (v(!0), m(I, null, R(_(H)(s.content), (f, h) => (v(), m("p", {
260
- key: h,
300
+ f("span", ue, C(m.role === "user" ? "你" : "AI 客服"), 1),
301
+ f("div", de, [
302
+ (h(!0), _(R, null, I(g(ae)(m.content), (w, x) => (h(), _("p", {
303
+ key: x,
261
304
  class: "seer-chat__line"
262
305
  }, [
263
- (v(!0), m(I, null, R(f, (p, g) => (v(), m(I, { key: g }, [
264
- p.kind === "link" ? (v(), m("a", {
306
+ (h(!0), _(R, null, I(w, (u, E) => (h(), _(R, { key: E }, [
307
+ u.kind === "link" ? (h(), _("a", {
265
308
  key: 0,
266
309
  class: "seer-chat__link",
267
- href: p.href,
310
+ href: u.href,
268
311
  target: "_blank",
269
312
  rel: "noopener noreferrer"
270
- }, C(p.label), 9, ne)) : (v(), m("span", se, C(p.value), 1))
313
+ }, C(u.label), 9, fe)) : u.kind === "image" ? (h(), _("button", {
314
+ key: 1,
315
+ type: "button",
316
+ class: "seer-chat__image-button",
317
+ "aria-label": `放大查看${u.alt}`,
318
+ onClick: (b) => p(u.href, u.alt)
319
+ }, [
320
+ f("img", {
321
+ class: "seer-chat__image",
322
+ src: u.href,
323
+ alt: u.alt,
324
+ loading: "lazy"
325
+ }, null, 8, _e)
326
+ ], 8, he)) : u.kind === "strong" ? (h(), _("strong", ve, C(u.value), 1)) : u.kind === "price" ? (h(), _("span", pe, C(u.value), 1)) : (h(), _("span", me, C(u.value), 1))
271
327
  ], 64))), 128))
272
328
  ]))), 128))
273
329
  ])
274
330
  ], 2))), 128))
275
331
  ]),
276
- _(a).loading.value ? (v(), m("p", ae, "正在回复...")) : E("", !0),
277
- _(a).error.value ? (v(), m("p", oe, C(_(a).error.value), 1)) : E("", !0),
278
- _(a).handoffRequested.value ? (v(), m("p", re, " 建议转人工:请留下联系方式或等待客服接入。 ")) : E("", !0),
279
- u("form", {
332
+ g(s).loading.value ? (h(), _("p", ge, "正在回复...")) : T("", !0),
333
+ g(s).error.value ? (h(), _("p", ke, C(g(s).error.value), 1)) : T("", !0),
334
+ g(s).handoffRequested.value ? (h(), _("p", be, " 建议转人工:请留下联系方式或等待客服接入。 ")) : T("", !0),
335
+ f("form", {
280
336
  class: "seer-chat__form",
281
- onSubmit: O(r, ["prevent"])
337
+ onSubmit: A(i, ["prevent"])
282
338
  }, [
283
- o[6] || (o[6] = u("label", {
339
+ o[6] || (o[6] = f("label", {
284
340
  class: "seer-chat__label",
285
341
  for: "seer-chat-input"
286
342
  }, "问题", -1)),
287
- K(u("textarea", {
343
+ z(f("textarea", {
288
344
  id: "seer-chat-input",
289
- "onUpdate:modelValue": o[1] || (o[1] = (s) => t.value = s),
345
+ "onUpdate:modelValue": o[1] || (o[1] = (m) => t.value = m),
290
346
  placeholder: e.placeholder,
291
- disabled: _(a).loading.value,
347
+ disabled: g(s).loading.value,
292
348
  rows: "3",
293
- onKeydown: D(O(r, ["exact", "prevent"]), ["enter"])
294
- }, null, 40, le), [
295
- [F, t.value]
349
+ onKeydown: F(A(i, ["exact", "prevent"]), ["enter"])
350
+ }, null, 40, ye), [
351
+ [V, t.value]
296
352
  ]),
297
- u("div", ie, [
298
- o[5] || (o[5] = u("span", { class: "seer-chat__hint" }, "Enter 发送 · Shift+Enter 换行", -1)),
299
- _(a).loading.value ? (v(), m("button", {
353
+ f("div", we, [
354
+ o[5] || (o[5] = f("span", { class: "seer-chat__hint" }, "Enter 发送 · Shift+Enter 换行", -1)),
355
+ g(s).loading.value ? (h(), _("button", {
300
356
  key: 0,
301
357
  type: "button",
302
358
  class: "seer-chat__stop-button",
303
- onClick: o[2] || (o[2] = (s) => _(a).abort())
304
- }, " 停止 ")) : E("", !0),
305
- u("button", {
359
+ onClick: o[2] || (o[2] = (m) => g(s).abort())
360
+ }, " 停止 ")) : T("", !0),
361
+ f("button", {
306
362
  class: "seer-chat__send-button",
307
363
  type: "submit",
308
- disabled: !l.value
364
+ disabled: !r.value
309
365
  }, [...o[4] || (o[4] = [
310
- u("span", null, "发送", -1),
311
- u("span", { "aria-hidden": "true" }, "↵", -1)
312
- ])], 8, ce)
366
+ f("span", null, "发送", -1),
367
+ f("span", { "aria-hidden": "true" }, "↵", -1)
368
+ ])], 8, Ee)
313
369
  ])
314
- ], 32)
370
+ ], 32),
371
+ a.value ? (h(), _("div", {
372
+ key: 3,
373
+ class: "seer-chat__lightbox",
374
+ role: "dialog",
375
+ "aria-modal": "true",
376
+ "aria-label": a.value.alt,
377
+ onClick: l
378
+ }, [
379
+ f("button", {
380
+ type: "button",
381
+ class: "seer-chat__lightbox-close",
382
+ "aria-label": "关闭",
383
+ onClick: l
384
+ }, " × "),
385
+ f("img", {
386
+ class: "seer-chat__lightbox-image",
387
+ src: a.value.src,
388
+ alt: a.value.alt
389
+ }, null, 8, Ce)
390
+ ], 8, Se)) : T("", !0)
315
391
  ]));
316
392
  }
317
- }), de = (e, n) => {
393
+ }), Te = (e, n) => {
318
394
  const t = e.__vccOpts || e;
319
- for (const [a, l] of n)
320
- t[a] = l;
395
+ for (const [s, r] of n)
396
+ t[s] = r;
321
397
  return t;
322
- }, ve = /* @__PURE__ */ de(ue, [["__scopeId", "data-v-f2b8b91f"]]);
398
+ }, Ae = /* @__PURE__ */ Te(xe, [["__scopeId", "data-v-dc651545"]]);
323
399
  export {
324
- ve as SeerChat,
325
- he as SeerChatPlugin,
326
- U as createSeerClient,
327
- J as linkAnchorLabel,
328
- H as toContentLines,
329
- G as toContentSegments,
330
- W as useSeerChat
400
+ Ae as SeerChat,
401
+ Ie as SeerChatPlugin,
402
+ X as createSeerClient,
403
+ ne as linkAnchorLabel,
404
+ ae as toContentLines,
405
+ se as toContentSegments,
406
+ oe as useSeerChat
331
407
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seer-ai/seer-vue",
3
- "version": "0.1.0-beta.5",
3
+ "version": "0.1.0-beta.6",
4
4
  "description": "Vue chat plugin for the seer OpenAI-compatible API",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",