From b5abf3253057e4b7faecca9dbfe6751e1400718e Mon Sep 17 00:00:00 2001 From: wanghanlin <1533525126@qq.com> Date: Mon, 10 Aug 2026 14:41:37 +0800 Subject: [PATCH] =?UTF-8?q?=E8=BF=81=E7=A7=BB=E5=88=B0=20TDesign=20?= =?UTF-8?q?=E6=9E=B6=E6=9E=84=E6=97=B6=E6=BC=8F=E6=8E=89=E4=BA=86=E6=96=87?= =?UTF-8?q?=E6=A1=A3=E4=B8=8A=E4=BC=A0=E8=B7=AF=E7=94=B1=E5=92=8C=E8=8F=9C?= =?UTF-8?q?=E5=8D=95=E5=85=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/dist/chatbot-sdk.js | 266 ++++++++++++++++-- client/dist/chatbot-sdk.min.js | 2 +- client/src/api.ts | 24 +- client/src/chat.ts | 84 ++++-- client/src/dom.ts | 87 ++++++ client/src/i18n.ts | 14 + client/src/styles.ts | 95 +++++++ client/src/types.ts | 4 + frontend/auto-imports.d.ts | 2 +- frontend/src/router/index.ts | 2 + frontend/src/stores/navigation.ts | 1 + frontend/src/views/ChatPanel.vue | 11 +- frontend/src/views/DashboardPanel.vue | 18 +- .../com/wok/supportbot/app/ChatPipeline.java | 20 ++ .../com/wok/supportbot/rag/RagPipeline.java | 33 +++ .../supportbot/security/SdkAuthFilter.java | 4 +- .../supportbot/service/DashboardService.java | 202 ++++++++++--- .../service/MessageFeedbackService.java | 22 +- src/main/resources/static/sdk/chatbot-sdk.js | 266 ++++++++++++++++-- .../resources/static/sdk/chatbot-sdk.min.js | 2 +- .../wok/supportbot/MessageFeedbackTests.java | 227 +++++++++++++++ 21 files changed, 1254 insertions(+), 132 deletions(-) create mode 100644 src/test/java/com/wok/supportbot/MessageFeedbackTests.java diff --git a/client/dist/chatbot-sdk.js b/client/dist/chatbot-sdk.js index 45f3b70..4421fbd 100644 --- a/client/dist/chatbot-sdk.js +++ b/client/dist/chatbot-sdk.js @@ -199,6 +199,13 @@ var ChatbotSDK = (function () { // 消息反馈 feedback_up: '有帮助', feedback_down: '没帮助', + feedback_reason_title: '请选择不满意的原因:', + feedback_reason_inaccurate: '信息错误', + feedback_reason_irrelevant: '不相关', + feedback_reason_incomplete: '不完整', + feedback_reason_other: '其他', + feedback_reason_comment_placeholder: '补充说明(可选)', + feedback_reason_submit: '提交', // 提示气泡 teaser_text: '有什么可以帮你的吗?', new_msg_announce: '收到新消息', @@ -266,6 +273,13 @@ var ChatbotSDK = (function () { // Feedback feedback_up: 'Helpful', feedback_down: 'Not helpful', + feedback_reason_title: 'Please tell us why:', + feedback_reason_inaccurate: 'Inaccurate', + feedback_reason_irrelevant: 'Irrelevant', + feedback_reason_incomplete: 'Incomplete', + feedback_reason_other: 'Other', + feedback_reason_comment_placeholder: 'Additional comments (optional)', + feedback_reason_submit: 'Submit', // Teaser teaser_text: 'How can I help you?', new_msg_announce: 'New message received', @@ -457,11 +471,12 @@ var ChatbotSDK = (function () { Object.assign(headers, options.headers); } } - if ((currentConfig === null || currentConfig === void 0 ? void 0 : currentConfig.token) && url.includes('/ai/')) { + // 为受 SdkAuthFilter 保护的路径自动注入 Bearer Token(/ai/** 和 /feedback) + if ((currentConfig === null || currentConfig === void 0 ? void 0 : currentConfig.token) && (url.includes('/ai/') || url.endsWith('/feedback'))) { headers['Authorization'] = `Bearer ${currentConfig.token}`; } const response = await fetch(url, Object.assign(Object.assign({}, options), { headers, signal: controller.signal, mode: 'cors', credentials: 'include' })); - if (response.status === 401 && url.includes('/ai/')) { + if (response.status === 401 && (url.includes('/ai/') || url.endsWith('/feedback'))) { logger.error('SDK 认证失败:Token 缺失或已过期,请重新调用 /open-api/auth/token 换取 Token'); } return response; @@ -724,21 +739,26 @@ var ChatbotSDK = (function () { } // ==================== P0-002: 消息反馈 ==================== /** - * 提交消息反馈(点赞/点踩) + * 提交消息反馈(点赞/点踩),支持点踩原因分类 */ - async function submitFeedbackApi(messageId, feedbackType) { + async function submitFeedbackApi(messageId, feedbackType, reasonCategory, reasonComment) { if (!currentConfig) return false; const url = buildUrl('/feedback'); try { + const body = { + messageId: String(messageId), + conversationId: currentConfig.chatId, + feedbackType, + }; + if (reasonCategory) + body.reasonCategory = reasonCategory; + if (reasonComment) + body.reasonComment = reasonComment; const response = await safeFetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - messageId: String(messageId), - conversationId: currentConfig.chatId, - feedbackType, - }), + body: JSON.stringify(body), }); if (!response.ok) { logger.error(`反馈提交失败 status=${response.status}`); @@ -2377,6 +2397,101 @@ var ChatbotSDK = (function () { .csk-feedback-btn:active { transform: scale(0.9); } .csk-msg--streaming .csk-feedback-btn { display: none; } +/* ========== 点踩原因选择面板 ========== */ +.csk-feedback-reason { + position: relative; + margin-top: 6px; + padding: 10px 12px; + background: var(--csk-bg); + border: 1px solid var(--csk-border); + border-radius: 8px; + animation: cskFadeIn 0.15s ease; +} +.csk-feedback-reason__title { + font-size: 12px; + color: var(--csk-text-muted); + margin-bottom: 8px; +} +.csk-feedback-reason__options { + display: flex; + flex-wrap: wrap; + gap: 6px; + margin-bottom: 8px; +} +.csk-feedback-reason__btn { + padding: 4px 10px; + font-size: 12px; + border: 1px solid var(--csk-border); + border-radius: 14px; + background: var(--csk-bg); + color: var(--csk-text); + cursor: pointer; + transition: all 0.15s ease; +} +.csk-feedback-reason__btn:hover { + border-color: var(--csk-primary); + color: var(--csk-primary); + background: rgba(var(--csk-primary-rgb), 0.08); +} +.csk-feedback-reason__comment-row { + display: flex; + gap: 6px; +} +.csk-feedback-reason__comment { + flex: 1; + padding: 4px 8px; + font-size: 12px; + border: 1px solid var(--csk-border); + border-radius: 6px; + background: var(--csk-bg); + color: var(--csk-text); + outline: none; +} +.csk-feedback-reason__comment:focus { border-color: var(--csk-primary); } +.csk-feedback-reason__submit { + padding: 4px 10px; + font-size: 12px; + border: none; + border-radius: 6px; + background: var(--csk-primary); + color: #fff; + cursor: pointer; + white-space: nowrap; +} +.csk-feedback-reason__close { + position: absolute; + top: 8px; + right: 8px; + width: 18px; + height: 18px; + border: none; + background: none; + color: var(--csk-text-muted); + cursor: pointer; + padding: 0; + display: flex; + align-items: center; + justify-content: center; + border-radius: 4px; +} +.csk-feedback-reason__close:hover { color: var(--csk-text); background: var(--csk-hover); } +.csk-dark .csk-feedback-reason { background: var(--csk-bg); border-color: var(--csk-border); } +.csk-dark .csk-feedback-reason__btn { + background: rgba(255,255,255,0.06); + border-color: var(--csk-border); + color: var(--csk-text); +} +.csk-dark .csk-feedback-reason__btn:hover { + border-color: var(--csk-primary-light); + color: var(--csk-primary-light); + background: rgba(var(--csk-primary-rgb), 0.15); +} +.csk-dark .csk-feedback-reason__comment { + background: rgba(255,255,255,0.06); + border-color: var(--csk-border); + color: var(--csk-text); +} + /* ========== 历史会话搜索框 ========== */ .csk-history-panel__search-wrap { padding: 8px 10px; @@ -3740,6 +3855,80 @@ var ChatbotSDK = (function () { if (existing) existing.remove(); } + // ==================== 反馈原因选择面板 ==================== + /** 点踩原因选项(与后端 MessageFeedback.reasonCategory 枚举一致) */ + const REASON_OPTIONS = [ + { key: 'inaccurate', labelKey: 'feedback_reason_inaccurate' }, + { key: 'irrelevant', labelKey: 'feedback_reason_irrelevant' }, + { key: 'incomplete', labelKey: 'feedback_reason_incomplete' }, + { key: 'other', labelKey: 'feedback_reason_other' }, + ]; + /** + * 在消息气泡下方展示点踩原因选择面板 + * 用户选择原因后回调 onConfirm(reason, comment),取消时回调 undefined 参数 + */ + function showFeedbackReasonPanel(wrapper, msgId, onConfirm) { + // 移除已存在的原因面板 + const existing = wrapper.querySelector('.csk-feedback-reason'); + if (existing) + existing.remove(); + const panel = document.createElement('div'); + panel.className = 'csk-feedback-reason'; + // 标题 + const title = document.createElement('div'); + title.className = 'csk-feedback-reason__title'; + title.textContent = t('feedback_reason_title'); + panel.appendChild(title); + // 原因选项按钮 + const optionsRow = document.createElement('div'); + optionsRow.className = 'csk-feedback-reason__options'; + REASON_OPTIONS.forEach((opt) => { + const btn = document.createElement('button'); + btn.type = 'button'; + btn.className = 'csk-feedback-reason__btn'; + btn.textContent = t(opt.labelKey); + btn.addEventListener('click', (e) => { + e.stopPropagation(); + onConfirm(opt.key); + panel.remove(); + }); + optionsRow.appendChild(btn); + }); + panel.appendChild(optionsRow); + // 补充说明输入框(可选) + const commentRow = document.createElement('div'); + commentRow.className = 'csk-feedback-reason__comment-row'; + const commentInput = document.createElement('input'); + commentInput.type = 'text'; + commentInput.className = 'csk-feedback-reason__comment'; + commentInput.placeholder = t('feedback_reason_comment_placeholder'); + commentInput.maxLength = 200; + commentRow.appendChild(commentInput); + const submitBtn = document.createElement('button'); + submitBtn.type = 'button'; + submitBtn.className = 'csk-feedback-reason__submit'; + submitBtn.textContent = t('feedback_reason_submit'); + submitBtn.addEventListener('click', (e) => { + e.stopPropagation(); + const comment = commentInput.value.trim() || undefined; + onConfirm('other', comment); + panel.remove(); + }); + commentRow.appendChild(submitBtn); + panel.appendChild(commentRow); + // 关闭按钮 + const closeBtn = document.createElement('button'); + closeBtn.type = 'button'; + closeBtn.className = 'csk-feedback-reason__close'; + closeBtn.setAttribute('aria-label', t('close')); + closeBtn.innerHTML = ``; + closeBtn.addEventListener('click', (e) => { + e.stopPropagation(); + panel.remove(); + }); + panel.appendChild(closeBtn); + wrapper.appendChild(panel); + } const STORAGE_PREFIX = 'csk_history_'; const MAX_MESSAGES = 200; @@ -4330,6 +4519,7 @@ var ChatbotSDK = (function () { /** * 处理消息反馈:切换 AI 消息的点赞/点踩状态 * 前端状态持久化(存入 messages 数组 + localStorage)+ 调用后端 API 记录反馈 + * 点踩时弹出原因选择弹窗,点赞直接提交 */ function handleFeedback(msgId, value) { if (!messagesContainer$1) @@ -4337,20 +4527,50 @@ var ChatbotSDK = (function () { const msg = messages.find(m => m.id === msgId && m.role === 'ai'); if (!msg) return; - // 切换逻辑:同值取消,异值切换 - const newValue = msg.feedback === value ? undefined : value; - msg.feedback = newValue; - // 更新 DOM 状态 - const wrapper = messagesContainer$1.querySelector(`[data-csk-msg-id="${msgId}"]`); - if (wrapper) - updateFeedbackUI(wrapper, newValue); - // 持久化(localStorage) - if (config$1) - saveMessages(config$1.integrateId, messages); - // 调用后端 API 记录反馈 - if (newValue) { - const feedbackType = newValue === 'up' ? 'THUMBS_UP' : 'THUMBS_DOWN'; - submitFeedbackApi(String(msgId), feedbackType).then(success => { + if (value === 'up') { + // 点赞:直接切换提交,无需原因 + const newValue = msg.feedback === 'up' ? undefined : 'up'; + msg.feedback = newValue; + msg.feedbackReason = undefined; + msg.feedbackComment = undefined; + const wrapper = messagesContainer$1.querySelector(`[data-csk-msg-id="${msgId}"]`); + if (wrapper) + updateFeedbackUI(wrapper, newValue); + if (config$1) + saveMessages(config$1.integrateId, messages); + if (newValue) { + submitFeedbackApi(String(msgId), 'THUMBS_UP').then(success => { + }); + } + return; + } + // 点踩:弹出原因选择弹窗 + if (value === 'down') { + const wrapper = messagesContainer$1.querySelector(`[data-csk-msg-id="${msgId}"]`); + if (!wrapper) + return; + // 如果已点踩,取消(同 SDK 现有行为) + if (msg.feedback === 'down') { + msg.feedback = undefined; + msg.feedbackReason = undefined; + msg.feedbackComment = undefined; + if (wrapper) + updateFeedbackUI(wrapper, undefined); + if (config$1) + saveMessages(config$1.integrateId, messages); + return; + } + // 弹出原因选择面板 + showFeedbackReasonPanel(wrapper, msgId, (reason, comment) => { + msg.feedback = 'down'; + msg.feedbackReason = reason; + msg.feedbackComment = comment; + if (wrapper) + updateFeedbackUI(wrapper, 'down'); + if (config$1) + saveMessages(config$1.integrateId, messages); + submitFeedbackApi(String(msgId), 'THUMBS_DOWN', reason, comment).then(success => { + }); }); } } diff --git a/client/dist/chatbot-sdk.min.js b/client/dist/chatbot-sdk.min.js index b172006..72eedec 100644 --- a/client/dist/chatbot-sdk.min.js +++ b/client/dist/chatbot-sdk.min.js @@ -1 +1 @@ -var ChatbotSDK=function(){"use strict";let e=null;function n(n){e=n||null}const t={info(e,n){},warn(e,n){},error(n,t){if(e)try{const r=t instanceof Error&&t.type||"error";e({message:n,code:String(r),detail:t})}catch(e){}},time(e){},timeEnd:(e,n)=>0,lifecycleInit(e,n){},lifecycleDestroy(e){},lifecycleSend(e,n){},lifecycleReply(e,n){},lifecycleError(e,n,t){},lifecycleClear(e){},lifecycleStreamDone(e,n){},lifecycleCategoryChange(e){}};const r={"zh-CN":{title:"AI 智能助手",minimize:"最小化",close:"关闭",status_online:"在线",role_selector_label:"服务角色",welcome_title:"你好,我是 AI 智能助手",welcome_desc:"有什么可以帮你的吗?在下方输入框开始提问吧~",placeholder:"输入您的问题...",send:"发送",stop:"停止生成",new_message:"新消息",copy:"复制",copied:"已复制",retry:"重新生成",retrying:"重新生成中...",loading:"正在思考...",stream_interrupted:"回复被中断",stream_unstable:"网络不稳定,内容可能不完整",category_placeholder:"选择知识库分类",category_all:"全部分类",category_load_error:"加载分类失败",source_title:"参考来源",source_count:"{n} 条参考来源",source_loading:"加载来源中...",clear:"新对话",history_title:"历史会话",history_empty:"暂无历史会话",history_load_error:"加载会话列表失败",history_delete_confirm:"确定删除该会话?",history_export:"导出",history_delete:"删除",history_search:"搜索会话...",history_group_today:"今天",history_group_yesterday:"昨天",history_group_week:"本周",history_group_earlier:"更早",feedback_up:"有帮助",feedback_down:"没帮助",teaser_text:"有什么可以帮你的吗?",new_msg_announce:"收到新消息",resize:"拖拽缩放窗口",error_network:"网络连接失败,请检查网络",error_offline:"⚠️ 网络连接异常,请检查网络后重试",error_timeout:"请求超时,请稍后重试",error_server:"服务器异常,请稍后重试",error_cors:"跨域请求被拦截,请联系管理员将当前域名加入 API 白名单",error_auth:"鉴权失败,请联系管理员",error_forbidden:"无访问权限,请联系管理员配置",error_not_found:"请求的资源不存在",error_rate_limit:"请求过于频繁,请稍后重试",error_unavailable:"服务暂不可用,请稍后重试",error_unknown:"请求发生未知错误",error_send:"发送失败,请稍后重试",error_stream_unsupported:"浏览器不支持流式读取"},en:{title:"AI Assistant",minimize:"Minimize",close:"Close",status_online:"Online",role_selector_label:"Service",welcome_title:"Hi, I am your AI assistant",welcome_desc:"How can I help you? Type your question below to get started.",placeholder:"Type your question...",send:"Send",stop:"Stop generating",new_message:"New message",copy:"Copy",copied:"Copied",retry:"Regenerate",retrying:"Regenerating...",loading:"Thinking...",stream_interrupted:"Response interrupted",stream_unstable:"Network unstable, content may be incomplete",category_placeholder:"Select category",category_all:"All categories",category_load_error:"Failed to load categories",source_title:"Sources",source_count:"{n} source(s)",source_loading:"Loading sources...",clear:"New chat",history_title:"History",history_empty:"No conversations yet",history_load_error:"Failed to load conversations",history_delete_confirm:"Delete this conversation?",history_export:"Export",history_delete:"Delete",history_search:"Search conversations...",history_group_today:"Today",history_group_yesterday:"Yesterday",history_group_week:"This Week",history_group_earlier:"Earlier",feedback_up:"Helpful",feedback_down:"Not helpful",teaser_text:"How can I help you?",new_msg_announce:"New message received",resize:"Resize window",error_network:"Network connection failed",error_offline:"⚠️ Connection lost. Please check your network and try again.",error_timeout:"Request timed out, please try again",error_server:"Server error, please try again later",error_cors:"CORS request blocked. Please contact admin to whitelist your domain",error_auth:"Authentication failed, please contact admin",error_forbidden:"Access denied, please contact admin",error_not_found:"Resource not found",error_rate_limit:"Too many requests, please try again later",error_unavailable:"Service temporarily unavailable",error_unknown:"Unknown request error",error_send:"Failed to send, please try again",error_stream_unsupported:"Browser does not support streaming"}};let s="zh-CN";function o(e,n){let t=(r[s]||r["zh-CN"])[e]||r["zh-CN"][e]||e;if(n)for(const[e,r]of Object.entries(n))t=t.replace(`{${e}}`,String(r));return t}let a=null,i=null;function c(e){i=e}function l(){var e;return null!==(e=null!=i?i:null==a?void 0:a.integrateId)&&void 0!==e?e:""}function d(e){a&&(a.chatId=e)}function p(){return(null==a?void 0:a.chatId)||""}function u(e){if(!a)throw new Error("API 配置未初始化");return`${a.requestDomain.replace(/\/+$/,"")}${e.startsWith("/")?e:`/${e}`}`}function m(e,n,t){null!=t&&("string"==typeof t&&""===t.trim()||e.set(n,String(t)))}async function g(e,n={},r=3e4,s){const i=new AbortController,c=setTimeout(()=>i.abort(),r);s&&(s.aborted?i.abort():s.addEventListener("abort",()=>i.abort(),{once:!0}));try{const r={};n.headers&&(n.headers instanceof Headers?n.headers.forEach((e,n)=>{r[n]=e}):Array.isArray(n.headers)?n.headers.forEach(([e,n])=>{r[e]=n}):Object.assign(r,n.headers)),(null==a?void 0:a.token)&&e.includes("/ai/")&&(r.Authorization=`Bearer ${a.token}`);const s=await fetch(e,Object.assign(Object.assign({},n),{headers:r,signal:i.signal,mode:"cors",credentials:"include"}));return 401===s.status&&e.includes("/ai/")&&t.error("SDK 认证失败:Token 缺失或已过期,请重新调用 /open-api/auth/token 换取 Token"),s}catch(e){if(null==s?void 0:s.aborted)throw new h("aborted","aborted");if(e instanceof DOMException&&"AbortError"===e.name)throw new h(o("error_timeout"),"timeout");if(e instanceof TypeError&&e.message.includes("Failed to fetch"))throw new h(o("error_cors"),"cors");throw new h(o("error_network"),"network")}finally{clearTimeout(c)}}class h extends Error{constructor(e,n){super(e),this.name="CskError",this.type=n}}function k(e){switch(e){case 401:return o("error_auth");case 403:return o("error_forbidden");case 404:return o("error_not_found");case 429:return o("error_rate_limit");case 500:return o("error_server");case 502:case 503:return o("error_unavailable");default:return`${o("error_unknown")}(${e})`}}async function b(e){const n=function(e){const n=new URLSearchParams;return n.set("message",e),n.set("chatId",a.chatId),m(n,"roleId",l()),m(n,"accountId",a.userId),u(`/ai/assistant_app/chat/sync?${n.toString()}`)}(e);t.lifecycleSend(l(),e.length);try{const e=await g(n);if(!e.ok){const n=k(e.status);throw t.lifecycleError(l(),String(e.status),n),new h(n,`http_${e.status}`)}const r=await e.text();return t.lifecycleReply(l(),r.length),r}catch(e){if(e instanceof h)throw e;throw t.lifecycleError(l(),"unknown",String(e)),new h(o("error_unknown"),"unknown")}}async function f(e,n,r,s,i,c,d){var p;const b=c?function(e,n){const t=new URLSearchParams;return t.set("message",e),t.set("chatId",a.chatId),t.set("rewriteStrategy",a.rewriteStrategy||"REWRITE"),m(t,"roleId",l()),m(t,"accountId",a.userId),m(t,"categoryId",null!=n?n:a.categoryId),u(`/ai/assistant_app/chat/rag/sse?${t.toString()}`)}(e,i):function(e,n){const t=new URLSearchParams;return t.set("message",e),t.set("chatId",a.chatId),m(t,"roleId",l()),m(t,"accountId",a.userId),m(t,"categoryId",null!=n?n:a.categoryId),u(`/ai/assistant_app/chat/sse?${t.toString()}`)}(e,i);let f="";t.lifecycleSend(l(),e.length);try{const e=await g(b,{},6e4,d);if(!e.ok){const n=k(e.status);return t.lifecycleError(l(),String(e.status),n),void s(new h(n,`http_${e.status}`))}const a=null===(p=e.body)||void 0===p?void 0:p.getReader();if(!a)return void s(new h(o("error_stream_unsupported"),"stream_unsupported"));const i=new TextDecoder("utf-8",{stream:!0});let c="",u=[],m="";try{for(;;){const{done:e,value:t}=await a.read();if(e)break;c+=i.decode(t,{stream:!0});const r=c.split("\n");c=r.pop()||"";for(const e of r){const t=e.trim();if(!t){if(u.length>0){if("status"!==m&&"tool_call_result"!==m){const e=u.join("\n");f+=e,n(e)}u=[]}m="";continue}if(t.startsWith(":"))continue;if("[DONE]"===t){if(u.length>0&&"status"!==m&&"tool_call_result"!==m){const e=u.join("\n");f+=e,n(e),u=[]}m="";break}if(t.startsWith("event:")){m=t.substring(6).trim();continue}if(t.startsWith("id:")||t.startsWith("retry:"))continue;let r;t.startsWith("data:")?(r=t.substring(5),r.startsWith(" ")&&(r=r.substring(1))):r=t,u.push(r)}}if(c.trim()){const e=c.trim();if(!e.startsWith(":"))if(e.startsWith("data:")){let n=e.substring(5);n.startsWith(" ")&&(n=n.substring(1)),u.push(n)}else"[DONE]"===e||e.startsWith("event:")||e.startsWith("id:")||e.startsWith("retry:")||u.push(e)}if(u.length>0&&"status"!==m&&"tool_call_result"!==m){const e=u.join("\n");f+=e,n(e),u=[]}}catch(e){if(null==d?void 0:d.aborted)t.info(`流式被用户中断,保留已生成内容 length=${f.length}`);else{if(!(f.length>0))throw e;n("\n\n"+o("stream_unstable"))}}finally{a.releaseLock()}t.lifecycleStreamDone(l(),f.length),r()}catch(e){if((null==d?void 0:d.aborted)||e instanceof h&&"aborted"===e.type)return void r();e instanceof h?s(e):(t.lifecycleError(l(),"unknown",String(e)),s(new h(o("error_network"),"network")))}}async function y(e,n){const r=function(e,n){const t=new URLSearchParams;return t.set("message",e),t.set("chatId",a.chatId),t.set("rewriteStrategy",a.rewriteStrategy||"REWRITE"),m(t,"roleId",l()),m(t,"accountId",a.userId),m(t,"categoryId",null!=n?n:a.categoryId),u(`/ai/assistant_app/rag/sources?${t.toString()}`)}(e,n);try{const e=await g(r);if(!e.ok)throw new h(k(e.status),`http_${e.status}`);const n=await e.json();return n.success&&Array.isArray(n.data)?(t.info(`获取引用来源 count=${n.data.length}`),n.data):[]}catch(e){return t.error("获取引用来源失败",e),[]}}async function x(e=1,n=20,r,s){const o=new URLSearchParams;o.set("page",String(e)),o.set("size",String(n)),r&&o.set("accountId",r),s&&o.set("roleId",s);const a=u(`/ai/sdk/conversation/list?${o.toString()}`);try{const e=await g(a);if(!e.ok)throw new h(k(e.status),`http_${e.status}`);const n=await e.json();return{list:n.success&&Array.isArray(n.data)?n.data:[],total:n.total||0,pages:n.pages||0}}catch(e){return t.error("加载会话列表失败",e),{list:[],total:0,pages:0}}}async function v(e){const n=new URLSearchParams;(null==a?void 0:a.userId)&&n.set("accountId",a.userId),l()&&n.set("roleId",l());const r=u(`/ai/sdk/conversation/${e}/messages?${n.toString()}`);try{const e=await g(r);if(!e.ok)throw new h(k(e.status),`http_${e.status}`);const n=await e.json();return{messages:n.success&&Array.isArray(n.data)?n.data:[],total:n.total||0}}catch(e){return t.error("加载会话消息失败",e),{messages:[],total:0}}}async function w(e){const n=new URLSearchParams;(null==a?void 0:a.userId)&&n.set("accountId",a.userId),l()&&n.set("roleId",l());const r=u(`/ai/sdk/conversation/${e}?${n.toString()}`);try{const n=await g(r,{method:"DELETE"});if(!n.ok)throw new h(k(n.status),`http_${n.status}`);const s=await n.json();return t.info(`删除会话 id=${e} success=${s.success}`),s.success||!1}catch(e){return t.error("删除会话失败",e),!1}}function _(e){const n=new URLSearchParams;return(null==a?void 0:a.userId)&&n.set("accountId",a.userId),l()&&n.set("roleId",l()),u(`/ai/sdk/conversation/${e}/export?${n.toString()}`)}async function E(e=!1){if(!a)return"";const n=l();if(!e){const e=function(e,n){try{return localStorage.getItem(C(e,n))||""}catch(e){return""}}(n,a.userId);if(e)return a.chatId=e,e}try{const e=await x(1,5,a.userId,n);if(e.list.length>0){const r=e.list[0],s=r.conversationId||r.chatId||"";if(s)return a.chatId=s,L(n,a.userId,s),t.info(`从后端恢复会话 chatId=${s} messageCount=${r.messageCount}`),s}}catch(e){}const r=function(){const e="undefined"!=typeof crypto&&crypto.randomUUID?crypto.randomUUID().substring(0,8):Math.random().toString(36).substring(2,10);return`sdk_${Date.now()}_${e}`}();return a.chatId=r,L(n,a.userId,r),r}function C(e,n){return`csk_chatId_${e}${n?"_"+n:""}`}function L(e,n,t){try{t?localStorage.setItem(C(e,n),t):localStorage.removeItem(C(e,n))}catch(e){}}let I=null;function S(e){const n=A(e.primaryColor,-15),t=A(e.primaryColor,18),r=function(e){const n=e.match(/^#([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/);return n?`${parseInt(n[1],16)}, ${parseInt(n[2],16)}, ${parseInt(n[3],16)}`:"79, 70, 229"}(e.primaryColor);return`\n --csk-primary: ${e.primaryColor};\n --csk-primary-hover: ${n};\n --csk-primary-light: ${t};\n --csk-primary-rgb: ${r};\n --csk-bg-user: linear-gradient(135deg, ${e.primaryColor}, ${n});\n --csk-bg-ai: #ffffff;\n --csk-text-user: #ffffff;\n --csk-text-ai: #1F2937;\n --csk-window-width: ${e.width}px;\n --csk-window-height: ${e.height}px;\n --csk-radius: 16px;\n --csk-shadow-window: 0 12px 48px rgba(15, 23, 42, 0.18), 0 2px 8px rgba(15, 23, 42, 0.06);\n --csk-shadow-bubble: 0 1px 2px rgba(15, 23, 42, 0.06);\n --csk-border: #ECEEF2;\n --csk-bg-app: #F6F7F9;\n `}function A(e,n){const t=e.match(/^#([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/);if(!t)return e;const r=e=>Math.max(0,Math.min(255,e)),s=r(parseInt(t[1],16)+n),o=r(parseInt(t[2],16)+n),a=r(parseInt(t[3],16)+n);return`#${s.toString(16).padStart(2,"0")}${o.toString(16).padStart(2,"0")}${a.toString(16).padStart(2,"0")}`}function $(e){document.querySelector("style[data-csk-sdk]")||(I=document.createElement("style"),I.setAttribute("data-csk-sdk",""),I.textContent=function(e){return`\n/* ChatbotSDK 样式 - csk- 命名空间 */\n.csk-root {\n ${S(e)}\n font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans SC", "PingFang SC", "Microsoft YaHei", sans-serif;\n font-size: 14px;\n line-height: 1.55;\n color: #1F2937;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n box-sizing: border-box;\n}\n.csk-root *, .csk-root *::before, .csk-root *::after { box-sizing: border-box; }\n\n/* ========== 悬浮按钮 ========== */\n.csk-launcher {\n position: fixed;\n bottom: 24px;\n z-index: 9998;\n width: 60px;\n height: 60px;\n border-radius: 50%;\n /* 白色背景,简洁克制 */\n background: #ffffff;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n color: #fff;\n user-select: none;\n overflow: hidden;\n /* 浅灰边框 */\n border: 2px solid #E5E7EB;\n /* 简洁柔和阴影 */\n box-shadow:\n 0 2px 8px rgba(0, 0, 0, 0.08),\n 0 4px 16px rgba(0, 0, 0, 0.06);\n transition:\n transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1),\n box-shadow 0.25s ease,\n border-color 0.25s ease;\n animation:\n csk-launcher-in 0.55s cubic-bezier(0.22, 1, 0.36, 1) both;\n}\n.csk-launcher--right { right: 24px; }\n.csk-launcher--left { left: 24px; }\n\n.csk-launcher:hover {\n transform: translateY(-3px) scale(1.08);\n border-color: #D1D5DB;\n box-shadow:\n 0 4px 12px rgba(0, 0, 0, 0.10),\n 0 8px 24px rgba(0, 0, 0, 0.08);\n}\n.csk-launcher:active { transform: scale(0.93); }\n.csk-launcher svg {\n width: 30px;\n height: 30px;\n position: relative;\n z-index: 1;\n filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.15));\n}\n.csk-launcher img {\n width: 36px;\n height: 36px;\n object-fit: contain;\n position: relative;\n z-index: 1;\n -webkit-user-drag: none;\n user-select: none;\n}\n\n@keyframes csk-launcher-in {\n 0% { opacity: 0; transform: scale(0.5) translateY(16px); }\n 60% { transform: scale(1.06) translateY(-2px); }\n 100% { opacity: 1; transform: scale(1) translateY(0); }\n}\n\n/* ========== 聊天弹窗 ========== */\n.csk-window {\n position: fixed;\n bottom: 24px;\n z-index: 9999;\n width: var(--csk-window-width);\n height: var(--csk-window-height);\n max-height: calc(100vh - 48px);\n background: #fff;\n border-radius: var(--csk-radius);\n box-shadow: var(--csk-shadow-window);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n transform-origin: bottom right;\n transition: opacity 0.24s ease, transform 0.24s cubic-bezier(0.34, 1.2, 0.64, 1), visibility 0.24s;\n opacity: 1;\n transform: translateY(0) scale(1);\n visibility: visible;\n pointer-events: auto;\n}\n.csk-window--right { right: 24px; transform-origin: bottom right; }\n.csk-window--left { left: 24px; transform-origin: bottom left; }\n.csk-window--hidden {\n opacity: 0;\n transform: translateY(12px) scale(0.96);\n visibility: hidden;\n pointer-events: none;\n}\n\n/* ========== 水印层 ========== */\n.csk-watermark {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n pointer-events: none;\n user-select: none;\n z-index: 0;\n background-repeat: repeat;\n opacity: 0.8;\n}\n\n/* ========== 头部 ========== */\n.csk-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 16px;\n min-height: 60px;\n background: var(--csk-bg-user);\n color: #fff;\n cursor: move;\n user-select: none;\n position: relative;\n flex-shrink: 0;\n}\n.csk-header::after {\n content: '';\n position: absolute;\n left: 0; right: 0; bottom: 0;\n height: 24px;\n background: linear-gradient(to bottom, rgba(0,0,0,0.04), transparent);\n pointer-events: none;\n}\n.csk-header__left {\n display: flex;\n align-items: center;\n gap: 12px;\n min-width: 0;\n}\n.csk-header__avatar {\n width: 38px;\n height: 38px;\n border-radius: 50%;\n background: rgba(255, 255, 255, 0.22);\n backdrop-filter: blur(4px);\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.25);\n}\n.csk-header__avatar svg { width: 22px; height: 22px; }\n.csk-header__info {\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n.csk-header__title {\n font-size: 15px;\n font-weight: 600;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n letter-spacing: 0.2px;\n}\n.csk-header__status {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n font-size: 11.5px;\n opacity: 0.9;\n margin-top: 2px;\n}\n.csk-status-dot {\n width: 7px;\n height: 7px;\n border-radius: 50%;\n background: #6EE7B7;\n box-shadow: 0 0 0 0 rgba(110, 231, 183, 0.7);\n animation: csk-status-pulse 2s infinite;\n}\n@keyframes csk-status-pulse {\n 0% { box-shadow: 0 0 0 0 rgba(110, 231, 183, 0.7); }\n 70% { box-shadow: 0 0 0 6px rgba(110, 231, 183, 0); }\n 100% { box-shadow: 0 0 0 0 rgba(110, 231, 183, 0); }\n}\n.csk-header__actions {\n display: flex;\n align-items: center;\n gap: 2px;\n flex-shrink: 0;\n}\n.csk-header__btn,\n.csk-history-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n border: none;\n background: transparent;\n color: #fff;\n cursor: pointer;\n border-radius: 8px;\n transition: background 0.15s, transform 0.15s;\n}\n.csk-header__btn:hover,\n.csk-history-btn:hover {\n background: rgba(255, 255, 255, 0.2);\n}\n.csk-header__btn:active,\n.csk-history-btn:active { transform: scale(0.92); }\n\n/* ========== 角色选择器 ========== */\n.csk-role-select-wrap {\n display: flex;\n align-items: center;\n flex-shrink: 0;\n margin: 0 4px;\n}\n.csk-role-select {\n appearance: none;\n -webkit-appearance: none;\n padding: 4px 24px 4px 10px;\n border: 1px solid rgba(255, 255, 255, 0.35);\n border-radius: 8px;\n background: rgba(255, 255, 255, 0.15) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='white' stroke-width='1.5' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") no-repeat right 6px center;\n color: #fff;\n font-size: 12px;\n font-family: inherit;\n cursor: pointer;\n outline: none;\n transition: background 0.15s, border-color 0.15s;\n max-width: 120px;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.csk-role-select:hover {\n background-color: rgba(255, 255, 255, 0.25);\n border-color: rgba(255, 255, 255, 0.55);\n}\n.csk-role-select:focus {\n border-color: rgba(255, 255, 255, 0.7);\n box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.2);\n}\n.csk-role-select option {\n color: #1F2937;\n background: #fff;\n}\n\n/* ========== 消息区 ========== */\n.csk-messages {\n flex: 1;\n overflow-y: auto;\n padding: 20px 16px 12px;\n background: var(--csk-bg-app);\n scroll-behavior: smooth;\n}\n.csk-messages::-webkit-scrollbar { width: 6px; }\n.csk-messages::-webkit-scrollbar-track { background: transparent; }\n.csk-messages::-webkit-scrollbar-thumb {\n background: #D8DCE3;\n border-radius: 3px;\n}\n.csk-messages::-webkit-scrollbar-thumb:hover { background: #C2C7D0; }\n\n/* 离线提示横幅 */\n.csk-offline-banner {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n padding: 8px 12px;\n margin: 0 0 8px 0;\n border-radius: 8px;\n font-size: 12px;\n line-height: 1.5;\n background: #FEF2F2;\n color: #991B1B;\n border: 1px solid #FECACA;\n}\n.csk-dark .csk-offline-banner {\n background: #450A0A;\n color: #FCA5A5;\n border-color: #7F1D1D;\n}\n\n/* 欢迎空状态 */\n.csk-welcome {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n text-align: center;\n padding: 48px 24px 32px;\n color: #6B7280;\n animation: csk-fade-in 0.3s ease;\n}\n.csk-welcome__avatar {\n width: 56px;\n height: 56px;\n border-radius: 50%;\n background: var(--csk-bg-user);\n color: #fff;\n display: flex;\n align-items: center;\n justify-content: center;\n margin-bottom: 14px;\n box-shadow: 0 6px 18px rgba(var(--csk-primary-rgb), 0.3);\n}\n.csk-welcome__avatar svg { width: 30px; height: 30px; }\n.csk-welcome__title {\n font-size: 15px;\n font-weight: 600;\n color: #1F2937;\n margin-bottom: 4px;\n}\n.csk-welcome__desc {\n font-size: 13px;\n color: #9CA3AF;\n line-height: 1.6;\n}\n\n/* 消息气泡 */\n.csk-msg {\n display: flex;\n margin-bottom: 12px;\n max-width: 100%;\n word-break: break-word;\n animation: csk-msg-in 0.28s cubic-bezier(0.22, 1, 0.36, 1);\n}\n.csk-msg--user {\n flex-direction: row-reverse;\n align-items: flex-end;\n}\n.csk-msg--ai {\n flex-direction: row;\n align-items: flex-start;\n}\n.csk-msg__avatar {\n width: 30px;\n height: 30px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n margin: 0 8px;\n box-shadow: var(--csk-shadow-bubble);\n}\n.csk-msg__avatar svg { width: 18px; height: 18px; }\n.csk-msg__avatar--ai {\n background: #fff;\n color: var(--csk-primary);\n border: 1px solid var(--csk-border);\n}\n.csk-msg__avatar--user {\n background: var(--csk-bg-user);\n color: #fff;\n}\n.csk-msg__content {\n display: flex;\n flex-direction: column;\n min-width: 0;\n max-width: calc(100% - 46px);\n}\n.csk-msg--user .csk-msg__content { align-items: flex-end; }\n.csk-msg--ai .csk-msg__content { align-items: flex-start; }\n.csk-msg__bubble {\n padding: 10px 14px;\n border-radius: 16px;\n font-size: 14px;\n line-height: 1.6;\n box-shadow: var(--csk-shadow-bubble);\n}\n.csk-msg--user .csk-msg__bubble {\n background: var(--csk-bg-user);\n color: var(--csk-text-user);\n border-radius: 16px 16px 4px 16px;\n}\n.csk-msg--ai .csk-msg__bubble {\n background: var(--csk-bg-ai);\n color: var(--csk-text-ai);\n border-radius: 16px 16px 16px 4px;\n border: 1px solid var(--csk-border);\n}\n.csk-msg__time {\n font-size: 11px;\n color: #9CA3AF;\n margin-top: 3px;\n padding: 0 4px;\n}\n\n/* 元信息行:时间戳居左,操作按钮居右,共用一行 */\n.csk-msg__meta {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-top: 3px;\n width: 100%;\n}\n.csk-msg__meta .csk-msg__time { margin-top: 0; }\n\n@keyframes csk-msg-in {\n from { opacity: 0; transform: translateY(8px); }\n to { opacity: 1; transform: translateY(0); }\n}\n@keyframes csk-fade-in {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n/* ========== Loading 动画 ========== */\n.csk-loading {\n display: flex;\n align-items: center;\n margin-bottom: 12px;\n animation: csk-msg-in 0.28s ease;\n}\n.csk-loading__avatar {\n width: 30px;\n height: 30px;\n border-radius: 50%;\n background: #fff;\n color: var(--csk-primary);\n border: 1px solid var(--csk-border);\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n margin: 0 8px;\n box-shadow: var(--csk-shadow-bubble);\n}\n.csk-loading__avatar svg { width: 18px; height: 18px; }\n.csk-loading__bubble {\n background: #fff;\n border: 1px solid var(--csk-border);\n border-radius: 16px 16px 16px 4px;\n padding: 12px 16px;\n display: flex;\n align-items: center;\n gap: 5px;\n}\n.csk-loading__dot {\n width: 7px;\n height: 7px;\n border-radius: 50%;\n background: #B4B9C2;\n animation: csk-bounce 1.4s ease-in-out infinite both;\n}\n.csk-loading__dot:nth-child(1) { animation-delay: 0s; }\n.csk-loading__dot:nth-child(2) { animation-delay: 0.16s; }\n.csk-loading__dot:nth-child(3) { animation-delay: 0.32s; }\n\n@keyframes csk-bounce {\n 0%, 80%, 100% { transform: scale(0.6); opacity: 0.6; }\n 40% { transform: scale(1); opacity: 1; }\n}\n\n/* ========== 输入区 ========== */\n.csk-input-area {\n padding: 10px 12px 14px;\n background: #fff;\n border-top: 1px solid var(--csk-border);\n flex-shrink: 0;\n}\n.csk-input-wrap {\n display: flex;\n align-items: flex-end;\n gap: 8px;\n background: var(--csk-bg-app);\n border: 1px solid var(--csk-border);\n border-radius: 14px;\n padding: 6px 6px 6px 14px;\n transition: border-color 0.2s, box-shadow 0.2s, background 0.2s;\n}\n.csk-input-wrap--focus {\n border-color: var(--csk-primary);\n background: #fff;\n box-shadow: 0 0 0 3px rgba(var(--csk-primary-rgb), 0.12);\n}\n.csk-input {\n flex: 1;\n border: none;\n background: transparent;\n padding: 8px 0;\n font-size: 14px;\n outline: none;\n font-family: inherit;\n resize: none;\n min-height: 22px;\n max-height: 120px;\n line-height: 1.5;\n color: #1F2937;\n}\n.csk-input::placeholder { color: #9CA3AF; }\n.csk-root .csk-input:focus-visible { outline: none; }\n.csk-send-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 36px;\n height: 36px;\n min-width: 36px;\n border: none;\n border-radius: 10px;\n background: var(--csk-bg-user);\n color: #fff;\n cursor: pointer;\n transition: transform 0.18s, box-shadow 0.18s, opacity 0.18s;\n box-shadow: 0 3px 10px rgba(var(--csk-primary-rgb), 0.3);\n}\n.csk-send-btn:hover:not(:disabled) {\n transform: translateY(-1px);\n box-shadow: 0 5px 14px rgba(var(--csk-primary-rgb), 0.4);\n}\n.csk-send-btn:active:not(:disabled) { transform: scale(0.92); }\n.csk-send-btn:disabled {\n background: #D1D5DB;\n box-shadow: none;\n cursor: not-allowed;\n opacity: 0.7;\n}\n.csk-send-btn svg { width: 18px; height: 18px; }\n\n/* ========== 保密声明脚注 ========== */\n.csk-disclaimer {\n margin-top: 8px;\n padding: 6px 8px 4px;\n font-size: 10px;\n color: #9CA3AF;\n line-height: 1.5;\n user-select: none;\n}\n.csk-disclaimer__title {\n font-weight: 600;\n margin-bottom: 2px;\n color: #9CA3AF;\n}\n.csk-dark .csk-disclaimer { color: #6B7280; }\n.csk-dark .csk-disclaimer__title { color: #6B7280; }\n\n/* ========== 新对话按钮 ========== */\n.csk-clear-btn {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n padding: 5px 12px;\n border: 1px solid var(--csk-border);\n border-radius: 999px;\n background: #fff;\n color: #6B7280;\n font-size: 12px;\n cursor: pointer;\n margin: 0 auto 8px;\n transition: all 0.15s;\n font-family: inherit;\n}\n.csk-clear-btn:hover {\n background: #FEF2F2;\n border-color: #FCA5A5;\n color: #DC2626;\n}\n\n/* ========== P1: 知识库分类下拉 ========== */\n.csk-category-bar {\n display: flex;\n align-items: center;\n padding: 8px 12px;\n border-top: 1px solid var(--csk-border);\n background: #FBFBFC;\n gap: 8px;\n flex-shrink: 0;\n}\n.csk-category-bar__label {\n font-size: 13px;\n white-space: nowrap;\n}\n.csk-category-select {\n flex: 1;\n padding: 6px 28px 6px 10px;\n border: 1px solid var(--csk-border);\n border-radius: 8px;\n font-size: 12.5px;\n color: #374151;\n background: #fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%239CA3AF' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E") no-repeat right 9px center;\n appearance: none;\n -webkit-appearance: none;\n outline: none;\n cursor: pointer;\n font-family: inherit;\n transition: border-color 0.2s, box-shadow 0.2s;\n max-width: 220px;\n}\n.csk-category-select:focus {\n border-color: var(--csk-primary);\n box-shadow: 0 0 0 3px rgba(var(--csk-primary-rgb), 0.12);\n}\n\n/* ========== P1: RAG 引用来源卡片 ========== */\n.csk-sources {\n margin-top: 6px;\n border: 1px solid var(--csk-border);\n border-radius: 12px;\n overflow: hidden;\n font-size: 12px;\n max-width: 100%;\n background: #FAFBFC;\n}\n.csk-sources__header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 6px 10px;\n background: #F3F4F7;\n cursor: pointer;\n user-select: none;\n transition: background 0.15s;\n}\n.csk-sources__header:hover { background: #ECEEF2; }\n.csk-sources__title {\n display: flex;\n align-items: center;\n gap: 5px;\n font-weight: 500;\n color: #374151;\n}\n.csk-sources__arrow {\n transition: transform 0.2s;\n color: #9CA3AF;\n font-size: 10px;\n}\n.csk-sources--collapsed .csk-sources__arrow { transform: rotate(-90deg); }\n.csk-sources__body {\n border-top: 1px solid var(--csk-border);\n padding: 0;\n}\n.csk-sources--collapsed .csk-sources__body { display: none; }\n.csk-source-item {\n padding: 6px 10px;\n border-bottom: 1px solid #F0F1F4;\n transition: background 0.15s;\n}\n.csk-source-item:last-child { border-bottom: none; }\n.csk-source-item:hover { background: #fff; }\n.csk-source-item__name {\n font-weight: 500;\n color: #1F2937;\n margin-bottom: 2px;\n}\n.csk-source-item__snippet {\n color: #6B7280;\n line-height: 1.5;\n overflow: hidden;\n text-overflow: ellipsis;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n}\n.csk-source-item__meta {\n font-size: 11px;\n color: #9CA3AF;\n margin-top: 2px;\n}\n\n/* ========== P1: Markdown 渲染样式 ========== */\n.csk-msg--ai .csk-msg__bubble .csk-md-p { margin: 0 0 8px; }\n.csk-msg--ai .csk-msg__bubble .csk-md-p:last-child { margin-bottom: 0; }\n.csk-msg--ai .csk-msg__bubble .csk-md-h1,\n.csk-msg--ai .csk-msg__bubble .csk-md-h2,\n.csk-msg--ai .csk-msg__bubble .csk-md-h3,\n.csk-msg--ai .csk-msg__bubble .csk-md-h4,\n.csk-msg--ai .csk-msg__bubble .csk-md-h5,\n.csk-msg--ai .csk-msg__bubble .csk-md-h6 {\n margin: 14px 0 6px;\n font-weight: 600;\n line-height: 1.3;\n color: #111827;\n}\n.csk-msg--ai .csk-msg__bubble .csk-md-h1 { font-size: 20px; }\n.csk-msg--ai .csk-msg__bubble .csk-md-h2 { font-size: 17px; }\n.csk-msg--ai .csk-msg__bubble .csk-md-h3 { font-size: 15px; }\n.csk-msg--ai .csk-msg__bubble .csk-md-h4 { font-size: 14px; }\n\n.csk-md-code-block {\n position: relative;\n background: #1E293B;\n color: #E2E8F0;\n padding: 12px 14px;\n border-radius: 10px;\n overflow-x: auto;\n margin: 8px 0;\n font-size: 13px;\n line-height: 1.55;\n font-family: 'SF Mono', 'Consolas', 'Menlo', 'Monaco', monospace;\n}\n.csk-md-code-block code {\n background: none;\n padding: 0;\n border-radius: 0;\n font-size: inherit;\n color: inherit;\n}\n.csk-md-inline-code {\n background: rgba(var(--csk-primary-rgb), 0.1);\n color: var(--csk-primary);\n padding: 1px 6px;\n border-radius: 5px;\n font-size: 13px;\n font-family: 'SF Mono', 'Consolas', 'Menlo', 'Monaco', monospace;\n}\n.csk-msg--ai .csk-msg__bubble .csk-md-ul,\n.csk-msg--ai .csk-msg__bubble .csk-md-ol {\n padding-left: 22px;\n margin: 6px 0;\n}\n.csk-msg--ai .csk-msg__bubble .csk-md-ul li,\n.csk-msg--ai .csk-msg__bubble .csk-md-ol li { margin-bottom: 4px; }\n.csk-md-blockquote {\n border-left: 3px solid var(--csk-primary);\n padding: 2px 12px;\n margin: 8px 0;\n color: #6B7280;\n background: rgba(var(--csk-primary-rgb), 0.05);\n border-radius: 0 6px 6px 0;\n}\n.csk-md-link {\n color: var(--csk-primary);\n text-decoration: none;\n border-bottom: 1px solid rgba(var(--csk-primary-rgb), 0.3);\n transition: border-color 0.15s;\n}\n.csk-md-link:hover { border-bottom-color: var(--csk-primary); }\n.csk-md-hr {\n border: none;\n border-top: 1px solid var(--csk-border);\n margin: 12px 0;\n}\n.csk-md-table-wrap {\n max-width: 100%;\n overflow-x: auto;\n margin: 10px 0;\n border: 1px solid var(--csk-border);\n border-radius: 8px;\n}\n.csk-md-table {\n width: 100%;\n min-width: 360px;\n border-collapse: collapse;\n font-size: 12.5px;\n line-height: 1.5;\n}\n.csk-md-table th,\n.csk-md-table td {\n padding: 7px 9px;\n border-right: 1px solid var(--csk-border);\n border-bottom: 1px solid var(--csk-border);\n text-align: left;\n vertical-align: top;\n}\n.csk-md-table th:last-child,\n.csk-md-table td:last-child { border-right: none; }\n.csk-md-table tbody tr:last-child td { border-bottom: none; }\n.csk-md-table th {\n background: rgba(var(--csk-primary-rgb), 0.07);\n color: #374151;\n font-weight: 600;\n}\n.csk-md-table tbody tr:nth-child(even) {\n background: rgba(148, 163, 184, 0.06);\n}\n.csk-md-table .csk-md-align-left { text-align: left; }\n.csk-md-table .csk-md-align-center { text-align: center; }\n.csk-md-table .csk-md-align-right { text-align: right; }\n\n/* ========== P2: 会话管理面板 ========== */\n.csk-history-panel {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: #fff;\n z-index: 10;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n animation: csk-slide-in 0.24s ease;\n}\n.csk-history-panel--hidden { display: none; }\n@keyframes csk-slide-in {\n from { transform: translateX(100%); opacity: 0.4; }\n to { transform: translateX(0); opacity: 1; }\n}\n.csk-history-panel__header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 14px 16px;\n border-bottom: 1px solid var(--csk-border);\n background: var(--csk-bg-app);\n flex-shrink: 0;\n}\n.csk-history-panel__title {\n font-size: 14px;\n font-weight: 600;\n color: #1F2937;\n}\n.csk-history-panel__back {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 5px 12px;\n border: 1px solid var(--csk-border);\n border-radius: 8px;\n background: #fff;\n color: #374151;\n font-size: 12px;\n cursor: pointer;\n transition: all 0.15s;\n font-family: inherit;\n}\n.csk-history-panel__back:hover { background: #F3F4F6; }\n.csk-history-panel__list {\n flex: 1;\n overflow-y: auto;\n padding: 10px;\n}\n.csk-history-panel__list::-webkit-scrollbar { width: 5px; }\n.csk-history-panel__list::-webkit-scrollbar-thumb { background: #E5E7EB; border-radius: 2px; }\n.csk-history-item {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 11px 12px;\n border-radius: 10px;\n cursor: pointer;\n transition: background 0.15s;\n margin-bottom: 5px;\n border: 1px solid transparent;\n}\n.csk-history-item:hover { background: #F3F4F6; }\n.csk-history-item--active {\n background: rgba(var(--csk-primary-rgb), 0.08);\n border-color: rgba(var(--csk-primary-rgb), 0.2);\n}\n.csk-history-item--active:hover { background: rgba(var(--csk-primary-rgb), 0.12); }\n.csk-history-item__info { flex: 1; min-width: 0; }\n.csk-history-item__id {\n font-size: 13px;\n font-weight: 500;\n color: #1F2937;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.csk-history-item__meta {\n font-size: 11px;\n color: #9CA3AF;\n margin-top: 3px;\n}\n.csk-history-item__actions {\n display: flex;\n gap: 4px;\n margin-left: 8px;\n opacity: 0;\n transition: opacity 0.15s;\n}\n.csk-history-item:hover .csk-history-item__actions { opacity: 1; }\n.csk-history-action {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border: none;\n border-radius: 7px;\n cursor: pointer;\n font-size: 12px;\n transition: all 0.15s;\n}\n.csk-history-action--export { background: #EFF6FF; color: #2563EB; }\n.csk-history-action--export:hover { background: #DBEAFE; }\n.csk-history-action--delete { background: #FEF2F2; color: #DC2626; }\n.csk-history-action--delete:hover { background: #FEE2E2; }\n.csk-history-panel__empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 48px 20px;\n color: #9CA3AF;\n font-size: 13px;\n text-align: center;\n}\n.csk-history-panel__empty-icon {\n font-size: 34px;\n margin-bottom: 10px;\n opacity: 0.5;\n}\n.csk-history-panel__loading {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 24px;\n color: #9CA3AF;\n font-size: 13px;\n}\n\n/* ========== 快捷问题芯片 ========== */\n.csk-quick-replies {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n justify-content: center;\n margin-top: 18px;\n max-width: 320px;\n}\n.csk-quick-reply {\n border: 1px solid var(--csk-border);\n background: #fff;\n color: #374151;\n font-size: 12.5px;\n padding: 7px 13px;\n border-radius: 999px;\n cursor: pointer;\n font-family: inherit;\n line-height: 1.3;\n transition: all 0.18s ease;\n max-width: 100%;\n}\n.csk-quick-reply:hover {\n border-color: var(--csk-primary);\n color: var(--csk-primary);\n background: rgba(var(--csk-primary-rgb), 0.06);\n transform: translateY(-1px);\n}\n.csk-quick-reply:active { transform: scale(0.96); }\n\n/* ========== 推荐问题(suggest-message-list) ========== */\n.csk-suggestions {\n margin-top: 6px;\n padding: 4px 0 0 0;\n}\n.csk-suggestions__list {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n}\n.csk-suggestion-item {\n border: 1px solid var(--csk-border);\n background: #fff;\n color: #374151;\n font-size: 12px;\n padding: 4px 10px;\n border-radius: 999px;\n cursor: pointer;\n font-family: inherit;\n line-height: 1.3;\n transition: all 0.18s ease;\n max-width: 100%;\n text-align: left;\n}\n.csk-suggestion-item:hover {\n border-color: var(--csk-primary);\n color: var(--csk-primary);\n background: rgba(var(--csk-primary-rgb), 0.06);\n transform: translateY(-1px);\n}\n.csk-suggestion-item:active { transform: scale(0.96); }\n\n/* ========== AI 消息操作条 ========== */\n.csk-msg__actions {\n display: flex;\n gap: 2px;\n padding: 0 2px;\n opacity: 0;\n transition: opacity 0.15s ease;\n}\n.csk-msg--ai:hover .csk-msg__actions { opacity: 1; }\n.csk-msg--streaming .csk-msg__actions { display: none; }\n.csk-action-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 26px;\n height: 26px;\n border: none;\n background: transparent;\n color: #9CA3AF;\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.15s ease;\n}\n.csk-action-btn:hover {\n background: #F3F4F6;\n color: #374151;\n}\n.csk-action-btn--done { color: #10B981; }\n.csk-action-btn:active { transform: scale(0.9); }\n\n/* ========== 流式打字光标 ========== */\n.csk-caret {\n display: inline-block;\n width: 7px;\n height: 15px;\n margin-left: 2px;\n vertical-align: text-bottom;\n background: var(--csk-primary);\n border-radius: 1px;\n animation: csk-caret-blink 1s step-end infinite;\n}\n@keyframes csk-caret-blink {\n 0%, 50% { opacity: 1; }\n 51%, 100% { opacity: 0; }\n}\n\n/* ========== 代码块复制按钮 ========== */\n.csk-md-code-copy {\n position: absolute;\n top: 8px;\n right: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 26px;\n height: 26px;\n border: none;\n background: rgba(255, 255, 255, 0.12);\n color: #CBD5E1;\n border-radius: 6px;\n cursor: pointer;\n opacity: 0;\n transition: all 0.15s ease;\n}\n.csk-md-code-block:hover .csk-md-code-copy { opacity: 1; }\n.csk-md-code-copy:hover { background: rgba(255, 255, 255, 0.22); color: #fff; }\n.csk-md-code-copy:active { transform: scale(0.9); }\n\n/* ========== 新消息提示按钮 ========== */\n.csk-newmsg {\n position: absolute;\n bottom: 82px;\n left: 50%;\n transform: translateX(-50%);\n z-index: 5;\n display: inline-flex;\n align-items: center;\n gap: 5px;\n padding: 7px 14px;\n border: none;\n background: var(--csk-primary);\n color: #fff;\n font-size: 12px;\n font-family: inherit;\n border-radius: 999px;\n cursor: pointer;\n box-shadow: 0 4px 14px rgba(var(--csk-primary-rgb), 0.38);\n transition: transform 0.2s ease, box-shadow 0.2s ease;\n animation: csk-msg-in 0.25s ease;\n white-space: nowrap;\n}\n.csk-newmsg:hover { transform: translateX(-50%) translateY(-1px); box-shadow: 0 6px 18px rgba(var(--csk-primary-rgb), 0.48); }\n.csk-newmsg:active { transform: translateX(-50%) scale(0.95); }\n.csk-newmsg--hidden { display: none; }\n\n/* ========== 发送按钮停止态 ========== */\n.csk-send-btn--stop {\n background: #EF4444 !important;\n box-shadow: 0 3px 10px rgba(239, 68, 68, 0.35) !important;\n}\n.csk-send-btn--stop:hover:not(:disabled) {\n box-shadow: 0 5px 14px rgba(239, 68, 68, 0.45) !important;\n}\n\n/* ========== 窗口缩放拖拽手柄 ========== */\n.csk-resize-handle {\n position: absolute;\n right: 4px;\n bottom: 4px;\n width: 20px;\n height: 20px;\n display: flex;\n align-items: flex-end;\n justify-content: flex-end;\n cursor: nwse-resize;\n z-index: 5;\n user-select: none;\n -webkit-user-select: none;\n /* 圆形半透明背景,与整体圆润风格一致 */\n border-radius: 50%;\n background: transparent;\n transition: background 0.2s ease;\n}\n.csk-resize-handle:hover {\n background: rgba(var(--csk-primary-rgb), 0.08);\n}\n\n/* 三斜线抓手 — 纯 CSS 绘制,用两条间距微调的线,视觉上是三条 */\n.csk-resize-grip {\n display: block;\n width: 10px;\n height: 10px;\n background:\n linear-gradient(135deg,\n transparent 0%, transparent 38%,\n #C8CCD2 38%, #C8CCD2 42%,\n transparent 42%, transparent 54%,\n #C8CCD2 54%, #C8CCD2 58%,\n transparent 58%, transparent 70%,\n #C8CCD2 70%, #C8CCD2 74%,\n transparent 74%\n );\n transition: background 0.2s ease;\n border-radius: 2px;\n}\n/* hover 时线条变为主色 */\n.csk-resize-handle:hover .csk-resize-grip {\n background:\n linear-gradient(135deg,\n transparent 0%, transparent 38%,\n var(--csk-primary) 38%, var(--csk-primary) 42%,\n transparent 42%, transparent 54%,\n var(--csk-primary) 54%, var(--csk-primary) 58%,\n transparent 58%, transparent 70%,\n var(--csk-primary) 70%, var(--csk-primary) 74%,\n transparent 74%\n );\n}\n\n/* 暗色模式 */\n.csk-dark .csk-resize-grip {\n background:\n linear-gradient(135deg,\n transparent 0%, transparent 38%,\n #5B6070 38%, #5B6070 42%,\n transparent 42%, transparent 54%,\n #5B6070 54%, #5B6070 58%,\n transparent 58%, transparent 70%,\n #5B6070 70%, #5B6070 74%,\n transparent 74%\n );\n}\n.csk-dark .csk-resize-handle:hover .csk-resize-grip {\n background:\n linear-gradient(135deg,\n transparent 0%, transparent 38%,\n var(--csk-primary-light) 38%, var(--csk-primary-light) 42%,\n transparent 42%, transparent 54%,\n var(--csk-primary-light) 54%, var(--csk-primary-light) 58%,\n transparent 58%, transparent 70%,\n var(--csk-primary-light) 70%, var(--csk-primary-light) 74%,\n transparent 74%\n );\n}\n\n/* 缩放拖拽中:禁用过渡动画 + 全局光标 */\n.csk-window--resizing {\n transition: none !important;\n user-select: none;\n}\n.csk-window--resizing * { cursor: nwse-resize !important; }\n\n/* ========== 暗色模式 ========== */\n.csk-root.csk-dark {\n --csk-bg-ai: #1E1E2E;\n --csk-text-ai: #E2E8F0;\n --csk-border: #3B3B52;\n --csk-bg-app: #141421;\n color: #E2E8F0;\n}\n.csk-dark .csk-window {\n background: #1A1A2E;\n box-shadow: 0 12px 48px rgba(0, 0, 0, 0.4), 0 2px 8px rgba(0, 0, 0, 0.2);\n}\n.csk-dark .csk-watermark {\n opacity: 1;\n}\n.csk-dark .csk-header::after { background: linear-gradient(to bottom, rgba(0,0,0,0.12), transparent); }\n.csk-dark .csk-msg__avatar--ai {\n background: var(--csk-bg-ai);\n color: var(--csk-primary);\n border-color: var(--csk-border);\n}\n.csk-dark .csk-input-area { background: #1A1A2E; border-top-color: var(--csk-border); }\n.csk-dark .csk-input-wrap { background: var(--csk-bg-app); border-color: var(--csk-border); }\n.csk-dark .csk-input-wrap--focus { background: #1A1A2E; border-color: var(--csk-primary); }\n.csk-dark .csk-input { color: #E2E8F0; }\n.csk-dark .csk-loading__avatar { background: var(--csk-bg-ai); border-color: var(--csk-border); }\n.csk-dark .csk-loading__bubble { background: var(--csk-bg-ai); border-color: var(--csk-border); }\n.csk-dark .csk-loading__dot { background: #6B7280; }\n.csk-dark .csk-category-bar { background: #1A1A2E; border-top-color: var(--csk-border); }\n.csk-dark .csk-category-select { background-color: var(--csk-bg-app); border-color: var(--csk-border); color: #E2E8F0; }\n.csk-dark .csk-sources { background: #1E1E2E; border-color: var(--csk-border); }\n.csk-dark .csk-sources__header { background: #25253A; }\n.csk-dark .csk-sources__header:hover { background: #2D2D48; }\n.csk-dark .csk-source-item:hover { background: var(--csk-bg-ai); }\n.csk-dark .csk-source-item__name { color: #E2E8F0; }\n.csk-dark .csk-source-item__meta { color: #6B7280; }\n.csk-dark .csk-history-panel { background: #1A1A2E; }\n.csk-dark .csk-history-panel__header { background: var(--csk-bg-app); border-bottom-color: var(--csk-border); }\n.csk-dark .csk-history-panel__back { background: var(--csk-bg-app); border-color: var(--csk-border); color: #E2E8F0; }\n.csk-dark .csk-history-panel__back:hover { background: #2D2D48; }\n.csk-dark .csk-history-item:hover { background: #25253A; }\n.csk-dark .csk-history-item__id { color: #E2E8F0; }\n.csk-dark .csk-history-item__meta { color: #6B7280; }\n.csk-dark .csk-history-item--active { background: rgba(var(--csk-primary-rgb), 0.15); }\n.csk-dark .csk-history-item--active:hover { background: rgba(var(--csk-primary-rgb), 0.22); }\n.csk-dark .csk-action-btn:hover { background: #2D2D48; color: #E2E8F0; }\n.csk-dark .csk-clear-btn { background: var(--csk-bg-app); border-color: var(--csk-border); color: #9CA3AF; }\n.csk-dark .csk-clear-btn:hover { background: #3B1A1A; border-color: #7F1D1D; color: #FCA5A5; }\n.csk-dark .csk-md-code-block { background: #0F0F1A; }\n.csk-dark .csk-md-blockquote { background: rgba(var(--csk-primary-rgb), 0.08); }\n.csk-dark .csk-md-link { color: var(--csk-primary-light); }\n.csk-dark .csk-md-table th { background: rgba(var(--csk-primary-rgb), 0.14); color: #E2E8F0; }\n.csk-dark .csk-md-table tbody tr:nth-child(even) { background: rgba(148, 163, 184, 0.05); }\n.csk-dark .csk-msg--ai .csk-msg__bubble { background: var(--csk-bg-ai); color: var(--csk-text-ai); border-color: var(--csk-border); }\n.csk-dark .csk-welcome__title { color: #E2E8F0; }\n.csk-dark .csk-welcome__desc { color: #6B7280; }\n.csk-dark .csk-quick-reply { background: var(--csk-bg-app); border-color: var(--csk-border); color: #CBD5E1; }\n.csk-dark .csk-quick-reply:hover { background: rgba(var(--csk-primary-rgb), 0.12); border-color: var(--csk-primary); color: var(--csk-primary-light); }\n.csk-dark .csk-suggestion-item { background: var(--csk-bg-app); border-color: var(--csk-border); color: #CBD5E1; }\n.csk-dark .csk-suggestion-item:hover { background: rgba(var(--csk-primary-rgb), 0.12); border-color: var(--csk-primary); color: var(--csk-primary-light); }\n.csk-dark .csk-teaser { background: #2D2D48; color: #E2E8F0; box-shadow: 0 4px 20px rgba(0,0,0,0.35); }\n.csk-dark .csk-teaser::after { border-top-color: #2D2D48; }\n.csk-dark .csk-teaser__close { color: #6B7280; }\n.csk-dark .csk-teaser__close:hover { color: #9CA3AF; }\n.csk-dark .csk-feedback-btn { background: rgba(var(--csk-primary-rgb), 0.1); color: #9CA3AF; }\n.csk-dark .csk-feedback-btn:hover { background: rgba(var(--csk-primary-rgb), 0.2); color: var(--csk-primary-light); }\n.csk-dark .csk-feedback-btn--active { background: rgba(var(--csk-primary-rgb), 0.28); color: var(--csk-primary-light); }\n.csk-dark .csk-history-panel__search-wrap { background: var(--csk-bg-app); border-color: var(--csk-border); }\n.csk-dark .csk-history-panel__search-wrap:focus-within { border-color: var(--csk-primary); }\n.csk-dark .csk-history-panel__search { color: #E2E8F0; }\n.csk-dark .csk-launcher__badge { box-shadow: 0 0 0 2px #1A1A2E; }\n.csk-dark .csk-welcome__avatar { box-shadow: 0 6px 18px rgba(var(--csk-primary-rgb), 0.25); }\n.csk-dark .csk-header__avatar { box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.15); background: rgba(255, 255, 255, 0.1); }\n.csk-dark .csk-role-select option {\n background: #1A1A2E;\n color: #E2E8F0;\n}\n\n/* Launcher 拖拽态:微放大 + 阴影加深 */\n.csk-launcher--dragging {\n cursor: grabbing !important;\n transform: scale(1.1) !important;\n box-shadow:\n 0 4px 12px rgba(0, 0, 0, 0.14),\n 0 12px 32px rgba(0, 0, 0, 0.18),\n 0 14px 40px rgba(236, 72, 153, 0.36),\n 0 0 56px rgba(236, 72, 153, 0.18) !important;\n}\n/* 拖拽中隐藏未读徽章 */\n.csk-launcher--dragging .csk-launcher__badge { display: none !important; }\n/* 吸附过渡动画(释放时的缓动) */\n.csk-launcher--snap {\n transition: left 0.3s ease-out, right 0.3s ease-out, bottom 0.3s ease-out !important;\n}\n\n/* ========== Launcher 未读徽章 ========== */\n.csk-launcher__badge {\n position: absolute;\n top: -2px;\n right: -2px;\n width: 16px;\n height: 16px;\n border-radius: 50%;\n background: #EF4444;\n border: 2px solid #fff;\n box-shadow: 0 0 0 2px #fff;\n animation: csk-badge-in 0.28s cubic-bezier(0.34, 1.56, 0.64, 1);\n pointer-events: none;\n}\n.csk-launcher__badge--hidden { display: none; }\n@keyframes csk-badge-in {\n from { transform: scale(0); }\n to { transform: scale(1); }\n}\n\n/* ========== Launcher 提示气泡 ========== */\n.csk-teaser {\n position: fixed;\n bottom: 90px;\n z-index: 9997;\n max-width: 240px;\n padding: 10px 14px;\n background: #fff;\n color: #1F2937;\n font-size: 13px;\n line-height: 1.5;\n border-radius: 12px;\n box-shadow: 0 4px 20px rgba(15, 23, 42, 0.15);\n animation: csk-teaser-in 0.35s cubic-bezier(0.22, 1, 0.36, 1);\n cursor: pointer;\n user-select: none;\n}\n.csk-teaser--right { right: 24px; }\n.csk-teaser--left { left: 24px; }\n.csk-teaser::after {\n content: '';\n position: absolute;\n bottom: -6px;\n right: 28px;\n width: 12px;\n height: 12px;\n background: inherit;\n border-radius: 2px;\n transform: rotate(45deg);\n box-shadow: 2px 2px 4px rgba(15, 23, 42, 0.08);\n}\n.csk-teaser--left::after { right: auto; left: 28px; }\n.csk-teaser__close {\n position: absolute;\n top: 4px;\n right: 6px;\n background: none;\n border: none;\n font-size: 16px;\n color: #9CA3AF;\n cursor: pointer;\n padding: 2px 4px;\n line-height: 1;\n border-radius: 4px;\n}\n.csk-teaser__close:hover { color: #374151; }\n.csk-teaser--hidden { display: none; }\n@keyframes csk-teaser-in {\n from { opacity: 0; transform: translateY(8px) scale(0.95); }\n to { opacity: 1; transform: translateY(0) scale(1); }\n}\n\n/* ========== 消息反馈按钮(👍 / 👎) ========== */\n.csk-feedback-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 26px;\n height: 26px;\n border: none;\n background: rgba(var(--csk-primary-rgb), 0.08);\n color: #9CA3AF;\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.15s ease;\n padding: 0;\n}\n.csk-feedback-btn:hover { background: rgba(var(--csk-primary-rgb), 0.18); color: var(--csk-primary); }\n.csk-feedback-btn--active {\n background: rgba(var(--csk-primary-rgb), 0.28);\n color: var(--csk-primary);\n}\n.csk-feedback-btn--active.down { background: #FEF2F2; color: #EF4444; }\n.csk-feedback-btn:active { transform: scale(0.9); }\n.csk-msg--streaming .csk-feedback-btn { display: none; }\n\n/* ========== 历史会话搜索框 ========== */\n.csk-history-panel__search-wrap {\n padding: 8px 10px;\n border-bottom: 1px solid var(--csk-border);\n flex-shrink: 0;\n}\n.csk-history-panel__search-wrap:focus-within {\n border-bottom-color: var(--csk-primary);\n}\n.csk-history-panel__search {\n width: 100%;\n padding: 7px 10px;\n border: 1px solid var(--csk-border);\n border-radius: 8px;\n font-size: 12.5px;\n font-family: inherit;\n color: #1F2937;\n background: var(--csk-bg-app);\n outline: none;\n transition: border-color 0.2s;\n}\n.csk-history-panel__search:focus { border-color: var(--csk-primary); }\n.csk-history-panel__search::placeholder { color: #9CA3AF; }\n\n/* ========== a11y 焦点指示 ========== */\n.csk-root :focus-visible {\n outline: 2px solid var(--csk-primary);\n outline-offset: 2px;\n}\n.csk-root button:focus-visible {\n outline: 2px solid var(--csk-primary);\n outline-offset: 2px;\n border-radius: inherit;\n}\n/* 弹窗打开时隐藏 launcher 上的焦点环 */\n.csk-launcher:focus-visible {\n outline: none;\n border-color: rgba(255, 255, 255, 0.75);\n box-shadow:\n 0 1px 2px rgba(0, 0, 0, 0.06),\n 0 4px 16px rgba(0, 0, 0, 0.10),\n 0 6px 24px rgba(var(--csk-primary-rgb), 0.28),\n 0 0 48px rgba(var(--csk-primary-rgb), 0.12),\n 0 0 0 4px rgba(var(--csk-primary-rgb), 0.3);\n}\n\n/* ========== a11y aria-live 播报区(视觉隐藏) ========== */\n.csk-sr-only {\n position: absolute !important;\n width: 1px !important;\n height: 1px !important;\n padding: 0 !important;\n margin: -1px !important;\n overflow: hidden !important;\n clip: rect(0,0,0,0) !important;\n white-space: nowrap !important;\n border: 0 !important;\n}\n\n/* ========== 会话分组标题 ========== */\n.csk-history-group {\n margin-bottom: 4px;\n}\n.csk-history-group__label {\n font-size: 11px;\n font-weight: 600;\n color: #9CA3AF;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n padding: 8px 12px 4px;\n user-select: none;\n}\n.csk-dark .csk-history-group__label { color: #6B7280; }\n\n/* ========== 移动端适配 ========== */\n@media (max-width: 480px) {\n .csk-window {\n width: 100vw !important;\n height: 100vh !important;\n max-height: 100vh;\n bottom: 0 !important;\n right: 0 !important;\n left: 0 !important;\n border-radius: 0;\n }\n .csk-resize-handle { display: none !important; }\n .csk-window--hidden { transform: translateY(100%); }\n /* 移动端默认位置,仅在未被 JS 拖拽覆盖时生效 */\n .csk-launcher:not([style*="bottom"]) { bottom: 20px; }\n .csk-launcher--right:not([style*="bottom"]) { right: 20px; }\n .csk-launcher--left:not([style*="bottom"]) { left: 20px; }\n}\n`}(e),document.head.appendChild(I))}function N(){return"undefined"!=typeof crypto&&crypto.randomUUID?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,e=>{const n=16*Math.random()|0;return("x"===e?n:3&n|8).toString(16)})}function M(e){const n={"&":"&","<":"<",">":">",'"':""","'":"'"};return e.replace(/[&<>"']/g,e=>n[e]||e)}function F(e){const n=new Date(e);return`${String(n.getHours()).padStart(2,"0")}:${String(n.getMinutes()).padStart(2,"0")}`}function z(){return Date.now()}const D='';function T(e,n){const t=document.createElement("div");t.id="csk-launcher",t.className="csk-launcher csk-launcher--"+("left-bottom"===e.position?"left":"right"),t.setAttribute("title",e.title),t.setAttribute("aria-label",e.title),t.setAttribute("role","button"),t.setAttribute("tabindex","0"),t.innerHTML=e.launcherIcon;const r=document.createElement("div");r.className="csk-launcher__badge csk-launcher__badge--hidden",t.appendChild(r);const s=function(e,n){let t=null;return function(...r){null!==t&&clearTimeout(t),t=setTimeout(()=>{e.apply(this,r),t=null},n)}}(n,300);return t.addEventListener("click",s),t.addEventListener("keydown",e=>{"Enter"!==e.key&&" "!==e.key||(e.preventDefault(),s())}),t}function B(e){const n=document.createElement("div");if(n.id="csk-window",n.className=`csk-root csk-window csk-window--${"left-bottom"===e.position?"left":"right"} csk-window--hidden${"dark"===e.theme?" csk-dark":""}`,n.setAttribute("role","dialog"),n.setAttribute("aria-label",e.title),n.setAttribute("aria-modal","false"),e.watermark){const t=document.createElement("div");t.className="csk-watermark";const r=function(e){const n=document.createElement("canvas"),t=n.getContext("2d");if(!t)return"";const r=new Date,s=`${r.getFullYear()}-${String(r.getMonth()+1).padStart(2,"0")}-${String(r.getDate()).padStart(2,"0")} ${String(r.getHours()).padStart(2,"0")}:${String(r.getMinutes()).padStart(2,"0")}`,o=e.watermark?`${e.watermark} ${s}`:s;n.width=280,n.height=160;const a="dark"===e.theme;return t.fillStyle=a?"rgba(255, 255, 255, 0.05)":"rgba(0, 0, 0, 0.06)",t.font='13px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "PingFang SC", "Microsoft YaHei", sans-serif',t.textAlign="center",t.textBaseline="middle",t.save(),t.translate(140,80),t.rotate(-22*Math.PI/180),t.fillText(o,0,0),t.restore(),n.toDataURL("image/png")}(e);r&&(t.style.backgroundImage=`url(${r})`),n.appendChild(t)}const t=document.createElement("div");t.className="csk-header";const r=document.createElement("div");r.className="csk-header__left";const s=document.createElement("div");s.className="csk-header__avatar",s.innerHTML=D;const a=document.createElement("div");a.className="csk-header__info";const i=document.createElement("span");i.className="csk-header__title",i.textContent=e.title;const c=document.createElement("span");c.className="csk-header__status",c.innerHTML=`${o("status_online")}`,a.appendChild(i),a.appendChild(c),r.appendChild(s),r.appendChild(a);let l=null;const d=e.roles;if(d&&d.length>1){l=document.createElement("select"),l.className="csk-role-select",l.setAttribute("aria-label",o("role_selector_label"));for(const n of d){const t=document.createElement("option");t.value=String(n.id),t.textContent=n.name||String(n.id),String(n.id)===String(e.integrateId)&&(t.selected=!0),l.appendChild(t)}l.addEventListener("change",()=>{const e=l.value;n.dispatchEvent(new CustomEvent("csk:roleChange",{detail:{roleId:e}}))});const s=document.createElement("div");s.className="csk-role-select-wrap",s.appendChild(l),t.appendChild(r),t.appendChild(s)}else t.appendChild(r);const p=document.createElement("div");p.className="csk-header__actions";const u=document.createElement("button");u.className="csk-history-btn",u.setAttribute("title",o("history_title")),u.innerHTML='';const m=document.createElement("button");m.className="csk-header__btn csk-header__btn--minimize",m.setAttribute("title",o("minimize")),m.innerHTML='',m.addEventListener("click",()=>{n.classList.add("csk-window--hidden")});const g=document.createElement("button");g.className="csk-header__btn csk-header__btn--close",g.setAttribute("title",o("close")),g.innerHTML='',g.addEventListener("click",()=>{n.classList.add("csk-window--hidden")}),p.appendChild(u),p.appendChild(m),p.appendChild(g),t.appendChild(p);const h=document.createElement("div");h.id="csk-messages",h.className="csk-messages";const k=document.createElement("div");if(k.className="csk-welcome",k.innerHTML=`\n
${o}`),`${ee}${s}\0`});const r=[];t=t.replace(/`([^`\n]+)`/g,(e,n)=>{const t=r.length;return r.push(`${M(n)}`),`${ne}${t}\0`}),t=M(t),t=re(t,ee,n),t=re(t,ne,r);const s=t.split("\n"),o=[];let a=!1,i="",c=!1,l=[];for(let e=0;e| ${d(e)} | `)}),o.push("${d(r[t]||"")} | `)}),o.push(""),e++}o.push("
|---|
')),o.push(`"),c=!1)}}function re(e,n,t){return e.replace(new RegExp(n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")+"(\\d+)\0","g"),(e,n)=>t[parseInt(n)]||"")}let se,oe=null,ae=[],ie=null,ce=null,le=null,de=null,pe=null,ue=null,me=null,ge=null,he=null,ke=null,be=null,fe=null,ye=null,xe=null,ve=!1,we=null,_e=!0,Ee=[],Ce="",Le=!1;function Ie(e,n){oe=e,ie=n.messagesContainer,ce=n.inputEl,le=n.inputEl.parentElement,de=n.sendBtn,pe=n.clearBtn,ue=n.categorySelect,me=n.roleSelect,ge=n.historyPanel,he=n.welcomeEl,ke=n.newMsgBtn,be=n.searchInput,fe=n.ariaLiveEl,ye=n.showLoading,xe=n.hideLoading,se=e.categoryId,Le=e.enableRag,function(){if(!ce||!de)return;de.addEventListener("click",()=>{ve&&we?we.abort():Be()}),ce.addEventListener("keydown",e=>{"Enter"!==e.key||e.shiftKey||e.isComposing||(e.preventDefault(),Be())}),ce.addEventListener("input",()=>{Te(),function(){if(!ce)return;ce.style.height="auto",ce.style.height=`${Math.min(ce.scrollHeight,120)}px`}()}),ce.addEventListener("focus",()=>{le&&le.classList.add("csk-input-wrap--focus")}),ce.addEventListener("blur",()=>{le&&le.classList.remove("csk-input-wrap--focus")}),pe&&pe.addEventListener("click",()=>function(){if(!oe)return;if(ae=[],ie){ie.querySelectorAll(".csk-msg, .csk-loading").forEach(e=>e.remove())}pe&&(pe.style.display="none");De(),Z(oe.integrateId);const e=function(){const e="undefined"!=typeof crypto&&crypto.randomUUID?crypto.randomUUID().substring(0,8):Math.random().toString(36).substring(2,10);return`sdk_${Date.now()}_${e}`}();d(e),L(oe.integrateId,oe.userId,e),t.lifecycleClear(oe.integrateId)}())}(),function(){if(!ie)return;ie.addEventListener("scroll",()=>{if(!ie)return;const{scrollTop:e,scrollHeight:n,clientHeight:t}=ie;_e=n-e-t<80,_e&&$e()}),ke&&ke.addEventListener("click",()=>{ie&&V(ie),_e=!0,$e()})}(),function(){if(!be)return;be.addEventListener("input",()=>{Ce=be.value.trim().toLowerCase(),Fe()})}(),e.showCategorySwitch&&ue&&async function(){if(!ue)return;try{const e=await async function(){const e=u("/category/tree");try{const n=await g(e);if(!n.ok)throw new h(k(n.status),`http_${n.status}`);const r=await n.json();return r.success&&Array.isArray(r.data)?(t.info(`加载分类树成功 count=${r.data.length}`),r.data):[]}catch(e){return e instanceof h?t.error(`加载分类树失败: ${e.message}`):t.error("加载分类树失败",e),[]}}();if(0===e.length)return;ue.innerHTML=``;const n=(e,t=0)=>{for(const r of e){const e=document.createElement("option");e.value=String(r.id),e.textContent=`${" ".repeat(t)}${r.name}`,void 0!==se&&String(r.id)===String(se)&&(e.selected=!0),ue.appendChild(e),r.children&&r.children.length>0&&n(r.children,t+1)}};n(e),t.info(`知识库分类加载成功 count=${e.length}`)}catch(e){t.error(o("category_load_error"),e)}}()}async function Se(){if(oe&&ie&&(await E(),await Ae(),0===ae.length)){const e=function(e){try{const n=localStorage.getItem(G(e));if(!n)return[];const r=JSON.parse(n);return r&&Array.isArray(r.messages)?(t.info(`加载历史消息 integrateId=${e} count=${r.messages.length}`),r.messages):[]}catch(e){return[]}}(oe.integrateId);e.length>0&&(ae=e,je(),t.info(`从本地缓存恢复 ${e.length} 条消息`))}}async function Ae(){if(!oe||!ie)return;const e=p();if(e)try{const n=await v(e);n.messages.length>0&&(ae=n.messages.map((e,n)=>({id:N(),role:"USER"===e.messageType?"user":"ai",content:e.content,timestamp:new Date(e.createTime).getTime()})),je(),t.info(`从后端加载 ${ae.length} 条历史消息`),Q(l(),ae))}catch(e){}}function $e(){ke&&ke.classList.add("csk-newmsg--hidden")}function Ne(){ie&&(_e?V(ie):ke&&ke.classList.remove("csk-newmsg--hidden"))}function Me(e){de&&("stop"===e?(de.classList.add("csk-send-btn--stop"),de.removeAttribute("disabled"),de.setAttribute("title",o("stop")),de.setAttribute("aria-label",o("stop")),de.innerHTML=''):(de.classList.remove("csk-send-btn--stop"),de.setAttribute("title",o("send")),de.setAttribute("aria-label",o("send")),de.innerHTML='',Te()))}function Fe(){const e=null==ge?void 0:ge.querySelector("#csk-history-list");if(!e||!oe)return;K(e,Ce?Ee.filter(e=>(e.lastMessagePreview||e.chatId||e.id||"").toLowerCase().includes(Ce)):Ee,e=>{Re(e)},e=>{window.open(_(e),"_blank")},async e=>{if(!confirm(o("history_delete_confirm")))return;await w(e)&&(e===p()&&(ae=[],ie&&ie.querySelectorAll(".csk-msg, .csk-loading").forEach(e=>e.remove()),pe&&(pe.style.display="none"),De()),Ee=Ee.filter(n=>(n.chatId||n.id)!==e),Fe())},p())}function ze(e,n){if(!ie)return;const r=ae.find(n=>n.id===e&&"ai"===n.role);if(!r)return;const s=r.feedback===n?void 0:n;r.feedback=s;const o=ie.querySelector(`[data-csk-msg-id="${e}"]`);if(o&&W(o,s),oe&&Q(oe.integrateId,ae),s){const n="up"===s?"THUMBS_UP":"THUMBS_DOWN";(async function(e,n){if(!a)return!1;const r=u("/feedback");try{const s=await g(r,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({messageId:String(e),conversationId:a.chatId,feedbackType:n})});return s.ok?(await s.json()).success||!1:(t.error(`反馈提交失败 status=${s.status}`),!1)}catch(e){return t.error("反馈提交异常",e),!1}})(String(e),n).then(e=>{})}}function De(){if(!he)return;const e=ae.length>0||ie&&ie.querySelector(".csk-msg");he.style.display=e?"none":""}function Te(){if(!de||!ce)return;ce.value.trim().length>0&&!ve?de.removeAttribute("disabled"):de.setAttribute("disabled","true")}async function Be(){if(!ce||!oe||ve)return;const e=ce.value.trim();if(""===e)return;ce.value="",Te(),ce.style.height="auto";const n=z(),t={id:N(),role:"user",content:e,timestamp:n};ie&&q(ie,e,n),ae.push(t),De(),pe&&ae.length>0&&(pe.style.display="inline-flex"),ie&&Ne(),await He(e)}async function He(e){if(!oe||!ie)return;ve=!0,Me("stop"),oe.chatId||await E();const n=z(),r=Le;ye&&ye(),ie&&Ne();const s=N();let i="";try{oe.streaming?i=await async function(e,n,t,r){we=new AbortController;const s=we.signal;return new Promise((a,i)=>{let c=null,l=null,d="",p=!1;f(e,e=>{if(d+=e,!p&&ie){xe&&xe();const{wrapper:e,bubble:t}=function(e,n,t){const r=document.createElement("div");r.className="csk-msg csk-msg--ai csk-msg--streaming",t&&(r.dataset.cskMsgId=t);const s=document.createElement("div");s.className="csk-msg__avatar csk-msg__avatar--ai",s.innerHTML=D;const o=document.createElement("div");o.className="csk-msg__content";const a=document.createElement("div");a.className="csk-msg__bubble",a.innerHTML="";const i=document.createElement("div");i.className="csk-msg__time",i.textContent=F(n),o.appendChild(a);const c=document.createElement("div");return c.className="csk-msg__meta",c.appendChild(i),c.appendChild(U(a,r)),o.appendChild(c),r.appendChild(s),r.appendChild(o),e.appendChild(r),{wrapper:r,bubble:a}}(ie,n,r);l=e,c=t,p=!0}c&&(c.innerHTML=te(d),function(e){if(e.querySelector(".csk-caret"))return;const n=document.createElement("span");n.className="csk-caret",n.setAttribute("aria-hidden","true"),e.appendChild(n)}(c)),ie&&Ne()},()=>{if(l&&c){if(!p&&""===d)return void b(e).then(a).catch(i);d&&(c.innerHTML=te(d)),X(l,c)}a(d)},e=>{"network"!==e.type&&"cors"!==e.type||ie&&function(e){if(document.getElementById("csk-offline-banner"))return;const n=document.createElement("div");n.id="csk-offline-banner",n.className="csk-offline-banner",n.textContent=o("error_offline"),e.insertBefore(n,e.firstChild)}(ie),d.length>0?(c&&(c.innerHTML=te(d+"\n\n"+o("stream_interrupted")),l&&X(l,c)),a(d)):i(e)},se,t,s)})}(e,n,r,s):(i=await b(e),xe&&xe(),ie&&j(ie,i,n,te,s));const t={id:s,role:"ai",content:i,timestamp:n};ae.push(t),Q(oe.integrateId,ae),ie&&Ne(),function(e){if(!fe)return;const n=e.length>120?e.substring(0,120)+"...":e;fe.textContent=o("new_msg_announce")+":"+n}(i),ie&&ie.dispatchEvent(new CustomEvent("csk:newMessage",{bubbles:!0,detail:{msg:t}})),r&&async function(e,n){try{const t=await y(e,se);if(t.length>0){const e=t.map(e=>{var n,t;return{documentId:e.documentId||"",title:e.title||"",sourceName:e.sourceName||"",chunkIndex:null!==(n=e.chunkIndex)&&void 0!==n?n:0,score:null!==(t=e.score)&&void 0!==t?t:0,snippet:e.snippet||""}});if(n.sources=e,ie){const n=ie.querySelector(".csk-msg--ai:last-of-type");n&&J(n,e)}oe&&Q(oe.integrateId,ae)}}catch(e){}}(e,t),oe.suggestions&&async function(e){const n=p();if(!n||!ie)return;try{const t=await async function(e){if(!a||!e)return[];try{const n=new URLSearchParams;n.set("chatId",e);const t=u(`/ai/suggestions?${n.toString()}`),r=await g(t);if(!r.ok)return[];const s=await r.json();return s.success&&s.data&&Array.isArray(s.data.suggestions)?s.data.suggestions.filter(e=>"string"==typeof e&&e.trim().length>0):[]}catch(e){return[]}}(n);if(t.length>0&&ie){const n=ie.querySelector(`[data-csk-msg-id="${e}"]`);n&&function(e,n,t){if(function(e){const n=e.querySelector(".csk-suggestions");n&&n.remove()}(e),!n||0===n.length)return;const r=document.createElement("div");r.className="csk-suggestions";const s=document.createElement("div");s.className="csk-suggestions__list";for(const e of n){const n=document.createElement("button");n.type="button",n.className="csk-suggestion-item",n.textContent=e,n.addEventListener("click",n=>{n.stopPropagation(),t(e)}),s.appendChild(n)}r.appendChild(s);const o=e.querySelector(".csk-msg__content");o?o.appendChild(r):e.appendChild(r)}(n,t,qe)}}catch(e){}}(s),function(){const e=document.getElementById("csk-offline-banner");e&&e.remove()}()}catch(e){xe&&xe();const n=e instanceof h?e.message:o("error_send");if(ie){const e=document.createElement("div");e.className="csk-msg csk-msg--ai";const t=document.createElement("div");t.className="csk-msg__bubble",t.style.color="#DC2626",t.textContent=`⚠ ${n}`,e.appendChild(t),ie.appendChild(e)}t.error(`发送失败 integrateId=${oe.integrateId}`,e)}finally{ve=!1,we=null,Me("send"),Te()}}function qe(e){return!ce||ve?Promise.resolve():(ce.value=e,Te(),Be())}function je(){if(!ie)return;const e=ie.querySelector(".csk-history-panel");ie.querySelectorAll(".csk-msg, .csk-loading").forEach(e=>e.remove());for(const e of ae)if("user"===e.role)q(ie,e.content,e.timestamp);else{const n=j(ie,e.content,e.timestamp,te,e.id);e.sources&&e.sources.length>0&&J(n,e.sources),e.feedback&&W(n,e.feedback)}_e=!0,V(ie),pe&&ae.length>0&&(pe.style.display="inline-flex"),De(),e&&!ie.contains(e)&&ie.appendChild(e)}async function Re(e){if(!oe||!ie)return;const n=Ee.find(n=>(n.chatId||n.id)===e);if(n&&void 0!==n.roleId){const e=String(n.roleId),t=l();e&&e!==t&&(c(e),me&&(me.value=e))}d(e),L(l(),oe.userId,e),ge&&ge.classList.add("csk-history-panel--hidden"),ae=[];ie.querySelectorAll(".csk-msg, .csk-loading").forEach(e=>e.remove());try{const n=await v(e);n.messages.length>0&&(ae=n.messages.map(e=>({id:N(),role:"USER"===e.messageType?"user":"ai",content:e.content,timestamp:new Date(e.createTime).getTime()})),je(),t.info(`加载会话 ${e} 的 ${ae.length} 条消息`),Q(oe.integrateId,ae))}catch(e){}pe&&ae.length>0&&(pe.style.display="inline-flex"),De()}let Pe=null,Ue=!1,We=null,Ye=null,Oe=null,Xe=null,Je=null,Ke=null,Ve=null,Ge=null,Qe=null,Ze=null,en=null,nn=null,tn=null,rn=null,sn=null,on=null,an=null,cn=null,ln=null;function dn(){if(!sn||!We)return;const e=We.getBoundingClientRect(),n=rn?"left"===rn.side:"left-bottom"===(null==Pe?void 0:Pe.position);n?(sn.style.left=`${e.left}px`,sn.style.right="auto"):(sn.style.right=window.innerWidth-e.right+"px",sn.style.left="auto"),sn.style.bottom=window.innerHeight-e.top+8+"px",sn.classList.toggle("csk-teaser--left",!!n),sn.classList.toggle("csk-teaser--right",!n)}function pn(){if(!sn)return;sn.classList.add("csk-teaser--hidden"),sn.removeEventListener("click",un);const e=sn.querySelector(".csk-teaser__close");e&&e.removeEventListener("click",mn)}function un(e){e.target.closest(".csk-teaser__close")||(pn(),bn())}function mn(e){e.stopPropagation(),pn()}function gn(){sn&&!sn.classList.contains("csk-teaser--hidden")&&dn()}const hn='button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';function kn(e){"Escape"===e.key&&Ye&&!Ye.classList.contains("csk-window--hidden")&&fn(),function(e){if(!Ye||Ye.classList.contains("csk-window--hidden"))return;if("Tab"!==e.key)return;const n=Array.from(Ye.querySelectorAll(hn));if(0===n.length)return;const t=n[0],r=n[n.length-1];e.shiftKey?document.activeElement===t&&(e.preventDefault(),r.focus()):document.activeElement===r&&(e.preventDefault(),t.focus())}(e)}function bn(){Ye&&(Ye.classList.remove("csk-window--hidden"),pn(),an&&an.classList.add("csk-launcher__badge--hidden"),setTimeout(()=>{Xe&&Xe.focus()},80))}function fn(){Ye&&Ye.classList.add("csk-window--hidden")}function yn(){Ye&&(Ye.classList.contains("csk-window--hidden")?bn():fn())}function xn(e){return`csk_size_${e}`}function vn(e){return`csk_position_${e}`}function wn(e){return`csk_launcher_pos_${e}`}function _n(e){Ye&&(Ye.classList.remove("csk-window--right","csk-window--left"),Ye.classList.add(`csk-window--${e}`),sn&&(sn.classList.remove("csk-teaser--right","csk-teaser--left"),sn.classList.add(`csk-teaser--${e}`)))}const En={init:function(e){if(Ue)return;const i=function(e){var n,r,s,o,a,i,c,l,d,p,u,m,g;if(!e.integrateId||"string"!=typeof e.integrateId&&"number"!=typeof e.integrateId||"string"==typeof e.integrateId&&""===e.integrateId.trim())return t.error('integrateId 是必传参数(对应后端 roleId 客服角色 ID),请检查 init() 调用。示例:ChatbotSDK.init({ integrateId: 1, requestDomain: "https://api.example.com" })'),null;if(!e.requestDomain||"string"!=typeof e.requestDomain||""===e.requestDomain.trim())return t.error('requestDomain 是必传参数,请检查 init() 调用。示例:ChatbotSDK.init({ integrateId: 1, requestDomain: "https://api.example.com" })'),null;try{new URL(e.requestDomain)}catch(n){return t.error(`requestDomain 不是合法的 URL 格式:${e.requestDomain}。请提供完整的域名,如 https://api.example.com`),null}const h=String(e.integrateId).trim(),k=e.requestDomain.replace(/\/+$/,""),b=e.launcherIcon||`${d(r[1])}
`);continue}c&&f();const y=n.match(/^ {0,3}[\-\*]\s+(.+)/);if(y){k(),f(),a&&"ul"===i||(b(),a=!0,i="ul",o.push('')),o.push(`
":""),a=!1,i="")}function f(){c&&(o.push("- ${d(y[1])}
`);continue}const x=n.match(/^ {0,3}\d+\.\s+(.+)/);x?(k(),f(),a&&"ol"===i||(b(),a=!0,i="ol",o.push('')),o.push(`
- ${d(x[1])}
`)):""!==n.trim()?/^(\*{3,}|-{3,}|_{3,})$/.test(n.trim())?(k(),b(),f(),o.push('
')):(b(),f(),l.push(d(n))):(k(),b())}return k(),b(),f(),o.join("\n");function d(e){return e=(e=(e=(e=(e=(e=e.replace(/\*\*(.+?)\*\*/g,"$1")).replace(/__(.+?)__/g,"$1")).replace(/\*(.+?)\*/g,"$1")).replace(/(?$1")).replace(/~~(.+?)~~/g,"$1")).replace(/\[([^\]]+)\]\(([^)]+)\)/g,(e,n,t)=>`${n}`)}function p(e){const n=m(e);return n.length>0&&n.every(e=>/^:?-{3,}:?$/.test(e.trim()))}function u(e){return""!==e.trim()&&e.includes("|")}function m(e){const n=e.trim().replace(/^\|/,"").replace(/\|$/,"");if(!n.includes("|"))return[];const t=[];let r="";for(let e=0;e0&&(o.push(` ${l.join("
`),l=[])}function b(){a&&(o.push("ul"===i?"
")}
`,f=e.primaryColor||"#4F46E5",y={integrateId:h,requestDomain:e.requestDomain.replace(/\/+$/,""),userId:e.userId,categoryId:e.categoryId,showCategorySwitch:null!==(n=e.showCategorySwitch)&&void 0!==n&&n,title:e.title||"AI 智能助手",width:null!==(r=e.width)&&void 0!==r?r:500,height:Math.max(400,null!==(s=e.height)&&void 0!==s?s:520),position:"left-bottom"===e.position?"left-bottom":"right-bottom",primaryColor:f,launcherIcon:b,showClear:null===(o=e.showClear)||void 0===o||o,showAdminPanel:null!==(a=e.showAdminPanel)&&void 0!==a&&a,quickReplies:Array.isArray(e.quickReplies)?e.quickReplies.map(e=>String(e).trim()).filter(Boolean):[],suggestions:null===(i=e.suggestions)||void 0===i||i,theme:"dark"===e.theme?"dark":"light",showTeaser:null===(c=e.showTeaser)||void 0===c||c,teaserText:"string"==typeof e.teaserText&&e.teaserText.trim()||"",resizable:null===(l=e.resizable)||void 0===l||l,watermark:"string"==typeof e.watermark&&e.watermark.trim()||void 0,streaming:null===(d=e.streaming)||void 0===d||d,enableRag:null===(p=e.enableRag)||void 0===p||p,rewriteStrategy:e.rewriteStrategy||"REWRITE",locale:e.locale||"zh-CN",debug:null===(u=e.debug)||void 0===u||u,sound:null!==(m=e.sound)&&void 0!==m&&m,notification:null!==(g=e.notification)&&void 0!==g&&g,onError:"function"==typeof e.onError?e.onError:void 0,onReady:"function"==typeof e.onReady?e.onReady:void 0,onMessage:"function"==typeof e.onMessage?e.onMessage:void 0,token:e.token,roles:e.roles,disclaimer:e.disclaimer,chatId:""};return t.info(`配置解析完成 integrateId(=roleId)=${y.integrateId} userId(=accountId)=${y.userId||"(未设置)"} requestDomain=${y.requestDomain}`),y}(e);if(!i)return;Pe=i,function(e){if(r[e])s=e;else{const n=e.split("-")[0],t=Object.keys(r).find(e=>e.startsWith(n));t&&(s=t)}}(Pe.locale),Pe.debug,n(Pe.onError),function(e){a=e}(Pe),$(Pe),We=T(Pe,yn),document.body.appendChild(We),an=We.querySelector(".csk-launcher__badge"),function(e,n){try{const t=localStorage.getItem(wn(e));if(!t)return;const r=JSON.parse(t);if("left"!==r.side&&"right"!==r.side||"number"!=typeof r.bottom)return;const s=window.innerHeight-76,o=Math.max(16,Math.min(r.bottom,s));n.classList.remove("csk-launcher--right","csk-launcher--left"),n.classList.add(`csk-launcher--${r.side}`),n.style.bottom=`${o}px`,rn={side:r.side,bottom:o}}catch(e){}}(Pe.integrateId,We),nn=function(e,n,t){let r=!1,s=0,o=0,a=!1,i=0,c=0,l=0,d=!1;function p(){const n=parseFloat(getComputedStyle(e).bottom);return isNaN(n)?24:n}function u(n,t){if(d)return;r=!0,a=!1,s=n,o=t,i=p();const u=e.style,m=getComputedStyle(e);c=u.right?parseFloat(u.right):parseFloat(m.right),l=u.left?parseFloat(u.left):parseFloat(m.left)}function m(n,t,d){if(!r)return;const p=n-s,u=t-o;if(!a){if(Math.abs(p)<5&&Math.abs(u)<5)return;a=!0,e.classList.add("csk-launcher--dragging"),e.classList.remove("csk-launcher--right","csk-launcher--left"),e.style.transition="none",!isNaN(c)&&c>=0&&isNaN(l)?(e.style.right=`${c}px`,e.style.left="auto"):!isNaN(l)&&l>=0&&(e.style.left=`${l}px`,e.style.right="auto")}if(a){d.preventDefault();const n=Math.max(16,Math.min(i-u,H()));e.style.bottom=`${n}px`}}function g(){if(!r)return;if(r=!1,!a)return;const n=parseFloat(e.style.bottom)||p(),s=Math.max(16,Math.min(n,H())),o=e.getBoundingClientRect(),i=o.left+o.width/2<=window.innerWidth/2?"left":"right";e.classList.remove("csk-launcher--dragging"),e.classList.add(`csk-launcher--${i}`,"csk-launcher--snap"),e.style.left="",e.style.right="",e.style.bottom=`${s}px`,d=!0;const c=()=>{e.removeEventListener("transitionend",c),e.classList.remove("csk-launcher--snap"),e.style.transition="",d=!1};e.addEventListener("transitionend",c),setTimeout(()=>{d&&c()},350);const l=n=>{n.stopPropagation(),e.removeEventListener("click",l,!0)};e.addEventListener("click",l,!0);const u=e.querySelector(".csk-launcher__badge");u&&(u.style.display=""),t&&t({side:i,bottom:s})}function h(e){u(e.clientX,e.clientY)}function k(e){m(e.clientX,e.clientY,e)}function b(){g()}function f(e){1===e.touches.length&&u(e.touches[0].clientX,e.touches[0].clientY)}function y(e){1===e.touches.length&&m(e.touches[0].clientX,e.touches[0].clientY,e)}function x(){g()}return e.addEventListener("mousedown",h),document.addEventListener("mousemove",k),document.addEventListener("mouseup",b),e.addEventListener("touchstart",f,{passive:!0}),document.addEventListener("touchmove",y,{passive:!1}),document.addEventListener("touchend",x),()=>{e.removeEventListener("mousedown",h),document.removeEventListener("mousemove",k),document.removeEventListener("mouseup",b),e.removeEventListener("touchstart",f),document.removeEventListener("touchmove",y),document.removeEventListener("touchend",x)}}(We,0,e=>{const n=null==rn?void 0:rn.side;rn=e,function(e,n){try{localStorage.setItem(wn(e),JSON.stringify(n))}catch(e){}}(Pe.integrateId,e),n&&n!==e.side&&function(){if(!Ye)return;Ye.style.left="",Ye.style.top="",Ye.style.right="",Ye.style.bottom=""}(),_n(e.side),sn&&!sn.classList.contains("csk-teaser--hidden")&&dn()}),rn&&_n(rn.side);const d=B(Pe);Ye=d.window,Oe=d.messagesContainer,Xe=d.inputEl,Je=d.sendBtn,Ke=d.clearBtn,Ve=d.categorySelect,Ge=d.historyPanel,Qe=d.showLoading,Ze=d.hideLoading,ln=d.disclaimer,document.body.appendChild(Ye),sn=d.teaserEl,document.body.appendChild(sn),dn();const m=Ye.querySelector(".csk-header");if(m&&(en=function(e,n,t){let r=!1,s=0,o=0,a=0,i=0;const c=e=>{if(e.target.closest("button"))return;r=!0,s=e.clientX,o=e.clientY;const t=n.getBoundingClientRect();a=s-t.left,i=o-t.top,document.addEventListener("mousemove",l),document.addEventListener("mouseup",d)},l=e=>{if(!r)return;const t=e.clientX-a,s=e.clientY-i,o=window.innerWidth-n.offsetWidth,c=window.innerHeight-n.offsetHeight;n.style.right="auto",n.style.bottom="auto",n.style.left=`${Math.max(0,Math.min(t,o))}px`,n.style.top=`${Math.max(0,Math.min(s,c))}px`},d=()=>{if(r=!1,document.removeEventListener("mousemove",l),document.removeEventListener("mouseup",d),t){const e=n.getBoundingClientRect();t({x:e.left,y:e.top})}};return e.addEventListener("mousedown",c),()=>{e.removeEventListener("mousedown",c),document.removeEventListener("mousemove",l),document.removeEventListener("mouseup",d)}}(m,Ye,e=>{!function(e,n){try{localStorage.setItem(vn(e),JSON.stringify(n))}catch(e){}}(Pe.integrateId,e)})),function(e,n){try{const t=localStorage.getItem(vn(e));if(!t)return;const r=JSON.parse(t);if("number"!=typeof r.x||"number"!=typeof r.y)return;const s=window.innerWidth-n.offsetWidth,o=window.innerHeight-n.offsetHeight,a=Math.max(0,Math.min(r.x,s)),i=Math.max(0,Math.min(r.y,o));n.style.right="auto",n.style.bottom="auto",n.style.left=`${a}px`,n.style.top=`${i}px`}catch(e){}}(Pe.integrateId,Ye),Pe.resizable){const e=d.resizeHandle;tn=function(e,n,t){let r=!1,s=0,o=0,a=0,i=0;const c=(e,t)=>{r=!0,s=e,o=t;const c=n.getBoundingClientRect();a=c.width,i=c.height,n.classList.add("csk-window--resizing"),document.addEventListener("mousemove",p),document.addEventListener("mouseup",u),document.addEventListener("touchmove",h,{passive:!1}),document.addEventListener("touchend",k)},l=(e,t,c)=>{if(!r)return;c&&c.preventDefault();const l=e-s,d=t-o,p=Math.max(300,Math.min(a+l,window.innerWidth-24)),u=Math.max(300,Math.min(i+d,window.innerHeight-24));n.style.width=`${p}px`,n.style.height=`${u}px`,n.style.setProperty("--csk-window-width",`${p}px`),n.style.setProperty("--csk-window-height",`${u}px`),n.style.bottom="",n.style.right=""},d=()=>{if(!r)return;r=!1,n.classList.remove("csk-window--resizing"),document.removeEventListener("mousemove",p),document.removeEventListener("mouseup",u),document.removeEventListener("touchmove",h),document.removeEventListener("touchend",k);const e=n.getBoundingClientRect();t&&t({width:e.width,height:e.height})};function p(e){l(e.clientX,e.clientY,e)}function u(){d()}function m(e){e.preventDefault(),e.stopPropagation(),c(e.clientX,e.clientY)}function g(e){e.preventDefault(),e.stopPropagation(),1===e.touches.length&&c(e.touches[0].clientX,e.touches[0].clientY)}function h(e){1===e.touches.length&&l(e.touches[0].clientX,e.touches[0].clientY,e)}function k(){d()}return e.addEventListener("mousedown",m),e.addEventListener("touchstart",g,{passive:!1}),()=>{e.removeEventListener("mousedown",m),e.removeEventListener("touchstart",g),document.removeEventListener("mousemove",p),document.removeEventListener("mouseup",u),document.removeEventListener("touchmove",h),document.removeEventListener("touchend",k)}}(e,Ye,e=>{!function(e,n){try{localStorage.setItem(xn(e),JSON.stringify(n))}catch(e){}}(Pe.integrateId,e)}),function(e,n){try{const t=localStorage.getItem(xn(e));if(!t)return;const r=JSON.parse(t);if("number"!=typeof r.width||"number"!=typeof r.height)return;const s=Math.max(300,Math.min(r.width,window.innerWidth-24)),o=Math.max(300,Math.min(r.height,window.innerHeight-24));n.style.width=`${s}px`,n.style.height=`${o}px`,n.style.setProperty("--csk-window-width",`${s}px`),n.style.setProperty("--csk-window-height",`${o}px`)}catch(e){}}(Pe.integrateId,Ye)}if(Ie(Pe,{messagesContainer:Oe,inputEl:Xe,sendBtn:Je,clearBtn:Ke,categorySelect:Ve,historyPanel:Ge,welcomeEl:d.welcomeEl,newMsgBtn:d.newMsgBtn,searchInput:d.searchInput,ariaLiveEl:d.ariaLiveEl,roleSelect:d.roleSelect,showLoading:Qe,hideLoading:Ze}),Ye.addEventListener("csk:categoryChange",e=>{var n,t;n=e.detail.categoryId,se=n,Le=null===(t=null==oe?void 0:oe.enableRag)||void 0===t||t}),Ye.addEventListener("csk:loadHistory",()=>{!async function(){if(!ge||!oe)return;const e=ge.querySelector("#csk-history-list");if(e){e.innerHTML='${o}`),`${te}${s}\0`});const r=[];t=t.replace(/`([^`\n]+)`/g,(e,n)=>{const t=r.length;return r.push(`${F(n)}`),`${re}${t}\0`}),t=F(t),t=oe(t,te,n),t=oe(t,re,r);const s=t.split("\n"),o=[];let a=!1,i="",c=!1,l=[];for(let e=0;e| ${d(e)} | `)}),o.push("${d(r[t]||"")} | `)}),o.push(""),e++}o.push("
|---|
')),o.push(`"),c=!1)}}function oe(e,n,t){return e.replace(new RegExp(n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")+"(\\d+)\0","g"),(e,n)=>t[parseInt(n)]||"")}let ae,ie=null,ce=[],le=null,de=null,pe=null,ue=null,me=null,ke=null,ge=null,he=null,be=null,fe=null,ye=null,ve=null,xe=null,we=null,_e=!1,Ee=null,Ce=!0,Le=[],Ie="",Se=!1;function Ae(e,n){ie=e,le=n.messagesContainer,de=n.inputEl,pe=n.inputEl.parentElement,ue=n.sendBtn,me=n.clearBtn,ke=n.categorySelect,ge=n.roleSelect,he=n.historyPanel,be=n.welcomeEl,fe=n.newMsgBtn,ye=n.searchInput,ve=n.ariaLiveEl,xe=n.showLoading,we=n.hideLoading,ae=e.categoryId,Se=e.enableRag,function(){if(!de||!ue)return;ue.addEventListener("click",()=>{_e&&Ee?Ee.abort():He()}),de.addEventListener("keydown",e=>{"Enter"!==e.key||e.shiftKey||e.isComposing||(e.preventDefault(),He())}),de.addEventListener("input",()=>{qe(),function(){if(!de)return;de.style.height="auto",de.style.height=`${Math.min(de.scrollHeight,120)}px`}()}),de.addEventListener("focus",()=>{pe&&pe.classList.add("csk-input-wrap--focus")}),de.addEventListener("blur",()=>{pe&&pe.classList.remove("csk-input-wrap--focus")}),me&&me.addEventListener("click",()=>function(){if(!ie)return;if(ce=[],le){le.querySelectorAll(".csk-msg, .csk-loading").forEach(e=>e.remove())}me&&(me.style.display="none");Be(),ne(ie.integrateId);const e=function(){const e="undefined"!=typeof crypto&&crypto.randomUUID?crypto.randomUUID().substring(0,8):Math.random().toString(36).substring(2,10);return`sdk_${Date.now()}_${e}`}();d(e),I(ie.integrateId,ie.userId,e),t.lifecycleClear(ie.integrateId)}())}(),function(){if(!le)return;le.addEventListener("scroll",()=>{if(!le)return;const{scrollTop:e,scrollHeight:n,clientHeight:t}=le;Ce=n-e-t<80,Ce&&Me()}),fe&&fe.addEventListener("click",()=>{le&&G(le),Ce=!0,Me()})}(),function(){if(!ye)return;ye.addEventListener("input",()=>{Ie=ye.value.trim().toLowerCase(),De()})}(),e.showCategorySwitch&&ke&&async function(){if(!ke)return;try{const e=await async function(){const e=u("/category/tree");try{const n=await k(e);if(!n.ok)throw new g(h(n.status),`http_${n.status}`);const r=await n.json();return r.success&&Array.isArray(r.data)?(t.info(`加载分类树成功 count=${r.data.length}`),r.data):[]}catch(e){return e instanceof g?t.error(`加载分类树失败: ${e.message}`):t.error("加载分类树失败",e),[]}}();if(0===e.length)return;ke.innerHTML=``;const n=(e,t=0)=>{for(const r of e){const e=document.createElement("option");e.value=String(r.id),e.textContent=`${" ".repeat(t)}${r.name}`,void 0!==ae&&String(r.id)===String(ae)&&(e.selected=!0),ke.appendChild(e),r.children&&r.children.length>0&&n(r.children,t+1)}};n(e),t.info(`知识库分类加载成功 count=${e.length}`)}catch(e){t.error(o("category_load_error"),e)}}()}async function $e(){if(ie&&le&&(await C(),await Ne(),0===ce.length)){const e=function(e){try{const n=localStorage.getItem(Z(e));if(!n)return[];const r=JSON.parse(n);return r&&Array.isArray(r.messages)?(t.info(`加载历史消息 integrateId=${e} count=${r.messages.length}`),r.messages):[]}catch(e){return[]}}(ie.integrateId);e.length>0&&(ce=e,Pe(),t.info(`从本地缓存恢复 ${e.length} 条消息`))}}async function Ne(){if(!ie||!le)return;const e=p();if(e)try{const n=await w(e);n.messages.length>0&&(ce=n.messages.map((e,n)=>({id:M(),role:"USER"===e.messageType?"user":"ai",content:e.content,timestamp:new Date(e.createTime).getTime()})),Pe(),t.info(`从后端加载 ${ce.length} 条历史消息`),ee(l(),ce))}catch(e){}}function Me(){fe&&fe.classList.add("csk-newmsg--hidden")}function Fe(){le&&(Ce?G(le):fe&&fe.classList.remove("csk-newmsg--hidden"))}function ze(e){ue&&("stop"===e?(ue.classList.add("csk-send-btn--stop"),ue.removeAttribute("disabled"),ue.setAttribute("title",o("stop")),ue.setAttribute("aria-label",o("stop")),ue.innerHTML=''):(ue.classList.remove("csk-send-btn--stop"),ue.setAttribute("title",o("send")),ue.setAttribute("aria-label",o("send")),ue.innerHTML='',qe()))}function De(){const e=null==he?void 0:he.querySelector("#csk-history-list");if(!e||!ie)return;V(e,Ie?Le.filter(e=>(e.lastMessagePreview||e.chatId||e.id||"").toLowerCase().includes(Ie)):Le,e=>{Ue(e)},e=>{window.open(E(e),"_blank")},async e=>{if(!confirm(o("history_delete_confirm")))return;await _(e)&&(e===p()&&(ce=[],le&&le.querySelectorAll(".csk-msg, .csk-loading").forEach(e=>e.remove()),me&&(me.style.display="none"),Be()),Le=Le.filter(n=>(n.chatId||n.id)!==e),De())},p())}function Te(e,n){if(!le)return;const t=ce.find(n=>n.id===e&&"ai"===n.role);if(t){if("up"===n){const n="up"===t.feedback?void 0:"up";t.feedback=n,t.feedbackReason=void 0,t.feedbackComment=void 0;const r=le.querySelector(`[data-csk-msg-id="${e}"]`);return r&&Y(r,n),ie&&ee(ie.integrateId,ce),void(n&&v(String(e),"THUMBS_UP").then(e=>{}))}if("down"===n){const n=le.querySelector(`[data-csk-msg-id="${e}"]`);if(!n)return;if("down"===t.feedback)return t.feedback=void 0,t.feedbackReason=void 0,t.feedbackComment=void 0,n&&Y(n,void 0),void(ie&&ee(ie.integrateId,ce));!function(e,n,t){const r=e.querySelector(".csk-feedback-reason");r&&r.remove();const s=document.createElement("div");s.className="csk-feedback-reason";const a=document.createElement("div");a.className="csk-feedback-reason__title",a.textContent=o("feedback_reason_title"),s.appendChild(a);const i=document.createElement("div");i.className="csk-feedback-reason__options",Q.forEach(e=>{const n=document.createElement("button");n.type="button",n.className="csk-feedback-reason__btn",n.textContent=o(e.labelKey),n.addEventListener("click",n=>{n.stopPropagation(),t(e.key),s.remove()}),i.appendChild(n)}),s.appendChild(i);const c=document.createElement("div");c.className="csk-feedback-reason__comment-row";const l=document.createElement("input");l.type="text",l.className="csk-feedback-reason__comment",l.placeholder=o("feedback_reason_comment_placeholder"),l.maxLength=200,c.appendChild(l);const d=document.createElement("button");d.type="button",d.className="csk-feedback-reason__submit",d.textContent=o("feedback_reason_submit"),d.addEventListener("click",e=>{e.stopPropagation();const n=l.value.trim()||void 0;t("other",n),s.remove()}),c.appendChild(d),s.appendChild(c);const p=document.createElement("button");p.type="button",p.className="csk-feedback-reason__close",p.setAttribute("aria-label",o("close")),p.innerHTML='',p.addEventListener("click",e=>{e.stopPropagation(),s.remove()}),s.appendChild(p),e.appendChild(s)}(n,0,(r,s)=>{t.feedback="down",t.feedbackReason=r,t.feedbackComment=s,n&&Y(n,"down"),ie&&ee(ie.integrateId,ce),v(String(e),"THUMBS_DOWN",r,s).then(e=>{})})}}}function Be(){if(!be)return;const e=ce.length>0||le&&le.querySelector(".csk-msg");be.style.display=e?"none":""}function qe(){if(!ue||!de)return;de.value.trim().length>0&&!_e?ue.removeAttribute("disabled"):ue.setAttribute("disabled","true")}async function He(){if(!de||!ie||_e)return;const e=de.value.trim();if(""===e)return;de.value="",qe(),de.style.height="auto";const n=D(),t={id:M(),role:"user",content:e,timestamp:n};le&&j(le,e,n),ce.push(t),Be(),me&&ce.length>0&&(me.style.display="inline-flex"),le&&Fe(),await je(e)}async function je(e){if(!ie||!le)return;_e=!0,ze("stop"),ie.chatId||await C();const n=D(),r=Se;xe&&xe(),le&&Fe();const s=M();let i="";try{ie.streaming?i=await async function(e,n,t,r){Ee=new AbortController;const s=Ee.signal;return new Promise((a,i)=>{let c=null,l=null,d="",p=!1;f(e,e=>{if(d+=e,!p&&le){we&&we();const{wrapper:e,bubble:t}=function(e,n,t){const r=document.createElement("div");r.className="csk-msg csk-msg--ai csk-msg--streaming",t&&(r.dataset.cskMsgId=t);const s=document.createElement("div");s.className="csk-msg__avatar csk-msg__avatar--ai",s.innerHTML=T;const o=document.createElement("div");o.className="csk-msg__content";const a=document.createElement("div");a.className="csk-msg__bubble",a.innerHTML="";const i=document.createElement("div");i.className="csk-msg__time",i.textContent=z(n),o.appendChild(a);const c=document.createElement("div");return c.className="csk-msg__meta",c.appendChild(i),c.appendChild(W(a,r)),o.appendChild(c),r.appendChild(s),r.appendChild(o),e.appendChild(r),{wrapper:r,bubble:a}}(le,n,r);l=e,c=t,p=!0}c&&(c.innerHTML=se(d),function(e){if(e.querySelector(".csk-caret"))return;const n=document.createElement("span");n.className="csk-caret",n.setAttribute("aria-hidden","true"),e.appendChild(n)}(c)),le&&Fe()},()=>{if(l&&c){if(!p&&""===d)return void b(e).then(a).catch(i);d&&(c.innerHTML=se(d)),K(l,c)}a(d)},e=>{"network"!==e.type&&"cors"!==e.type||le&&function(e){if(document.getElementById("csk-offline-banner"))return;const n=document.createElement("div");n.id="csk-offline-banner",n.className="csk-offline-banner",n.textContent=o("error_offline"),e.insertBefore(n,e.firstChild)}(le),d.length>0?(c&&(c.innerHTML=se(d+"\n\n"+o("stream_interrupted")),l&&K(l,c)),a(d)):i(e)},ae,t,s)})}(e,n,r,s):(i=await b(e),we&&we(),le&&R(le,i,n,se,s));const t={id:s,role:"ai",content:i,timestamp:n};ce.push(t),ee(ie.integrateId,ce),le&&Fe(),function(e){if(!ve)return;const n=e.length>120?e.substring(0,120)+"...":e;ve.textContent=o("new_msg_announce")+":"+n}(i),le&&le.dispatchEvent(new CustomEvent("csk:newMessage",{bubbles:!0,detail:{msg:t}})),r&&async function(e,n){try{const t=await y(e,ae);if(t.length>0){const e=t.map(e=>{var n,t;return{documentId:e.documentId||"",title:e.title||"",sourceName:e.sourceName||"",chunkIndex:null!==(n=e.chunkIndex)&&void 0!==n?n:0,score:null!==(t=e.score)&&void 0!==t?t:0,snippet:e.snippet||""}});if(n.sources=e,le){const n=le.querySelector(".csk-msg--ai:last-of-type");n&&J(n,e)}ie&&ee(ie.integrateId,ce)}}catch(e){}}(e,t),ie.suggestions&&async function(e){const n=p();if(!n||!le)return;try{const t=await async function(e){if(!a||!e)return[];try{const n=new URLSearchParams;n.set("chatId",e);const t=u(`/ai/suggestions?${n.toString()}`),r=await k(t);if(!r.ok)return[];const s=await r.json();return s.success&&s.data&&Array.isArray(s.data.suggestions)?s.data.suggestions.filter(e=>"string"==typeof e&&e.trim().length>0):[]}catch(e){return[]}}(n);if(t.length>0&&le){const n=le.querySelector(`[data-csk-msg-id="${e}"]`);n&&function(e,n,t){if(function(e){const n=e.querySelector(".csk-suggestions");n&&n.remove()}(e),!n||0===n.length)return;const r=document.createElement("div");r.className="csk-suggestions";const s=document.createElement("div");s.className="csk-suggestions__list";for(const e of n){const n=document.createElement("button");n.type="button",n.className="csk-suggestion-item",n.textContent=e,n.addEventListener("click",n=>{n.stopPropagation(),t(e)}),s.appendChild(n)}r.appendChild(s);const o=e.querySelector(".csk-msg__content");o?o.appendChild(r):e.appendChild(r)}(n,t,Re)}}catch(e){}}(s),function(){const e=document.getElementById("csk-offline-banner");e&&e.remove()}()}catch(e){we&&we();const n=e instanceof g?e.message:o("error_send");if(le){const e=document.createElement("div");e.className="csk-msg csk-msg--ai";const t=document.createElement("div");t.className="csk-msg__bubble",t.style.color="#DC2626",t.textContent=`⚠ ${n}`,e.appendChild(t),le.appendChild(e)}t.error(`发送失败 integrateId=${ie.integrateId}`,e)}finally{_e=!1,Ee=null,ze("send"),qe()}}function Re(e){return!de||_e?Promise.resolve():(de.value=e,qe(),He())}function Pe(){if(!le)return;const e=le.querySelector(".csk-history-panel");le.querySelectorAll(".csk-msg, .csk-loading").forEach(e=>e.remove());for(const e of ce)if("user"===e.role)j(le,e.content,e.timestamp);else{const n=R(le,e.content,e.timestamp,se,e.id);e.sources&&e.sources.length>0&&J(n,e.sources),e.feedback&&Y(n,e.feedback)}Ce=!0,G(le),me&&ce.length>0&&(me.style.display="inline-flex"),Be(),e&&!le.contains(e)&&le.appendChild(e)}async function Ue(e){if(!ie||!le)return;const n=Le.find(n=>(n.chatId||n.id)===e);if(n&&void 0!==n.roleId){const e=String(n.roleId),t=l();e&&e!==t&&(c(e),ge&&(ge.value=e))}d(e),I(l(),ie.userId,e),he&&he.classList.add("csk-history-panel--hidden"),ce=[];le.querySelectorAll(".csk-msg, .csk-loading").forEach(e=>e.remove());try{const n=await w(e);n.messages.length>0&&(ce=n.messages.map(e=>({id:M(),role:"USER"===e.messageType?"user":"ai",content:e.content,timestamp:new Date(e.createTime).getTime()})),Pe(),t.info(`加载会话 ${e} 的 ${ce.length} 条消息`),ee(ie.integrateId,ce))}catch(e){}me&&ce.length>0&&(me.style.display="inline-flex"),Be()}let We=null,Ye=!1,Oe=null,Xe=null,Ke=null,Je=null,Ve=null,Ge=null,Qe=null,Ze=null,en=null,nn=null,tn=null,rn=null,sn=null,on=null,an=null,cn=null,ln=null,dn=null,pn=null;function un(){if(!an||!Oe)return;const e=Oe.getBoundingClientRect(),n=on?"left"===on.side:"left-bottom"===(null==We?void 0:We.position);n?(an.style.left=`${e.left}px`,an.style.right="auto"):(an.style.right=window.innerWidth-e.right+"px",an.style.left="auto"),an.style.bottom=window.innerHeight-e.top+8+"px",an.classList.toggle("csk-teaser--left",!!n),an.classList.toggle("csk-teaser--right",!n)}function mn(){if(!an)return;an.classList.add("csk-teaser--hidden"),an.removeEventListener("click",kn);const e=an.querySelector(".csk-teaser__close");e&&e.removeEventListener("click",gn)}function kn(e){e.target.closest(".csk-teaser__close")||(mn(),yn())}function gn(e){e.stopPropagation(),mn()}function hn(){an&&!an.classList.contains("csk-teaser--hidden")&&un()}const bn='button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';function fn(e){"Escape"===e.key&&Xe&&!Xe.classList.contains("csk-window--hidden")&&vn(),function(e){if(!Xe||Xe.classList.contains("csk-window--hidden"))return;if("Tab"!==e.key)return;const n=Array.from(Xe.querySelectorAll(bn));if(0===n.length)return;const t=n[0],r=n[n.length-1];e.shiftKey?document.activeElement===t&&(e.preventDefault(),r.focus()):document.activeElement===r&&(e.preventDefault(),t.focus())}(e)}function yn(){Xe&&(Xe.classList.remove("csk-window--hidden"),mn(),ln&&ln.classList.add("csk-launcher__badge--hidden"),setTimeout(()=>{Je&&Je.focus()},80))}function vn(){Xe&&Xe.classList.add("csk-window--hidden")}function xn(){Xe&&(Xe.classList.contains("csk-window--hidden")?yn():vn())}function wn(e){return`csk_size_${e}`}function _n(e){return`csk_position_${e}`}function En(e){return`csk_launcher_pos_${e}`}function Cn(e){Xe&&(Xe.classList.remove("csk-window--right","csk-window--left"),Xe.classList.add(`csk-window--${e}`),an&&(an.classList.remove("csk-teaser--right","csk-teaser--left"),an.classList.add(`csk-teaser--${e}`)))}const Ln={init:function(e){if(Ye)return;const i=function(e){var n,r,s,o,a,i,c,l,d,p,u,m,k;if(!e.integrateId||"string"!=typeof e.integrateId&&"number"!=typeof e.integrateId||"string"==typeof e.integrateId&&""===e.integrateId.trim())return t.error('integrateId 是必传参数(对应后端 roleId 客服角色 ID),请检查 init() 调用。示例:ChatbotSDK.init({ integrateId: 1, requestDomain: "https://api.example.com" })'),null;if(!e.requestDomain||"string"!=typeof e.requestDomain||""===e.requestDomain.trim())return t.error('requestDomain 是必传参数,请检查 init() 调用。示例:ChatbotSDK.init({ integrateId: 1, requestDomain: "https://api.example.com" })'),null;try{new URL(e.requestDomain)}catch(n){return t.error(`requestDomain 不是合法的 URL 格式:${e.requestDomain}。请提供完整的域名,如 https://api.example.com`),null}const g=String(e.integrateId).trim(),h=e.requestDomain.replace(/\/+$/,""),b=e.launcherIcon||`${d(r[1])}
`);continue}c&&f();const y=n.match(/^ {0,3}[\-\*]\s+(.+)/);if(y){h(),f(),a&&"ul"===i||(b(),a=!0,i="ul",o.push('')),o.push(`
":""),a=!1,i="")}function f(){c&&(o.push("- ${d(y[1])}
`);continue}const v=n.match(/^ {0,3}\d+\.\s+(.+)/);v?(h(),f(),a&&"ol"===i||(b(),a=!0,i="ol",o.push('')),o.push(`
- ${d(v[1])}
`)):""!==n.trim()?/^(\*{3,}|-{3,}|_{3,})$/.test(n.trim())?(h(),b(),f(),o.push('
')):(b(),f(),l.push(d(n))):(h(),b())}return h(),b(),f(),o.join("\n");function d(e){return e=(e=(e=(e=(e=(e=e.replace(/\*\*(.+?)\*\*/g,"$1")).replace(/__(.+?)__/g,"$1")).replace(/\*(.+?)\*/g,"$1")).replace(/(?$1")).replace(/~~(.+?)~~/g,"$1")).replace(/\[([^\]]+)\]\(([^)]+)\)/g,(e,n,t)=>`${n}`)}function p(e){const n=m(e);return n.length>0&&n.every(e=>/^:?-{3,}:?$/.test(e.trim()))}function u(e){return""!==e.trim()&&e.includes("|")}function m(e){const n=e.trim().replace(/^\|/,"").replace(/\|$/,"");if(!n.includes("|"))return[];const t=[];let r="";for(let e=0;e0&&(o.push(` ${l.join("
`),l=[])}function b(){a&&(o.push("ul"===i?"
")}
`,f=e.primaryColor||"#4F46E5",y={integrateId:g,requestDomain:e.requestDomain.replace(/\/+$/,""),userId:e.userId,categoryId:e.categoryId,showCategorySwitch:null!==(n=e.showCategorySwitch)&&void 0!==n&&n,title:e.title||"AI 智能助手",width:null!==(r=e.width)&&void 0!==r?r:500,height:Math.max(400,null!==(s=e.height)&&void 0!==s?s:520),position:"left-bottom"===e.position?"left-bottom":"right-bottom",primaryColor:f,launcherIcon:b,showClear:null===(o=e.showClear)||void 0===o||o,showAdminPanel:null!==(a=e.showAdminPanel)&&void 0!==a&&a,quickReplies:Array.isArray(e.quickReplies)?e.quickReplies.map(e=>String(e).trim()).filter(Boolean):[],suggestions:null===(i=e.suggestions)||void 0===i||i,theme:"dark"===e.theme?"dark":"light",showTeaser:null===(c=e.showTeaser)||void 0===c||c,teaserText:"string"==typeof e.teaserText&&e.teaserText.trim()||"",resizable:null===(l=e.resizable)||void 0===l||l,watermark:"string"==typeof e.watermark&&e.watermark.trim()||void 0,streaming:null===(d=e.streaming)||void 0===d||d,enableRag:null===(p=e.enableRag)||void 0===p||p,rewriteStrategy:e.rewriteStrategy||"REWRITE",locale:e.locale||"zh-CN",debug:null===(u=e.debug)||void 0===u||u,sound:null!==(m=e.sound)&&void 0!==m&&m,notification:null!==(k=e.notification)&&void 0!==k&&k,onError:"function"==typeof e.onError?e.onError:void 0,onReady:"function"==typeof e.onReady?e.onReady:void 0,onMessage:"function"==typeof e.onMessage?e.onMessage:void 0,token:e.token,roles:e.roles,disclaimer:e.disclaimer,chatId:""};return t.info(`配置解析完成 integrateId(=roleId)=${y.integrateId} userId(=accountId)=${y.userId||"(未设置)"} requestDomain=${y.requestDomain}`),y}(e);if(!i)return;We=i,function(e){if(r[e])s=e;else{const n=e.split("-")[0],t=Object.keys(r).find(e=>e.startsWith(n));t&&(s=t)}}(We.locale),We.debug,n(We.onError),function(e){a=e}(We),N(We),Oe=B(We,xn),document.body.appendChild(Oe),ln=Oe.querySelector(".csk-launcher__badge"),function(e,n){try{const t=localStorage.getItem(En(e));if(!t)return;const r=JSON.parse(t);if("left"!==r.side&&"right"!==r.side||"number"!=typeof r.bottom)return;const s=window.innerHeight-76,o=Math.max(16,Math.min(r.bottom,s));n.classList.remove("csk-launcher--right","csk-launcher--left"),n.classList.add(`csk-launcher--${r.side}`),n.style.bottom=`${o}px`,on={side:r.side,bottom:o}}catch(e){}}(We.integrateId,Oe),rn=function(e,n,t){let r=!1,s=0,o=0,a=!1,i=0,c=0,l=0,d=!1;function p(){const n=parseFloat(getComputedStyle(e).bottom);return isNaN(n)?24:n}function u(n,t){if(d)return;r=!0,a=!1,s=n,o=t,i=p();const u=e.style,m=getComputedStyle(e);c=u.right?parseFloat(u.right):parseFloat(m.right),l=u.left?parseFloat(u.left):parseFloat(m.left)}function m(n,t,d){if(!r)return;const p=n-s,u=t-o;if(!a){if(Math.abs(p)<5&&Math.abs(u)<5)return;a=!0,e.classList.add("csk-launcher--dragging"),e.classList.remove("csk-launcher--right","csk-launcher--left"),e.style.transition="none",!isNaN(c)&&c>=0&&isNaN(l)?(e.style.right=`${c}px`,e.style.left="auto"):!isNaN(l)&&l>=0&&(e.style.left=`${l}px`,e.style.right="auto")}if(a){d.preventDefault();const n=Math.max(16,Math.min(i-u,H()));e.style.bottom=`${n}px`}}function k(){if(!r)return;if(r=!1,!a)return;const n=parseFloat(e.style.bottom)||p(),s=Math.max(16,Math.min(n,H())),o=e.getBoundingClientRect(),i=o.left+o.width/2<=window.innerWidth/2?"left":"right";e.classList.remove("csk-launcher--dragging"),e.classList.add(`csk-launcher--${i}`,"csk-launcher--snap"),e.style.left="",e.style.right="",e.style.bottom=`${s}px`,d=!0;const c=()=>{e.removeEventListener("transitionend",c),e.classList.remove("csk-launcher--snap"),e.style.transition="",d=!1};e.addEventListener("transitionend",c),setTimeout(()=>{d&&c()},350);const l=n=>{n.stopPropagation(),e.removeEventListener("click",l,!0)};e.addEventListener("click",l,!0);const u=e.querySelector(".csk-launcher__badge");u&&(u.style.display=""),t&&t({side:i,bottom:s})}function g(e){u(e.clientX,e.clientY)}function h(e){m(e.clientX,e.clientY,e)}function b(){k()}function f(e){1===e.touches.length&&u(e.touches[0].clientX,e.touches[0].clientY)}function y(e){1===e.touches.length&&m(e.touches[0].clientX,e.touches[0].clientY,e)}function v(){k()}return e.addEventListener("mousedown",g),document.addEventListener("mousemove",h),document.addEventListener("mouseup",b),e.addEventListener("touchstart",f,{passive:!0}),document.addEventListener("touchmove",y,{passive:!1}),document.addEventListener("touchend",v),()=>{e.removeEventListener("mousedown",g),document.removeEventListener("mousemove",h),document.removeEventListener("mouseup",b),e.removeEventListener("touchstart",f),document.removeEventListener("touchmove",y),document.removeEventListener("touchend",v)}}(Oe,0,e=>{const n=null==on?void 0:on.side;on=e,function(e,n){try{localStorage.setItem(En(e),JSON.stringify(n))}catch(e){}}(We.integrateId,e),n&&n!==e.side&&function(){if(!Xe)return;Xe.style.left="",Xe.style.top="",Xe.style.right="",Xe.style.bottom=""}(),Cn(e.side),an&&!an.classList.contains("csk-teaser--hidden")&&un()}),on&&Cn(on.side);const d=q(We);Xe=d.window,Ke=d.messagesContainer,Je=d.inputEl,Ve=d.sendBtn,Ge=d.clearBtn,Qe=d.categorySelect,Ze=d.historyPanel,en=d.showLoading,nn=d.hideLoading,pn=d.disclaimer,document.body.appendChild(Xe),an=d.teaserEl,document.body.appendChild(an),un();const m=Xe.querySelector(".csk-header");if(m&&(tn=function(e,n,t){let r=!1,s=0,o=0,a=0,i=0;const c=e=>{if(e.target.closest("button"))return;r=!0,s=e.clientX,o=e.clientY;const t=n.getBoundingClientRect();a=s-t.left,i=o-t.top,document.addEventListener("mousemove",l),document.addEventListener("mouseup",d)},l=e=>{if(!r)return;const t=e.clientX-a,s=e.clientY-i,o=window.innerWidth-n.offsetWidth,c=window.innerHeight-n.offsetHeight;n.style.right="auto",n.style.bottom="auto",n.style.left=`${Math.max(0,Math.min(t,o))}px`,n.style.top=`${Math.max(0,Math.min(s,c))}px`},d=()=>{if(r=!1,document.removeEventListener("mousemove",l),document.removeEventListener("mouseup",d),t){const e=n.getBoundingClientRect();t({x:e.left,y:e.top})}};return e.addEventListener("mousedown",c),()=>{e.removeEventListener("mousedown",c),document.removeEventListener("mousemove",l),document.removeEventListener("mouseup",d)}}(m,Xe,e=>{!function(e,n){try{localStorage.setItem(_n(e),JSON.stringify(n))}catch(e){}}(We.integrateId,e)})),function(e,n){try{const t=localStorage.getItem(_n(e));if(!t)return;const r=JSON.parse(t);if("number"!=typeof r.x||"number"!=typeof r.y)return;const s=window.innerWidth-n.offsetWidth,o=window.innerHeight-n.offsetHeight,a=Math.max(0,Math.min(r.x,s)),i=Math.max(0,Math.min(r.y,o));n.style.right="auto",n.style.bottom="auto",n.style.left=`${a}px`,n.style.top=`${i}px`}catch(e){}}(We.integrateId,Xe),We.resizable){const e=d.resizeHandle;sn=function(e,n,t){let r=!1,s=0,o=0,a=0,i=0;const c=(e,t)=>{r=!0,s=e,o=t;const c=n.getBoundingClientRect();a=c.width,i=c.height,n.classList.add("csk-window--resizing"),document.addEventListener("mousemove",p),document.addEventListener("mouseup",u),document.addEventListener("touchmove",g,{passive:!1}),document.addEventListener("touchend",h)},l=(e,t,c)=>{if(!r)return;c&&c.preventDefault();const l=e-s,d=t-o,p=Math.max(300,Math.min(a+l,window.innerWidth-24)),u=Math.max(300,Math.min(i+d,window.innerHeight-24));n.style.width=`${p}px`,n.style.height=`${u}px`,n.style.setProperty("--csk-window-width",`${p}px`),n.style.setProperty("--csk-window-height",`${u}px`),n.style.bottom="",n.style.right=""},d=()=>{if(!r)return;r=!1,n.classList.remove("csk-window--resizing"),document.removeEventListener("mousemove",p),document.removeEventListener("mouseup",u),document.removeEventListener("touchmove",g),document.removeEventListener("touchend",h);const e=n.getBoundingClientRect();t&&t({width:e.width,height:e.height})};function p(e){l(e.clientX,e.clientY,e)}function u(){d()}function m(e){e.preventDefault(),e.stopPropagation(),c(e.clientX,e.clientY)}function k(e){e.preventDefault(),e.stopPropagation(),1===e.touches.length&&c(e.touches[0].clientX,e.touches[0].clientY)}function g(e){1===e.touches.length&&l(e.touches[0].clientX,e.touches[0].clientY,e)}function h(){d()}return e.addEventListener("mousedown",m),e.addEventListener("touchstart",k,{passive:!1}),()=>{e.removeEventListener("mousedown",m),e.removeEventListener("touchstart",k),document.removeEventListener("mousemove",p),document.removeEventListener("mouseup",u),document.removeEventListener("touchmove",g),document.removeEventListener("touchend",h)}}(e,Xe,e=>{!function(e,n){try{localStorage.setItem(wn(e),JSON.stringify(n))}catch(e){}}(We.integrateId,e)}),function(e,n){try{const t=localStorage.getItem(wn(e));if(!t)return;const r=JSON.parse(t);if("number"!=typeof r.width||"number"!=typeof r.height)return;const s=Math.max(300,Math.min(r.width,window.innerWidth-24)),o=Math.max(300,Math.min(r.height,window.innerHeight-24));n.style.width=`${s}px`,n.style.height=`${o}px`,n.style.setProperty("--csk-window-width",`${s}px`),n.style.setProperty("--csk-window-height",`${o}px`)}catch(e){}}(We.integrateId,Xe)}if(Ae(We,{messagesContainer:Ke,inputEl:Je,sendBtn:Ve,clearBtn:Ge,categorySelect:Qe,historyPanel:Ze,welcomeEl:d.welcomeEl,newMsgBtn:d.newMsgBtn,searchInput:d.searchInput,ariaLiveEl:d.ariaLiveEl,roleSelect:d.roleSelect,showLoading:en,hideLoading:nn}),Xe.addEventListener("csk:categoryChange",e=>{var n,t;n=e.detail.categoryId,ae=n,Se=null===(t=null==ie?void 0:ie.enableRag)||void 0===t||t}),Xe.addEventListener("csk:loadHistory",()=>{!async function(){if(!he||!ie)return;const e=he.querySelector("#csk-history-list");if(e){e.innerHTML='
@@ -97,6 +101,22 @@ public class ChatPipeline {
// RAG 检索(含 FAQ 优先匹配)
RagContext rag = ragPipeline.retrieve(ctx);
+
+ // 记录 RAG 检索日志到 rag_hit_log 表(供知识库分析看板使用)
+ if (!rag.faqHit() && rag.documents() != null && !rag.documents().isEmpty()) {
+ String searchMode = ctx.rewriteStrategy() != null ? ctx.rewriteStrategy() : "VECTOR";
+ for (Document doc : rag.documents()) {
+ String docIdStr = String.valueOf(doc.getMetadata().getOrDefault("documentId", ""));
+ Long documentId = null;
+ try { if (!docIdStr.isEmpty()) documentId = Long.parseLong(docIdStr); } catch (NumberFormatException ignored) { }
+ String title = String.valueOf(doc.getMetadata().getOrDefault("title", ""));
+ String score = String.valueOf(doc.getMetadata().getOrDefault("score", ""));
+ ragHitLogService.recordHit(ctx.chatId(), ctx.message(), documentId, title, score, searchMode);
+ }
+ } else if (!rag.faqHit()) {
+ String searchMode = ctx.rewriteStrategy() != null ? ctx.rewriteStrategy() : "VECTOR";
+ ragHitLogService.recordMiss(ctx.chatId(), ctx.message(), searchMode);
+ }
if (rag.faqHit()) {
return new ChatRequest(ctx, ctx.message(), baseSystem, rag.faqAnswer());
}
diff --git a/src/main/java/com/wok/supportbot/rag/RagPipeline.java b/src/main/java/com/wok/supportbot/rag/RagPipeline.java
index 0fb20c0..9af53e9 100644
--- a/src/main/java/com/wok/supportbot/rag/RagPipeline.java
+++ b/src/main/java/com/wok/supportbot/rag/RagPipeline.java
@@ -8,6 +8,7 @@ import com.wok.supportbot.rag.preretrieval.MultiQueryExpanderRewriter;
import com.wok.supportbot.rag.preretrieval.RewriteQueryRewriter;
import com.wok.supportbot.rag.preretrieval.TranslationQueryRewriter;
import com.wok.supportbot.service.FaqMatchEngine;
+import com.wok.supportbot.service.RagHitLogService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.messages.Message;
@@ -73,6 +74,9 @@ public class RagPipeline {
@Resource
private RagPromptConfig ragPromptConfig;
+ @Resource
+ private RagHitLogService ragHitLogService;
+
@Resource
private CategoryFilter categoryFilter;
@@ -141,6 +145,10 @@ public class RagPipeline {
rewrittenQuery = rewriteQuery(ctx.message(), ctx.chatId(), ctx.rewriteStrategy());
docs = similaritySearch(rewrittenQuery, ctx.categoryIds());
}
+
+ // RAG 命中日志:记录本次检索的命中/未命中情况
+ logRagHit(ctx.chatId(), ctx.message(), docs, rewrittenQuery);
+
String contextText = joinContext(docs);
return new RagContext(Optional.empty(), docs, contextText, rewrittenQuery);
}
@@ -274,4 +282,29 @@ public class RagPipeline {
.filter(StringUtils::hasText)
.collect(Collectors.joining("\n\n---\n\n"));
}
+
+ /**
+ * 异步记录 RAG 命中日志到 rag_hit_log 表。
+ * 有命中文档时逐条记录 hit,无命中时记录一条 miss。
+ */
+ private void logRagHit(String conversationId, String userQuery, List ${d(r[1])} ${l.join(" ${d(r[1])} ${l.join("
+ * 需要运行中的 PostgreSQL。
+ */
+@SpringBootTest
+@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
+@DisplayName("消息反馈功能集成测试")
+class MessageFeedbackTests {
+
+ @Resource
+ private MessageFeedbackService messageFeedbackService;
+
+ @Resource
+ private MessageFeedbackMapper messageFeedbackMapper;
+
+ private static final String TEST_MESSAGE_ID = "test_feedback_" + UUID.randomUUID().toString().substring(0, 8);
+ private static final String TEST_CONVERSATION_ID = "test_conv_" + UUID.randomUUID().toString().substring(0, 8);
+
+ // ==================== 提交与查询 ====================
+
+ @Test
+ @Order(1)
+ @DisplayName("F-01 新增反馈(点赞)应持久化到数据库")
+ void submitThumbsUp() {
+ MessageFeedback fb = MessageFeedback.builder()
+ .messageId(TEST_MESSAGE_ID)
+ .conversationId(TEST_CONVERSATION_ID)
+ .feedbackType("THUMBS_UP")
+ .build();
+ MessageFeedback saved = messageFeedbackService.submitFeedback(fb);
+ assertNotNull(saved);
+ assertNotNull(saved.getId());
+ assertEquals(TEST_MESSAGE_ID, saved.getMessageId());
+ assertEquals("THUMBS_UP", saved.getFeedbackType());
+ }
+
+ @Test
+ @Order(2)
+ @DisplayName("F-02 按 messageId 查询反馈")
+ void getByMessageId() {
+ MessageFeedback fb = messageFeedbackService.getByMessageId(TEST_MESSAGE_ID);
+ assertNotNull(fb);
+ assertEquals(TEST_MESSAGE_ID, fb.getMessageId());
+ assertEquals("THUMBS_UP", fb.getFeedbackType());
+ }
+
+ @Test
+ @Order(3)
+ @DisplayName("F-03 覆盖提交(upsert):点赞改为点踩")
+ void upsertFeedback() {
+ MessageFeedback fb = MessageFeedback.builder()
+ .messageId(TEST_MESSAGE_ID)
+ .conversationId(TEST_CONVERSATION_ID)
+ .feedbackType("THUMBS_DOWN")
+ .reasonCategory("inaccurate")
+ .reasonComment("答案有误")
+ .build();
+ MessageFeedback saved = messageFeedbackService.submitFeedback(fb);
+
+ // 验证覆盖后只有一条记录
+ MessageFeedback queried = messageFeedbackService.getByMessageId(TEST_MESSAGE_ID);
+ assertNotNull(queried);
+ assertEquals("THUMBS_DOWN", queried.getFeedbackType());
+ assertEquals("inaccurate", queried.getReasonCategory());
+ assertEquals("答案有误", queried.getReasonComment());
+
+ // 验证 upsert 逻辑:id 应与原始相同 (不是新插入)
+ assertEquals(queried.getId(), saved.getId());
+ }
+
+ // ==================== 批量查询 ====================
+
+ @Test
+ @Order(4)
+ @DisplayName("F-04 批量查询反馈(SDK 回显场景)")
+ void getBatchByMessageIds() {
+ // 插入一条额外反馈
+ String msg2 = "test_batch_" + UUID.randomUUID().toString().substring(0, 8);
+ messageFeedbackService.submitFeedback(MessageFeedback.builder()
+ .messageId(msg2)
+ .conversationId(TEST_CONVERSATION_ID)
+ .feedbackType("THUMBS_UP")
+ .build());
+
+ List
`),`${ee}${s}\0`});const r=[];t=t.replace(/`([^`\n]+)`/g,(e,n)=>{const t=r.length;return r.push(`${o}${M(n)}`),`${ne}${t}\0`}),t=M(t),t=re(t,ee,n),t=re(t,ne,r);const s=t.split("\n"),o=[];let a=!1,i="",c=!1,l=[];for(let e=0;e'),o.push("
"),t.forEach((e,t)=>{o.push(` "),e+=2;e${d(e)} `)}),o.push("${d(r[t]||"")} `)}),o.push(""),e++}o.push("')),o.push(`
"),c=!1)}}function re(e,n,t){return e.replace(new RegExp(n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")+"(\\d+)\0","g"),(e,n)=>t[parseInt(n)]||"")}let se,oe=null,ae=[],ie=null,ce=null,le=null,de=null,pe=null,ue=null,me=null,ge=null,he=null,ke=null,be=null,fe=null,ye=null,xe=null,ve=!1,we=null,_e=!0,Ee=[],Ce="",Le=!1;function Ie(e,n){oe=e,ie=n.messagesContainer,ce=n.inputEl,le=n.inputEl.parentElement,de=n.sendBtn,pe=n.clearBtn,ue=n.categorySelect,me=n.roleSelect,ge=n.historyPanel,he=n.welcomeEl,ke=n.newMsgBtn,be=n.searchInput,fe=n.ariaLiveEl,ye=n.showLoading,xe=n.hideLoading,se=e.categoryId,Le=e.enableRag,function(){if(!ce||!de)return;de.addEventListener("click",()=>{ve&&we?we.abort():Be()}),ce.addEventListener("keydown",e=>{"Enter"!==e.key||e.shiftKey||e.isComposing||(e.preventDefault(),Be())}),ce.addEventListener("input",()=>{Te(),function(){if(!ce)return;ce.style.height="auto",ce.style.height=`${Math.min(ce.scrollHeight,120)}px`}()}),ce.addEventListener("focus",()=>{le&&le.classList.add("csk-input-wrap--focus")}),ce.addEventListener("blur",()=>{le&&le.classList.remove("csk-input-wrap--focus")}),pe&&pe.addEventListener("click",()=>function(){if(!oe)return;if(ae=[],ie){ie.querySelectorAll(".csk-msg, .csk-loading").forEach(e=>e.remove())}pe&&(pe.style.display="none");De(),Z(oe.integrateId);const e=function(){const e="undefined"!=typeof crypto&&crypto.randomUUID?crypto.randomUUID().substring(0,8):Math.random().toString(36).substring(2,10);return`sdk_${Date.now()}_${e}`}();d(e),L(oe.integrateId,oe.userId,e),t.lifecycleClear(oe.integrateId)}())}(),function(){if(!ie)return;ie.addEventListener("scroll",()=>{if(!ie)return;const{scrollTop:e,scrollHeight:n,clientHeight:t}=ie;_e=n-e-t<80,_e&&$e()}),ke&&ke.addEventListener("click",()=>{ie&&V(ie),_e=!0,$e()})}(),function(){if(!be)return;be.addEventListener("input",()=>{Ce=be.value.trim().toLowerCase(),Fe()})}(),e.showCategorySwitch&&ue&&async function(){if(!ue)return;try{const e=await async function(){const e=u("/category/tree");try{const n=await g(e);if(!n.ok)throw new h(k(n.status),`http_${n.status}`);const r=await n.json();return r.success&&Array.isArray(r.data)?(t.info(`加载分类树成功 count=${r.data.length}`),r.data):[]}catch(e){return e instanceof h?t.error(`加载分类树失败: ${e.message}`):t.error("加载分类树失败",e),[]}}();if(0===e.length)return;ue.innerHTML=``;const n=(e,t=0)=>{for(const r of e){const e=document.createElement("option");e.value=String(r.id),e.textContent=`${" ".repeat(t)}${r.name}`,void 0!==se&&String(r.id)===String(se)&&(e.selected=!0),ue.appendChild(e),r.children&&r.children.length>0&&n(r.children,t+1)}};n(e),t.info(`知识库分类加载成功 count=${e.length}`)}catch(e){t.error(o("category_load_error"),e)}}()}async function Se(){if(oe&&ie&&(await E(),await Ae(),0===ae.length)){const e=function(e){try{const n=localStorage.getItem(G(e));if(!n)return[];const r=JSON.parse(n);return r&&Array.isArray(r.messages)?(t.info(`加载历史消息 integrateId=${e} count=${r.messages.length}`),r.messages):[]}catch(e){return[]}}(oe.integrateId);e.length>0&&(ae=e,je(),t.info(`从本地缓存恢复 ${e.length} 条消息`))}}async function Ae(){if(!oe||!ie)return;const e=p();if(e)try{const n=await v(e);n.messages.length>0&&(ae=n.messages.map((e,n)=>({id:N(),role:"USER"===e.messageType?"user":"ai",content:e.content,timestamp:new Date(e.createTime).getTime()})),je(),t.info(`从后端加载 ${ae.length} 条历史消息`),Q(l(),ae))}catch(e){}}function $e(){ke&&ke.classList.add("csk-newmsg--hidden")}function Ne(){ie&&(_e?V(ie):ke&&ke.classList.remove("csk-newmsg--hidden"))}function Me(e){de&&("stop"===e?(de.classList.add("csk-send-btn--stop"),de.removeAttribute("disabled"),de.setAttribute("title",o("stop")),de.setAttribute("aria-label",o("stop")),de.innerHTML=''):(de.classList.remove("csk-send-btn--stop"),de.setAttribute("title",o("send")),de.setAttribute("aria-label",o("send")),de.innerHTML='',Te()))}function Fe(){const e=null==ge?void 0:ge.querySelector("#csk-history-list");if(!e||!oe)return;K(e,Ce?Ee.filter(e=>(e.lastMessagePreview||e.chatId||e.id||"").toLowerCase().includes(Ce)):Ee,e=>{Re(e)},e=>{window.open(_(e),"_blank")},async e=>{if(!confirm(o("history_delete_confirm")))return;await w(e)&&(e===p()&&(ae=[],ie&&ie.querySelectorAll(".csk-msg, .csk-loading").forEach(e=>e.remove()),pe&&(pe.style.display="none"),De()),Ee=Ee.filter(n=>(n.chatId||n.id)!==e),Fe())},p())}function ze(e,n){if(!ie)return;const r=ae.find(n=>n.id===e&&"ai"===n.role);if(!r)return;const s=r.feedback===n?void 0:n;r.feedback=s;const o=ie.querySelector(`[data-csk-msg-id="${e}"]`);if(o&&W(o,s),oe&&Q(oe.integrateId,ae),s){const n="up"===s?"THUMBS_UP":"THUMBS_DOWN";(async function(e,n){if(!a)return!1;const r=u("/feedback");try{const s=await g(r,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({messageId:String(e),conversationId:a.chatId,feedbackType:n})});return s.ok?(await s.json()).success||!1:(t.error(`反馈提交失败 status=${s.status}`),!1)}catch(e){return t.error("反馈提交异常",e),!1}})(String(e),n).then(e=>{})}}function De(){if(!he)return;const e=ae.length>0||ie&&ie.querySelector(".csk-msg");he.style.display=e?"none":""}function Te(){if(!de||!ce)return;ce.value.trim().length>0&&!ve?de.removeAttribute("disabled"):de.setAttribute("disabled","true")}async function Be(){if(!ce||!oe||ve)return;const e=ce.value.trim();if(""===e)return;ce.value="",Te(),ce.style.height="auto";const n=z(),t={id:N(),role:"user",content:e,timestamp:n};ie&&q(ie,e,n),ae.push(t),De(),pe&&ae.length>0&&(pe.style.display="inline-flex"),ie&&Ne(),await He(e)}async function He(e){if(!oe||!ie)return;ve=!0,Me("stop"),oe.chatId||await E();const n=z(),r=Le;ye&&ye(),ie&&Ne();const s=N();let i="";try{oe.streaming?i=await async function(e,n,t,r){we=new AbortController;const s=we.signal;return new Promise((a,i)=>{let c=null,l=null,d="",p=!1;f(e,e=>{if(d+=e,!p&&ie){xe&&xe();const{wrapper:e,bubble:t}=function(e,n,t){const r=document.createElement("div");r.className="csk-msg csk-msg--ai csk-msg--streaming",t&&(r.dataset.cskMsgId=t);const s=document.createElement("div");s.className="csk-msg__avatar csk-msg__avatar--ai",s.innerHTML=D;const o=document.createElement("div");o.className="csk-msg__content";const a=document.createElement("div");a.className="csk-msg__bubble",a.innerHTML="";const i=document.createElement("div");i.className="csk-msg__time",i.textContent=F(n),o.appendChild(a);const c=document.createElement("div");return c.className="csk-msg__meta",c.appendChild(i),c.appendChild(U(a,r)),o.appendChild(c),r.appendChild(s),r.appendChild(o),e.appendChild(r),{wrapper:r,bubble:a}}(ie,n,r);l=e,c=t,p=!0}c&&(c.innerHTML=te(d),function(e){if(e.querySelector(".csk-caret"))return;const n=document.createElement("span");n.className="csk-caret",n.setAttribute("aria-hidden","true"),e.appendChild(n)}(c)),ie&&Ne()},()=>{if(l&&c){if(!p&&""===d)return void b(e).then(a).catch(i);d&&(c.innerHTML=te(d)),X(l,c)}a(d)},e=>{"network"!==e.type&&"cors"!==e.type||ie&&function(e){if(document.getElementById("csk-offline-banner"))return;const n=document.createElement("div");n.id="csk-offline-banner",n.className="csk-offline-banner",n.textContent=o("error_offline"),e.insertBefore(n,e.firstChild)}(ie),d.length>0?(c&&(c.innerHTML=te(d+"\n\n"+o("stream_interrupted")),l&&X(l,c)),a(d)):i(e)},se,t,s)})}(e,n,r,s):(i=await b(e),xe&&xe(),ie&&j(ie,i,n,te,s));const t={id:s,role:"ai",content:i,timestamp:n};ae.push(t),Q(oe.integrateId,ae),ie&&Ne(),function(e){if(!fe)return;const n=e.length>120?e.substring(0,120)+"...":e;fe.textContent=o("new_msg_announce")+":"+n}(i),ie&&ie.dispatchEvent(new CustomEvent("csk:newMessage",{bubbles:!0,detail:{msg:t}})),r&&async function(e,n){try{const t=await y(e,se);if(t.length>0){const e=t.map(e=>{var n,t;return{documentId:e.documentId||"",title:e.title||"",sourceName:e.sourceName||"",chunkIndex:null!==(n=e.chunkIndex)&&void 0!==n?n:0,score:null!==(t=e.score)&&void 0!==t?t:0,snippet:e.snippet||""}});if(n.sources=e,ie){const n=ie.querySelector(".csk-msg--ai:last-of-type");n&&J(n,e)}oe&&Q(oe.integrateId,ae)}}catch(e){}}(e,t),oe.suggestions&&async function(e){const n=p();if(!n||!ie)return;try{const t=await async function(e){if(!a||!e)return[];try{const n=new URLSearchParams;n.set("chatId",e);const t=u(`/ai/suggestions?${n.toString()}`),r=await g(t);if(!r.ok)return[];const s=await r.json();return s.success&&s.data&&Array.isArray(s.data.suggestions)?s.data.suggestions.filter(e=>"string"==typeof e&&e.trim().length>0):[]}catch(e){return[]}}(n);if(t.length>0&&ie){const n=ie.querySelector(`[data-csk-msg-id="${e}"]`);n&&function(e,n,t){if(function(e){const n=e.querySelector(".csk-suggestions");n&&n.remove()}(e),!n||0===n.length)return;const r=document.createElement("div");r.className="csk-suggestions";const s=document.createElement("div");s.className="csk-suggestions__list";for(const e of n){const n=document.createElement("button");n.type="button",n.className="csk-suggestion-item",n.textContent=e,n.addEventListener("click",n=>{n.stopPropagation(),t(e)}),s.appendChild(n)}r.appendChild(s);const o=e.querySelector(".csk-msg__content");o?o.appendChild(r):e.appendChild(r)}(n,t,qe)}}catch(e){}}(s),function(){const e=document.getElementById("csk-offline-banner");e&&e.remove()}()}catch(e){xe&&xe();const n=e instanceof h?e.message:o("error_send");if(ie){const e=document.createElement("div");e.className="csk-msg csk-msg--ai";const t=document.createElement("div");t.className="csk-msg__bubble",t.style.color="#DC2626",t.textContent=`⚠ ${n}`,e.appendChild(t),ie.appendChild(e)}t.error(`发送失败 integrateId=${oe.integrateId}`,e)}finally{ve=!1,we=null,Me("send"),Te()}}function qe(e){return!ce||ve?Promise.resolve():(ce.value=e,Te(),Be())}function je(){if(!ie)return;const e=ie.querySelector(".csk-history-panel");ie.querySelectorAll(".csk-msg, .csk-loading").forEach(e=>e.remove());for(const e of ae)if("user"===e.role)q(ie,e.content,e.timestamp);else{const n=j(ie,e.content,e.timestamp,te,e.id);e.sources&&e.sources.length>0&&J(n,e.sources),e.feedback&&W(n,e.feedback)}_e=!0,V(ie),pe&&ae.length>0&&(pe.style.display="inline-flex"),De(),e&&!ie.contains(e)&&ie.appendChild(e)}async function Re(e){if(!oe||!ie)return;const n=Ee.find(n=>(n.chatId||n.id)===e);if(n&&void 0!==n.roleId){const e=String(n.roleId),t=l();e&&e!==t&&(c(e),me&&(me.value=e))}d(e),L(l(),oe.userId,e),ge&&ge.classList.add("csk-history-panel--hidden"),ae=[];ie.querySelectorAll(".csk-msg, .csk-loading").forEach(e=>e.remove());try{const n=await v(e);n.messages.length>0&&(ae=n.messages.map(e=>({id:N(),role:"USER"===e.messageType?"user":"ai",content:e.content,timestamp:new Date(e.createTime).getTime()})),je(),t.info(`加载会话 ${e} 的 ${ae.length} 条消息`),Q(oe.integrateId,ae))}catch(e){}pe&&ae.length>0&&(pe.style.display="inline-flex"),De()}let Pe=null,Ue=!1,We=null,Ye=null,Oe=null,Xe=null,Je=null,Ke=null,Ve=null,Ge=null,Qe=null,Ze=null,en=null,nn=null,tn=null,rn=null,sn=null,on=null,an=null,cn=null,ln=null;function dn(){if(!sn||!We)return;const e=We.getBoundingClientRect(),n=rn?"left"===rn.side:"left-bottom"===(null==Pe?void 0:Pe.position);n?(sn.style.left=`${e.left}px`,sn.style.right="auto"):(sn.style.right=window.innerWidth-e.right+"px",sn.style.left="auto"),sn.style.bottom=window.innerHeight-e.top+8+"px",sn.classList.toggle("csk-teaser--left",!!n),sn.classList.toggle("csk-teaser--right",!n)}function pn(){if(!sn)return;sn.classList.add("csk-teaser--hidden"),sn.removeEventListener("click",un);const e=sn.querySelector(".csk-teaser__close");e&&e.removeEventListener("click",mn)}function un(e){e.target.closest(".csk-teaser__close")||(pn(),bn())}function mn(e){e.stopPropagation(),pn()}function gn(){sn&&!sn.classList.contains("csk-teaser--hidden")&&dn()}const hn='button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';function kn(e){"Escape"===e.key&&Ye&&!Ye.classList.contains("csk-window--hidden")&&fn(),function(e){if(!Ye||Ye.classList.contains("csk-window--hidden"))return;if("Tab"!==e.key)return;const n=Array.from(Ye.querySelectorAll(hn));if(0===n.length)return;const t=n[0],r=n[n.length-1];e.shiftKey?document.activeElement===t&&(e.preventDefault(),r.focus()):document.activeElement===r&&(e.preventDefault(),t.focus())}(e)}function bn(){Ye&&(Ye.classList.remove("csk-window--hidden"),pn(),an&&an.classList.add("csk-launcher__badge--hidden"),setTimeout(()=>{Xe&&Xe.focus()},80))}function fn(){Ye&&Ye.classList.add("csk-window--hidden")}function yn(){Ye&&(Ye.classList.contains("csk-window--hidden")?bn():fn())}function xn(e){return`csk_size_${e}`}function vn(e){return`csk_position_${e}`}function wn(e){return`csk_launcher_pos_${e}`}function _n(e){Ye&&(Ye.classList.remove("csk-window--right","csk-window--left"),Ye.classList.add(`csk-window--${e}`),sn&&(sn.classList.remove("csk-teaser--right","csk-teaser--left"),sn.classList.add(`csk-teaser--${e}`)))}const En={init:function(e){if(Ue)return;const i=function(e){var n,r,s,o,a,i,c,l,d,p,u,m,g;if(!e.integrateId||"string"!=typeof e.integrateId&&"number"!=typeof e.integrateId||"string"==typeof e.integrateId&&""===e.integrateId.trim())return t.error('integrateId 是必传参数(对应后端 roleId 客服角色 ID),请检查 init() 调用。示例:ChatbotSDK.init({ integrateId: 1, requestDomain: "https://api.example.com" })'),null;if(!e.requestDomain||"string"!=typeof e.requestDomain||""===e.requestDomain.trim())return t.error('requestDomain 是必传参数,请检查 init() 调用。示例:ChatbotSDK.init({ integrateId: 1, requestDomain: "https://api.example.com" })'),null;try{new URL(e.requestDomain)}catch(n){return t.error(`requestDomain 不是合法的 URL 格式:${e.requestDomain}。请提供完整的域名,如 https://api.example.com`),null}const h=String(e.integrateId).trim(),k=e.requestDomain.replace(/\/+$/,""),b=e.launcherIcon||`')),o.push(`
":""),a=!1,i="")}function f(){c&&(o.push("')),o.push(`
')):(b(),f(),l.push(d(n))):(k(),b())}return k(),b(),f(),o.join("\n");function d(e){return e=(e=(e=(e=(e=(e=e.replace(/\*\*(.+?)\*\*/g,"$1")).replace(/__(.+?)__/g,"$1")).replace(/\*(.+?)\*/g,"$1")).replace(/(?$1")).replace(/~~(.+?)~~/g,"$1")).replace(/\[([^\]]+)\]\(([^)]+)\)/g,(e,n,t)=>`${n}`)}function p(e){const n=m(e);return n.length>0&&n.every(e=>/^:?-{3,}:?$/.test(e.trim()))}function u(e){return""!==e.trim()&&e.includes("|")}function m(e){const n=e.trim().replace(/^\|/,"").replace(/\|$/,"");if(!n.includes("|"))return[];const t=[];let r="";for(let e=0;e
")}
`,f=e.primaryColor||"#4F46E5",y={integrateId:h,requestDomain:e.requestDomain.replace(/\/+$/,""),userId:e.userId,categoryId:e.categoryId,showCategorySwitch:null!==(n=e.showCategorySwitch)&&void 0!==n&&n,title:e.title||"AI 智能助手",width:null!==(r=e.width)&&void 0!==r?r:500,height:Math.max(400,null!==(s=e.height)&&void 0!==s?s:520),position:"left-bottom"===e.position?"left-bottom":"right-bottom",primaryColor:f,launcherIcon:b,showClear:null===(o=e.showClear)||void 0===o||o,showAdminPanel:null!==(a=e.showAdminPanel)&&void 0!==a&&a,quickReplies:Array.isArray(e.quickReplies)?e.quickReplies.map(e=>String(e).trim()).filter(Boolean):[],suggestions:null===(i=e.suggestions)||void 0===i||i,theme:"dark"===e.theme?"dark":"light",showTeaser:null===(c=e.showTeaser)||void 0===c||c,teaserText:"string"==typeof e.teaserText&&e.teaserText.trim()||"",resizable:null===(l=e.resizable)||void 0===l||l,watermark:"string"==typeof e.watermark&&e.watermark.trim()||void 0,streaming:null===(d=e.streaming)||void 0===d||d,enableRag:null===(p=e.enableRag)||void 0===p||p,rewriteStrategy:e.rewriteStrategy||"REWRITE",locale:e.locale||"zh-CN",debug:null===(u=e.debug)||void 0===u||u,sound:null!==(m=e.sound)&&void 0!==m&&m,notification:null!==(g=e.notification)&&void 0!==g&&g,onError:"function"==typeof e.onError?e.onError:void 0,onReady:"function"==typeof e.onReady?e.onReady:void 0,onMessage:"function"==typeof e.onMessage?e.onMessage:void 0,token:e.token,roles:e.roles,disclaimer:e.disclaimer,chatId:""};return t.info(`配置解析完成 integrateId(=roleId)=${y.integrateId} userId(=accountId)=${y.userId||"(未设置)"} requestDomain=${y.requestDomain}`),y}(e);if(!i)return;Pe=i,function(e){if(r[e])s=e;else{const n=e.split("-")[0],t=Object.keys(r).find(e=>e.startsWith(n));t&&(s=t)}}(Pe.locale),Pe.debug,n(Pe.onError),function(e){a=e}(Pe),$(Pe),We=T(Pe,yn),document.body.appendChild(We),an=We.querySelector(".csk-launcher__badge"),function(e,n){try{const t=localStorage.getItem(wn(e));if(!t)return;const r=JSON.parse(t);if("left"!==r.side&&"right"!==r.side||"number"!=typeof r.bottom)return;const s=window.innerHeight-76,o=Math.max(16,Math.min(r.bottom,s));n.classList.remove("csk-launcher--right","csk-launcher--left"),n.classList.add(`csk-launcher--${r.side}`),n.style.bottom=`${o}px`,rn={side:r.side,bottom:o}}catch(e){}}(Pe.integrateId,We),nn=function(e,n,t){let r=!1,s=0,o=0,a=!1,i=0,c=0,l=0,d=!1;function p(){const n=parseFloat(getComputedStyle(e).bottom);return isNaN(n)?24:n}function u(n,t){if(d)return;r=!0,a=!1,s=n,o=t,i=p();const u=e.style,m=getComputedStyle(e);c=u.right?parseFloat(u.right):parseFloat(m.right),l=u.left?parseFloat(u.left):parseFloat(m.left)}function m(n,t,d){if(!r)return;const p=n-s,u=t-o;if(!a){if(Math.abs(p)<5&&Math.abs(u)<5)return;a=!0,e.classList.add("csk-launcher--dragging"),e.classList.remove("csk-launcher--right","csk-launcher--left"),e.style.transition="none",!isNaN(c)&&c>=0&&isNaN(l)?(e.style.right=`${c}px`,e.style.left="auto"):!isNaN(l)&&l>=0&&(e.style.left=`${l}px`,e.style.right="auto")}if(a){d.preventDefault();const n=Math.max(16,Math.min(i-u,H()));e.style.bottom=`${n}px`}}function g(){if(!r)return;if(r=!1,!a)return;const n=parseFloat(e.style.bottom)||p(),s=Math.max(16,Math.min(n,H())),o=e.getBoundingClientRect(),i=o.left+o.width/2<=window.innerWidth/2?"left":"right";e.classList.remove("csk-launcher--dragging"),e.classList.add(`csk-launcher--${i}`,"csk-launcher--snap"),e.style.left="",e.style.right="",e.style.bottom=`${s}px`,d=!0;const c=()=>{e.removeEventListener("transitionend",c),e.classList.remove("csk-launcher--snap"),e.style.transition="",d=!1};e.addEventListener("transitionend",c),setTimeout(()=>{d&&c()},350);const l=n=>{n.stopPropagation(),e.removeEventListener("click",l,!0)};e.addEventListener("click",l,!0);const u=e.querySelector(".csk-launcher__badge");u&&(u.style.display=""),t&&t({side:i,bottom:s})}function h(e){u(e.clientX,e.clientY)}function k(e){m(e.clientX,e.clientY,e)}function b(){g()}function f(e){1===e.touches.length&&u(e.touches[0].clientX,e.touches[0].clientY)}function y(e){1===e.touches.length&&m(e.touches[0].clientX,e.touches[0].clientY,e)}function x(){g()}return e.addEventListener("mousedown",h),document.addEventListener("mousemove",k),document.addEventListener("mouseup",b),e.addEventListener("touchstart",f,{passive:!0}),document.addEventListener("touchmove",y,{passive:!1}),document.addEventListener("touchend",x),()=>{e.removeEventListener("mousedown",h),document.removeEventListener("mousemove",k),document.removeEventListener("mouseup",b),e.removeEventListener("touchstart",f),document.removeEventListener("touchmove",y),document.removeEventListener("touchend",x)}}(We,0,e=>{const n=null==rn?void 0:rn.side;rn=e,function(e,n){try{localStorage.setItem(wn(e),JSON.stringify(n))}catch(e){}}(Pe.integrateId,e),n&&n!==e.side&&function(){if(!Ye)return;Ye.style.left="",Ye.style.top="",Ye.style.right="",Ye.style.bottom=""}(),_n(e.side),sn&&!sn.classList.contains("csk-teaser--hidden")&&dn()}),rn&&_n(rn.side);const d=B(Pe);Ye=d.window,Oe=d.messagesContainer,Xe=d.inputEl,Je=d.sendBtn,Ke=d.clearBtn,Ve=d.categorySelect,Ge=d.historyPanel,Qe=d.showLoading,Ze=d.hideLoading,ln=d.disclaimer,document.body.appendChild(Ye),sn=d.teaserEl,document.body.appendChild(sn),dn();const m=Ye.querySelector(".csk-header");if(m&&(en=function(e,n,t){let r=!1,s=0,o=0,a=0,i=0;const c=e=>{if(e.target.closest("button"))return;r=!0,s=e.clientX,o=e.clientY;const t=n.getBoundingClientRect();a=s-t.left,i=o-t.top,document.addEventListener("mousemove",l),document.addEventListener("mouseup",d)},l=e=>{if(!r)return;const t=e.clientX-a,s=e.clientY-i,o=window.innerWidth-n.offsetWidth,c=window.innerHeight-n.offsetHeight;n.style.right="auto",n.style.bottom="auto",n.style.left=`${Math.max(0,Math.min(t,o))}px`,n.style.top=`${Math.max(0,Math.min(s,c))}px`},d=()=>{if(r=!1,document.removeEventListener("mousemove",l),document.removeEventListener("mouseup",d),t){const e=n.getBoundingClientRect();t({x:e.left,y:e.top})}};return e.addEventListener("mousedown",c),()=>{e.removeEventListener("mousedown",c),document.removeEventListener("mousemove",l),document.removeEventListener("mouseup",d)}}(m,Ye,e=>{!function(e,n){try{localStorage.setItem(vn(e),JSON.stringify(n))}catch(e){}}(Pe.integrateId,e)})),function(e,n){try{const t=localStorage.getItem(vn(e));if(!t)return;const r=JSON.parse(t);if("number"!=typeof r.x||"number"!=typeof r.y)return;const s=window.innerWidth-n.offsetWidth,o=window.innerHeight-n.offsetHeight,a=Math.max(0,Math.min(r.x,s)),i=Math.max(0,Math.min(r.y,o));n.style.right="auto",n.style.bottom="auto",n.style.left=`${a}px`,n.style.top=`${i}px`}catch(e){}}(Pe.integrateId,Ye),Pe.resizable){const e=d.resizeHandle;tn=function(e,n,t){let r=!1,s=0,o=0,a=0,i=0;const c=(e,t)=>{r=!0,s=e,o=t;const c=n.getBoundingClientRect();a=c.width,i=c.height,n.classList.add("csk-window--resizing"),document.addEventListener("mousemove",p),document.addEventListener("mouseup",u),document.addEventListener("touchmove",h,{passive:!1}),document.addEventListener("touchend",k)},l=(e,t,c)=>{if(!r)return;c&&c.preventDefault();const l=e-s,d=t-o,p=Math.max(300,Math.min(a+l,window.innerWidth-24)),u=Math.max(300,Math.min(i+d,window.innerHeight-24));n.style.width=`${p}px`,n.style.height=`${u}px`,n.style.setProperty("--csk-window-width",`${p}px`),n.style.setProperty("--csk-window-height",`${u}px`),n.style.bottom="",n.style.right=""},d=()=>{if(!r)return;r=!1,n.classList.remove("csk-window--resizing"),document.removeEventListener("mousemove",p),document.removeEventListener("mouseup",u),document.removeEventListener("touchmove",h),document.removeEventListener("touchend",k);const e=n.getBoundingClientRect();t&&t({width:e.width,height:e.height})};function p(e){l(e.clientX,e.clientY,e)}function u(){d()}function m(e){e.preventDefault(),e.stopPropagation(),c(e.clientX,e.clientY)}function g(e){e.preventDefault(),e.stopPropagation(),1===e.touches.length&&c(e.touches[0].clientX,e.touches[0].clientY)}function h(e){1===e.touches.length&&l(e.touches[0].clientX,e.touches[0].clientY,e)}function k(){d()}return e.addEventListener("mousedown",m),e.addEventListener("touchstart",g,{passive:!1}),()=>{e.removeEventListener("mousedown",m),e.removeEventListener("touchstart",g),document.removeEventListener("mousemove",p),document.removeEventListener("mouseup",u),document.removeEventListener("touchmove",h),document.removeEventListener("touchend",k)}}(e,Ye,e=>{!function(e,n){try{localStorage.setItem(xn(e),JSON.stringify(n))}catch(e){}}(Pe.integrateId,e)}),function(e,n){try{const t=localStorage.getItem(xn(e));if(!t)return;const r=JSON.parse(t);if("number"!=typeof r.width||"number"!=typeof r.height)return;const s=Math.max(300,Math.min(r.width,window.innerWidth-24)),o=Math.max(300,Math.min(r.height,window.innerHeight-24));n.style.width=`${s}px`,n.style.height=`${o}px`,n.style.setProperty("--csk-window-width",`${s}px`),n.style.setProperty("--csk-window-height",`${o}px`)}catch(e){}}(Pe.integrateId,Ye)}if(Ie(Pe,{messagesContainer:Oe,inputEl:Xe,sendBtn:Je,clearBtn:Ke,categorySelect:Ve,historyPanel:Ge,welcomeEl:d.welcomeEl,newMsgBtn:d.newMsgBtn,searchInput:d.searchInput,ariaLiveEl:d.ariaLiveEl,roleSelect:d.roleSelect,showLoading:Qe,hideLoading:Ze}),Ye.addEventListener("csk:categoryChange",e=>{var n,t;n=e.detail.categoryId,se=n,Le=null===(t=null==oe?void 0:oe.enableRag)||void 0===t||t}),Ye.addEventListener("csk:loadHistory",()=>{!async function(){if(!ge||!oe)return;const e=ge.querySelector("#csk-history-list");if(e){e.innerHTML='
`),`${te}${s}\0`});const r=[];t=t.replace(/`([^`\n]+)`/g,(e,n)=>{const t=r.length;return r.push(`${o}${F(n)}`),`${re}${t}\0`}),t=F(t),t=oe(t,te,n),t=oe(t,re,r);const s=t.split("\n"),o=[];let a=!1,i="",c=!1,l=[];for(let e=0;e'),o.push("
"),t.forEach((e,t)=>{o.push(` "),e+=2;e${d(e)} `)}),o.push("${d(r[t]||"")} `)}),o.push(""),e++}o.push("')),o.push(`
"),c=!1)}}function oe(e,n,t){return e.replace(new RegExp(n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")+"(\\d+)\0","g"),(e,n)=>t[parseInt(n)]||"")}let ae,ie=null,ce=[],le=null,de=null,pe=null,ue=null,me=null,ke=null,ge=null,he=null,be=null,fe=null,ye=null,ve=null,xe=null,we=null,_e=!1,Ee=null,Ce=!0,Le=[],Ie="",Se=!1;function Ae(e,n){ie=e,le=n.messagesContainer,de=n.inputEl,pe=n.inputEl.parentElement,ue=n.sendBtn,me=n.clearBtn,ke=n.categorySelect,ge=n.roleSelect,he=n.historyPanel,be=n.welcomeEl,fe=n.newMsgBtn,ye=n.searchInput,ve=n.ariaLiveEl,xe=n.showLoading,we=n.hideLoading,ae=e.categoryId,Se=e.enableRag,function(){if(!de||!ue)return;ue.addEventListener("click",()=>{_e&&Ee?Ee.abort():He()}),de.addEventListener("keydown",e=>{"Enter"!==e.key||e.shiftKey||e.isComposing||(e.preventDefault(),He())}),de.addEventListener("input",()=>{qe(),function(){if(!de)return;de.style.height="auto",de.style.height=`${Math.min(de.scrollHeight,120)}px`}()}),de.addEventListener("focus",()=>{pe&&pe.classList.add("csk-input-wrap--focus")}),de.addEventListener("blur",()=>{pe&&pe.classList.remove("csk-input-wrap--focus")}),me&&me.addEventListener("click",()=>function(){if(!ie)return;if(ce=[],le){le.querySelectorAll(".csk-msg, .csk-loading").forEach(e=>e.remove())}me&&(me.style.display="none");Be(),ne(ie.integrateId);const e=function(){const e="undefined"!=typeof crypto&&crypto.randomUUID?crypto.randomUUID().substring(0,8):Math.random().toString(36).substring(2,10);return`sdk_${Date.now()}_${e}`}();d(e),I(ie.integrateId,ie.userId,e),t.lifecycleClear(ie.integrateId)}())}(),function(){if(!le)return;le.addEventListener("scroll",()=>{if(!le)return;const{scrollTop:e,scrollHeight:n,clientHeight:t}=le;Ce=n-e-t<80,Ce&&Me()}),fe&&fe.addEventListener("click",()=>{le&&G(le),Ce=!0,Me()})}(),function(){if(!ye)return;ye.addEventListener("input",()=>{Ie=ye.value.trim().toLowerCase(),De()})}(),e.showCategorySwitch&&ke&&async function(){if(!ke)return;try{const e=await async function(){const e=u("/category/tree");try{const n=await k(e);if(!n.ok)throw new g(h(n.status),`http_${n.status}`);const r=await n.json();return r.success&&Array.isArray(r.data)?(t.info(`加载分类树成功 count=${r.data.length}`),r.data):[]}catch(e){return e instanceof g?t.error(`加载分类树失败: ${e.message}`):t.error("加载分类树失败",e),[]}}();if(0===e.length)return;ke.innerHTML=``;const n=(e,t=0)=>{for(const r of e){const e=document.createElement("option");e.value=String(r.id),e.textContent=`${" ".repeat(t)}${r.name}`,void 0!==ae&&String(r.id)===String(ae)&&(e.selected=!0),ke.appendChild(e),r.children&&r.children.length>0&&n(r.children,t+1)}};n(e),t.info(`知识库分类加载成功 count=${e.length}`)}catch(e){t.error(o("category_load_error"),e)}}()}async function $e(){if(ie&&le&&(await C(),await Ne(),0===ce.length)){const e=function(e){try{const n=localStorage.getItem(Z(e));if(!n)return[];const r=JSON.parse(n);return r&&Array.isArray(r.messages)?(t.info(`加载历史消息 integrateId=${e} count=${r.messages.length}`),r.messages):[]}catch(e){return[]}}(ie.integrateId);e.length>0&&(ce=e,Pe(),t.info(`从本地缓存恢复 ${e.length} 条消息`))}}async function Ne(){if(!ie||!le)return;const e=p();if(e)try{const n=await w(e);n.messages.length>0&&(ce=n.messages.map((e,n)=>({id:M(),role:"USER"===e.messageType?"user":"ai",content:e.content,timestamp:new Date(e.createTime).getTime()})),Pe(),t.info(`从后端加载 ${ce.length} 条历史消息`),ee(l(),ce))}catch(e){}}function Me(){fe&&fe.classList.add("csk-newmsg--hidden")}function Fe(){le&&(Ce?G(le):fe&&fe.classList.remove("csk-newmsg--hidden"))}function ze(e){ue&&("stop"===e?(ue.classList.add("csk-send-btn--stop"),ue.removeAttribute("disabled"),ue.setAttribute("title",o("stop")),ue.setAttribute("aria-label",o("stop")),ue.innerHTML=''):(ue.classList.remove("csk-send-btn--stop"),ue.setAttribute("title",o("send")),ue.setAttribute("aria-label",o("send")),ue.innerHTML='',qe()))}function De(){const e=null==he?void 0:he.querySelector("#csk-history-list");if(!e||!ie)return;V(e,Ie?Le.filter(e=>(e.lastMessagePreview||e.chatId||e.id||"").toLowerCase().includes(Ie)):Le,e=>{Ue(e)},e=>{window.open(E(e),"_blank")},async e=>{if(!confirm(o("history_delete_confirm")))return;await _(e)&&(e===p()&&(ce=[],le&&le.querySelectorAll(".csk-msg, .csk-loading").forEach(e=>e.remove()),me&&(me.style.display="none"),Be()),Le=Le.filter(n=>(n.chatId||n.id)!==e),De())},p())}function Te(e,n){if(!le)return;const t=ce.find(n=>n.id===e&&"ai"===n.role);if(t){if("up"===n){const n="up"===t.feedback?void 0:"up";t.feedback=n,t.feedbackReason=void 0,t.feedbackComment=void 0;const r=le.querySelector(`[data-csk-msg-id="${e}"]`);return r&&Y(r,n),ie&&ee(ie.integrateId,ce),void(n&&v(String(e),"THUMBS_UP").then(e=>{}))}if("down"===n){const n=le.querySelector(`[data-csk-msg-id="${e}"]`);if(!n)return;if("down"===t.feedback)return t.feedback=void 0,t.feedbackReason=void 0,t.feedbackComment=void 0,n&&Y(n,void 0),void(ie&&ee(ie.integrateId,ce));!function(e,n,t){const r=e.querySelector(".csk-feedback-reason");r&&r.remove();const s=document.createElement("div");s.className="csk-feedback-reason";const a=document.createElement("div");a.className="csk-feedback-reason__title",a.textContent=o("feedback_reason_title"),s.appendChild(a);const i=document.createElement("div");i.className="csk-feedback-reason__options",Q.forEach(e=>{const n=document.createElement("button");n.type="button",n.className="csk-feedback-reason__btn",n.textContent=o(e.labelKey),n.addEventListener("click",n=>{n.stopPropagation(),t(e.key),s.remove()}),i.appendChild(n)}),s.appendChild(i);const c=document.createElement("div");c.className="csk-feedback-reason__comment-row";const l=document.createElement("input");l.type="text",l.className="csk-feedback-reason__comment",l.placeholder=o("feedback_reason_comment_placeholder"),l.maxLength=200,c.appendChild(l);const d=document.createElement("button");d.type="button",d.className="csk-feedback-reason__submit",d.textContent=o("feedback_reason_submit"),d.addEventListener("click",e=>{e.stopPropagation();const n=l.value.trim()||void 0;t("other",n),s.remove()}),c.appendChild(d),s.appendChild(c);const p=document.createElement("button");p.type="button",p.className="csk-feedback-reason__close",p.setAttribute("aria-label",o("close")),p.innerHTML='',p.addEventListener("click",e=>{e.stopPropagation(),s.remove()}),s.appendChild(p),e.appendChild(s)}(n,0,(r,s)=>{t.feedback="down",t.feedbackReason=r,t.feedbackComment=s,n&&Y(n,"down"),ie&&ee(ie.integrateId,ce),v(String(e),"THUMBS_DOWN",r,s).then(e=>{})})}}}function Be(){if(!be)return;const e=ce.length>0||le&&le.querySelector(".csk-msg");be.style.display=e?"none":""}function qe(){if(!ue||!de)return;de.value.trim().length>0&&!_e?ue.removeAttribute("disabled"):ue.setAttribute("disabled","true")}async function He(){if(!de||!ie||_e)return;const e=de.value.trim();if(""===e)return;de.value="",qe(),de.style.height="auto";const n=D(),t={id:M(),role:"user",content:e,timestamp:n};le&&j(le,e,n),ce.push(t),Be(),me&&ce.length>0&&(me.style.display="inline-flex"),le&&Fe(),await je(e)}async function je(e){if(!ie||!le)return;_e=!0,ze("stop"),ie.chatId||await C();const n=D(),r=Se;xe&&xe(),le&&Fe();const s=M();let i="";try{ie.streaming?i=await async function(e,n,t,r){Ee=new AbortController;const s=Ee.signal;return new Promise((a,i)=>{let c=null,l=null,d="",p=!1;f(e,e=>{if(d+=e,!p&&le){we&&we();const{wrapper:e,bubble:t}=function(e,n,t){const r=document.createElement("div");r.className="csk-msg csk-msg--ai csk-msg--streaming",t&&(r.dataset.cskMsgId=t);const s=document.createElement("div");s.className="csk-msg__avatar csk-msg__avatar--ai",s.innerHTML=T;const o=document.createElement("div");o.className="csk-msg__content";const a=document.createElement("div");a.className="csk-msg__bubble",a.innerHTML="";const i=document.createElement("div");i.className="csk-msg__time",i.textContent=z(n),o.appendChild(a);const c=document.createElement("div");return c.className="csk-msg__meta",c.appendChild(i),c.appendChild(W(a,r)),o.appendChild(c),r.appendChild(s),r.appendChild(o),e.appendChild(r),{wrapper:r,bubble:a}}(le,n,r);l=e,c=t,p=!0}c&&(c.innerHTML=se(d),function(e){if(e.querySelector(".csk-caret"))return;const n=document.createElement("span");n.className="csk-caret",n.setAttribute("aria-hidden","true"),e.appendChild(n)}(c)),le&&Fe()},()=>{if(l&&c){if(!p&&""===d)return void b(e).then(a).catch(i);d&&(c.innerHTML=se(d)),K(l,c)}a(d)},e=>{"network"!==e.type&&"cors"!==e.type||le&&function(e){if(document.getElementById("csk-offline-banner"))return;const n=document.createElement("div");n.id="csk-offline-banner",n.className="csk-offline-banner",n.textContent=o("error_offline"),e.insertBefore(n,e.firstChild)}(le),d.length>0?(c&&(c.innerHTML=se(d+"\n\n"+o("stream_interrupted")),l&&K(l,c)),a(d)):i(e)},ae,t,s)})}(e,n,r,s):(i=await b(e),we&&we(),le&&R(le,i,n,se,s));const t={id:s,role:"ai",content:i,timestamp:n};ce.push(t),ee(ie.integrateId,ce),le&&Fe(),function(e){if(!ve)return;const n=e.length>120?e.substring(0,120)+"...":e;ve.textContent=o("new_msg_announce")+":"+n}(i),le&&le.dispatchEvent(new CustomEvent("csk:newMessage",{bubbles:!0,detail:{msg:t}})),r&&async function(e,n){try{const t=await y(e,ae);if(t.length>0){const e=t.map(e=>{var n,t;return{documentId:e.documentId||"",title:e.title||"",sourceName:e.sourceName||"",chunkIndex:null!==(n=e.chunkIndex)&&void 0!==n?n:0,score:null!==(t=e.score)&&void 0!==t?t:0,snippet:e.snippet||""}});if(n.sources=e,le){const n=le.querySelector(".csk-msg--ai:last-of-type");n&&J(n,e)}ie&&ee(ie.integrateId,ce)}}catch(e){}}(e,t),ie.suggestions&&async function(e){const n=p();if(!n||!le)return;try{const t=await async function(e){if(!a||!e)return[];try{const n=new URLSearchParams;n.set("chatId",e);const t=u(`/ai/suggestions?${n.toString()}`),r=await k(t);if(!r.ok)return[];const s=await r.json();return s.success&&s.data&&Array.isArray(s.data.suggestions)?s.data.suggestions.filter(e=>"string"==typeof e&&e.trim().length>0):[]}catch(e){return[]}}(n);if(t.length>0&&le){const n=le.querySelector(`[data-csk-msg-id="${e}"]`);n&&function(e,n,t){if(function(e){const n=e.querySelector(".csk-suggestions");n&&n.remove()}(e),!n||0===n.length)return;const r=document.createElement("div");r.className="csk-suggestions";const s=document.createElement("div");s.className="csk-suggestions__list";for(const e of n){const n=document.createElement("button");n.type="button",n.className="csk-suggestion-item",n.textContent=e,n.addEventListener("click",n=>{n.stopPropagation(),t(e)}),s.appendChild(n)}r.appendChild(s);const o=e.querySelector(".csk-msg__content");o?o.appendChild(r):e.appendChild(r)}(n,t,Re)}}catch(e){}}(s),function(){const e=document.getElementById("csk-offline-banner");e&&e.remove()}()}catch(e){we&&we();const n=e instanceof g?e.message:o("error_send");if(le){const e=document.createElement("div");e.className="csk-msg csk-msg--ai";const t=document.createElement("div");t.className="csk-msg__bubble",t.style.color="#DC2626",t.textContent=`⚠ ${n}`,e.appendChild(t),le.appendChild(e)}t.error(`发送失败 integrateId=${ie.integrateId}`,e)}finally{_e=!1,Ee=null,ze("send"),qe()}}function Re(e){return!de||_e?Promise.resolve():(de.value=e,qe(),He())}function Pe(){if(!le)return;const e=le.querySelector(".csk-history-panel");le.querySelectorAll(".csk-msg, .csk-loading").forEach(e=>e.remove());for(const e of ce)if("user"===e.role)j(le,e.content,e.timestamp);else{const n=R(le,e.content,e.timestamp,se,e.id);e.sources&&e.sources.length>0&&J(n,e.sources),e.feedback&&Y(n,e.feedback)}Ce=!0,G(le),me&&ce.length>0&&(me.style.display="inline-flex"),Be(),e&&!le.contains(e)&&le.appendChild(e)}async function Ue(e){if(!ie||!le)return;const n=Le.find(n=>(n.chatId||n.id)===e);if(n&&void 0!==n.roleId){const e=String(n.roleId),t=l();e&&e!==t&&(c(e),ge&&(ge.value=e))}d(e),I(l(),ie.userId,e),he&&he.classList.add("csk-history-panel--hidden"),ce=[];le.querySelectorAll(".csk-msg, .csk-loading").forEach(e=>e.remove());try{const n=await w(e);n.messages.length>0&&(ce=n.messages.map(e=>({id:M(),role:"USER"===e.messageType?"user":"ai",content:e.content,timestamp:new Date(e.createTime).getTime()})),Pe(),t.info(`加载会话 ${e} 的 ${ce.length} 条消息`),ee(ie.integrateId,ce))}catch(e){}me&&ce.length>0&&(me.style.display="inline-flex"),Be()}let We=null,Ye=!1,Oe=null,Xe=null,Ke=null,Je=null,Ve=null,Ge=null,Qe=null,Ze=null,en=null,nn=null,tn=null,rn=null,sn=null,on=null,an=null,cn=null,ln=null,dn=null,pn=null;function un(){if(!an||!Oe)return;const e=Oe.getBoundingClientRect(),n=on?"left"===on.side:"left-bottom"===(null==We?void 0:We.position);n?(an.style.left=`${e.left}px`,an.style.right="auto"):(an.style.right=window.innerWidth-e.right+"px",an.style.left="auto"),an.style.bottom=window.innerHeight-e.top+8+"px",an.classList.toggle("csk-teaser--left",!!n),an.classList.toggle("csk-teaser--right",!n)}function mn(){if(!an)return;an.classList.add("csk-teaser--hidden"),an.removeEventListener("click",kn);const e=an.querySelector(".csk-teaser__close");e&&e.removeEventListener("click",gn)}function kn(e){e.target.closest(".csk-teaser__close")||(mn(),yn())}function gn(e){e.stopPropagation(),mn()}function hn(){an&&!an.classList.contains("csk-teaser--hidden")&&un()}const bn='button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';function fn(e){"Escape"===e.key&&Xe&&!Xe.classList.contains("csk-window--hidden")&&vn(),function(e){if(!Xe||Xe.classList.contains("csk-window--hidden"))return;if("Tab"!==e.key)return;const n=Array.from(Xe.querySelectorAll(bn));if(0===n.length)return;const t=n[0],r=n[n.length-1];e.shiftKey?document.activeElement===t&&(e.preventDefault(),r.focus()):document.activeElement===r&&(e.preventDefault(),t.focus())}(e)}function yn(){Xe&&(Xe.classList.remove("csk-window--hidden"),mn(),ln&&ln.classList.add("csk-launcher__badge--hidden"),setTimeout(()=>{Je&&Je.focus()},80))}function vn(){Xe&&Xe.classList.add("csk-window--hidden")}function xn(){Xe&&(Xe.classList.contains("csk-window--hidden")?yn():vn())}function wn(e){return`csk_size_${e}`}function _n(e){return`csk_position_${e}`}function En(e){return`csk_launcher_pos_${e}`}function Cn(e){Xe&&(Xe.classList.remove("csk-window--right","csk-window--left"),Xe.classList.add(`csk-window--${e}`),an&&(an.classList.remove("csk-teaser--right","csk-teaser--left"),an.classList.add(`csk-teaser--${e}`)))}const Ln={init:function(e){if(Ye)return;const i=function(e){var n,r,s,o,a,i,c,l,d,p,u,m,k;if(!e.integrateId||"string"!=typeof e.integrateId&&"number"!=typeof e.integrateId||"string"==typeof e.integrateId&&""===e.integrateId.trim())return t.error('integrateId 是必传参数(对应后端 roleId 客服角色 ID),请检查 init() 调用。示例:ChatbotSDK.init({ integrateId: 1, requestDomain: "https://api.example.com" })'),null;if(!e.requestDomain||"string"!=typeof e.requestDomain||""===e.requestDomain.trim())return t.error('requestDomain 是必传参数,请检查 init() 调用。示例:ChatbotSDK.init({ integrateId: 1, requestDomain: "https://api.example.com" })'),null;try{new URL(e.requestDomain)}catch(n){return t.error(`requestDomain 不是合法的 URL 格式:${e.requestDomain}。请提供完整的域名,如 https://api.example.com`),null}const g=String(e.integrateId).trim(),h=e.requestDomain.replace(/\/+$/,""),b=e.launcherIcon||`')),o.push(`
":""),a=!1,i="")}function f(){c&&(o.push("')),o.push(`
')):(b(),f(),l.push(d(n))):(h(),b())}return h(),b(),f(),o.join("\n");function d(e){return e=(e=(e=(e=(e=(e=e.replace(/\*\*(.+?)\*\*/g,"$1")).replace(/__(.+?)__/g,"$1")).replace(/\*(.+?)\*/g,"$1")).replace(/(?$1")).replace(/~~(.+?)~~/g,"$1")).replace(/\[([^\]]+)\]\(([^)]+)\)/g,(e,n,t)=>`${n}`)}function p(e){const n=m(e);return n.length>0&&n.every(e=>/^:?-{3,}:?$/.test(e.trim()))}function u(e){return""!==e.trim()&&e.includes("|")}function m(e){const n=e.trim().replace(/^\|/,"").replace(/\|$/,"");if(!n.includes("|"))return[];const t=[];let r="";for(let e=0;e
")}
`,f=e.primaryColor||"#4F46E5",y={integrateId:g,requestDomain:e.requestDomain.replace(/\/+$/,""),userId:e.userId,categoryId:e.categoryId,showCategorySwitch:null!==(n=e.showCategorySwitch)&&void 0!==n&&n,title:e.title||"AI 智能助手",width:null!==(r=e.width)&&void 0!==r?r:500,height:Math.max(400,null!==(s=e.height)&&void 0!==s?s:520),position:"left-bottom"===e.position?"left-bottom":"right-bottom",primaryColor:f,launcherIcon:b,showClear:null===(o=e.showClear)||void 0===o||o,showAdminPanel:null!==(a=e.showAdminPanel)&&void 0!==a&&a,quickReplies:Array.isArray(e.quickReplies)?e.quickReplies.map(e=>String(e).trim()).filter(Boolean):[],suggestions:null===(i=e.suggestions)||void 0===i||i,theme:"dark"===e.theme?"dark":"light",showTeaser:null===(c=e.showTeaser)||void 0===c||c,teaserText:"string"==typeof e.teaserText&&e.teaserText.trim()||"",resizable:null===(l=e.resizable)||void 0===l||l,watermark:"string"==typeof e.watermark&&e.watermark.trim()||void 0,streaming:null===(d=e.streaming)||void 0===d||d,enableRag:null===(p=e.enableRag)||void 0===p||p,rewriteStrategy:e.rewriteStrategy||"REWRITE",locale:e.locale||"zh-CN",debug:null===(u=e.debug)||void 0===u||u,sound:null!==(m=e.sound)&&void 0!==m&&m,notification:null!==(k=e.notification)&&void 0!==k&&k,onError:"function"==typeof e.onError?e.onError:void 0,onReady:"function"==typeof e.onReady?e.onReady:void 0,onMessage:"function"==typeof e.onMessage?e.onMessage:void 0,token:e.token,roles:e.roles,disclaimer:e.disclaimer,chatId:""};return t.info(`配置解析完成 integrateId(=roleId)=${y.integrateId} userId(=accountId)=${y.userId||"(未设置)"} requestDomain=${y.requestDomain}`),y}(e);if(!i)return;We=i,function(e){if(r[e])s=e;else{const n=e.split("-")[0],t=Object.keys(r).find(e=>e.startsWith(n));t&&(s=t)}}(We.locale),We.debug,n(We.onError),function(e){a=e}(We),N(We),Oe=B(We,xn),document.body.appendChild(Oe),ln=Oe.querySelector(".csk-launcher__badge"),function(e,n){try{const t=localStorage.getItem(En(e));if(!t)return;const r=JSON.parse(t);if("left"!==r.side&&"right"!==r.side||"number"!=typeof r.bottom)return;const s=window.innerHeight-76,o=Math.max(16,Math.min(r.bottom,s));n.classList.remove("csk-launcher--right","csk-launcher--left"),n.classList.add(`csk-launcher--${r.side}`),n.style.bottom=`${o}px`,on={side:r.side,bottom:o}}catch(e){}}(We.integrateId,Oe),rn=function(e,n,t){let r=!1,s=0,o=0,a=!1,i=0,c=0,l=0,d=!1;function p(){const n=parseFloat(getComputedStyle(e).bottom);return isNaN(n)?24:n}function u(n,t){if(d)return;r=!0,a=!1,s=n,o=t,i=p();const u=e.style,m=getComputedStyle(e);c=u.right?parseFloat(u.right):parseFloat(m.right),l=u.left?parseFloat(u.left):parseFloat(m.left)}function m(n,t,d){if(!r)return;const p=n-s,u=t-o;if(!a){if(Math.abs(p)<5&&Math.abs(u)<5)return;a=!0,e.classList.add("csk-launcher--dragging"),e.classList.remove("csk-launcher--right","csk-launcher--left"),e.style.transition="none",!isNaN(c)&&c>=0&&isNaN(l)?(e.style.right=`${c}px`,e.style.left="auto"):!isNaN(l)&&l>=0&&(e.style.left=`${l}px`,e.style.right="auto")}if(a){d.preventDefault();const n=Math.max(16,Math.min(i-u,H()));e.style.bottom=`${n}px`}}function k(){if(!r)return;if(r=!1,!a)return;const n=parseFloat(e.style.bottom)||p(),s=Math.max(16,Math.min(n,H())),o=e.getBoundingClientRect(),i=o.left+o.width/2<=window.innerWidth/2?"left":"right";e.classList.remove("csk-launcher--dragging"),e.classList.add(`csk-launcher--${i}`,"csk-launcher--snap"),e.style.left="",e.style.right="",e.style.bottom=`${s}px`,d=!0;const c=()=>{e.removeEventListener("transitionend",c),e.classList.remove("csk-launcher--snap"),e.style.transition="",d=!1};e.addEventListener("transitionend",c),setTimeout(()=>{d&&c()},350);const l=n=>{n.stopPropagation(),e.removeEventListener("click",l,!0)};e.addEventListener("click",l,!0);const u=e.querySelector(".csk-launcher__badge");u&&(u.style.display=""),t&&t({side:i,bottom:s})}function g(e){u(e.clientX,e.clientY)}function h(e){m(e.clientX,e.clientY,e)}function b(){k()}function f(e){1===e.touches.length&&u(e.touches[0].clientX,e.touches[0].clientY)}function y(e){1===e.touches.length&&m(e.touches[0].clientX,e.touches[0].clientY,e)}function v(){k()}return e.addEventListener("mousedown",g),document.addEventListener("mousemove",h),document.addEventListener("mouseup",b),e.addEventListener("touchstart",f,{passive:!0}),document.addEventListener("touchmove",y,{passive:!1}),document.addEventListener("touchend",v),()=>{e.removeEventListener("mousedown",g),document.removeEventListener("mousemove",h),document.removeEventListener("mouseup",b),e.removeEventListener("touchstart",f),document.removeEventListener("touchmove",y),document.removeEventListener("touchend",v)}}(Oe,0,e=>{const n=null==on?void 0:on.side;on=e,function(e,n){try{localStorage.setItem(En(e),JSON.stringify(n))}catch(e){}}(We.integrateId,e),n&&n!==e.side&&function(){if(!Xe)return;Xe.style.left="",Xe.style.top="",Xe.style.right="",Xe.style.bottom=""}(),Cn(e.side),an&&!an.classList.contains("csk-teaser--hidden")&&un()}),on&&Cn(on.side);const d=q(We);Xe=d.window,Ke=d.messagesContainer,Je=d.inputEl,Ve=d.sendBtn,Ge=d.clearBtn,Qe=d.categorySelect,Ze=d.historyPanel,en=d.showLoading,nn=d.hideLoading,pn=d.disclaimer,document.body.appendChild(Xe),an=d.teaserEl,document.body.appendChild(an),un();const m=Xe.querySelector(".csk-header");if(m&&(tn=function(e,n,t){let r=!1,s=0,o=0,a=0,i=0;const c=e=>{if(e.target.closest("button"))return;r=!0,s=e.clientX,o=e.clientY;const t=n.getBoundingClientRect();a=s-t.left,i=o-t.top,document.addEventListener("mousemove",l),document.addEventListener("mouseup",d)},l=e=>{if(!r)return;const t=e.clientX-a,s=e.clientY-i,o=window.innerWidth-n.offsetWidth,c=window.innerHeight-n.offsetHeight;n.style.right="auto",n.style.bottom="auto",n.style.left=`${Math.max(0,Math.min(t,o))}px`,n.style.top=`${Math.max(0,Math.min(s,c))}px`},d=()=>{if(r=!1,document.removeEventListener("mousemove",l),document.removeEventListener("mouseup",d),t){const e=n.getBoundingClientRect();t({x:e.left,y:e.top})}};return e.addEventListener("mousedown",c),()=>{e.removeEventListener("mousedown",c),document.removeEventListener("mousemove",l),document.removeEventListener("mouseup",d)}}(m,Xe,e=>{!function(e,n){try{localStorage.setItem(_n(e),JSON.stringify(n))}catch(e){}}(We.integrateId,e)})),function(e,n){try{const t=localStorage.getItem(_n(e));if(!t)return;const r=JSON.parse(t);if("number"!=typeof r.x||"number"!=typeof r.y)return;const s=window.innerWidth-n.offsetWidth,o=window.innerHeight-n.offsetHeight,a=Math.max(0,Math.min(r.x,s)),i=Math.max(0,Math.min(r.y,o));n.style.right="auto",n.style.bottom="auto",n.style.left=`${a}px`,n.style.top=`${i}px`}catch(e){}}(We.integrateId,Xe),We.resizable){const e=d.resizeHandle;sn=function(e,n,t){let r=!1,s=0,o=0,a=0,i=0;const c=(e,t)=>{r=!0,s=e,o=t;const c=n.getBoundingClientRect();a=c.width,i=c.height,n.classList.add("csk-window--resizing"),document.addEventListener("mousemove",p),document.addEventListener("mouseup",u),document.addEventListener("touchmove",g,{passive:!1}),document.addEventListener("touchend",h)},l=(e,t,c)=>{if(!r)return;c&&c.preventDefault();const l=e-s,d=t-o,p=Math.max(300,Math.min(a+l,window.innerWidth-24)),u=Math.max(300,Math.min(i+d,window.innerHeight-24));n.style.width=`${p}px`,n.style.height=`${u}px`,n.style.setProperty("--csk-window-width",`${p}px`),n.style.setProperty("--csk-window-height",`${u}px`),n.style.bottom="",n.style.right=""},d=()=>{if(!r)return;r=!1,n.classList.remove("csk-window--resizing"),document.removeEventListener("mousemove",p),document.removeEventListener("mouseup",u),document.removeEventListener("touchmove",g),document.removeEventListener("touchend",h);const e=n.getBoundingClientRect();t&&t({width:e.width,height:e.height})};function p(e){l(e.clientX,e.clientY,e)}function u(){d()}function m(e){e.preventDefault(),e.stopPropagation(),c(e.clientX,e.clientY)}function k(e){e.preventDefault(),e.stopPropagation(),1===e.touches.length&&c(e.touches[0].clientX,e.touches[0].clientY)}function g(e){1===e.touches.length&&l(e.touches[0].clientX,e.touches[0].clientY,e)}function h(){d()}return e.addEventListener("mousedown",m),e.addEventListener("touchstart",k,{passive:!1}),()=>{e.removeEventListener("mousedown",m),e.removeEventListener("touchstart",k),document.removeEventListener("mousemove",p),document.removeEventListener("mouseup",u),document.removeEventListener("touchmove",g),document.removeEventListener("touchend",h)}}(e,Xe,e=>{!function(e,n){try{localStorage.setItem(wn(e),JSON.stringify(n))}catch(e){}}(We.integrateId,e)}),function(e,n){try{const t=localStorage.getItem(wn(e));if(!t)return;const r=JSON.parse(t);if("number"!=typeof r.width||"number"!=typeof r.height)return;const s=Math.max(300,Math.min(r.width,window.innerWidth-24)),o=Math.max(300,Math.min(r.height,window.innerHeight-24));n.style.width=`${s}px`,n.style.height=`${o}px`,n.style.setProperty("--csk-window-width",`${s}px`),n.style.setProperty("--csk-window-height",`${o}px`)}catch(e){}}(We.integrateId,Xe)}if(Ae(We,{messagesContainer:Ke,inputEl:Je,sendBtn:Ve,clearBtn:Ge,categorySelect:Qe,historyPanel:Ze,welcomeEl:d.welcomeEl,newMsgBtn:d.newMsgBtn,searchInput:d.searchInput,ariaLiveEl:d.ariaLiveEl,roleSelect:d.roleSelect,showLoading:en,hideLoading:nn}),Xe.addEventListener("csk:categoryChange",e=>{var n,t;n=e.detail.categoryId,ae=n,Se=null===(t=null==ie?void 0:ie.enableRag)||void 0===t||t}),Xe.addEventListener("csk:loadHistory",()=>{!async function(){if(!he||!ie)return;const e=he.querySelector("#csk-history-list");if(e){e.innerHTML='