@seer-ai/seer-vue 0.1.0-beta.1 → 0.1.0-beta.2
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 +3 -2
- package/dist/client.d.ts +1 -0
- package/dist/index.js +118 -100
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -17,7 +17,8 @@ import App from './App.vue'
|
|
|
17
17
|
|
|
18
18
|
createApp(App)
|
|
19
19
|
.use(SeerChatPlugin, {
|
|
20
|
-
|
|
20
|
+
sessionEndpoint: 'https://seer.example.com/v1/browser/session',
|
|
21
|
+
endpoint: 'https://seer.example.com/v1/browser/chat/completions',
|
|
21
22
|
model: 'seer',
|
|
22
23
|
stream: false,
|
|
23
24
|
})
|
|
@@ -55,4 +56,4 @@ async function submit() {
|
|
|
55
56
|
|
|
56
57
|
## Security
|
|
57
58
|
|
|
58
|
-
Do not put long-lived seer API keys in browser code or `VITE_*` variables. Browser code should call
|
|
59
|
+
Do not put long-lived seer API keys in browser code or `VITE_*` variables. Browser code should call seer's browser session endpoint, receive a short-lived token, and use that token for `/v1/browser/chat/completions`.
|
package/dist/client.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,71 +1,88 @@
|
|
|
1
|
-
import { hasInjectionContext as
|
|
1
|
+
import { hasInjectionContext as A, inject as q, ref as y, defineComponent as M, computed as N, openBlock as m, createElementBlock as v, createElementVNode as u, toDisplayString as S, unref as h, createCommentVNode as b, Fragment as j, renderList as O, normalizeClass as B, withModifiers as D, withDirectives as F, vModelText as P } from "vue";
|
|
2
2
|
function V(n) {
|
|
3
3
|
const t = n.fetcher ?? fetch, e = n.model ?? "seer";
|
|
4
|
+
let s, c = 0;
|
|
4
5
|
return {
|
|
5
|
-
async chat(
|
|
6
|
-
const
|
|
6
|
+
async chat(r, a = {}) {
|
|
7
|
+
const o = r.stream ?? !1, f = await l(), p = {
|
|
8
|
+
"Content-Type": "application/json"
|
|
9
|
+
};
|
|
10
|
+
f && (p.Authorization = `Bearer ${f}`);
|
|
11
|
+
const d = await t(n.endpoint, {
|
|
7
12
|
method: "POST",
|
|
8
|
-
headers:
|
|
9
|
-
|
|
10
|
-
},
|
|
11
|
-
signal: i.signal,
|
|
13
|
+
headers: p,
|
|
14
|
+
signal: a.signal,
|
|
12
15
|
body: JSON.stringify({
|
|
13
|
-
model:
|
|
14
|
-
messages:
|
|
15
|
-
stream:
|
|
16
|
-
conversation_id:
|
|
17
|
-
metadata:
|
|
16
|
+
model: r.model ?? e,
|
|
17
|
+
messages: r.messages,
|
|
18
|
+
stream: o,
|
|
19
|
+
conversation_id: r.conversationId,
|
|
20
|
+
metadata: r.metadata
|
|
18
21
|
})
|
|
19
22
|
});
|
|
20
|
-
if (!
|
|
21
|
-
throw new Error(await
|
|
22
|
-
if (
|
|
23
|
-
return
|
|
24
|
-
const
|
|
25
|
-
return
|
|
23
|
+
if (!d.ok)
|
|
24
|
+
throw new Error(await R(d));
|
|
25
|
+
if (o)
|
|
26
|
+
return z(d, a.onDelta);
|
|
27
|
+
const w = await d.json();
|
|
28
|
+
return T(w);
|
|
26
29
|
}
|
|
27
30
|
};
|
|
31
|
+
async function l() {
|
|
32
|
+
if (!n.sessionEndpoint)
|
|
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"
|
|
39
|
+
});
|
|
40
|
+
if (!a.ok)
|
|
41
|
+
throw new Error(await R(a));
|
|
42
|
+
const o = await a.json();
|
|
43
|
+
return s = o.token, c = o.expires_at, s;
|
|
44
|
+
}
|
|
28
45
|
}
|
|
29
|
-
function
|
|
30
|
-
var e, s,
|
|
46
|
+
function T(n) {
|
|
47
|
+
var e, s, c;
|
|
31
48
|
const t = (e = n.choices) == null ? void 0 : e[0];
|
|
32
49
|
return {
|
|
33
|
-
content: ((s = t == null ? void 0 : t.message) == null ? void 0 : s.content) ?? ((
|
|
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) ?? "",
|
|
34
51
|
conversationId: n.conversation_id,
|
|
35
52
|
citations: n.citations ?? [],
|
|
36
53
|
handoffRequested: n.handoff_requested ?? !1,
|
|
37
54
|
finishReason: t == null ? void 0 : t.finish_reason
|
|
38
55
|
};
|
|
39
56
|
}
|
|
40
|
-
async function
|
|
41
|
-
var
|
|
57
|
+
async function z(n, t) {
|
|
58
|
+
var p, d, w;
|
|
42
59
|
if (!n.body)
|
|
43
|
-
return
|
|
60
|
+
return T({});
|
|
44
61
|
const e = n.body.getReader(), s = new TextDecoder();
|
|
45
|
-
let
|
|
62
|
+
let c = "", l = "", r, a = [], o = !1, f;
|
|
46
63
|
for (; ; ) {
|
|
47
|
-
const { done: x, value:
|
|
64
|
+
const { done: x, value: I } = await e.read();
|
|
48
65
|
if (x)
|
|
49
66
|
break;
|
|
50
|
-
|
|
51
|
-
const
|
|
67
|
+
c += s.decode(I, { stream: !0 });
|
|
68
|
+
const C = c.split(`
|
|
52
69
|
|
|
53
70
|
`);
|
|
54
|
-
|
|
55
|
-
for (const
|
|
56
|
-
const
|
|
57
|
-
if (!
|
|
71
|
+
c = C.pop() ?? "";
|
|
72
|
+
for (const E of C) {
|
|
73
|
+
const k = J(E);
|
|
74
|
+
if (!k || k === "[DONE]")
|
|
58
75
|
continue;
|
|
59
|
-
const
|
|
60
|
-
|
|
76
|
+
const _ = JSON.parse(k), i = (p = _.choices) == null ? void 0 : p[0], g = ((d = i == null ? void 0 : i.delta) == null ? void 0 : d.content) ?? ((w = i == null ? void 0 : i.message) == null ? void 0 : w.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;
|
|
61
78
|
}
|
|
62
79
|
}
|
|
63
80
|
return {
|
|
64
|
-
content:
|
|
65
|
-
conversationId:
|
|
81
|
+
content: l,
|
|
82
|
+
conversationId: r,
|
|
66
83
|
citations: a,
|
|
67
84
|
handoffRequested: o,
|
|
68
|
-
finishReason:
|
|
85
|
+
finishReason: f
|
|
69
86
|
};
|
|
70
87
|
}
|
|
71
88
|
function J(n) {
|
|
@@ -74,7 +91,7 @@ function J(n) {
|
|
|
74
91
|
return t.length === 0 ? null : t.join(`
|
|
75
92
|
`);
|
|
76
93
|
}
|
|
77
|
-
async function
|
|
94
|
+
async function R(n) {
|
|
78
95
|
let t = n.statusText || "unknown error";
|
|
79
96
|
try {
|
|
80
97
|
const e = await n.json();
|
|
@@ -90,70 +107,71 @@ const $ = Symbol("seer-chat-options"), re = {
|
|
|
90
107
|
n.provide($, t);
|
|
91
108
|
}
|
|
92
109
|
};
|
|
93
|
-
function
|
|
94
|
-
const e = { ...
|
|
110
|
+
function L(n = {}) {
|
|
111
|
+
const e = { ...A() ? q($, void 0) : void 0, ...n };
|
|
95
112
|
if (!e.endpoint)
|
|
96
113
|
throw new Error("Seer chat endpoint is required. Pass it to app.use() or useSeerChat().");
|
|
97
114
|
const s = {
|
|
98
115
|
endpoint: e.endpoint,
|
|
116
|
+
sessionEndpoint: e.sessionEndpoint,
|
|
99
117
|
model: e.model,
|
|
100
118
|
fetcher: e.fetcher
|
|
101
|
-
},
|
|
102
|
-
let
|
|
103
|
-
async function C
|
|
104
|
-
const
|
|
105
|
-
if (!
|
|
119
|
+
}, c = V(s), l = y([]), r = y(!1), a = y(null), o = y(), f = y([]), p = y(!1);
|
|
120
|
+
let d = null;
|
|
121
|
+
async function w(C) {
|
|
122
|
+
const E = C.trim();
|
|
123
|
+
if (!E || r.value)
|
|
106
124
|
return;
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
const
|
|
110
|
-
e.stream && (
|
|
125
|
+
const k = { role: "user", content: E };
|
|
126
|
+
l.value = [...l.value, k], r.value = !0, a.value = null, d = new AbortController();
|
|
127
|
+
const _ = { role: "assistant", content: "" };
|
|
128
|
+
e.stream && (l.value = [...l.value, _]);
|
|
111
129
|
try {
|
|
112
|
-
const
|
|
130
|
+
const i = await c.chat(
|
|
113
131
|
{
|
|
114
|
-
messages:
|
|
132
|
+
messages: l.value.filter((g) => g.content),
|
|
115
133
|
stream: e.stream ?? !1,
|
|
116
134
|
conversationId: o.value
|
|
117
135
|
},
|
|
118
136
|
{
|
|
119
|
-
signal:
|
|
120
|
-
onDelta(
|
|
121
|
-
|
|
137
|
+
signal: d.signal,
|
|
138
|
+
onDelta(g) {
|
|
139
|
+
_.content += g, l.value = [...l.value];
|
|
122
140
|
}
|
|
123
141
|
}
|
|
124
142
|
);
|
|
125
|
-
e.stream || (
|
|
126
|
-
} catch (
|
|
127
|
-
|
|
143
|
+
e.stream || (l.value = [...l.value, { role: "assistant", content: i.content }]), o.value = i.conversationId, f.value = i.citations, p.value = i.handoffRequested;
|
|
144
|
+
} catch (i) {
|
|
145
|
+
i.name !== "AbortError" && (a.value = i instanceof Error ? i.message : String(i));
|
|
128
146
|
} finally {
|
|
129
|
-
|
|
147
|
+
r.value = !1, d = null;
|
|
130
148
|
}
|
|
131
149
|
}
|
|
132
150
|
function x() {
|
|
133
|
-
|
|
151
|
+
l.value = [], a.value = null, o.value = void 0, f.value = [], p.value = !1;
|
|
134
152
|
}
|
|
135
|
-
function
|
|
136
|
-
|
|
153
|
+
function I() {
|
|
154
|
+
d == null || d.abort();
|
|
137
155
|
}
|
|
138
156
|
return {
|
|
139
|
-
messages:
|
|
140
|
-
loading:
|
|
157
|
+
messages: l,
|
|
158
|
+
loading: r,
|
|
141
159
|
error: a,
|
|
142
160
|
conversationId: o,
|
|
143
|
-
citations:
|
|
144
|
-
handoffRequested:
|
|
145
|
-
send:
|
|
161
|
+
citations: f,
|
|
162
|
+
handoffRequested: p,
|
|
163
|
+
send: w,
|
|
146
164
|
reset: x,
|
|
147
|
-
abort:
|
|
165
|
+
abort: I
|
|
148
166
|
};
|
|
149
167
|
}
|
|
150
|
-
const
|
|
168
|
+
const G = {
|
|
151
169
|
class: "seer-chat",
|
|
152
170
|
"aria-label": "多发货 AI 客服聊天"
|
|
153
|
-
},
|
|
171
|
+
}, K = { class: "seer-chat__header" }, U = {
|
|
154
172
|
class: "seer-chat__messages",
|
|
155
173
|
"aria-live": "polite"
|
|
156
|
-
},
|
|
174
|
+
}, W = {
|
|
157
175
|
key: 0,
|
|
158
176
|
class: "seer-chat__empty"
|
|
159
177
|
}, H = { class: "seer-chat__role" }, Q = {
|
|
@@ -169,7 +187,7 @@ const K = {
|
|
|
169
187
|
}, Z = {
|
|
170
188
|
key: 3,
|
|
171
189
|
class: "seer-chat__citations"
|
|
172
|
-
}, ee = ["placeholder", "disabled"], te = { class: "seer-chat__actions" }, ne = ["disabled"], se = /* @__PURE__ */
|
|
190
|
+
}, ee = ["placeholder", "disabled"], te = { class: "seer-chat__actions" }, ne = ["disabled"], se = /* @__PURE__ */ M({
|
|
173
191
|
__name: "SeerChat",
|
|
174
192
|
props: {
|
|
175
193
|
endpoint: {},
|
|
@@ -180,20 +198,20 @@ const K = {
|
|
|
180
198
|
placeholder: { default: "输入你的问题,例如:美国海派怎么报价?" }
|
|
181
199
|
},
|
|
182
200
|
setup(n) {
|
|
183
|
-
const t = n, e =
|
|
201
|
+
const t = n, e = y(""), s = L({
|
|
184
202
|
endpoint: t.endpoint,
|
|
185
203
|
model: t.model,
|
|
186
204
|
stream: t.stream,
|
|
187
205
|
fetcher: t.fetcher
|
|
188
|
-
}),
|
|
189
|
-
async function
|
|
190
|
-
if (!
|
|
206
|
+
}), c = N(() => e.value.trim().length > 0 && !s.loading.value);
|
|
207
|
+
async function l() {
|
|
208
|
+
if (!c.value)
|
|
191
209
|
return;
|
|
192
|
-
const
|
|
193
|
-
e.value = "", await s.send(
|
|
210
|
+
const r = e.value;
|
|
211
|
+
e.value = "", await s.send(r);
|
|
194
212
|
}
|
|
195
|
-
return (
|
|
196
|
-
u("header",
|
|
213
|
+
return (r, a) => (m(), v("section", G, [
|
|
214
|
+
u("header", K, [
|
|
197
215
|
u("div", null, [
|
|
198
216
|
u("h2", null, S(n.title), 1),
|
|
199
217
|
a[3] || (a[3] = u("p", null, "可咨询渠道报价、时效、下单资料、入仓和售后问题。", -1))
|
|
@@ -201,31 +219,31 @@ const K = {
|
|
|
201
219
|
u("button", {
|
|
202
220
|
type: "button",
|
|
203
221
|
class: "seer-chat__ghost-button",
|
|
204
|
-
onClick: a[0] || (a[0] = (o) =>
|
|
222
|
+
onClick: a[0] || (a[0] = (o) => h(s).reset())
|
|
205
223
|
}, "清空")
|
|
206
224
|
]),
|
|
207
|
-
u("div",
|
|
208
|
-
|
|
209
|
-
(
|
|
210
|
-
key: `${o.role}-${
|
|
211
|
-
class:
|
|
225
|
+
u("div", U, [
|
|
226
|
+
h(s).messages.value.length === 0 ? (m(), v("p", W, " 直接输入问题即可,复杂查单或赔付问题会提示转人工。 ")) : b("", !0),
|
|
227
|
+
(m(!0), v(j, null, O(h(s).messages.value, (o, f) => (m(), v("article", {
|
|
228
|
+
key: `${o.role}-${f}`,
|
|
229
|
+
class: B(["seer-chat__message", `seer-chat__message--${o.role}`])
|
|
212
230
|
}, [
|
|
213
231
|
u("span", H, S(o.role === "user" ? "你" : "AI 客服"), 1),
|
|
214
232
|
u("p", null, S(o.content), 1)
|
|
215
233
|
], 2))), 128))
|
|
216
234
|
]),
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
235
|
+
h(s).loading.value ? (m(), v("p", Q, "正在回复...")) : b("", !0),
|
|
236
|
+
h(s).error.value ? (m(), v("p", X, S(h(s).error.value), 1)) : b("", !0),
|
|
237
|
+
h(s).handoffRequested.value ? (m(), v("p", Y, " 建议转人工:请留下联系方式或等待客服接入。 ")) : b("", !0),
|
|
238
|
+
h(s).citations.value.length > 0 ? (m(), v("footer", Z, [
|
|
221
239
|
a[4] || (a[4] = u("span", null, "参考资料", -1)),
|
|
222
240
|
u("ul", null, [
|
|
223
|
-
(
|
|
241
|
+
(m(!0), v(j, null, O(h(s).citations.value, (o) => (m(), v("li", { key: o }, S(o), 1))), 128))
|
|
224
242
|
])
|
|
225
243
|
])) : b("", !0),
|
|
226
244
|
u("form", {
|
|
227
245
|
class: "seer-chat__form",
|
|
228
|
-
onSubmit:
|
|
246
|
+
onSubmit: D(l, ["prevent"])
|
|
229
247
|
}, [
|
|
230
248
|
a[5] || (a[5] = u("label", {
|
|
231
249
|
class: "seer-chat__label",
|
|
@@ -235,21 +253,21 @@ const K = {
|
|
|
235
253
|
id: "seer-chat-input",
|
|
236
254
|
"onUpdate:modelValue": a[1] || (a[1] = (o) => e.value = o),
|
|
237
255
|
placeholder: n.placeholder,
|
|
238
|
-
disabled:
|
|
256
|
+
disabled: h(s).loading.value,
|
|
239
257
|
rows: "3"
|
|
240
258
|
}, null, 8, ee), [
|
|
241
259
|
[P, e.value]
|
|
242
260
|
]),
|
|
243
261
|
u("div", te, [
|
|
244
|
-
|
|
262
|
+
h(s).loading.value ? (m(), v("button", {
|
|
245
263
|
key: 0,
|
|
246
264
|
type: "button",
|
|
247
265
|
class: "seer-chat__ghost-button",
|
|
248
|
-
onClick: a[2] || (a[2] = (o) =>
|
|
266
|
+
onClick: a[2] || (a[2] = (o) => h(s).abort())
|
|
249
267
|
}, " 停止 ")) : b("", !0),
|
|
250
268
|
u("button", {
|
|
251
269
|
type: "submit",
|
|
252
|
-
disabled: !
|
|
270
|
+
disabled: !c.value
|
|
253
271
|
}, "发送", 8, ne)
|
|
254
272
|
])
|
|
255
273
|
], 32)
|
|
@@ -257,13 +275,13 @@ const K = {
|
|
|
257
275
|
}
|
|
258
276
|
}), ae = (n, t) => {
|
|
259
277
|
const e = n.__vccOpts || n;
|
|
260
|
-
for (const [s,
|
|
261
|
-
e[s] =
|
|
278
|
+
for (const [s, c] of t)
|
|
279
|
+
e[s] = c;
|
|
262
280
|
return e;
|
|
263
|
-
},
|
|
281
|
+
}, ie = /* @__PURE__ */ ae(se, [["__scopeId", "data-v-51cf8455"]]);
|
|
264
282
|
export {
|
|
265
|
-
|
|
283
|
+
ie as SeerChat,
|
|
266
284
|
re as SeerChatPlugin,
|
|
267
285
|
V as createSeerClient,
|
|
268
|
-
|
|
286
|
+
L as useSeerChat
|
|
269
287
|
};
|