@seer-ai/seer-vue 0.1.0-beta.7 → 0.1.0-beta.9

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
@@ -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;
@@ -3,6 +3,7 @@ type __VLS_Props = {
3
3
  endpoint?: string;
4
4
  sessionEndpoint?: string;
5
5
  transcriptionEndpoint?: string;
6
+ orgOwner?: string;
6
7
  model?: string;
7
8
  stream?: boolean;
8
9
  fetcher?: SeerClientOptions["fetcher"];
package/dist/index.css CHANGED
@@ -1,2 +1,2 @@
1
- .seer-chat[data-v-e6edd9a7]{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-e6edd9a7]{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-e6edd9a7]{letter-spacing:-.03em;margin:0;font-size:22px}.seer-chat__header p[data-v-e6edd9a7],.seer-chat__empty[data-v-e6edd9a7],.seer-chat__status[data-v-e6edd9a7]{color:#5f6f89;margin:4px 0 0;font-size:14px}.seer-chat__header p[data-v-e6edd9a7]{color:#ffffffb8;max-width:34ch}.seer-chat__messages[data-v-e6edd9a7]{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-e6edd9a7]{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-e6edd9a7]{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-e6edd9a7]{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-e6edd9a7]{opacity:.75;font-size:12px;font-weight:700}.seer-chat__body[data-v-e6edd9a7]{flex-direction:column;display:flex}.seer-chat__line[data-v-e6edd9a7]{white-space:pre-wrap;overflow-wrap:anywhere;margin:0}.seer-chat__line[data-v-e6edd9a7]:not(:last-child){margin-bottom:5px}.seer-chat__line[data-v-e6edd9a7]:empty{height:7px}.seer-chat__strong[data-v-e6edd9a7]{font-weight:700}.seer-chat__price[data-v-e6edd9a7]{color:#e0331d;font-weight:600}.seer-chat__message--user .seer-chat__price[data-v-e6edd9a7]{color:#ffe2dc}.seer-chat__link[data-v-e6edd9a7]{color:#1f5eff;text-underline-offset:2px;overflow-wrap:anywhere;font-weight:600;text-decoration:underline}.seer-chat__link[data-v-e6edd9a7]:hover{color:#173fb3}.seer-chat__message--user .seer-chat__link[data-v-e6edd9a7]{color:#fff}.seer-chat__image-button[data-v-e6edd9a7]{cursor:zoom-in;background:0 0;border:0;padding:0;display:block}.seer-chat__image-button[data-v-e6edd9a7]:not(:disabled):hover{transform:none}.seer-chat__image[data-v-e6edd9a7]{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-e6edd9a7]{filter:brightness(.96)}.seer-chat__lightbox[data-v-e6edd9a7]{z-index:1000;cursor:zoom-out;background:#0a0f1ad1;place-items:center;padding:32px;animation:.14s seer-chat__fade-in-e6edd9a7;display:grid;position:fixed;inset:0}.seer-chat__lightbox-image[data-v-e6edd9a7]{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-e6edd9a7]{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-e6edd9a7]:not(:disabled):hover{background:#ffffff3d}@keyframes seer-chat__fade-in-e6edd9a7{0%{opacity:0}to{opacity:1}}.seer-chat__error[data-v-e6edd9a7],.seer-chat__handoff[data-v-e6edd9a7]{border-radius:14px;margin:0 18px;padding:10px 12px}.seer-chat__error[data-v-e6edd9a7]{color:#8a1f11;background:#fff0ed}.seer-chat__handoff[data-v-e6edd9a7]{color:#704600;background:#fff7db}.seer-chat__form[data-v-e6edd9a7]{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-e6edd9a7]{font-size:13px;font-weight:700}.seer-chat textarea[data-v-e6edd9a7]{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-e6edd9a7]{color:inherit;cursor:pointer;border:0;font-weight:700;transition:transform .16s,box-shadow .16s,opacity .16s}.seer-chat button[data-v-e6edd9a7]:not(:disabled):hover{transform:translateY(-1px)}.seer-chat button[data-v-e6edd9a7]:disabled{cursor:not-allowed;opacity:.5}.seer-chat button[data-v-e6edd9a7]:focus-visible,.seer-chat textarea[data-v-e6edd9a7]:focus-visible{border-color:#1f5eff6b;box-shadow:0 0 0 4px #1f5eff21}.seer-chat__clear-button[data-v-e6edd9a7]{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-e6edd9a7]:not(:disabled):hover{color:#fff;box-shadow:none;background:#ffffff1a}.seer-chat__stop-button[data-v-e6edd9a7]{color:#6c3b12;background:#fff1df;border-radius:12px;padding:8px 11px;font-size:12px}.seer-chat__mic-button[data-v-e6edd9a7]{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-e6edd9a7]:not(:disabled):hover{background:#dfe8ff}.seer-chat__mic-button--recording[data-v-e6edd9a7]{color:#fff;background:#d9342b;animation:1.4s ease-in-out infinite seer-chat__recording-pulse-e6edd9a7;box-shadow:0 0 0 5px #d9342b24}.seer-chat__mic-button--recording[data-v-e6edd9a7]:not(:disabled):hover{background:#bd271f}.seer-chat__stop-icon[data-v-e6edd9a7]{background:currentColor;border-radius:3px;width:12px;height:12px}@keyframes seer-chat__recording-pulse-e6edd9a7{50%{box-shadow:0 0 0 9px #d9342b14}}.seer-chat__send-button[data-v-e6edd9a7]{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-e6edd9a7]:not(:disabled):hover{box-shadow:0 14px 28px #1f5eff47}.seer-chat__hint[data-v-e6edd9a7]{color:#7a879a;margin-right:auto;font-size:12px}.seer-chat__composer-footer[data-v-e6edd9a7]{justify-content:flex-end;align-items:center;gap:8px;display:flex}
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
- //#region src/client.ts
2
+ // src/client.ts
3
3
  function y(e) {
4
- let t = e.fetcher ?? fetch, n = e.model ?? "seer", r = b(e), i = e.now ?? (() => Math.floor(Date.now() / 1e3)), a, o = 0;
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 s(), c = { "Content-Type": "application/json" };
9
- o && (c.Authorization = `Bearer ${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: c,
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 w(l));
23
- return a ? S(l, i.onDelta) : x(await l.json());
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 s(), o = {};
27
+ let a = await c(), o = {};
28
28
  a && (o.Authorization = `Bearer ${a}`);
29
- let c = new FormData();
30
- c.append("file", e, n);
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: c
35
+ body: s
36
36
  });
37
- if (!l.ok) throw Error(await w(l));
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 s() {
43
+ async function c() {
44
44
  if (!e.sessionEndpoint) return;
45
- let n = i();
46
- if (a && o - 30 > n) return a;
47
- let r = await t(e.sessionEndpoint, {
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 c()
49
+ headers: await l(r)
50
50
  });
51
- if (!r.ok) throw Error(await w(r));
52
- let s = await r.json();
53
- return a = s.token, o = s.expires_at, 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 c() {
56
- let t = {};
57
- return e.challengeTokenProvider && (t["X-Seer-Challenge-Token"] = await e.challengeTokenProvider()), t;
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 x(e) {
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 S(e, t) {
75
- if (!e.body) return x({});
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 = C(e);
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 C(e) {
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 w(e) {
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
- //#endregion
119
- //#region src/content.ts
120
- var T = /https?:\/\/[^\s)]+/g, E = /\.(png|jpe?g|gif|webp|bmp|svg)$/i, D = /* @__PURE__ */ RegExp("(单价\\s*\\d[\\d.]*\\s*[A-Za-z]+\\/kg)|(按当前信息为您筛选出[^\\n:]*推荐方案[^\\n:]*:)|(方案PK|时效最快|价格最低)", "g");
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
- D.lastIndex = 0;
125
+ O.lastIndex = 0;
124
126
  let n = 0, r;
125
- for (; (r = D.exec(e)) !== null;) {
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 k = /标签|箱唛|唛头|入库单|交接单|入仓单|面单|下载/;
145
- function A(e, t) {
146
+ var A = /标签|箱唛|唛头|入库单|交接单|入仓单|面单|下载/;
147
+ function j(e, t) {
146
148
  if (/方案|截图|报价图|效果图|示意图|图片/.test(t)) return !0;
147
- if (k.test(t)) return !1;
149
+ if (A.test(t)) return !1;
148
150
  let n = e.split(/[?#]/)[0];
149
- return E.test(n);
151
+ return D.test(n);
150
152
  }
151
- function j(e) {
153
+ function M(e) {
152
154
  return /方案|报价|截图|PK/.test(e) ? "方案PK" : "图片";
153
155
  }
154
- function M(e) {
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 N(e) {
159
+ function P(e) {
158
160
  let t = [];
159
- T.lastIndex = 0;
161
+ E.lastIndex = 0;
160
162
  let n = 0, r;
161
- for (; (r = T.exec(e)) !== null;) {
162
- let i = r[0], a = r.index, o = e.lastIndexOf("\n", a - 1) + 1, s = e.slice(o, a), c = A(i, s);
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(...O(r));
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: j(s)
172
+ alt: M(s)
171
173
  }) : t.push({
172
174
  kind: "link",
173
175
  href: i,
174
- label: M(s) ?? i
176
+ label: N(s) ?? i
175
177
  }), n = a + i.length;
176
178
  }
177
- return n < e.length && t.push(...O(e.slice(n))), t;
179
+ return n < e.length && t.push(...k(e.slice(n))), t;
178
180
  }
179
- function P(e) {
180
- return e.split("\n").map((e) => N(e));
181
+ function F(e) {
182
+ return e.split("\n").map((e) => P(e));
181
183
  }
182
- //#endregion
183
- //#region src/plugin.ts
184
- var F = Symbol("seer-chat-options"), I = { install(e, t) {
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
- //#endregion
188
- //#region src/useSeerChat.ts
189
- function L(e = {}) {
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 b() {
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: b
256
+ abort: x
256
257
  };
257
258
  }
258
- //#endregion
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
- }, ie = { class: "seer-chat__role" }, R = { class: "seer-chat__body" }, z = ["href"], B = ["aria-label", "onClick"], V = ["src", "alt"], H = {
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
- }, U = {
272
+ }, G = {
273
273
  key: 3,
274
274
  class: "seer-chat__price"
275
- }, W = { key: 4 }, G = {
275
+ }, K = { key: 4 }, q = {
276
276
  key: 0,
277
277
  class: "seer-chat__status"
278
- }, K = {
278
+ }, J = {
279
279
  key: 1,
280
280
  class: "seer-chat__error",
281
281
  role: "alert"
282
- }, q = {
282
+ }, Y = {
283
283
  key: 2,
284
284
  class: "seer-chat__handoff"
285
- }, J = [
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"], Y = /*#__PURE__*/ ((e, t) => {
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 = L({
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 F() {
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
- if (y.value) {
363
- X();
364
- return;
365
- }
366
- await Y();
364
+ y.value ? X() : await L();
367
365
  }
368
- async function Y() {
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 = pe();
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
- Z(T?.mimeType || e || "audio/webm");
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
- !T || T.state === "inactive" || (y.value = !1, b.value = !0, Q(), T.stop());
397
+ T && T.state !== "inactive" && (y.value = !1, b.value = !0, Q(), T.stop());
400
398
  }
401
- async function Z(e) {
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
- x.value = "没有录到声音,请重试。", b.value = !1;
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 pe() {
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", ie, p(t.role === "user" ? "你" : "AI 客服"), 1), i("div", R, [(u(!0), r(e, null, f(m(P)(t.content), (t, n) => (u(), r("p", {
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, z)) : t.kind === "image" ? (u(), r("button", {
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, V)], 8, B)) : t.kind === "strong" ? (u(), r("strong", H, p(t.value), 1)) : t.kind === "price" ? (u(), r("span", U, p(t.value), 1)) : (u(), r("span", W, p(t.value), 1))], 64))), 128))]))), 128))])], 2))), 128))]),
473
- m(S).loading.value ? (u(), r("p", G, "正在回复...")) : n("", !0),
474
- m(S).error.value || x.value ? (u(), r("p", K, p(x.value || m(S).error.value), 1)) : n("", !0),
475
- m(S).handoffRequested.value ? (u(), r("p", q, " 建议转人工:请留下联系方式或等待客服接入。 ")) : n("", !0),
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(F, ["prevent"])
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(F, ["exact", "prevent"]), ["enter"])
491
- }, null, 40, J), [[h, s.value]]),
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-e6edd9a7"]]);
539
- //#endregion
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.7",
3
+ "version": "0.1.0-beta.9",
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": "^20.9.0",
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.35",
38
+ "vue": "^3.5.44",
39
39
  "vue-tsc": "^3.3.2"
40
40
  }
41
41
  }