diff --git a/static/douyin.html b/static/douyin.html
index f57b4f7..563fc07 100644
--- a/static/douyin.html
+++ b/static/douyin.html
@@ -164,39 +164,53 @@
-
-
-
-
+
+
+
+
+
diff --git a/static/js/douyin.js b/static/js/douyin.js
index 6a10efc..1fa13e7 100644
--- a/static/js/douyin.js
+++ b/static/js/douyin.js
@@ -1,5 +1,75 @@
const { createApp, ref, computed, onMounted } = Vue;
+// 1. 全局渲染器 - 纯手写的高鲁棒性解析器,不再依赖 marked
+const globalRenderMarkdown = (text) => {
+ if (!text) return '';
+
+ // 0. 预处理:去除 AI 可能返回的代码块标记
+ let cleanText = text.trim();
+ // 去除开头的 ```markdown 或 ```
+ cleanText = cleanText.replace(/^```(markdown)?\s*/i, '');
+ // 去除结尾的 ```
+ cleanText = cleanText.replace(/```\s*$/, '');
+
+ // 1. 预处理:按行分割
+ const lines = cleanText.split('\n');
+ let html = '';
+ let inList = false;
+
+ for (let i = 0; i < lines.length; i++) {
+ let line = lines[i];
+ // 关键:去除行首尾空白,解决缩进导致的解析失败
+ let trimmed = line.trim();
+
+ // 空行处理
+ if (!trimmed) {
+ if (inList) { html += '\n'; inList = false; }
+ continue; // 忽略空行,或者可以加
+ }
+
+ // 2. 内联格式处理(加粗、代码、链接)
+ // 加粗 **text** -> text
+ trimmed = trimmed.replace(/\*\*(.*?)\*\*/g, '$1');
+ // 代码 `text` -> text
+ trimmed = trimmed.replace(/`([^`]+)`/g, '$1');
+
+ // 3. 块级元素处理
+ // 标题 ### Title
+ if (trimmed.startsWith('###')) {
+ if (inList) { html += '\n'; inList = false; }
+ html += `
${trimmed.replace(/^###\s*/, '')}
`;
+ }
+ else if (trimmed.startsWith('##')) {
+ if (inList) { html += '\n'; inList = false; }
+ html += `${trimmed.replace(/^##\s*/, '')}
`;
+ }
+ else if (trimmed.startsWith('#')) {
+ if (inList) { html += '\n'; inList = false; }
+ html += `${trimmed.replace(/^#\s*/, '')}
`;
+ }
+ // 列表 - Item 或 * Item
+ else if (trimmed.startsWith('- ') || trimmed.startsWith('* ')) {
+ if (!inList) { html += '\n'; inList = true; }
+ html += `- ${trimmed.substring(2)}
`;
+ }
+ // 数字列表 1. Item
+ else if (/^\d+\.\s/.test(trimmed)) {
+ // 简单起见,数字列表也用 ul,或者你可以维护一个 ordered list 状态
+ if (!inList) { html += '\n'; inList = true; }
+ html += `- ${trimmed.replace(/^\d+\.\s/, '')}
`;
+ }
+ // 普通段落
+ else {
+ if (inList) { html += '
\n'; inList = false; }
+ html += `${trimmed}
`;
+ }
+ }
+
+ if (inList) { html += '
\n'; }
+
+ return html;
+};
+
createApp({
setup() {
const apiBase = ref(window.location.origin || "http://localhost:8000");
@@ -15,96 +85,26 @@ createApp({
const summaryLoading = ref(false);
const summaryText = ref('');
- // 降级用的简易 Markdown 解析器
- const simpleMarkdown = (text) => {
- if (!text) return '';
- let lines = text.split('\n');
- let html = '';
- let inList = false;
- const parseInline = (str) => {
- return str
- .replace(/\*\*(.*?)\*\*/g, '$1')
- .replace(/`(.*?)`/g, '$1');
- };
- for (let line of lines) {
- let trimmed = line.trim();
- if (!trimmed) {
- if (inList) { html += ''; inList = false; }
- html += '
';
- continue;
- }
- if (trimmed.startsWith('### ')) {
- if (inList) { html += ''; inList = false; }
- html += `${parseInline(trimmed.substring(4))}
`;
- } else if (trimmed.startsWith('- ') || /^\d+\./.test(trimmed)) {
- if (!inList) { html += ''; inList = true; }
- let content = trimmed.replace(/^(- |\d+\. )/, '');
- html += `- ${parseInline(content)}
`;
- } else {
- if (inList) { html += '
'; inList = false; }
- html += `${parseInline(trimmed)}
`;
- }
- }
- if (inList) html += '';
- return html;
- };
-
- // Configure Marked
- if (typeof marked !== 'undefined') {
- marked.use({
- gfm: true,
- breaks: true
- });
- }
-
- // 增强的 Markdown & LaTeX 解析器
- const renderMarkdownAndLatex = (text) => {
- if (!text) return '';
-
- try {
- let processedText = text;
-
- // 1. 处理 LaTeX
- if (typeof katex !== 'undefined') {
- // 处理块级 LaTeX: $$ ... $$
- processedText = processedText.replace(/\$\$\s*([\s\S]*?)\s*\$\$/g, (match, formula) => {
- try {
- return '' + katex.renderToString(formula, { displayMode: true, throwOnError: false }) + '
';
- } catch (e) { return match; }
- });
-
- // 处理行内 LaTeX: $ ... $
- processedText = processedText.replace(/\$([^\$\n]+?)\$/g, (match, formula) => {
- try {
- return katex.renderToString(formula, { displayMode: false, throwOnError: false });
- } catch (e) { return match; }
- });
- }
-
- // 2. 使用 marked 解析 Markdown
- if (typeof marked !== 'undefined') {
- // marked v12+ 使用 marked.parse
- return marked.parse(processedText);
- } else {
- // 降级使用 simpleMarkdown
- return simpleMarkdown(processedText);
- }
- } catch (e) {
- console.error('Markdown rendering error:', e);
- // 最后的兜底:如果 marked 报错,尝试用 simpleMarkdown
- try {
- return simpleMarkdown(text);
- } catch (e2) {
- return text;
- }
- }
- };
-
+ // 使用全局渲染器
const renderedSummary = computed(() => {
if (!summaryText.value) return '';
- return renderMarkdownAndLatex(summaryText.value);
+ const html = globalRenderMarkdown(summaryText.value);
+ return html;
});
+ // 这里的配置仍然保留,作为双重保险
+ if (typeof marked !== 'undefined') {
+ const m = (typeof marked.marked === 'function') ? marked.marked : marked;
+ if (m.setOptions) {
+ m.setOptions({
+ gfm: true,
+ breaks: true,
+ mangle: false,
+ headerIds: false
+ });
+ }
+ }
+
// Methods
const startParsing = async () => {
if (!shareText.value.trim()) return;