@seer-ai/seer-vue 0.1.0-beta.1 → 0.1.0-beta.3
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.css +1 -1
- package/dist/index.js +128 -119
- 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.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
.seer-chat[data-v-
|
|
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}
|
package/dist/index.js
CHANGED
|
@@ -1,71 +1,88 @@
|
|
|
1
|
-
import { hasInjectionContext as
|
|
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
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(), m = {
|
|
8
|
+
"Content-Type": "application/json"
|
|
9
|
+
};
|
|
10
|
+
f && (m.Authorization = `Bearer ${f}`);
|
|
11
|
+
const d = await t(n.endpoint, {
|
|
7
12
|
method: "POST",
|
|
8
|
-
headers:
|
|
9
|
-
|
|
10
|
-
},
|
|
11
|
-
signal: i.signal,
|
|
13
|
+
headers: m,
|
|
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 j(d));
|
|
25
|
+
if (o)
|
|
26
|
+
return z(d, a.onDelta);
|
|
27
|
+
const y = await d.json();
|
|
28
|
+
return O(y);
|
|
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 j(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 O(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 m, d, y;
|
|
42
59
|
if (!n.body)
|
|
43
|
-
return
|
|
60
|
+
return O({});
|
|
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 S = c.split(`
|
|
52
69
|
|
|
53
70
|
`);
|
|
54
|
-
|
|
55
|
-
for (const
|
|
56
|
-
const
|
|
57
|
-
if (!
|
|
71
|
+
c = S.pop() ?? "";
|
|
72
|
+
for (const C of S) {
|
|
73
|
+
const b = J(C);
|
|
74
|
+
if (!b || b === "[DONE]")
|
|
58
75
|
continue;
|
|
59
|
-
const
|
|
60
|
-
|
|
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;
|
|
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 j(n) {
|
|
78
95
|
let t = n.statusText || "unknown error";
|
|
79
96
|
try {
|
|
80
97
|
const e = await n.json();
|
|
@@ -85,75 +102,76 @@ async function L(n) {
|
|
|
85
102
|
}
|
|
86
103
|
return `seer chat request failed with status ${n.status}: ${t}`;
|
|
87
104
|
}
|
|
88
|
-
const
|
|
105
|
+
const R = Symbol("seer-chat-options"), oe = {
|
|
89
106
|
install(n, t) {
|
|
90
|
-
n.provide(
|
|
107
|
+
n.provide(R, t);
|
|
91
108
|
}
|
|
92
109
|
};
|
|
93
|
-
function
|
|
94
|
-
const e = { ...
|
|
110
|
+
function L(n = {}) {
|
|
111
|
+
const e = { ...T() ? $(R, 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
|
|
104
|
-
const
|
|
105
|
-
if (!
|
|
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)
|
|
106
124
|
return;
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
const
|
|
110
|
-
e.stream && (
|
|
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, _]);
|
|
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, m.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 = [], m.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: m,
|
|
163
|
+
send: y,
|
|
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 = {
|
|
@@ -166,10 +184,7 @@ const K = {
|
|
|
166
184
|
}, Y = {
|
|
167
185
|
key: 2,
|
|
168
186
|
class: "seer-chat__handoff"
|
|
169
|
-
}, Z = {
|
|
170
|
-
key: 3,
|
|
171
|
-
class: "seer-chat__citations"
|
|
172
|
-
}, ee = ["placeholder", "disabled"], te = { class: "seer-chat__actions" }, ne = ["disabled"], se = /* @__PURE__ */ N({
|
|
187
|
+
}, Z = ["placeholder", "disabled"], ee = { class: "seer-chat__actions" }, te = ["disabled"], ne = /* @__PURE__ */ A({
|
|
173
188
|
__name: "SeerChat",
|
|
174
189
|
props: {
|
|
175
190
|
endpoint: {},
|
|
@@ -180,54 +195,48 @@ const K = {
|
|
|
180
195
|
placeholder: { default: "输入你的问题,例如:美国海派怎么报价?" }
|
|
181
196
|
},
|
|
182
197
|
setup(n) {
|
|
183
|
-
const t = n, e =
|
|
198
|
+
const t = n, e = w(""), s = L({
|
|
184
199
|
endpoint: t.endpoint,
|
|
185
200
|
model: t.model,
|
|
186
201
|
stream: t.stream,
|
|
187
202
|
fetcher: t.fetcher
|
|
188
|
-
}),
|
|
189
|
-
async function
|
|
190
|
-
if (!
|
|
203
|
+
}), c = q(() => e.value.trim().length > 0 && !s.loading.value);
|
|
204
|
+
async function l() {
|
|
205
|
+
if (!c.value)
|
|
191
206
|
return;
|
|
192
|
-
const
|
|
193
|
-
e.value = "", await s.send(
|
|
207
|
+
const r = e.value;
|
|
208
|
+
e.value = "", await s.send(r);
|
|
194
209
|
}
|
|
195
|
-
return (
|
|
196
|
-
u("header",
|
|
210
|
+
return (r, a) => (v(), p("section", G, [
|
|
211
|
+
u("header", K, [
|
|
197
212
|
u("div", null, [
|
|
198
|
-
u("h2", null,
|
|
213
|
+
u("h2", null, E(n.title), 1),
|
|
199
214
|
a[3] || (a[3] = u("p", null, "可咨询渠道报价、时效、下单资料、入仓和售后问题。", -1))
|
|
200
215
|
]),
|
|
201
216
|
u("button", {
|
|
202
217
|
type: "button",
|
|
203
218
|
class: "seer-chat__ghost-button",
|
|
204
|
-
onClick: a[0] || (a[0] = (o) =>
|
|
219
|
+
onClick: a[0] || (a[0] = (o) => h(s).reset())
|
|
205
220
|
}, "清空")
|
|
206
221
|
]),
|
|
207
|
-
u("div",
|
|
208
|
-
|
|
209
|
-
(
|
|
210
|
-
key: `${o.role}-${
|
|
211
|
-
class:
|
|
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}`])
|
|
212
227
|
}, [
|
|
213
|
-
u("span", H,
|
|
214
|
-
u("p", null,
|
|
228
|
+
u("span", H, E(o.role === "user" ? "你" : "AI 客服"), 1),
|
|
229
|
+
u("p", null, E(o.content), 1)
|
|
215
230
|
], 2))), 128))
|
|
216
231
|
]),
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
d(s).citations.value.length > 0 ? (f(), h("footer", Z, [
|
|
221
|
-
a[4] || (a[4] = u("span", null, "参考资料", -1)),
|
|
222
|
-
u("ul", null, [
|
|
223
|
-
(f(!0), h(R, null, j(d(s).citations.value, (o) => (f(), h("li", { key: o }, S(o), 1))), 128))
|
|
224
|
-
])
|
|
225
|
-
])) : b("", !0),
|
|
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),
|
|
226
235
|
u("form", {
|
|
227
236
|
class: "seer-chat__form",
|
|
228
|
-
onSubmit:
|
|
237
|
+
onSubmit: D(l, ["prevent"])
|
|
229
238
|
}, [
|
|
230
|
-
a[
|
|
239
|
+
a[4] || (a[4] = u("label", {
|
|
231
240
|
class: "seer-chat__label",
|
|
232
241
|
for: "seer-chat-input"
|
|
233
242
|
}, "问题", -1)),
|
|
@@ -235,35 +244,35 @@ const K = {
|
|
|
235
244
|
id: "seer-chat-input",
|
|
236
245
|
"onUpdate:modelValue": a[1] || (a[1] = (o) => e.value = o),
|
|
237
246
|
placeholder: n.placeholder,
|
|
238
|
-
disabled:
|
|
247
|
+
disabled: h(s).loading.value,
|
|
239
248
|
rows: "3"
|
|
240
|
-
}, null, 8,
|
|
249
|
+
}, null, 8, Z), [
|
|
241
250
|
[P, e.value]
|
|
242
251
|
]),
|
|
243
|
-
u("div",
|
|
244
|
-
|
|
252
|
+
u("div", ee, [
|
|
253
|
+
h(s).loading.value ? (v(), p("button", {
|
|
245
254
|
key: 0,
|
|
246
255
|
type: "button",
|
|
247
256
|
class: "seer-chat__ghost-button",
|
|
248
|
-
onClick: a[2] || (a[2] = (o) =>
|
|
249
|
-
}, " 停止 ")) :
|
|
257
|
+
onClick: a[2] || (a[2] = (o) => h(s).abort())
|
|
258
|
+
}, " 停止 ")) : k("", !0),
|
|
250
259
|
u("button", {
|
|
251
260
|
type: "submit",
|
|
252
|
-
disabled: !
|
|
253
|
-
}, "发送", 8,
|
|
261
|
+
disabled: !c.value
|
|
262
|
+
}, "发送", 8, te)
|
|
254
263
|
])
|
|
255
264
|
], 32)
|
|
256
265
|
]));
|
|
257
266
|
}
|
|
258
|
-
}),
|
|
267
|
+
}), se = (n, t) => {
|
|
259
268
|
const e = n.__vccOpts || n;
|
|
260
|
-
for (const [s,
|
|
261
|
-
e[s] =
|
|
269
|
+
for (const [s, c] of t)
|
|
270
|
+
e[s] = c;
|
|
262
271
|
return e;
|
|
263
|
-
},
|
|
272
|
+
}, re = /* @__PURE__ */ se(ne, [["__scopeId", "data-v-163bc07c"]]);
|
|
264
273
|
export {
|
|
265
|
-
|
|
266
|
-
|
|
274
|
+
re as SeerChat,
|
|
275
|
+
oe as SeerChatPlugin,
|
|
267
276
|
V as createSeerClient,
|
|
268
|
-
|
|
277
|
+
L as useSeerChat
|
|
269
278
|
};
|