feat: 添加 AI 垃圾评论检测的设置页选项
- 关键字必查:触发关键字后立即 AI 审核 - AI 主动学习:自动分析管理员决策并优化关键字 - 学习到的关键字:显示 AI 学习的关键词统计 - 智能预审查:在评论保存前进行 AI 审查 - 添加同步检测函数支持预审查功能
This commit is contained in:
146
functions.php
146
functions.php
@@ -2835,6 +2835,142 @@ function post_comment_preprocessing($comment){
|
|||||||
if ($_POST['use_markdown'] == 'true' && get_option("argon_comment_allow_markdown") != "false"){
|
if ($_POST['use_markdown'] == 'true' && get_option("argon_comment_allow_markdown") != "false"){
|
||||||
$comment['comment_content'] = comment_markdown_parse($comment['comment_content']);
|
$comment['comment_content'] = comment_markdown_parse($comment['comment_content']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AI 智能审查:在评论保存前进行检测和处理
|
||||||
|
if (get_option('argon_comment_spam_detection_enable', 'false') === 'true') {
|
||||||
|
$mode = get_option('argon_comment_spam_detection_mode', 'manual');
|
||||||
|
|
||||||
|
// 只有在启用了实时检测模式时才进行预审查
|
||||||
|
if ($mode !== 'manual') {
|
||||||
|
// 检查是否为已登录用户(可跳过)
|
||||||
|
$skip_logged_in = get_option('argon_comment_spam_detection_exclude_logged_in', 'true') === 'true';
|
||||||
|
$is_logged_in = is_user_logged_in();
|
||||||
|
|
||||||
|
if (!$is_logged_in || !$skip_logged_in) {
|
||||||
|
// 创建临时评论对象用于检测
|
||||||
|
$temp_comment = (object) [
|
||||||
|
'comment_author' => $comment['comment_author'],
|
||||||
|
'comment_author_email' => $comment['comment_author_email'],
|
||||||
|
'comment_author_url' => $comment['comment_author_url'],
|
||||||
|
'comment_author_IP' => $comment['comment_author_IP'],
|
||||||
|
'comment_content' => strip_tags($comment['comment_content']),
|
||||||
|
'comment_post_ID' => $comment['comment_post_ID'],
|
||||||
|
'user_id' => $comment['user_id']
|
||||||
|
];
|
||||||
|
|
||||||
|
// 检查白名单
|
||||||
|
if (!argon_is_comment_in_whitelist($temp_comment)) {
|
||||||
|
$should_check = false;
|
||||||
|
$check_reason = '';
|
||||||
|
|
||||||
|
// 优先级1:检查是否触发关键字
|
||||||
|
$keyword_check = argon_check_spam_keywords($temp_comment);
|
||||||
|
if ($keyword_check && $keyword_check['triggered']) {
|
||||||
|
$should_check = true;
|
||||||
|
$check_reason = 'keyword';
|
||||||
|
}
|
||||||
|
// 优先级2:全量检测模式
|
||||||
|
elseif ($mode === 'all') {
|
||||||
|
$should_check = true;
|
||||||
|
$check_reason = 'all';
|
||||||
|
}
|
||||||
|
// 优先级3:抽查模式(根据概率)
|
||||||
|
elseif ($mode === 'sample') {
|
||||||
|
$check_probability = argon_get_user_spam_check_probability($temp_comment);
|
||||||
|
if (rand(1, 100) <= $check_probability) {
|
||||||
|
$should_check = true;
|
||||||
|
$check_reason = 'sample';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果需要检测,立即进行同步检测
|
||||||
|
if ($should_check) {
|
||||||
|
$result = argon_detect_spam_comment_sync($temp_comment);
|
||||||
|
|
||||||
|
if ($result && isset($result['is_spam'])) {
|
||||||
|
$content_spam = $result['is_spam'];
|
||||||
|
$username_invalid = isset($result['username_invalid']) ? $result['username_invalid'] : false;
|
||||||
|
$confidence = isset($result['confidence']) ? floatval($result['confidence']) : 0.8;
|
||||||
|
$suggestion = isset($result['suggestion']) ? $result['suggestion'] : 'auto';
|
||||||
|
$confidence_threshold = floatval(get_option('argon_comment_spam_detection_confidence_threshold', 0.85));
|
||||||
|
|
||||||
|
// 情况1:内容违规且置信度高 - 直接拒绝评论
|
||||||
|
if ($content_spam && $confidence >= $confidence_threshold && $suggestion === 'auto') {
|
||||||
|
wp_die(
|
||||||
|
'<div style="max-width:600px;margin:50px auto;padding:30px;background:#fff;border-radius:8px;box-shadow:0 2px 12px rgba(0,0,0,0.1);">
|
||||||
|
<h2 style="color:#f5365c;margin-bottom:20px;">⚠️ ' . __('评论审核未通过', 'argon') . '</h2>
|
||||||
|
<p style="font-size:16px;line-height:1.8;color:#525f7f;">' . __('您的评论因以下原因未能通过审核:', 'argon') . '</p>
|
||||||
|
<div style="background:#f7fafc;padding:15px;border-left:4px solid #f5365c;margin:20px 0;">
|
||||||
|
<strong>' . esc_html($result['reason']) . '</strong>
|
||||||
|
</div>
|
||||||
|
<p style="font-size:14px;color:#8898aa;">' . __('如果您认为这是误判,请联系网站管理员。', 'argon') . '</p>
|
||||||
|
<div style="margin-top:30px;text-align:center;">
|
||||||
|
<a href="javascript:history.back()" style="display:inline-block;padding:12px 30px;background:#5e72e4;color:#fff;text-decoration:none;border-radius:4px;">' . __('返回修改', 'argon') . '</a>
|
||||||
|
</div>
|
||||||
|
</div>',
|
||||||
|
__('评论审核未通过', 'argon'),
|
||||||
|
['response' => 403, 'back_link' => true]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 情况2:用户名违规且没有邮箱 - 直接拒绝评论
|
||||||
|
if ($username_invalid && empty($comment['comment_author_email'])) {
|
||||||
|
wp_die(
|
||||||
|
'<div style="max-width:600px;margin:50px auto;padding:30px;background:#fff;border-radius:8px;box-shadow:0 2px 12px rgba(0,0,0,0.1);">
|
||||||
|
<h2 style="color:#f5365c;margin-bottom:20px;">⚠️ ' . __('用户名审核未通过', 'argon') . '</h2>
|
||||||
|
<p style="font-size:16px;line-height:1.8;color:#525f7f;">' . __('您的用户名因以下原因未能通过审核:', 'argon') . '</p>
|
||||||
|
<div style="background:#f7fafc;padding:15px;border-left:4px solid #f5365c;margin:20px 0;">
|
||||||
|
<strong>' . esc_html($result['username_reason']) . '</strong>
|
||||||
|
</div>
|
||||||
|
<p style="font-size:14px;color:#8898aa;">' . __('请修改用户名后重试,或填写邮箱以便我们为您自动生成合规的用户名。', 'argon') . '</p>
|
||||||
|
<div style="margin-top:30px;text-align:center;">
|
||||||
|
<a href="javascript:history.back()" style="display:inline-block;padding:12px 30px;background:#5e72e4;color:#fff;text-decoration:none;border-radius:4px;">' . __('返回修改', 'argon') . '</a>
|
||||||
|
</div>
|
||||||
|
</div>',
|
||||||
|
__('用户名审核未通过', 'argon'),
|
||||||
|
['response' => 403, 'back_link' => true]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 情况3:用户名违规但有邮箱 - 自动修改用户名
|
||||||
|
if ($username_invalid && !empty($comment['comment_author_email'])) {
|
||||||
|
$original_username = $comment['comment_author'];
|
||||||
|
$new_username = argon_generate_unique_username(
|
||||||
|
$original_username,
|
||||||
|
$comment['comment_author_email'],
|
||||||
|
$comment['comment_author_IP'],
|
||||||
|
isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : ''
|
||||||
|
);
|
||||||
|
|
||||||
|
// 修改评论数组中的用户名
|
||||||
|
$comment['comment_author'] = $new_username;
|
||||||
|
|
||||||
|
// 保存原始用户名和检测结果到 $_POST,稍后在 post_comment_updatemetas 中保存
|
||||||
|
$_POST['_argon_original_username'] = $original_username;
|
||||||
|
$_POST['_argon_username_changed'] = 'true';
|
||||||
|
$_POST['_argon_username_change_reason'] = $result['username_reason'];
|
||||||
|
$_POST['_argon_spam_detection_result'] = json_encode($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 情况4:内容违规但置信度不足 - 标记为待审核
|
||||||
|
if ($content_spam && ($confidence < $confidence_threshold || $suggestion !== 'auto')) {
|
||||||
|
// 保存检测结果,稍后标记为待审核
|
||||||
|
$_POST['_argon_spam_low_confidence'] = 'true';
|
||||||
|
$_POST['_argon_spam_detection_result'] = json_encode($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存检测原因
|
||||||
|
$_POST['_argon_spam_check_reason'] = $check_reason;
|
||||||
|
if ($keyword_check && $keyword_check['triggered']) {
|
||||||
|
$_POST['_argon_spam_triggered_keywords'] = json_encode($keyword_check['keywords']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return $comment;
|
return $comment;
|
||||||
}
|
}
|
||||||
add_filter('preprocess_comment' , 'post_comment_preprocessing');
|
add_filter('preprocess_comment' , 'post_comment_preprocessing');
|
||||||
@@ -7584,6 +7720,16 @@ function argon_detect_spam_comment($comment_id) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return argon_detect_spam_comment_sync($comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 同步检测评论是否为垃圾评论(支持临时评论对象)
|
||||||
|
* @param object $comment 评论对象
|
||||||
|
* @return array|false ['is_spam' => bool, 'reason' => string, 'username_invalid' => bool, 'username_reason' => string] 或 false
|
||||||
|
*/
|
||||||
|
function argon_detect_spam_comment_sync($comment) {
|
||||||
|
|
||||||
// 获取 AI 配置
|
// 获取 AI 配置
|
||||||
$provider = get_option('argon_ai_summary_provider', 'openai');
|
$provider = get_option('argon_ai_summary_provider', 'openai');
|
||||||
$api_key = get_option('argon_ai_summary_api_key', '');
|
$api_key = get_option('argon_ai_summary_api_key', '');
|
||||||
|
|||||||
95
settings.php
95
settings.php
@@ -4020,6 +4020,98 @@ window.pjaxLoaded = function(){
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<th><label><?php _e('关键字必查', 'argon');?></label></th>
|
||||||
|
<td>
|
||||||
|
<textarea rows="6" cols="70" name="argon_comment_spam_detection_keywords" placeholder="<?php _e('每行一个关键字或短语', 'argon');?>"><?php echo get_option('argon_comment_spam_detection_keywords', ''); ?></textarea>
|
||||||
|
<p class="description">
|
||||||
|
<strong><?php _e('触发关键字后立即 AI 审核(最高优先级)', 'argon');?></strong><br/>
|
||||||
|
<?php _e('当评论的用户名或内容包含这些关键字时,会立即进行 AI 检测,不受检测模式限制。', 'argon');?><br/>
|
||||||
|
<?php _e('每行一个关键字或短语,支持中英文。例如:', 'argon');?><br/>
|
||||||
|
<code>加微信</code>, <code>联系QQ</code>, <code>点击链接</code>, <code>免费领取</code>, <code>刷单</code>, <code>兼职</code>
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<th><label><?php _e('AI 主动学习', 'argon');?></label></th>
|
||||||
|
<td>
|
||||||
|
<?php $argon_comment_spam_detection_ai_learn = get_option('argon_comment_spam_detection_ai_learn', 'false'); ?>
|
||||||
|
<label style="display: block; margin-bottom: 8px;">
|
||||||
|
<input type="checkbox" name="argon_comment_spam_detection_ai_learn" value="true" <?php if ($argon_comment_spam_detection_ai_learn=='true'){echo 'checked';}?>/>
|
||||||
|
<?php _e('启用 AI 主动学习关键字', 'argon');?>
|
||||||
|
</label>
|
||||||
|
<p class="description">
|
||||||
|
<?php _e('开启后,系统会分析管理员的审核决策,自动优化关键字列表:', 'argon');?><br/>
|
||||||
|
<?php _e('• 当 AI 判断与管理员决策不一致时,使用 AI 提取关键词', 'argon');?><br/>
|
||||||
|
<?php _e('• 统计关键词在垃圾评论和正常评论中的出现频率', 'argon');?><br/>
|
||||||
|
<?php _e('• 置信度 > 70% 且出现 >= 3 次的关键词自动加入关键字列表', 'argon');?><br/>
|
||||||
|
<?php _e('• 持续学习,不断提升检测准确性,减少误判和漏判', 'argon');?>
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<th><label><?php _e('学习到的关键字', 'argon');?></label></th>
|
||||||
|
<td>
|
||||||
|
<?php
|
||||||
|
$learned_keywords = get_option('argon_comment_spam_learned_keywords', []);
|
||||||
|
if (!empty($learned_keywords) && is_array($learned_keywords)) {
|
||||||
|
echo '<div style="background:#f7fafc;padding:15px;border-radius:4px;max-height:200px;overflow-y:auto;">';
|
||||||
|
echo '<table style="width:100%;border-collapse:collapse;">';
|
||||||
|
echo '<thead><tr style="border-bottom:2px solid #e2e8f0;">';
|
||||||
|
echo '<th style="text-align:left;padding:8px;">' . __('关键字', 'argon') . '</th>';
|
||||||
|
echo '<th style="text-align:center;padding:8px;">' . __('垃圾', 'argon') . '</th>';
|
||||||
|
echo '<th style="text-align:center;padding:8px;">' . __('正常', 'argon') . '</th>';
|
||||||
|
echo '<th style="text-align:center;padding:8px;">' . __('置信度', 'argon') . '</th>';
|
||||||
|
echo '</tr></thead><tbody>';
|
||||||
|
|
||||||
|
// 按置信度排序
|
||||||
|
uasort($learned_keywords, function($a, $b) {
|
||||||
|
return $b['confidence'] <=> $a['confidence'];
|
||||||
|
});
|
||||||
|
|
||||||
|
foreach ($learned_keywords as $keyword => $stats) {
|
||||||
|
$confidence = round($stats['confidence'] * 100);
|
||||||
|
$color = $confidence >= 70 ? '#48bb78' : ($confidence >= 50 ? '#ed8936' : '#cbd5e0');
|
||||||
|
echo '<tr style="border-bottom:1px solid #e2e8f0;">';
|
||||||
|
echo '<td style="padding:8px;"><code>' . esc_html($keyword) . '</code></td>';
|
||||||
|
echo '<td style="text-align:center;padding:8px;">' . $stats['spam_count'] . '</td>';
|
||||||
|
echo '<td style="text-align:center;padding:8px;">' . $stats['normal_count'] . '</td>';
|
||||||
|
echo '<td style="text-align:center;padding:8px;"><span style="color:' . $color . ';font-weight:bold;">' . $confidence . '%</span></td>';
|
||||||
|
echo '</tr>';
|
||||||
|
}
|
||||||
|
echo '</tbody></table></div>';
|
||||||
|
echo '<p class="description" style="margin-top:10px;">';
|
||||||
|
echo __('绿色表示已自动加入关键字列表(置信度 ≥ 70%),橙色表示观察中(50-70%),灰色表示置信度较低。', 'argon');
|
||||||
|
echo '</p>';
|
||||||
|
} else {
|
||||||
|
echo '<p class="description">' . __('暂无学习到的关键字。启用 AI 主动学习后,系统会自动分析并记录。', 'argon') . '</p>';
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<th><label><?php _e('智能预审查', 'argon');?></label></th>
|
||||||
|
<td>
|
||||||
|
<?php $argon_comment_spam_detection_pre_check = get_option('argon_comment_spam_detection_pre_check', 'true'); ?>
|
||||||
|
<label style="display: block; margin-bottom: 8px;">
|
||||||
|
<input type="checkbox" name="argon_comment_spam_detection_pre_check" value="true" <?php if ($argon_comment_spam_detection_pre_check=='true'){echo 'checked';}?>/>
|
||||||
|
<?php _e('在评论保存前进行 AI 审查', 'argon');?>
|
||||||
|
</label>
|
||||||
|
<p class="description">
|
||||||
|
<strong><?php _e('推荐开启', 'argon');?></strong><br/>
|
||||||
|
<?php _e('开启后,评论会在保存到数据库前先进行 AI 审查:', 'argon');?><br/>
|
||||||
|
<?php _e('• 高置信度垃圾评论:直接拒绝,不保存到数据库', 'argon');?><br/>
|
||||||
|
<?php _e('• 用户名违规且无邮箱:直接拒绝', 'argon');?><br/>
|
||||||
|
<?php _e('• 用户名违规但有邮箱:自动修改用户名后保存', 'argon');?><br/>
|
||||||
|
<?php _e('• 低置信度垃圾评论:标记为待审核', 'argon');?><br/>
|
||||||
|
<?php _e('关闭后,评论会先保存,然后异步检测(可能已发送邮件通知)', 'argon');?>
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<th><label><?php _e('手动批量检测', 'argon');?></label></th>
|
<th><label><?php _e('手动批量检测', 'argon');?></label></th>
|
||||||
<td>
|
<td>
|
||||||
@@ -6688,6 +6780,9 @@ function argon_update_themeoptions(){
|
|||||||
argon_update_option('argon_comment_spam_detection_auto_action');
|
argon_update_option('argon_comment_spam_detection_auto_action');
|
||||||
argon_update_option('argon_comment_spam_detection_whitelist');
|
argon_update_option('argon_comment_spam_detection_whitelist');
|
||||||
argon_update_option_checkbox('argon_comment_spam_detection_exclude_logged_in');
|
argon_update_option_checkbox('argon_comment_spam_detection_exclude_logged_in');
|
||||||
|
argon_update_option('argon_comment_spam_detection_keywords');
|
||||||
|
argon_update_option_checkbox('argon_comment_spam_detection_ai_learn');
|
||||||
|
argon_update_option_checkbox('argon_comment_spam_detection_pre_check');
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user