feat: 添加 Mermaid Shortcode 支持(推荐方式)

- 新增 [mermaid]...[/mermaid] shortcode
- 支持 theme、width、height、align 参数
- 不依赖 WP-Markdown 的处理方式
- 不会被 WordPress 自动格式化破坏
- 在原生编辑器中清晰可见
- 添加完整的使用指南和示例
This commit is contained in:
2026-01-24 21:02:47 +08:00
parent bf8f973e91
commit 32c2a72d2b
5 changed files with 1102 additions and 2 deletions

View File

@@ -0,0 +1,365 @@
# 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

@@ -0,0 +1,197 @@
<!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>