@seer-ai/seer-vue 0.1.0-beta.3 → 0.1.0-beta.4

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/dist/client.d.ts CHANGED
@@ -7,8 +7,10 @@ export interface SeerChatMessage {
7
7
  export interface SeerClientOptions {
8
8
  endpoint: string;
9
9
  sessionEndpoint?: string;
10
+ challengeTokenProvider?: () => Promise<string>;
10
11
  model?: string;
11
12
  fetcher?: typeof fetch;
13
+ now?: () => number;
12
14
  }
13
15
  export interface SeerChatRequest {
14
16
  messages: SeerChatMessage[];
@@ -1,9 +1,9 @@
1
- import type { SeerClientOptions } from '../client';
1
+ import type { SeerClientOptions } from "../client";
2
2
  type __VLS_Props = {
3
3
  endpoint?: string;
4
4
  model?: string;
5
5
  stream?: boolean;
6
- fetcher?: SeerClientOptions['fetcher'];
6
+ fetcher?: SeerClientOptions["fetcher"];
7
7
  title?: string;
8
8
  placeholder?: string;
9
9
  };
package/dist/index.css CHANGED
@@ -1 +1 @@
1
- .seer-chat[data-v-163bc07c]{display:grid;gap:16px;max-width:720px;padding:20px;color:#172033;background:#fff;border:1px solid #d9e2ef;border-radius:16px}.seer-chat__header[data-v-163bc07c]{display:flex;gap:16px;align-items:flex-start;justify-content:space-between}.seer-chat__header h2[data-v-163bc07c]{margin:0;font-size:20px}.seer-chat__header p[data-v-163bc07c],.seer-chat__empty[data-v-163bc07c],.seer-chat__status[data-v-163bc07c]{margin:4px 0 0;color:#5f6f89;font-size:14px}.seer-chat__messages[data-v-163bc07c]{display:grid;gap:12px;min-height:180px}.seer-chat__message[data-v-163bc07c]{display:grid;gap:4px;max-width:86%;padding:12px 14px;border-radius:14px;background:#f3f6fb}.seer-chat__message--user[data-v-163bc07c]{justify-self:end;color:#fff;background:#1f5eff}.seer-chat__role[data-v-163bc07c]{font-size:12px;font-weight:700;opacity:.75}.seer-chat__message p[data-v-163bc07c]{margin:0;white-space:pre-wrap}.seer-chat__error[data-v-163bc07c],.seer-chat__handoff[data-v-163bc07c]{margin:0;padding:10px 12px;border-radius:10px}.seer-chat__error[data-v-163bc07c]{color:#8a1f11;background:#fff0ed}.seer-chat__handoff[data-v-163bc07c]{color:#704600;background:#fff7db}.seer-chat__form[data-v-163bc07c]{display:grid;gap:10px}.seer-chat__label[data-v-163bc07c]{font-size:13px;font-weight:700}.seer-chat textarea[data-v-163bc07c]{width:100%;box-sizing:border-box;padding:12px;color:inherit;border:1px solid #c8d3e2;border-radius:12px;resize:vertical}.seer-chat button[data-v-163bc07c]{padding:9px 14px;color:#fff;background:#172033;border:0;border-radius:999px;cursor:pointer}.seer-chat button[data-v-163bc07c]:disabled{cursor:not-allowed;opacity:.5}.seer-chat button[data-v-163bc07c]:focus-visible,.seer-chat textarea[data-v-163bc07c]:focus-visible{outline:3px solid #8fb4ff;outline-offset:2px}.seer-chat__ghost-button[data-v-163bc07c]{color:#172033!important;background:#eef3fa!important}.seer-chat__actions[data-v-163bc07c]{display:flex;gap:8px;justify-content:flex-end}
1
+ .seer-chat[data-v-fefeb009]{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-fefeb009]{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-fefeb009]{margin:0;font-size:22px;letter-spacing:-.03em}.seer-chat__header p[data-v-fefeb009],.seer-chat__empty[data-v-fefeb009],.seer-chat__status[data-v-fefeb009]{margin:4px 0 0;color:#5f6f89;font-size:14px}.seer-chat__header p[data-v-fefeb009]{max-width:34ch;color:#ffffffb8}.seer-chat__messages[data-v-fefeb009]{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-fefeb009]{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-fefeb009]{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-fefeb009]{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-fefeb009]{font-size:12px;font-weight:700;opacity:.75}.seer-chat__body[data-v-fefeb009]{display:flex;flex-direction:column}.seer-chat__line[data-v-fefeb009]{margin:0;white-space:pre-wrap;overflow-wrap:anywhere}.seer-chat__line[data-v-fefeb009]:not(:last-child){margin-bottom:5px}.seer-chat__line[data-v-fefeb009]:empty{height:7px}.seer-chat__link[data-v-fefeb009]{color:#1f5eff;font-weight:600;text-decoration:underline;text-underline-offset:2px;overflow-wrap:anywhere}.seer-chat__link[data-v-fefeb009]:hover{color:#173fb3}.seer-chat__message--user .seer-chat__link[data-v-fefeb009]{color:#fff}.seer-chat__error[data-v-fefeb009],.seer-chat__handoff[data-v-fefeb009]{margin:0 18px;padding:10px 12px;border-radius:14px}.seer-chat__error[data-v-fefeb009]{color:#8a1f11;background:#fff0ed}.seer-chat__handoff[data-v-fefeb009]{color:#704600;background:#fff7db}.seer-chat__form[data-v-fefeb009]{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-fefeb009]{font-size:13px;font-weight:700}.seer-chat textarea[data-v-fefeb009]{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-fefeb009]{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-fefeb009]:not(:disabled):hover{transform:translateY(-1px)}.seer-chat button[data-v-fefeb009]:disabled{cursor:not-allowed;opacity:.5}.seer-chat button[data-v-fefeb009]:focus-visible,.seer-chat textarea[data-v-fefeb009]:focus-visible{border-color:#1f5eff6b;box-shadow:0 0 0 4px #1f5eff21}.seer-chat__clear-button[data-v-fefeb009]{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-fefeb009]:not(:disabled):hover{color:#fff;background:#ffffff1a;box-shadow:none}.seer-chat__stop-button[data-v-fefeb009]{padding:8px 11px;color:#6c3b12;font-size:12px;background:#fff1df;border-radius:12px}.seer-chat__send-button[data-v-fefeb009]{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-fefeb009]:not(:disabled):hover{box-shadow:0 14px 28px #1f5eff47}.seer-chat__hint[data-v-fefeb009]{margin-right:auto;color:#7a879a;font-size:12px}.seer-chat__composer-footer[data-v-fefeb009]{display:flex;gap:8px;align-items:center;justify-content:flex-end}
package/dist/index.js CHANGED
@@ -1,190 +1,196 @@
1
- import { hasInjectionContext as T, inject as $, ref as w, defineComponent as A, computed as q, openBlock as v, createElementBlock as p, createElementVNode as u, toDisplayString as E, unref as h, createCommentVNode as k, Fragment as M, renderList as N, normalizeClass as B, withModifiers as D, withDirectives as F, vModelText as P } from "vue";
2
- function V(n) {
3
- const t = n.fetcher ?? fetch, e = n.model ?? "seer";
4
- let s, c = 0;
1
+ import { hasInjectionContext as $, inject as N, ref as E, defineComponent as q, computed as L, openBlock as v, createElementBlock as m, createElementVNode as f, toDisplayString as T, unref as w, createCommentVNode as x, Fragment as I, renderList as R, normalizeClass as M, withModifiers as O, withDirectives as B, withKeys as K, vModelText as D } from "vue";
2
+ function F(t) {
3
+ const n = t.fetcher ?? fetch, e = t.model ?? "seer", o = t.now ?? (() => Math.floor(Date.now() / 1e3));
4
+ let u, i = 0;
5
5
  return {
6
- async chat(r, a = {}) {
7
- const o = r.stream ?? !1, f = await l(), m = {
6
+ async chat(l, d = {}) {
7
+ const a = l.stream ?? !1, s = await p(), r = {
8
8
  "Content-Type": "application/json"
9
9
  };
10
- f && (m.Authorization = `Bearer ${f}`);
11
- const d = await t(n.endpoint, {
10
+ s && (r.Authorization = `Bearer ${s}`);
11
+ const h = await n(t.endpoint, {
12
12
  method: "POST",
13
- headers: m,
14
- signal: a.signal,
13
+ headers: r,
14
+ signal: d.signal,
15
15
  body: JSON.stringify({
16
- model: r.model ?? e,
17
- messages: r.messages,
18
- stream: o,
19
- conversation_id: r.conversationId,
20
- metadata: r.metadata
16
+ model: l.model ?? e,
17
+ messages: l.messages,
18
+ stream: a,
19
+ conversation_id: l.conversationId,
20
+ metadata: l.metadata
21
21
  })
22
22
  });
23
- if (!d.ok)
24
- throw new Error(await j(d));
25
- if (o)
26
- return z(d, a.onDelta);
27
- const y = await d.json();
28
- return O(y);
23
+ if (!h.ok)
24
+ throw new Error(await j(h));
25
+ if (a)
26
+ return U(h, d.onDelta);
27
+ const y = await h.json();
28
+ return A(y);
29
29
  }
30
30
  };
31
- async function l() {
32
- if (!n.sessionEndpoint)
31
+ async function p() {
32
+ if (!t.sessionEndpoint)
33
33
  return;
34
- const r = Math.floor(Date.now() / 1e3);
35
- if (s && c - 30 > r)
36
- return s;
37
- const a = await t(n.sessionEndpoint, {
38
- method: "GET"
34
+ const l = o();
35
+ if (u && i - 30 > l)
36
+ return u;
37
+ const d = await n(t.sessionEndpoint, {
38
+ method: "GET",
39
+ headers: await _()
39
40
  });
40
- if (!a.ok)
41
- throw new Error(await j(a));
42
- const o = await a.json();
43
- return s = o.token, c = o.expires_at, s;
41
+ if (!d.ok)
42
+ throw new Error(await j(d));
43
+ const a = await d.json();
44
+ return u = a.token, i = a.expires_at, u;
45
+ }
46
+ async function _() {
47
+ const l = {};
48
+ return t.challengeTokenProvider && (l["X-Seer-Challenge-Token"] = await t.challengeTokenProvider()), l;
44
49
  }
45
50
  }
46
- function O(n) {
47
- var e, s, c;
48
- const t = (e = n.choices) == null ? void 0 : e[0];
51
+ function A(t) {
52
+ var e, o, u;
53
+ const n = (e = t.choices) == null ? void 0 : e[0];
49
54
  return {
50
- content: ((s = t == null ? void 0 : t.message) == null ? void 0 : s.content) ?? ((c = t == null ? void 0 : t.delta) == null ? void 0 : c.content) ?? "",
51
- conversationId: n.conversation_id,
52
- citations: n.citations ?? [],
53
- handoffRequested: n.handoff_requested ?? !1,
54
- finishReason: t == null ? void 0 : t.finish_reason
55
+ content: ((o = n == null ? void 0 : n.message) == null ? void 0 : o.content) ?? ((u = n == null ? void 0 : n.delta) == null ? void 0 : u.content) ?? "",
56
+ conversationId: t.conversation_id,
57
+ citations: t.citations ?? [],
58
+ handoffRequested: t.handoff_requested ?? !1,
59
+ finishReason: n == null ? void 0 : n.finish_reason
55
60
  };
56
61
  }
57
- async function z(n, t) {
58
- var m, d, y;
59
- if (!n.body)
60
- return O({});
61
- const e = n.body.getReader(), s = new TextDecoder();
62
- let c = "", l = "", r, a = [], o = !1, f;
62
+ async function U(t, n) {
63
+ var a, s, r;
64
+ if (!t.body)
65
+ return A({});
66
+ const e = t.body.getReader(), o = new TextDecoder();
67
+ let u = "", i = "", p, _ = [], l = !1, d;
63
68
  for (; ; ) {
64
- const { done: x, value: I } = await e.read();
65
- if (x)
69
+ const { done: h, value: y } = await e.read();
70
+ if (h)
66
71
  break;
67
- c += s.decode(I, { stream: !0 });
68
- const S = c.split(`
72
+ u += o.decode(y, { stream: !0 });
73
+ const g = u.split(`
69
74
 
70
75
  `);
71
- c = S.pop() ?? "";
72
- for (const C of S) {
73
- const b = J(C);
76
+ u = g.pop() ?? "";
77
+ for (const k of g) {
78
+ const b = V(k);
74
79
  if (!b || b === "[DONE]")
75
80
  continue;
76
- const _ = JSON.parse(b), i = (m = _.choices) == null ? void 0 : m[0], g = ((d = i == null ? void 0 : i.delta) == null ? void 0 : d.content) ?? ((y = i == null ? void 0 : i.message) == null ? void 0 : y.content) ?? "";
77
- g && (l += g, t == null || t(g)), r = _.conversation_id ?? r, a = _.citations ?? a, o = _.handoff_requested ?? o, f = (i == null ? void 0 : i.finish_reason) ?? f;
81
+ const S = JSON.parse(b), c = (a = S.choices) == null ? void 0 : a[0], C = ((s = c == null ? void 0 : c.delta) == null ? void 0 : s.content) ?? ((r = c == null ? void 0 : c.message) == null ? void 0 : r.content) ?? "";
82
+ C && (i += C, n == null || n(C)), p = S.conversation_id ?? p, _ = S.citations ?? _, l = S.handoff_requested ?? l, d = (c == null ? void 0 : c.finish_reason) ?? d;
78
83
  }
79
84
  }
80
85
  return {
81
- content: l,
82
- conversationId: r,
83
- citations: a,
84
- handoffRequested: o,
85
- finishReason: f
86
+ content: i,
87
+ conversationId: p,
88
+ citations: _,
89
+ handoffRequested: l,
90
+ finishReason: d
86
91
  };
87
92
  }
88
- function J(n) {
89
- const t = n.split(`
93
+ function V(t) {
94
+ const n = t.split(`
90
95
  `).map((e) => e.trim()).filter((e) => e.startsWith("data:")).map((e) => e.slice(5).trim());
91
- return t.length === 0 ? null : t.join(`
96
+ return n.length === 0 ? null : n.join(`
92
97
  `);
93
98
  }
94
- async function j(n) {
95
- let t = n.statusText || "unknown error";
99
+ async function j(t) {
100
+ let n = t.statusText || "unknown error";
96
101
  try {
97
- const e = await n.json();
98
- typeof (e == null ? void 0 : e.detail) == "string" ? t = e.detail : typeof (e == null ? void 0 : e.error) == "string" && (t = e.error);
102
+ const e = await t.json();
103
+ typeof (e == null ? void 0 : e.detail) == "string" ? n = e.detail : typeof (e == null ? void 0 : e.error) == "string" && (n = e.error);
99
104
  } catch {
100
- const e = await n.text().catch(() => "");
101
- e && (t = e);
105
+ const e = await t.text().catch(() => "");
106
+ e && (n = e);
102
107
  }
103
- return `seer chat request failed with status ${n.status}: ${t}`;
108
+ return `seer chat request failed with status ${t.status}: ${n}`;
104
109
  }
105
- const R = Symbol("seer-chat-options"), oe = {
106
- install(n, t) {
107
- n.provide(R, t);
110
+ const P = Symbol("seer-chat-options"), ce = {
111
+ install(t, n) {
112
+ t.provide(P, n);
108
113
  }
109
114
  };
110
- function L(n = {}) {
111
- const e = { ...T() ? $(R, void 0) : void 0, ...n };
115
+ function z(t = {}) {
116
+ const e = { ...$() ? N(P, void 0) : void 0, ...t };
112
117
  if (!e.endpoint)
113
118
  throw new Error("Seer chat endpoint is required. Pass it to app.use() or useSeerChat().");
114
- const s = {
119
+ const o = {
115
120
  endpoint: e.endpoint,
116
121
  sessionEndpoint: e.sessionEndpoint,
122
+ challengeTokenProvider: e.challengeTokenProvider,
117
123
  model: e.model,
118
124
  fetcher: e.fetcher
119
- }, c = V(s), l = w([]), r = w(!1), a = w(null), o = w(), f = w([]), m = w(!1);
120
- let d = null;
121
- async function y(S) {
122
- const C = S.trim();
123
- if (!C || r.value)
125
+ }, u = F(o), i = E([]), p = E(!1), _ = E(null), l = E(), d = E([]), a = E(!1);
126
+ let s = null;
127
+ async function r(g) {
128
+ const k = g.trim();
129
+ if (!k || p.value)
124
130
  return;
125
- const b = { role: "user", content: C };
126
- l.value = [...l.value, b], r.value = !0, a.value = null, d = new AbortController();
127
- const _ = { role: "assistant", content: "" };
128
- e.stream && (l.value = [...l.value, _]);
131
+ const b = { role: "user", content: k };
132
+ i.value = [...i.value, b], p.value = !0, _.value = null, s = new AbortController();
133
+ const S = { role: "assistant", content: "" };
134
+ e.stream && (i.value = [...i.value, S]);
129
135
  try {
130
- const i = await c.chat(
136
+ const c = await u.chat(
131
137
  {
132
- messages: l.value.filter((g) => g.content),
138
+ messages: i.value.filter((C) => C.content),
133
139
  stream: e.stream ?? !1,
134
- conversationId: o.value
140
+ conversationId: l.value
135
141
  },
136
142
  {
137
- signal: d.signal,
138
- onDelta(g) {
139
- _.content += g, l.value = [...l.value];
143
+ signal: s.signal,
144
+ onDelta(C) {
145
+ S.content += C, i.value = [...i.value];
140
146
  }
141
147
  }
142
148
  );
143
- e.stream || (l.value = [...l.value, { role: "assistant", content: i.content }]), o.value = i.conversationId, f.value = i.citations, m.value = i.handoffRequested;
144
- } catch (i) {
145
- i.name !== "AbortError" && (a.value = i instanceof Error ? i.message : String(i));
149
+ e.stream || (i.value = [...i.value, { role: "assistant", content: c.content }]), l.value = c.conversationId, d.value = c.citations, a.value = c.handoffRequested;
150
+ } catch (c) {
151
+ c.name !== "AbortError" && (_.value = c instanceof Error ? c.message : String(c));
146
152
  } finally {
147
- r.value = !1, d = null;
153
+ p.value = !1, s = null;
148
154
  }
149
155
  }
150
- function x() {
151
- l.value = [], a.value = null, o.value = void 0, f.value = [], m.value = !1;
156
+ function h() {
157
+ i.value = [], _.value = null, l.value = void 0, d.value = [], a.value = !1;
152
158
  }
153
- function I() {
154
- d == null || d.abort();
159
+ function y() {
160
+ s == null || s.abort();
155
161
  }
156
162
  return {
157
- messages: l,
158
- loading: r,
159
- error: a,
160
- conversationId: o,
161
- citations: f,
162
- handoffRequested: m,
163
- send: y,
164
- reset: x,
165
- abort: I
163
+ messages: i,
164
+ loading: p,
165
+ error: _,
166
+ conversationId: l,
167
+ citations: d,
168
+ handoffRequested: a,
169
+ send: r,
170
+ reset: h,
171
+ abort: y
166
172
  };
167
173
  }
168
- const G = {
174
+ const J = {
169
175
  class: "seer-chat",
170
176
  "aria-label": "多发货 AI 客服聊天"
171
- }, K = { class: "seer-chat__header" }, U = {
177
+ }, G = { class: "seer-chat__header" }, H = {
172
178
  class: "seer-chat__messages",
173
179
  "aria-live": "polite"
174
180
  }, W = {
175
181
  key: 0,
176
182
  class: "seer-chat__empty"
177
- }, H = { class: "seer-chat__role" }, Q = {
183
+ }, X = { class: "seer-chat__role" }, Q = { class: "seer-chat__body" }, Y = ["href"], Z = { key: 1 }, ee = {
178
184
  key: 0,
179
185
  class: "seer-chat__status"
180
- }, X = {
186
+ }, te = {
181
187
  key: 1,
182
188
  class: "seer-chat__error",
183
189
  role: "alert"
184
- }, Y = {
190
+ }, ne = {
185
191
  key: 2,
186
192
  class: "seer-chat__handoff"
187
- }, Z = ["placeholder", "disabled"], ee = { class: "seer-chat__actions" }, te = ["disabled"], ne = /* @__PURE__ */ A({
193
+ }, se = ["placeholder", "disabled", "onKeydown"], ae = { class: "seer-chat__composer-footer" }, oe = ["disabled"], re = /* @__PURE__ */ q({
188
194
  __name: "SeerChat",
189
195
  props: {
190
196
  endpoint: {},
@@ -194,85 +200,128 @@ const G = {
194
200
  title: { default: "多发货 AI 客服" },
195
201
  placeholder: { default: "输入你的问题,例如:美国海派怎么报价?" }
196
202
  },
197
- setup(n) {
198
- const t = n, e = w(""), s = L({
199
- endpoint: t.endpoint,
200
- model: t.model,
201
- stream: t.stream,
202
- fetcher: t.fetcher
203
- }), c = q(() => e.value.trim().length > 0 && !s.loading.value);
204
- async function l() {
205
- if (!c.value)
203
+ setup(t) {
204
+ const n = t, e = E(""), o = z({
205
+ endpoint: n.endpoint,
206
+ model: n.model,
207
+ stream: n.stream,
208
+ fetcher: n.fetcher
209
+ }), u = L(
210
+ () => e.value.trim().length > 0 && !o.loading.value
211
+ ), i = /https?:\/\/[^\s)]+/g;
212
+ function p(a) {
213
+ return /标签|箱唛/.test(a) ? "点击下载箱唛" : /入库单|交接单/.test(a) ? "点击下载入库单" : /面单/.test(a) ? "点击下载面单" : /截图/.test(a) ? "点击查看报价截图" : /下载链接|labelUrl|下载/.test(a) ? "点击下载" : /链接/.test(a) ? "点击查看" : null;
214
+ }
215
+ function _(a) {
216
+ const s = [];
217
+ i.lastIndex = 0;
218
+ let r = 0, h;
219
+ for (; (h = i.exec(a)) !== null; ) {
220
+ const y = h[0], g = h.index;
221
+ g > r && s.push({ kind: "text", value: a.slice(r, g) });
222
+ const k = a.lastIndexOf(`
223
+ `, g - 1) + 1, b = p(a.slice(k, g)) ?? y;
224
+ s.push({ kind: "link", href: y, label: b }), r = g + y.length;
225
+ }
226
+ return r < a.length && s.push({ kind: "text", value: a.slice(r) }), s;
227
+ }
228
+ function l(a) {
229
+ return a.split(`
230
+ `).map((s) => _(s));
231
+ }
232
+ async function d() {
233
+ if (!u.value)
206
234
  return;
207
- const r = e.value;
208
- e.value = "", await s.send(r);
235
+ const a = e.value;
236
+ e.value = "", await o.send(a);
209
237
  }
210
- return (r, a) => (v(), p("section", G, [
211
- u("header", K, [
212
- u("div", null, [
213
- u("h2", null, E(n.title), 1),
214
- a[3] || (a[3] = u("p", null, "可咨询渠道报价、时效、下单资料、入仓和售后问题。", -1))
238
+ return (a, s) => (v(), m("section", J, [
239
+ f("header", G, [
240
+ f("div", null, [
241
+ f("h2", null, T(t.title), 1),
242
+ s[3] || (s[3] = f("p", null, "可咨询渠道报价、时效、下单资料、入仓和售后问题。", -1))
215
243
  ]),
216
- u("button", {
244
+ f("button", {
217
245
  type: "button",
218
- class: "seer-chat__ghost-button",
219
- onClick: a[0] || (a[0] = (o) => h(s).reset())
220
- }, "清空")
246
+ class: "seer-chat__clear-button",
247
+ onClick: s[0] || (s[0] = (r) => w(o).reset())
248
+ }, " 清空对话 ")
221
249
  ]),
222
- u("div", U, [
223
- h(s).messages.value.length === 0 ? (v(), p("p", W, " 直接输入问题即可,复杂查单或赔付问题会提示转人工。 ")) : k("", !0),
224
- (v(!0), p(M, null, N(h(s).messages.value, (o, f) => (v(), p("article", {
225
- key: `${o.role}-${f}`,
226
- class: B(["seer-chat__message", `seer-chat__message--${o.role}`])
250
+ f("div", H, [
251
+ w(o).messages.value.length === 0 ? (v(), m("p", W, " 直接输入问题即可,复杂查单或赔付问题会提示转人工。 ")) : x("", !0),
252
+ (v(!0), m(I, null, R(w(o).messages.value, (r, h) => (v(), m("article", {
253
+ key: `${r.role}-${h}`,
254
+ class: M(["seer-chat__message", `seer-chat__message--${r.role}`])
227
255
  }, [
228
- u("span", H, E(o.role === "user" ? "你" : "AI 客服"), 1),
229
- u("p", null, E(o.content), 1)
256
+ f("span", X, T(r.role === "user" ? "你" : "AI 客服"), 1),
257
+ f("div", Q, [
258
+ (v(!0), m(I, null, R(l(r.content), (y, g) => (v(), m("p", {
259
+ key: g,
260
+ class: "seer-chat__line"
261
+ }, [
262
+ (v(!0), m(I, null, R(y, (k, b) => (v(), m(I, { key: b }, [
263
+ k.kind === "link" ? (v(), m("a", {
264
+ key: 0,
265
+ class: "seer-chat__link",
266
+ href: k.href,
267
+ target: "_blank",
268
+ rel: "noopener noreferrer"
269
+ }, T(k.label), 9, Y)) : (v(), m("span", Z, T(k.value), 1))
270
+ ], 64))), 128))
271
+ ]))), 128))
272
+ ])
230
273
  ], 2))), 128))
231
274
  ]),
232
- h(s).loading.value ? (v(), p("p", Q, "正在回复...")) : k("", !0),
233
- h(s).error.value ? (v(), p("p", X, E(h(s).error.value), 1)) : k("", !0),
234
- h(s).handoffRequested.value ? (v(), p("p", Y, " 建议转人工:请留下联系方式或等待客服接入。 ")) : k("", !0),
235
- u("form", {
275
+ w(o).loading.value ? (v(), m("p", ee, "正在回复...")) : x("", !0),
276
+ w(o).error.value ? (v(), m("p", te, T(w(o).error.value), 1)) : x("", !0),
277
+ w(o).handoffRequested.value ? (v(), m("p", ne, " 建议转人工:请留下联系方式或等待客服接入。 ")) : x("", !0),
278
+ f("form", {
236
279
  class: "seer-chat__form",
237
- onSubmit: D(l, ["prevent"])
280
+ onSubmit: O(d, ["prevent"])
238
281
  }, [
239
- a[4] || (a[4] = u("label", {
282
+ s[6] || (s[6] = f("label", {
240
283
  class: "seer-chat__label",
241
284
  for: "seer-chat-input"
242
285
  }, "问题", -1)),
243
- F(u("textarea", {
286
+ B(f("textarea", {
244
287
  id: "seer-chat-input",
245
- "onUpdate:modelValue": a[1] || (a[1] = (o) => e.value = o),
246
- placeholder: n.placeholder,
247
- disabled: h(s).loading.value,
248
- rows: "3"
249
- }, null, 8, Z), [
250
- [P, e.value]
288
+ "onUpdate:modelValue": s[1] || (s[1] = (r) => e.value = r),
289
+ placeholder: t.placeholder,
290
+ disabled: w(o).loading.value,
291
+ rows: "3",
292
+ onKeydown: K(O(d, ["exact", "prevent"]), ["enter"])
293
+ }, null, 40, se), [
294
+ [D, e.value]
251
295
  ]),
252
- u("div", ee, [
253
- h(s).loading.value ? (v(), p("button", {
296
+ f("div", ae, [
297
+ s[5] || (s[5] = f("span", { class: "seer-chat__hint" }, "Enter 发送 · Shift+Enter 换行", -1)),
298
+ w(o).loading.value ? (v(), m("button", {
254
299
  key: 0,
255
300
  type: "button",
256
- class: "seer-chat__ghost-button",
257
- onClick: a[2] || (a[2] = (o) => h(s).abort())
258
- }, " 停止 ")) : k("", !0),
259
- u("button", {
301
+ class: "seer-chat__stop-button",
302
+ onClick: s[2] || (s[2] = (r) => w(o).abort())
303
+ }, " 停止 ")) : x("", !0),
304
+ f("button", {
305
+ class: "seer-chat__send-button",
260
306
  type: "submit",
261
- disabled: !c.value
262
- }, "发送", 8, te)
307
+ disabled: !u.value
308
+ }, [...s[4] || (s[4] = [
309
+ f("span", null, "发送", -1),
310
+ f("span", { "aria-hidden": "true" }, "↵", -1)
311
+ ])], 8, oe)
263
312
  ])
264
313
  ], 32)
265
314
  ]));
266
315
  }
267
- }), se = (n, t) => {
268
- const e = n.__vccOpts || n;
269
- for (const [s, c] of t)
270
- e[s] = c;
316
+ }), le = (t, n) => {
317
+ const e = t.__vccOpts || t;
318
+ for (const [o, u] of n)
319
+ e[o] = u;
271
320
  return e;
272
- }, re = /* @__PURE__ */ se(ne, [["__scopeId", "data-v-163bc07c"]]);
321
+ }, ue = /* @__PURE__ */ le(re, [["__scopeId", "data-v-fefeb009"]]);
273
322
  export {
274
- re as SeerChat,
275
- oe as SeerChatPlugin,
276
- V as createSeerClient,
277
- L as useSeerChat
323
+ ue as SeerChat,
324
+ ce as SeerChatPlugin,
325
+ F as createSeerClient,
326
+ z as useSeerChat
278
327
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seer-ai/seer-vue",
3
- "version": "0.1.0-beta.3",
3
+ "version": "0.1.0-beta.4",
4
4
  "description": "Vue chat plugin for the seer OpenAI-compatible API",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -22,7 +22,8 @@
22
22
  "scripts": {
23
23
  "test": "vitest run",
24
24
  "typecheck": "vue-tsc --noEmit",
25
- "build": "vite build && vue-tsc -p tsconfig.build.json --declaration --emitDeclarationOnly --outDir dist"
25
+ "build": "vite build && vue-tsc -p tsconfig.build.json --declaration --emitDeclarationOnly --outDir dist",
26
+ "prepublishOnly": "npm run build"
26
27
  },
27
28
  "peerDependencies": {
28
29
  "vue": "^3.5.0"