deploy: 2026-07-15 14:57 部署更新

This commit is contained in:
selfrelease
2026-07-15 14:57:12 +08:00
parent 8e40d2c9b6
commit 8166dfa745
2 changed files with 112 additions and 31 deletions
+72 -18
View File
@@ -1138,10 +1138,10 @@ async function generateParadigm() {
<svg class="animate-spin w-5 h-5 text-green-600" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"/><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"/></svg>
<span class="text-sm text-gray-500">正在调用千问 LLM 生成标准范式对话...</span>
</div>
<pre id="paradigm-stream-text" class="text-xs text-gray-600 bg-gray-50 rounded p-3 max-h-96 overflow-auto whitespace-pre-wrap break-all font-mono"></pre>
<div id="paradigm-md" class="text-sm leading-relaxed"></div>
</div>
`;
const streamText = document.getElementById('paradigm-stream-text');
const mdContainer = document.getElementById('paradigm-md');
let fullContent = '';
try {
const productId = document.getElementById('paradigm-product-select').value;
@@ -1152,6 +1152,15 @@ async function generateParadigm() {
const reader = resp.body.getReader();
const decoder = new TextDecoder();
let buffer = '';
let renderRaf = null;
function scheduleRender() {
if (renderRaf) return;
renderRaf = requestAnimationFrame(() => {
renderRaf = null;
mdContainer.innerHTML = renderMarkdown(fullContent);
mdContainer.scrollTop = mdContainer.scrollHeight;
});
}
while (true) {
const { done, value } = await reader.read();
if (done) break;
@@ -1167,28 +1176,19 @@ async function generateParadigm() {
if (obj.error) throw new Error(obj.error);
if (obj.content) {
fullContent += obj.content;
streamText.textContent = fullContent;
streamText.scrollTop = streamText.scrollHeight;
scheduleRender();
}
} catch (e) {
// 忽略解析错误的行
}
}
}
// 尝试解析完整 JSON 并渲染结构化结果
try {
const data = JSON.parse(fullContent);
renderParadigm(data);
} catch (e) {
// JSON 解析失败,保留原始流式文本
result.innerHTML = `
<div class="bg-white rounded-lg shadow p-6">
<h3 class="text-lg font-bold mb-2">标准范式对话模板</h3>
<p class="text-sm text-orange-500 mb-3">LLM 返回内容无法解析为 JSON,以下为原始输出:</p>
<pre class="text-xs text-gray-600 bg-gray-50 rounded p-3 max-h-96 overflow-auto whitespace-pre-wrap break-all">${escapeHtml(fullContent)}</pre>
</div>
`;
}
// 最终渲染
if (renderRaf) cancelAnimationFrame(renderRaf);
mdContainer.innerHTML = renderMarkdown(fullContent);
// 移除加载动画
const loader = result.querySelector('.animate-spin');
if (loader) loader.parentElement.remove();
} catch (e) {
result.innerHTML = `<p class="text-sm text-red-500">生成失败: ${e.message}</p>`;
} finally {
@@ -1197,6 +1197,60 @@ async function generateParadigm() {
}
}
/** 轻量 Markdown 转 HTML 渲染器 */
function renderMarkdown(md) {
if (!md) return '';
const lines = md.split('\n');
let html = '';
let inList = false;
let inOrderedList = false;
for (let i = 0; i < lines.length; i++) {
let line = lines[i];
// 标题
if (/^### /.test(line)) {
if (inList) { html += '</ul>'; inList = false; }
if (inOrderedList) { html += '</ol>'; inOrderedList = false; }
html += `<h4 class="font-semibold text-base mt-4 mb-2 text-gray-800">${inlineMd(line.slice(4))}</h4>`;
} else if (/^## /.test(line)) {
if (inList) { html += '</ul>'; inList = false; }
if (inOrderedList) { html += '</ol>'; inOrderedList = false; }
html += `<h3 class="font-bold text-lg mt-5 mb-2 text-gray-900 border-b pb-1">${inlineMd(line.slice(3))}</h3>`;
} else if (/^# /.test(line)) {
if (inList) { html += '</ul>'; inList = false; }
if (inOrderedList) { html += '</ol>'; inOrderedList = false; }
html += `<h2 class="font-bold text-xl mt-5 mb-3 text-gray-900">${inlineMd(line.slice(2))}</h2>`;
} else if (/^[-*] /.test(line)) {
if (!inList) { html += '<ul class="space-y-1 ml-4 list-disc">'; inList = true; }
html += `<li>${inlineMd(line.slice(2))}</li>`;
} else if (/^\d+\. /.test(line)) {
if (!inOrderedList) { html += '<ol class="space-y-1 ml-5 list-decimal">'; inOrderedList = true; }
html += `<li>${inlineMd(line.replace(/^\d+\. /, ''))}</li>`;
} else if (line.trim() === '') {
if (inList) { html += '</ul>'; inList = false; }
if (inOrderedList) { html += '</ol>'; inOrderedList = false; }
html += '';
} else {
if (inList) { html += '</ul>'; inList = false; }
if (inOrderedList) { html += '</ol>'; inOrderedList = false; }
html += `<p class="mb-2">${inlineMd(line)}</p>`;
}
}
if (inList) html += '</ul>';
if (inOrderedList) html += '</ol>';
return html;
}
/** 行内 Markdown:粗体、行内代码、链接 */
function inlineMd(text) {
// 转义 HTML
text = escapeHtml(text);
// 粗体 **text**
text = text.replace(/\*\*(.+?)\*\*/g, '<strong class="font-semibold text-gray-900">$1</strong>');
// 行内代码 `code`
text = text.replace(/`(.+?)`/g, '<code class="bg-gray-100 px-1 rounded text-xs">$1</code>');
return text;
}
function renderParadigm(data) {
const result = document.getElementById('paradigm-result');
const stageColors = {