feat: 批量检测集成统一接口并添加AI查询统计页面
- 修改 argon_batch_detect_spam_comments() 使用统一的 argon_ai_query() 接口 - 删除旧的 argon_call_ai_api_for_batch_spam_detection() 函数 - 添加 argon_register_ai_query_stats_page() 注册统计页面 - 添加 argon_render_ai_query_stats_page() 渲染统计页面 - 统计页面显示总查询次数、成功率、平均响应时间、失败次数 - 按场景和服务商分别统计查询数据 - 显示最近30天的查询趋势 - 在 settings.php 的 AI 摘要设置中添加查看统计链接 统计页面功能: - 总览卡片:总查询次数、成功率、平均响应时间、失败次数 - 按场景统计:文章摘要、垃圾评论检测、批量检测等 - 按服务商统计:OpenAI、Claude、DeepSeek 等 - 查询趋势:最近30天每日查询数据
This commit is contained in:
310
functions.php
310
functions.php
@@ -6702,6 +6702,185 @@ function argon_ajax_get_ai_query_stats() {
|
||||
}
|
||||
add_action('wp_ajax_argon_get_ai_query_stats', 'argon_ajax_get_ai_query_stats');
|
||||
|
||||
/**
|
||||
* 注册 AI 查询统计页面
|
||||
*/
|
||||
function argon_register_ai_query_stats_page() {
|
||||
add_submenu_page(
|
||||
null, // 不在菜单中显示,通过其他方式访问
|
||||
__('AI 查询统计', 'argon'),
|
||||
__('AI 查询统计', 'argon'),
|
||||
'manage_options',
|
||||
'argon-ai-query-stats',
|
||||
'argon_render_ai_query_stats_page'
|
||||
);
|
||||
}
|
||||
add_action('admin_menu', 'argon_register_ai_query_stats_page');
|
||||
|
||||
/**
|
||||
* 渲染 AI 查询统计页面
|
||||
*/
|
||||
function argon_render_ai_query_stats_page() {
|
||||
if (!current_user_can('manage_options')) {
|
||||
wp_die(__('权限不足', 'argon'));
|
||||
}
|
||||
|
||||
global $wpdb;
|
||||
$table_name = $wpdb->prefix . 'argon_ai_query_log';
|
||||
|
||||
// 获取统计数据
|
||||
$stats = argon_get_ai_query_stats();
|
||||
|
||||
// 获取最近30天的查询趋势
|
||||
$trend_data = $wpdb->get_results("
|
||||
SELECT
|
||||
DATE(query_time) as date,
|
||||
COUNT(*) as total,
|
||||
SUM(CASE WHEN status = 'success' THEN 1 ELSE 0 END) as success,
|
||||
AVG(response_time) as avg_time
|
||||
FROM $table_name
|
||||
WHERE query_time >= DATE_SUB(NOW(), INTERVAL 30 DAY)
|
||||
GROUP BY DATE(query_time)
|
||||
ORDER BY date DESC
|
||||
LIMIT 30
|
||||
", ARRAY_A);
|
||||
|
||||
?>
|
||||
<div class="wrap">
|
||||
<h1><?php _e('AI 查询统计', 'argon'); ?></h1>
|
||||
|
||||
<div class="argon-ai-stats-container" style="margin-top: 20px;">
|
||||
<!-- 总览卡片 -->
|
||||
<div class="argon-stats-cards" style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 20px; margin-bottom: 30px;">
|
||||
<div class="argon-stat-card" style="background: #fff; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
|
||||
<h3 style="margin: 0 0 10px 0; color: #666; font-size: 14px;"><?php _e('总查询次数', 'argon'); ?></h3>
|
||||
<p style="margin: 0; font-size: 32px; font-weight: bold; color: #0073aa;"><?php echo number_format($stats['total_queries']); ?></p>
|
||||
</div>
|
||||
|
||||
<div class="argon-stat-card" style="background: #fff; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
|
||||
<h3 style="margin: 0 0 10px 0; color: #666; font-size: 14px;"><?php _e('成功率', 'argon'); ?></h3>
|
||||
<p style="margin: 0; font-size: 32px; font-weight: bold; color: #46b450;"><?php echo $stats['success_rate']; ?>%</p>
|
||||
</div>
|
||||
|
||||
<div class="argon-stat-card" style="background: #fff; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
|
||||
<h3 style="margin: 0 0 10px 0; color: #666; font-size: 14px;"><?php _e('平均响应时间', 'argon'); ?></h3>
|
||||
<p style="margin: 0; font-size: 32px; font-weight: bold; color: #f0b849;"><?php echo round($stats['avg_response_time']); ?>ms</p>
|
||||
</div>
|
||||
|
||||
<div class="argon-stat-card" style="background: #fff; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
|
||||
<h3 style="margin: 0 0 10px 0; color: #666; font-size: 14px;"><?php _e('失败次数', 'argon'); ?></h3>
|
||||
<p style="margin: 0; font-size: 32px; font-weight: bold; color: #dc3232;"><?php echo number_format($stats['error_queries']); ?></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 按场景统计 -->
|
||||
<div class="argon-stats-section" style="background: #fff; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); margin-bottom: 20px;">
|
||||
<h2 style="margin-top: 0;"><?php _e('按场景统计', 'argon'); ?></h2>
|
||||
<table class="wp-list-table widefat fixed striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php _e('场景', 'argon'); ?></th>
|
||||
<th><?php _e('查询次数', 'argon'); ?></th>
|
||||
<th><?php _e('平均响应时间', 'argon'); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
$scenario_names = [
|
||||
'summary' => __('文章摘要', 'argon'),
|
||||
'spam_detection' => __('垃圾评论检测', 'argon'),
|
||||
'spam_detection_batch' => __('批量垃圾评论检测', 'argon'),
|
||||
'keyword_extraction' => __('关键词提取', 'argon'),
|
||||
'test' => __('测试', 'argon')
|
||||
];
|
||||
|
||||
foreach ($stats['by_scenario'] as $row):
|
||||
$scenario_name = isset($scenario_names[$row['scenario']]) ? $scenario_names[$row['scenario']] : $row['scenario'];
|
||||
?>
|
||||
<tr>
|
||||
<td><?php echo esc_html($scenario_name); ?></td>
|
||||
<td><?php echo number_format($row['count']); ?></td>
|
||||
<td><?php echo round($row['avg_time'], 2); ?>ms</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- 按服务商统计 -->
|
||||
<div class="argon-stats-section" style="background: #fff; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); margin-bottom: 20px;">
|
||||
<h2 style="margin-top: 0;"><?php _e('按服务商统计', 'argon'); ?></h2>
|
||||
<table class="wp-list-table widefat fixed striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php _e('服务商', 'argon'); ?></th>
|
||||
<th><?php _e('查询次数', 'argon'); ?></th>
|
||||
<th><?php _e('平均响应时间', 'argon'); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
$provider_names = [
|
||||
'openai' => 'OpenAI',
|
||||
'anthropic' => 'Anthropic Claude',
|
||||
'deepseek' => 'DeepSeek',
|
||||
'xiaomi' => __('小米 Mimo', 'argon'),
|
||||
'qianwen' => __('通义千问', 'argon'),
|
||||
'wenxin' => __('文心一言', 'argon'),
|
||||
'doubao' => __('豆包', 'argon'),
|
||||
'kimi' => 'Kimi',
|
||||
'zhipu' => __('智谱 AI', 'argon'),
|
||||
'siliconflow' => __('硅基流动', 'argon')
|
||||
];
|
||||
|
||||
foreach ($stats['by_provider'] as $row):
|
||||
$provider_name = isset($provider_names[$row['provider']]) ? $provider_names[$row['provider']] : $row['provider'];
|
||||
?>
|
||||
<tr>
|
||||
<td><?php echo esc_html($provider_name); ?></td>
|
||||
<td><?php echo number_format($row['count']); ?></td>
|
||||
<td><?php echo round($row['avg_time'], 2); ?>ms</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- 查询趋势 -->
|
||||
<div class="argon-stats-section" style="background: #fff; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
|
||||
<h2 style="margin-top: 0;"><?php _e('最近30天查询趋势', 'argon'); ?></h2>
|
||||
<table class="wp-list-table widefat fixed striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php _e('日期', 'argon'); ?></th>
|
||||
<th><?php _e('总查询', 'argon'); ?></th>
|
||||
<th><?php _e('成功', 'argon'); ?></th>
|
||||
<th><?php _e('平均响应时间', 'argon'); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($trend_data as $row): ?>
|
||||
<tr>
|
||||
<td><?php echo esc_html($row['date']); ?></td>
|
||||
<td><?php echo number_format($row['total']); ?></td>
|
||||
<td><?php echo number_format($row['success']); ?></td>
|
||||
<td><?php echo round($row['avg_time'], 2); ?>ms</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p style="margin-top: 30px;">
|
||||
<a href="<?php echo admin_url('themes.php?page=argon-theme-options'); ?>" class="button">
|
||||
<?php _e('返回主题设置', 'argon'); ?>
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
// ==================== AI 文章摘要功能 ====================
|
||||
|
||||
/**
|
||||
@@ -9826,23 +10005,15 @@ add_action('wp_ajax_argon_spam_detection_scan', 'argon_spam_detection_scan');
|
||||
* @return array|false 检测结果或 false
|
||||
*/
|
||||
function argon_batch_detect_spam_comments($comments_data) {
|
||||
// 获取 AI 配置
|
||||
$provider = get_option('argon_ai_summary_provider', 'openai');
|
||||
$config = argon_get_ai_provider_config($provider);
|
||||
$api_key = $config['api_key'];
|
||||
$model = $config['model'];
|
||||
$prompt = get_option('argon_comment_spam_detection_prompt', '');
|
||||
// 获取配置
|
||||
$prompt_mode = get_option('argon_comment_spam_detection_prompt_mode', 'standard');
|
||||
$custom_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 填写 "正常"。如果是垃圾评论,简要说明原因。';
|
||||
// 根据模式选择 Prompt
|
||||
if ($prompt_mode === 'custom' && !empty($custom_prompt)) {
|
||||
$prompt = $custom_prompt . "\n\n请对每条评论返回检测结果。";
|
||||
} else {
|
||||
$prompt = argon_get_spam_detection_prompt($prompt_mode);
|
||||
}
|
||||
|
||||
// 构建批量检测内容
|
||||
@@ -9858,10 +10029,12 @@ function argon_batch_detect_spam_comments($comments_data) {
|
||||
);
|
||||
}
|
||||
|
||||
$batch_content .= "\n请返回 JSON 数组格式:[{\"id\": 评论ID, \"is_spam\": true/false, \"reason\": \"理由(25字以内)\"}]";
|
||||
$batch_content .= "\n请返回 JSON 数组格式:[{\"id\": 评论ID, \"is_spam\": true/false, \"reason\": \"理由(25字以内)\", \"confidence\": 0.0-1.0}]";
|
||||
|
||||
// 调用 AI API
|
||||
$ai_response = argon_call_ai_api_for_batch_spam_detection($provider, $api_key, $model, $prompt, $batch_content);
|
||||
// 使用统一的 AI 查询接口
|
||||
$ai_response = argon_ai_query('spam_detection_batch', $prompt, $batch_content, [
|
||||
'user_id' => get_current_user_id()
|
||||
]);
|
||||
|
||||
if (!$ai_response) {
|
||||
return false;
|
||||
@@ -9883,105 +10056,6 @@ function argon_batch_detect_spam_comments($comments_data) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用 AI API 进行批量垃圾评论检测
|
||||
*/
|
||||
function argon_call_ai_api_for_batch_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',
|
||||
'xiaomi' => 'MiMo-V2-Flash',
|
||||
'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' => 4000 // 批量检测需要更多 token
|
||||
];
|
||||
|
||||
// 根据服务商设置端点
|
||||
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',
|
||||
'xiaomi' => 'https://api.mimo.xiaomi.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' => 4000
|
||||
];
|
||||
$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' => 60 // 批量检测需要更长超时时间
|
||||
]);
|
||||
|
||||
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'];
|
||||
}
|
||||
}
|
||||
|
||||
return $ai_response;
|
||||
}
|
||||
|
||||
/**
|
||||
* 后台处理扫描任务(已废弃,保留以兼容旧代码)
|
||||
|
||||
10
settings.php
10
settings.php
@@ -2587,6 +2587,16 @@ function themeoptions_page(){
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th><label><?php _e('AI 查询统计', 'argon');?></label></th>
|
||||
<td>
|
||||
<a href="<?php echo admin_url('admin.php?page=argon-ai-query-stats'); ?>" class="button" target="_blank">
|
||||
<?php _e('查看 AI 查询统计', 'argon');?>
|
||||
</a>
|
||||
<p class="description"><?php _e('查看所有 AI 查询的统计信息,包括查询次数、成功率、响应时间等', 'argon');?></p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr><th class="subtitle"><h3 id="subsection-footnote"><?php _e('脚注引用', 'argon');?></h3></th></tr>
|
||||
|
||||
<tr>
|
||||
|
||||
Reference in New Issue
Block a user