@seer-ai/seer-vue 0.1.0-beta.10 → 0.1.0-beta.11
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 +4 -0
- package/dist/client.d.ts +13 -0
- package/dist/components/SeerChat.vue.d.ts +3 -0
- package/dist/index.css +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +223 -127
- package/dist/plugin.d.ts +2 -0
- package/dist/useSeerChat.d.ts +18 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -41,6 +41,10 @@ import { SeerChat } from '@seer-ai/seer-vue'
|
|
|
41
41
|
60 秒;SenseVoice 转写结果只回填输入框,不会自动发送。标准 browser chat endpoint 会自动
|
|
42
42
|
推导 transcription endpoint,也可显式配置;传 `voiceEnabled: false` 可关闭话筒。
|
|
43
43
|
|
|
44
|
+
输入框旁的回形针按钮用来上传附件(下单模板 xlsx/xls/csv、图片、PDF),上传地址同样按 endpoint 推导成
|
|
45
|
+
`/v1/browser/files`,也可用 `uploadEndpoint` 显式配置;传 `uploadEnabled: false` 隐藏按钮。自定义 UI 用
|
|
46
|
+
`useSeerChat()` 的 `attach(file)` / `removeAttachment(fileId)` / `attachments`,`send(text)` 会带上待发送的附件。
|
|
47
|
+
|
|
44
48
|
## Logged-in customer (`orgOwner`)
|
|
45
49
|
|
|
46
50
|
传入已登录用户的多发货 `orgOwner`,询价时 seer 直接用它当客户编码,不再追问。登录态会变时传函数;
|
package/dist/client.d.ts
CHANGED
|
@@ -9,6 +9,8 @@ export interface SeerClientOptions {
|
|
|
9
9
|
endpoint: string;
|
|
10
10
|
sessionEndpoint?: string;
|
|
11
11
|
transcriptionEndpoint?: string;
|
|
12
|
+
/** 附件上传地址;不传时按 endpoint 推成同域的 /v1/browser/files,传空字符串关闭上传。 */
|
|
13
|
+
uploadEndpoint?: string;
|
|
12
14
|
challengeTokenProvider?: () => Promise<string>;
|
|
13
15
|
/** 已登录用户的多发货 orgOwner;报价时自动当作客户编码。登录态会变时传函数。 */
|
|
14
16
|
orgOwner?: SeerOrgOwner;
|
|
@@ -22,6 +24,15 @@ export interface SeerChatRequest {
|
|
|
22
24
|
stream?: boolean;
|
|
23
25
|
conversationId?: string;
|
|
24
26
|
metadata?: Record<string, unknown>;
|
|
27
|
+
/** 先 upload() 拿到的 fileId,随这条消息一起提交。 */
|
|
28
|
+
attachments?: string[];
|
|
29
|
+
}
|
|
30
|
+
export interface SeerUploadedFile {
|
|
31
|
+
fileId: string;
|
|
32
|
+
filename: string;
|
|
33
|
+
kind: 'spreadsheet' | 'image' | 'document' | string;
|
|
34
|
+
contentType: string;
|
|
35
|
+
size: number;
|
|
25
36
|
}
|
|
26
37
|
export interface SeerChatCallbacks {
|
|
27
38
|
signal?: AbortSignal;
|
|
@@ -42,8 +53,10 @@ export interface SeerChatResult {
|
|
|
42
53
|
}
|
|
43
54
|
export interface SeerClient {
|
|
44
55
|
transcriptionEnabled: boolean;
|
|
56
|
+
uploadEnabled: boolean;
|
|
45
57
|
chat(request: SeerChatRequest, callbacks?: SeerChatCallbacks): Promise<SeerChatResult>;
|
|
46
58
|
transcribe(audio: Blob, filename: string, callbacks?: SeerTranscriptionCallbacks): Promise<SeerTranscriptionResult>;
|
|
59
|
+
upload(file: Blob, filename: string, callbacks?: SeerTranscriptionCallbacks): Promise<SeerUploadedFile>;
|
|
47
60
|
}
|
|
48
61
|
export declare function createSeerClient(options: SeerClientOptions): SeerClient;
|
|
49
62
|
export declare function resolveOrgOwner(orgOwner: SeerOrgOwner | undefined): string | undefined;
|
|
@@ -3,6 +3,8 @@ type __VLS_Props = {
|
|
|
3
3
|
endpoint?: string;
|
|
4
4
|
sessionEndpoint?: string;
|
|
5
5
|
transcriptionEndpoint?: string;
|
|
6
|
+
uploadEndpoint?: string;
|
|
7
|
+
uploadEnabled?: boolean;
|
|
6
8
|
orgOwner?: string;
|
|
7
9
|
model?: string;
|
|
8
10
|
stream?: boolean;
|
|
@@ -17,6 +19,7 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
|
|
|
17
19
|
title: string;
|
|
18
20
|
placeholder: string;
|
|
19
21
|
voiceEnabled: boolean;
|
|
22
|
+
uploadEnabled: boolean;
|
|
20
23
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
21
24
|
declare const _default: typeof __VLS_export;
|
|
22
25
|
export default _default;
|
package/dist/index.css
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
.seer-chat[data-v-
|
|
1
|
+
.seer-chat[data-v-adaeb672]{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-adaeb672]{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-adaeb672]{letter-spacing:-.03em;margin:0;font-size:22px}.seer-chat__header p[data-v-adaeb672],.seer-chat__empty[data-v-adaeb672],.seer-chat__status[data-v-adaeb672]{color:#5f6f89;margin:4px 0 0;font-size:14px}.seer-chat__header p[data-v-adaeb672]{color:#ffffffb8;max-width:34ch}.seer-chat__messages[data-v-adaeb672]{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-adaeb672]{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-adaeb672]{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-adaeb672]{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-adaeb672]{opacity:.75;font-size:12px;font-weight:700}.seer-chat__body[data-v-adaeb672]{flex-direction:column;display:flex}.seer-chat__line[data-v-adaeb672]{white-space:pre-wrap;overflow-wrap:anywhere;margin:0}.seer-chat__line[data-v-adaeb672]:not(:last-child){margin-bottom:5px}.seer-chat__line[data-v-adaeb672]:empty{height:7px}.seer-chat__strong[data-v-adaeb672]{font-weight:700}.seer-chat__price[data-v-adaeb672]{color:#e0331d;font-weight:600}.seer-chat__message--user .seer-chat__price[data-v-adaeb672]{color:#ffe2dc}.seer-chat__link[data-v-adaeb672]{color:#1f5eff;text-underline-offset:2px;overflow-wrap:anywhere;font-weight:600;text-decoration:underline}.seer-chat__link[data-v-adaeb672]:hover{color:#173fb3}.seer-chat__message--user .seer-chat__link[data-v-adaeb672]{color:#fff}.seer-chat__image-button[data-v-adaeb672]{cursor:zoom-in;background:0 0;border:0;padding:0;display:block}.seer-chat__image-button[data-v-adaeb672]:not(:disabled):hover{transform:none}.seer-chat__image[data-v-adaeb672]{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-adaeb672]{filter:brightness(.96)}.seer-chat__lightbox[data-v-adaeb672]{z-index:1000;cursor:zoom-out;background:#0a0f1ad1;place-items:center;padding:32px;animation:.14s seer-chat__fade-in-adaeb672;display:grid;position:fixed;inset:0}.seer-chat__lightbox-image[data-v-adaeb672]{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-adaeb672]{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-adaeb672]:not(:disabled):hover{background:#ffffff3d}@keyframes seer-chat__fade-in-adaeb672{0%{opacity:0}to{opacity:1}}.seer-chat__error[data-v-adaeb672],.seer-chat__handoff[data-v-adaeb672]{border-radius:14px;margin:0 18px;padding:10px 12px}.seer-chat__error[data-v-adaeb672]{color:#8a1f11;background:#fff0ed}.seer-chat__handoff[data-v-adaeb672]{color:#704600;background:#fff7db}.seer-chat__form[data-v-adaeb672]{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-adaeb672]{font-size:13px;font-weight:700}.seer-chat textarea[data-v-adaeb672]{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-adaeb672]{color:inherit;cursor:pointer;border:0;font-weight:700;transition:transform .16s,box-shadow .16s,opacity .16s}.seer-chat button[data-v-adaeb672]:not(:disabled):hover{transform:translateY(-1px)}.seer-chat button[data-v-adaeb672]:disabled{cursor:not-allowed;opacity:.5}.seer-chat button[data-v-adaeb672]:focus-visible,.seer-chat textarea[data-v-adaeb672]:focus-visible{border-color:#1f5eff6b;box-shadow:0 0 0 4px #1f5eff21}.seer-chat__clear-button[data-v-adaeb672]{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-adaeb672]:not(:disabled):hover{color:#fff;box-shadow:none;background:#ffffff1a}.seer-chat__stop-button[data-v-adaeb672]{color:#6c3b12;background:#fff1df;border-radius:12px;padding:8px 11px;font-size:12px}.seer-chat__mic-button[data-v-adaeb672],.seer-chat__attach-button[data-v-adaeb672]{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-adaeb672]:not(:disabled):hover,.seer-chat__attach-button[data-v-adaeb672]:not(:disabled):hover{background:#dfe8ff}.seer-chat__file-input[data-v-adaeb672]{display:none}.seer-chat__attachments[data-v-adaeb672]{flex-wrap:wrap;gap:6px;margin:0 0 8px;padding:0;list-style:none;display:flex}.seer-chat__attachment[data-v-adaeb672]{color:#1f2a44;background:#edf2ff;border-radius:999px;align-items:center;gap:4px;max-width:100%;padding:4px 6px 4px 10px;font-size:13px;display:inline-flex}.seer-chat__attachment-name[data-v-adaeb672]{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.seer-chat__attachment-remove[data-v-adaeb672]{color:#4b5878;background:0 0;border-radius:50%;width:20px;height:20px;padding:0;line-height:1}.seer-chat__attachment-remove[data-v-adaeb672]:hover{background:#dfe8ff}.seer-chat__mic-button--recording[data-v-adaeb672]{color:#fff;background:#d9342b;animation:1.4s ease-in-out infinite seer-chat__recording-pulse-adaeb672;box-shadow:0 0 0 5px #d9342b24}.seer-chat__mic-button--recording[data-v-adaeb672]:not(:disabled):hover{background:#bd271f}.seer-chat__stop-icon[data-v-adaeb672]{background:currentColor;border-radius:3px;width:12px;height:12px}@keyframes seer-chat__recording-pulse-adaeb672{50%{box-shadow:0 0 0 9px #d9342b14}}.seer-chat__send-button[data-v-adaeb672]{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-adaeb672]:not(:disabled):hover{box-shadow:0 14px 28px #1f5eff47}.seer-chat__hint[data-v-adaeb672]{color:#7a879a;margin-right:auto;font-size:12px}.seer-chat__composer-footer[data-v-adaeb672]{justify-content:flex-end;align-items:center;gap:8px;display:flex}
|
|
2
2
|
/*$vite$:1*/
|
package/dist/index.d.ts
CHANGED
|
@@ -3,6 +3,6 @@ export { linkAnchorLabel, toContentLines, toContentSegments, type ContentOptions
|
|
|
3
3
|
export { SeerChatPlugin } from './plugin';
|
|
4
4
|
export { useSeerChat } from './useSeerChat';
|
|
5
5
|
export { default as SeerChat } from './components/SeerChat.vue';
|
|
6
|
-
export type { SeerChatCallbacks, SeerChatMessage, SeerChatRequest, SeerChatResult, SeerChatRole, SeerClient, SeerClientOptions, SeerTranscriptionCallbacks, SeerTranscriptionResult, } from './client';
|
|
6
|
+
export type { SeerChatCallbacks, SeerChatMessage, SeerChatRequest, SeerChatResult, SeerChatRole, SeerClient, SeerClientOptions, SeerTranscriptionCallbacks, SeerTranscriptionResult, SeerUploadedFile, } from './client';
|
|
7
7
|
export type { SeerChatPluginOptions } from './plugin';
|
|
8
8
|
export type { UseSeerChatOptions } from './useSeerChat';
|
package/dist/index.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
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 = x(e), i = e.now ?? (() => Math.floor(Date.now() / 1e3)),
|
|
4
|
+
let t = e.fetcher ?? fetch, n = e.model ?? "seer", r = x(e.endpoint, e.transcriptionEndpoint, "/v1/browser/audio/transcriptions"), i = x(e.endpoint, e.uploadEndpoint, "/v1/browser/files"), a = e.now ?? (() => Math.floor(Date.now() / 1e3)), o, s = 0, c;
|
|
5
5
|
return {
|
|
6
6
|
transcriptionEnabled: !!r,
|
|
7
|
+
uploadEnabled: !!i,
|
|
7
8
|
async chat(r, i = {}) {
|
|
8
|
-
let a = r.stream ?? !1, o = await
|
|
9
|
+
let a = r.stream ?? !1, o = await l(), s = { "Content-Type": "application/json" };
|
|
9
10
|
o && (s.Authorization = `Bearer ${o}`);
|
|
10
|
-
let
|
|
11
|
+
let c = await t(e.endpoint, {
|
|
11
12
|
method: "POST",
|
|
12
13
|
headers: s,
|
|
13
14
|
signal: i.signal,
|
|
@@ -16,43 +17,67 @@ function y(e) {
|
|
|
16
17
|
messages: r.messages,
|
|
17
18
|
stream: a,
|
|
18
19
|
conversation_id: r.conversationId,
|
|
19
|
-
metadata: r.metadata
|
|
20
|
+
metadata: r.metadata,
|
|
21
|
+
...r.attachments?.length ? { attachments: r.attachments } : {}
|
|
20
22
|
})
|
|
21
23
|
});
|
|
22
|
-
if (!
|
|
23
|
-
return a ? C(
|
|
24
|
+
if (!c.ok) throw Error(await T(c));
|
|
25
|
+
return a ? C(c, i.onDelta) : S(await c.json());
|
|
24
26
|
},
|
|
25
27
|
async transcribe(e, n, i = {}) {
|
|
26
28
|
if (!r) throw Error("Seer audio transcription endpoint is not configured");
|
|
27
|
-
let a = await
|
|
29
|
+
let a = await l(), o = {};
|
|
28
30
|
a && (o.Authorization = `Bearer ${a}`);
|
|
29
31
|
let s = new FormData();
|
|
30
32
|
s.append("file", e, n);
|
|
31
|
-
let
|
|
33
|
+
let c = await t(r, {
|
|
32
34
|
method: "POST",
|
|
33
35
|
headers: o,
|
|
34
36
|
signal: i.signal,
|
|
35
37
|
body: s
|
|
36
38
|
});
|
|
37
|
-
if (!
|
|
38
|
-
let u = await
|
|
39
|
+
if (!c.ok) throw Error(await T(c));
|
|
40
|
+
let u = await c.json(), d = typeof u.text == "string" ? u.text.trim() : "";
|
|
39
41
|
if (!d) throw Error("Seer audio transcription returned empty text");
|
|
40
42
|
return { text: d };
|
|
43
|
+
},
|
|
44
|
+
async upload(e, n, r = {}) {
|
|
45
|
+
if (!i) throw Error("Seer file upload endpoint is not configured");
|
|
46
|
+
let a = await l(), o = {};
|
|
47
|
+
a && (o.Authorization = `Bearer ${a}`);
|
|
48
|
+
let s = new FormData();
|
|
49
|
+
s.append("file", e, n);
|
|
50
|
+
let c = await t(i, {
|
|
51
|
+
method: "POST",
|
|
52
|
+
headers: o,
|
|
53
|
+
signal: r.signal,
|
|
54
|
+
body: s
|
|
55
|
+
});
|
|
56
|
+
if (!c.ok) throw Error(await T(c));
|
|
57
|
+
let u = await c.json();
|
|
58
|
+
if (!u.file_id) throw Error("Seer file upload returned no file_id");
|
|
59
|
+
return {
|
|
60
|
+
fileId: u.file_id,
|
|
61
|
+
filename: u.filename ?? n,
|
|
62
|
+
kind: u.kind ?? "document",
|
|
63
|
+
contentType: u.content_type ?? "",
|
|
64
|
+
size: u.size ?? e.size
|
|
65
|
+
};
|
|
41
66
|
}
|
|
42
67
|
};
|
|
43
|
-
async function
|
|
68
|
+
async function l() {
|
|
44
69
|
if (!e.sessionEndpoint) return;
|
|
45
|
-
let n =
|
|
46
|
-
if (
|
|
47
|
-
let
|
|
70
|
+
let n = a(), r = b(e.orgOwner);
|
|
71
|
+
if (o && c === r && s - 30 > n) return o;
|
|
72
|
+
let i = await t(e.sessionEndpoint, {
|
|
48
73
|
method: "GET",
|
|
49
|
-
headers: await
|
|
74
|
+
headers: await u(r)
|
|
50
75
|
});
|
|
51
|
-
if (!
|
|
52
|
-
let
|
|
53
|
-
return
|
|
76
|
+
if (!i.ok) throw Error(await T(i));
|
|
77
|
+
let l = await i.json();
|
|
78
|
+
return o = l.token, s = l.expires_at, c = r, o;
|
|
54
79
|
}
|
|
55
|
-
async function
|
|
80
|
+
async function u(t) {
|
|
56
81
|
let n = {};
|
|
57
82
|
return e.challengeTokenProvider && (n["X-Seer-Challenge-Token"] = await e.challengeTokenProvider()), t && (n["X-Seer-Org-Owner"] = t), n;
|
|
58
83
|
}
|
|
@@ -60,9 +85,9 @@ function y(e) {
|
|
|
60
85
|
function b(e) {
|
|
61
86
|
return (typeof e == "function" ? e() : e)?.trim() || void 0;
|
|
62
87
|
}
|
|
63
|
-
function x(e) {
|
|
64
|
-
if (
|
|
65
|
-
if (e.
|
|
88
|
+
function x(e, t, n) {
|
|
89
|
+
if (t !== void 0) return t || void 0;
|
|
90
|
+
if (e.endsWith("/v1/browser/chat/completions")) return `${e.slice(0, -28)}${n}`;
|
|
66
91
|
}
|
|
67
92
|
function S(e) {
|
|
68
93
|
let t = e.choices?.[0];
|
|
@@ -200,33 +225,49 @@ function B(e = {}) {
|
|
|
200
225
|
endpoint: r.endpoint,
|
|
201
226
|
sessionEndpoint: r.sessionEndpoint,
|
|
202
227
|
transcriptionEndpoint: r.transcriptionEndpoint,
|
|
228
|
+
uploadEndpoint: r.uploadEndpoint,
|
|
203
229
|
challengeTokenProvider: r.challengeTokenProvider,
|
|
204
230
|
orgOwner: () => b(e.orgOwner) ?? b(t?.orgOwner),
|
|
205
231
|
model: r.model,
|
|
206
232
|
fetcher: r.fetcher
|
|
207
|
-
}), 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,
|
|
208
|
-
async function
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
233
|
+
}), a = d([]), c = d(!1), l = d(null), u = d(), f = d([]), p = d(!1), m = r.voiceEnabled !== !1 && i.transcriptionEnabled, h = r.uploadEnabled !== !1 && i.uploadEnabled, g = r.maxRecordingSeconds ?? 60, _ = d([]), v = d(!1), x = null;
|
|
234
|
+
async function S(e) {
|
|
235
|
+
v.value = !0, l.value = null;
|
|
236
|
+
try {
|
|
237
|
+
let t = await i.upload(e, e.name);
|
|
238
|
+
_.value = [..._.value, t];
|
|
239
|
+
} catch (e) {
|
|
240
|
+
l.value = e instanceof Error ? e.message : String(e);
|
|
241
|
+
} finally {
|
|
242
|
+
v.value = !1;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
function C(e) {
|
|
246
|
+
_.value = _.value.filter((t) => t.fileId !== e);
|
|
247
|
+
}
|
|
248
|
+
async function w(e) {
|
|
249
|
+
let t = e.trim(), n = _.value;
|
|
250
|
+
if (!t && n.length === 0 || c.value || v.value) return;
|
|
251
|
+
let o = {
|
|
212
252
|
role: "user",
|
|
213
|
-
content: t
|
|
253
|
+
content: [t, n.map((e) => `[附件:${e.filename}]`).join("\n")].filter(Boolean).join("\n")
|
|
214
254
|
};
|
|
215
|
-
a.value = [...a.value,
|
|
216
|
-
let
|
|
255
|
+
_.value = [], a.value = [...a.value, o], c.value = !0, l.value = null, x = new AbortController();
|
|
256
|
+
let s = {
|
|
217
257
|
role: "assistant",
|
|
218
258
|
content: ""
|
|
219
259
|
};
|
|
220
|
-
r.stream && (a.value = [...a.value,
|
|
260
|
+
r.stream && (a.value = [...a.value, s]);
|
|
221
261
|
try {
|
|
222
262
|
let e = await i.chat({
|
|
223
263
|
messages: a.value.filter((e) => e.content),
|
|
224
264
|
stream: r.stream ?? !1,
|
|
225
|
-
conversationId: u.value
|
|
265
|
+
conversationId: u.value,
|
|
266
|
+
attachments: n.map((e) => e.fileId)
|
|
226
267
|
}, {
|
|
227
|
-
signal:
|
|
268
|
+
signal: x.signal,
|
|
228
269
|
onDelta(e) {
|
|
229
|
-
|
|
270
|
+
s.content += e, a.value = [...a.value];
|
|
230
271
|
}
|
|
231
272
|
});
|
|
232
273
|
r.stream || (a.value = [...a.value, {
|
|
@@ -236,14 +277,14 @@ function B(e = {}) {
|
|
|
236
277
|
} catch (e) {
|
|
237
278
|
e.name !== "AbortError" && (l.value = e instanceof Error ? e.message : String(e));
|
|
238
279
|
} finally {
|
|
239
|
-
c.value = !1,
|
|
280
|
+
c.value = !1, x = null;
|
|
240
281
|
}
|
|
241
282
|
}
|
|
242
|
-
function
|
|
243
|
-
a.value = [], l.value = null, u.value = void 0, f.value = [], p.value = !1;
|
|
283
|
+
function T() {
|
|
284
|
+
a.value = [], _.value = [], l.value = null, u.value = void 0, f.value = [], p.value = !1;
|
|
244
285
|
}
|
|
245
|
-
function
|
|
246
|
-
|
|
286
|
+
function E() {
|
|
287
|
+
x?.abort();
|
|
247
288
|
}
|
|
248
289
|
return {
|
|
249
290
|
messages: a,
|
|
@@ -253,61 +294,70 @@ function B(e = {}) {
|
|
|
253
294
|
citations: f,
|
|
254
295
|
handoffRequested: p,
|
|
255
296
|
transcriptionEnabled: m,
|
|
256
|
-
maxRecordingSeconds:
|
|
297
|
+
maxRecordingSeconds: g,
|
|
257
298
|
transcribe: i.transcribe,
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
299
|
+
uploadEnabled: h,
|
|
300
|
+
attachments: _,
|
|
301
|
+
uploading: v,
|
|
302
|
+
attach: S,
|
|
303
|
+
removeAttachment: C,
|
|
304
|
+
send: w,
|
|
305
|
+
reset: T,
|
|
306
|
+
abort: E
|
|
261
307
|
};
|
|
262
308
|
}
|
|
263
309
|
// src/components/SeerChat.vue?vue&type=script&setup=true&lang.ts
|
|
264
|
-
var
|
|
310
|
+
var ee = {
|
|
265
311
|
class: "seer-chat",
|
|
266
312
|
"aria-label": "多发货 AI 客服聊天"
|
|
267
|
-
},
|
|
313
|
+
}, te = { class: "seer-chat__header" }, ne = {
|
|
268
314
|
class: "seer-chat__messages",
|
|
269
315
|
"aria-live": "polite"
|
|
270
|
-
},
|
|
316
|
+
}, re = {
|
|
271
317
|
key: 0,
|
|
272
318
|
class: "seer-chat__empty"
|
|
273
|
-
},
|
|
319
|
+
}, V = { class: "seer-chat__role" }, H = { class: "seer-chat__body" }, U = ["href"], W = ["aria-label", "onClick"], G = ["src", "alt"], K = {
|
|
274
320
|
key: 2,
|
|
275
321
|
class: "seer-chat__strong"
|
|
276
|
-
},
|
|
322
|
+
}, q = {
|
|
277
323
|
key: 3,
|
|
278
324
|
class: "seer-chat__price"
|
|
279
|
-
},
|
|
325
|
+
}, J = { key: 4 }, Y = {
|
|
280
326
|
key: 0,
|
|
281
327
|
class: "seer-chat__status"
|
|
282
|
-
},
|
|
328
|
+
}, ie = {
|
|
283
329
|
key: 1,
|
|
284
330
|
class: "seer-chat__error",
|
|
285
331
|
role: "alert"
|
|
286
|
-
},
|
|
332
|
+
}, ae = {
|
|
287
333
|
key: 2,
|
|
288
334
|
class: "seer-chat__handoff"
|
|
289
|
-
},
|
|
335
|
+
}, oe = {
|
|
336
|
+
key: 0,
|
|
337
|
+
class: "seer-chat__attachments",
|
|
338
|
+
"aria-label": "待发送的附件"
|
|
339
|
+
}, se = { class: "seer-chat__attachment-name" }, ce = ["aria-label", "onClick"], le = [
|
|
290
340
|
"placeholder",
|
|
291
341
|
"disabled",
|
|
292
342
|
"onKeydown"
|
|
293
|
-
],
|
|
343
|
+
], ue = { class: "seer-chat__composer-footer" }, de = {
|
|
294
344
|
class: "seer-chat__hint",
|
|
295
345
|
"aria-live": "polite"
|
|
296
|
-
},
|
|
346
|
+
}, fe = ["disabled"], pe = [
|
|
297
347
|
"disabled",
|
|
298
348
|
"aria-label",
|
|
299
349
|
"title"
|
|
300
|
-
],
|
|
350
|
+
], me = {
|
|
301
351
|
key: 0,
|
|
302
352
|
class: "seer-chat__stop-icon",
|
|
303
353
|
"aria-hidden": "true"
|
|
304
|
-
},
|
|
354
|
+
}, he = {
|
|
305
355
|
key: 1,
|
|
306
356
|
viewBox: "0 0 24 24",
|
|
307
357
|
width: "20",
|
|
308
358
|
height: "20",
|
|
309
359
|
"aria-hidden": "true"
|
|
310
|
-
},
|
|
360
|
+
}, ge = ["disabled"], X = ["aria-label"], _e = ["src", "alt"], ve = ".xlsx,.xls,.csv,.png,.jpg,.jpeg,.webp,.pdf", Z = /*#__PURE__*/ ((e, t) => {
|
|
311
361
|
let n = e.__vccOpts || e;
|
|
312
362
|
for (let [e, r] of t) n[e] = r;
|
|
313
363
|
return n;
|
|
@@ -317,6 +367,11 @@ var V = {
|
|
|
317
367
|
endpoint: {},
|
|
318
368
|
sessionEndpoint: {},
|
|
319
369
|
transcriptionEndpoint: {},
|
|
370
|
+
uploadEndpoint: {},
|
|
371
|
+
uploadEnabled: {
|
|
372
|
+
type: Boolean,
|
|
373
|
+
default: void 0
|
|
374
|
+
},
|
|
320
375
|
orgOwner: {},
|
|
321
376
|
model: {},
|
|
322
377
|
stream: {
|
|
@@ -337,77 +392,85 @@ var V = {
|
|
|
337
392
|
endpoint: o.endpoint,
|
|
338
393
|
sessionEndpoint: o.sessionEndpoint,
|
|
339
394
|
transcriptionEndpoint: o.transcriptionEndpoint,
|
|
395
|
+
uploadEndpoint: o.uploadEndpoint,
|
|
396
|
+
uploadEnabled: o.uploadEnabled,
|
|
340
397
|
orgOwner: () => o.orgOwner,
|
|
341
398
|
model: o.model,
|
|
342
399
|
stream: o.stream,
|
|
343
400
|
fetcher: o.fetcher,
|
|
344
401
|
voiceEnabled: o.voiceEnabled,
|
|
345
402
|
maxRecordingSeconds: o.maxRecordingSeconds
|
|
346
|
-
}), C = t(() => s.value.trim().length > 0
|
|
347
|
-
function
|
|
348
|
-
e.
|
|
403
|
+
}), C = d(null), w = t(() => (s.value.trim().length > 0 || S.attachments.value.length > 0) && !S.loading.value && !S.uploading.value && !y.value && !b.value);
|
|
404
|
+
async function T(e) {
|
|
405
|
+
let t = e.target, n = Array.from(t.files ?? []);
|
|
406
|
+
t.value = "";
|
|
407
|
+
for (let e of n) await S.attach(e);
|
|
408
|
+
}
|
|
409
|
+
let E = t(() => S.transcriptionEnabled && typeof navigator < "u" && typeof navigator.mediaDevices?.getUserMedia == "function" && typeof MediaRecorder < "u"), D = null, O = null, k = [], A, j = !1, M = d(null);
|
|
410
|
+
function N(e) {
|
|
411
|
+
e.key === "Escape" && F();
|
|
349
412
|
}
|
|
350
|
-
function
|
|
351
|
-
|
|
413
|
+
function P(e, t) {
|
|
414
|
+
M.value = {
|
|
352
415
|
src: e,
|
|
353
416
|
alt: t
|
|
354
|
-
}, window.addEventListener("keydown",
|
|
417
|
+
}, window.addEventListener("keydown", N);
|
|
355
418
|
}
|
|
356
|
-
function
|
|
357
|
-
|
|
419
|
+
function F() {
|
|
420
|
+
M.value = null, window.removeEventListener("keydown", N);
|
|
358
421
|
}
|
|
359
422
|
l(() => {
|
|
360
|
-
|
|
423
|
+
j = !0, window.removeEventListener("keydown", N), Q(), D && D.state !== "inactive" && (D.ondataavailable = null, D.onstop = null, D.onerror = null, D.stop()), $();
|
|
361
424
|
});
|
|
362
|
-
async function
|
|
363
|
-
if (!
|
|
425
|
+
async function I() {
|
|
426
|
+
if (!w.value) return;
|
|
364
427
|
let e = s.value;
|
|
365
428
|
s.value = "", await S.send(e);
|
|
366
429
|
}
|
|
367
|
-
async function
|
|
368
|
-
y.value ?
|
|
430
|
+
async function R() {
|
|
431
|
+
y.value ? Z() : await z();
|
|
369
432
|
}
|
|
370
|
-
async function
|
|
371
|
-
if (!(!
|
|
433
|
+
async function z() {
|
|
434
|
+
if (!(!E.value || b.value || S.loading.value)) {
|
|
372
435
|
x.value = null;
|
|
373
436
|
try {
|
|
374
|
-
if (
|
|
437
|
+
if (O = await navigator.mediaDevices.getUserMedia({
|
|
375
438
|
audio: {
|
|
376
439
|
echoCancellation: !0,
|
|
377
440
|
noiseSuppression: !0
|
|
378
441
|
},
|
|
379
442
|
video: !1
|
|
380
|
-
}),
|
|
443
|
+
}), j) {
|
|
381
444
|
$();
|
|
382
445
|
return;
|
|
383
446
|
}
|
|
384
|
-
let e =
|
|
385
|
-
|
|
447
|
+
let e = be();
|
|
448
|
+
D = e ? new MediaRecorder(O, {
|
|
386
449
|
mimeType: e,
|
|
387
450
|
audioBitsPerSecond: 64e3
|
|
388
|
-
}) : new MediaRecorder(
|
|
389
|
-
e.data.size > 0 &&
|
|
390
|
-
},
|
|
391
|
-
|
|
392
|
-
},
|
|
451
|
+
}) : new MediaRecorder(O), k = [], D.ondataavailable = (e) => {
|
|
452
|
+
e.data.size > 0 && k.push(e.data);
|
|
453
|
+
}, D.onstop = () => {
|
|
454
|
+
ye(D?.mimeType || e || "audio/webm");
|
|
455
|
+
}, D.onerror = () => {
|
|
393
456
|
x.value = "录音失败,请重试或用文字输入。", y.value = !1, b.value = !1, Q(), $();
|
|
394
|
-
},
|
|
457
|
+
}, D.start(), y.value = !0, A = setTimeout(Z, Math.max(1, S.maxRecordingSeconds) * 1e3);
|
|
395
458
|
} catch (e) {
|
|
396
|
-
x.value =
|
|
459
|
+
x.value = Se(e), $();
|
|
397
460
|
}
|
|
398
461
|
}
|
|
399
462
|
}
|
|
400
|
-
function
|
|
401
|
-
|
|
463
|
+
function Z() {
|
|
464
|
+
D && D.state !== "inactive" && (y.value = !1, b.value = !0, Q(), D.stop());
|
|
402
465
|
}
|
|
403
|
-
async function
|
|
466
|
+
async function ye(e) {
|
|
404
467
|
Q(), $();
|
|
405
|
-
let t =
|
|
406
|
-
if (
|
|
468
|
+
let t = k;
|
|
469
|
+
if (k = [], D = null, j) return;
|
|
407
470
|
let n = new Blob(t, { type: e });
|
|
408
471
|
if (n.size === 0) x.value = "没有录到声音,请重试。", b.value = !1;
|
|
409
472
|
else try {
|
|
410
|
-
let t = await S.transcribe(n,
|
|
473
|
+
let t = await S.transcribe(n, xe(e));
|
|
411
474
|
s.value = s.value.trim() ? `${s.value.trim()} ${t.text}` : t.text;
|
|
412
475
|
} catch {
|
|
413
476
|
x.value = "语音识别失败,请重试或用文字输入。";
|
|
@@ -415,7 +478,7 @@ var V = {
|
|
|
415
478
|
b.value = !1;
|
|
416
479
|
}
|
|
417
480
|
}
|
|
418
|
-
function
|
|
481
|
+
function be() {
|
|
419
482
|
if (typeof MediaRecorder.isTypeSupported == "function") return [
|
|
420
483
|
"audio/webm;codecs=opus",
|
|
421
484
|
"audio/mp4",
|
|
@@ -423,32 +486,32 @@ var V = {
|
|
|
423
486
|
"audio/webm"
|
|
424
487
|
].find((e) => MediaRecorder.isTypeSupported(e));
|
|
425
488
|
}
|
|
426
|
-
function
|
|
489
|
+
function xe(e) {
|
|
427
490
|
return `recording.${{
|
|
428
491
|
"audio/mp4": "m4a",
|
|
429
492
|
"audio/ogg": "ogg",
|
|
430
493
|
"audio/webm": "webm"
|
|
431
494
|
}[e.split(";", 1)[0].toLowerCase()] || "webm"}`;
|
|
432
495
|
}
|
|
433
|
-
function
|
|
496
|
+
function Se(e) {
|
|
434
497
|
return e instanceof DOMException && e.name === "NotAllowedError" ? "请允许浏览器使用麦克风。" : e instanceof DOMException && e.name === "NotFoundError" ? "未检测到可用的麦克风。" : "无法启动麦克风,请重试或用文字输入。";
|
|
435
498
|
}
|
|
436
499
|
function Q() {
|
|
437
|
-
|
|
500
|
+
A !== void 0 && (clearTimeout(A), A = void 0);
|
|
438
501
|
}
|
|
439
502
|
function $() {
|
|
440
|
-
|
|
503
|
+
O?.getTracks().forEach((e) => e.stop()), O = null;
|
|
441
504
|
}
|
|
442
|
-
return (t, o) => (u(), r("section",
|
|
443
|
-
i("header",
|
|
505
|
+
return (t, o) => (u(), r("section", ee, [
|
|
506
|
+
i("header", te, [i("div", null, [i("h2", null, p(a.title), 1), o[4] ||= i("p", null, "可咨询渠道报价、时效、下单资料、入仓和售后问题。", -1)]), i("button", {
|
|
444
507
|
type: "button",
|
|
445
508
|
class: "seer-chat__clear-button",
|
|
446
509
|
onClick: o[0] ||= (e) => m(S).reset()
|
|
447
510
|
}, " 清空对话 ")]),
|
|
448
|
-
i("div",
|
|
511
|
+
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", {
|
|
449
512
|
key: `${t.role}-${n}`,
|
|
450
513
|
class: c(["seer-chat__message", `seer-chat__message--${t.role}`])
|
|
451
|
-
}, [i("span",
|
|
514
|
+
}, [i("span", V, p(t.role === "user" ? "你" : "AI 客服"), 1), i("div", H, [(u(!0), r(e, null, f(m(L)(t.content, { complete: !(m(S).loading.value && n === m(S).messages.value.length - 1) }), (t, n) => (u(), r("p", {
|
|
452
515
|
key: n,
|
|
453
516
|
class: "seer-chat__line"
|
|
454
517
|
}, [(u(!0), r(e, null, f(t, (t, n) => (u(), r(e, { key: n }, [t.kind === "link" ? (u(), r("a", {
|
|
@@ -457,82 +520,115 @@ var V = {
|
|
|
457
520
|
href: t.href,
|
|
458
521
|
target: "_blank",
|
|
459
522
|
rel: "noopener noreferrer"
|
|
460
|
-
}, p(t.label), 9,
|
|
523
|
+
}, p(t.label), 9, U)) : t.kind === "image" ? (u(), r("button", {
|
|
461
524
|
key: 1,
|
|
462
525
|
type: "button",
|
|
463
526
|
class: "seer-chat__image-button",
|
|
464
527
|
"aria-label": `放大查看${t.alt}`,
|
|
465
|
-
onClick: (e) =>
|
|
528
|
+
onClick: (e) => P(t.href, t.alt)
|
|
466
529
|
}, [i("img", {
|
|
467
530
|
class: "seer-chat__image",
|
|
468
531
|
src: t.href,
|
|
469
532
|
alt: t.alt,
|
|
470
533
|
loading: "lazy"
|
|
471
|
-
}, null, 8,
|
|
472
|
-
m(S).loading.value ? (u(), r("p",
|
|
473
|
-
m(S).error.value || x.value ? (u(), r("p",
|
|
474
|
-
m(S).handoffRequested.value ? (u(), r("p",
|
|
534
|
+
}, null, 8, G)], 8, W)) : t.kind === "strong" ? (u(), r("strong", K, p(t.value), 1)) : t.kind === "price" ? (u(), r("span", q, p(t.value), 1)) : (u(), r("span", J, p(t.value), 1))], 64))), 128))]))), 128))])], 2))), 128))]),
|
|
535
|
+
m(S).loading.value ? (u(), r("p", Y, "正在回复...")) : n("", !0),
|
|
536
|
+
m(S).error.value || x.value ? (u(), r("p", ie, p(x.value || m(S).error.value), 1)) : n("", !0),
|
|
537
|
+
m(S).handoffRequested.value ? (u(), r("p", ae, " 建议转人工:请留下联系方式或等待客服接入。 ")) : n("", !0),
|
|
475
538
|
i("form", {
|
|
476
539
|
class: "seer-chat__form",
|
|
477
|
-
onSubmit: v(
|
|
540
|
+
onSubmit: v(I, ["prevent"])
|
|
478
541
|
}, [
|
|
479
|
-
o[
|
|
542
|
+
o[8] ||= i("label", {
|
|
480
543
|
class: "seer-chat__label",
|
|
481
544
|
for: "seer-chat-input"
|
|
482
545
|
}, "问题", -1),
|
|
546
|
+
m(S).attachments.value.length > 0 ? (u(), r("ul", oe, [(u(!0), r(e, null, f(m(S).attachments.value, (e) => (u(), r("li", {
|
|
547
|
+
key: e.fileId,
|
|
548
|
+
class: "seer-chat__attachment"
|
|
549
|
+
}, [i("span", se, p(e.filename), 1), i("button", {
|
|
550
|
+
type: "button",
|
|
551
|
+
class: "seer-chat__attachment-remove",
|
|
552
|
+
"aria-label": `移除附件${e.filename}`,
|
|
553
|
+
onClick: (t) => m(S).removeAttachment(e.fileId)
|
|
554
|
+
}, " × ", 8, ce)]))), 128))])) : n("", !0),
|
|
483
555
|
g(i("textarea", {
|
|
484
556
|
id: "seer-chat-input",
|
|
485
557
|
"onUpdate:modelValue": o[1] ||= (e) => s.value = e,
|
|
486
558
|
placeholder: a.placeholder,
|
|
487
559
|
disabled: m(S).loading.value || b.value,
|
|
488
560
|
rows: "3",
|
|
489
|
-
onKeydown: _(v(
|
|
490
|
-
}, null, 40,
|
|
491
|
-
i("div",
|
|
492
|
-
i("span",
|
|
493
|
-
|
|
494
|
-
|
|
561
|
+
onKeydown: _(v(I, ["exact", "prevent"]), ["enter"])
|
|
562
|
+
}, null, 40, le), [[h, s.value]]),
|
|
563
|
+
i("div", ue, [
|
|
564
|
+
i("span", de, p(y.value ? `正在录音,最长 ${m(S).maxRecordingSeconds} 秒` : b.value ? "正在识别语音..." : m(S).uploading.value ? "正在上传附件..." : "Enter 发送 · Shift+Enter 换行"), 1),
|
|
565
|
+
m(S).uploadEnabled ? (u(), r(e, { key: 0 }, [i("input", {
|
|
566
|
+
ref_key: "fileInput",
|
|
567
|
+
ref: C,
|
|
568
|
+
class: "seer-chat__file-input",
|
|
569
|
+
type: "file",
|
|
570
|
+
multiple: "",
|
|
571
|
+
accept: ve,
|
|
572
|
+
onChange: T
|
|
573
|
+
}, null, 544), i("button", {
|
|
574
|
+
type: "button",
|
|
575
|
+
class: "seer-chat__attach-button",
|
|
576
|
+
disabled: m(S).loading.value || m(S).uploading.value,
|
|
577
|
+
"aria-label": "上传附件",
|
|
578
|
+
title: "上传下单模板、实物图片等",
|
|
579
|
+
onClick: o[2] ||= (e) => C.value?.click()
|
|
580
|
+
}, [...o[5] ||= [i("svg", {
|
|
581
|
+
viewBox: "0 0 24 24",
|
|
582
|
+
width: "20",
|
|
583
|
+
height: "20",
|
|
584
|
+
"aria-hidden": "true"
|
|
585
|
+
}, [i("path", {
|
|
586
|
+
fill: "currentColor",
|
|
587
|
+
d: "M16.5 6.5v10a4.5 4.5 0 0 1-9 0V5a3 3 0 0 1 6 0v10.5a1.5 1.5 0 0 1-3 0V6.5H9v9a3 3 0 0 0 6 0V5a4.5 4.5 0 0 0-9 0v11.5a6 6 0 0 0 12 0v-10h-1.5Z"
|
|
588
|
+
})], -1)]], 8, fe)], 64)) : n("", !0),
|
|
589
|
+
E.value ? (u(), r("button", {
|
|
590
|
+
key: 1,
|
|
495
591
|
type: "button",
|
|
496
592
|
class: c(["seer-chat__mic-button", { "seer-chat__mic-button--recording": y.value }]),
|
|
497
593
|
disabled: b.value || m(S).loading.value && !y.value,
|
|
498
594
|
"aria-label": y.value ? "停止录音" : "开始语音输入",
|
|
499
595
|
title: y.value ? "停止录音" : "语音输入",
|
|
500
|
-
onClick:
|
|
501
|
-
}, [y.value ? (u(), r("span",
|
|
596
|
+
onClick: R
|
|
597
|
+
}, [y.value ? (u(), r("span", me)) : (u(), r("svg", he, [...o[6] ||= [i("path", {
|
|
502
598
|
fill: "currentColor",
|
|
503
599
|
d: "M12 14a3 3 0 0 0 3-3V5a3 3 0 1 0-6 0v6a3 3 0 0 0 3 3Zm5-3a1 1 0 1 1 2 0 7 7 0 0 1-6 6.93V20h3a1 1 0 1 1 0 2H8a1 1 0 1 1 0-2h3v-2.07A7 7 0 0 1 5 11a1 1 0 1 1 2 0 5 5 0 0 0 10 0Z"
|
|
504
|
-
}, null, -1)]]))], 10,
|
|
600
|
+
}, null, -1)]]))], 10, pe)) : n("", !0),
|
|
505
601
|
m(S).loading.value ? (u(), r("button", {
|
|
506
|
-
key:
|
|
602
|
+
key: 2,
|
|
507
603
|
type: "button",
|
|
508
604
|
class: "seer-chat__stop-button",
|
|
509
|
-
onClick: o[
|
|
605
|
+
onClick: o[3] ||= (e) => m(S).abort()
|
|
510
606
|
}, " 停止 ")) : n("", !0),
|
|
511
607
|
i("button", {
|
|
512
608
|
class: "seer-chat__send-button",
|
|
513
609
|
type: "submit",
|
|
514
|
-
disabled: !
|
|
515
|
-
}, [...o[
|
|
610
|
+
disabled: !w.value
|
|
611
|
+
}, [...o[7] ||= [i("span", null, "发送", -1), i("span", { "aria-hidden": "true" }, "↵", -1)]], 8, ge)
|
|
516
612
|
])
|
|
517
613
|
], 32),
|
|
518
|
-
|
|
614
|
+
M.value ? (u(), r("div", {
|
|
519
615
|
key: 3,
|
|
520
616
|
class: "seer-chat__lightbox",
|
|
521
617
|
role: "dialog",
|
|
522
618
|
"aria-modal": "true",
|
|
523
|
-
"aria-label":
|
|
524
|
-
onClick:
|
|
619
|
+
"aria-label": M.value.alt,
|
|
620
|
+
onClick: F
|
|
525
621
|
}, [i("button", {
|
|
526
622
|
type: "button",
|
|
527
623
|
class: "seer-chat__lightbox-close",
|
|
528
624
|
"aria-label": "关闭",
|
|
529
|
-
onClick:
|
|
625
|
+
onClick: F
|
|
530
626
|
}, " × "), i("img", {
|
|
531
627
|
class: "seer-chat__lightbox-image",
|
|
532
|
-
src:
|
|
533
|
-
alt:
|
|
534
|
-
}, null, 8,
|
|
628
|
+
src: M.value.src,
|
|
629
|
+
alt: M.value.alt
|
|
630
|
+
}, null, 8, _e)], 8, X)) : n("", !0)
|
|
535
631
|
]));
|
|
536
632
|
}
|
|
537
|
-
}), [["__scopeId", "data-v-
|
|
633
|
+
}), [["__scopeId", "data-v-adaeb672"]]);
|
|
538
634
|
export { Z as SeerChat, z as SeerChatPlugin, y as createSeerClient, F as linkAnchorLabel, L as toContentLines, I as toContentSegments, B as useSeerChat };
|
package/dist/plugin.d.ts
CHANGED
|
@@ -4,6 +4,8 @@ export interface SeerChatPluginOptions extends SeerClientOptions {
|
|
|
4
4
|
stream?: boolean;
|
|
5
5
|
voiceEnabled?: boolean;
|
|
6
6
|
maxRecordingSeconds?: number;
|
|
7
|
+
/** 显示附件按钮(下单模板、实物图片等);默认跟随 uploadEndpoint 是否可用。 */
|
|
8
|
+
uploadEnabled?: boolean;
|
|
7
9
|
}
|
|
8
10
|
export declare const seerChatOptionsKey: InjectionKey<SeerChatPluginOptions>;
|
|
9
11
|
export declare const SeerChatPlugin: {
|
package/dist/useSeerChat.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type SeerChatMessage } from './client';
|
|
1
|
+
import { type SeerChatMessage, type SeerUploadedFile } from './client';
|
|
2
2
|
import { type SeerChatPluginOptions } from './plugin';
|
|
3
3
|
export interface UseSeerChatOptions extends Partial<SeerChatPluginOptions> {
|
|
4
4
|
endpoint?: string;
|
|
@@ -21,6 +21,23 @@ export declare function useSeerChat(localOptions?: UseSeerChatOptions): {
|
|
|
21
21
|
transcriptionEnabled: boolean;
|
|
22
22
|
maxRecordingSeconds: number;
|
|
23
23
|
transcribe: (audio: Blob, filename: string, callbacks?: import("./client").SeerTranscriptionCallbacks) => Promise<import("./client").SeerTranscriptionResult>;
|
|
24
|
+
uploadEnabled: boolean;
|
|
25
|
+
attachments: import("vue").Ref<{
|
|
26
|
+
fileId: string;
|
|
27
|
+
filename: string;
|
|
28
|
+
kind: "spreadsheet" | "image" | "document" | string;
|
|
29
|
+
contentType: string;
|
|
30
|
+
size: number;
|
|
31
|
+
}[], SeerUploadedFile[] | {
|
|
32
|
+
fileId: string;
|
|
33
|
+
filename: string;
|
|
34
|
+
kind: "spreadsheet" | "image" | "document" | string;
|
|
35
|
+
contentType: string;
|
|
36
|
+
size: number;
|
|
37
|
+
}[]>;
|
|
38
|
+
uploading: import("vue").Ref<boolean, boolean>;
|
|
39
|
+
attach: (file: File) => Promise<void>;
|
|
40
|
+
removeAttachment: (fileId: string) => void;
|
|
24
41
|
send: (content: string) => Promise<void>;
|
|
25
42
|
reset: () => void;
|
|
26
43
|
abort: () => void;
|