feat: 为 AI 摘要功能添加详细的错误报告
- 新增 argon_log_ai_error() 统一错误处理函数 - 记录错误到 WordPress error_log 和文章 meta - 添加配置完整性检查(API 密钥、端点、模型) - 添加文章内容长度检查(至少50字) - 改进 OpenAI API 调用的错误处理 - 网络错误详细记录 - HTTP 状态码检查 - 响应格式验证 - 空内容检查 - 记录详细的调用信息(文章ID、标题、提供商、模型、内容长度) - 保存错误信息到文章 meta(_argon_ai_summary_error) - 保存错误时间到文章 meta(_argon_ai_summary_error_time) - 成功时清除错误记录 - 所有错误信息包含上下文数据(endpoint、model等)
This commit is contained in:
170
functions.php
170
functions.php
@@ -6651,6 +6651,35 @@ function argon_set_active_api($provider, $api_id) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 记录 AI API 错误
|
||||||
|
* @param string $provider 提供商名称
|
||||||
|
* @param string $error_type 错误类型
|
||||||
|
* @param string $error_message 错误信息
|
||||||
|
* @param int $post_id 文章ID
|
||||||
|
* @param array $extra_data 额外数据
|
||||||
|
*/
|
||||||
|
function argon_log_ai_error($provider, $error_type, $error_message, $post_id = 0, $extra_data = []) {
|
||||||
|
$log_message = sprintf(
|
||||||
|
'Argon AI Summary Error (%s): %s - %s',
|
||||||
|
$provider,
|
||||||
|
$error_type,
|
||||||
|
$error_message
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!empty($extra_data)) {
|
||||||
|
$log_message .= ' | 额外信息: ' . json_encode($extra_data, JSON_UNESCAPED_UNICODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
error_log($log_message);
|
||||||
|
|
||||||
|
if ($post_id > 0) {
|
||||||
|
$user_message = sprintf('%s %s: %s', $provider, $error_type, $error_message);
|
||||||
|
update_post_meta($post_id, '_argon_ai_summary_error', $user_message);
|
||||||
|
update_post_meta($post_id, '_argon_ai_summary_error_time', current_time('mysql'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成 AI 摘要
|
* 生成 AI 摘要
|
||||||
* @param WP_Post $post 文章对象
|
* @param WP_Post $post 文章对象
|
||||||
@@ -6661,7 +6690,15 @@ function argon_generate_ai_summary($post) {
|
|||||||
$config = argon_get_ai_provider_config($provider);
|
$config = argon_get_ai_provider_config($provider);
|
||||||
$api_key = $config['api_key'];
|
$api_key = $config['api_key'];
|
||||||
|
|
||||||
|
// 错误检查:API 密钥
|
||||||
if (empty($api_key)) {
|
if (empty($api_key)) {
|
||||||
|
argon_log_ai_error($provider, '配置错误', 'API 密钥未配置', $post->ID);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 错误检查:配置完整性
|
||||||
|
if (!isset($config['api_endpoint']) || !isset($config['model'])) {
|
||||||
|
argon_log_ai_error($provider, '配置错误', 'API 配置不完整', $post->ID, $config);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6670,39 +6707,85 @@ function argon_generate_ai_summary($post) {
|
|||||||
$content = preg_replace('/\s+/', ' ', $content);
|
$content = preg_replace('/\s+/', ' ', $content);
|
||||||
$content = mb_substr($content, 0, 8000); // 限制长度
|
$content = mb_substr($content, 0, 8000); // 限制长度
|
||||||
|
|
||||||
$prompt = get_option('argon_ai_summary_prompt', '你是一个专业的内容摘要助手。请仔细阅读以下文章内容,用简洁、准确的语言总结文章的核心观点和主要内容。要求:1) 控制在 100-150 字以内;2) 突出文章的关键信息和亮点;3) 使用通俗易懂的语言;4) 保持客观中立的语气。');
|
// 错误检查:文章内容
|
||||||
|
if (empty($content) || mb_strlen($content) < 50) {
|
||||||
// 根据不同服务商调用 API
|
argon_log_ai_error($provider, '内容错误', '文章内容过短(至少需要50字)', $post->ID, [
|
||||||
switch ($provider) {
|
'content_length' => mb_strlen($content)
|
||||||
case 'openai':
|
]);
|
||||||
return argon_call_openai_api($api_key, $prompt, $content);
|
|
||||||
case 'anthropic':
|
|
||||||
return argon_call_anthropic_api($api_key, $prompt, $content);
|
|
||||||
case 'deepseek':
|
|
||||||
return argon_call_deepseek_api($api_key, $prompt, $content);
|
|
||||||
case 'xiaomi':
|
|
||||||
return argon_call_xiaomi_api($api_key, $prompt, $content);
|
|
||||||
case 'qianwen':
|
|
||||||
return argon_call_qianwen_api($api_key, $prompt, $content);
|
|
||||||
case 'wenxin':
|
|
||||||
return argon_call_wenxin_api($api_key, $prompt, $content);
|
|
||||||
case 'doubao':
|
|
||||||
return argon_call_doubao_api($api_key, $prompt, $content);
|
|
||||||
case 'kimi':
|
|
||||||
return argon_call_kimi_api($api_key, $prompt, $content);
|
|
||||||
case 'zhipu':
|
|
||||||
return argon_call_zhipu_api($api_key, $prompt, $content);
|
|
||||||
case 'siliconflow':
|
|
||||||
return argon_call_siliconflow_api($api_key, $prompt, $content);
|
|
||||||
default:
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$prompt = get_option('argon_ai_summary_prompt', '你是一个专业的内容摘要助手。请仔细阅读以下文章内容,用简洁、准确的语言总结文章的核心观点和主要内容。要求:1) 控制在 100-150 字以内;2) 突出文章的关键信息和亮点;3) 使用通俗易懂的语言;4) 保持客观中立的语气。');
|
||||||
|
|
||||||
|
// 记录调用信息
|
||||||
|
error_log(sprintf(
|
||||||
|
'Argon AI Summary: 开始生成摘要 (文章ID: %d, 标题: %s, 提供商: %s, 模型: %s, 内容长度: %d)',
|
||||||
|
$post->ID,
|
||||||
|
$post->post_title,
|
||||||
|
$provider,
|
||||||
|
$config['model'],
|
||||||
|
mb_strlen($content)
|
||||||
|
));
|
||||||
|
|
||||||
|
// 根据不同服务商调用 API
|
||||||
|
$result = false;
|
||||||
|
switch ($provider) {
|
||||||
|
case 'openai':
|
||||||
|
$result = argon_call_openai_api($api_key, $prompt, $content, $post->ID);
|
||||||
|
break;
|
||||||
|
case 'anthropic':
|
||||||
|
$result = argon_call_anthropic_api($api_key, $prompt, $content, $post->ID);
|
||||||
|
break;
|
||||||
|
case 'deepseek':
|
||||||
|
$result = argon_call_deepseek_api($api_key, $prompt, $content, $post->ID);
|
||||||
|
break;
|
||||||
|
case 'xiaomi':
|
||||||
|
$result = argon_call_xiaomi_api($api_key, $prompt, $content, $post->ID);
|
||||||
|
break;
|
||||||
|
case 'qianwen':
|
||||||
|
$result = argon_call_qianwen_api($api_key, $prompt, $content, $post->ID);
|
||||||
|
break;
|
||||||
|
case 'wenxin':
|
||||||
|
$result = argon_call_wenxin_api($api_key, $prompt, $content, $post->ID);
|
||||||
|
break;
|
||||||
|
case 'doubao':
|
||||||
|
$result = argon_call_doubao_api($api_key, $prompt, $content, $post->ID);
|
||||||
|
break;
|
||||||
|
case 'kimi':
|
||||||
|
$result = argon_call_kimi_api($api_key, $prompt, $content, $post->ID);
|
||||||
|
break;
|
||||||
|
case 'zhipu':
|
||||||
|
$result = argon_call_zhipu_api($api_key, $prompt, $content, $post->ID);
|
||||||
|
break;
|
||||||
|
case 'siliconflow':
|
||||||
|
$result = argon_call_siliconflow_api($api_key, $prompt, $content, $post->ID);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
argon_log_ai_error($provider, '配置错误', '不支持的服务商', $post->ID);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查结果
|
||||||
|
if ($result === false) {
|
||||||
|
error_log('Argon AI Summary: API 调用失败 (文章ID: ' . $post->ID . ', 提供商: ' . $provider . ')');
|
||||||
|
// 错误信息已在具体的 API 调用函数中记录
|
||||||
|
} else {
|
||||||
|
error_log(sprintf(
|
||||||
|
'Argon AI Summary: 摘要生成成功 (文章ID: %d, 摘要长度: %d字)',
|
||||||
|
$post->ID,
|
||||||
|
mb_strlen($result)
|
||||||
|
));
|
||||||
|
delete_post_meta($post->ID, '_argon_ai_summary_error');
|
||||||
|
delete_post_meta($post->ID, '_argon_ai_summary_error_time');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 调用 OpenAI API
|
* 调用 OpenAI API
|
||||||
*/
|
*/
|
||||||
function argon_call_openai_api($api_key, $prompt, $content) {
|
function argon_call_openai_api($api_key, $prompt, $content, $post_id = 0) {
|
||||||
$provider = 'openai';
|
$provider = 'openai';
|
||||||
$config = argon_get_ai_provider_config($provider);
|
$config = argon_get_ai_provider_config($provider);
|
||||||
|
|
||||||
@@ -6729,18 +6812,49 @@ function argon_call_openai_api($api_key, $prompt, $content) {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
if (is_wp_error($response)) {
|
if (is_wp_error($response)) {
|
||||||
|
argon_log_ai_error('OpenAI', '网络错误', $response->get_error_message(), $post_id, [
|
||||||
|
'endpoint' => $endpoint
|
||||||
|
]);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$status_code = wp_remote_retrieve_response_code($response);
|
||||||
$body = json_decode(wp_remote_retrieve_body($response), true);
|
$body = json_decode(wp_remote_retrieve_body($response), true);
|
||||||
|
|
||||||
if (isset($body['choices'][0]['message']['content'])) {
|
// 检查 HTTP 状态码
|
||||||
return trim($body['choices'][0]['message']['content']);
|
if ($status_code !== 200) {
|
||||||
|
$error_msg = isset($body['error']['message']) ? $body['error']['message'] : '未知错误';
|
||||||
|
$error_type = isset($body['error']['type']) ? $body['error']['type'] : 'unknown';
|
||||||
|
argon_log_ai_error('OpenAI', 'API 错误 (HTTP ' . $status_code . ')', $error_msg, $post_id, [
|
||||||
|
'error_type' => $error_type,
|
||||||
|
'model' => $model,
|
||||||
|
'endpoint' => $endpoint
|
||||||
|
]);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 检查响应格式
|
||||||
|
if (!isset($body['choices'][0]['message']['content'])) {
|
||||||
|
argon_log_ai_error('OpenAI', '响应格式错误', '未找到预期的响应字段', $post_id, [
|
||||||
|
'response_keys' => array_keys($body),
|
||||||
|
'model' => $model
|
||||||
|
]);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$summary = trim($body['choices'][0]['message']['content']);
|
||||||
|
|
||||||
|
// 检查摘要内容
|
||||||
|
if (empty($summary)) {
|
||||||
|
argon_log_ai_error('OpenAI', '内容错误', '返回的摘要为空', $post_id, [
|
||||||
|
'model' => $model
|
||||||
|
]);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $summary;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 调用 Anthropic Claude API
|
* 调用 Anthropic Claude API
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user