@seer-ai/seer-vue 0.1.0-beta.11 → 0.1.0-beta.12
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 +22 -0
- package/dist/client.d.ts +34 -0
- package/dist/components/SeerChat.vue.d.ts +1 -0
- package/dist/components/SeerOrderCard.vue.d.ts +13 -0
- package/dist/content.d.ts +6 -0
- package/dist/index.css +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +319 -225
- package/dist/useSeerChat.d.ts +72 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -60,6 +60,28 @@ app.use(SeerChatPlugin, {
|
|
|
60
60
|
|
|
61
61
|
插件在建会话时发 `X-Seer-Org-Owner`。seer 不校验这个值,只用于补报价客户编码,不参与订单归属。
|
|
62
62
|
|
|
63
|
+
## Order estimate card
|
|
64
|
+
|
|
65
|
+
客户发下单模板、估价成功后,回复附带 `order_card`,`<SeerChat>` 在消息下方画「物流费用智能核算」卡片(渠道、
|
|
66
|
+
官网指导价 / 补贴价、计费重、各项费用、已补贴、预估总金额、「提交订单」按钮),正文里同一份费用的文字版自动去掉。
|
|
67
|
+
自定义 UI:助手消息上有 `message.orderCard`,可用导出的 `<SeerOrderCard :card="card" @submit="send" />`,
|
|
68
|
+
正文用 `withoutCardText(content, card)` 去掉重复的文字版。`toContentLines()` 会把行首「标签:」切成 `label` 段。
|
|
69
|
+
|
|
70
|
+
## Ordering with the customer's login token (`sellerToken`)
|
|
71
|
+
|
|
72
|
+
和 `orgOwner` 同一处取已登录用户的多发货登录 token 传进来,客户在聊天里回「确认下单」后,seer 用它调多发货
|
|
73
|
+
`/seller/order/create` 直接下单并回订单号;不传就转客服下单。插件把它放在每条聊天请求的请求头
|
|
74
|
+
`X-DFH-Seller-Token`(不进会话 token,不发给上传接口)。登录态会变时传函数,每次发消息都现取。
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
app.use(SeerChatPlugin, {
|
|
78
|
+
sessionEndpoint: 'https://seer.example.com/v1/browser/session',
|
|
79
|
+
endpoint: 'https://seer.example.com/v1/browser/chat/completions',
|
|
80
|
+
orgOwner: () => currentUser.value?.orgOwner,
|
|
81
|
+
sellerToken: () => currentUser.value?.token,
|
|
82
|
+
})
|
|
83
|
+
```
|
|
84
|
+
|
|
63
85
|
## Use custom UI
|
|
64
86
|
|
|
65
87
|
自定义 UI 时**不要**直接把 `message.content` 当纯文本渲染——回复里的下载/截图链接是裸
|
package/dist/client.d.ts
CHANGED
|
@@ -3,6 +3,34 @@ export interface SeerChatMessage {
|
|
|
3
3
|
role: SeerChatRole;
|
|
4
4
|
content: string;
|
|
5
5
|
name?: string;
|
|
6
|
+
/** 助手消息附带的下单估价卡片;只用于显示,不随历史发回服务端。 */
|
|
7
|
+
orderCard?: SeerOrderCard;
|
|
8
|
+
}
|
|
9
|
+
export interface SeerOrderCardItem {
|
|
10
|
+
label: string;
|
|
11
|
+
value: string;
|
|
12
|
+
/** 有补贴价时官网指导价划线 */
|
|
13
|
+
struck?: boolean;
|
|
14
|
+
detail?: string;
|
|
15
|
+
}
|
|
16
|
+
/** 「物流费用智能核算」卡片:行已经按多发货卖家端「下单详情」规则排好,照着画就行。 */
|
|
17
|
+
export interface SeerOrderCard {
|
|
18
|
+
type: 'order_estimate';
|
|
19
|
+
title: string;
|
|
20
|
+
channel_name: string;
|
|
21
|
+
rows: SeerOrderCardItem[];
|
|
22
|
+
subsidy: SeerOrderCardItem | null;
|
|
23
|
+
coupon: SeerOrderCardItem | null;
|
|
24
|
+
total: SeerOrderCardItem;
|
|
25
|
+
note: string;
|
|
26
|
+
/** 正文里同一份费用的文字版;画了卡片时从正文里去掉它(`withoutCardText`),免得显示两遍 */
|
|
27
|
+
panel_text: string;
|
|
28
|
+
/** 能下单时有:按钮文案和点了要发的消息(「确认下单」);不能下单时为 null,看 blocked_reason。 */
|
|
29
|
+
action: {
|
|
30
|
+
label: string;
|
|
31
|
+
message: string;
|
|
32
|
+
} | null;
|
|
33
|
+
blocked_reason: string;
|
|
6
34
|
}
|
|
7
35
|
export type SeerOrgOwner = string | (() => string | undefined);
|
|
8
36
|
export interface SeerClientOptions {
|
|
@@ -14,6 +42,11 @@ export interface SeerClientOptions {
|
|
|
14
42
|
challengeTokenProvider?: () => Promise<string>;
|
|
15
43
|
/** 已登录用户的多发货 orgOwner;报价时自动当作客户编码。登录态会变时传函数。 */
|
|
16
44
|
orgOwner?: SeerOrgOwner;
|
|
45
|
+
/**
|
|
46
|
+
* 已登录用户的多发货登录 token(和 orgOwner 同一处取)。随每条聊天消息放在请求头
|
|
47
|
+
* X-DFH-Seller-Token,客户确认后 AI 用它估价和下单;不传时确认下单转客服。登录态会变时传函数。
|
|
48
|
+
*/
|
|
49
|
+
sellerToken?: SeerOrgOwner;
|
|
17
50
|
model?: string;
|
|
18
51
|
fetcher?: typeof fetch;
|
|
19
52
|
now?: () => number;
|
|
@@ -50,6 +83,7 @@ export interface SeerChatResult {
|
|
|
50
83
|
citations: string[];
|
|
51
84
|
handoffRequested: boolean;
|
|
52
85
|
finishReason?: string;
|
|
86
|
+
orderCard?: SeerOrderCard;
|
|
53
87
|
}
|
|
54
88
|
export interface SeerClient {
|
|
55
89
|
transcriptionEnabled: boolean;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { SeerOrderCard } from "../client";
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
card: SeerOrderCard;
|
|
4
|
+
/** 不是最新一张卡、或正在回复时,按钮不可点 */
|
|
5
|
+
disabled?: boolean;
|
|
6
|
+
};
|
|
7
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
8
|
+
submit: (message: string) => any;
|
|
9
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
10
|
+
onSubmit?: ((message: string) => any) | undefined;
|
|
11
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
12
|
+
declare const _default: typeof __VLS_export;
|
|
13
|
+
export default _default;
|
package/dist/content.d.ts
CHANGED
|
@@ -15,6 +15,9 @@ export type ContentSegment = {
|
|
|
15
15
|
} | {
|
|
16
16
|
kind: 'strong';
|
|
17
17
|
value: string;
|
|
18
|
+
} | {
|
|
19
|
+
kind: 'label';
|
|
20
|
+
value: string;
|
|
18
21
|
};
|
|
19
22
|
export interface ContentOptions {
|
|
20
23
|
complete?: boolean;
|
|
@@ -22,3 +25,6 @@ export interface ContentOptions {
|
|
|
22
25
|
export declare function linkAnchorLabel(prefix: string): string | null;
|
|
23
26
|
export declare function toContentSegments(content: string, options?: ContentOptions): ContentSegment[];
|
|
24
27
|
export declare function toContentLines(content: string, options?: ContentOptions): ContentSegment[][];
|
|
28
|
+
export declare function withoutCardText(content: string, card?: {
|
|
29
|
+
panel_text?: string;
|
|
30
|
+
} | null): string;
|
package/dist/index.css
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
.seer-chat[data-v-
|
|
1
|
+
.seer-order-card[data-v-17d9e82e]{background:linear-gradient(#eef1fb,#fff 56px);border:1px solid #7f8faa38;border-radius:16px;margin-top:8px;padding:14px 14px 12px}.seer-order-card__title[data-v-17d9e82e]{color:#1d2129;margin:0 0 10px;font-size:18px;font-weight:800}.seer-order-card__panel[data-v-17d9e82e]{background:#fff;border-radius:12px;gap:10px;padding:12px;display:grid}.seer-order-card__channel[data-v-17d9e82e]{color:#1d2129;margin:0;font-size:14px;font-weight:600}.seer-order-card__rows[data-v-17d9e82e]{border:1px solid #e5e6eb;border-radius:10px;margin:0;overflow:hidden}.seer-order-card__row[data-v-17d9e82e]{grid-template-columns:1fr auto;gap:12px;padding:9px 12px;display:grid}.seer-order-card__row+.seer-order-card__row[data-v-17d9e82e]{border-top:1px solid #e5e6eb}.seer-order-card__label[data-v-17d9e82e]{color:#4e5969;font-weight:700}.seer-order-card__value[data-v-17d9e82e]{color:#1d2129;text-align:right;margin:0;font-weight:400}.seer-order-card__value--struck[data-v-17d9e82e]{text-decoration:line-through}.seer-order-card__subsidy[data-v-17d9e82e]{color:#c4161c;border:1px solid #c4161c;border-radius:10px;gap:2px;padding:8px 12px;font-size:13px;display:grid}.seer-order-card__total[data-v-17d9e82e]{justify-content:space-between;align-items:baseline;display:flex}.seer-order-card__total-value[data-v-17d9e82e]{color:#1d2129;font-size:20px;font-weight:800}.seer-order-card__submit[data-v-17d9e82e]{color:#1d2129;cursor:pointer;background:#fc0;border:0;border-radius:10px;padding:11px 0;font-size:16px;font-weight:700}.seer-order-card__submit[data-v-17d9e82e]:disabled{cursor:not-allowed;opacity:.5}.seer-order-card__blocked[data-v-17d9e82e]{color:#c4161c;margin:0;font-size:13px}.seer-chat[data-v-d821ceaf]{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-d821ceaf]{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-d821ceaf]{letter-spacing:-.03em;margin:0;font-size:22px}.seer-chat__header p[data-v-d821ceaf],.seer-chat__empty[data-v-d821ceaf],.seer-chat__status[data-v-d821ceaf]{color:#5f6f89;margin:4px 0 0;font-size:14px}.seer-chat__header p[data-v-d821ceaf]{color:#ffffffb8;max-width:34ch}.seer-chat__messages[data-v-d821ceaf]{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-d821ceaf]{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-d821ceaf]{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-d821ceaf]{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-d821ceaf]{opacity:.75;font-size:12px;font-weight:700}.seer-chat__body[data-v-d821ceaf]{flex-direction:column;display:flex}.seer-chat__line[data-v-d821ceaf]{white-space:pre-wrap;overflow-wrap:anywhere;margin:0}.seer-chat__line[data-v-d821ceaf]:not(:last-child){margin-bottom:5px}.seer-chat__line[data-v-d821ceaf]:empty{height:7px}.seer-chat__strong[data-v-d821ceaf]{font-weight:700}.seer-chat__message--assistant .seer-chat__line[data-v-d821ceaf]:has(.seer-chat__label-text){color:#1d2129}.seer-chat__label-text[data-v-d821ceaf]{color:#4e5969;font-weight:700}.seer-chat__message--user .seer-chat__label-text[data-v-d821ceaf]{color:inherit}.seer-chat__price[data-v-d821ceaf]{color:#e0331d;font-weight:600}.seer-chat__message--user .seer-chat__price[data-v-d821ceaf]{color:#ffe2dc}.seer-chat__link[data-v-d821ceaf]{color:#1f5eff;text-underline-offset:2px;overflow-wrap:anywhere;font-weight:600;text-decoration:underline}.seer-chat__link[data-v-d821ceaf]:hover{color:#173fb3}.seer-chat__message--user .seer-chat__link[data-v-d821ceaf]{color:#fff}.seer-chat__image-button[data-v-d821ceaf]{cursor:zoom-in;background:0 0;border:0;padding:0;display:block}.seer-chat__image-button[data-v-d821ceaf]:not(:disabled):hover{transform:none}.seer-chat__image[data-v-d821ceaf]{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-d821ceaf]{filter:brightness(.96)}.seer-chat__lightbox[data-v-d821ceaf]{z-index:1000;cursor:zoom-out;background:#0a0f1ad1;place-items:center;padding:32px;animation:.14s seer-chat__fade-in-d821ceaf;display:grid;position:fixed;inset:0}.seer-chat__lightbox-image[data-v-d821ceaf]{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-d821ceaf]{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-d821ceaf]:not(:disabled):hover{background:#ffffff3d}@keyframes seer-chat__fade-in-d821ceaf{0%{opacity:0}to{opacity:1}}.seer-chat__error[data-v-d821ceaf],.seer-chat__handoff[data-v-d821ceaf]{border-radius:14px;margin:0 18px;padding:10px 12px}.seer-chat__error[data-v-d821ceaf]{color:#8a1f11;background:#fff0ed}.seer-chat__handoff[data-v-d821ceaf]{color:#704600;background:#fff7db}.seer-chat__form[data-v-d821ceaf]{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-d821ceaf]{font-size:13px;font-weight:700}.seer-chat textarea[data-v-d821ceaf]{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-d821ceaf]{color:inherit;cursor:pointer;border:0;font-weight:700;transition:transform .16s,box-shadow .16s,opacity .16s}.seer-chat button[data-v-d821ceaf]:not(:disabled):hover{transform:translateY(-1px)}.seer-chat button[data-v-d821ceaf]:disabled{cursor:not-allowed;opacity:.5}.seer-chat button[data-v-d821ceaf]:focus-visible,.seer-chat textarea[data-v-d821ceaf]:focus-visible{border-color:#1f5eff6b;box-shadow:0 0 0 4px #1f5eff21}.seer-chat__clear-button[data-v-d821ceaf]{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-d821ceaf]:not(:disabled):hover{color:#fff;box-shadow:none;background:#ffffff1a}.seer-chat__stop-button[data-v-d821ceaf]{color:#6c3b12;background:#fff1df;border-radius:12px;padding:8px 11px;font-size:12px}.seer-chat__mic-button[data-v-d821ceaf],.seer-chat__attach-button[data-v-d821ceaf]{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-d821ceaf]:not(:disabled):hover,.seer-chat__attach-button[data-v-d821ceaf]:not(:disabled):hover{background:#dfe8ff}.seer-chat__file-input[data-v-d821ceaf]{display:none}.seer-chat__attachments[data-v-d821ceaf]{flex-wrap:wrap;gap:6px;margin:0 0 8px;padding:0;list-style:none;display:flex}.seer-chat__attachment[data-v-d821ceaf]{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-d821ceaf]{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.seer-chat__attachment-remove[data-v-d821ceaf]{color:#4b5878;background:0 0;border-radius:50%;width:20px;height:20px;padding:0;line-height:1}.seer-chat__attachment-remove[data-v-d821ceaf]:hover{background:#dfe8ff}.seer-chat__mic-button--recording[data-v-d821ceaf]{color:#fff;background:#d9342b;animation:1.4s ease-in-out infinite seer-chat__recording-pulse-d821ceaf;box-shadow:0 0 0 5px #d9342b24}.seer-chat__mic-button--recording[data-v-d821ceaf]:not(:disabled):hover{background:#bd271f}.seer-chat__stop-icon[data-v-d821ceaf]{background:currentColor;border-radius:3px;width:12px;height:12px}@keyframes seer-chat__recording-pulse-d821ceaf{50%{box-shadow:0 0 0 9px #d9342b14}}.seer-chat__send-button[data-v-d821ceaf]{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-d821ceaf]:not(:disabled):hover{box-shadow:0 14px 28px #1f5eff47}.seer-chat__hint[data-v-d821ceaf]{color:#7a879a;margin-right:auto;font-size:12px}.seer-chat__composer-footer[data-v-d821ceaf]{justify-content:flex-end;align-items:center;gap:8px;display:flex}
|
|
2
2
|
/*$vite$:1*/
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
export { createSeerClient } from './client';
|
|
2
|
-
export { linkAnchorLabel, toContentLines, toContentSegments, type ContentOptions, type ContentSegment, } from './content';
|
|
2
|
+
export { linkAnchorLabel, toContentLines, toContentSegments, withoutCardText, type ContentOptions, type ContentSegment, } from './content';
|
|
3
3
|
export { SeerChatPlugin } from './plugin';
|
|
4
4
|
export { useSeerChat } from './useSeerChat';
|
|
5
5
|
export { default as SeerChat } from './components/SeerChat.vue';
|
|
6
|
-
export
|
|
6
|
+
export { default as SeerOrderCard } from './components/SeerOrderCard.vue';
|
|
7
|
+
export type { SeerChatCallbacks, SeerChatMessage, SeerChatRequest, SeerChatResult, SeerChatRole, SeerClient, SeerClientOptions, SeerOrderCard as SeerOrderCardData, SeerOrderCardItem, SeerTranscriptionCallbacks, SeerTranscriptionResult, SeerUploadedFile, } from './client';
|
|
7
8
|
export type { SeerChatPluginOptions } from './plugin';
|
|
8
9
|
export type { UseSeerChatOptions } from './useSeerChat';
|
package/dist/index.js
CHANGED
|
@@ -1,28 +1,37 @@
|
|
|
1
|
-
import { Fragment as e, computed as t,
|
|
1
|
+
import { Fragment as e, computed as t, createBlock as n, createCommentVNode as r, createElementBlock as i, createElementVNode as a, defineComponent as o, hasInjectionContext as s, inject as c, normalizeClass as l, onBeforeUnmount as u, openBlock as d, ref as f, renderList as p, toDisplayString as m, unref as h, vModelText as g, withDirectives as _, withKeys as v, withModifiers as y } from "vue";
|
|
2
2
|
// src/client.ts
|
|
3
|
-
function
|
|
4
|
-
let t = e.fetcher ?? fetch, n = e.model ?? "seer", r =
|
|
3
|
+
function b(e) {
|
|
4
|
+
let t = e.fetcher ?? fetch, n = e.model ?? "seer", r = S(e.endpoint, e.transcriptionEndpoint, "/v1/browser/audio/transcriptions"), i = S(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
7
|
uploadEnabled: !!i,
|
|
8
8
|
async chat(r, i = {}) {
|
|
9
9
|
let a = r.stream ?? !1, o = await l(), s = { "Content-Type": "application/json" };
|
|
10
10
|
o && (s.Authorization = `Bearer ${o}`);
|
|
11
|
-
let c =
|
|
11
|
+
let c = x(e.sellerToken);
|
|
12
|
+
c && (s["X-DFH-Seller-Token"] = c);
|
|
13
|
+
let u = await t(e.endpoint, {
|
|
12
14
|
method: "POST",
|
|
13
15
|
headers: s,
|
|
14
16
|
signal: i.signal,
|
|
15
17
|
body: JSON.stringify({
|
|
16
18
|
model: r.model ?? n,
|
|
17
|
-
messages: r.messages,
|
|
19
|
+
messages: r.messages.map(({ role: e, content: t, name: n }) => n ? {
|
|
20
|
+
role: e,
|
|
21
|
+
content: t,
|
|
22
|
+
name: n
|
|
23
|
+
} : {
|
|
24
|
+
role: e,
|
|
25
|
+
content: t
|
|
26
|
+
}),
|
|
18
27
|
stream: a,
|
|
19
28
|
conversation_id: r.conversationId,
|
|
20
29
|
metadata: r.metadata,
|
|
21
30
|
...r.attachments?.length ? { attachments: r.attachments } : {}
|
|
22
31
|
})
|
|
23
32
|
});
|
|
24
|
-
if (!
|
|
25
|
-
return a ?
|
|
33
|
+
if (!u.ok) throw Error(await E(u));
|
|
34
|
+
return a ? w(u, i.onDelta) : C(await u.json());
|
|
26
35
|
},
|
|
27
36
|
async transcribe(e, n, i = {}) {
|
|
28
37
|
if (!r) throw Error("Seer audio transcription endpoint is not configured");
|
|
@@ -36,7 +45,7 @@ function y(e) {
|
|
|
36
45
|
signal: i.signal,
|
|
37
46
|
body: s
|
|
38
47
|
});
|
|
39
|
-
if (!c.ok) throw Error(await
|
|
48
|
+
if (!c.ok) throw Error(await E(c));
|
|
40
49
|
let u = await c.json(), d = typeof u.text == "string" ? u.text.trim() : "";
|
|
41
50
|
if (!d) throw Error("Seer audio transcription returned empty text");
|
|
42
51
|
return { text: d };
|
|
@@ -53,7 +62,7 @@ function y(e) {
|
|
|
53
62
|
signal: r.signal,
|
|
54
63
|
body: s
|
|
55
64
|
});
|
|
56
|
-
if (!c.ok) throw Error(await
|
|
65
|
+
if (!c.ok) throw Error(await E(c));
|
|
57
66
|
let u = await c.json();
|
|
58
67
|
if (!u.file_id) throw Error("Seer file upload returned no file_id");
|
|
59
68
|
return {
|
|
@@ -67,13 +76,13 @@ function y(e) {
|
|
|
67
76
|
};
|
|
68
77
|
async function l() {
|
|
69
78
|
if (!e.sessionEndpoint) return;
|
|
70
|
-
let n = a(), r =
|
|
79
|
+
let n = a(), r = x(e.orgOwner);
|
|
71
80
|
if (o && c === r && s - 30 > n) return o;
|
|
72
81
|
let i = await t(e.sessionEndpoint, {
|
|
73
82
|
method: "GET",
|
|
74
83
|
headers: await u(r)
|
|
75
84
|
});
|
|
76
|
-
if (!i.ok) throw Error(await
|
|
85
|
+
if (!i.ok) throw Error(await E(i));
|
|
77
86
|
let l = await i.json();
|
|
78
87
|
return o = l.token, s = l.expires_at, c = r, o;
|
|
79
88
|
}
|
|
@@ -82,57 +91,59 @@ function y(e) {
|
|
|
82
91
|
return e.challengeTokenProvider && (n["X-Seer-Challenge-Token"] = await e.challengeTokenProvider()), t && (n["X-Seer-Org-Owner"] = t), n;
|
|
83
92
|
}
|
|
84
93
|
}
|
|
85
|
-
function
|
|
94
|
+
function x(e) {
|
|
86
95
|
return (typeof e == "function" ? e() : e)?.trim() || void 0;
|
|
87
96
|
}
|
|
88
|
-
function
|
|
97
|
+
function S(e, t, n) {
|
|
89
98
|
if (t !== void 0) return t || void 0;
|
|
90
99
|
if (e.endsWith("/v1/browser/chat/completions")) return `${e.slice(0, -28)}${n}`;
|
|
91
100
|
}
|
|
92
|
-
function
|
|
101
|
+
function C(e) {
|
|
93
102
|
let t = e.choices?.[0];
|
|
94
103
|
return {
|
|
95
104
|
content: t?.message?.content ?? t?.delta?.content ?? "",
|
|
96
105
|
conversationId: e.conversation_id,
|
|
97
106
|
citations: e.citations ?? [],
|
|
98
107
|
handoffRequested: e.handoff_requested ?? !1,
|
|
99
|
-
finishReason: t?.finish_reason
|
|
108
|
+
finishReason: t?.finish_reason,
|
|
109
|
+
...e.order_card ? { orderCard: e.order_card } : {}
|
|
100
110
|
};
|
|
101
111
|
}
|
|
102
|
-
async function
|
|
103
|
-
if (!e.body) return
|
|
104
|
-
let n = e.body.getReader(), r = new TextDecoder(), i = "", a = "", o, s = [], c = !1, l, u = !1;
|
|
112
|
+
async function w(e, t) {
|
|
113
|
+
if (!e.body) return C({});
|
|
114
|
+
let n = e.body.getReader(), r = new TextDecoder(), i = "", a = "", o, s = [], c = !1, l, u, d = !1;
|
|
105
115
|
for (;;) {
|
|
106
|
-
let { done: e, value:
|
|
116
|
+
let { done: e, value: f } = await n.read();
|
|
107
117
|
if (e) break;
|
|
108
|
-
i += r.decode(
|
|
109
|
-
let
|
|
110
|
-
i =
|
|
111
|
-
for (let e of
|
|
112
|
-
let n =
|
|
118
|
+
i += r.decode(f, { stream: !0 });
|
|
119
|
+
let p = i.split("\n\n");
|
|
120
|
+
i = p.pop() ?? "";
|
|
121
|
+
for (let e of p) {
|
|
122
|
+
let n = T(e);
|
|
113
123
|
if (!n) continue;
|
|
114
124
|
if (n === "[DONE]") {
|
|
115
|
-
|
|
125
|
+
d = !0;
|
|
116
126
|
continue;
|
|
117
127
|
}
|
|
118
|
-
let r = JSON.parse(n), i = r.choices?.[0],
|
|
119
|
-
|
|
128
|
+
let r = JSON.parse(n), i = r.choices?.[0], f = i?.delta?.content ?? i?.message?.content ?? "";
|
|
129
|
+
f && (a += f, t?.(f)), o = r.conversation_id ?? o, s = r.citations ?? s, c = r.handoff_requested ?? c, l = i?.finish_reason ?? l, u = r.order_card ?? u;
|
|
120
130
|
}
|
|
121
131
|
}
|
|
122
|
-
if (!
|
|
132
|
+
if (!d) throw Error("seer chat stream ended before [DONE]");
|
|
123
133
|
return {
|
|
124
134
|
content: a,
|
|
125
135
|
conversationId: o,
|
|
126
136
|
citations: s,
|
|
127
137
|
handoffRequested: c,
|
|
128
|
-
finishReason: l
|
|
138
|
+
finishReason: l,
|
|
139
|
+
...u ? { orderCard: u } : {}
|
|
129
140
|
};
|
|
130
141
|
}
|
|
131
|
-
function
|
|
142
|
+
function T(e) {
|
|
132
143
|
let t = e.split("\n").map((e) => e.trim()).filter((e) => e.startsWith("data:")).map((e) => e.slice(5).trim());
|
|
133
144
|
return t.length === 0 ? null : t.join("\n");
|
|
134
145
|
}
|
|
135
|
-
async function
|
|
146
|
+
async function E(e) {
|
|
136
147
|
let t = e.statusText || "unknown error";
|
|
137
148
|
try {
|
|
138
149
|
let n = await e.json();
|
|
@@ -144,12 +155,12 @@ async function T(e) {
|
|
|
144
155
|
return `seer chat request failed with status ${e.status}: ${t}`;
|
|
145
156
|
}
|
|
146
157
|
// src/content.ts
|
|
147
|
-
var
|
|
148
|
-
function
|
|
158
|
+
var D = /https?:\/\/[^\s)\u3000-\u303f\u4e00-\u9fff\uff00-\uffef]+/g, O = /\.(png|jpe?g|gif|webp|bmp|svg)$/i, k = "链接生成中…", A = "图片加载中…", j = /* @__PURE__ */ RegExp("(单价\\s*\\d[\\d.]*\\s*[A-Za-z]+\\/(?:kg|方))|(按当前信息为您筛选出[^\\n:]*推荐方案[^\\n:]*:)|(方案PK|时效最快|价格最低)", "g");
|
|
159
|
+
function M(e) {
|
|
149
160
|
let t = [];
|
|
150
|
-
|
|
161
|
+
j.lastIndex = 0;
|
|
151
162
|
let n = 0, r;
|
|
152
|
-
for (; (r =
|
|
163
|
+
for (; (r = j.exec(e)) !== null;) {
|
|
153
164
|
r.index > n && t.push({
|
|
154
165
|
kind: "text",
|
|
155
166
|
value: e.slice(n, r.index)
|
|
@@ -168,69 +179,95 @@ function j(e) {
|
|
|
168
179
|
value: e.slice(n)
|
|
169
180
|
}), t;
|
|
170
181
|
}
|
|
171
|
-
var
|
|
172
|
-
function
|
|
182
|
+
var N = /标签|箱唛|唛头|入库单|交接单|入仓单|面单|下载/;
|
|
183
|
+
function P(e, t) {
|
|
173
184
|
if (/方案|截图|报价图|效果图|示意图|图片/.test(t)) return !0;
|
|
174
|
-
if (
|
|
185
|
+
if (N.test(t)) return !1;
|
|
175
186
|
let n = e.split(/[?#]/)[0];
|
|
176
|
-
return
|
|
187
|
+
return O.test(n);
|
|
177
188
|
}
|
|
178
|
-
function
|
|
189
|
+
function F(e) {
|
|
179
190
|
return /方案|报价|截图|PK/.test(e) ? "方案PK" : "图片";
|
|
180
191
|
}
|
|
181
|
-
function
|
|
192
|
+
function I(e) {
|
|
182
193
|
return /标签|箱唛/.test(e) ? "点击下载箱唛" : /入库单|交接单/.test(e) ? "点击下载入库单" : /面单/.test(e) ? "点击下载面单" : /截图|方案/.test(e) ? "点击查看方案PK" : /下载链接|labelUrl|下载/.test(e) ? "点击下载" : /链接/.test(e) ? "点击查看" : null;
|
|
183
194
|
}
|
|
184
|
-
function
|
|
195
|
+
function L(e, t = {}) {
|
|
185
196
|
let n = [];
|
|
186
|
-
|
|
197
|
+
D.lastIndex = 0;
|
|
187
198
|
let r = 0, i;
|
|
188
|
-
for (; (i =
|
|
189
|
-
let a = i[0], o = i.index, s = e.lastIndexOf("\n", o - 1) + 1, c = e.slice(s, o), l =
|
|
199
|
+
for (; (i = D.exec(e)) !== null;) {
|
|
200
|
+
let a = i[0], o = i.index, s = e.lastIndexOf("\n", o - 1) + 1, c = e.slice(s, o), l = P(a, c), u = !t.complete && o + a.length === e.length;
|
|
190
201
|
if (o > r) {
|
|
191
202
|
let t = e.slice(r, o);
|
|
192
|
-
l && (t = t.replace(/链接([::])\s*$/, "$1")), n.push(...
|
|
203
|
+
l && (t = t.replace(/链接([::])\s*$/, "$1")), n.push(...M(t));
|
|
193
204
|
}
|
|
194
205
|
u ? n.push({
|
|
195
206
|
kind: "text",
|
|
196
|
-
value: l ?
|
|
207
|
+
value: l ? A : k
|
|
197
208
|
}) : l ? n.push({
|
|
198
209
|
kind: "image",
|
|
199
210
|
href: a,
|
|
200
|
-
alt:
|
|
211
|
+
alt: F(c)
|
|
201
212
|
}) : n.push({
|
|
202
213
|
kind: "link",
|
|
203
214
|
href: a,
|
|
204
|
-
label:
|
|
215
|
+
label: I(c) ?? a
|
|
205
216
|
}), r = o + a.length;
|
|
206
217
|
}
|
|
207
|
-
return r < e.length && n.push(...
|
|
218
|
+
return r < e.length && n.push(...M(e.slice(r))), n;
|
|
208
219
|
}
|
|
209
|
-
function
|
|
220
|
+
function R(e, t = {}) {
|
|
210
221
|
let n = e.split("\n");
|
|
211
|
-
return n.map((e, r) =>
|
|
222
|
+
return n.map((e, r) => {
|
|
223
|
+
let i = L(e, { complete: t.complete || r < n.length - 1 }), a = B.exec(e);
|
|
224
|
+
return a ? z(i, a[0]) : i;
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
function z(e, t) {
|
|
228
|
+
let n = t.length, r = [];
|
|
229
|
+
for (let t of e) {
|
|
230
|
+
if (n === 0 || !("value" in t)) {
|
|
231
|
+
r.push(t);
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
let e = Math.min(n, t.value.length);
|
|
235
|
+
n -= e, e < t.value.length && r.push({
|
|
236
|
+
...t,
|
|
237
|
+
value: t.value.slice(e)
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
return [{
|
|
241
|
+
kind: "label",
|
|
242
|
+
value: t
|
|
243
|
+
}, ...r];
|
|
244
|
+
}
|
|
245
|
+
var B = /^[\u4e00-\u9fffA-Za-z0-9()()/-]{1,14}:(?=\S)/;
|
|
246
|
+
function V(e, t) {
|
|
247
|
+
return t?.panel_text ? e.replace(t.panel_text, "").replace(/\n{3,}/g, "\n\n") : e;
|
|
212
248
|
}
|
|
213
249
|
// src/plugin.ts
|
|
214
|
-
var
|
|
215
|
-
e.provide(
|
|
250
|
+
var H = Symbol("seer-chat-options"), U = { install(e, t) {
|
|
251
|
+
e.provide(H, t);
|
|
216
252
|
} };
|
|
217
253
|
// src/useSeerChat.ts
|
|
218
|
-
function
|
|
219
|
-
let t =
|
|
254
|
+
function W(e = {}) {
|
|
255
|
+
let t = s() ? c(H, void 0) : void 0, n = Object.fromEntries(Object.entries(e).filter(([, e]) => e !== void 0)), r = {
|
|
220
256
|
...t,
|
|
221
257
|
...n
|
|
222
258
|
};
|
|
223
259
|
if (!r.endpoint) throw Error("Seer chat endpoint is required. Pass it to app.use() or useSeerChat().");
|
|
224
|
-
let i =
|
|
260
|
+
let i = b({
|
|
225
261
|
endpoint: r.endpoint,
|
|
226
262
|
sessionEndpoint: r.sessionEndpoint,
|
|
227
263
|
transcriptionEndpoint: r.transcriptionEndpoint,
|
|
228
264
|
uploadEndpoint: r.uploadEndpoint,
|
|
229
265
|
challengeTokenProvider: r.challengeTokenProvider,
|
|
230
|
-
orgOwner: () =>
|
|
266
|
+
orgOwner: () => x(e.orgOwner) ?? x(t?.orgOwner),
|
|
267
|
+
sellerToken: () => x(e.sellerToken) ?? x(t?.sellerToken),
|
|
231
268
|
model: r.model,
|
|
232
269
|
fetcher: r.fetcher
|
|
233
|
-
}), a =
|
|
270
|
+
}), a = f([]), o = f(!1), l = f(null), u = f(), d = f([]), p = f(!1), m = r.voiceEnabled !== !1 && i.transcriptionEnabled, h = r.uploadEnabled !== !1 && i.uploadEnabled, g = r.maxRecordingSeconds ?? 60, _ = f([]), v = f(!1), y = null;
|
|
234
271
|
async function S(e) {
|
|
235
272
|
v.value = !0, l.value = null;
|
|
236
273
|
try {
|
|
@@ -247,17 +284,17 @@ function B(e = {}) {
|
|
|
247
284
|
}
|
|
248
285
|
async function w(e) {
|
|
249
286
|
let t = e.trim(), n = _.value;
|
|
250
|
-
if (!t && n.length === 0 ||
|
|
251
|
-
let
|
|
287
|
+
if (!t && n.length === 0 || o.value || v.value) return;
|
|
288
|
+
let s = {
|
|
252
289
|
role: "user",
|
|
253
290
|
content: [t, n.map((e) => `[附件:${e.filename}]`).join("\n")].filter(Boolean).join("\n")
|
|
254
291
|
};
|
|
255
|
-
_.value = [], a.value = [...a.value,
|
|
256
|
-
let
|
|
292
|
+
_.value = [], a.value = [...a.value, s], o.value = !0, l.value = null, y = new AbortController();
|
|
293
|
+
let c = {
|
|
257
294
|
role: "assistant",
|
|
258
295
|
content: ""
|
|
259
296
|
};
|
|
260
|
-
r.stream && (a.value = [...a.value,
|
|
297
|
+
r.stream && (a.value = [...a.value, c]);
|
|
261
298
|
try {
|
|
262
299
|
let e = await i.chat({
|
|
263
300
|
messages: a.value.filter((e) => e.content),
|
|
@@ -265,33 +302,34 @@ function B(e = {}) {
|
|
|
265
302
|
conversationId: u.value,
|
|
266
303
|
attachments: n.map((e) => e.fileId)
|
|
267
304
|
}, {
|
|
268
|
-
signal:
|
|
305
|
+
signal: y.signal,
|
|
269
306
|
onDelta(e) {
|
|
270
|
-
|
|
307
|
+
c.content += e, a.value = [...a.value];
|
|
271
308
|
}
|
|
272
309
|
});
|
|
273
|
-
r.stream
|
|
310
|
+
r.stream ? e.orderCard && (c.orderCard = e.orderCard, a.value = [...a.value]) : a.value = [...a.value, {
|
|
274
311
|
role: "assistant",
|
|
275
|
-
content: e.content
|
|
276
|
-
|
|
312
|
+
content: e.content,
|
|
313
|
+
...e.orderCard ? { orderCard: e.orderCard } : {}
|
|
314
|
+
}], u.value = e.conversationId, d.value = e.citations, p.value = e.handoffRequested;
|
|
277
315
|
} catch (e) {
|
|
278
316
|
e.name !== "AbortError" && (l.value = e instanceof Error ? e.message : String(e));
|
|
279
317
|
} finally {
|
|
280
|
-
|
|
318
|
+
o.value = !1, y = null;
|
|
281
319
|
}
|
|
282
320
|
}
|
|
283
321
|
function T() {
|
|
284
|
-
a.value = [], _.value = [], l.value = null, u.value = void 0,
|
|
322
|
+
a.value = [], _.value = [], l.value = null, u.value = void 0, d.value = [], p.value = !1;
|
|
285
323
|
}
|
|
286
324
|
function E() {
|
|
287
|
-
|
|
325
|
+
y?.abort();
|
|
288
326
|
}
|
|
289
327
|
return {
|
|
290
328
|
messages: a,
|
|
291
|
-
loading:
|
|
329
|
+
loading: o,
|
|
292
330
|
error: l,
|
|
293
331
|
conversationId: u,
|
|
294
|
-
citations:
|
|
332
|
+
citations: d,
|
|
295
333
|
handoffRequested: p,
|
|
296
334
|
transcriptionEnabled: m,
|
|
297
335
|
maxRecordingSeconds: g,
|
|
@@ -306,62 +344,107 @@ function B(e = {}) {
|
|
|
306
344
|
abort: E
|
|
307
345
|
};
|
|
308
346
|
}
|
|
309
|
-
// src/components/
|
|
310
|
-
var ee = {
|
|
347
|
+
// src/components/SeerOrderCard.vue?vue&type=script&setup=true&lang.ts
|
|
348
|
+
var G = ["aria-label"], K = { class: "seer-order-card__title" }, q = { class: "seer-order-card__panel" }, J = { class: "seer-order-card__channel" }, Y = { class: "seer-order-card__rows" }, ee = { class: "seer-order-card__label" }, te = {
|
|
349
|
+
key: 0,
|
|
350
|
+
class: "seer-order-card__row"
|
|
351
|
+
}, ne = { class: "seer-order-card__label" }, re = { class: "seer-order-card__value" }, X = {
|
|
352
|
+
key: 0,
|
|
353
|
+
class: "seer-order-card__subsidy"
|
|
354
|
+
}, ie = { class: "seer-order-card__total" }, ae = ["title"], oe = { class: "seer-order-card__total-value" }, se = ["disabled"], ce = {
|
|
355
|
+
key: 2,
|
|
356
|
+
class: "seer-order-card__blocked",
|
|
357
|
+
role: "note"
|
|
358
|
+
}, le = /*@__PURE__*/ o({
|
|
359
|
+
__name: "SeerOrderCard",
|
|
360
|
+
props: {
|
|
361
|
+
card: {},
|
|
362
|
+
disabled: { type: Boolean }
|
|
363
|
+
},
|
|
364
|
+
emits: ["submit"],
|
|
365
|
+
setup(t, { emit: n }) {
|
|
366
|
+
let o = n;
|
|
367
|
+
return (n, s) => (d(), i("section", {
|
|
368
|
+
class: "seer-order-card",
|
|
369
|
+
"aria-label": t.card.title
|
|
370
|
+
}, [a("h3", K, m(t.card.title), 1), a("div", q, [
|
|
371
|
+
a("h4", J, m(t.card.channel_name), 1),
|
|
372
|
+
a("dl", Y, [(d(!0), i(e, null, p(t.card.rows, (e) => (d(), i("div", {
|
|
373
|
+
key: e.label,
|
|
374
|
+
class: "seer-order-card__row"
|
|
375
|
+
}, [a("dt", ee, m(e.label), 1), a("dd", { class: l(["seer-order-card__value", { "seer-order-card__value--struck": e.struck }]) }, m(e.value), 3)]))), 128)), t.card.coupon ? (d(), i("div", te, [a("dt", ne, m(t.card.coupon.label), 1), a("dd", re, m(t.card.coupon.value), 1)])) : r("", !0)]),
|
|
376
|
+
t.card.subsidy ? (d(), i("div", X, [a("strong", null, m(t.card.subsidy.label), 1), a("span", null, m(t.card.subsidy.value) + " = " + m(t.card.subsidy.detail), 1)])) : r("", !0),
|
|
377
|
+
a("div", ie, [a("span", {
|
|
378
|
+
class: "seer-order-card__label",
|
|
379
|
+
title: t.card.note
|
|
380
|
+
}, m(t.card.total.label), 9, ae), a("span", oe, m(t.card.total.value), 1)]),
|
|
381
|
+
t.card.action ? (d(), i("button", {
|
|
382
|
+
key: 1,
|
|
383
|
+
type: "button",
|
|
384
|
+
class: "seer-order-card__submit",
|
|
385
|
+
disabled: t.disabled,
|
|
386
|
+
onClick: s[0] ||= (e) => o("submit", t.card.action.message)
|
|
387
|
+
}, m(t.card.action.label), 9, se)) : t.card.blocked_reason ? (d(), i("p", ce, m(t.card.blocked_reason), 1)) : r("", !0)
|
|
388
|
+
])], 8, G));
|
|
389
|
+
}
|
|
390
|
+
}), Z = (e, t) => {
|
|
391
|
+
let n = e.__vccOpts || e;
|
|
392
|
+
for (let [e, r] of t) n[e] = r;
|
|
393
|
+
return n;
|
|
394
|
+
}, Q = /*#__PURE__*/ Z(le, [["__scopeId", "data-v-17d9e82e"]]), ue = {
|
|
311
395
|
class: "seer-chat",
|
|
312
396
|
"aria-label": "多发货 AI 客服聊天"
|
|
313
|
-
},
|
|
397
|
+
}, de = { class: "seer-chat__header" }, fe = {
|
|
314
398
|
class: "seer-chat__messages",
|
|
315
399
|
"aria-live": "polite"
|
|
316
|
-
},
|
|
400
|
+
}, pe = {
|
|
317
401
|
key: 0,
|
|
318
402
|
class: "seer-chat__empty"
|
|
319
|
-
},
|
|
403
|
+
}, me = { class: "seer-chat__role" }, he = { class: "seer-chat__body" }, ge = ["href"], _e = ["aria-label", "onClick"], ve = ["src", "alt"], ye = {
|
|
320
404
|
key: 2,
|
|
321
405
|
class: "seer-chat__strong"
|
|
322
|
-
},
|
|
406
|
+
}, be = {
|
|
323
407
|
key: 3,
|
|
324
408
|
class: "seer-chat__price"
|
|
325
|
-
},
|
|
409
|
+
}, xe = {
|
|
410
|
+
key: 4,
|
|
411
|
+
class: "seer-chat__label-text"
|
|
412
|
+
}, Se = { key: 5 }, Ce = {
|
|
326
413
|
key: 0,
|
|
327
414
|
class: "seer-chat__status"
|
|
328
|
-
},
|
|
415
|
+
}, we = {
|
|
329
416
|
key: 1,
|
|
330
417
|
class: "seer-chat__error",
|
|
331
418
|
role: "alert"
|
|
332
|
-
},
|
|
419
|
+
}, Te = {
|
|
333
420
|
key: 2,
|
|
334
421
|
class: "seer-chat__handoff"
|
|
335
|
-
},
|
|
422
|
+
}, Ee = {
|
|
336
423
|
key: 0,
|
|
337
424
|
class: "seer-chat__attachments",
|
|
338
425
|
"aria-label": "待发送的附件"
|
|
339
|
-
},
|
|
426
|
+
}, De = { class: "seer-chat__attachment-name" }, Oe = ["aria-label", "onClick"], $ = [
|
|
340
427
|
"placeholder",
|
|
341
428
|
"disabled",
|
|
342
429
|
"onKeydown"
|
|
343
|
-
],
|
|
430
|
+
], ke = { class: "seer-chat__composer-footer" }, Ae = {
|
|
344
431
|
class: "seer-chat__hint",
|
|
345
432
|
"aria-live": "polite"
|
|
346
|
-
},
|
|
433
|
+
}, je = ["disabled"], Me = [
|
|
347
434
|
"disabled",
|
|
348
435
|
"aria-label",
|
|
349
436
|
"title"
|
|
350
|
-
],
|
|
437
|
+
], Ne = {
|
|
351
438
|
key: 0,
|
|
352
439
|
class: "seer-chat__stop-icon",
|
|
353
440
|
"aria-hidden": "true"
|
|
354
|
-
},
|
|
441
|
+
}, Pe = {
|
|
355
442
|
key: 1,
|
|
356
443
|
viewBox: "0 0 24 24",
|
|
357
444
|
width: "20",
|
|
358
445
|
height: "20",
|
|
359
446
|
"aria-hidden": "true"
|
|
360
|
-
},
|
|
361
|
-
let n = e.__vccOpts || e;
|
|
362
|
-
for (let [e, r] of t) n[e] = r;
|
|
363
|
-
return n;
|
|
364
|
-
})(/* @__PURE__ */ a({
|
|
447
|
+
}, Fe = ["disabled"], Ie = ["aria-label"], Le = ["src", "alt"], Re = ".xlsx,.xls,.csv,.png,.jpg,.jpeg,.webp,.pdf", ze = /*#__PURE__*/ Z(/* @__PURE__ */ o({
|
|
365
448
|
__name: "SeerChat",
|
|
366
449
|
props: {
|
|
367
450
|
endpoint: {},
|
|
@@ -373,6 +456,7 @@ var ee = {
|
|
|
373
456
|
default: void 0
|
|
374
457
|
},
|
|
375
458
|
orgOwner: {},
|
|
459
|
+
sellerToken: {},
|
|
376
460
|
model: {},
|
|
377
461
|
stream: {
|
|
378
462
|
type: Boolean,
|
|
@@ -387,98 +471,99 @@ var ee = {
|
|
|
387
471
|
},
|
|
388
472
|
maxRecordingSeconds: {}
|
|
389
473
|
},
|
|
390
|
-
setup(
|
|
391
|
-
let
|
|
392
|
-
endpoint:
|
|
393
|
-
sessionEndpoint:
|
|
394
|
-
transcriptionEndpoint:
|
|
395
|
-
uploadEndpoint:
|
|
396
|
-
uploadEnabled:
|
|
397
|
-
orgOwner: () =>
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
474
|
+
setup(o) {
|
|
475
|
+
let s = o, c = f(""), b = f(!1), x = f(!1), S = f(null), C = W({
|
|
476
|
+
endpoint: s.endpoint,
|
|
477
|
+
sessionEndpoint: s.sessionEndpoint,
|
|
478
|
+
transcriptionEndpoint: s.transcriptionEndpoint,
|
|
479
|
+
uploadEndpoint: s.uploadEndpoint,
|
|
480
|
+
uploadEnabled: s.uploadEnabled,
|
|
481
|
+
orgOwner: () => s.orgOwner,
|
|
482
|
+
sellerToken: () => s.sellerToken,
|
|
483
|
+
model: s.model,
|
|
484
|
+
stream: s.stream,
|
|
485
|
+
fetcher: s.fetcher,
|
|
486
|
+
voiceEnabled: s.voiceEnabled,
|
|
487
|
+
maxRecordingSeconds: s.maxRecordingSeconds
|
|
488
|
+
}), w = f(null), T = t(() => (c.value.trim().length > 0 || C.attachments.value.length > 0) && !C.loading.value && !C.uploading.value && !b.value && !x.value);
|
|
489
|
+
async function E(e) {
|
|
405
490
|
let t = e.target, n = Array.from(t.files ?? []);
|
|
406
491
|
t.value = "";
|
|
407
|
-
for (let e of n) await
|
|
492
|
+
for (let e of n) await C.attach(e);
|
|
408
493
|
}
|
|
409
|
-
let
|
|
410
|
-
function
|
|
411
|
-
e.key === "Escape" &&
|
|
494
|
+
let D = t(() => C.transcriptionEnabled && typeof navigator < "u" && typeof navigator.mediaDevices?.getUserMedia == "function" && typeof MediaRecorder < "u"), O = null, k = null, A = [], j, M = !1, N = f(null);
|
|
495
|
+
function P(e) {
|
|
496
|
+
e.key === "Escape" && I();
|
|
412
497
|
}
|
|
413
|
-
function
|
|
414
|
-
|
|
498
|
+
function F(e, t) {
|
|
499
|
+
N.value = {
|
|
415
500
|
src: e,
|
|
416
501
|
alt: t
|
|
417
|
-
}, window.addEventListener("keydown",
|
|
502
|
+
}, window.addEventListener("keydown", P);
|
|
418
503
|
}
|
|
419
|
-
function
|
|
420
|
-
|
|
504
|
+
function I() {
|
|
505
|
+
N.value = null, window.removeEventListener("keydown", P);
|
|
421
506
|
}
|
|
422
|
-
|
|
423
|
-
|
|
507
|
+
u(() => {
|
|
508
|
+
M = !0, window.removeEventListener("keydown", P), J(), O && O.state !== "inactive" && (O.ondataavailable = null, O.onstop = null, O.onerror = null, O.stop()), Y();
|
|
424
509
|
});
|
|
425
|
-
async function
|
|
426
|
-
if (!
|
|
427
|
-
let e =
|
|
428
|
-
|
|
429
|
-
}
|
|
430
|
-
async function R() {
|
|
431
|
-
y.value ? Z() : await z();
|
|
510
|
+
async function L() {
|
|
511
|
+
if (!T.value) return;
|
|
512
|
+
let e = c.value;
|
|
513
|
+
c.value = "", await C.send(e);
|
|
432
514
|
}
|
|
433
515
|
async function z() {
|
|
434
|
-
|
|
435
|
-
|
|
516
|
+
b.value ? H() : await B();
|
|
517
|
+
}
|
|
518
|
+
async function B() {
|
|
519
|
+
if (!(!D.value || x.value || C.loading.value)) {
|
|
520
|
+
S.value = null;
|
|
436
521
|
try {
|
|
437
|
-
if (
|
|
522
|
+
if (k = await navigator.mediaDevices.getUserMedia({
|
|
438
523
|
audio: {
|
|
439
524
|
echoCancellation: !0,
|
|
440
525
|
noiseSuppression: !0
|
|
441
526
|
},
|
|
442
527
|
video: !1
|
|
443
|
-
}),
|
|
444
|
-
|
|
528
|
+
}), M) {
|
|
529
|
+
Y();
|
|
445
530
|
return;
|
|
446
531
|
}
|
|
447
|
-
let e =
|
|
448
|
-
|
|
532
|
+
let e = G();
|
|
533
|
+
O = e ? new MediaRecorder(k, {
|
|
449
534
|
mimeType: e,
|
|
450
535
|
audioBitsPerSecond: 64e3
|
|
451
|
-
}) : new MediaRecorder(
|
|
452
|
-
e.data.size > 0 &&
|
|
453
|
-
},
|
|
454
|
-
|
|
455
|
-
},
|
|
456
|
-
|
|
457
|
-
},
|
|
536
|
+
}) : new MediaRecorder(k), A = [], O.ondataavailable = (e) => {
|
|
537
|
+
e.data.size > 0 && A.push(e.data);
|
|
538
|
+
}, O.onstop = () => {
|
|
539
|
+
U(O?.mimeType || e || "audio/webm");
|
|
540
|
+
}, O.onerror = () => {
|
|
541
|
+
S.value = "录音失败,请重试或用文字输入。", b.value = !1, x.value = !1, J(), Y();
|
|
542
|
+
}, O.start(), b.value = !0, j = setTimeout(H, Math.max(1, C.maxRecordingSeconds) * 1e3);
|
|
458
543
|
} catch (e) {
|
|
459
|
-
|
|
544
|
+
S.value = q(e), Y();
|
|
460
545
|
}
|
|
461
546
|
}
|
|
462
547
|
}
|
|
463
|
-
function
|
|
464
|
-
|
|
548
|
+
function H() {
|
|
549
|
+
O && O.state !== "inactive" && (b.value = !1, x.value = !0, J(), O.stop());
|
|
465
550
|
}
|
|
466
|
-
async function
|
|
467
|
-
|
|
468
|
-
let t =
|
|
469
|
-
if (
|
|
551
|
+
async function U(e) {
|
|
552
|
+
J(), Y();
|
|
553
|
+
let t = A;
|
|
554
|
+
if (A = [], O = null, M) return;
|
|
470
555
|
let n = new Blob(t, { type: e });
|
|
471
|
-
if (n.size === 0)
|
|
556
|
+
if (n.size === 0) S.value = "没有录到声音,请重试。", x.value = !1;
|
|
472
557
|
else try {
|
|
473
|
-
let t = await
|
|
474
|
-
|
|
558
|
+
let t = await C.transcribe(n, K(e));
|
|
559
|
+
c.value = c.value.trim() ? `${c.value.trim()} ${t.text}` : t.text;
|
|
475
560
|
} catch {
|
|
476
|
-
|
|
561
|
+
S.value = "语音识别失败,请重试或用文字输入。";
|
|
477
562
|
} finally {
|
|
478
|
-
|
|
563
|
+
x.value = !1;
|
|
479
564
|
}
|
|
480
565
|
}
|
|
481
|
-
function
|
|
566
|
+
function G() {
|
|
482
567
|
if (typeof MediaRecorder.isTypeSupported == "function") return [
|
|
483
568
|
"audio/webm;codecs=opus",
|
|
484
569
|
"audio/mp4",
|
|
@@ -486,149 +571,158 @@ var ee = {
|
|
|
486
571
|
"audio/webm"
|
|
487
572
|
].find((e) => MediaRecorder.isTypeSupported(e));
|
|
488
573
|
}
|
|
489
|
-
function
|
|
574
|
+
function K(e) {
|
|
490
575
|
return `recording.${{
|
|
491
576
|
"audio/mp4": "m4a",
|
|
492
577
|
"audio/ogg": "ogg",
|
|
493
578
|
"audio/webm": "webm"
|
|
494
579
|
}[e.split(";", 1)[0].toLowerCase()] || "webm"}`;
|
|
495
580
|
}
|
|
496
|
-
function
|
|
581
|
+
function q(e) {
|
|
497
582
|
return e instanceof DOMException && e.name === "NotAllowedError" ? "请允许浏览器使用麦克风。" : e instanceof DOMException && e.name === "NotFoundError" ? "未检测到可用的麦克风。" : "无法启动麦克风,请重试或用文字输入。";
|
|
498
583
|
}
|
|
499
|
-
function
|
|
500
|
-
|
|
584
|
+
function J() {
|
|
585
|
+
j !== void 0 && (clearTimeout(j), j = void 0);
|
|
501
586
|
}
|
|
502
|
-
function
|
|
503
|
-
|
|
587
|
+
function Y() {
|
|
588
|
+
k?.getTracks().forEach((e) => e.stop()), k = null;
|
|
504
589
|
}
|
|
505
|
-
return (t,
|
|
506
|
-
|
|
590
|
+
return (t, s) => (d(), i("section", ue, [
|
|
591
|
+
a("header", de, [a("div", null, [a("h2", null, m(o.title), 1), s[4] ||= a("p", null, "可咨询渠道报价、时效、下单资料、入仓和售后问题。", -1)]), a("button", {
|
|
507
592
|
type: "button",
|
|
508
593
|
class: "seer-chat__clear-button",
|
|
509
|
-
onClick:
|
|
594
|
+
onClick: s[0] ||= (e) => h(C).reset()
|
|
510
595
|
}, " 清空对话 ")]),
|
|
511
|
-
|
|
512
|
-
key: `${t.role}-${
|
|
513
|
-
class:
|
|
514
|
-
}, [
|
|
596
|
+
a("div", fe, [h(C).messages.value.length === 0 ? (d(), i("p", pe, " 直接输入问题即可,复杂查单或赔付问题会提示转人工。 ")) : r("", !0), (d(!0), i(e, null, p(h(C).messages.value, (t, o) => (d(), i("article", {
|
|
597
|
+
key: `${t.role}-${o}`,
|
|
598
|
+
class: l(["seer-chat__message", `seer-chat__message--${t.role}`])
|
|
599
|
+
}, [a("span", me, m(t.role === "user" ? "你" : "AI 客服"), 1), a("div", he, [(d(!0), i(e, null, p(h(R)(h(V)(t.content, t.orderCard), { complete: !(h(C).loading.value && o === h(C).messages.value.length - 1) }), (t, n) => (d(), i("p", {
|
|
515
600
|
key: n,
|
|
516
601
|
class: "seer-chat__line"
|
|
517
|
-
}, [(
|
|
602
|
+
}, [(d(!0), i(e, null, p(t, (t, n) => (d(), i(e, { key: n }, [t.kind === "link" ? (d(), i("a", {
|
|
518
603
|
key: 0,
|
|
519
604
|
class: "seer-chat__link",
|
|
520
605
|
href: t.href,
|
|
521
606
|
target: "_blank",
|
|
522
607
|
rel: "noopener noreferrer"
|
|
523
|
-
},
|
|
608
|
+
}, m(t.label), 9, ge)) : t.kind === "image" ? (d(), i("button", {
|
|
524
609
|
key: 1,
|
|
525
610
|
type: "button",
|
|
526
611
|
class: "seer-chat__image-button",
|
|
527
612
|
"aria-label": `放大查看${t.alt}`,
|
|
528
|
-
onClick: (e) =>
|
|
529
|
-
}, [
|
|
613
|
+
onClick: (e) => F(t.href, t.alt)
|
|
614
|
+
}, [a("img", {
|
|
530
615
|
class: "seer-chat__image",
|
|
531
616
|
src: t.href,
|
|
532
617
|
alt: t.alt,
|
|
533
618
|
loading: "lazy"
|
|
534
|
-
}, null, 8,
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
619
|
+
}, null, 8, ve)], 8, _e)) : t.kind === "strong" ? (d(), i("strong", ye, m(t.value), 1)) : t.kind === "price" ? (d(), i("span", be, m(t.value), 1)) : t.kind === "label" ? (d(), i("span", xe, m(t.value), 1)) : (d(), i("span", Se, m(t.value), 1))], 64))), 128))]))), 128)), t.orderCard ? (d(), n(Q, {
|
|
620
|
+
key: 0,
|
|
621
|
+
card: t.orderCard,
|
|
622
|
+
disabled: h(C).loading.value || o !== h(C).messages.value.length - 1,
|
|
623
|
+
onSubmit: h(C).send
|
|
624
|
+
}, null, 8, [
|
|
625
|
+
"card",
|
|
626
|
+
"disabled",
|
|
627
|
+
"onSubmit"
|
|
628
|
+
])) : r("", !0)])], 2))), 128))]),
|
|
629
|
+
h(C).loading.value ? (d(), i("p", Ce, "正在回复...")) : r("", !0),
|
|
630
|
+
h(C).error.value || S.value ? (d(), i("p", we, m(S.value || h(C).error.value), 1)) : r("", !0),
|
|
631
|
+
h(C).handoffRequested.value ? (d(), i("p", Te, " 建议转人工:请留下联系方式或等待客服接入。 ")) : r("", !0),
|
|
632
|
+
a("form", {
|
|
539
633
|
class: "seer-chat__form",
|
|
540
|
-
onSubmit:
|
|
634
|
+
onSubmit: y(L, ["prevent"])
|
|
541
635
|
}, [
|
|
542
|
-
|
|
636
|
+
s[8] ||= a("label", {
|
|
543
637
|
class: "seer-chat__label",
|
|
544
638
|
for: "seer-chat-input"
|
|
545
639
|
}, "问题", -1),
|
|
546
|
-
|
|
640
|
+
h(C).attachments.value.length > 0 ? (d(), i("ul", Ee, [(d(!0), i(e, null, p(h(C).attachments.value, (e) => (d(), i("li", {
|
|
547
641
|
key: e.fileId,
|
|
548
642
|
class: "seer-chat__attachment"
|
|
549
|
-
}, [
|
|
643
|
+
}, [a("span", De, m(e.filename), 1), a("button", {
|
|
550
644
|
type: "button",
|
|
551
645
|
class: "seer-chat__attachment-remove",
|
|
552
646
|
"aria-label": `移除附件${e.filename}`,
|
|
553
|
-
onClick: (t) =>
|
|
554
|
-
}, " × ", 8,
|
|
555
|
-
|
|
647
|
+
onClick: (t) => h(C).removeAttachment(e.fileId)
|
|
648
|
+
}, " × ", 8, Oe)]))), 128))])) : r("", !0),
|
|
649
|
+
_(a("textarea", {
|
|
556
650
|
id: "seer-chat-input",
|
|
557
|
-
"onUpdate:modelValue":
|
|
558
|
-
placeholder:
|
|
559
|
-
disabled:
|
|
651
|
+
"onUpdate:modelValue": s[1] ||= (e) => c.value = e,
|
|
652
|
+
placeholder: o.placeholder,
|
|
653
|
+
disabled: h(C).loading.value || x.value,
|
|
560
654
|
rows: "3",
|
|
561
|
-
onKeydown:
|
|
562
|
-
}, null, 40,
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
655
|
+
onKeydown: v(y(L, ["exact", "prevent"]), ["enter"])
|
|
656
|
+
}, null, 40, $), [[g, c.value]]),
|
|
657
|
+
a("div", ke, [
|
|
658
|
+
a("span", Ae, m(b.value ? `正在录音,最长 ${h(C).maxRecordingSeconds} 秒` : x.value ? "正在识别语音..." : h(C).uploading.value ? "正在上传附件..." : "Enter 发送 · Shift+Enter 换行"), 1),
|
|
659
|
+
h(C).uploadEnabled ? (d(), i(e, { key: 0 }, [a("input", {
|
|
566
660
|
ref_key: "fileInput",
|
|
567
|
-
ref:
|
|
661
|
+
ref: w,
|
|
568
662
|
class: "seer-chat__file-input",
|
|
569
663
|
type: "file",
|
|
570
664
|
multiple: "",
|
|
571
|
-
accept:
|
|
572
|
-
onChange:
|
|
573
|
-
}, null, 544),
|
|
665
|
+
accept: Re,
|
|
666
|
+
onChange: E
|
|
667
|
+
}, null, 544), a("button", {
|
|
574
668
|
type: "button",
|
|
575
669
|
class: "seer-chat__attach-button",
|
|
576
|
-
disabled:
|
|
670
|
+
disabled: h(C).loading.value || h(C).uploading.value,
|
|
577
671
|
"aria-label": "上传附件",
|
|
578
672
|
title: "上传下单模板、实物图片等",
|
|
579
|
-
onClick:
|
|
580
|
-
}, [...
|
|
673
|
+
onClick: s[2] ||= (e) => w.value?.click()
|
|
674
|
+
}, [...s[5] ||= [a("svg", {
|
|
581
675
|
viewBox: "0 0 24 24",
|
|
582
676
|
width: "20",
|
|
583
677
|
height: "20",
|
|
584
678
|
"aria-hidden": "true"
|
|
585
|
-
}, [
|
|
679
|
+
}, [a("path", {
|
|
586
680
|
fill: "currentColor",
|
|
587
681
|
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,
|
|
589
|
-
|
|
682
|
+
})], -1)]], 8, je)], 64)) : r("", !0),
|
|
683
|
+
D.value ? (d(), i("button", {
|
|
590
684
|
key: 1,
|
|
591
685
|
type: "button",
|
|
592
|
-
class:
|
|
593
|
-
disabled:
|
|
594
|
-
"aria-label":
|
|
595
|
-
title:
|
|
596
|
-
onClick:
|
|
597
|
-
}, [
|
|
686
|
+
class: l(["seer-chat__mic-button", { "seer-chat__mic-button--recording": b.value }]),
|
|
687
|
+
disabled: x.value || h(C).loading.value && !b.value,
|
|
688
|
+
"aria-label": b.value ? "停止录音" : "开始语音输入",
|
|
689
|
+
title: b.value ? "停止录音" : "语音输入",
|
|
690
|
+
onClick: z
|
|
691
|
+
}, [b.value ? (d(), i("span", Ne)) : (d(), i("svg", Pe, [...s[6] ||= [a("path", {
|
|
598
692
|
fill: "currentColor",
|
|
599
693
|
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"
|
|
600
|
-
}, null, -1)]]))], 10,
|
|
601
|
-
|
|
694
|
+
}, null, -1)]]))], 10, Me)) : r("", !0),
|
|
695
|
+
h(C).loading.value ? (d(), i("button", {
|
|
602
696
|
key: 2,
|
|
603
697
|
type: "button",
|
|
604
698
|
class: "seer-chat__stop-button",
|
|
605
|
-
onClick:
|
|
606
|
-
}, " 停止 ")) :
|
|
607
|
-
|
|
699
|
+
onClick: s[3] ||= (e) => h(C).abort()
|
|
700
|
+
}, " 停止 ")) : r("", !0),
|
|
701
|
+
a("button", {
|
|
608
702
|
class: "seer-chat__send-button",
|
|
609
703
|
type: "submit",
|
|
610
|
-
disabled: !
|
|
611
|
-
}, [...
|
|
704
|
+
disabled: !T.value
|
|
705
|
+
}, [...s[7] ||= [a("span", null, "发送", -1), a("span", { "aria-hidden": "true" }, "↵", -1)]], 8, Fe)
|
|
612
706
|
])
|
|
613
707
|
], 32),
|
|
614
|
-
|
|
708
|
+
N.value ? (d(), i("div", {
|
|
615
709
|
key: 3,
|
|
616
710
|
class: "seer-chat__lightbox",
|
|
617
711
|
role: "dialog",
|
|
618
712
|
"aria-modal": "true",
|
|
619
|
-
"aria-label":
|
|
620
|
-
onClick:
|
|
621
|
-
}, [
|
|
713
|
+
"aria-label": N.value.alt,
|
|
714
|
+
onClick: I
|
|
715
|
+
}, [a("button", {
|
|
622
716
|
type: "button",
|
|
623
717
|
class: "seer-chat__lightbox-close",
|
|
624
718
|
"aria-label": "关闭",
|
|
625
|
-
onClick:
|
|
626
|
-
}, " × "),
|
|
719
|
+
onClick: I
|
|
720
|
+
}, " × "), a("img", {
|
|
627
721
|
class: "seer-chat__lightbox-image",
|
|
628
|
-
src:
|
|
629
|
-
alt:
|
|
630
|
-
}, null, 8,
|
|
722
|
+
src: N.value.src,
|
|
723
|
+
alt: N.value.alt
|
|
724
|
+
}, null, 8, Le)], 8, Ie)) : r("", !0)
|
|
631
725
|
]));
|
|
632
726
|
}
|
|
633
|
-
}), [["__scopeId", "data-v-
|
|
634
|
-
export {
|
|
727
|
+
}), [["__scopeId", "data-v-d821ceaf"]]);
|
|
728
|
+
export { ze as SeerChat, U as SeerChatPlugin, Q as SeerOrderCard, b as createSeerClient, I as linkAnchorLabel, R as toContentLines, L as toContentSegments, W as useSeerChat, V as withoutCardText };
|
package/dist/useSeerChat.d.ts
CHANGED
|
@@ -8,10 +8,82 @@ export declare function useSeerChat(localOptions?: UseSeerChatOptions): {
|
|
|
8
8
|
role: import("./client").SeerChatRole;
|
|
9
9
|
content: string;
|
|
10
10
|
name?: string | undefined;
|
|
11
|
+
orderCard?: {
|
|
12
|
+
type: "order_estimate";
|
|
13
|
+
title: string;
|
|
14
|
+
channel_name: string;
|
|
15
|
+
rows: {
|
|
16
|
+
label: string;
|
|
17
|
+
value: string;
|
|
18
|
+
struck?: boolean | undefined;
|
|
19
|
+
detail?: string | undefined;
|
|
20
|
+
}[];
|
|
21
|
+
subsidy: {
|
|
22
|
+
label: string;
|
|
23
|
+
value: string;
|
|
24
|
+
struck?: boolean | undefined;
|
|
25
|
+
detail?: string | undefined;
|
|
26
|
+
} | null;
|
|
27
|
+
coupon: {
|
|
28
|
+
label: string;
|
|
29
|
+
value: string;
|
|
30
|
+
struck?: boolean | undefined;
|
|
31
|
+
detail?: string | undefined;
|
|
32
|
+
} | null;
|
|
33
|
+
total: {
|
|
34
|
+
label: string;
|
|
35
|
+
value: string;
|
|
36
|
+
struck?: boolean | undefined;
|
|
37
|
+
detail?: string | undefined;
|
|
38
|
+
};
|
|
39
|
+
note: string;
|
|
40
|
+
panel_text: string;
|
|
41
|
+
action: {
|
|
42
|
+
label: string;
|
|
43
|
+
message: string;
|
|
44
|
+
} | null;
|
|
45
|
+
blocked_reason: string;
|
|
46
|
+
} | undefined;
|
|
11
47
|
}[], SeerChatMessage[] | {
|
|
12
48
|
role: import("./client").SeerChatRole;
|
|
13
49
|
content: string;
|
|
14
50
|
name?: string | undefined;
|
|
51
|
+
orderCard?: {
|
|
52
|
+
type: "order_estimate";
|
|
53
|
+
title: string;
|
|
54
|
+
channel_name: string;
|
|
55
|
+
rows: {
|
|
56
|
+
label: string;
|
|
57
|
+
value: string;
|
|
58
|
+
struck?: boolean | undefined;
|
|
59
|
+
detail?: string | undefined;
|
|
60
|
+
}[];
|
|
61
|
+
subsidy: {
|
|
62
|
+
label: string;
|
|
63
|
+
value: string;
|
|
64
|
+
struck?: boolean | undefined;
|
|
65
|
+
detail?: string | undefined;
|
|
66
|
+
} | null;
|
|
67
|
+
coupon: {
|
|
68
|
+
label: string;
|
|
69
|
+
value: string;
|
|
70
|
+
struck?: boolean | undefined;
|
|
71
|
+
detail?: string | undefined;
|
|
72
|
+
} | null;
|
|
73
|
+
total: {
|
|
74
|
+
label: string;
|
|
75
|
+
value: string;
|
|
76
|
+
struck?: boolean | undefined;
|
|
77
|
+
detail?: string | undefined;
|
|
78
|
+
};
|
|
79
|
+
note: string;
|
|
80
|
+
panel_text: string;
|
|
81
|
+
action: {
|
|
82
|
+
label: string;
|
|
83
|
+
message: string;
|
|
84
|
+
} | null;
|
|
85
|
+
blocked_reason: string;
|
|
86
|
+
} | undefined;
|
|
15
87
|
}[]>;
|
|
16
88
|
loading: import("vue").Ref<boolean, boolean>;
|
|
17
89
|
error: import("vue").Ref<string | null, string | null>;
|