@seer-ai/seer-vue 0.1.0-beta.11 → 0.1.0-beta.13

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
@@ -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;
@@ -6,6 +6,7 @@ type __VLS_Props = {
6
6
  uploadEndpoint?: string;
7
7
  uploadEnabled?: boolean;
8
8
  orgOwner?: string;
9
+ sellerToken?: string;
9
10
  model?: string;
10
11
  stream?: boolean;
11
12
  fetcher?: SeerClientOptions["fetcher"];
@@ -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-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}
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-4cdc6832]{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-4cdc6832]{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-4cdc6832]{letter-spacing:-.03em;margin:0;font-size:22px}.seer-chat__header p[data-v-4cdc6832],.seer-chat__empty[data-v-4cdc6832],.seer-chat__status[data-v-4cdc6832]{color:#5f6f89;margin:4px 0 0;font-size:14px}.seer-chat__header p[data-v-4cdc6832]{color:#ffffffb8;max-width:34ch}.seer-chat__messages[data-v-4cdc6832]{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-4cdc6832]{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-4cdc6832]{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-4cdc6832]{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-4cdc6832]{opacity:.75;font-size:12px;font-weight:700}.seer-chat__body[data-v-4cdc6832]{flex-direction:column;display:flex}.seer-chat__line[data-v-4cdc6832]{white-space:pre-wrap;overflow-wrap:anywhere;margin:0}.seer-chat__line[data-v-4cdc6832]:not(:last-child){margin-bottom:5px}.seer-chat__line[data-v-4cdc6832]:empty{height:7px}.seer-chat__strong[data-v-4cdc6832]{font-weight:700}.seer-chat__message--assistant .seer-chat__line[data-v-4cdc6832]:has(.seer-chat__label-text){color:#1d2129}.seer-chat__label-text[data-v-4cdc6832]{color:#4e5969;font-weight:700}.seer-chat__message--user .seer-chat__label-text[data-v-4cdc6832]{color:inherit}.seer-chat__price[data-v-4cdc6832]{color:#e0331d;font-weight:600}.seer-chat__message--user .seer-chat__price[data-v-4cdc6832]{color:#ffe2dc}.seer-chat__link[data-v-4cdc6832]{color:#1f5eff;text-underline-offset:2px;overflow-wrap:anywhere;font-weight:600;text-decoration:underline}.seer-chat__link[data-v-4cdc6832]:hover{color:#173fb3}.seer-chat__message--user .seer-chat__link[data-v-4cdc6832]{color:#fff}.seer-chat__image-button[data-v-4cdc6832]{cursor:zoom-in;background:0 0;border:0;padding:0;display:block}.seer-chat__image-button[data-v-4cdc6832]:not(:disabled):hover{transform:none}.seer-chat__image[data-v-4cdc6832]{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-4cdc6832]{filter:brightness(.96)}.seer-chat__lightbox[data-v-4cdc6832]{z-index:1000;cursor:zoom-out;background:#0a0f1ad1;place-items:center;padding:32px;animation:.14s seer-chat__fade-in-4cdc6832;display:grid;position:fixed;inset:0}.seer-chat__lightbox-image[data-v-4cdc6832]{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-4cdc6832]{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-4cdc6832]:not(:disabled):hover{background:#ffffff3d}@keyframes seer-chat__fade-in-4cdc6832{0%{opacity:0}to{opacity:1}}.seer-chat__error[data-v-4cdc6832],.seer-chat__handoff[data-v-4cdc6832]{border-radius:14px;margin:0 18px;padding:10px 12px}.seer-chat__error[data-v-4cdc6832]{color:#8a1f11;background:#fff0ed}.seer-chat__handoff[data-v-4cdc6832]{color:#704600;background:#fff7db}.seer-chat__form[data-v-4cdc6832]{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__form--dragging[data-v-4cdc6832]{background:#f3f6ff;border:1px dashed #285cff}.seer-chat__label[data-v-4cdc6832]{font-size:13px;font-weight:700}.seer-chat textarea[data-v-4cdc6832]{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-4cdc6832]{color:inherit;cursor:pointer;border:0;font-weight:700;transition:transform .16s,box-shadow .16s,opacity .16s}.seer-chat button[data-v-4cdc6832]:not(:disabled):hover{transform:translateY(-1px)}.seer-chat button[data-v-4cdc6832]:disabled{cursor:not-allowed;opacity:.5}.seer-chat button[data-v-4cdc6832]:focus-visible,.seer-chat textarea[data-v-4cdc6832]:focus-visible{border-color:#1f5eff6b;box-shadow:0 0 0 4px #1f5eff21}.seer-chat__clear-button[data-v-4cdc6832]{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-4cdc6832]:not(:disabled):hover{color:#fff;box-shadow:none;background:#ffffff1a}.seer-chat__stop-button[data-v-4cdc6832]{color:#6c3b12;background:#fff1df;border-radius:12px;padding:8px 11px;font-size:12px}.seer-chat__mic-button[data-v-4cdc6832],.seer-chat__attach-button[data-v-4cdc6832]{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-4cdc6832]:not(:disabled):hover,.seer-chat__attach-button[data-v-4cdc6832]:not(:disabled):hover{background:#dfe8ff}.seer-chat__file-input[data-v-4cdc6832]{display:none}.seer-chat__attachments[data-v-4cdc6832]{flex-wrap:wrap;gap:6px;margin:0 0 8px;padding:0;list-style:none;display:flex}.seer-chat__attachment[data-v-4cdc6832]{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-4cdc6832]{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.seer-chat__attachment-remove[data-v-4cdc6832]{color:#4b5878;background:0 0;border-radius:50%;width:20px;height:20px;padding:0;line-height:1}.seer-chat__attachment-remove[data-v-4cdc6832]:hover{background:#dfe8ff}.seer-chat__mic-button--recording[data-v-4cdc6832]{color:#fff;background:#d9342b;animation:1.4s ease-in-out infinite seer-chat__recording-pulse-4cdc6832;box-shadow:0 0 0 5px #d9342b24}.seer-chat__mic-button--recording[data-v-4cdc6832]:not(:disabled):hover{background:#bd271f}.seer-chat__stop-icon[data-v-4cdc6832]{background:currentColor;border-radius:3px;width:12px;height:12px}@keyframes seer-chat__recording-pulse-4cdc6832{50%{box-shadow:0 0 0 9px #d9342b14}}.seer-chat__send-button[data-v-4cdc6832]{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-4cdc6832]:not(:disabled):hover{box-shadow:0 14px 28px #1f5eff47}.seer-chat__hint[data-v-4cdc6832]{color:#7a879a;margin-right:auto;font-size:12px}.seer-chat__composer-footer[data-v-4cdc6832]{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 type { SeerChatCallbacks, SeerChatMessage, SeerChatRequest, SeerChatResult, SeerChatRole, SeerClient, SeerClientOptions, SeerTranscriptionCallbacks, SeerTranscriptionResult, SeerUploadedFile, } from './client';
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, 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";
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 y(e) {
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;
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 = await t(e.endpoint, {
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 (!c.ok) throw Error(await T(c));
25
- return a ? C(c, i.onDelta) : S(await c.json());
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 T(c));
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 T(c));
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 = b(e.orgOwner);
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 T(i));
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 b(e) {
94
+ function x(e) {
86
95
  return (typeof e == "function" ? e() : e)?.trim() || void 0;
87
96
  }
88
- function x(e, t, n) {
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 S(e) {
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 C(e, t) {
103
- if (!e.body) return S({});
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: d } = await n.read();
116
+ let { done: e, value: f } = await n.read();
107
117
  if (e) break;
108
- i += r.decode(d, { stream: !0 });
109
- let f = i.split("\n\n");
110
- i = f.pop() ?? "";
111
- for (let e of f) {
112
- let n = w(e);
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
- u = !0;
125
+ d = !0;
116
126
  continue;
117
127
  }
118
- let r = JSON.parse(n), i = r.choices?.[0], d = i?.delta?.content ?? i?.message?.content ?? "";
119
- d && (a += d, t?.(d)), o = r.conversation_id ?? o, s = r.citations ?? s, c = r.handoff_requested ?? c, l = i?.finish_reason ?? l;
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 (!u) throw Error("seer chat stream ended before [DONE]");
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 w(e) {
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 T(e) {
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 E = /https?:\/\/[^\s)\u3000-\u303f\u4e00-\u9fff\uff00-\uffef]+/g, D = /\.(png|jpe?g|gif|webp|bmp|svg)$/i, O = "链接生成中…", k = "图片加载中…", A = /* @__PURE__ */ RegExp("(单价\\s*\\d[\\d.]*\\s*[A-Za-z]+\\/(?:kg|方))|(按当前信息为您筛选出[^\\n:]*推荐方案[^\\n:]*:)|(方案PK|时效最快|价格最低)", "g");
148
- function j(e) {
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
- A.lastIndex = 0;
161
+ j.lastIndex = 0;
151
162
  let n = 0, r;
152
- for (; (r = A.exec(e)) !== null;) {
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,74 +179,100 @@ function j(e) {
168
179
  value: e.slice(n)
169
180
  }), t;
170
181
  }
171
- var M = /标签|箱唛|唛头|入库单|交接单|入仓单|面单|下载/;
172
- function N(e, t) {
182
+ var N = /标签|箱唛|唛头|入库单|交接单|入仓单|面单|下载/;
183
+ function P(e, t) {
173
184
  if (/方案|截图|报价图|效果图|示意图|图片/.test(t)) return !0;
174
- if (M.test(t)) return !1;
185
+ if (N.test(t)) return !1;
175
186
  let n = e.split(/[?#]/)[0];
176
- return D.test(n);
187
+ return O.test(n);
177
188
  }
178
- function P(e) {
189
+ function F(e) {
179
190
  return /方案|报价|截图|PK/.test(e) ? "方案PK" : "图片";
180
191
  }
181
- function F(e) {
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 I(e, t = {}) {
195
+ function L(e, t = {}) {
185
196
  let n = [];
186
- E.lastIndex = 0;
197
+ D.lastIndex = 0;
187
198
  let r = 0, i;
188
- for (; (i = E.exec(e)) !== null;) {
189
- let a = i[0], o = i.index, s = e.lastIndexOf("\n", o - 1) + 1, c = e.slice(s, o), l = N(a, c), u = !t.complete && o + a.length === e.length;
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(...j(t));
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 ? k : O
207
+ value: l ? A : k
197
208
  }) : l ? n.push({
198
209
  kind: "image",
199
210
  href: a,
200
- alt: P(c)
211
+ alt: F(c)
201
212
  }) : n.push({
202
213
  kind: "link",
203
214
  href: a,
204
- label: F(c) ?? a
215
+ label: I(c) ?? a
205
216
  }), r = o + a.length;
206
217
  }
207
- return r < e.length && n.push(...j(e.slice(r))), n;
218
+ return r < e.length && n.push(...M(e.slice(r))), n;
208
219
  }
209
- function L(e, t = {}) {
220
+ function R(e, t = {}) {
210
221
  let n = e.split("\n");
211
- return n.map((e, r) => I(e, { complete: t.complete || r < n.length - 1 }));
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 R = Symbol("seer-chat-options"), z = { install(e, t) {
215
- e.provide(R, t);
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 B(e = {}) {
219
- let t = o() ? s(R, void 0) : void 0, n = Object.fromEntries(Object.entries(e).filter(([, e]) => e !== void 0)), r = {
254
+ function ee(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 = y({
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: () => b(e.orgOwner) ?? b(t?.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 = 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) {
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;
271
+ async function S(e, t = {}) {
235
272
  v.value = !0, l.value = null;
236
273
  try {
237
- let t = await i.upload(e, e.name);
238
- _.value = [..._.value, t];
274
+ let n = await i.upload(e, e.name);
275
+ _.value = t.replace ? [n] : [..._.value, n];
239
276
  } catch (e) {
240
277
  l.value = e instanceof Error ? e.message : String(e);
241
278
  } finally {
@@ -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 || c.value || v.value) return;
251
- let o = {
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, o], c.value = !0, l.value = null, x = new AbortController();
256
- let s = {
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, s]);
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: x.signal,
305
+ signal: y.signal,
269
306
  onDelta(e) {
270
- s.content += e, a.value = [...a.value];
307
+ c.content += e, a.value = [...a.value];
271
308
  }
272
309
  });
273
- r.stream || (a.value = [...a.value, {
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
- }]), u.value = e.conversationId, f.value = e.citations, p.value = e.handoffRequested;
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
- c.value = !1, x = null;
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, f.value = [], p.value = !1;
322
+ a.value = [], _.value = [], l.value = null, u.value = void 0, d.value = [], p.value = !1;
285
323
  }
286
324
  function E() {
287
- x?.abort();
325
+ y?.abort();
288
326
  }
289
327
  return {
290
328
  messages: a,
291
- loading: c,
329
+ loading: o,
292
330
  error: l,
293
331
  conversationId: u,
294
- citations: f,
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/SeerChat.vue?vue&type=script&setup=true&lang.ts
310
- var ee = {
347
+ // src/components/SeerOrderCard.vue?vue&type=script&setup=true&lang.ts
348
+ var W = ["aria-label"], G = { class: "seer-order-card__title" }, K = { class: "seer-order-card__panel" }, q = { class: "seer-order-card__channel" }, J = { class: "seer-order-card__rows" }, Y = { class: "seer-order-card__label" }, X = {
349
+ key: 0,
350
+ class: "seer-order-card__row"
351
+ }, Z = { class: "seer-order-card__label" }, Q = { class: "seer-order-card__value" }, $ = {
352
+ key: 0,
353
+ class: "seer-order-card__subsidy"
354
+ }, te = { class: "seer-order-card__total" }, ne = ["title"], re = { class: "seer-order-card__total-value" }, ie = ["disabled"], ae = {
355
+ key: 2,
356
+ class: "seer-order-card__blocked",
357
+ role: "note"
358
+ }, oe = /*@__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", G, m(t.card.title), 1), a("div", K, [
371
+ a("h4", q, m(t.card.channel_name), 1),
372
+ a("dl", J, [(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", Y, 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", X, [a("dt", Z, m(t.card.coupon.label), 1), a("dd", Q, m(t.card.coupon.value), 1)])) : r("", !0)]),
376
+ t.card.subsidy ? (d(), i("div", $, [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", te, [a("span", {
378
+ class: "seer-order-card__label",
379
+ title: t.card.note
380
+ }, m(t.card.total.label), 9, ne), a("span", re, 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, ie)) : t.card.blocked_reason ? (d(), i("p", ae, m(t.card.blocked_reason), 1)) : r("", !0)
388
+ ])], 8, W));
389
+ }
390
+ }), se = (e, t) => {
391
+ let n = e.__vccOpts || e;
392
+ for (let [e, r] of t) n[e] = r;
393
+ return n;
394
+ }, ce = /*#__PURE__*/ se(oe, [["__scopeId", "data-v-17d9e82e"]]), le = {
311
395
  class: "seer-chat",
312
396
  "aria-label": "多发货 AI 客服聊天"
313
- }, te = { class: "seer-chat__header" }, ne = {
397
+ }, ue = { class: "seer-chat__header" }, de = {
314
398
  class: "seer-chat__messages",
315
399
  "aria-live": "polite"
316
- }, re = {
400
+ }, fe = {
317
401
  key: 0,
318
402
  class: "seer-chat__empty"
319
- }, V = { class: "seer-chat__role" }, H = { class: "seer-chat__body" }, U = ["href"], W = ["aria-label", "onClick"], G = ["src", "alt"], K = {
403
+ }, pe = { class: "seer-chat__role" }, me = { class: "seer-chat__body" }, he = ["href"], ge = ["aria-label", "onClick"], _e = ["src", "alt"], ve = {
320
404
  key: 2,
321
405
  class: "seer-chat__strong"
322
- }, q = {
406
+ }, ye = {
323
407
  key: 3,
324
408
  class: "seer-chat__price"
325
- }, J = { key: 4 }, Y = {
409
+ }, be = {
410
+ key: 4,
411
+ class: "seer-chat__label-text"
412
+ }, xe = { key: 5 }, Se = {
326
413
  key: 0,
327
414
  class: "seer-chat__status"
328
- }, ie = {
415
+ }, Ce = {
329
416
  key: 1,
330
417
  class: "seer-chat__error",
331
418
  role: "alert"
332
- }, ae = {
419
+ }, we = {
333
420
  key: 2,
334
421
  class: "seer-chat__handoff"
335
- }, oe = {
422
+ }, Te = {
336
423
  key: 0,
337
424
  class: "seer-chat__attachments",
338
425
  "aria-label": "待发送的附件"
339
- }, se = { class: "seer-chat__attachment-name" }, ce = ["aria-label", "onClick"], le = [
426
+ }, Ee = { class: "seer-chat__attachment-name" }, De = ["aria-label", "onClick"], Oe = [
340
427
  "placeholder",
341
428
  "disabled",
342
429
  "onKeydown"
343
- ], ue = { class: "seer-chat__composer-footer" }, de = {
430
+ ], ke = { class: "seer-chat__composer-footer" }, Ae = {
344
431
  class: "seer-chat__hint",
345
432
  "aria-live": "polite"
346
- }, fe = ["disabled"], pe = [
433
+ }, je = ["disabled"], Me = [
347
434
  "disabled",
348
435
  "aria-label",
349
436
  "title"
350
- ], me = {
437
+ ], Ne = {
351
438
  key: 0,
352
439
  class: "seer-chat__stop-icon",
353
440
  "aria-hidden": "true"
354
- }, he = {
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
- }, ge = ["disabled"], X = ["aria-label"], _e = ["src", "alt"], ve = ".xlsx,.xls,.csv,.png,.jpg,.jpeg,.webp,.pdf", Z = /*#__PURE__*/ ((e, t) => {
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__*/ se(/* @__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,110 @@ var ee = {
387
471
  },
388
472
  maxRecordingSeconds: {}
389
473
  },
390
- setup(a) {
391
- let o = a, s = d(""), y = d(!1), b = d(!1), x = d(null), S = B({
392
- endpoint: o.endpoint,
393
- sessionEndpoint: o.sessionEndpoint,
394
- transcriptionEndpoint: o.transcriptionEndpoint,
395
- uploadEndpoint: o.uploadEndpoint,
396
- uploadEnabled: o.uploadEnabled,
397
- orgOwner: () => o.orgOwner,
398
- model: o.model,
399
- stream: o.stream,
400
- fetcher: o.fetcher,
401
- voiceEnabled: o.voiceEnabled,
402
- maxRecordingSeconds: o.maxRecordingSeconds
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) {
474
+ setup(o) {
475
+ let s = o, c = Re.split(","), b = f(""), x = f(!1), S = f(!1), C = f(null), w = ee({
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
+ }), T = f(null), E = f(!1), D = f(null), O = t(() => (b.value.trim().length > 0 || w.attachments.value.length > 0) && !w.loading.value && !w.uploading.value && !x.value && !S.value);
489
+ async function k(e) {
405
490
  let t = e.target, n = Array.from(t.files ?? []);
406
491
  t.value = "";
407
- for (let e of n) await S.attach(e);
492
+ for (let e of n) await w.attach(e);
408
493
  }
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();
494
+ function A(e) {
495
+ w.uploadEnabled && e.dataTransfer?.types.includes("Files") && (e.preventDefault(), E.value = !0);
412
496
  }
413
- function P(e, t) {
414
- M.value = {
497
+ async function j(e) {
498
+ E.value = !1;
499
+ let t = e.dataTransfer?.files?.[0];
500
+ if (!w.uploadEnabled || !t) return;
501
+ e.preventDefault(), D.value = null;
502
+ let n = t.name.slice(t.name.lastIndexOf(".")).toLowerCase();
503
+ c.includes(n) ? w.loading.value || w.uploading.value || await w.attach(t, { replace: !0 }) : D.value = "不支持这种文件,请拖入 Excel(xlsx / xls / csv)、图片或 PDF。";
504
+ }
505
+ let M = t(() => w.transcriptionEnabled && typeof navigator < "u" && typeof navigator.mediaDevices?.getUserMedia == "function" && typeof MediaRecorder < "u"), N = null, P = null, F = [], I, L = !1, z = f(null);
506
+ function B(e) {
507
+ e.key === "Escape" && U();
508
+ }
509
+ function H(e, t) {
510
+ z.value = {
415
511
  src: e,
416
512
  alt: t
417
- }, window.addEventListener("keydown", N);
513
+ }, window.addEventListener("keydown", B);
418
514
  }
419
- function F() {
420
- M.value = null, window.removeEventListener("keydown", N);
515
+ function U() {
516
+ z.value = null, window.removeEventListener("keydown", B);
421
517
  }
422
- l(() => {
423
- j = !0, window.removeEventListener("keydown", N), Q(), D && D.state !== "inactive" && (D.ondataavailable = null, D.onstop = null, D.onerror = null, D.stop()), $();
518
+ u(() => {
519
+ L = !0, window.removeEventListener("keydown", B), Q(), N && N.state !== "inactive" && (N.ondataavailable = null, N.onstop = null, N.onerror = null, N.stop()), $();
424
520
  });
425
- async function I() {
426
- if (!w.value) return;
427
- let e = s.value;
428
- s.value = "", await S.send(e);
521
+ async function W() {
522
+ if (!O.value) return;
523
+ let e = b.value;
524
+ b.value = "", await w.send(e);
429
525
  }
430
- async function R() {
431
- y.value ? Z() : await z();
526
+ async function G() {
527
+ x.value ? q() : await K();
432
528
  }
433
- async function z() {
434
- if (!(!E.value || b.value || S.loading.value)) {
435
- x.value = null;
529
+ async function K() {
530
+ if (!(!M.value || S.value || w.loading.value)) {
531
+ C.value = null;
436
532
  try {
437
- if (O = await navigator.mediaDevices.getUserMedia({
533
+ if (P = await navigator.mediaDevices.getUserMedia({
438
534
  audio: {
439
535
  echoCancellation: !0,
440
536
  noiseSuppression: !0
441
537
  },
442
538
  video: !1
443
- }), j) {
539
+ }), L) {
444
540
  $();
445
541
  return;
446
542
  }
447
- let e = be();
448
- D = e ? new MediaRecorder(O, {
543
+ let e = Y();
544
+ N = e ? new MediaRecorder(P, {
449
545
  mimeType: e,
450
546
  audioBitsPerSecond: 64e3
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 = () => {
456
- x.value = "录音失败,请重试或用文字输入。", y.value = !1, b.value = !1, Q(), $();
457
- }, D.start(), y.value = !0, A = setTimeout(Z, Math.max(1, S.maxRecordingSeconds) * 1e3);
547
+ }) : new MediaRecorder(P), F = [], N.ondataavailable = (e) => {
548
+ e.data.size > 0 && F.push(e.data);
549
+ }, N.onstop = () => {
550
+ J(N?.mimeType || e || "audio/webm");
551
+ }, N.onerror = () => {
552
+ C.value = "录音失败,请重试或用文字输入。", x.value = !1, S.value = !1, Q(), $();
553
+ }, N.start(), x.value = !0, I = setTimeout(q, Math.max(1, w.maxRecordingSeconds) * 1e3);
458
554
  } catch (e) {
459
- x.value = Se(e), $();
555
+ C.value = Z(e), $();
460
556
  }
461
557
  }
462
558
  }
463
- function Z() {
464
- D && D.state !== "inactive" && (y.value = !1, b.value = !0, Q(), D.stop());
559
+ function q() {
560
+ N && N.state !== "inactive" && (x.value = !1, S.value = !0, Q(), N.stop());
465
561
  }
466
- async function ye(e) {
562
+ async function J(e) {
467
563
  Q(), $();
468
- let t = k;
469
- if (k = [], D = null, j) return;
564
+ let t = F;
565
+ if (F = [], N = null, L) return;
470
566
  let n = new Blob(t, { type: e });
471
- if (n.size === 0) x.value = "没有录到声音,请重试。", b.value = !1;
567
+ if (n.size === 0) C.value = "没有录到声音,请重试。", S.value = !1;
472
568
  else try {
473
- let t = await S.transcribe(n, xe(e));
474
- s.value = s.value.trim() ? `${s.value.trim()} ${t.text}` : t.text;
569
+ let t = await w.transcribe(n, X(e));
570
+ b.value = b.value.trim() ? `${b.value.trim()} ${t.text}` : t.text;
475
571
  } catch {
476
- x.value = "语音识别失败,请重试或用文字输入。";
572
+ C.value = "语音识别失败,请重试或用文字输入。";
477
573
  } finally {
478
- b.value = !1;
574
+ S.value = !1;
479
575
  }
480
576
  }
481
- function be() {
577
+ function Y() {
482
578
  if (typeof MediaRecorder.isTypeSupported == "function") return [
483
579
  "audio/webm;codecs=opus",
484
580
  "audio/mp4",
@@ -486,149 +582,161 @@ var ee = {
486
582
  "audio/webm"
487
583
  ].find((e) => MediaRecorder.isTypeSupported(e));
488
584
  }
489
- function xe(e) {
585
+ function X(e) {
490
586
  return `recording.${{
491
587
  "audio/mp4": "m4a",
492
588
  "audio/ogg": "ogg",
493
589
  "audio/webm": "webm"
494
590
  }[e.split(";", 1)[0].toLowerCase()] || "webm"}`;
495
591
  }
496
- function Se(e) {
592
+ function Z(e) {
497
593
  return e instanceof DOMException && e.name === "NotAllowedError" ? "请允许浏览器使用麦克风。" : e instanceof DOMException && e.name === "NotFoundError" ? "未检测到可用的麦克风。" : "无法启动麦克风,请重试或用文字输入。";
498
594
  }
499
595
  function Q() {
500
- A !== void 0 && (clearTimeout(A), A = void 0);
596
+ I !== void 0 && (clearTimeout(I), I = void 0);
501
597
  }
502
598
  function $() {
503
- O?.getTracks().forEach((e) => e.stop()), O = null;
599
+ P?.getTracks().forEach((e) => e.stop()), P = null;
504
600
  }
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", {
601
+ return (t, s) => (d(), i("section", le, [
602
+ a("header", ue, [a("div", null, [a("h2", null, m(o.title), 1), s[5] ||= a("p", null, "可咨询渠道报价、时效、下单资料、入仓和售后问题。", -1)]), a("button", {
507
603
  type: "button",
508
604
  class: "seer-chat__clear-button",
509
- onClick: o[0] ||= (e) => m(S).reset()
605
+ onClick: s[0] ||= (e) => h(w).reset()
510
606
  }, " 清空对话 ")]),
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", {
512
- key: `${t.role}-${n}`,
513
- class: c(["seer-chat__message", `seer-chat__message--${t.role}`])
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", {
607
+ a("div", de, [h(w).messages.value.length === 0 ? (d(), i("p", fe, " 直接输入问题即可,复杂查单或赔付问题会提示转人工。 ")) : r("", !0), (d(!0), i(e, null, p(h(w).messages.value, (t, o) => (d(), i("article", {
608
+ key: `${t.role}-${o}`,
609
+ class: l(["seer-chat__message", `seer-chat__message--${t.role}`])
610
+ }, [a("span", pe, m(t.role === "user" ? "你" : "AI 客服"), 1), a("div", me, [(d(!0), i(e, null, p(h(R)(h(V)(t.content, t.orderCard), { complete: !(h(w).loading.value && o === h(w).messages.value.length - 1) }), (t, n) => (d(), i("p", {
515
611
  key: n,
516
612
  class: "seer-chat__line"
517
- }, [(u(!0), r(e, null, f(t, (t, n) => (u(), r(e, { key: n }, [t.kind === "link" ? (u(), r("a", {
613
+ }, [(d(!0), i(e, null, p(t, (t, n) => (d(), i(e, { key: n }, [t.kind === "link" ? (d(), i("a", {
518
614
  key: 0,
519
615
  class: "seer-chat__link",
520
616
  href: t.href,
521
617
  target: "_blank",
522
618
  rel: "noopener noreferrer"
523
- }, p(t.label), 9, U)) : t.kind === "image" ? (u(), r("button", {
619
+ }, m(t.label), 9, he)) : t.kind === "image" ? (d(), i("button", {
524
620
  key: 1,
525
621
  type: "button",
526
622
  class: "seer-chat__image-button",
527
623
  "aria-label": `放大查看${t.alt}`,
528
- onClick: (e) => P(t.href, t.alt)
529
- }, [i("img", {
624
+ onClick: (e) => H(t.href, t.alt)
625
+ }, [a("img", {
530
626
  class: "seer-chat__image",
531
627
  src: t.href,
532
628
  alt: t.alt,
533
629
  loading: "lazy"
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),
538
- i("form", {
539
- class: "seer-chat__form",
540
- onSubmit: v(I, ["prevent"])
630
+ }, null, 8, _e)], 8, ge)) : t.kind === "strong" ? (d(), i("strong", ve, m(t.value), 1)) : t.kind === "price" ? (d(), i("span", ye, m(t.value), 1)) : t.kind === "label" ? (d(), i("span", be, m(t.value), 1)) : (d(), i("span", xe, m(t.value), 1))], 64))), 128))]))), 128)), t.orderCard ? (d(), n(ce, {
631
+ key: 0,
632
+ card: t.orderCard,
633
+ disabled: h(w).loading.value || o !== h(w).messages.value.length - 1,
634
+ onSubmit: h(w).send
635
+ }, null, 8, [
636
+ "card",
637
+ "disabled",
638
+ "onSubmit"
639
+ ])) : r("", !0)])], 2))), 128))]),
640
+ h(w).loading.value ? (d(), i("p", Se, "正在回复...")) : r("", !0),
641
+ h(w).error.value || C.value || D.value ? (d(), i("p", Ce, m(C.value || D.value || h(w).error.value), 1)) : r("", !0),
642
+ h(w).handoffRequested.value ? (d(), i("p", we, " 建议转人工:请留下联系方式或等待客服接入。 ")) : r("", !0),
643
+ a("form", {
644
+ class: l(["seer-chat__form", { "seer-chat__form--dragging": E.value }]),
645
+ onSubmit: y(W, ["prevent"]),
646
+ onDragover: A,
647
+ onDragleave: s[4] ||= (e) => E.value = !1,
648
+ onDrop: j
541
649
  }, [
542
- o[8] ||= i("label", {
650
+ s[9] ||= a("label", {
543
651
  class: "seer-chat__label",
544
652
  for: "seer-chat-input"
545
653
  }, "问题", -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", {
654
+ h(w).attachments.value.length > 0 ? (d(), i("ul", Te, [(d(!0), i(e, null, p(h(w).attachments.value, (e) => (d(), i("li", {
547
655
  key: e.fileId,
548
656
  class: "seer-chat__attachment"
549
- }, [i("span", se, p(e.filename), 1), i("button", {
657
+ }, [a("span", Ee, m(e.filename), 1), a("button", {
550
658
  type: "button",
551
659
  class: "seer-chat__attachment-remove",
552
660
  "aria-label": `移除附件${e.filename}`,
553
- onClick: (t) => m(S).removeAttachment(e.fileId)
554
- }, " × ", 8, ce)]))), 128))])) : n("", !0),
555
- g(i("textarea", {
661
+ onClick: (t) => h(w).removeAttachment(e.fileId)
662
+ }, " × ", 8, De)]))), 128))])) : r("", !0),
663
+ _(a("textarea", {
556
664
  id: "seer-chat-input",
557
- "onUpdate:modelValue": o[1] ||= (e) => s.value = e,
558
- placeholder: a.placeholder,
559
- disabled: m(S).loading.value || b.value,
665
+ "onUpdate:modelValue": s[1] ||= (e) => b.value = e,
666
+ placeholder: o.placeholder,
667
+ disabled: h(w).loading.value || S.value,
560
668
  rows: "3",
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", {
669
+ onKeydown: v(y(W, ["exact", "prevent"]), ["enter"])
670
+ }, null, 40, Oe), [[g, b.value]]),
671
+ a("div", ke, [
672
+ a("span", Ae, m(x.value ? `正在录音,最长 ${h(w).maxRecordingSeconds} 秒` : S.value ? "正在识别语音..." : h(w).uploading.value ? "正在上传附件..." : E.value ? "松开即可上传(一次一个文件,会替换当前附件)" : "Enter 发送 · Shift+Enter 换行"), 1),
673
+ h(w).uploadEnabled ? (d(), i(e, { key: 0 }, [a("input", {
566
674
  ref_key: "fileInput",
567
- ref: C,
675
+ ref: T,
568
676
  class: "seer-chat__file-input",
569
677
  type: "file",
570
678
  multiple: "",
571
- accept: ve,
572
- onChange: T
573
- }, null, 544), i("button", {
679
+ accept: Re,
680
+ onChange: k
681
+ }, null, 544), a("button", {
574
682
  type: "button",
575
683
  class: "seer-chat__attach-button",
576
- disabled: m(S).loading.value || m(S).uploading.value,
684
+ disabled: h(w).loading.value || h(w).uploading.value,
577
685
  "aria-label": "上传附件",
578
686
  title: "上传下单模板、实物图片等",
579
- onClick: o[2] ||= (e) => C.value?.click()
580
- }, [...o[5] ||= [i("svg", {
687
+ onClick: s[2] ||= (e) => T.value?.click()
688
+ }, [...s[6] ||= [a("svg", {
581
689
  viewBox: "0 0 24 24",
582
690
  width: "20",
583
691
  height: "20",
584
692
  "aria-hidden": "true"
585
- }, [i("path", {
693
+ }, [a("path", {
586
694
  fill: "currentColor",
587
695
  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", {
696
+ })], -1)]], 8, je)], 64)) : r("", !0),
697
+ M.value ? (d(), i("button", {
590
698
  key: 1,
591
699
  type: "button",
592
- class: c(["seer-chat__mic-button", { "seer-chat__mic-button--recording": y.value }]),
593
- disabled: b.value || m(S).loading.value && !y.value,
594
- "aria-label": y.value ? "停止录音" : "开始语音输入",
595
- title: y.value ? "停止录音" : "语音输入",
596
- onClick: R
597
- }, [y.value ? (u(), r("span", me)) : (u(), r("svg", he, [...o[6] ||= [i("path", {
700
+ class: l(["seer-chat__mic-button", { "seer-chat__mic-button--recording": x.value }]),
701
+ disabled: S.value || h(w).loading.value && !x.value,
702
+ "aria-label": x.value ? "停止录音" : "开始语音输入",
703
+ title: x.value ? "停止录音" : "语音输入",
704
+ onClick: G
705
+ }, [x.value ? (d(), i("span", Ne)) : (d(), i("svg", Pe, [...s[7] ||= [a("path", {
598
706
  fill: "currentColor",
599
707
  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, pe)) : n("", !0),
601
- m(S).loading.value ? (u(), r("button", {
708
+ }, null, -1)]]))], 10, Me)) : r("", !0),
709
+ h(w).loading.value ? (d(), i("button", {
602
710
  key: 2,
603
711
  type: "button",
604
712
  class: "seer-chat__stop-button",
605
- onClick: o[3] ||= (e) => m(S).abort()
606
- }, " 停止 ")) : n("", !0),
607
- i("button", {
713
+ onClick: s[3] ||= (e) => h(w).abort()
714
+ }, " 停止 ")) : r("", !0),
715
+ a("button", {
608
716
  class: "seer-chat__send-button",
609
717
  type: "submit",
610
- disabled: !w.value
611
- }, [...o[7] ||= [i("span", null, "发送", -1), i("span", { "aria-hidden": "true" }, "↵", -1)]], 8, ge)
718
+ disabled: !O.value
719
+ }, [...s[8] ||= [a("span", null, "发送", -1), a("span", { "aria-hidden": "true" }, "↵", -1)]], 8, Fe)
612
720
  ])
613
- ], 32),
614
- M.value ? (u(), r("div", {
721
+ ], 34),
722
+ z.value ? (d(), i("div", {
615
723
  key: 3,
616
724
  class: "seer-chat__lightbox",
617
725
  role: "dialog",
618
726
  "aria-modal": "true",
619
- "aria-label": M.value.alt,
620
- onClick: F
621
- }, [i("button", {
727
+ "aria-label": z.value.alt,
728
+ onClick: U
729
+ }, [a("button", {
622
730
  type: "button",
623
731
  class: "seer-chat__lightbox-close",
624
732
  "aria-label": "关闭",
625
- onClick: F
626
- }, " × "), i("img", {
733
+ onClick: U
734
+ }, " × "), a("img", {
627
735
  class: "seer-chat__lightbox-image",
628
- src: M.value.src,
629
- alt: M.value.alt
630
- }, null, 8, _e)], 8, X)) : n("", !0)
736
+ src: z.value.src,
737
+ alt: z.value.alt
738
+ }, null, 8, Le)], 8, Ie)) : r("", !0)
631
739
  ]));
632
740
  }
633
- }), [["__scopeId", "data-v-adaeb672"]]);
634
- export { Z as SeerChat, z as SeerChatPlugin, y as createSeerClient, F as linkAnchorLabel, L as toContentLines, I as toContentSegments, B as useSeerChat };
741
+ }), [["__scopeId", "data-v-4cdc6832"]]);
742
+ export { ze as SeerChat, U as SeerChatPlugin, ce as SeerOrderCard, b as createSeerClient, I as linkAnchorLabel, R as toContentLines, L as toContentSegments, ee as useSeerChat, V as withoutCardText };
@@ -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>;
@@ -36,7 +108,9 @@ export declare function useSeerChat(localOptions?: UseSeerChatOptions): {
36
108
  size: number;
37
109
  }[]>;
38
110
  uploading: import("vue").Ref<boolean, boolean>;
39
- attach: (file: File) => Promise<void>;
111
+ attach: (file: File, attachOptions?: {
112
+ replace?: boolean;
113
+ }) => Promise<void>;
40
114
  removeAttachment: (fileId: string) => void;
41
115
  send: (content: string) => Promise<void>;
42
116
  reset: () => void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seer-ai/seer-vue",
3
- "version": "0.1.0-beta.11",
3
+ "version": "0.1.0-beta.13",
4
4
  "description": "Vue chat plugin for the seer OpenAI-compatible API",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",