@seer-ai/seer-vue 0.1.0-beta.7 → 0.1.0-beta.8
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 +15 -0
- package/dist/client.d.ts +4 -0
- package/dist/components/SeerChat.vue.d.ts +1 -0
- package/dist/index.css +1 -1
- package/dist/index.js +94 -100
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -41,6 +41,21 @@ import { SeerChat } from '@seer-ai/seer-vue'
|
|
|
41
41
|
60 秒;SenseVoice 转写结果只回填输入框,不会自动发送。标准 browser chat endpoint 会自动
|
|
42
42
|
推导 transcription endpoint,也可显式配置;传 `voiceEnabled: false` 可关闭话筒。
|
|
43
43
|
|
|
44
|
+
## Logged-in customer (`orgOwner`)
|
|
45
|
+
|
|
46
|
+
传入已登录用户的多发货 `orgOwner`,询价时 seer 直接用它当客户编码,不再追问。登录态会变时传函数;
|
|
47
|
+
值变化后插件自动重新建会话。也可以用组件 prop:`<SeerChat :org-owner="user?.orgOwner" />`。
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
app.use(SeerChatPlugin, {
|
|
51
|
+
sessionEndpoint: 'https://seer.example.com/v1/browser/session',
|
|
52
|
+
endpoint: 'https://seer.example.com/v1/browser/chat/completions',
|
|
53
|
+
orgOwner: () => currentUser.value?.orgOwner,
|
|
54
|
+
})
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
插件在建会话时发 `X-Seer-Org-Owner`。seer 不校验这个值,只用于补报价客户编码,不参与订单归属。
|
|
58
|
+
|
|
44
59
|
## Use custom UI
|
|
45
60
|
|
|
46
61
|
自定义 UI 时**不要**直接把 `message.content` 当纯文本渲染——回复里的下载/截图链接是裸
|
package/dist/client.d.ts
CHANGED
|
@@ -4,11 +4,14 @@ export interface SeerChatMessage {
|
|
|
4
4
|
content: string;
|
|
5
5
|
name?: string;
|
|
6
6
|
}
|
|
7
|
+
export type SeerOrgOwner = string | (() => string | undefined);
|
|
7
8
|
export interface SeerClientOptions {
|
|
8
9
|
endpoint: string;
|
|
9
10
|
sessionEndpoint?: string;
|
|
10
11
|
transcriptionEndpoint?: string;
|
|
11
12
|
challengeTokenProvider?: () => Promise<string>;
|
|
13
|
+
/** 已登录用户的多发货 orgOwner;报价时自动当作客户编码。登录态会变时传函数。 */
|
|
14
|
+
orgOwner?: SeerOrgOwner;
|
|
12
15
|
model?: string;
|
|
13
16
|
fetcher?: typeof fetch;
|
|
14
17
|
now?: () => number;
|
|
@@ -43,3 +46,4 @@ export interface SeerClient {
|
|
|
43
46
|
transcribe(audio: Blob, filename: string, callbacks?: SeerTranscriptionCallbacks): Promise<SeerTranscriptionResult>;
|
|
44
47
|
}
|
|
45
48
|
export declare function createSeerClient(options: SeerClientOptions): SeerClient;
|
|
49
|
+
export declare function resolveOrgOwner(orgOwner: SeerOrgOwner | undefined): string | undefined;
|
package/dist/index.css
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
.seer-chat[data-v-
|
|
1
|
+
.seer-chat[data-v-b64d9d8e]{color:#18212f;background:radial-gradient(circle at 18% 0,#476aff24,#0000 32%),linear-gradient(#fff 0%,#f7f9fd 100%);border:1px solid #7f8faa47;border-radius:28px;gap:18px;max-width:720px;min-height:640px;padding:0;display:grid;overflow:hidden;box-shadow:0 24px 70px #151f3429}.seer-chat__header[data-v-b64d9d8e]{color:#fff;background:linear-gradient(135deg,#141f34f5,#243f76f0),#172033;justify-content:space-between;align-items:flex-start;gap:16px;padding:22px 22px 18px;display:flex}.seer-chat__header h2[data-v-b64d9d8e]{letter-spacing:-.03em;margin:0;font-size:22px}.seer-chat__header p[data-v-b64d9d8e],.seer-chat__empty[data-v-b64d9d8e],.seer-chat__status[data-v-b64d9d8e]{color:#5f6f89;margin:4px 0 0;font-size:14px}.seer-chat__header p[data-v-b64d9d8e]{color:#ffffffb8;max-width:34ch}.seer-chat__messages[data-v-b64d9d8e]{align-content:start;gap:12px;min-height:330px;max-height:470px;padding:18px 18px 4px;display:grid;overflow-y:auto}.seer-chat__empty[data-v-b64d9d8e]{color:#66748a;text-align:center;background:#ffffff9e;border:1px dashed #7f8faa61;border-radius:22px;place-items:center;min-height:260px;padding:0 28px;display:grid}.seer-chat__message[data-v-b64d9d8e]{background:#ffffffe0;border:1px solid #7f8faa29;border-radius:18px 18px 18px 6px;gap:6px;max-width:min(86%,520px);padding:13px 15px;display:grid;box-shadow:0 12px 28px #151f3414}.seer-chat__message--user[data-v-b64d9d8e]{color:#fff;background:linear-gradient(135deg,#285cff,#1d45c9);border-color:#0000;border-radius:18px 18px 6px;justify-self:end;box-shadow:0 14px 30px #1f5eff3d}.seer-chat__role[data-v-b64d9d8e]{opacity:.75;font-size:12px;font-weight:700}.seer-chat__body[data-v-b64d9d8e]{flex-direction:column;display:flex}.seer-chat__line[data-v-b64d9d8e]{white-space:pre-wrap;overflow-wrap:anywhere;margin:0}.seer-chat__line[data-v-b64d9d8e]:not(:last-child){margin-bottom:5px}.seer-chat__line[data-v-b64d9d8e]:empty{height:7px}.seer-chat__strong[data-v-b64d9d8e]{font-weight:700}.seer-chat__price[data-v-b64d9d8e]{color:#e0331d;font-weight:600}.seer-chat__message--user .seer-chat__price[data-v-b64d9d8e]{color:#ffe2dc}.seer-chat__link[data-v-b64d9d8e]{color:#1f5eff;text-underline-offset:2px;overflow-wrap:anywhere;font-weight:600;text-decoration:underline}.seer-chat__link[data-v-b64d9d8e]:hover{color:#173fb3}.seer-chat__message--user .seer-chat__link[data-v-b64d9d8e]{color:#fff}.seer-chat__image-button[data-v-b64d9d8e]{cursor:zoom-in;background:0 0;border:0;padding:0;display:block}.seer-chat__image-button[data-v-b64d9d8e]:not(:disabled):hover{transform:none}.seer-chat__image[data-v-b64d9d8e]{border:1px solid #7f8faa38;border-radius:12px;max-width:100%;margin:6px 0;transition:filter .16s;display:block}.seer-chat__image-button:hover .seer-chat__image[data-v-b64d9d8e]{filter:brightness(.96)}.seer-chat__lightbox[data-v-b64d9d8e]{z-index:1000;cursor:zoom-out;background:#0a0f1ad1;place-items:center;padding:32px;animation:.14s seer-chat__fade-in-b64d9d8e;display:grid;position:fixed;inset:0}.seer-chat__lightbox-image[data-v-b64d9d8e]{object-fit:contain;border-radius:12px;max-width:min(92vw,1200px);max-height:90vh;box-shadow:0 30px 80px #00000080}.seer-chat__lightbox-close[data-v-b64d9d8e]{color:#fff;background:#ffffff24;border-radius:50%;place-items:center;width:40px;height:40px;font-size:26px;line-height:1;display:grid;position:fixed;top:18px;right:22px}.seer-chat__lightbox-close[data-v-b64d9d8e]:not(:disabled):hover{background:#ffffff3d}@keyframes seer-chat__fade-in-b64d9d8e{0%{opacity:0}to{opacity:1}}.seer-chat__error[data-v-b64d9d8e],.seer-chat__handoff[data-v-b64d9d8e]{border-radius:14px;margin:0 18px;padding:10px 12px}.seer-chat__error[data-v-b64d9d8e]{color:#8a1f11;background:#fff0ed}.seer-chat__handoff[data-v-b64d9d8e]{color:#704600;background:#fff7db}.seer-chat__form[data-v-b64d9d8e]{background:#fff;border:1px solid #7f8faa42;border-radius:22px;gap:11px;margin:0 18px 18px;padding:14px;display:grid;box-shadow:0 18px 38px #151f3417}.seer-chat__label[data-v-b64d9d8e]{font-size:13px;font-weight:700}.seer-chat textarea[data-v-b64d9d8e]{box-sizing:border-box;width:100%;min-height:92px;color:inherit;resize:vertical;background:#f8fafd;border:1px solid #0000;border-radius:16px;outline:none;padding:14px;line-height:1.55;transition:background .16s,border-color .16s,box-shadow .16s}.seer-chat button[data-v-b64d9d8e]{color:inherit;cursor:pointer;border:0;font-weight:700;transition:transform .16s,box-shadow .16s,opacity .16s}.seer-chat button[data-v-b64d9d8e]:not(:disabled):hover{transform:translateY(-1px)}.seer-chat button[data-v-b64d9d8e]:disabled{cursor:not-allowed;opacity:.5}.seer-chat button[data-v-b64d9d8e]:focus-visible,.seer-chat textarea[data-v-b64d9d8e]:focus-visible{border-color:#1f5eff6b;box-shadow:0 0 0 4px #1f5eff21}.seer-chat__clear-button[data-v-b64d9d8e]{color:#ffffffc7;background:0 0;border-radius:12px;flex:none;padding:8px 11px;font-size:12px;border:1px solid #ffffff2e!important}.seer-chat__clear-button[data-v-b64d9d8e]:not(:disabled):hover{color:#fff;box-shadow:none;background:#ffffff1a}.seer-chat__stop-button[data-v-b64d9d8e]{color:#6c3b12;background:#fff1df;border-radius:12px;padding:8px 11px;font-size:12px}.seer-chat__mic-button[data-v-b64d9d8e]{color:#285cff;background:#edf2ff;border-radius:50%;flex:none;place-items:center;width:40px;height:40px;padding:0;display:grid}.seer-chat__mic-button[data-v-b64d9d8e]:not(:disabled):hover{background:#dfe8ff}.seer-chat__mic-button--recording[data-v-b64d9d8e]{color:#fff;background:#d9342b;animation:1.4s ease-in-out infinite seer-chat__recording-pulse-b64d9d8e;box-shadow:0 0 0 5px #d9342b24}.seer-chat__mic-button--recording[data-v-b64d9d8e]:not(:disabled):hover{background:#bd271f}.seer-chat__stop-icon[data-v-b64d9d8e]{background:currentColor;border-radius:3px;width:12px;height:12px}@keyframes seer-chat__recording-pulse-b64d9d8e{50%{box-shadow:0 0 0 9px #d9342b14}}.seer-chat__send-button[data-v-b64d9d8e]{color:#fff;background:linear-gradient(135deg,#1f5eff,#173fb3);border-radius:14px;justify-content:center;align-items:center;gap:8px;min-width:86px;padding:10px 14px;display:inline-flex;box-shadow:0 12px 24px #1f5eff38}.seer-chat__send-button[data-v-b64d9d8e]:not(:disabled):hover{box-shadow:0 14px 28px #1f5eff47}.seer-chat__hint[data-v-b64d9d8e]{color:#7a879a;margin-right:auto;font-size:12px}.seer-chat__composer-footer[data-v-b64d9d8e]{justify-content:flex-end;align-items:center;gap:8px;display:flex}
|
|
2
2
|
/*$vite$:1*/
|
package/dist/index.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { Fragment as e, computed as t, createCommentVNode as n, createElementBlock as r, createElementVNode as i, defineComponent as a, hasInjectionContext as o, inject as s, normalizeClass as c, onBeforeUnmount as l, openBlock as u, ref as d, renderList as f, toDisplayString as p, unref as m, vModelText as h, withDirectives as g, withKeys as _, withModifiers as v } from "vue";
|
|
2
|
-
|
|
2
|
+
// src/client.ts
|
|
3
3
|
function y(e) {
|
|
4
|
-
let t = e.fetcher ?? fetch, n = e.model ?? "seer", r =
|
|
4
|
+
let t = e.fetcher ?? fetch, n = e.model ?? "seer", r = x(e), i = e.now ?? (() => Math.floor(Date.now() / 1e3)), a, o = 0, s;
|
|
5
5
|
return {
|
|
6
6
|
transcriptionEnabled: !!r,
|
|
7
7
|
async chat(r, i = {}) {
|
|
8
|
-
let a = r.stream ?? !1, o = await
|
|
9
|
-
o && (
|
|
8
|
+
let a = r.stream ?? !1, o = await c(), s = { "Content-Type": "application/json" };
|
|
9
|
+
o && (s.Authorization = `Bearer ${o}`);
|
|
10
10
|
let l = await t(e.endpoint, {
|
|
11
11
|
method: "POST",
|
|
12
|
-
headers:
|
|
12
|
+
headers: s,
|
|
13
13
|
signal: i.signal,
|
|
14
14
|
body: JSON.stringify({
|
|
15
15
|
model: r.model ?? n,
|
|
@@ -19,49 +19,52 @@ function y(e) {
|
|
|
19
19
|
metadata: r.metadata
|
|
20
20
|
})
|
|
21
21
|
});
|
|
22
|
-
if (!l.ok) throw Error(await
|
|
23
|
-
return a ?
|
|
22
|
+
if (!l.ok) throw Error(await T(l));
|
|
23
|
+
return a ? C(l, i.onDelta) : S(await l.json());
|
|
24
24
|
},
|
|
25
25
|
async transcribe(e, n, i = {}) {
|
|
26
26
|
if (!r) throw Error("Seer audio transcription endpoint is not configured");
|
|
27
|
-
let a = await
|
|
27
|
+
let a = await c(), o = {};
|
|
28
28
|
a && (o.Authorization = `Bearer ${a}`);
|
|
29
|
-
let
|
|
30
|
-
|
|
29
|
+
let s = new FormData();
|
|
30
|
+
s.append("file", e, n);
|
|
31
31
|
let l = await t(r, {
|
|
32
32
|
method: "POST",
|
|
33
33
|
headers: o,
|
|
34
34
|
signal: i.signal,
|
|
35
|
-
body:
|
|
35
|
+
body: s
|
|
36
36
|
});
|
|
37
|
-
if (!l.ok) throw Error(await
|
|
37
|
+
if (!l.ok) throw Error(await T(l));
|
|
38
38
|
let u = await l.json(), d = typeof u.text == "string" ? u.text.trim() : "";
|
|
39
39
|
if (!d) throw Error("Seer audio transcription returned empty text");
|
|
40
40
|
return { text: d };
|
|
41
41
|
}
|
|
42
42
|
};
|
|
43
|
-
async function
|
|
43
|
+
async function c() {
|
|
44
44
|
if (!e.sessionEndpoint) return;
|
|
45
|
-
let n = i();
|
|
46
|
-
if (a && o - 30 > n) return a;
|
|
47
|
-
let
|
|
45
|
+
let n = i(), r = b(e.orgOwner);
|
|
46
|
+
if (a && s === r && o - 30 > n) return a;
|
|
47
|
+
let c = await t(e.sessionEndpoint, {
|
|
48
48
|
method: "GET",
|
|
49
|
-
headers: await
|
|
49
|
+
headers: await l(r)
|
|
50
50
|
});
|
|
51
|
-
if (!
|
|
52
|
-
let
|
|
53
|
-
return a =
|
|
51
|
+
if (!c.ok) throw Error(await T(c));
|
|
52
|
+
let u = await c.json();
|
|
53
|
+
return a = u.token, o = u.expires_at, s = r, a;
|
|
54
54
|
}
|
|
55
|
-
async function
|
|
56
|
-
let
|
|
57
|
-
return e.challengeTokenProvider && (
|
|
55
|
+
async function l(t) {
|
|
56
|
+
let n = {};
|
|
57
|
+
return e.challengeTokenProvider && (n["X-Seer-Challenge-Token"] = await e.challengeTokenProvider()), t && (n["X-Seer-Org-Owner"] = t), n;
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
function b(e) {
|
|
61
|
+
return (typeof e == "function" ? e() : e)?.trim() || void 0;
|
|
62
|
+
}
|
|
63
|
+
function x(e) {
|
|
61
64
|
if (e.transcriptionEndpoint !== void 0) return e.transcriptionEndpoint || void 0;
|
|
62
65
|
if (e.endpoint.endsWith("/v1/browser/chat/completions")) return `${e.endpoint.slice(0, -28)}/v1/browser/audio/transcriptions`;
|
|
63
66
|
}
|
|
64
|
-
function
|
|
67
|
+
function S(e) {
|
|
65
68
|
let t = e.choices?.[0];
|
|
66
69
|
return {
|
|
67
70
|
content: t?.message?.content ?? t?.delta?.content ?? "",
|
|
@@ -71,8 +74,8 @@ function x(e) {
|
|
|
71
74
|
finishReason: t?.finish_reason
|
|
72
75
|
};
|
|
73
76
|
}
|
|
74
|
-
async function
|
|
75
|
-
if (!e.body) return
|
|
77
|
+
async function C(e, t) {
|
|
78
|
+
if (!e.body) return S({});
|
|
76
79
|
let n = e.body.getReader(), r = new TextDecoder(), i = "", a = "", o, s = [], c = !1, l, u = !1;
|
|
77
80
|
for (;;) {
|
|
78
81
|
let { done: e, value: d } = await n.read();
|
|
@@ -81,7 +84,7 @@ async function S(e, t) {
|
|
|
81
84
|
let f = i.split("\n\n");
|
|
82
85
|
i = f.pop() ?? "";
|
|
83
86
|
for (let e of f) {
|
|
84
|
-
let n =
|
|
87
|
+
let n = w(e);
|
|
85
88
|
if (!n) continue;
|
|
86
89
|
if (n === "[DONE]") {
|
|
87
90
|
u = !0;
|
|
@@ -100,11 +103,11 @@ async function S(e, t) {
|
|
|
100
103
|
finishReason: l
|
|
101
104
|
};
|
|
102
105
|
}
|
|
103
|
-
function
|
|
106
|
+
function w(e) {
|
|
104
107
|
let t = e.split("\n").map((e) => e.trim()).filter((e) => e.startsWith("data:")).map((e) => e.slice(5).trim());
|
|
105
108
|
return t.length === 0 ? null : t.join("\n");
|
|
106
109
|
}
|
|
107
|
-
async function
|
|
110
|
+
async function T(e) {
|
|
108
111
|
let t = e.statusText || "unknown error";
|
|
109
112
|
try {
|
|
110
113
|
let n = await e.json();
|
|
@@ -115,14 +118,13 @@ async function w(e) {
|
|
|
115
118
|
}
|
|
116
119
|
return `seer chat request failed with status ${e.status}: ${t}`;
|
|
117
120
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
function O(e) {
|
|
121
|
+
// src/content.ts
|
|
122
|
+
var E = /https?:\/\/[^\s)]+/g, D = /\.(png|jpe?g|gif|webp|bmp|svg)$/i, O = /* @__PURE__ */ RegExp("(单价\\s*\\d[\\d.]*\\s*[A-Za-z]+\\/kg)|(按当前信息为您筛选出[^\\n:]*推荐方案[^\\n:]*:)|(方案PK|时效最快|价格最低)", "g");
|
|
123
|
+
function k(e) {
|
|
122
124
|
let t = [];
|
|
123
|
-
|
|
125
|
+
O.lastIndex = 0;
|
|
124
126
|
let n = 0, r;
|
|
125
|
-
for (; (r =
|
|
127
|
+
for (; (r = O.exec(e)) !== null;) {
|
|
126
128
|
r.index > n && t.push({
|
|
127
129
|
kind: "text",
|
|
128
130
|
value: e.slice(n, r.index)
|
|
@@ -141,53 +143,51 @@ function O(e) {
|
|
|
141
143
|
value: e.slice(n)
|
|
142
144
|
}), t;
|
|
143
145
|
}
|
|
144
|
-
var
|
|
145
|
-
function
|
|
146
|
+
var A = /标签|箱唛|唛头|入库单|交接单|入仓单|面单|下载/;
|
|
147
|
+
function j(e, t) {
|
|
146
148
|
if (/方案|截图|报价图|效果图|示意图|图片/.test(t)) return !0;
|
|
147
|
-
if (
|
|
149
|
+
if (A.test(t)) return !1;
|
|
148
150
|
let n = e.split(/[?#]/)[0];
|
|
149
|
-
return
|
|
151
|
+
return D.test(n);
|
|
150
152
|
}
|
|
151
|
-
function
|
|
153
|
+
function M(e) {
|
|
152
154
|
return /方案|报价|截图|PK/.test(e) ? "方案PK" : "图片";
|
|
153
155
|
}
|
|
154
|
-
function
|
|
156
|
+
function N(e) {
|
|
155
157
|
return /标签|箱唛/.test(e) ? "点击下载箱唛" : /入库单|交接单/.test(e) ? "点击下载入库单" : /面单/.test(e) ? "点击下载面单" : /截图|方案/.test(e) ? "点击查看方案PK" : /下载链接|labelUrl|下载/.test(e) ? "点击下载" : /链接/.test(e) ? "点击查看" : null;
|
|
156
158
|
}
|
|
157
|
-
function
|
|
159
|
+
function P(e) {
|
|
158
160
|
let t = [];
|
|
159
|
-
|
|
161
|
+
E.lastIndex = 0;
|
|
160
162
|
let n = 0, r;
|
|
161
|
-
for (; (r =
|
|
162
|
-
let i = r[0], a = r.index, o = e.lastIndexOf("\n", a - 1) + 1, s = e.slice(o, a), c =
|
|
163
|
+
for (; (r = E.exec(e)) !== null;) {
|
|
164
|
+
let i = r[0], a = r.index, o = e.lastIndexOf("\n", a - 1) + 1, s = e.slice(o, a), c = j(i, s);
|
|
163
165
|
if (a > n) {
|
|
164
166
|
let r = e.slice(n, a);
|
|
165
|
-
c && (r = r.replace(/链接([::])\s*$/, "$1")), t.push(...
|
|
167
|
+
c && (r = r.replace(/链接([::])\s*$/, "$1")), t.push(...k(r));
|
|
166
168
|
}
|
|
167
169
|
c ? t.push({
|
|
168
170
|
kind: "image",
|
|
169
171
|
href: i,
|
|
170
|
-
alt:
|
|
172
|
+
alt: M(s)
|
|
171
173
|
}) : t.push({
|
|
172
174
|
kind: "link",
|
|
173
175
|
href: i,
|
|
174
|
-
label:
|
|
176
|
+
label: N(s) ?? i
|
|
175
177
|
}), n = a + i.length;
|
|
176
178
|
}
|
|
177
|
-
return n < e.length && t.push(...
|
|
179
|
+
return n < e.length && t.push(...k(e.slice(n))), t;
|
|
178
180
|
}
|
|
179
|
-
function
|
|
180
|
-
return e.split("\n").map((e) =>
|
|
181
|
+
function F(e) {
|
|
182
|
+
return e.split("\n").map((e) => P(e));
|
|
181
183
|
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
e.provide(F, t);
|
|
184
|
+
// src/plugin.ts
|
|
185
|
+
var I = Symbol("seer-chat-options"), L = { install(e, t) {
|
|
186
|
+
e.provide(I, t);
|
|
186
187
|
} };
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
let t = o() ? s(F, void 0) : void 0, n = Object.fromEntries(Object.entries(e).filter(([, e]) => e !== void 0)), r = {
|
|
188
|
+
// src/useSeerChat.ts
|
|
189
|
+
function R(e = {}) {
|
|
190
|
+
let t = o() ? s(I, void 0) : void 0, n = Object.fromEntries(Object.entries(e).filter(([, e]) => e !== void 0)), r = {
|
|
191
191
|
...t,
|
|
192
192
|
...n
|
|
193
193
|
};
|
|
@@ -197,6 +197,7 @@ function L(e = {}) {
|
|
|
197
197
|
sessionEndpoint: r.sessionEndpoint,
|
|
198
198
|
transcriptionEndpoint: r.transcriptionEndpoint,
|
|
199
199
|
challengeTokenProvider: r.challengeTokenProvider,
|
|
200
|
+
orgOwner: () => b(e.orgOwner) ?? b(t?.orgOwner),
|
|
200
201
|
model: r.model,
|
|
201
202
|
fetcher: r.fetcher
|
|
202
203
|
}), a = d([]), c = d(!1), l = d(null), u = d(), f = d([]), p = d(!1), m = r.voiceEnabled !== !1 && i.transcriptionEnabled, h = r.maxRecordingSeconds ?? 60, g = null;
|
|
@@ -237,7 +238,7 @@ function L(e = {}) {
|
|
|
237
238
|
function v() {
|
|
238
239
|
a.value = [], l.value = null, u.value = void 0, f.value = [], p.value = !1;
|
|
239
240
|
}
|
|
240
|
-
function
|
|
241
|
+
function x() {
|
|
241
242
|
g?.abort();
|
|
242
243
|
}
|
|
243
244
|
return {
|
|
@@ -252,11 +253,10 @@ function L(e = {}) {
|
|
|
252
253
|
transcribe: i.transcribe,
|
|
253
254
|
send: _,
|
|
254
255
|
reset: v,
|
|
255
|
-
abort:
|
|
256
|
+
abort: x
|
|
256
257
|
};
|
|
257
258
|
}
|
|
258
|
-
|
|
259
|
-
//#region src/components/SeerChat.vue?vue&type=script&setup=true&lang.ts
|
|
259
|
+
// src/components/SeerChat.vue?vue&type=script&setup=true&lang.ts
|
|
260
260
|
var ee = {
|
|
261
261
|
class: "seer-chat",
|
|
262
262
|
"aria-label": "多发货 AI 客服聊天"
|
|
@@ -266,23 +266,23 @@ var ee = {
|
|
|
266
266
|
}, re = {
|
|
267
267
|
key: 0,
|
|
268
268
|
class: "seer-chat__empty"
|
|
269
|
-
},
|
|
269
|
+
}, z = { class: "seer-chat__role" }, B = { class: "seer-chat__body" }, V = ["href"], H = ["aria-label", "onClick"], U = ["src", "alt"], W = {
|
|
270
270
|
key: 2,
|
|
271
271
|
class: "seer-chat__strong"
|
|
272
|
-
},
|
|
272
|
+
}, G = {
|
|
273
273
|
key: 3,
|
|
274
274
|
class: "seer-chat__price"
|
|
275
|
-
},
|
|
275
|
+
}, K = { key: 4 }, q = {
|
|
276
276
|
key: 0,
|
|
277
277
|
class: "seer-chat__status"
|
|
278
|
-
},
|
|
278
|
+
}, J = {
|
|
279
279
|
key: 1,
|
|
280
280
|
class: "seer-chat__error",
|
|
281
281
|
role: "alert"
|
|
282
|
-
},
|
|
282
|
+
}, Y = {
|
|
283
283
|
key: 2,
|
|
284
284
|
class: "seer-chat__handoff"
|
|
285
|
-
},
|
|
285
|
+
}, ie = [
|
|
286
286
|
"placeholder",
|
|
287
287
|
"disabled",
|
|
288
288
|
"onKeydown"
|
|
@@ -303,7 +303,7 @@ var ee = {
|
|
|
303
303
|
width: "20",
|
|
304
304
|
height: "20",
|
|
305
305
|
"aria-hidden": "true"
|
|
306
|
-
}, ue = ["disabled"], de = ["aria-label"], fe = ["src", "alt"],
|
|
306
|
+
}, ue = ["disabled"], de = ["aria-label"], fe = ["src", "alt"], X = /*#__PURE__*/ ((e, t) => {
|
|
307
307
|
let n = e.__vccOpts || e;
|
|
308
308
|
for (let [e, r] of t) n[e] = r;
|
|
309
309
|
return n;
|
|
@@ -313,6 +313,7 @@ var ee = {
|
|
|
313
313
|
endpoint: {},
|
|
314
314
|
sessionEndpoint: {},
|
|
315
315
|
transcriptionEndpoint: {},
|
|
316
|
+
orgOwner: {},
|
|
316
317
|
model: {},
|
|
317
318
|
stream: {
|
|
318
319
|
type: Boolean,
|
|
@@ -328,10 +329,11 @@ var ee = {
|
|
|
328
329
|
maxRecordingSeconds: {}
|
|
329
330
|
},
|
|
330
331
|
setup(a) {
|
|
331
|
-
let o = a, s = d(""), y = d(!1), b = d(!1), x = d(null), S =
|
|
332
|
+
let o = a, s = d(""), y = d(!1), b = d(!1), x = d(null), S = R({
|
|
332
333
|
endpoint: o.endpoint,
|
|
333
334
|
sessionEndpoint: o.sessionEndpoint,
|
|
334
335
|
transcriptionEndpoint: o.transcriptionEndpoint,
|
|
336
|
+
orgOwner: () => o.orgOwner,
|
|
335
337
|
model: o.model,
|
|
336
338
|
stream: o.stream,
|
|
337
339
|
fetcher: o.fetcher,
|
|
@@ -353,19 +355,15 @@ var ee = {
|
|
|
353
355
|
l(() => {
|
|
354
356
|
k = !0, window.removeEventListener("keydown", j), Q(), T && T.state !== "inactive" && (T.ondataavailable = null, T.onstop = null, T.onerror = null, T.stop()), $();
|
|
355
357
|
});
|
|
356
|
-
async function
|
|
358
|
+
async function P() {
|
|
357
359
|
if (!C.value) return;
|
|
358
360
|
let e = s.value;
|
|
359
361
|
s.value = "", await S.send(e);
|
|
360
362
|
}
|
|
361
363
|
async function I() {
|
|
362
|
-
|
|
363
|
-
X();
|
|
364
|
-
return;
|
|
365
|
-
}
|
|
366
|
-
await Y();
|
|
364
|
+
y.value ? X() : await L();
|
|
367
365
|
}
|
|
368
|
-
async function
|
|
366
|
+
async function L() {
|
|
369
367
|
if (!(!w.value || b.value || S.loading.value)) {
|
|
370
368
|
x.value = null;
|
|
371
369
|
try {
|
|
@@ -379,14 +377,14 @@ var ee = {
|
|
|
379
377
|
$();
|
|
380
378
|
return;
|
|
381
379
|
}
|
|
382
|
-
let e =
|
|
380
|
+
let e = Z();
|
|
383
381
|
T = e ? new MediaRecorder(E, {
|
|
384
382
|
mimeType: e,
|
|
385
383
|
audioBitsPerSecond: 64e3
|
|
386
384
|
}) : new MediaRecorder(E), D = [], T.ondataavailable = (e) => {
|
|
387
385
|
e.data.size > 0 && D.push(e.data);
|
|
388
386
|
}, T.onstop = () => {
|
|
389
|
-
|
|
387
|
+
pe(T?.mimeType || e || "audio/webm");
|
|
390
388
|
}, T.onerror = () => {
|
|
391
389
|
x.value = "录音失败,请重试或用文字输入。", y.value = !1, b.value = !1, Q(), $();
|
|
392
390
|
}, T.start(), y.value = !0, O = setTimeout(X, Math.max(1, S.maxRecordingSeconds) * 1e3);
|
|
@@ -396,18 +394,15 @@ var ee = {
|
|
|
396
394
|
}
|
|
397
395
|
}
|
|
398
396
|
function X() {
|
|
399
|
-
|
|
397
|
+
T && T.state !== "inactive" && (y.value = !1, b.value = !0, Q(), T.stop());
|
|
400
398
|
}
|
|
401
|
-
async function
|
|
399
|
+
async function pe(e) {
|
|
402
400
|
Q(), $();
|
|
403
401
|
let t = D;
|
|
404
402
|
if (D = [], T = null, k) return;
|
|
405
403
|
let n = new Blob(t, { type: e });
|
|
406
|
-
if (n.size === 0)
|
|
407
|
-
|
|
408
|
-
return;
|
|
409
|
-
}
|
|
410
|
-
try {
|
|
404
|
+
if (n.size === 0) x.value = "没有录到声音,请重试。", b.value = !1;
|
|
405
|
+
else try {
|
|
411
406
|
let t = await S.transcribe(n, me(e));
|
|
412
407
|
s.value = s.value.trim() ? `${s.value.trim()} ${t.text}` : t.text;
|
|
413
408
|
} catch {
|
|
@@ -416,7 +411,7 @@ var ee = {
|
|
|
416
411
|
b.value = !1;
|
|
417
412
|
}
|
|
418
413
|
}
|
|
419
|
-
function
|
|
414
|
+
function Z() {
|
|
420
415
|
if (typeof MediaRecorder.isTypeSupported == "function") return [
|
|
421
416
|
"audio/webm;codecs=opus",
|
|
422
417
|
"audio/mp4",
|
|
@@ -449,7 +444,7 @@ var ee = {
|
|
|
449
444
|
i("div", ne, [m(S).messages.value.length === 0 ? (u(), r("p", re, " 直接输入问题即可,复杂查单或赔付问题会提示转人工。 ")) : n("", !0), (u(!0), r(e, null, f(m(S).messages.value, (t, n) => (u(), r("article", {
|
|
450
445
|
key: `${t.role}-${n}`,
|
|
451
446
|
class: c(["seer-chat__message", `seer-chat__message--${t.role}`])
|
|
452
|
-
}, [i("span",
|
|
447
|
+
}, [i("span", z, p(t.role === "user" ? "你" : "AI 客服"), 1), i("div", B, [(u(!0), r(e, null, f(m(F)(t.content), (t, n) => (u(), r("p", {
|
|
453
448
|
key: n,
|
|
454
449
|
class: "seer-chat__line"
|
|
455
450
|
}, [(u(!0), r(e, null, f(t, (t, n) => (u(), r(e, { key: n }, [t.kind === "link" ? (u(), r("a", {
|
|
@@ -458,7 +453,7 @@ var ee = {
|
|
|
458
453
|
href: t.href,
|
|
459
454
|
target: "_blank",
|
|
460
455
|
rel: "noopener noreferrer"
|
|
461
|
-
}, p(t.label), 9,
|
|
456
|
+
}, p(t.label), 9, V)) : t.kind === "image" ? (u(), r("button", {
|
|
462
457
|
key: 1,
|
|
463
458
|
type: "button",
|
|
464
459
|
class: "seer-chat__image-button",
|
|
@@ -469,13 +464,13 @@ var ee = {
|
|
|
469
464
|
src: t.href,
|
|
470
465
|
alt: t.alt,
|
|
471
466
|
loading: "lazy"
|
|
472
|
-
}, null, 8,
|
|
473
|
-
m(S).loading.value ? (u(), r("p",
|
|
474
|
-
m(S).error.value || x.value ? (u(), r("p",
|
|
475
|
-
m(S).handoffRequested.value ? (u(), r("p",
|
|
467
|
+
}, null, 8, U)], 8, H)) : t.kind === "strong" ? (u(), r("strong", W, p(t.value), 1)) : t.kind === "price" ? (u(), r("span", G, p(t.value), 1)) : (u(), r("span", K, p(t.value), 1))], 64))), 128))]))), 128))])], 2))), 128))]),
|
|
468
|
+
m(S).loading.value ? (u(), r("p", q, "正在回复...")) : n("", !0),
|
|
469
|
+
m(S).error.value || x.value ? (u(), r("p", J, p(x.value || m(S).error.value), 1)) : n("", !0),
|
|
470
|
+
m(S).handoffRequested.value ? (u(), r("p", Y, " 建议转人工:请留下联系方式或等待客服接入。 ")) : n("", !0),
|
|
476
471
|
i("form", {
|
|
477
472
|
class: "seer-chat__form",
|
|
478
|
-
onSubmit: v(
|
|
473
|
+
onSubmit: v(P, ["prevent"])
|
|
479
474
|
}, [
|
|
480
475
|
o[6] ||= i("label", {
|
|
481
476
|
class: "seer-chat__label",
|
|
@@ -487,8 +482,8 @@ var ee = {
|
|
|
487
482
|
placeholder: a.placeholder,
|
|
488
483
|
disabled: m(S).loading.value || b.value,
|
|
489
484
|
rows: "3",
|
|
490
|
-
onKeydown: _(v(
|
|
491
|
-
}, null, 40,
|
|
485
|
+
onKeydown: _(v(P, ["exact", "prevent"]), ["enter"])
|
|
486
|
+
}, null, 40, ie), [[h, s.value]]),
|
|
492
487
|
i("div", ae, [
|
|
493
488
|
i("span", oe, p(y.value ? `正在录音,最长 ${m(S).maxRecordingSeconds} 秒` : b.value ? "正在识别语音..." : "Enter 发送 · Shift+Enter 换行"), 1),
|
|
494
489
|
w.value ? (u(), r("button", {
|
|
@@ -535,6 +530,5 @@ var ee = {
|
|
|
535
530
|
}, null, 8, fe)], 8, de)) : n("", !0)
|
|
536
531
|
]));
|
|
537
532
|
}
|
|
538
|
-
}), [["__scopeId", "data-v-
|
|
539
|
-
|
|
540
|
-
export { Y as SeerChat, I as SeerChatPlugin, y as createSeerClient, M as linkAnchorLabel, P as toContentLines, N as toContentSegments, L as useSeerChat };
|
|
533
|
+
}), [["__scopeId", "data-v-b64d9d8e"]]);
|
|
534
|
+
export { X as SeerChat, L as SeerChatPlugin, y as createSeerClient, N as linkAnchorLabel, F as toContentLines, P as toContentSegments, R as useSeerChat };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seer-ai/seer-vue",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.8",
|
|
4
4
|
"description": "Vue chat plugin for the seer OpenAI-compatible API",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -31,11 +31,11 @@
|
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@vitejs/plugin-vue": "^6.0.7",
|
|
33
33
|
"@vue/test-utils": "^2.4.10",
|
|
34
|
-
"happy-dom": "^
|
|
34
|
+
"happy-dom": "^21.0.4",
|
|
35
35
|
"typescript": "^6.0.3",
|
|
36
36
|
"vite": "^8.1.3",
|
|
37
37
|
"vitest": "^4.1.7",
|
|
38
|
-
"vue": "^3.5.
|
|
38
|
+
"vue": "^3.5.44",
|
|
39
39
|
"vue-tsc": "^3.3.2"
|
|
40
40
|
}
|
|
41
41
|
}
|