From 25c3d9d82891b1c1368bec808734e7d101572a60 Mon Sep 17 00:00:00 2001 From: zzlgreat Date: Sun, 30 Nov 2025 17:06:34 +0800 Subject: [PATCH] update pay function --- __pycache__/mcp_server.cpython-310.pyc | Bin 88624 -> 89343 bytes mcp_server.py | 31 +++++++++++++- src/components/ChatBot/MarkdownWithCharts.js | 42 ++++++++++++++++--- 3 files changed, 66 insertions(+), 7 deletions(-) diff --git a/__pycache__/mcp_server.cpython-310.pyc b/__pycache__/mcp_server.cpython-310.pyc index fcea44c977b5de90ef0cc6f04959586b185a5105..e4a163a0158929d49d059175cde9fee1d7289579 100644 GIT binary patch delta 4628 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 J_Y5r1e*v``)DZvx delta 3943 zcmZ`*3tW^{7XQvS?-^byFvH7XAjAPiKtwYUP)IaIO#5kRF0y{4j0$)i@X<$7tc1L_rU8*^_r4X8t-#&-qh(oNBf)@{=(8; z3w6sxNiS($6lASrkc^AOFd)i&ao2-|*OFg9ET5Xj<;w!*NCi=qzQsv zcuJ5ARi@`m;{;ETyBlexFezM$sMXwWop6UKMUMN;XD-au2+k<4Z&@DjqUE7Hu-OO~ zxve>~|7t^p37eFVaB|&>)9)>hW|cT%uYw>{SX90F$4~gle=dF`dUQ#&22E4Zw3^Rr z?$cd13c^J{BJowK3lwEJR>-xFaKcWjyv!I~)BX_ykjpRmA~k?fgXQaU4(z0dikSM&{JY2@`AnSC=Dcefm9dWz>LY-!IhPq%S{OH!45Vst0XHA4g{wfL5wUdn4zuHvX^AQBp2}bhO`0C%7!{^`7+#;R@o)@l#}HYNv_51uC}8} z*4~aFr=aH+wU+0kh5WUKSWC5>Kvu~iJ(%O=_shiKz$=8ZdS=HnF~KJUTX;uPZ$Gx2`PX*MKl?;f*f;35 z8dhsq2Bnx!K#vRCrBW-gjmTDd{OB zUEt=kufcJ?_-uOkB~tv6Oj8Li(@-MmSAOQ~Ga+g^0ft9!5$71)0eQLiq7i)hp%cAek`!A*iDf+^&$J}tL^|GA@gS9WSSoqS72 z1ia0E=-3G+@2a1hL1)3J4qnme01H<-v%t*vcAkc7yzydQAZ0udFHGh~Q(yC1e>o01 zf0Q5Rw=Oxr-|M*CO#?wZ?dsU57mzonJ5FuXYXQI7U@&Toh5#^%EX4b-t3d#vUhlOj zMzH#VHL%nKHs3}+I28zCz9o?ms)KN4qXP;cz^9FY5yl904WFi3)Pr9*-l8c^>Q$?&3YFrOcaveDy|)}D zITv?b%P?E(36rfgP-T@8WUK5aB`UX)!C^>}=}vSh@hOl7eUwQlPzTY<*%Zj=k%+O| zv_%!3vSF+i+g&0=D}z$O0o#?ysqiSW|D6i`@vkivqMR+raBA3OTIN2K)svX~6D2}6 zs&&kT12&y(+m(pE&}K;^3eCVG-bjP65VerUiSRW6IkOO@Pa1^xiYHbqfs>$!Of=0z z^Q+{08mklKslsfDNw8$$8!Ws%|7IJ-Xc^Vp)!8)V z@l41X`x$nTg`<{UMDKiXEZ}`2^uQk*L_Qe=g9(nH&Izhd*THz_6cX@aVwuXZOh|Ix zZRP_fr$FZ@c(yVi3*sPKnVbbZ^<8I@@_ZJ=*wvR!^_o>X(2rbN$z=dZvC3yzkbr*Y zvcLvTMV}1=B5BfzW>z+{xX@EpHgnEBZEI7W%7!fCL9Eg#vT$WtHuQp3N>eu6NE9ic zhCoZ8BhV8V5S)7UGtGK|AXe!Z0^yb%GO9<`K_z%7#KL0b;h|uMT;<83a40u|%nuV^ ztv!l{v?g8M4<|zrg44+UKT}zd1GsIK4|1Tu6o<~EG3|beAs6~uUD)S2c%b1szo^xN z-lDyvzsZLA#^k~P5tDd%7(U2(%9dfU5{4^{BcX>ra_<-r#)LYXxj zJNQ@^Va;#|x0h33x(&o?n??luiX!L%PoL{J!6@H};ZP0s>boqnCKNdVc$fu1PcT-C zx7cW3&0~1{K|aNevA=RJIpFu?F+On=gaGtcZ26EB<-j^8>dVTDON&aFy7vsUJ%>>5 zt|&$MP!2|=H6N}oRNqb6wb(7_iVHiOkId&_aH?_FjQ&Lu{ best_pos: + best_pos = pos + + if best_pos > max_length // 2: # 只有找到的位置超过一半时才使用 + truncated = truncated[:best_pos + 1] + + # 如果结果看起来像 JSON,添加省略提示 + if truncated.strip().startswith('{') or truncated.strip().startswith('['): + return truncated + "\n...(数据已截断)" + else: + return truncated + "..." + + # 构建结果文本(精简版,安全截取) results_text = "\n\n".join([ f"**步骤 {r.step_index + 1}: {r.tool}**\n" - f"结果: {str(r.result)[:800]}..." + f"结果: {safe_truncate_result(r.result)}" for r in successful_results[:3] # 只取前3个,避免超长 ]) diff --git a/src/components/ChatBot/MarkdownWithCharts.js b/src/components/ChatBot/MarkdownWithCharts.js index 0f9dc0dd..0efdd1ec 100644 --- a/src/components/ChatBot/MarkdownWithCharts.js +++ b/src/components/ChatBot/MarkdownWithCharts.js @@ -8,6 +8,35 @@ import remarkGfm from 'remark-gfm'; import { EChartsRenderer } from './EChartsRenderer'; import { logger } from '@utils/logger'; +/** + * 清理消息中可能存在的残缺 JSON 片段 + * 这种情况通常是模型生成时意外混入的工具返回数据 + * @param {string} text - 原始文本 + * @returns {string} - 清理后的文本 + */ +const cleanBrokenJson = (text) => { + if (!text) return text; + + // 移除可能的残缺 JSON 对象片段(没有开头的 { 但有结尾的 }) + // 例如: "...一些文字itemStyle": {"color": "#ee6666"}, "smooth": true}]\n}" + let cleaned = text; + + // 模式1: 移除以 JSON 属性开始的残缺片段 (如 itemStyle": {...}) + cleaned = cleaned.replace(/[a-zA-Z_][a-zA-Z0-9_]*"\s*:\s*\{[^{}]*\}(\s*,\s*"[a-zA-Z_][a-zA-Z0-9_]*"\s*:\s*[^,}\]]+)*\s*\}\s*\]\s*\}/g, ''); + + // 模式2: 移除孤立的 JSON 数组/对象结尾 (如 ]\n}) + cleaned = cleaned.replace(/\s*\]\s*\}\s*```\s*$/g, ''); + + // 模式3: 移除不完整的 echarts 代码块残留 + // 匹配没有开始标记的残缺内容 + cleaned = cleaned.replace(/[a-zA-Z_][a-zA-Z0-9_]*"\s*:\s*\[[^\]]*\]\s*\}\s*```/g, ''); + + // 模式4: 清理残留的属性片段 + cleaned = cleaned.replace(/,?\s*"[a-zA-Z_][a-zA-Z0-9_]*"\s*:\s*(?:true|false|null|\d+|"[^"]*")\s*\}\s*\]\s*\}\s*$/g, ''); + + return cleaned.trim(); +}; + /** * 解析 Markdown 内容,提取 ECharts 代码块 * @param {string} markdown - Markdown 文本 @@ -16,15 +45,18 @@ import { logger } from '@utils/logger'; const parseMarkdownWithCharts = (markdown) => { if (!markdown) return []; + // 先清理可能的残缺 JSON + const cleanedMarkdown = cleanBrokenJson(markdown); + const parts = []; const echartsRegex = /```echarts\s*\n([\s\S]*?)```/g; let lastIndex = 0; let match; - while ((match = echartsRegex.exec(markdown)) !== null) { + while ((match = echartsRegex.exec(cleanedMarkdown)) !== null) { // 添加代码块前的文本 if (match.index > lastIndex) { - const textBefore = markdown.substring(lastIndex, match.index).trim(); + const textBefore = cleanedMarkdown.substring(lastIndex, match.index).trim(); if (textBefore) { parts.push({ type: 'text', content: textBefore }); } @@ -38,8 +70,8 @@ const parseMarkdownWithCharts = (markdown) => { } // 添加剩余文本 - if (lastIndex < markdown.length) { - const textAfter = markdown.substring(lastIndex).trim(); + if (lastIndex < cleanedMarkdown.length) { + const textAfter = cleanedMarkdown.substring(lastIndex).trim(); if (textAfter) { parts.push({ type: 'text', content: textAfter }); } @@ -47,7 +79,7 @@ const parseMarkdownWithCharts = (markdown) => { // 如果没有找到图表,返回整个 markdown 作为文本 if (parts.length === 0) { - parts.push({ type: 'text', content: markdown }); + parts.push({ type: 'text', content: cleanedMarkdown }); } return parts;