feat: 添加 AI 垃圾评论识别功能
- 在评论设置中新增 AI 垃圾评论识别配置项 - 支持三种检测模式:仅手动、抽查(20%)、全量检测 - 实现全站评论扫描和待审核评论扫描功能 - 自动识别广告、反动、违法等垃圾评论并移入回收站 - 复用现有 AI 摘要的服务商配置和 API 密钥 - 提供可视化扫描进度和结果展示 - 支持跳过已登录用户评论的选项 - 优化提示词以降低 token 消耗
This commit is contained in:
362
functions.php
362
functions.php
@@ -7276,3 +7276,365 @@ function argon_get_siliconflow_models($api_key, $custom_endpoint = '') {
|
|||||||
|
|
||||||
return $models;
|
return $models;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==========================================================================
|
||||||
|
// AI 垃圾评论识别
|
||||||
|
// ==========================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检测评论是否为垃圾评论
|
||||||
|
* @param int $comment_id 评论 ID
|
||||||
|
* @return array|false ['is_spam' => bool, 'reason' => string] 或 false
|
||||||
|
*/
|
||||||
|
function argon_detect_spam_comment($comment_id) {
|
||||||
|
$comment = get_comment($comment_id);
|
||||||
|
if (!$comment) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取 AI 配置
|
||||||
|
$provider = get_option('argon_ai_summary_provider', 'openai');
|
||||||
|
$api_key = get_option('argon_ai_summary_api_key', '');
|
||||||
|
$model = get_option('argon_ai_summary_model', '');
|
||||||
|
$prompt = get_option('argon_comment_spam_detection_prompt', '');
|
||||||
|
|
||||||
|
if (empty($api_key)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($prompt)) {
|
||||||
|
$prompt = '你是一个专业的内容审核助手。请判断以下评论是否为垃圾评论。垃圾评论包括但不限于:广告推广、反动言论、错误政治观点、时政敏感内容、违法信息、色情暴力、恶意攻击等。
|
||||||
|
|
||||||
|
请仅返回 JSON 格式:{"is_spam": true/false, "reason": "理由(25字以内)"}
|
||||||
|
|
||||||
|
如果是正常评论,reason 填写 "正常"。如果是垃圾评论,简要说明原因。';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建评论内容
|
||||||
|
$comment_text = sprintf(
|
||||||
|
"作者:%s\n邮箱:%s\n网站:%s\n内容:%s",
|
||||||
|
$comment->comment_author,
|
||||||
|
$comment->comment_author_email,
|
||||||
|
$comment->comment_author_url,
|
||||||
|
$comment->comment_content
|
||||||
|
);
|
||||||
|
|
||||||
|
// 调用 AI API
|
||||||
|
$result = argon_call_ai_api_for_spam_detection($provider, $api_key, $model, $prompt, $comment_text);
|
||||||
|
|
||||||
|
if ($result && isset($result['is_spam'])) {
|
||||||
|
// 保存检测结果
|
||||||
|
update_comment_meta($comment_id, '_argon_spam_detection_result', $result);
|
||||||
|
update_comment_meta($comment_id, '_argon_spam_detection_time', time());
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 调用 AI API 进行垃圾评论检测
|
||||||
|
*/
|
||||||
|
function argon_call_ai_api_for_spam_detection($provider, $api_key, $model, $prompt, $content) {
|
||||||
|
$endpoint = get_option('argon_ai_summary_api_endpoint', '');
|
||||||
|
|
||||||
|
// 根据不同服务商设置默认端点和模型
|
||||||
|
$default_models = [
|
||||||
|
'openai' => 'gpt-4o-mini',
|
||||||
|
'anthropic' => 'claude-3-5-haiku-20241022',
|
||||||
|
'deepseek' => 'deepseek-chat',
|
||||||
|
'qianwen' => 'qwen-turbo',
|
||||||
|
'wenxin' => 'ernie-4.0-turbo-8k',
|
||||||
|
'doubao' => 'doubao-pro-32k',
|
||||||
|
'kimi' => 'moonshot-v1-8k',
|
||||||
|
'zhipu' => 'glm-4-flash',
|
||||||
|
'siliconflow' => 'Qwen/Qwen2.5-7B-Instruct'
|
||||||
|
];
|
||||||
|
|
||||||
|
if (empty($model) && isset($default_models[$provider])) {
|
||||||
|
$model = $default_models[$provider];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建请求
|
||||||
|
$messages = [
|
||||||
|
['role' => 'system', 'content' => $prompt],
|
||||||
|
['role' => 'user', 'content' => $content]
|
||||||
|
];
|
||||||
|
|
||||||
|
$body = [
|
||||||
|
'model' => $model,
|
||||||
|
'messages' => $messages,
|
||||||
|
'temperature' => 0.3,
|
||||||
|
'max_tokens' => 100
|
||||||
|
];
|
||||||
|
|
||||||
|
// 根据服务商设置端点
|
||||||
|
if (empty($endpoint)) {
|
||||||
|
$endpoints = [
|
||||||
|
'openai' => 'https://api.openai.com/v1/chat/completions',
|
||||||
|
'anthropic' => 'https://api.anthropic.com/v1/messages',
|
||||||
|
'deepseek' => 'https://api.deepseek.com/v1/chat/completions',
|
||||||
|
'qianwen' => 'https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions',
|
||||||
|
'wenxin' => 'https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions',
|
||||||
|
'doubao' => 'https://ark.cn-beijing.volces.com/api/v3/chat/completions',
|
||||||
|
'kimi' => 'https://api.moonshot.cn/v1/chat/completions',
|
||||||
|
'zhipu' => 'https://open.bigmodel.cn/api/paas/v4/chat/completions',
|
||||||
|
'siliconflow' => 'https://api.siliconflow.cn/v1/chat/completions'
|
||||||
|
];
|
||||||
|
$endpoint = isset($endpoints[$provider]) ? $endpoints[$provider] : $endpoints['openai'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Anthropic 特殊处理
|
||||||
|
if ($provider === 'anthropic') {
|
||||||
|
$body = [
|
||||||
|
'model' => $model,
|
||||||
|
'messages' => [['role' => 'user', 'content' => $prompt . "\n\n" . $content]],
|
||||||
|
'max_tokens' => 100
|
||||||
|
];
|
||||||
|
$headers = [
|
||||||
|
'x-api-key' => $api_key,
|
||||||
|
'anthropic-version' => '2023-06-01',
|
||||||
|
'Content-Type' => 'application/json'
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
$headers = [
|
||||||
|
'Authorization' => 'Bearer ' . $api_key,
|
||||||
|
'Content-Type' => 'application/json'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = wp_remote_post($endpoint, [
|
||||||
|
'headers' => $headers,
|
||||||
|
'body' => json_encode($body),
|
||||||
|
'timeout' => 30
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (is_wp_error($response)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$response_body = json_decode(wp_remote_retrieve_body($response), true);
|
||||||
|
|
||||||
|
// 解析响应
|
||||||
|
$ai_response = '';
|
||||||
|
if ($provider === 'anthropic') {
|
||||||
|
if (isset($response_body['content'][0]['text'])) {
|
||||||
|
$ai_response = $response_body['content'][0]['text'];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (isset($response_body['choices'][0]['message']['content'])) {
|
||||||
|
$ai_response = $response_body['choices'][0]['message']['content'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($ai_response)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析 JSON 响应
|
||||||
|
$result = json_decode($ai_response, true);
|
||||||
|
if (!$result || !isset($result['is_spam'])) {
|
||||||
|
// 尝试从文本中提取 JSON
|
||||||
|
if (preg_match('/\{[^}]*"is_spam"[^}]*\}/s', $ai_response, $matches)) {
|
||||||
|
$result = json_decode($matches[0], true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($result && isset($result['is_spam'])) {
|
||||||
|
return [
|
||||||
|
'is_spam' => (bool)$result['is_spam'],
|
||||||
|
'reason' => isset($result['reason']) ? mb_substr($result['reason'], 0, 25) : '未知原因'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新评论发布时自动检测
|
||||||
|
*/
|
||||||
|
function argon_auto_detect_spam_on_comment($comment_id, $comment_approved) {
|
||||||
|
// 检查是否启用
|
||||||
|
if (get_option('argon_comment_spam_detection_enable', 'false') !== 'true') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$mode = get_option('argon_comment_spam_detection_mode', 'manual');
|
||||||
|
if ($mode === 'manual') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 抽查模式:20% 概率检测
|
||||||
|
if ($mode === 'sample' && rand(1, 100) > 20) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$comment = get_comment($comment_id);
|
||||||
|
if (!$comment) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 跳过已登录用户
|
||||||
|
if (get_option('argon_comment_spam_detection_exclude_logged_in', 'true') === 'true' && $comment->user_id > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 异步检测
|
||||||
|
wp_schedule_single_event(time(), 'argon_async_spam_detection', [$comment_id]);
|
||||||
|
}
|
||||||
|
add_action('comment_post', 'argon_auto_detect_spam_on_comment', 10, 2);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 异步执行垃圾评论检测
|
||||||
|
*/
|
||||||
|
function argon_async_spam_detection_handler($comment_id) {
|
||||||
|
$result = argon_detect_spam_comment($comment_id);
|
||||||
|
|
||||||
|
if ($result && $result['is_spam']) {
|
||||||
|
// 移入回收站
|
||||||
|
wp_trash_comment($comment_id);
|
||||||
|
|
||||||
|
// 记录日志
|
||||||
|
update_comment_meta($comment_id, '_argon_spam_auto_trashed', true);
|
||||||
|
update_comment_meta($comment_id, '_argon_spam_trash_reason', $result['reason']);
|
||||||
|
update_comment_meta($comment_id, '_argon_spam_trash_time', time());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
add_action('argon_async_spam_detection', 'argon_async_spam_detection_handler');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AJAX: 开始批量扫描
|
||||||
|
*/
|
||||||
|
function argon_spam_detection_scan() {
|
||||||
|
check_ajax_referer('argon_spam_detection_scan', 'nonce');
|
||||||
|
|
||||||
|
if (!current_user_can('moderate_comments')) {
|
||||||
|
wp_send_json_error(__('权限不足', 'argon'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$scan_type = isset($_POST['scan_type']) ? sanitize_text_field($_POST['scan_type']) : 'all';
|
||||||
|
|
||||||
|
// 获取评论列表
|
||||||
|
$args = [
|
||||||
|
'status' => $scan_type === 'pending' ? 'hold' : 'approve',
|
||||||
|
'number' => 0,
|
||||||
|
'orderby' => 'comment_ID',
|
||||||
|
'order' => 'DESC'
|
||||||
|
];
|
||||||
|
|
||||||
|
$comments = get_comments($args);
|
||||||
|
$comment_ids = array_map(function($comment) {
|
||||||
|
return $comment->comment_ID;
|
||||||
|
}, $comments);
|
||||||
|
|
||||||
|
// 保存扫描任务
|
||||||
|
set_transient('argon_spam_scan_task', [
|
||||||
|
'status' => 'running',
|
||||||
|
'total' => count($comment_ids),
|
||||||
|
'processed' => 0,
|
||||||
|
'comment_ids' => $comment_ids,
|
||||||
|
'results' => [],
|
||||||
|
'current_index' => 0
|
||||||
|
], 3600);
|
||||||
|
|
||||||
|
// 启动后台处理
|
||||||
|
wp_schedule_single_event(time(), 'argon_spam_scan_process');
|
||||||
|
|
||||||
|
wp_send_json_success(['message' => __('扫描已开始', 'argon')]);
|
||||||
|
}
|
||||||
|
add_action('wp_ajax_argon_spam_detection_scan', 'argon_spam_detection_scan');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 后台处理扫描任务
|
||||||
|
*/
|
||||||
|
function argon_spam_scan_process_handler() {
|
||||||
|
$task = get_transient('argon_spam_scan_task');
|
||||||
|
if (!$task || $task['status'] !== 'running') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$batch_size = 5; // 每批处理 5 条
|
||||||
|
$end_index = min($task['current_index'] + $batch_size, $task['total']);
|
||||||
|
|
||||||
|
for ($i = $task['current_index']; $i < $end_index; $i++) {
|
||||||
|
$comment_id = $task['comment_ids'][$i];
|
||||||
|
$result = argon_detect_spam_comment($comment_id);
|
||||||
|
|
||||||
|
if ($result && $result['is_spam']) {
|
||||||
|
$comment = get_comment($comment_id);
|
||||||
|
$task['results'][] = [
|
||||||
|
'comment_id' => $comment_id,
|
||||||
|
'author' => $comment->comment_author,
|
||||||
|
'content' => mb_substr(strip_tags($comment->comment_content), 0, 100),
|
||||||
|
'reason' => $result['reason']
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$task['processed']++;
|
||||||
|
}
|
||||||
|
|
||||||
|
$task['current_index'] = $end_index;
|
||||||
|
|
||||||
|
if ($task['current_index'] >= $task['total']) {
|
||||||
|
$task['status'] = 'completed';
|
||||||
|
}
|
||||||
|
|
||||||
|
set_transient('argon_spam_scan_task', $task, 3600);
|
||||||
|
|
||||||
|
// 继续处理
|
||||||
|
if ($task['status'] === 'running') {
|
||||||
|
wp_schedule_single_event(time() + 2, 'argon_spam_scan_process');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
add_action('argon_spam_scan_process', 'argon_spam_scan_process_handler');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AJAX: 获取扫描进度
|
||||||
|
*/
|
||||||
|
function argon_spam_detection_get_progress() {
|
||||||
|
check_ajax_referer('argon_spam_detection_get_progress', 'nonce');
|
||||||
|
|
||||||
|
if (!current_user_can('moderate_comments')) {
|
||||||
|
wp_send_json_error(__('权限不足', 'argon'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$task = get_transient('argon_spam_scan_task');
|
||||||
|
if (!$task) {
|
||||||
|
wp_send_json_error(__('未找到扫描任务', 'argon'));
|
||||||
|
}
|
||||||
|
|
||||||
|
wp_send_json_success([
|
||||||
|
'status' => $task['status'],
|
||||||
|
'total' => $task['total'],
|
||||||
|
'processed' => $task['processed'],
|
||||||
|
'results' => isset($task['results']) ? $task['results'] : []
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
add_action('wp_ajax_argon_spam_detection_get_progress', 'argon_spam_detection_get_progress');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AJAX: 将评论移入回收站
|
||||||
|
*/
|
||||||
|
function argon_spam_detection_trash_comment() {
|
||||||
|
check_ajax_referer('argon_spam_detection_trash_comment', 'nonce');
|
||||||
|
|
||||||
|
if (!current_user_can('moderate_comments')) {
|
||||||
|
wp_send_json_error(__('权限不足', 'argon'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$comment_id = isset($_POST['comment_id']) ? intval($_POST['comment_id']) : 0;
|
||||||
|
if (!$comment_id) {
|
||||||
|
wp_send_json_error(__('无效的评论 ID', 'argon'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = wp_trash_comment($comment_id);
|
||||||
|
if ($result) {
|
||||||
|
update_comment_meta($comment_id, '_argon_spam_manual_trashed', true);
|
||||||
|
update_comment_meta($comment_id, '_argon_spam_trash_time', time());
|
||||||
|
wp_send_json_success();
|
||||||
|
} else {
|
||||||
|
wp_send_json_error(__('移入回收站失败', 'argon'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
add_action('wp_ajax_argon_spam_detection_trash_comment', 'argon_spam_detection_trash_comment');
|
||||||
|
|||||||
226
settings.php
226
settings.php
@@ -3865,6 +3865,226 @@ window.pjaxLoaded = function(){
|
|||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
<tr><th class="subtitle"><h3 id="subsection-comment-spam-detection"><?php _e('AI 垃圾评论识别', 'argon');?></h3></th></tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<th><label><?php _e('启用 AI 垃圾评论识别', 'argon');?></label></th>
|
||||||
|
<td>
|
||||||
|
<?php $argon_comment_spam_detection_enable = get_option('argon_comment_spam_detection_enable', 'false'); ?>
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" name="argon_comment_spam_detection_enable" value="true" <?php if ($argon_comment_spam_detection_enable=='true'){echo 'checked';}?>/>
|
||||||
|
<?php _e('启用 AI 自动识别垃圾评论', 'argon');?>
|
||||||
|
</label>
|
||||||
|
<p class="description"><?php _e('开启后,将使用 AI 自动识别广告、反动、违法等垃圾评论,并自动移入回收站。', 'argon');?><br/><?php _e('注意:需要先在 "文章功能 - AI 文章摘要" 中配置 AI 服务商和 API 密钥。', 'argon');?></p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<th><label><?php _e('检测提示词', 'argon');?></label></th>
|
||||||
|
<td>
|
||||||
|
<textarea rows="6" cols="70" name="argon_comment_spam_detection_prompt"><?php echo get_option('argon_comment_spam_detection_prompt', '你是一个专业的内容审核助手。请判断以下评论是否为垃圾评论。垃圾评论包括但不限于:广告推广、反动言论、错误政治观点、时政敏感内容、违法信息、色情暴力、恶意攻击等。
|
||||||
|
|
||||||
|
请仅返回 JSON 格式:{"is_spam": true/false, "reason": "理由(25字以内)"}
|
||||||
|
|
||||||
|
如果是正常评论,reason 填写 "正常"。如果是垃圾评论,简要说明原因。'); ?></textarea>
|
||||||
|
<p class="description"><?php _e('自定义 AI 识别垃圾评论时使用的提示词。建议保持简洁以降低 token 消耗。', 'argon');?></p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<th><label><?php _e('检测模式', 'argon');?></label></th>
|
||||||
|
<td>
|
||||||
|
<select name="argon_comment_spam_detection_mode">
|
||||||
|
<?php $argon_comment_spam_detection_mode = get_option('argon_comment_spam_detection_mode', 'manual'); ?>
|
||||||
|
<option value="manual" <?php if ($argon_comment_spam_detection_mode=='manual'){echo 'selected';} ?>><?php _e('仅手动检测', 'argon');?></option>
|
||||||
|
<option value="sample" <?php if ($argon_comment_spam_detection_mode=='sample'){echo 'selected';} ?>><?php _e('抽查模式 (随机检测 20%)', 'argon');?></option>
|
||||||
|
<option value="all" <?php if ($argon_comment_spam_detection_mode=='all'){echo 'selected';} ?>><?php _e('全量检测 (每条评论都检测)', 'argon');?></option>
|
||||||
|
</select>
|
||||||
|
<p class="description">
|
||||||
|
<?php _e('仅手动检测:只在管理员手动触发时检测', 'argon');?><br/>
|
||||||
|
<?php _e('抽查模式:新评论有 20% 概率被检测,节省 API 调用', 'argon');?><br/>
|
||||||
|
<?php _e('全量检测:所有新评论都会被检测(推荐,但会增加 API 消耗)', 'argon');?>
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<th><label><?php _e('检测范围', 'argon');?></label></th>
|
||||||
|
<td>
|
||||||
|
<?php $argon_comment_spam_detection_exclude_logged_in = get_option('argon_comment_spam_detection_exclude_logged_in', 'true'); ?>
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" name="argon_comment_spam_detection_exclude_logged_in" value="true" <?php if ($argon_comment_spam_detection_exclude_logged_in=='true'){echo 'checked';}?>/>
|
||||||
|
<?php _e('跳过已登录用户的评论', 'argon');?>
|
||||||
|
</label>
|
||||||
|
<p class="description"><?php _e('开启后,已登录用户(包括管理员)的评论不会被检测。', 'argon');?></p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<th><label><?php _e('手动批量检测', 'argon');?></label></th>
|
||||||
|
<td>
|
||||||
|
<div style="margin-bottom: 15px;">
|
||||||
|
<button type="button" class="button button-primary" id="argon-spam-detection-scan-all"><?php _e('全站评论扫描', 'argon');?></button>
|
||||||
|
<button type="button" class="button" id="argon-spam-detection-scan-pending" style="margin-left: 10px;"><?php _e('仅扫描待审核评论', 'argon');?></button>
|
||||||
|
<span id="argon-spam-detection-status" style="margin-left: 15px; color: #666;"></span>
|
||||||
|
</div>
|
||||||
|
<div id="argon-spam-detection-progress" style="display: none; margin-bottom: 15px;">
|
||||||
|
<div style="background: #f0f0f1; border-radius: 4px; height: 24px; position: relative; overflow: hidden;">
|
||||||
|
<div id="argon-spam-detection-progress-bar" style="background: var(--themecolor, #5e72e4); height: 100%; width: 0%; transition: width 0.3s;"></div>
|
||||||
|
<span id="argon-spam-detection-progress-text" style="position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); font-size: 12px; font-weight: 600; color: #333;"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="argon-spam-detection-results" style="display: none; margin-top: 15px; padding: 15px; background: #fff; border: 1px solid #ddd; border-radius: 4px; max-height: 400px; overflow-y: auto;">
|
||||||
|
<h4 style="margin-top: 0;"><?php _e('检测结果', 'argon');?></h4>
|
||||||
|
<div id="argon-spam-detection-results-content"></div>
|
||||||
|
</div>
|
||||||
|
<p class="description">
|
||||||
|
<?php _e('手动扫描现有评论,识别垃圾评论。扫描不包括已在回收站的评论。', 'argon');?><br/>
|
||||||
|
<?php _e('检测到的垃圾评论会被标记,您可以选择性地移入回收站。', 'argon');?>
|
||||||
|
</p>
|
||||||
|
<script>
|
||||||
|
jQuery(document).ready(function($) {
|
||||||
|
let isScanning = false;
|
||||||
|
let scanAborted = false;
|
||||||
|
|
||||||
|
function startScan(scanType) {
|
||||||
|
if (isScanning) {
|
||||||
|
alert('<?php _e('正在扫描中,请稍候', 'argon');?>');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!confirm('<?php _e('确定要开始扫描吗?这可能需要一些时间。', 'argon');?>')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
isScanning = true;
|
||||||
|
scanAborted = false;
|
||||||
|
$('#argon-spam-detection-scan-all, #argon-spam-detection-scan-pending').prop('disabled', true);
|
||||||
|
$('#argon-spam-detection-status').text('<?php _e('正在扫描...', 'argon');?>');
|
||||||
|
$('#argon-spam-detection-progress').show();
|
||||||
|
$('#argon-spam-detection-results').hide();
|
||||||
|
$('#argon-spam-detection-progress-bar').css('width', '0%');
|
||||||
|
$('#argon-spam-detection-progress-text').text('0%');
|
||||||
|
|
||||||
|
$.post(ajaxurl, {
|
||||||
|
action: 'argon_spam_detection_scan',
|
||||||
|
nonce: '<?php echo wp_create_nonce('argon_spam_detection_scan'); ?>',
|
||||||
|
scan_type: scanType
|
||||||
|
}, function(response) {
|
||||||
|
if (response.success) {
|
||||||
|
pollScanProgress();
|
||||||
|
} else {
|
||||||
|
isScanning = false;
|
||||||
|
$('#argon-spam-detection-scan-all, #argon-spam-detection-scan-pending').prop('disabled', false);
|
||||||
|
$('#argon-spam-detection-status').text('<?php _e('扫描失败', 'argon');?>: ' + (response.data || ''));
|
||||||
|
$('#argon-spam-detection-progress').hide();
|
||||||
|
}
|
||||||
|
}).fail(function() {
|
||||||
|
isScanning = false;
|
||||||
|
$('#argon-spam-detection-scan-all, #argon-spam-detection-scan-pending').prop('disabled', false);
|
||||||
|
$('#argon-spam-detection-status').text('<?php _e('请求失败', 'argon');?>');
|
||||||
|
$('#argon-spam-detection-progress').hide();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function pollScanProgress() {
|
||||||
|
if (scanAborted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$.post(ajaxurl, {
|
||||||
|
action: 'argon_spam_detection_get_progress',
|
||||||
|
nonce: '<?php echo wp_create_nonce('argon_spam_detection_get_progress'); ?>'
|
||||||
|
}, function(response) {
|
||||||
|
if (response.success) {
|
||||||
|
const data = response.data;
|
||||||
|
const percent = Math.round((data.processed / data.total) * 100);
|
||||||
|
$('#argon-spam-detection-progress-bar').css('width', percent + '%');
|
||||||
|
$('#argon-spam-detection-progress-text').text(percent + '% (' + data.processed + '/' + data.total + ')');
|
||||||
|
$('#argon-spam-detection-status').text('<?php _e('已处理', 'argon');?> ' + data.processed + ' / ' + data.total);
|
||||||
|
|
||||||
|
if (data.status === 'completed') {
|
||||||
|
isScanning = false;
|
||||||
|
$('#argon-spam-detection-scan-all, #argon-spam-detection-scan-pending').prop('disabled', false);
|
||||||
|
$('#argon-spam-detection-status').text('<?php _e('扫描完成', 'argon');?>');
|
||||||
|
displayResults(data.results);
|
||||||
|
} else if (data.status === 'error') {
|
||||||
|
isScanning = false;
|
||||||
|
$('#argon-spam-detection-scan-all, #argon-spam-detection-scan-pending').prop('disabled', false);
|
||||||
|
$('#argon-spam-detection-status').text('<?php _e('扫描出错', 'argon');?>: ' + data.error);
|
||||||
|
$('#argon-spam-detection-progress').hide();
|
||||||
|
} else {
|
||||||
|
setTimeout(pollScanProgress, 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function displayResults(results) {
|
||||||
|
if (!results || results.length === 0) {
|
||||||
|
$('#argon-spam-detection-results-content').html('<p><?php _e('未发现垃圾评论', 'argon');?></p>');
|
||||||
|
$('#argon-spam-detection-results').show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let html = '<table class="wp-list-table widefat fixed striped" style="margin-top: 10px;"><thead><tr><th><?php _e('评论 ID', 'argon');?></th><th><?php _e('作者', 'argon');?></th><th><?php _e('内容', 'argon');?></th><th><?php _e('识别理由', 'argon');?></th><th><?php _e('操作', 'argon');?></th></tr></thead><tbody>';
|
||||||
|
|
||||||
|
results.forEach(function(item) {
|
||||||
|
html += '<tr data-comment-id="' + item.comment_id + '">';
|
||||||
|
html += '<td>' + item.comment_id + '</td>';
|
||||||
|
html += '<td>' + $('<div>').text(item.author).html() + '</td>';
|
||||||
|
html += '<td style="max-width: 300px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">' + $('<div>').text(item.content).html() + '</td>';
|
||||||
|
html += '<td>' + $('<div>').text(item.reason).html() + '</td>';
|
||||||
|
html += '<td><button type="button" class="button button-small argon-spam-trash-btn" data-comment-id="' + item.comment_id + '"><?php _e('移入回收站', 'argon');?></button></td>';
|
||||||
|
html += '</tr>';
|
||||||
|
});
|
||||||
|
|
||||||
|
html += '</tbody></table>';
|
||||||
|
$('#argon-spam-detection-results-content').html(html);
|
||||||
|
$('#argon-spam-detection-results').show();
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).on('click', '.argon-spam-trash-btn', function() {
|
||||||
|
const btn = $(this);
|
||||||
|
const commentId = btn.data('comment-id');
|
||||||
|
|
||||||
|
if (!confirm('<?php _e('确定要将此评论移入回收站吗?', 'argon');?>')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
btn.prop('disabled', true).text('<?php _e('处理中...', 'argon');?>');
|
||||||
|
|
||||||
|
$.post(ajaxurl, {
|
||||||
|
action: 'argon_spam_detection_trash_comment',
|
||||||
|
nonce: '<?php echo wp_create_nonce('argon_spam_detection_trash_comment'); ?>',
|
||||||
|
comment_id: commentId
|
||||||
|
}, function(response) {
|
||||||
|
if (response.success) {
|
||||||
|
btn.closest('tr').fadeOut(300, function() {
|
||||||
|
$(this).remove();
|
||||||
|
if ($('#argon-spam-detection-results-content tbody tr').length === 0) {
|
||||||
|
$('#argon-spam-detection-results-content').html('<p><?php _e('所有标记的垃圾评论已处理', 'argon');?></p>');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
alert('<?php _e('操作失败', 'argon');?>: ' + (response.data || ''));
|
||||||
|
btn.prop('disabled', false).text('<?php _e('移入回收站', 'argon');?>');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#argon-spam-detection-scan-all').on('click', function() {
|
||||||
|
startScan('all');
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#argon-spam-detection-scan-pending').on('click', function() {
|
||||||
|
startScan('pending');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
<tr><th class="subtitle"><h3 id="subsection-comment-appearance"><?php _e('评论区外观', 'argon');?></h3></th></tr>
|
<tr><th class="subtitle"><h3 id="subsection-comment-appearance"><?php _e('评论区外观', 'argon');?></h3></th></tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
@@ -6360,6 +6580,12 @@ function argon_update_themeoptions(){
|
|||||||
argon_update_option('argon_ai_summary_prompt');
|
argon_update_option('argon_ai_summary_prompt');
|
||||||
argon_update_option('argon_ai_summary_exclude_ids');
|
argon_update_option('argon_ai_summary_exclude_ids');
|
||||||
|
|
||||||
|
//AI 垃圾评论识别
|
||||||
|
argon_update_option_checkbox('argon_comment_spam_detection_enable');
|
||||||
|
argon_update_option('argon_comment_spam_detection_prompt');
|
||||||
|
argon_update_option('argon_comment_spam_detection_mode');
|
||||||
|
argon_update_option_checkbox('argon_comment_spam_detection_exclude_logged_in');
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user