chore: 清理非必要的测试文件和文档

This commit is contained in:
2026-01-25 12:39:32 +08:00
parent bfaeaa2ca2
commit f5b1ac44d1
21 changed files with 0 additions and 5032 deletions

View File

@@ -1,187 +0,0 @@
# AI 评论审核流程说明
## 流程概述
本文档通过 Mermaid 流程图详细展示用户提交评论后,系统进行 AI 审核的全流程涵盖预处理、规则判断、AI 检测、结果处理、数据学习等核心环节。
## 流程图
::: mermaid
flowchart TD
Start([用户提交评论]) --> PreProcess[预处理评论<br/>钩子preprocess_comment/post_comment_preprocessing]
PreProcess --> CheckEnabled{启用 AI 检测?}
CheckEnabled -->|否| SaveComment[保存评论]
CheckEnabled -->|是| CheckMode{检测模式?}
CheckMode -->|manual关闭实时检测| SaveComment
CheckMode -->|keyword/sample/all| CheckLoggedIn{已登录用户?}
CheckLoggedIn -->|是且跳过登录用户| SaveComment
CheckLoggedIn -->|否或不跳过| CheckWhitelist{在白名单?}
CheckWhitelist -->|是| SaveComment
CheckWhitelist -->|否| CheckKeyword[检查关键字触发]
CheckKeyword --> DecideCheck{决定是否检测}
DecideCheck -->|keyword模式且触发关键字| NeedCheck[需要检测]
DecideCheck -->|sample模式且触发关键字| NeedCheck
DecideCheck -->|sample模式且随机抽中| NeedCheck
DecideCheck -->|all模式| NeedCheck
DecideCheck -->|其他情况| SaveComment
NeedCheck --> SetPending[强制设置 comment_approved=0<br/>待审核状态]
SetPending --> SetFlag[设置 _argon_needs_spam_check=true]
SetFlag --> SaveKeywords[保存触发的关键字]
SaveKeywords --> SaveComment
SaveComment --> CommentPost[评论入库后处理<br/>钩子comment_post/post_comment_updatemetas]
CommentPost --> SaveMeta[保存评论元数据]
SaveMeta --> CheckNeedFlag{有 _argon_needs_spam_check 标记?}
CheckNeedFlag -->|否| ShowPending[显示审核中状态]
CheckNeedFlag -->|是| SaveCheckMeta[保存检测标记到数据库]
SaveCheckMeta --> AutoDetect[触发自动检测<br/>钩子comment_post/argon_auto_detect_spam_on_comment]
AutoDetect --> CheckSaved{有检测标记?}
CheckSaved -->|否| End1([结束])
CheckSaved -->|是| CheckDetected{已检测过?}
CheckDetected -->|是| End2([结束])
CheckDetected -->|否| CheckReason{检测原因?}
CheckReason -->|关键字触发| SyncDetect[立即同步检测]
CheckReason -->|其他| AsyncDetect[异步检测延迟1秒]
SyncDetect --> DetectHandler[检测处理函数<br/>argon_async_spam_detection_handler]
AsyncDetect --> DetectHandler
DetectHandler --> CallAI[调用 AI API<br/>argon_detect_spam_comment]
CallAI --> GetPrompt[根据 Prompt 模式获取提示词]
CallAI --> BuildContext[构建评论上下文(用户名+内容)]
BuildContext --> SendAPI[发送到 AI API]
SendAPI --> ParseResult[解析 AI 返回结果]
ParseResult --> SaveTime[记录检测时间]
SaveTime --> GenCode[生成识别码]
GenCode --> UpdateStats[更新用户统计]
UpdateStats --> CheckResult{检测结果?}
CheckResult -->|内容违规(高置信度)| CheckAction1{自动处理方式?}
CheckResult -->|内容违规(低置信度)| MarkLowConf[标记为疑似垃圾<br/>等待人工审核]
CheckResult -->|内容正常/用户名违规/无邮箱| TrashNoEmail[移入回收站]
CheckResult -->|内容正常/用户名违规/有邮箱| ChangeUsername[修改用户名]
CheckResult -->|都正常| MarkNormal[标记为正常评论]
CheckAction1 -->|trash| TrashComment[移入回收站]
CheckAction1 -->|hold| HoldComment[标记为待审核]
CheckAction1 -->|mark| MarkOnly[仅标记不处理]
TrashComment --> SendSpamEmail[发送垃圾评论通知]
HoldComment --> SendSpamEmail
MarkOnly --> SaveResult1[保存检测结果]
SendSpamEmail --> SaveResult1
MarkLowConf --> SaveResult2[保存检测结果]
TrashNoEmail --> SaveResult3[保存检测结果]
ChangeUsername --> GenNewName[生成新用户名]
GenNewName --> UpdateDB[更新数据库]
UpdateDB --> SendChangeEmail[发送用户名变更通知]
SendChangeEmail --> SaveResult4[保存检测结果]
MarkNormal --> SaveResult5[保存检测结果]
SaveResult1 --> AILearn{启用 AI 学习?}
SaveResult2 --> AILearn
SaveResult3 --> AILearn
SaveResult4 --> AILearn
SaveResult5 --> AILearn
AILearn -->|是| ExtractKeywords[提取关键词]
AILearn -->|否| DetectEnd([检测完成])
ExtractKeywords --> UpdateKeywords[更新学习关键词库]
UpdateKeywords --> DetectEnd
ShowPending --> UserView([用户看到:审核中状态])
DetectEnd --> AdminReview([管理员审核])
style Start fill:#e1f5e1,stroke:#2e7d32,stroke-width:2px
style End1 fill:#ffe1e1,stroke:#c62828,stroke-width:2px
style End2 fill:#ffe1e1,stroke:#c62828,stroke-width:2px
style DetectEnd fill:#e1f5e1,stroke:#2e7d32,stroke-width:2px
style UserView fill:#fff4e1,stroke:#ff8f00,stroke-width:2px
style AdminReview fill:#e1e8ff,stroke:#1565c0,stroke-width:2px
style NeedCheck fill:#ffcccc,stroke:#c62828,stroke-width:1px
style SetPending fill:#ffcccc,stroke:#c62828,stroke-width:1px
style TrashComment fill:#ff6b6b,stroke:#c62828,stroke-width:1px
style TrashNoEmail fill:#ff6b6b,stroke:#c62828,stroke-width:1px
style HoldComment fill:#ffa500,stroke:#ff8f00,stroke-width:1px
style MarkLowConf fill:#ffa500,stroke:#ff8f00,stroke-width:1px
style ChangeUsername fill:#4ecdc4,stroke:#00897b,stroke-width:1px
style MarkNormal fill:#95e1d3,stroke:#2e7d32,stroke-width:1px
:::
## 流程关键节点说明
### 1. 预处理阶段
- 触发 `preprocess_comment`/`post_comment_preprocessing` 钩子,完成评论基础清洗。
- 优先判断是否启用 AI 检测,未启用则直接保存评论。
### 2. 检测规则判断
- 检测模式分 4 类manual关闭、keyword关键字、sample抽样、all全量
- 白名单用户、已登录且配置跳过的用户,直接跳过检测。
- keyword/sample 模式下,仅关键字触发/随机抽中时才启动检测。
### 3. AI 检测执行
- 关键字触发:立即同步检测;其他情况:延迟 1 秒异步检测。
- 调用 `argon_detect_spam_comment` 接口,拼接用户名+评论内容作为上下文发送 AI。
### 4. 结果处理逻辑
| 检测结果 | 处理方式 |
|-------------------------|-----------------------------------|
| 内容违规(高置信度)| 按配置自动处理(移入回收站/待审核/仅标记) |
| 内容违规(低置信度)| 标记疑似垃圾,等待人工审核 |
| 用户名违规(无邮箱)| 直接移入回收站 |
| 用户名违规(有邮箱)| 自动生成新用户名并通知用户 |
| 内容+用户名均正常 | 标记为正常评论 |
### 5. 后续环节
- 所有检测结果均保存至数据库,支持 AI 学习功能(提取关键词更新词库)。
- 用户侧仅展示"审核中"状态,最终结果需管理员复核。
## 技术说明
### 使用的钩子
- `preprocess_comment` - 评论预处理
- `post_comment_preprocessing` - 评论预处理(备用)
- `comment_post` - 评论入库后
- `post_comment_updatemetas` - 更新评论元数据
- `argon_auto_detect_spam_on_comment` - 自动检测触发
### 关键函数
- `argon_detect_spam_comment()` - AI 检测主函数
- `argon_async_spam_detection_handler()` - 异步检测处理
- `argon_get_spam_detection_prompt()` - 获取检测 Prompt
- `argon_build_comment_context()` - 构建评论上下文
### 数据库字段
- `comment_approved` - 评论审核状态0=待审核1=已通过)
- `_argon_needs_spam_check` - 是否需要 AI 检测标记
- `_argon_spam_detection_result` - AI 检测结果
- `_argon_spam_detection_time` - 检测时间戳
- `_argon_spam_keywords` - 触发的关键字
## 配置建议
### 小型博客(评论量 < 100/天)
- 检测模式keyword关键字触发
- Prompt 模式:标准模式
- 自动处理阈值:置信度 > 0.9
### 中型博客(评论量 100-500/天)
- 检测模式sample智能抽样
- Prompt 模式:标准模式
- 自动处理阈值:置信度 > 0.85
### 大型博客(评论量 > 500/天)
- 检测模式sample智能抽样 30-40%
- Prompt 模式:极简模式
- 自动处理阈值:置信度 > 0.8
- 定期批量扫描待审核评论
## 注意事项
1. **API 成本控制**:合理设置检测模式和抽样比例
2. **误判处理**:始终保留人工审核入口
3. **隐私保护**:不要将敏感信息发送给 AI
4. **性能优化**:关键字触发使用同步检测,其他使用异步
5. **定期优化**:根据误判率调整 Prompt 和阈值

