'commit'
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>分时电价分析 - 驿来特AI智能大脑</title>
|
||||
<link rel="stylesheet" href="css/dashboard.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.5.1/github-markdown-dark.min.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
@@ -82,7 +83,7 @@
|
||||
<span>🤖 AI 调价策略建议</span>
|
||||
</div>
|
||||
<div class="ai-box" ref="aiBoxRef">
|
||||
<div v-if="!aiText && !aiLoading" style="text-align: center; color: #64748b; margin-top: 40px;">
|
||||
<div v-if="!aiText" style="text-align: center; color: #64748b; margin-top: 40px;">
|
||||
<span class="loading-dots">AI 正在深度分析中</span>
|
||||
</div>
|
||||
<div v-else class="markdown-body" v-html="renderedAiText"></div>
|
||||
@@ -95,9 +96,9 @@
|
||||
<script src="js/axios.min.js"></script>
|
||||
<script src="js/echarts.min.js"></script>
|
||||
<!-- Markdown & LaTeX Support -->
|
||||
<link rel="stylesheet" href="https://gcore.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css">
|
||||
<script src="https://gcore.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.js"></script>
|
||||
<script src="https://gcore.jsdelivr.net/npm/marked@12.0.0/lib/marked.umd.js"></script>
|
||||
<link rel="stylesheet" href="https://unpkg.com/katex@0.16.9/dist/katex.min.css">
|
||||
<script src="https://unpkg.com/katex@0.16.9/dist/katex.min.js"></script>
|
||||
<script src="https://unpkg.com/marked@12.0.0/marked.min.js"></script>
|
||||
<script src="js/dashboard.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -283,11 +283,20 @@ createApp({
|
||||
const reader = response.body.getReader();
|
||||
const decoder = new TextDecoder();
|
||||
|
||||
let fullText = "";
|
||||
while (true) {
|
||||
const {done, value} = await reader.read();
|
||||
if (done) break;
|
||||
const chunk = decoder.decode(value, {stream: true});
|
||||
aiText.value += chunk;
|
||||
fullText += chunk;
|
||||
|
||||
if (fullText.includes("---CLEAR_PREVIOUS_HINTS---")) {
|
||||
const parts = fullText.split("---CLEAR_PREVIOUS_HINTS---");
|
||||
aiText.value = parts[parts.length - 1];
|
||||
} else {
|
||||
aiText.value = fullText;
|
||||
}
|
||||
|
||||
await Vue.nextTick();
|
||||
if (aiBoxRef.value) {
|
||||
aiBoxRef.value.scrollTop = aiBoxRef.value.scrollHeight;
|
||||
@@ -325,7 +334,7 @@ createApp({
|
||||
});
|
||||
}
|
||||
|
||||
// 降级用的简易 Markdown 解析器
|
||||
// 降级用的简易 Markdown 解析器 (增强版)
|
||||
const simpleMarkdown = (text) => {
|
||||
if (!text) return '';
|
||||
let lines = text.split('\n');
|
||||
@@ -334,6 +343,7 @@ createApp({
|
||||
const parseInline = (str) => {
|
||||
return str
|
||||
.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
|
||||
.replace(/\*(.*?)\*/g, '<em>$1</em>')
|
||||
.replace(/`(.*?)`/g, '<code style="background:rgba(148, 163, 184, 0.1); padding:2px 4px; border-radius:4px;">$1</code>');
|
||||
};
|
||||
for (let line of lines) {
|
||||
@@ -343,13 +353,28 @@ createApp({
|
||||
html += '<br>';
|
||||
continue;
|
||||
}
|
||||
if (trimmed.startsWith('### ')) {
|
||||
if (trimmed.startsWith('# ')) {
|
||||
if (inList) { html += '</ul>'; inList = false; }
|
||||
html += `<h1>${parseInline(trimmed.substring(2))}</h1>`;
|
||||
} else if (trimmed.startsWith('## ')) {
|
||||
if (inList) { html += '</ul>'; inList = false; }
|
||||
html += `<h2>${parseInline(trimmed.substring(3))}</h2>`;
|
||||
} else if (trimmed.startsWith('### ')) {
|
||||
if (inList) { html += '</ul>'; inList = false; }
|
||||
html += `<h3>${parseInline(trimmed.substring(4))}</h3>`;
|
||||
} else if (trimmed.startsWith('- ') || /^\d+\./.test(trimmed)) {
|
||||
if (!inList) { html += '<ul>'; inList = true; }
|
||||
let content = trimmed.replace(/^(- |\d+\. )/, '');
|
||||
html += `<li>${parseInline(content)}</li>`;
|
||||
} else if (trimmed.startsWith('|') && trimmed.endsWith('|')) {
|
||||
// 简单的表格识别 (仅作示意,复杂表格仍需 marked)
|
||||
if (inList) { html += '</ul>'; inList = false; }
|
||||
let cells = trimmed.split('|').filter(c => c.trim() || c === '');
|
||||
html += '<div style="display:flex; border-bottom:1px solid #334155; padding:4px;">';
|
||||
cells.forEach(c => {
|
||||
html += `<div style="flex:1; padding:4px;">${parseInline(c.trim())}</div>`;
|
||||
});
|
||||
html += '</div>';
|
||||
} else {
|
||||
if (inList) { html += '</ul>'; inList = false; }
|
||||
html += `<p>${parseInline(trimmed)}</p>`;
|
||||
@@ -363,44 +388,45 @@ createApp({
|
||||
const renderMarkdownAndLatex = (text) => {
|
||||
if (!text) return '';
|
||||
|
||||
// 如果包含提示信息且还没被清除,先简单处理显示
|
||||
if (text.includes('正在收集各供应商价格数据') || text.includes('正在进行 AI 深度分析')) {
|
||||
return `<div style="color: #64748b; font-style: italic;">${text.replace(/\n/g, '<br>')}</div>`;
|
||||
}
|
||||
|
||||
try {
|
||||
// 1. 处理 LaTeX (简单替换,先处理 $$ 再处理 $)
|
||||
let processedText = text;
|
||||
|
||||
// 处理块级 LaTeX: $$ ... $$
|
||||
processedText = processedText.replace(/\$\$\s*([\s\S]*?)\s*\$\$/g, (match, formula) => {
|
||||
try {
|
||||
if (typeof katex !== 'undefined') {
|
||||
// 1. 处理 LaTeX (如果 katex 加载成功)
|
||||
if (typeof katex !== 'undefined') {
|
||||
// 处理块级 LaTeX: $$ ... $$
|
||||
processedText = processedText.replace(/\$\$\s*([\s\S]*?)\s*\$\$/g, (match, formula) => {
|
||||
try {
|
||||
return '<div class="katex-block">' + katex.renderToString(formula, { displayMode: true, throwOnError: false }) + '</div>';
|
||||
}
|
||||
return match;
|
||||
} catch (e) {
|
||||
return match;
|
||||
}
|
||||
});
|
||||
|
||||
// 处理行内 LaTeX: $ ... $
|
||||
processedText = processedText.replace(/\$([^\$\n]+?)\$/g, (match, formula) => {
|
||||
try {
|
||||
if (typeof katex !== 'undefined') {
|
||||
} catch (e) { return match; }
|
||||
});
|
||||
|
||||
// 处理行内 LaTeX: $ ... $
|
||||
processedText = processedText.replace(/\$([^\$\n]+?)\$/g, (match, formula) => {
|
||||
try {
|
||||
return katex.renderToString(formula, { displayMode: false, throwOnError: false });
|
||||
}
|
||||
return match;
|
||||
} catch (e) {
|
||||
return match;
|
||||
}
|
||||
});
|
||||
|
||||
// 2. 使用 marked 解析 Markdown
|
||||
if (typeof marked !== 'undefined') {
|
||||
return marked.parse(processedText);
|
||||
} else {
|
||||
// 降级使用之前的 simpleMarkdown
|
||||
return simpleMarkdown(processedText);
|
||||
} catch (e) { return match; }
|
||||
});
|
||||
}
|
||||
|
||||
// 2. 使用 marked 解析 Markdown (优先使用)
|
||||
if (typeof marked !== 'undefined') {
|
||||
// 兼容不同版本的 marked (UMD 版本中 marked 可能是函数或对象)
|
||||
const parseFn = (typeof marked.parse === 'function') ? marked.parse.bind(marked) : (typeof marked === 'function' ? marked : null);
|
||||
if (parseFn) {
|
||||
return parseFn(processedText);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 降级使用改进后的 simpleMarkdown
|
||||
return simpleMarkdown(processedText);
|
||||
} catch (e) {
|
||||
console.error('Markdown/LaTeX rendering error:', e);
|
||||
return text;
|
||||
console.error('Markdown rendering error:', e);
|
||||
return simpleMarkdown(text);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user