@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 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-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 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,69 +179,95 @@ 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 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 = 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;
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 || 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 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
- }, te = { class: "seer-chat__header" }, ne = {
397
+ }, de = { class: "seer-chat__header" }, fe = {
314
398
  class: "seer-chat__messages",
315
399
  "aria-live": "polite"
316
- }, re = {
400
+ }, pe = {
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
+ }, 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
- }, q = {
406
+ }, be = {
323
407
  key: 3,
324
408
  class: "seer-chat__price"
325
- }, J = { key: 4 }, Y = {
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
- }, ie = {
415
+ }, we = {
329
416
  key: 1,
330
417
  class: "seer-chat__error",
331
418
  role: "alert"
332
- }, ae = {
419
+ }, Te = {
333
420
  key: 2,
334
421
  class: "seer-chat__handoff"
335
- }, oe = {
422
+ }, Ee = {
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
+ }, De = { class: "seer-chat__attachment-name" }, Oe = ["aria-label", "onClick"], $ = [
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__*/ 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(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 = 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 S.attach(e);
492
+ for (let e of n) await C.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
+ 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 P(e, t) {
414
- M.value = {
498
+ function F(e, t) {
499
+ N.value = {
415
500
  src: e,
416
501
  alt: t
417
- }, window.addEventListener("keydown", N);
502
+ }, window.addEventListener("keydown", P);
418
503
  }
419
- function F() {
420
- M.value = null, window.removeEventListener("keydown", N);
504
+ function I() {
505
+ N.value = null, window.removeEventListener("keydown", P);
421
506
  }
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()), $();
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 I() {
426
- if (!w.value) return;
427
- let e = s.value;
428
- s.value = "", await S.send(e);
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
- if (!(!E.value || b.value || S.loading.value)) {
435
- x.value = null;
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 (O = await navigator.mediaDevices.getUserMedia({
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
- }), j) {
444
- $();
528
+ }), M) {
529
+ Y();
445
530
  return;
446
531
  }
447
- let e = be();
448
- D = e ? new MediaRecorder(O, {
532
+ let e = G();
533
+ O = e ? new MediaRecorder(k, {
449
534
  mimeType: e,
450
535
  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);
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
- x.value = Se(e), $();
544
+ S.value = q(e), Y();
460
545
  }
461
546
  }
462
547
  }
463
- function Z() {
464
- D && D.state !== "inactive" && (y.value = !1, b.value = !0, Q(), D.stop());
548
+ function H() {
549
+ O && O.state !== "inactive" && (b.value = !1, x.value = !0, J(), O.stop());
465
550
  }
466
- async function ye(e) {
467
- Q(), $();
468
- let t = k;
469
- if (k = [], D = null, j) return;
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) x.value = "没有录到声音,请重试。", b.value = !1;
556
+ if (n.size === 0) S.value = "没有录到声音,请重试。", x.value = !1;
472
557
  else try {
473
- let t = await S.transcribe(n, xe(e));
474
- s.value = s.value.trim() ? `${s.value.trim()} ${t.text}` : t.text;
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
- x.value = "语音识别失败,请重试或用文字输入。";
561
+ S.value = "语音识别失败,请重试或用文字输入。";
477
562
  } finally {
478
- b.value = !1;
563
+ x.value = !1;
479
564
  }
480
565
  }
481
- function be() {
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 xe(e) {
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 Se(e) {
581
+ function q(e) {
497
582
  return e instanceof DOMException && e.name === "NotAllowedError" ? "请允许浏览器使用麦克风。" : e instanceof DOMException && e.name === "NotFoundError" ? "未检测到可用的麦克风。" : "无法启动麦克风,请重试或用文字输入。";
498
583
  }
499
- function Q() {
500
- A !== void 0 && (clearTimeout(A), A = void 0);
584
+ function J() {
585
+ j !== void 0 && (clearTimeout(j), j = void 0);
501
586
  }
502
- function $() {
503
- O?.getTracks().forEach((e) => e.stop()), O = null;
587
+ function Y() {
588
+ k?.getTracks().forEach((e) => e.stop()), k = null;
504
589
  }
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", {
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: o[0] ||= (e) => m(S).reset()
594
+ onClick: s[0] ||= (e) => h(C).reset()
510
595
  }, " 清空对话 ")]),
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", {
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
- }, [(u(!0), r(e, null, f(t, (t, n) => (u(), r(e, { key: n }, [t.kind === "link" ? (u(), r("a", {
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
- }, p(t.label), 9, U)) : t.kind === "image" ? (u(), r("button", {
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) => P(t.href, t.alt)
529
- }, [i("img", {
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, 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", {
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: v(I, ["prevent"])
634
+ onSubmit: y(L, ["prevent"])
541
635
  }, [
542
- o[8] ||= i("label", {
636
+ s[8] ||= a("label", {
543
637
  class: "seer-chat__label",
544
638
  for: "seer-chat-input"
545
639
  }, "问题", -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", {
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
- }, [i("span", se, p(e.filename), 1), i("button", {
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) => m(S).removeAttachment(e.fileId)
554
- }, " × ", 8, ce)]))), 128))])) : n("", !0),
555
- g(i("textarea", {
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": o[1] ||= (e) => s.value = e,
558
- placeholder: a.placeholder,
559
- disabled: m(S).loading.value || b.value,
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: _(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", {
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: C,
661
+ ref: w,
568
662
  class: "seer-chat__file-input",
569
663
  type: "file",
570
664
  multiple: "",
571
- accept: ve,
572
- onChange: T
573
- }, null, 544), i("button", {
665
+ accept: Re,
666
+ onChange: E
667
+ }, null, 544), a("button", {
574
668
  type: "button",
575
669
  class: "seer-chat__attach-button",
576
- disabled: m(S).loading.value || m(S).uploading.value,
670
+ disabled: h(C).loading.value || h(C).uploading.value,
577
671
  "aria-label": "上传附件",
578
672
  title: "上传下单模板、实物图片等",
579
- onClick: o[2] ||= (e) => C.value?.click()
580
- }, [...o[5] ||= [i("svg", {
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
- }, [i("path", {
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, fe)], 64)) : n("", !0),
589
- E.value ? (u(), r("button", {
682
+ })], -1)]], 8, je)], 64)) : r("", !0),
683
+ D.value ? (d(), i("button", {
590
684
  key: 1,
591
685
  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", {
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, pe)) : n("", !0),
601
- m(S).loading.value ? (u(), r("button", {
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: o[3] ||= (e) => m(S).abort()
606
- }, " 停止 ")) : n("", !0),
607
- i("button", {
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: !w.value
611
- }, [...o[7] ||= [i("span", null, "发送", -1), i("span", { "aria-hidden": "true" }, "↵", -1)]], 8, ge)
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
- M.value ? (u(), r("div", {
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": M.value.alt,
620
- onClick: F
621
- }, [i("button", {
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: F
626
- }, " × "), i("img", {
719
+ onClick: I
720
+ }, " × "), a("img", {
627
721
  class: "seer-chat__lightbox-image",
628
- src: M.value.src,
629
- alt: M.value.alt
630
- }, null, 8, _e)], 8, X)) : n("", !0)
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-adaeb672"]]);
634
- export { Z as SeerChat, z as SeerChatPlugin, y as createSeerClient, F as linkAnchorLabel, L as toContentLines, I as toContentSegments, B as useSeerChat };
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 };
@@ -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>;
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.12",
4
4
  "description": "Vue chat plugin for the seer OpenAI-compatible API",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",