View File

@@ -1,297 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mermaid 代码块魔改测试</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
background: #f5f5f5;
}
.test-case {
background: white;
padding: 20px;
margin-bottom: 20px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.test-case h3 {
margin-top: 0;
color: #333;
border-bottom: 2px solid #007bff;
padding-bottom: 10px;
}
.test-case .description {
color: #666;
margin-bottom: 15px;
font-size: 14px;
}
.mermaid-from-codeblock {
background: #f8f9fa;
padding: 15px;
border-radius: 4px;
border: 1px solid #dee2e6;
}
pre {
background: #f8f9fa;
padding: 15px;
border-radius: 4px;
border: 1px solid #dee2e6;
overflow-x: auto;
}
code {
font-family: 'Courier New', Courier, monospace;
}
</style>
<!-- Mermaid 库 -->
<script src="https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js"></script>
</head>
<body>
<h1>Mermaid 代码块魔改测试</h1>
<p>本页面用于测试标准 Markdown 代码块 (<code>```mermaid</code>) 的 Mermaid 图表渲染功能。</p>
<!-- 测试用例 1标准格式 -->
<div class="test-case">
<h3>测试用例 1标准 Markdown 格式</h3>
<div class="description">
格式:<code>&lt;pre&gt;&lt;code class="language-mermaid"&gt;</code>
</div>
<pre><code class="language-mermaid">
flowchart TD
A[开始] --> B{判断}
B -->|是| C[执行操作]
B -->|否| D[跳过]
C --> E[结束]
D --> E
</code></pre>
</div>
<!-- 测试用例 2多个代码块 -->
<div class="test-case">
<h3>测试用例 2多个代码块批量处理</h3>
<div class="description">
测试同一页面中多个 Mermaid 代码块的处理
</div>
<pre><code class="language-mermaid">
graph LR
A[客户端] --> B[服务器]
B --> C[数据库]
C --> B
B --> A
</code></pre>
<br>
<pre><code class="language-mermaid">
sequenceDiagram
participant 用户
participant 系统
用户->>系统: 发送请求
系统->>用户: 返回响应
</code></pre>
</div>
<!-- 测试用例 3特殊字符 -->
<div class="test-case">
<h3>测试用例 3特殊字符保留</h3>
<div class="description">
测试箭头符号 <code>--&gt;</code>、双横线 <code>--</code>、等号 <code>==</code> 等特殊字符是否正确保留
</div>
<pre><code class="language-mermaid">
flowchart TD
A --> B
B -- 文本 --> C
C ==> D
D -.-> E
E ~~~ F
</code></pre>
</div>
<!-- 测试用例 4空代码块 -->
<div class="test-case">
<h3>测试用例 4空代码块边界情况</h3>
<div class="description">
测试空代码块是否会导致错误
</div>
<pre><code class="language-mermaid"></code></pre>
<p style="color: #666; font-size: 14px;">空代码块应该被跳过,不会创建容器</p>
</div>
<!-- 测试用例 5多行代码块 -->
<div class="test-case">
<h3>测试用例 5多行代码块换行符保留</h3>
<div class="description">
测试多行代码块中的换行符是否正确保留
</div>
<pre><code class="language-mermaid">
graph TB
subgraph 子图1
A1[节点A1]
A2[节点A2]
end
subgraph 子图2
B1[节点B1]
B2[节点B2]
end
A1 --> B1
A2 --> B2
</code></pre>
</div>
<!-- 测试用例 6简化格式 -->
<div class="test-case">
<h3>测试用例 6简化格式</h3>
<div class="description">
格式:<code>&lt;pre&gt;&lt;code class="mermaid"&gt;</code>
</div>
<pre><code class="mermaid">
pie title 数据分布
"类别A" : 45
"类别B" : 30
"类别C" : 25
</code></pre>
</div>
<!-- 测试用例 7无 pre 包裹 -->
<div class="test-case">
<h3>测试用例 7无 pre 包裹</h3>
<div class="description">
格式:<code>&lt;code class="language-mermaid"&gt;</code>(无 pre 标签)
</div>
<code class="language-mermaid">
flowchart LR
Start --> Stop
</code>
</div>
<!-- 测试用例 8自定义属性格式 -->
<div class="test-case">
<h3>测试用例 8自定义属性格式</h3>
<div class="description">
格式:<code>&lt;pre data-lang="mermaid"&gt;</code>
</div>
<pre data-lang="mermaid">
stateDiagram-v2
[*] --> 状态1
状态1 --> 状态2
状态2 --> [*]
</pre>
</div>
<!-- 测试用例 9复杂图表 -->
<div class="test-case">
<h3>测试用例 9复杂图表</h3>
<div class="description">
测试复杂的 Mermaid 图表渲染
</div>
<pre><code class="language-mermaid">
classDiagram
Animal <|-- Duck
Animal <|-- Fish
Animal <|-- Zebra
Animal : +int age
Animal : +String gender
Animal: +isMammal()
Animal: +mate()
class Duck{
+String beakColor
+swim()
+quack()
}
class Fish{
-int sizeInFeet
-canEat()
}
class Zebra{
+bool is_wild
+run()
}
</code></pre>
</div>
<script>
// 初始化 Mermaid
mermaid.initialize({
startOnLoad: false,
theme: 'default',
securityLevel: 'loose'
});
// 模拟主题的 convertMermaidCodeblocks 函数
function convertMermaidCodeblocks(){
const selectors = [
'pre > code.language-mermaid',
'pre > code.mermaid',
'code.language-mermaid',
'pre[data-lang="mermaid"]'
];
let processedCount = 0;
selectors.forEach(selector => {
document.querySelectorAll(selector).forEach(element => {
if (element.dataset.mermaidProcessed) {
return;
}
let code = element.textContent.trim();
if (!code) {
return;
}
const container = document.createElement('div');
container.className = 'mermaid-from-codeblock';
container.textContent = code;
container.dataset.processed = 'true';
const targetElement = element.closest('pre') || element;
if (targetElement.parentNode) {
targetElement.parentNode.replaceChild(container, targetElement);
processedCount++;
}
element.dataset.mermaidProcessed = 'true';
});
});
console.log('[Mermaid] 转换了 ' + processedCount + ' 个代码块');
}
// 渲染 Mermaid 图表
function renderMermaidCharts(){
const blocks = document.querySelectorAll('.mermaid-from-codeblock');
console.log('[Mermaid] 找到 ' + blocks.length + ' 个待渲染的图表');
blocks.forEach((block, index) => {
const id = 'mermaid-' + Date.now() + '-' + index;
const code = block.textContent;
try {
// Mermaid 10.x 使用 render 方法,返回 Promise
mermaid.render(id, code).then(function(result) {
block.innerHTML = result.svg;
console.log('[Mermaid] 成功渲染图表 ' + (index + 1));
}).catch(function(error) {
console.error('[Mermaid] 渲染失败:', error);
block.innerHTML = '<div style="color: red; padding: 10px; border: 1px solid red; border-radius: 4px;">渲染失败: ' + error.message + '</div>';
});
} catch (error) {
console.error('[Mermaid] 渲染异常:', error);
block.innerHTML = '<div style="color: red; padding: 10px; border: 1px solid red; border-radius: 4px;">渲染异常: ' + error.message + '</div>';
}
});
}
// 页面加载完成后执行
document.addEventListener('DOMContentLoaded', function(){
console.log('[测试] 开始执行代码块转换');
convertMermaidCodeblocks();
console.log('[测试] 开始渲染 Mermaid 图表');
setTimeout(renderMermaidCharts, 100);
});
</script>
</body>
</html>

View File

@@ -1,374 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mermaid 库加载失败降级处理测试</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
background: #f5f5f5;
}
.test-section {
background: white;
border-radius: 8px;
padding: 20px;
margin-bottom: 20px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
h1 {
color: #333;
border-bottom: 2px solid #5e72e4;
padding-bottom: 10px;
}
h2 {
color: #5e72e4;
margin-top: 0;
}
.mermaid {
background: #f8f9fa;
padding: 20px;
border-radius: 4px;
margin: 10px 0;
}
.mermaid-error-container {
background: #fff5f5;
border: 1px solid #fc8181;
border-radius: 8px;
padding: 20px;
margin: 20px 0;
}
.mermaid-error-header {
display: flex;
align-items: center;
margin-bottom: 15px;
}
.mermaid-error-icon {
font-size: 24px;
margin-right: 10px;
}
.mermaid-error-title {
font-size: 18px;
font-weight: bold;
color: #c53030;
}
.mermaid-error-body {
margin-bottom: 15px;
}
.mermaid-error-type {
font-weight: bold;
color: #742a2a;
margin: 5px 0;
}
.mermaid-error-message {
color: #742a2a;
margin: 5px 0;
}
.mermaid-error-code {
margin-top: 10px;
}
.mermaid-error-code summary {
cursor: pointer;
color: #5e72e4;
font-weight: bold;
}
.mermaid-error-code pre {
background: #2d3748;
color: #e2e8f0;
padding: 15px;
border-radius: 4px;
overflow-x: auto;
margin-top: 10px;
}
.test-log {
background: #2d3748;
color: #e2e8f0;
padding: 15px;
border-radius: 4px;
font-family: 'Courier New', monospace;
font-size: 14px;
max-height: 300px;
overflow-y: auto;
margin-top: 10px;
}
.test-log div {
margin: 5px 0;
}
.log-info {
color: #63b3ed;
}
.log-warn {
color: #f6ad55;
}
.log-error {
color: #fc8181;
}
.log-success {
color: #68d391;
}
.test-controls {
margin: 20px 0;
}
.test-controls button {
background: #5e72e4;
color: white;
border: none;
padding: 10px 20px;
border-radius: 4px;
cursor: pointer;
margin-right: 10px;
font-size: 14px;
}
.test-controls button:hover {
background: #4c63d2;
}
.test-controls button:disabled {
background: #cbd5e0;
cursor: not-allowed;
}
</style>
</head>
<body>
<h1>🧪 Mermaid 库加载失败降级处理测试</h1>
<div class="test-section">
<h2>测试说明</h2>
<p>本测试页面用于验证 Mermaid 库加载失败时的降级处理机制。</p>
<ul>
<li><strong>测试 1</strong>: 主 CDN 加载失败,自动尝试备用 CDN</li>
<li><strong>测试 2</strong>: 所有 CDN 都失败,显示友好的错误提示</li>
<li><strong>测试 3</strong>: 备用 CDN 加载成功,正常渲染图表</li>
</ul>
</div>
<div class="test-section">
<h2>测试控制</h2>
<div class="test-controls">
<button onclick="testFailedMainCDN()">测试 1: 主 CDN 失败</button>
<button onclick="testAllCDNsFailed()">测试 2: 所有 CDN 失败</button>
<button onclick="testSuccessfulFallback()">测试 3: 备用 CDN 成功</button>
<button onclick="clearLog()">清空日志</button>
</div>
<div id="testLog" class="test-log"></div>
</div>
<div class="test-section">
<h2>测试图表</h2>
<div class="mermaid">
flowchart TD
A[开始] --> B{主 CDN 加载}
B -->|成功| C[渲染图表]
B -->|失败| D[尝试备用 CDN 1]
D -->|成功| C
D -->|失败| E[尝试备用 CDN 2]
E -->|成功| C
E -->|失败| F[显示错误提示]
</div>
</div>
<script>
// 模拟降级处理脚本
(function() {
'use strict';
// 备用 CDN URL 列表
const fallbackUrls = [
'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js',
'https://unpkg.com/mermaid@10/dist/mermaid.min.js',
'https://cdnjs.cloudflare.com/ajax/libs/mermaid/10.0.0/mermaid.min.js'
];
let loadAttempted = false;
// 日志函数
function log(message, type = 'info') {
const logDiv = document.getElementById('testLog');
const timestamp = new Date().toLocaleTimeString();
const logEntry = document.createElement('div');
logEntry.className = `log-${type}`;
logEntry.textContent = `[${timestamp}] ${message}`;
logDiv.appendChild(logEntry);
logDiv.scrollTop = logDiv.scrollHeight;
// 同时输出到控制台
console.log(`[Argon Mermaid] ${message}`);
}
/**
* 尝试从备用 CDN 加载 Mermaid 库
*/
window.argonMermaidLoadFallback = function() {
// 避免重复调用
if (loadAttempted) {
return;
}
loadAttempted = true;
log('主 CDN 加载失败,尝试备用 CDN', 'warn');
// 尝试加载备用 CDN
loadMermaidWithFallback(fallbackUrls, 0);
};
/**
* 递归加载备用 CDN
* @param {Array} urls - CDN URL 列表
* @param {number} index - 当前尝试的索引
*/
function loadMermaidWithFallback(urls, index) {
// 如果所有 CDN 都失败了
if (index >= urls.length) {
log('所有 CDN 加载失败', 'error');
showGlobalError();
return;
}
const url = urls[index];
log(`尝试从备用 CDN 加载: ${url}`, 'info');
// 创建 script 标签
const script = document.createElement('script');
script.src = url;
script.async = true;
// 加载失败,尝试下一个 CDN
script.onerror = function() {
log(`CDN ${url} 加载失败`, 'warn');
loadMermaidWithFallback(urls, index + 1);
};
// 加载成功,初始化 Mermaid
script.onload = function() {
log(`成功从备用 CDN 加载: ${url}`, 'success');
// 初始化 Mermaid
if (typeof window.mermaid !== 'undefined') {
window.mermaid.initialize({
startOnLoad: true,
theme: 'default'
});
log('Mermaid 初始化成功', 'success');
}
};
// 添加到页面
document.head.appendChild(script);
}
/**
* 显示全局错误提示
*/
function showGlobalError() {
// 查找所有 Mermaid 代码块
const selectors = [
'div.mermaid',
'pre code.language-mermaid',
'pre[data-lang="mermaid"]',
'code.mermaid'
];
let blocks = [];
selectors.forEach(function(selector) {
const elements = document.querySelectorAll(selector);
elements.forEach(function(element) {
if (!blocks.includes(element)) {
blocks.push(element);
}
});
});
log(`找到 ${blocks.length} 个 Mermaid 代码块,显示错误提示`, 'info');
// 在每个代码块位置显示错误提示
blocks.forEach(function(block) {
const errorContainer = document.createElement('div');
errorContainer.className = 'mermaid-error-container';
errorContainer.innerHTML = `
<div class="mermaid-error-header">
<span class="mermaid-error-icon">⚠️</span>
<span class="mermaid-error-title">Mermaid 库加载失败</span>
</div>
<div class="mermaid-error-body">
<p class="mermaid-error-type">错误类型: 网络错误</p>
<p class="mermaid-error-message">无法从任何 CDN 加载 Mermaid 库,请检查网络连接或联系管理员。</p>
</div>
<details class="mermaid-error-code">
<summary>查看原始代码</summary>
<pre><code class="language-mermaid">${escapeHtml(block.textContent)}</code></pre>
</details>
`;
block.parentNode.replaceChild(errorContainer, block);
});
}
/**
* HTML 转义
* @param {string} text - 要转义的文本
* @returns {string} 转义后的文本
*/
function escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
// 测试函数
window.testFailedMainCDN = function() {
log('=== 开始测试 1: 主 CDN 失败 ===', 'info');
loadAttempted = false;
argonMermaidLoadFallback();
};
window.testAllCDNsFailed = function() {
log('=== 开始测试 2: 所有 CDN 失败 ===', 'info');
loadAttempted = false;
// 使用无效的 URL 列表
loadMermaidWithFallback(['https://invalid-cdn-1.com/mermaid.js', 'https://invalid-cdn-2.com/mermaid.js'], 0);
};
window.testSuccessfulFallback = function() {
log('=== 开始测试 3: 备用 CDN 成功 ===', 'info');
loadAttempted = false;
// 直接加载有效的 CDN
loadMermaidWithFallback(fallbackUrls, 0);
};
window.clearLog = function() {
document.getElementById('testLog').innerHTML = '';
log('日志已清空', 'info');
};
// 页面加载完成后的初始化
log('测试页面加载完成', 'success');
log('点击上方按钮开始测试', 'info');
})();
</script>
</body>
</html>

View File

@@ -1,276 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mermaid 修复测试</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
background: #f5f5f5;
}
.test-section {
background: white;
padding: 20px;
margin-bottom: 20px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.test-section h2 {
color: #5e72e4;
border-bottom: 2px solid #5e72e4;
padding-bottom: 10px;
}
.test-case {
margin: 15px 0;
padding: 15px;
background: #f8f9fa;
border-left: 4px solid #5e72e4;
}
.test-case h3 {
margin-top: 0;
color: #333;
}
.expected {
color: #28a745;
font-weight: bold;
}
.code-block {
background: #2d2d2d;
color: #d4d4d4;
padding: 15px;
border-radius: 4px;
overflow-x: auto;
font-family: 'Courier New', monospace;
font-size: 14px;
}
.mermaid {
background: white;
padding: 20px;
border: 1px solid #ddd;
border-radius: 4px;
margin: 10px 0;
}
pre code.language-mermaid {
display: block;
background: #f8f9fa;
padding: 15px;
border: 2px dashed #5e72e4;
border-radius: 4px;
}
</style>
</head>
<body>
<h1>🧪 Mermaid 修复测试页面</h1>
<p>本页面用于测试两个关键修复:</p>
<ol>
<li><strong>代码高亮排除 mermaid</strong>mermaid 代码块不应被代码高亮处理</li>
<li><strong>容器语法处理空行</strong>:容器语法中的空行应被正确保留</li>
</ol>
<!-- 测试 1: 代码高亮排除 -->
<div class="test-section">
<h2>测试 1: 代码高亮排除 Mermaid</h2>
<div class="test-case">
<h3>测试 1.1: 标准 Markdown 格式(应该被排除)</h3>
<p class="expected">✅ 预期:不应出现代码高亮窗口,直接渲染为 Mermaid 图表</p>
<pre><code class="language-mermaid">
flowchart TD
A[开始] --> B[处理]
B --> C[结束]
</code></pre>
</div>
<div class="test-case">
<h3>测试 1.2: 标准 div.mermaid 格式(应该被排除)</h3>
<p class="expected">✅ 预期:不应出现代码高亮窗口,直接渲染为 Mermaid 图表</p>
<div class="mermaid">
flowchart LR
A[用户] --> B{登录?}
B -->|是| C[显示首页]
B -->|否| D[跳转登录页]
</div>
</div>
<div class="test-case">
<h3>测试 1.3: 普通代码块(应该被高亮)</h3>
<p class="expected">✅ 预期:应该出现代码高亮窗口</p>
<pre><code class="language-javascript">
function hello() {
console.log('Hello World');
}
</code></pre>
</div>
</div>
<!-- 测试 2: 容器语法空行处理 -->
<div class="test-section">
<h2>测试 2: 容器语法空行处理</h2>
<div class="test-case">
<h3>测试 2.1: 包含空行的流程图</h3>
<p class="expected">✅ 预期:空行应被保留,图表正常渲染</p>
<div class="code-block">
::: mermaid
flowchart TD
A[开始]
B[处理步骤1]
C[处理步骤2]
D[结束]
A --> B
B --> C
C --> D
:::
</div>
<p>实际渲染:</p>
<p>
::: mermaid
flowchart TD
A[开始]
B[处理步骤1]
C[处理步骤2]
D[结束]
A --> B
B --> C
C --> D
:::
</p>
</div>
<div class="test-case">
<h3>测试 2.2: 包含空行的时序图</h3>
<p class="expected">✅ 预期:空行应被保留,图表正常渲染</p>
<div class="code-block">
::: mermaid
sequenceDiagram
participant A as Alice
participant B as Bob
A->>B: Hello Bob!
Note over A,B: 这是一个注释
B-->>A: Hi Alice!
:::
</div>
<p>实际渲染:</p>
<p>
::: mermaid
sequenceDiagram
participant A as Alice
participant B as Bob
A->>B: Hello Bob!
Note over A,B: 这是一个注释
B-->>A: Hi Alice!
:::
</p>
</div>
<div class="test-case">
<h3>测试 2.3: 包含多个连续空行</h3>
<p class="expected">✅ 预期:多个空行应被保留,图表正常渲染</p>
<div class="code-block">
::: mermaid
flowchart LR
A[步骤A]
B[步骤B]
C[步骤C]
A --> B --> C
:::
</div>
<p>实际渲染:</p>
<p>
::: mermaid
flowchart LR
A[步骤A]
B[步骤B]
C[步骤C]
A --> B --> C
:::
</p>
</div>
</div>
<!-- 测试 3: WP-Markdown 格式 -->
<div class="test-section">
<h2>测试 3: WP-Markdown 格式兼容性</h2>
<div class="test-case">
<h3>测试 3.1: document.write 格式</h3>
<p class="expected">✅ 预期:正确提取代码并渲染</p>
<div class="mermaid">
<script>document.write("flowchart TD\n A[开始] --> B[结束]")</script>
</div>
</div>
</div>
<!-- 测试结果说明 -->
<div class="test-section">
<h2>📋 测试检查清单</h2>
<ul>
<li>
<input type="checkbox" id="check1">
<label for="check1">测试 1.1: Markdown 格式的 mermaid 代码块没有代码高亮窗口</label>
</li>
<li>
<input type="checkbox" id="check2">
<label for="check2">测试 1.2: div.mermaid 格式没有代码高亮窗口</label>
</li>
<li>
<input type="checkbox" id="check3">
<label for="check3">测试 1.3: 普通 JavaScript 代码有代码高亮窗口</label>
</li>
<li>
<input type="checkbox" id="check4">
<label for="check4">测试 2.1: 包含空行的流程图正常渲染</label>
</li>
<li>
<input type="checkbox" id="check5">
<label for="check5">测试 2.2: 包含空行的时序图正常渲染</label>
</li>
<li>
<input type="checkbox" id="check6">
<label for="check6">测试 2.3: 包含多个连续空行的图表正常渲染</label>
</li>
<li>
<input type="checkbox" id="check7">
<label for="check7">测试 3.1: WP-Markdown 格式正常渲染</label>
</li>
</ul>
</div>
<script>
// 简单的日志输出
console.log('[Mermaid Test] 测试页面已加载');
console.log('[Mermaid Test] 请检查:');
console.log('[Mermaid Test] 1. mermaid 代码块是否被代码高亮处理');
console.log('[Mermaid Test] 2. 容器语法中的空行是否被正确保留');
console.log('[Mermaid Test] 3. 所有图表是否正常渲染');
</script>
</body>
</html>

View File

@@ -1,186 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mermaid 换行符测试</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
background: #f5f5f5;
}
.test-case {
background: white;
padding: 20px;
margin: 20px 0;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
h2 {
color: #333;
border-bottom: 2px solid #007bff;
padding-bottom: 10px;
}
.success {
color: green;
font-weight: bold;
}
.error {
color: red;
font-weight: bold;
}
pre {
background: #f4f4f4;
padding: 10px;
border-radius: 4px;
overflow-x: auto;
}
</style>
</head>
<body>
<h1>Mermaid 换行符测试</h1>
<p>测试 WP-Markdown 生成的 HTML 中 &lt;br&gt; 标签是否正确转换为换行符</p>
<!-- 测试用例 1: 模拟 WP-Markdown 生成的 HTML -->
<div class="test-case">
<h2>测试 1: 模拟 WP-Markdown 格式(带 &lt;br&gt; 标签)</h2>
<p>::: mermaid<br>
flowchart TD<br>
Start([开始]) --> Process[处理]<br>
Process --> End([结束])<br>
:::</p>
<div id="result1"></div>
</div>
<!-- 测试用例 2: 复杂流程图 -->
<div class="test-case">
<h2>测试 2: 复杂流程图(多行文本)</h2>
<p>::: mermaid<br>
flowchart TD<br>
A[用户提交评论] --> B{启用 AI 检测?}<br>
B -->|是| C[AI 检测]<br>
B -->|否| D[直接保存]<br>
C --> E{检测结果?}<br>
E -->|垃圾评论| F[移入回收站]<br>
E -->|正常评论| G[保存评论]<br>
:::</p>
<div id="result2"></div>
</div>
<!-- 测试用例 3: 带样式的流程图 -->
<div class="test-case">
<h2>测试 3: 带样式定义</h2>
<p>::: mermaid<br>
flowchart LR<br>
A[开始] --> B[处理]<br>
B --> C[结束]<br>
style A fill:#e1f5e1,stroke:#2e7d32<br>
style C fill:#ffe1e1,stroke:#c62828<br>
:::</p>
<div id="result3"></div>
</div>
<script src="https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js"></script>
<script>
// 模拟 Argon 主题的 htmlToText 函数
function htmlToText(html) {
// 将 <br> 和 <br/> 转换为换行符
let text = html.replace(/<br\s*\/?>/gi, '\n');
// 移除其他 HTML 标签
text = text.replace(/<[^>]+>/g, '');
// 解码 HTML 实体
text = text
.replace(/&nbsp;/g, ' ')
.replace(/&lt;/g, '<')
.replace(/&gt;/g, '>')
.replace(/&amp;/g, '&')
.replace(/&quot;/g, '"')
.replace(/&#039;/g, "'");
return text;
}
// 提取容器语法内容
function extractContainerContent(element) {
let html = element.innerHTML;
let text = element.textContent.trim();
console.log('[测试] 原始 HTML:', html);
console.log('[测试] 原始文本:', text);
if (!text.startsWith('::: mermaid')) {
return null;
}
// 使用 htmlToText 转换
let content = htmlToText(html);
console.log('[测试] 转换后文本:', content);
// 移除开始和结束标记
content = content.replace(/^:::\s*mermaid\s*/i, '').trim();
content = content.replace(/:::\s*$/, '').trim();
console.log('[测试] 最终代码:', content);
return content;
}
// 测试函数
function testMermaid(testId, resultId) {
const element = document.querySelector(`#${testId}`).previousElementSibling;
const resultDiv = document.getElementById(resultId);
try {
const code = extractContainerContent(element);
if (!code) {
resultDiv.innerHTML = '<p class="error">❌ 提取失败:未找到代码</p>';
return;
}
// 检查换行符
const lines = code.split('\n');
console.log(`[测试 ${testId}] 提取到 ${lines.length} 行代码`);
// 渲染图表
mermaid.render(`mermaid-${testId}`, code).then(result => {
resultDiv.innerHTML = `
<p class="success">✅ 渲染成功</p>
<p>提取到 ${lines.length} 行代码</p>
<details>
<summary>查看提取的代码</summary>
<pre>${code}</pre>
</details>
${result.svg}
`;
}).catch(error => {
resultDiv.innerHTML = `
<p class="error">❌ 渲染失败: ${error.message}</p>
<details>
<summary>查看提取的代码</summary>
<pre>${code}</pre>
</details>
`;
});
} catch (error) {
resultDiv.innerHTML = `<p class="error">❌ 错误: ${error.message}</p>`;
}
}
// 初始化
document.addEventListener('DOMContentLoaded', function() {
mermaid.initialize({
startOnLoad: false,
theme: 'default',
securityLevel: 'loose'
});
// 运行测试
testMermaid('test1', 'result1');
testMermaid('test2', 'result2');
testMermaid('test3', 'result3');
});
</script>
</body>
</html>

View File

@@ -1,383 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mermaid 图表尺寸优化测试</title>
<link rel="stylesheet" href="../style.css">
<style>
body {
font-family: Arial, sans-serif;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
background: #f5f5f5;
}
.test-section {
background: white;
padding: 20px;
margin-bottom: 20px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.test-section h2 {
color: #5e72e4;
border-bottom: 2px solid #5e72e4;
padding-bottom: 10px;
margin-top: 0;
}
.test-case {
margin: 20px 0;
padding: 15px;
background: #f8f9fa;
border-left: 4px solid #5e72e4;
}
.test-case h3 {
margin-top: 0;
color: #333;
font-size: 16px;
}
.expected {
color: #28a745;
font-weight: bold;
margin: 10px 0;
}
.info {
color: #666;
font-size: 14px;
margin: 5px 0;
}
.toggle-theme {
position: fixed;
top: 20px;
right: 20px;
padding: 10px 20px;
background: #5e72e4;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
z-index: 1000;
}
.toggle-theme:hover {
background: #4c63d2;
}
</style>
</head>
<body>
<button class="toggle-theme" onclick="toggleTheme()">🌓 切换夜间模式</button>
<h1>🎨 Mermaid 图表尺寸优化测试</h1>
<p>本页面用于测试 Mermaid 图表的尺寸优化,确保低内容图表不会显示过大。</p>
<!-- 测试 1: 极简图表 -->
<div class="test-section">
<h2>测试 1: 极简图表2-3个节点</h2>
<div class="test-case">
<h3>1.1 简单流程图2个节点</h3>
<p class="expected">✅ 预期:图表高度不超过 600px居中显示</p>
<p class="info">优化前:可能显示超大,占据整个屏幕</p>
<div class="mermaid-container">
<div class="mermaid">
flowchart TD
A[开始] --> B[结束]
</div>
</div>
</div>
<div class="test-case">
<h3>1.2 简单流程图3个节点</h3>
<p class="expected">✅ 预期:图表高度不超过 600px居中显示</p>
<div class="mermaid-container">
<div class="mermaid">
flowchart LR
A[输入] --> B[处理] --> C[输出]
</div>
</div>
</div>
<div class="test-case">
<h3>1.3 简单判断流程</h3>
<p class="expected">✅ 预期:图表高度不超过 600px居中显示</p>
<div class="mermaid-container">
<div class="mermaid">
flowchart TD
A[用户] --> B{登录?}
B -->|是| C[首页]
B -->|否| D[登录页]
</div>
</div>
</div>
</div>
<!-- 测试 2: 中等复杂度图表 -->
<div class="test-section">
<h2>测试 2: 中等复杂度图表5-10个节点</h2>
<div class="test-case">
<h3>2.1 标准流程图</h3>
<p class="expected">✅ 预期:图表高度不超过 600px自适应内容</p>
<div class="mermaid-container">
<div class="mermaid">
flowchart TD
A[开始] --> B[输入数据]
B --> C{数据有效?}
C -->|是| D[处理数据]
C -->|否| E[显示错误]
D --> F[保存结果]
E --> G[结束]
F --> G
</div>
</div>
</div>
<div class="test-case">
<h3>2.2 时序图</h3>
<p class="expected">✅ 预期:图表高度不超过 600px</p>
<div class="mermaid-container">
<div class="mermaid">
sequenceDiagram
participant U as 用户
participant F as 前端
participant B as 后端
participant D as 数据库
U->>F: 提交表单
F->>B: 发送请求
B->>D: 查询数据
D-->>B: 返回结果
B-->>F: 返回响应
F-->>U: 显示结果
</div>
</div>
</div>
</div>
<!-- 测试 3: 复杂图表 -->
<div class="test-section">
<h2>测试 3: 复杂图表10+个节点)</h2>
<div class="test-case">
<h3>3.1 复杂流程图</h3>
<p class="expected">✅ 预期:图表高度限制在 600px出现滚动条</p>
<p class="info">优化:超过最大高度时,容器会出现垂直滚动条</p>
<div class="mermaid-container">
<div class="mermaid">
flowchart TD
A[开始] --> B[初始化]
B --> C{检查权限}
C -->|有权限| D[加载配置]
C -->|无权限| E[显示错误]
D --> F{配置有效?}
F -->|是| G[连接数据库]
F -->|否| H[使用默认配置]
G --> I{连接成功?}
I -->|是| J[加载数据]
I -->|否| K[重试连接]
K --> L{重试次数<3?}
L -->|是| G
L -->|否| M[连接失败]
H --> J
J --> N[处理数据]
N --> O{处理成功?}
O -->|是| P[显示结果]
O -->|否| Q[显示错误]
P --> R[记录日志]
Q --> R
E --> R
M --> R
R --> S[结束]
</div>
</div>
</div>
<div class="test-case">
<h3>3.2 类图</h3>
<p class="expected">✅ 预期:图表高度限制在 600px</p>
<div class="mermaid-container">
<div class="mermaid">
classDiagram
class Animal {
+String name
+int age
+makeSound()
+eat()
}
class Dog {
+String breed
+bark()
+fetch()
}
class Cat {
+String color
+meow()
+scratch()
}
class Bird {
+boolean canFly
+sing()
+fly()
}
Animal <|-- Dog
Animal <|-- Cat
Animal <|-- Bird
</div>
</div>
</div>
</div>
<!-- 测试 4: 横向图表 -->
<div class="test-section">
<h2>测试 4: 横向图表(宽度测试)</h2>
<div class="test-case">
<h3>4.1 横向流程图</h3>
<p class="expected">✅ 预期:宽度自适应,出现横向滚动条</p>
<div class="mermaid-container">
<div class="mermaid">
flowchart LR
A[步骤1] --> B[步骤2] --> C[步骤3] --> D[步骤4] --> E[步骤5]
E --> F[步骤6] --> G[步骤7] --> H[步骤8] --> I[步骤9] --> J[步骤10]
</div>
</div>
</div>
</div>
<!-- 测试 5: 响应式测试 -->
<div class="test-section">
<h2>测试 5: 响应式适配</h2>
<div class="test-case">
<h3>5.1 移动端适配</h3>
<p class="expected">✅ 预期:在移动端(<768px高度限制为 500px</p>
<p class="info">请调整浏览器窗口大小测试</p>
<div class="mermaid-container">
<div class="mermaid">
flowchart TD
A[移动端] --> B[平板]
B --> C[桌面端]
A --> D[响应式]
B --> D
C --> D
</div>
</div>
</div>
</div>
<!-- 测试结果检查清单 -->
<div class="test-section">
<h2>📋 测试检查清单</h2>
<ul style="list-style: none; padding: 0;">
<li style="margin: 10px 0;">
<input type="checkbox" id="check1">
<label for="check1">✅ 极简图表2-3节点不会显示过大高度合理</label>
</li>
<li style="margin: 10px 0;">
<input type="checkbox" id="check2">
<label for="check2">✅ 图表在容器中居中显示</label>
</li>
<li style="margin: 10px 0;">
<input type="checkbox" id="check3">
<label for="check3">✅ 中等复杂度图表显示正常,高度不超过 600px</label>
</li>
<li style="margin: 10px 0;">
<input type="checkbox" id="check4">
<label for="check4">✅ 复杂图表高度限制在 600px出现滚动条</label>
</li>
<li style="margin: 10px 0;">
<input type="checkbox" id="check5">
<label for="check5">✅ 横向图表宽度自适应,出现横向滚动条</label>
</li>
<li style="margin: 10px 0;">
<input type="checkbox" id="check6">
<label for="check6">✅ 夜间模式下图表显示正常</label>
</li>
<li style="margin: 10px 0;">
<input type="checkbox" id="check7">
<label for="check7">✅ 移动端(<768px高度限制为 500px</label>
</li>
<li style="margin: 10px 0;">
<input type="checkbox" id="check8">
<label for="check8">✅ 小屏幕(<480px高度限制为 400px</label>
</li>
</ul>
</div>
<!-- 优化说明 -->
<div class="test-section">
<h2>🎯 优化说明</h2>
<h3>主要改进:</h3>
<ol>
<li><strong>最大高度限制</strong>SVG 最大高度设置为 600px桌面端</li>
<li><strong>居中显示</strong>:使用 flexbox 让图表在容器中居中</li>
<li><strong>宽度自适应</strong>:使用 <code>width: auto !important</code> 让图表保持原始宽高比</li>
<li><strong>响应式适配</strong>
<ul>
<li>平板(<768px最大高度 500px</li>
<li>手机(<480px最大高度 400px</li>
</ul>
</li>
<li><strong>最小高度</strong>:容器最小高度 100px避免空白过小</li>
</ol>
<h3>CSS 关键属性:</h3>
<pre style="background: #f8f9fa; padding: 15px; border-radius: 4px; overflow-x: auto;"><code>.mermaid-container {
display: flex;
justify-content: center;
align-items: center;
min-height: 100px;
}
.mermaid-container svg {
max-width: 100%;
max-height: 600px;
height: auto;
width: auto !important;
}</code></pre>
</div>
<script src="https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js"></script>
<script>
// 初始化 Mermaid
mermaid.initialize({
startOnLoad: true,
theme: 'default',
securityLevel: 'loose',
flowchart: {
useMaxWidth: false,
htmlLabels: true
}
});
// 切换夜间模式
function toggleTheme() {
document.documentElement.classList.toggle('darkmode');
const isDark = document.documentElement.classList.contains('darkmode');
// 重新初始化 Mermaid 以应用新主题
mermaid.initialize({
startOnLoad: false,
theme: isDark ? 'dark' : 'default',
securityLevel: 'loose',
flowchart: {
useMaxWidth: false,
htmlLabels: true
}
});
console.log(`[Theme] 切换到 ${isDark ? '夜间' : '日间'} 模式`);
}
// 页面加载完成后的日志
window.addEventListener('load', function() {
console.log('[Mermaid Size Test] 测试页面已加载');
console.log('[Mermaid Size Test] 请检查:');
console.log('[Mermaid Size Test] 1. 极简图表是否显示合理大小');
console.log('[Mermaid Size Test] 2. 图表是否在容器中居中');
console.log('[Mermaid Size Test] 3. 复杂图表是否有高度限制');
console.log('[Mermaid Size Test] 4. 响应式适配是否正常');
});
</script>
</body>
</html>

View File

@@ -1,365 +0,0 @@
# AI 垃圾评论检测系统架构
## 系统概述
本文档展示 Argon 主题的 AI 垃圾评论检测系统的完整架构和流程。
## 主流程图
[mermaid theme="default" width="100%" align="center"]
flowchart TD
Start([用户提交评论]) --> PreProcess[预处理评论]
PreProcess --> CheckEnabled{启用 AI 检测?}
CheckEnabled -->|否| DirectSave[直接保存评论]
CheckEnabled -->|是| CheckMode{检测模式?}
CheckMode -->|manual| DirectSave
CheckMode -->|keyword| CheckKeyword[检查关键字]
CheckMode -->|sample| CheckSample[智能抽样]
CheckMode -->|all| NeedCheck[需要检测]
CheckKeyword --> KeywordMatch{匹配关键字?}
KeywordMatch -->|是| NeedCheck
KeywordMatch -->|否| DirectSave
CheckSample --> SampleDecision{抽中?}
SampleDecision -->|是| NeedCheck
SampleDecision -->|否| DirectSave
NeedCheck --> SetPending[设置待审核状态]
SetPending --> SaveWithFlag[保存评论并标记]
SaveWithFlag --> TriggerDetect[触发 AI 检测]
TriggerDetect --> CallAPI[调用 AI API]
CallAPI --> ParseResult[解析结果]
ParseResult --> CheckConfidence{置信度?}
CheckConfidence -->|高| AutoHandle[自动处理]
CheckConfidence -->|中| ManualReview[人工审核]
CheckConfidence -->|低| MarkNormal[标记正常]
AutoHandle --> CheckAction{处理方式?}
CheckAction -->|trash| MoveTrash[移入回收站]
CheckAction -->|hold| KeepPending[保持待审核]
CheckAction -->|mark| JustMark[仅标记]
MoveTrash --> NotifyAdmin[通知管理员]
KeepPending --> NotifyAdmin
JustMark --> SaveResult[保存结果]
ManualReview --> SaveResult
MarkNormal --> SaveResult
NotifyAdmin --> SaveResult
SaveResult --> AILearn{启用学习?}
AILearn -->|是| ExtractKeywords[提取关键词]
AILearn -->|否| End([结束])
ExtractKeywords --> UpdateDB[更新词库]
UpdateDB --> End
DirectSave --> End
style Start fill:#e1f5e1,stroke:#2e7d32,stroke-width:2px
style End fill:#e1f5e1,stroke:#2e7d32,stroke-width:2px
style MoveTrash fill:#ff6b6b,stroke:#c62828,stroke-width:2px
style MarkNormal fill:#95e1d3,stroke:#2e7d32,stroke-width:2px
style ManualReview fill:#ffa500,stroke:#ff8f00,stroke-width:2px
[/mermaid]
## 检测模式详解
[mermaid theme="default" width="80%" align="center"]
flowchart LR
subgraph Manual[Manual 模式]
M1[关闭实时检测]
M2[仅手动扫描]
end
subgraph Keyword[Keyword 模式]
K1[关键字触发]
K2[精准检测]
K3[低成本]
end
subgraph Sample[Sample 模式]
S1[智能抽样]
S2[平衡准确性]
S3[控制成本]
end
subgraph All[All 模式]
A1[全量检测]
A2[最高准确性]
A3[高成本]
end
style Manual fill:#e3f2fd
style Keyword fill:#fff3e0
style Sample fill:#f3e5f5
style All fill:#fce4ec
[/mermaid]
## AI 检测流程
[mermaid theme="default" width="90%"]
sequenceDiagram
participant User as 用户
participant WP as WordPress
participant Argon as Argon 主题
participant AI as AI API
participant DB as 数据库
User->>WP: 提交评论
WP->>Argon: 触发 preprocess_comment
Argon->>Argon: 检查检测规则
alt 需要检测
Argon->>DB: 保存评论(待审核)
Argon->>AI: 发送检测请求
AI-->>Argon: 返回检测结果
Argon->>Argon: 解析结果和置信度
alt 高置信度垃圾评论
Argon->>DB: 移入回收站
Argon->>WP: 发送通知邮件
else 中等置信度
Argon->>DB: 标记待人工审核
else 正常评论
Argon->>DB: 标记为正常
end
Argon->>DB: 保存检测记录
opt 启用 AI 学习
Argon->>AI: 提取关键词
AI-->>Argon: 返回关键词
Argon->>DB: 更新学习词库
end
else 跳过检测
Argon->>DB: 直接保存评论
end
WP-->>User: 显示提交结果
[/mermaid]
## 数据库结构
[mermaid theme="default" width="85%"]
erDiagram
COMMENT ||--o{ COMMENT_META : has
COMMENT {
bigint comment_ID PK
bigint comment_post_ID FK
text comment_content
varchar comment_author
varchar comment_author_email
varchar comment_author_IP
datetime comment_date
varchar comment_approved
}
COMMENT_META {
bigint meta_id PK
bigint comment_id FK
varchar meta_key
longtext meta_value
}
SPAM_DETECTION ||--|| COMMENT : detects
SPAM_DETECTION {
bigint id PK
bigint comment_id FK
varchar result
float confidence
text reason
text keywords
datetime detected_at
varchar detection_code
}
LEARNED_KEYWORDS ||--o{ SPAM_DETECTION : learns_from
LEARNED_KEYWORDS {
bigint id PK
varchar keyword
int weight
varchar category
datetime created_at
datetime updated_at
}
[/mermaid]
## 系统状态机
[mermaid theme="default" width="70%"]
stateDiagram-v2
[*] --> Submitted: 用户提交
Submitted --> Pending: 需要检测
Submitted --> Approved: 跳过检测
Pending --> Detecting: 开始检测
Detecting --> Analyzed: 检测完成
Analyzed --> Spam: 高置信度垃圾
Analyzed --> Suspicious: 中等置信度
Analyzed --> Clean: 低置信度/正常
Spam --> Trash: 自动处理
Spam --> Hold: 保持待审核
Spam --> Marked: 仅标记
Suspicious --> ManualReview: 等待人工审核
Clean --> Approved: 自动通过
ManualReview --> Approved: 管理员批准
ManualReview --> Trash: 管理员拒绝
Hold --> Approved: 管理员批准
Hold --> Trash: 管理员拒绝
Marked --> Approved: 管理员批准
Marked --> Trash: 管理员拒绝
Trash --> [*]
Approved --> [*]
note right of Detecting
调用 AI API
解析返回结果
计算置信度
end note
note right of ManualReview
显示在后台
等待管理员操作
end note
[/mermaid]
## 性能优化策略
[mermaid theme="default" width="95%"]
flowchart TD
subgraph Input[输入优化]
I1[关键字预过滤]
I2[白名单用户]
I3[智能抽样]
end
subgraph Process[处理优化]
P1[异步检测]
P2[批量处理]
P3[缓存结果]
end
subgraph API[API 优化]
A1[Prompt 优化]
A2[Token 控制]
A3[超时处理]
end
subgraph Storage[存储优化]
S1[索引优化]
S2[定期清理]
S3[归档历史]
end
Input --> Process
Process --> API
API --> Storage
style Input fill:#e8f5e9
style Process fill:#e3f2fd
style API fill:#fff3e0
style Storage fill:#f3e5f5
[/mermaid]
## 配置建议矩阵
[mermaid theme="default" width="100%"]
graph TB
subgraph Small[小型博客 < 100评论/天]
S1[检测模式: keyword]
S2[Prompt: 标准模式]
S3[置信度阈值: > 0.9]
S4[自动处理: trash]
end
subgraph Medium[中型博客 100-500评论/天]
M1[检测模式: sample 30%]
M2[Prompt: 标准模式]
M3[置信度阈值: > 0.85]
M4[自动处理: hold]
end
subgraph Large[大型博客 > 500评论/天]
L1[检测模式: sample 40%]
L2[Prompt: 极简模式]
L3[置信度阈值: > 0.8]
L4[自动处理: mark]
L5[定期批量扫描]
end
style Small fill:#c8e6c9
style Medium fill:#fff9c4
style Large fill:#ffccbc
[/mermaid]
## 错误处理流程
[mermaid theme="default" width="85%"]
flowchart TD
Start([检测开始]) --> CallAPI[调用 AI API]
CallAPI --> CheckResponse{响应状态?}
CheckResponse -->|成功| ParseJSON[解析 JSON]
CheckResponse -->|超时| Timeout[超时处理]
CheckResponse -->|错误| APIError[API 错误]
ParseJSON --> ValidateData{数据有效?}
ValidateData -->|是| ProcessResult[处理结果]
ValidateData -->|否| DataError[数据错误]
Timeout --> RetryCheck{重试次数?}
RetryCheck -->|< 3| Retry[重试请求]
RetryCheck -->|>= 3| FallbackPending[降级:待审核]
Retry --> CallAPI
APIError --> LogError[记录错误日志]
DataError --> LogError
LogError --> NotifyAdmin[通知管理员]
NotifyAdmin --> FallbackPending
ProcessResult --> SaveResult[保存结果]
FallbackPending --> SaveResult
SaveResult --> End([结束])
style Timeout fill:#ffccbc
style APIError fill:#ffccbc
style DataError fill:#ffccbc
style FallbackPending fill:#fff9c4
style ProcessResult fill:#c8e6c9
[/mermaid]
## 总结
通过以上流程图,我们可以清晰地看到:
1. **主流程**:从用户提交到最终处理的完整流程
2. **检测模式**:四种模式的特点和适用场景
3. **时序交互**:各组件之间的交互顺序
4. **数据结构**:数据库表关系和字段定义
5. **状态机**:评论的各种状态转换
6. **性能优化**:多层次的优化策略
7. **配置建议**:不同规模博客的推荐配置
8. **错误处理**:完善的异常处理机制
这个系统设计充分考虑了:
- ✅ 准确性:多级置信度判断
- ✅ 性能:异步处理、智能抽样
- ✅ 成本:灵活的检测模式
- ✅ 可靠性:完善的错误处理
- ✅ 可维护性:清晰的架构设计

View File

@@ -1,197 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>单元素容器语法测试</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
background: #f5f5f5;
}
.test-case {
background: white;
padding: 20px;
margin: 20px 0;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
h2 {
color: #333;
border-bottom: 2px solid #007bff;
padding-bottom: 10px;
}
.success {
color: green;
font-weight: bold;
}
.error {
color: red;
font-weight: bold;
}
pre {
background: #f4f4f4;
padding: 10px;
border-radius: 4px;
overflow-x: auto;
white-space: pre-wrap;
}
</style>
</head>
<body>
<h1>单元素容器语法测试</h1>
<p>测试 WP-Markdown 将整个容器语法放在一个 &lt;p&gt; 元素中的情况</p>
<!-- 测试用例 1: 简单流程图(单元素) -->
<div class="test-case">
<h2>测试 1: 简单流程图(单元素,带全角箭头)</h2>
<p>::: mermaid<br>flowchart TD<br> Start([开始]) > Process[处理]<br> Process > End([结束])<br>:::</p>
<div id="result1"></div>
</div>
<!-- 测试用例 2: 带样式的流程图(单元素) -->
<div class="test-case">
<h2>测试 2: 带样式定义(单元素)</h2>
<p>::: mermaid<br>flowchart LR<br> A[开始] > B[处理]<br> B > C[结束]<br> style A fill:#e1f5e1,stroke:#2e7d32<br> style C fill:#ffe1e1,stroke:#c62828<br>:::</p>
<div id="result2"></div>
</div>
<!-- 测试用例 3: 复杂流程图(单元素,模拟 AI 评论审核) -->
<div class="test-case">
<h2>测试 3: 复杂流程图(单元素,多个节点)</h2>
<p>::: mermaid<br>flowchart TD<br> Start([用户提交评论]) > PreProcess[预处理]<br> PreProcess > CheckEnabled{启用 AI 检测?}<br> CheckEnabled >|否| SaveComment[保存评论]<br> CheckEnabled >|是| CheckMode{检测模式?}<br> CheckMode >|manual| SaveComment<br> CheckMode >|keyword/sample/all| AICheck[AI 检测]<br> AICheck > CheckResult{检测结果?}<br> CheckResult >|垃圾评论| Trash[移入回收站]<br> CheckResult >|正常评论| SaveComment<br> style Start fill:#e1f5e1,stroke:#2e7d32<br> style Trash fill:#ff6b6b,stroke:#c62828<br>:::</p>
<div id="result3"></div>
</div>
<script src="https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js"></script>
<script>
// 模拟 Argon 主题的 htmlToText 函数(增强版)
function htmlToText(html) {
// 将 <br> 和 <br/> 转换为换行符
let text = html.replace(/<br\s*\/?>/gi, '\n');
// 移除其他 HTML 标签
text = text.replace(/<[^>]+>/g, '');
// 解码 HTML 实体
text = text
.replace(/&nbsp;/g, ' ')
.replace(/&lt;/g, '<')
.replace(/&gt;/g, '>')
.replace(/&amp;/g, '&')
.replace(/&quot;/g, '"')
.replace(/&#039;/g, "'")
.replace(/&#8211;/g, '-') // EN DASH
.replace(/&#8212;/g, '--') // EM DASH
.replace(/&#8594;/g, '->') // RIGHTWARDS ARROW
.replace(/&ndash;/g, '-') // EN DASH (named entity)
.replace(/&mdash;/g, '--') // EM DASH (named entity)
.replace(/&rarr;/g, '->'); // RIGHTWARDS ARROW (named entity)
// 转换 Unicode 字符WordPress 可能直接输出 Unicode
text = text
.replace(//g, '-') // U+2013 EN DASH
.replace(/—/g, '--') // U+2014 EM DASH
.replace(/→/g, '->'); // U+2192 RIGHTWARDS ARROW
return text;
}
// 提取单元素容器语法内容
function extractSingleElementContainer(element) {
let html = element.innerHTML;
let text = element.textContent.trim();
console.log('[测试] 原始 HTML:', html.substring(0, 200));
console.log('[测试] 原始文本:', text.substring(0, 200));
if (!text.startsWith('::: mermaid')) {
return null;
}
// 检查是否整个内容都在一个元素中
if (text.includes(':::') && text.lastIndexOf(':::') > 10) {
console.log('[测试] 检测到单元素容器语法');
// 使用 htmlToText 转换
let fullText = htmlToText(html);
console.log('[测试] 转换后文本:', fullText.substring(0, 200));
// 移除开始和结束标记
fullText = fullText.replace(/^:::\s*mermaid\s*/i, '').trim();
fullText = fullText.replace(/:::\s*$/, '').trim();
console.log('[测试] 最终代码:', fullText);
return fullText;
}
return null;
}
// 测试函数
function testMermaid(testId, resultId) {
const element = document.querySelector(`#${testId}`).previousElementSibling;
const resultDiv = document.getElementById(resultId);
try {
const code = extractSingleElementContainer(element);
if (!code) {
resultDiv.innerHTML = '<p class="error">❌ 提取失败:未找到代码</p>';
return;
}
// 检查换行符
const lines = code.split('\n');
console.log(`[测试 ${testId}] 提取到 ${lines.length} 行代码`);
// 检查箭头符号
const hasCorrectArrows = code.includes('-->') || code.includes('->');
const hasWrongArrows = code.includes('>') || code.includes('→');
// 渲染图表
mermaid.render(`mermaid-${testId}`, code).then(result => {
resultDiv.innerHTML = `
<p class="success">✅ 渲染成功</p>
<p>提取到 ${lines.length} 行代码</p>
<p>箭头符号: ${hasCorrectArrows ? '✅ 正确 (-->)' : '❌ 错误'}</p>
<p>全角箭头: ${hasWrongArrows ? '❌ 存在 (>)' : '✅ 不存在'}</p>
<details>
<summary>查看提取的代码</summary>
<pre>${code}</pre>
</details>
${result.svg}
`;
}).catch(error => {
resultDiv.innerHTML = `
<p class="error">❌ 渲染失败: ${error.message}</p>
<p>箭头符号: ${hasCorrectArrows ? '✅ 正确 (-->)' : '❌ 错误'}</p>
<p>全角箭头: ${hasWrongArrows ? '❌ 存在 (>)' : '✅ 不存在'}</p>
<details>
<summary>查看提取的代码</summary>
<pre>${code}</pre>
</details>
`;
});
} catch (error) {
resultDiv.innerHTML = `<p class="error">❌ 错误: ${error.message}</p>`;
}
}
// 初始化
document.addEventListener('DOMContentLoaded', function() {
mermaid.initialize({
startOnLoad: false,
theme: 'default',
securityLevel: 'loose'
});
// 运行测试
testMermaid('test1', 'result1');
testMermaid('test2', 'result2');
testMermaid('test3', 'result3');
});
</script>
</body>
</html>

View File

@@ -1,214 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WP-Markdown Mermaid 格式测试</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
background: #f5f5f5;
}
.test-case {
background: white;
padding: 20px;
margin: 20px 0;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
h2 {
color: #333;
border-bottom: 2px solid #007bff;
padding-bottom: 10px;
}
.mermaid {
background: #f9f9f9;
padding: 15px;
border: 1px solid #ddd;
border-radius: 4px;
margin: 10px 0;
}
pre {
background: #f4f4f4;
padding: 10px;
border-radius: 4px;
overflow-x: auto;
}
</style>
</head>
<body>
<h1>WP-Markdown Mermaid 格式测试</h1>
<p>本页面测试 WP-Markdown 插件生成的各种 Mermaid 代码块格式</p>
<!-- 测试用例 1: 标准 document.write 格式(单行) -->
<div class="test-case">
<h2>测试 1: 标准 document.write 格式(单行)</h2>
<div class="mermaid">
<script>document.write("flowchart TD\nA[开始] --> B[处理]\nB --> C[结束]")</script>
</div>
</div>
<!-- 测试用例 2: document.write 格式(多行,带转义) -->
<div class="test-case">
<h2>测试 2: document.write 格式(多行,带转义)</h2>
<div class="mermaid">
<script>document.write("graph LR\n A[\"用户输入\"] --> B[\"数据验证\"]\n B --> C{\"是否有效?\"}\n C -->|是| D[\"保存数据\"]\n C -->|否| E[\"显示错误\"]")</script>
</div>
</div>
<!-- 测试用例 3: document.write 格式(包含 HTML 实体) -->
<div class="test-case">
<h2>测试 3: document.write 格式(包含 HTML 实体)</h2>
<div class="mermaid">
<script>document.write("sequenceDiagram\n Alice-&gt;&gt;Bob: Hello Bob!\n Bob--&gt;&gt;Alice: Hi Alice!")</script>
</div>
</div>
<!-- 测试用例 4: 纯文本格式(无 script 标签) -->
<div class="test-case">
<h2>测试 4: 纯文本格式(无 script 标签)</h2>
<div class="mermaid">
flowchart TD
Start --> Stop
</div>
</div>
<!-- 测试用例 5: pre code 格式 -->
<div class="test-case">
<h2>测试 5: pre code 格式</h2>
<pre><code class="language-mermaid">graph TD
A --> B
B --> C</code></pre>
</div>
<!-- 测试用例 6: 复杂图表(类图) -->
<div class="test-case">
<h2>测试 6: 复杂图表(类图)</h2>
<div class="mermaid">
<script>document.write("classDiagram\n class Animal {\n +String name\n +int age\n +makeSound()\n }\n class Dog {\n +String breed\n +bark()\n }\n Animal <|-- Dog")</script>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js"></script>
<script>
// 模拟 Argon 主题的 Mermaid 初始化逻辑
console.log('[测试] 开始初始化 Mermaid');
// 检测所有 Mermaid 代码块
function detectMermaidBlocks() {
const blocks = [];
const selectors = [
'div.mermaid',
'pre code.language-mermaid',
'pre[data-lang="mermaid"]',
'code.mermaid'
];
selectors.forEach(selector => {
const elements = document.querySelectorAll(selector);
elements.forEach(element => {
if (!blocks.includes(element)) {
blocks.push(element);
}
});
});
console.log(`[测试] 检测到 ${blocks.length} 个 Mermaid 代码块`);
return blocks;
}
// 提取代码块内容(使用改进后的正则)
function extractMermaidCode(element) {
let code = '';
if (element.tagName === 'DIV' && element.classList.contains('mermaid')) {
const scriptTag = element.querySelector('script');
if (scriptTag) {
const scriptContent = scriptTag.textContent || scriptTag.innerText;
console.log('[测试] 原始 script 内容:', scriptContent.substring(0, 100));
// 使用改进后的正则:[\s\S]*? 匹配包括换行在内的所有字符
let match = scriptContent.match(/document\.write\s*\(\s*["']([\s\S]*?)["']\s*\)/);
if (match && match[1]) {
code = match[1];
console.log('[测试] 从 document.write() 提取到代码,长度:', code.length);
} else {
// 降级方案:直接提取引号内容
match = scriptContent.match(/["']([\s\S]*?)["']/);
if (match && match[1]) {
code = match[1];
console.log('[测试] 从引号内提取到代码,长度:', code.length);
} else {
const clonedElement = element.cloneNode(true);
const scripts = clonedElement.querySelectorAll('script');
scripts.forEach(script => script.remove());
code = clonedElement.textContent;
console.log('[测试] 使用降级方案提取代码');
}
}
} else {
code = element.textContent;
console.log('[测试] 从纯文本提取代码');
}
} else if (element.tagName === 'CODE') {
code = element.textContent;
} else if (element.tagName === 'PRE') {
const codeElement = element.querySelector('code');
code = codeElement ? codeElement.textContent : element.textContent;
}
// 解码 HTML 实体
code = code
.replace(/&lt;/g, '<')
.replace(/&gt;/g, '>')
.replace(/&amp;/g, '&')
.replace(/&quot;/g, '"')
.replace(/&#039;/g, "'");
// 解码转义字符
code = code
.replace(/\\n/g, '\n')
.replace(/\\t/g, '\t')
.replace(/\\r/g, '\r')
.replace(/\\"/g, '"')
.replace(/\\'/g, "'")
.replace(/\\\\/g, '\\');
console.log('[测试] 最终提取的代码:', code.substring(0, 100) + (code.length > 100 ? '...' : ''));
return code.trim();
}
// 初始化并渲染
document.addEventListener('DOMContentLoaded', function() {
mermaid.initialize({
startOnLoad: false,
theme: 'default',
securityLevel: 'loose'
});
const blocks = detectMermaidBlocks();
blocks.forEach((block, index) => {
const code = extractMermaidCode(block);
const chartId = `mermaid-chart-${index}`;
console.log(`[测试] 渲染图表 ${index}:`, code);
mermaid.render(chartId, code).then(result => {
const container = document.createElement('div');
container.innerHTML = result.svg;
block.parentNode.replaceChild(container, block);
console.log(`[测试] 图表 ${index} 渲染成功`);
}).catch(error => {
console.error(`[测试] 图表 ${index} 渲染失败:`, error);
block.style.border = '2px solid red';
block.innerHTML = `<strong style="color: red;">渲染失败: ${error.message}</strong><br><pre>${code}</pre>`;
});
});
});
</script>
</body>
</html>