update pay function
This commit is contained in:
@@ -39,6 +39,7 @@ const cleanBrokenJson = (text) => {
|
||||
|
||||
/**
|
||||
* 解析 Markdown 内容,提取 ECharts 代码块
|
||||
* 支持处理不完整的代码块(LLM 输出被截断的情况)
|
||||
* @param {string} markdown - Markdown 文本
|
||||
* @returns {Array} - 包含文本和图表的数组
|
||||
*/
|
||||
@@ -49,11 +50,17 @@ const parseMarkdownWithCharts = (markdown) => {
|
||||
const cleanedMarkdown = cleanBrokenJson(markdown);
|
||||
|
||||
const parts = [];
|
||||
const echartsRegex = /```echarts\s*\n([\s\S]*?)```/g;
|
||||
|
||||
// 方案1: 匹配完整的 echarts 代码块
|
||||
const completeEchartsRegex = /```echarts\s*\n([\s\S]*?)```/g;
|
||||
// 方案2: 匹配不完整的 echarts 代码块(没有结束的 ```)
|
||||
const incompleteEchartsRegex = /```echarts\s*\n([\s\S]*?)$/;
|
||||
|
||||
let lastIndex = 0;
|
||||
let match;
|
||||
|
||||
while ((match = echartsRegex.exec(cleanedMarkdown)) !== null) {
|
||||
// 首先尝试匹配完整的代码块
|
||||
while ((match = completeEchartsRegex.exec(cleanedMarkdown)) !== null) {
|
||||
// 添加代码块前的文本
|
||||
if (match.index > lastIndex) {
|
||||
const textBefore = cleanedMarkdown.substring(lastIndex, match.index).trim();
|
||||
@@ -69,15 +76,36 @@ const parseMarkdownWithCharts = (markdown) => {
|
||||
lastIndex = match.index + match[0].length;
|
||||
}
|
||||
|
||||
// 添加剩余文本
|
||||
// 检查剩余内容是否包含不完整的 echarts 代码块
|
||||
if (lastIndex < cleanedMarkdown.length) {
|
||||
const textAfter = cleanedMarkdown.substring(lastIndex).trim();
|
||||
const remainingText = cleanedMarkdown.substring(lastIndex);
|
||||
const incompleteMatch = remainingText.match(incompleteEchartsRegex);
|
||||
|
||||
if (incompleteMatch) {
|
||||
// 提取不完整代码块之前的文本
|
||||
const textBeforeIncomplete = remainingText.substring(0, incompleteMatch.index).trim();
|
||||
if (textBeforeIncomplete) {
|
||||
parts.push({ type: 'text', content: textBeforeIncomplete });
|
||||
}
|
||||
|
||||
// 提取不完整的 echarts 内容
|
||||
const incompleteChartConfig = incompleteMatch[1].trim();
|
||||
if (incompleteChartConfig) {
|
||||
logger.warn('检测到不完整的 echarts 代码块(缺少结束符)', {
|
||||
contentPreview: incompleteChartConfig.substring(0, 100),
|
||||
});
|
||||
parts.push({ type: 'chart', content: incompleteChartConfig });
|
||||
}
|
||||
} else {
|
||||
// 普通剩余文本
|
||||
const textAfter = remainingText.trim();
|
||||
if (textAfter) {
|
||||
parts.push({ type: 'text', content: textAfter });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有找到图表,返回整个 markdown 作为文本
|
||||
// 如果没有找到任何图表,返回整个 markdown 作为文本
|
||||
if (parts.length === 0) {
|
||||
parts.push({ type: 'text', content: cleanedMarkdown });
|
||||
}
|
||||
@@ -240,11 +268,12 @@ export const MarkdownWithCharts = ({ content, variant = 'auto' }) => {
|
||||
// 移除可能的前后空白和不可见字符
|
||||
cleanContent = cleanContent.replace(/^\s+|\s+$/g, '');
|
||||
|
||||
// 检查 JSON 是否完整并尝试修复
|
||||
// 使用栈来跟踪括号,确保正确的闭合顺序
|
||||
// ========== 增强的 JSON 修复逻辑 ==========
|
||||
// 使用栈来跟踪括号和字符串状态
|
||||
const stack = [];
|
||||
let inString = false;
|
||||
let escape = false;
|
||||
let stringStartPos = -1;
|
||||
|
||||
for (let i = 0; i < cleanContent.length; i++) {
|
||||
const char = cleanContent[i];
|
||||
@@ -260,7 +289,13 @@ export const MarkdownWithCharts = ({ content, variant = 'auto' }) => {
|
||||
}
|
||||
|
||||
if (char === '"') {
|
||||
inString = !inString;
|
||||
if (inString) {
|
||||
inString = false;
|
||||
stringStartPos = -1;
|
||||
} else {
|
||||
inString = true;
|
||||
stringStartPos = i;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -279,7 +314,22 @@ export const MarkdownWithCharts = ({ content, variant = 'auto' }) => {
|
||||
}
|
||||
}
|
||||
|
||||
// 如果栈不为空,说明有未闭合的括号,需要补全
|
||||
// 修复1: 如果字符串未闭合,需要关闭字符串
|
||||
if (inString) {
|
||||
logger.warn('检测到未闭合的字符串,尝试修复', {
|
||||
position: stringStartPos,
|
||||
});
|
||||
// 找到最后一个有意义的位置(非空白)
|
||||
let lastMeaningful = cleanContent.length - 1;
|
||||
while (lastMeaningful > stringStartPos && /\s/.test(cleanContent[lastMeaningful])) {
|
||||
lastMeaningful--;
|
||||
}
|
||||
// 截取到最后一个有意义的字符,然后闭合字符串
|
||||
cleanContent = cleanContent.substring(0, lastMeaningful + 1) + '"';
|
||||
logger.info('字符串已修复(添加闭合引号)');
|
||||
}
|
||||
|
||||
// 修复2: 如果栈不为空,说明有未闭合的括号,需要补全
|
||||
if (stack.length > 0) {
|
||||
logger.warn('检测到不完整的 ECharts JSON,尝试修复', {
|
||||
unclosed: stack.join(''),
|
||||
@@ -291,11 +341,67 @@ export const MarkdownWithCharts = ({ content, variant = 'auto' }) => {
|
||||
cleanContent += open === '{' ? '}' : ']';
|
||||
}
|
||||
|
||||
logger.info('ECharts JSON 已修复');
|
||||
logger.info('ECharts JSON 括号已修复');
|
||||
}
|
||||
|
||||
// 修复3: 尝试清理可能的尾部垃圾字符(如截断导致的无效字符)
|
||||
// 找到最后一个有效的 JSON 结束字符
|
||||
const lastValidEnd = Math.max(
|
||||
cleanContent.lastIndexOf('}'),
|
||||
cleanContent.lastIndexOf(']'),
|
||||
cleanContent.lastIndexOf('"')
|
||||
);
|
||||
if (lastValidEnd > 0 && lastValidEnd < cleanContent.length - 1) {
|
||||
const tail = cleanContent.substring(lastValidEnd + 1).trim();
|
||||
// 如果尾部不是有效的 JSON 字符,则截断
|
||||
if (tail && !/^[,\}\]\s]*$/.test(tail)) {
|
||||
logger.warn('检测到尾部垃圾字符,截断处理', { tail: tail.substring(0, 50) });
|
||||
cleanContent = cleanContent.substring(0, lastValidEnd + 1);
|
||||
}
|
||||
}
|
||||
|
||||
// 尝试解析 JSON
|
||||
const chartOption = JSON.parse(cleanContent);
|
||||
let chartOption;
|
||||
try {
|
||||
chartOption = JSON.parse(cleanContent);
|
||||
} catch (parseError) {
|
||||
// 如果解析失败,尝试更激进的修复
|
||||
logger.warn('首次 JSON 解析失败,尝试更激进的修复', { error: parseError.message });
|
||||
|
||||
// 尝试找到 JSON 的有效开始和结束
|
||||
const jsonStart = cleanContent.indexOf('{');
|
||||
if (jsonStart >= 0) {
|
||||
let fixedContent = cleanContent.substring(jsonStart);
|
||||
// 重新计算并补全括号
|
||||
const fixStack = [];
|
||||
let fixInString = false;
|
||||
let fixEscape = false;
|
||||
|
||||
for (let i = 0; i < fixedContent.length; i++) {
|
||||
const char = fixedContent[i];
|
||||
if (fixEscape) { fixEscape = false; continue; }
|
||||
if (char === '\\' && fixInString) { fixEscape = true; continue; }
|
||||
if (char === '"') { fixInString = !fixInString; continue; }
|
||||
if (fixInString) continue;
|
||||
if (char === '{' || char === '[') fixStack.push(char);
|
||||
else if (char === '}' && fixStack.length > 0 && fixStack[fixStack.length - 1] === '{') fixStack.pop();
|
||||
else if (char === ']' && fixStack.length > 0 && fixStack[fixStack.length - 1] === '[') fixStack.pop();
|
||||
}
|
||||
|
||||
// 如果仍在字符串中,关闭字符串
|
||||
if (fixInString) fixedContent += '"';
|
||||
// 补全括号
|
||||
while (fixStack.length > 0) {
|
||||
const open = fixStack.pop();
|
||||
fixedContent += open === '{' ? '}' : ']';
|
||||
}
|
||||
|
||||
chartOption = JSON.parse(fixedContent);
|
||||
logger.info('激进修复成功');
|
||||
} else {
|
||||
throw parseError;
|
||||
}
|
||||
}
|
||||
|
||||
// 验证是否是有效的 ECharts 配置
|
||||
if (!chartOption || typeof chartOption !== 'object') {
|
||||
|
||||
Reference in New Issue
Block a user