fix(auto): markdown rendering for LLM answer and thinking blocks
This commit is contained in:
@@ -502,6 +502,44 @@ function escapeHtml(str) {
|
||||
return String(str).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');
|
||||
}
|
||||
|
||||
function renderMarkdown(text) {
|
||||
if (!text) return '';
|
||||
// Escape HTML first
|
||||
var html = escapeHtml(text);
|
||||
// Code blocks (```...```) — must be before inline code
|
||||
html = html.replace(/```(\w*)\n?([\s\S]*?)```/g, '<pre style="background:#1a1a2e;color:#e0e0e0;padding:0.5rem;border-radius:4px;font-size:0.78rem;overflow:auto;margin:0.4rem 0;"><code>$2</code></pre>');
|
||||
// Inline code
|
||||
html = html.replace(/`([^`]+)`/g, '<code style="background:#1a1a2e;color:#e0e0e0;padding:0.1rem 0.3rem;border-radius:3px;font-size:0.78rem;">$1</code>');
|
||||
// Bold (**text** or __text__)
|
||||
html = html.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>');
|
||||
html = html.replace(/__([^_]+)__/g, '<strong>$1</strong>');
|
||||
// Italic (*text* or _text_)
|
||||
html = html.replace(/\*([^*]+)\*/g, '<em>$1</em>');
|
||||
html = html.replace(/(?<!_)_{1}(?!_)([^_]+)_{1}(?!_)/g, '<em>$1</em>');
|
||||
// Links [text](url)
|
||||
html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2" target="_blank" style="color:#4361ee;">$1</a>');
|
||||
// Headers (# ## ###)
|
||||
html = html.replace(/^### (.+)$/gm, '<h4 style="margin:0.5rem 0 0.3rem;font-size:0.95rem;">$1</h4>');
|
||||
html = html.replace(/^## (.+)$/gm, '<h3 style="margin:0.5rem 0 0.3rem;font-size:1rem;">$1</h3>');
|
||||
html = html.replace(/^# (.+)$/gm, '<h2 style="margin:0.5rem 0 0.3rem;font-size:1.1rem;">$1</h2>');
|
||||
// Blockquotes
|
||||
html = html.replace(/^>\s?(.+)$/gm, '<blockquote style="border-left:3px solid #4361ee;padding:0.3rem 0.6rem;margin:0.3rem 0;background:#f0f4ff;border-radius:0 4px 4px 0;">$1</blockquote>');
|
||||
// Unordered lists
|
||||
html = html.replace(/^[\s]*[-*+]\s+(.+)$/gm, '<li style="margin:0.15rem 0;">$1</li>');
|
||||
html = html.replace(/(<li[\s\S]*?<\/li>)\n(?!<li)/g, function(m) { return '<ul style="padding-left:1.5rem;margin:0.3rem 0;">' + m + '</ul>'; });
|
||||
// Ordered lists
|
||||
html = html.replace(/^\d+\.\s+(.+)$/gm, '<li style="margin:0.15rem 0;">$1</li>');
|
||||
// Horizontal rules
|
||||
html = html.replace(/^---$/gm, '<hr style="border:none;border-top:1px solid #ddd;margin:0.5rem 0;">');
|
||||
// Paragraphs (double newlines → paragraphs)
|
||||
html = html.replace(/\n\n/g, '</p><p style="margin:0.4rem 0;">');
|
||||
// Line breaks (single newlines → br)
|
||||
html = html.replace(/\n/g, '<br>');
|
||||
// Wrap in paragraph if not already wrapped
|
||||
if (!html.startsWith('<')) html = '<p style="margin:0.4rem 0;">' + html + '</p>';
|
||||
return html;
|
||||
}
|
||||
|
||||
function prettyJson(obj) {
|
||||
try { return JSON.stringify(obj, null, 2); }
|
||||
catch(e) { return String(obj); }
|
||||
@@ -596,18 +634,18 @@ function renderTimeline(entries) {
|
||||
if (entry.type === 'thinking') {
|
||||
// 思考条目 — 浅蓝背景文本块
|
||||
const div = document.createElement('div');
|
||||
div.style.cssText = 'background:#eef2ff;padding:0.6rem;border-radius:6px;font-size:0.78rem;line-height:1.6;color:#333;max-height:200px;overflow:auto;margin-bottom:0.3rem;white-space:pre-wrap;border:1px solid #d0d8f0;';
|
||||
div.style.cssText = 'background:#eef2ff;padding:0.6rem;border-radius:6px;font-size:0.78rem;line-height:1.6;color:#333;max-height:300px;overflow:auto;margin-bottom:0.3rem;border:1px solid #d0d8f0;';
|
||||
div.innerHTML =
|
||||
'<span style="font-weight:600;color:#4361ee;font-size:0.75rem;display:block;margin-bottom:0.3rem;">💭 思考</span>' +
|
||||
escapeHtml(entry.text);
|
||||
renderMarkdown(entry.text);
|
||||
container.appendChild(div);
|
||||
} else if (entry.type === 'answer') {
|
||||
// 回答条目 — 绿色背景
|
||||
// 回答条目 — 绿色背景,支持 Markdown
|
||||
const div = document.createElement('div');
|
||||
div.style.cssText = 'background:#e8f5e9;padding:0.6rem;border-radius:6px;font-size:0.78rem;line-height:1.6;color:#333;max-height:300px;overflow:auto;margin-bottom:0.3rem;white-space:pre-wrap;border:1px solid #c8e6c9;';
|
||||
div.style.cssText = 'background:#e8f5e9;padding:0.6rem 0.8rem;border-radius:6px;font-size:0.82rem;line-height:1.7;color:#333;max-height:400px;overflow:auto;margin-bottom:0.3rem;border:1px solid #c8e6c9;';
|
||||
div.innerHTML =
|
||||
'<span style="font-weight:600;color:#2e7d32;font-size:0.75rem;display:block;margin-bottom:0.3rem;">✅ 回答</span>' +
|
||||
escapeHtml(entry.text);
|
||||
renderMarkdown(entry.text);
|
||||
container.appendChild(div);
|
||||
} else if (entry.type === 'tool') {
|
||||
const card = document.createElement('div');
|
||||
|
||||
Reference in New Issue
Block a user