File: /var/www/html/www.winghung.com/wp-content/plugins/upkyk-assistant-ai/admin/api-diagnostics-page.php
<?php
/**
* Upkyk AssistantAI API Key Diagnostics
*
* This utility will test your DeepSeek API key directly and display detailed information
* about the request and response to help diagnose authentication issues.
*/
// Exit if accessed directly
if (!defined('ABSPATH')) {
die(esc_html__('Direct access not allowed.', 'upkyk-assistant-ai'));
}
// Check for admin capabilities
if (!current_user_can('manage_options')) {
wp_die(esc_html__('You do not have sufficient permissions to access this page.', 'upkyk-assistant-ai'));
}
// Include necessary files for decryption
if (!class_exists('Upkyk_Assistant_AI_Admin')) {
require_once dirname(__FILE__) . '/class-upkyk-admin.php';
}
// Initialize admin class
$admin = new Upkyk_Assistant_AI_Admin();
// Get the encrypted key and provider
$provider = get_option('upkyk_assistant_ai_provider', 'deepseek');
$encrypted_key = get_option('upkyk_assistant_ai_api_key', '');
// Check if we have an encrypted key
if (empty($encrypted_key)) {
$status = 'error';
$message = esc_html__('No API key found in the database. Please set an API key first.', 'upkyk-assistant-ai');
} else {
// Try to decrypt
$api_key = $admin->decrypt_api_key($encrypted_key);
if (empty($api_key)) {
$status = 'error';
$message = esc_html__('Failed to decrypt API key. The encryption/decryption process is not working correctly.', 'upkyk-assistant-ai');
} else {
// We have a decrypted key, test it directly
$test_result = upkyk_test_api_directly($api_key, $provider);
$status = $test_result['success'] ? 'success' : 'error';
$message = $test_result['message'];
$details = $test_result['details'] ?? '';
}
}
/**
* Test API connection directly without any additional abstraction
*/
function upkyk_test_api_directly($api_key, $provider) {
$test_message = esc_html__("Test connection", 'upkyk-assistant-ai'); // Make the test string translatable just in case
// Trim the API key to remove any whitespace
$api_key = trim($api_key);
// Log key format for debugging (Keep this non-translatable, it's for debug logs)
$key_prefix = substr($api_key, 0, 8) . '...';
$key_length = strlen($api_key);
// Construct test data
switch ($provider) {
case 'deepseek':
$url = 'https://api.deepseek.com/v1/chat/completions';
$model = get_option('upkyk_assistant_ai_deepseek_model', 'deepseek-chat');
break;
case 'openai':
$url = 'https://api.openai.com/v1/chat/completions';
$model = get_option('upkyk_assistant_ai_openai_model', 'gpt-4o-mini');
break;
default:
return [
'success' => false,
/* translators: %s: Name of the invalid provider (e.g., "unknown") */
'message' => sprintf(esc_html__('Invalid provider: %s', 'upkyk-assistant-ai'), $provider),
'details' => esc_html__('Provider must be either deepseek or openai', 'upkyk-assistant-ai')
];
}
$data = [
"model" => $model,
"messages" => [["role" => "user", "content" => $test_message]],
"max_tokens" => 10
];
$request_data = [
'timeout' => 30,
'headers' => [
'Authorization' => 'Bearer ' . $api_key,
'Content-Type' => 'application/json'
],
'body' => json_encode($data)
];
// Make the request
$response = wp_remote_post($url, $request_data);
// Prepare response details (Keep these mostly non-translatable for debug context)
$details = [];
$details[] = "Request URL: " . $url;
$details[] = "API Key Format: Length = " . $key_length . ", Prefix = " . $key_prefix;
$details[] = "Model: " . $model;
$details[] = "Request Data: " . json_encode($data, JSON_PRETTY_PRINT);
// Handle errors
if (is_wp_error($response)) {
$error_message = $response->get_error_message();
$details[] = "WordPress Error: " . $error_message;
return [
'success' => false,
/* translators: %s: Specific connection error message from WordPress */
'message' => sprintf(esc_html__('Connection error: %s', 'upkyk-assistant-ai'), $error_message),
'details' => implode("\n", $details)
];
}
// Get response details
$response_code = wp_remote_retrieve_response_code($response);
$response_body = wp_remote_retrieve_body($response);
$response_headers = wp_remote_retrieve_headers($response);
$details[] = "Response Code: " . $response_code;
$details[] = "Response Headers: " . json_encode($response_headers, JSON_PRETTY_PRINT);
$details[] = "Response Body: " . $response_body;
// Analyze response
if ($response_code !== 200) {
$body_json = json_decode($response_body, true);
/* translators: %d: HTTP status code (e.g., 404, 500) */
$api_error_message = isset($body_json['error']['message']) ? $body_json['error']['message'] : sprintf(esc_html__('HTTP Error %d', 'upkyk-assistant-ai'), $response_code);
return [
'success' => false,
/* translators: %s: Specific error message returned by the API provider */
'message' => sprintf(esc_html__('API error: %s', 'upkyk-assistant-ai'), $api_error_message),
'details' => implode("\n", $details)
];
}
// Parse response
$body = json_decode($response_body, true);
if (!isset($body['choices'][0]['message']['content'])) {
return [
'success' => false,
'message' => esc_html__('Unexpected response format. API returned 200 but response structure is invalid.', 'upkyk-assistant-ai'),
'details' => implode("\n", $details)
];
}
return [
'success' => true,
/* translators: %s: A short snippet of the successful AI response content */
'message' => sprintf(esc_html__('API connection successful! Response: %s', 'upkyk-assistant-ai'), $body['choices'][0]['message']['content']),
'details' => implode("\n", $details)
];
}
// Enqueue script and localize strings for JS
function upkyk_enqueue_api_diagnostics_scripts() {
wp_enqueue_script('upkyk-api-diagnostics', UPKYK_ASSISTANT_AI_URL . 'admin/js/api-diagnostics.js', ['jquery'], UPKYK_ASSISTANT_AI_VERSION, true);
wp_localize_script('upkyk-api-diagnostics', 'upkykApiDiag', [
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('upkyk_assistant_ai_nonce'),
'text' => [
'test_custom_model' => esc_html__('Test Custom Model', 'upkyk-assistant-ai'),
/* translators: %s: Name of the AI model being tested (e.g., "gpt-4o-mini") */
'test_model_prefix' => esc_html__('Test %s', 'upkyk-assistant-ai'),
'testing' => esc_html__('Testing...', 'upkyk-assistant-ai'),
'enter_model_name' => esc_html__('Please enter a model name to test', 'upkyk-assistant-ai'),
'success' => esc_html__('Success!', 'upkyk-assistant-ai'),
'error' => esc_html__('Error:', 'upkyk-assistant-ai'),
'ai_response' => esc_html__('AI Response:', 'upkyk-assistant-ai'),
'no_details' => esc_html__('No detailed response available', 'upkyk-assistant-ai'),
'ajax_failed' => esc_html__('AJAX request failed. Please check your network connection.', 'upkyk-assistant-ai'),
'request_failed' => esc_html__('Request failed to complete.', 'upkyk-assistant-ai'),
'rebuild_warning' => esc_html__('WARNING: This will delete all existing phrases and keywords in the database. You will need to re-add them after rebuilding. Continue?', 'upkyk-assistant-ai'),
'rebuilding' => esc_html__('Rebuilding...', 'upkyk-assistant-ai'),
'rebuild_success' => esc_html__('Success! Database tables have been rebuilt successfully.', 'upkyk-assistant-ai'),
'rebuild_error' => esc_html__('Failed to rebuild database tables.', 'upkyk-assistant-ai'),
'delete_warning_1' => esc_html__("⚠️ EXTREME CAUTION ⚠️\n\nYou are about to PERMANENTLY DELETE ALL plugin data, including:\n\n- All chat history and conversations\n- All contact form submissions\n- All custom phrases\n- All uploaded documents and training data\n\nThis action CANNOT be undone!\n\nAre you absolutely sure you want to continue?", 'upkyk-assistant-ai'),
'delete_warning_2' => esc_html__("FINAL WARNING: This is your last chance to cancel.\n\nAll plugin data will be deleted permanently.\n\nContinue with deletion?", 'upkyk-assistant-ai'),
'deleting' => esc_html__('Deleting...', 'upkyk-assistant-ai'),
'delete_success' => esc_html__('Success! All plugin database tables have been permanently deleted.', 'upkyk-assistant-ai'),
'delete_error' => esc_html__('Failed to delete plugin tables.', 'upkyk-assistant-ai'),
/* translators: %s: Specific server error message */
'server_error' => esc_html__('Server error: %s', 'upkyk-assistant-ai'),
]
]);
}
add_action('admin_enqueue_scripts', 'upkyk_enqueue_api_diagnostics_scripts');
// Display the page
?>
<div class="wrap">
<div class="upkyk-admin-header">
<a href="<?php echo esc_url('https://upkyk.com/assistant-ai'); ?>" title="<?php echo esc_attr__('Upkyk Assistant AI Product Page', 'upkyk-assistant-ai'); ?>" target="_blank" rel="noopener noreferrer">
<div class="upkyk-logo">
<img src="<?php echo esc_url(UPKYK_ASSISTANT_AI_URL . 'assets/images/upkyk-logo.svg'); ?>" alt="<?php esc_attr_e('Upkyk Logo', 'upkyk-assistant-ai'); ?>">
</div>
</a>
</div>
<div class="upkyk-tab-content">
<div class="upkyk-tab-pane active">
<div class="upkyk-section-intro">
<h2><?php esc_html_e('API Diagnostics', 'upkyk-assistant-ai'); ?></h2>
<p><?php esc_html_e('Check API connection status and perform maintenance tasks.', 'upkyk-assistant-ai'); ?></p>
</div>
<div class="notice notice-<?php echo esc_attr($status); ?> is-dismissible">
<p><?php echo esc_html($message); ?></p>
</div>
<div class="upkyk-api-diagnostics">
<h2><?php esc_html_e('Current Configuration', 'upkyk-assistant-ai'); ?></h2>
<table class="form-table" role="presentation">
<tbody>
<tr>
<th scope="row"><?php esc_html_e('AI Provider:', 'upkyk-assistant-ai'); ?></th>
<td><?php echo esc_html($provider); ?></td>
</tr>
<tr>
<th scope="row"><?php esc_html_e('API Key Status:', 'upkyk-assistant-ai'); ?></th>
<td>
<?php if (!empty($encrypted_key)): ?>
<span style="color: #46b450; font-weight: bold; margin-right: 5px;">✓</span> <?php
/* translators: %d: Length (number of characters) of the encrypted API key */
printf(esc_html__('Encrypted key exists in database (length: %d)', 'upkyk-assistant-ai'), esc_html(strlen($encrypted_key)));
?>
<?php else: ?>
<span style="color: #dc3232; font-weight: bold; margin-right: 5px;">✗</span> <?php esc_html_e('No encrypted key found in database', 'upkyk-assistant-ai'); ?>
<?php endif; ?>
</td>
</tr>
<tr>
<th scope="row"><?php esc_html_e('Decryption Status:', 'upkyk-assistant-ai'); ?></th>
<td>
<?php if (!empty($encrypted_key) && !empty($api_key)): ?>
<span style="color: #46b450; font-weight: bold; margin-right: 5px;">✓</span> <?php
/* translators: %d: Length (number of characters) of the decrypted API key */
printf(esc_html__('Key successfully decrypted (length: %d)', 'upkyk-assistant-ai'), esc_html(strlen($api_key)));
?>
<?php else: ?>
<span style="color: #dc3232; font-weight: bold; margin-right: 5px;">✗</span> <?php esc_html_e('Decryption failed', 'upkyk-assistant-ai'); ?>
<?php endif; ?>
</td>
</tr>
</tbody>
</table>
<?php if (!empty($details)): ?>
<h2><?php esc_html_e('Diagnostic Details', 'upkyk-assistant-ai'); ?></h2>
<div style="background: #f8f8f8; border: 1px solid #e5e5e5; border-radius: 3px; padding: 10px; margin-bottom: 20px; overflow: auto; max-height: 300px;" class="upkyk-diagnostic-details">
<pre style="margin: 0; white-space: pre-wrap; font-size: 13px; font-family: Consolas, Monaco, monospace;"><?php echo esc_html($details); ?></pre>
</div>
<?php endif; ?>
<h2><?php esc_html_e('Test API Models', 'upkyk-assistant-ai'); ?></h2>
<p><?php
/* translators: %s: Name of the AI provider (e.g., "OpenAI", "DeepSeek") */
printf(esc_html__('Test different models available for the %s provider to find the best one for your use case.', 'upkyk-assistant-ai'), '<strong>' . esc_html(ucfirst($provider)) . '</strong>');
?></p>
<?php if ($provider === 'deepseek'): ?>
<div class="model-tester">
<div style="margin: 15px 0; display: flex; flex-wrap: wrap; gap: 10px; align-items: center;" class="model-selector">
<button class="button test-model-button" data-model="deepseek-chat" data-provider="deepseek"><?php /* translators: %s: Name of the AI model being tested */ printf(esc_html__('Test %s', 'upkyk-assistant-ai'), 'deepseek-chat'); ?></button>
<button class="button test-model-button" data-model="deepseek-chat-v1" data-provider="deepseek"><?php /* translators: %s: Name of the AI model being tested */ printf(esc_html__('Test %s', 'upkyk-assistant-ai'), 'deepseek-chat-v1'); ?></button>
<button class="button test-model-button" data-model="deepseek-lite" data-provider="deepseek"><?php /* translators: %s: Name of the AI model being tested */ printf(esc_html__('Test %s', 'upkyk-assistant-ai'), 'deepseek-lite'); ?></button>
<button class="button test-model-button" data-model="deepseek/deepseek-chat" data-provider="deepseek"><?php /* translators: %s: Name of the AI model being tested */ printf(esc_html__('Test %s', 'upkyk-assistant-ai'), 'deepseek/deepseek-chat'); ?></button>
<input type="text" id="custom-deepseek-model-name" style="margin: 0 5px; width: 250px;" placeholder="<?php esc_attr_e('Or enter custom DeepSeek model name', 'upkyk-assistant-ai'); ?>">
<button class="button test-model-button" id="test-custom-deepseek-model" data-provider="deepseek"><?php esc_html_e('Test Custom Model', 'upkyk-assistant-ai'); ?></button>
</div>
</div>
<?php elseif ($provider === 'openai'): ?>
<div class="model-tester">
<div style="margin: 15px 0; display: flex; flex-wrap: wrap; gap: 10px; align-items: center;" class="model-selector">
<button class="button test-model-button" data-model="gpt-4o-mini" data-provider="openai"><?php /* translators: %s: Name of the AI model being tested */ printf(esc_html__('Test %s', 'upkyk-assistant-ai'), 'gpt-4o-mini'); ?></button>
<button class="button test-model-button" data-model="gpt-4" data-provider="openai"><?php /* translators: %s: Name of the AI model being tested */ printf(esc_html__('Test %s', 'upkyk-assistant-ai'), 'gpt-4'); ?></button>
<button class="button test-model-button" data-model="gpt-4-turbo" data-provider="openai"><?php /* translators: %s: Name of the AI model being tested */ printf(esc_html__('Test %s', 'upkyk-assistant-ai'), 'gpt-4-turbo'); ?></button>
<button class="button test-model-button" data-model="gpt-3.5-turbo" data-provider="openai"><?php /* translators: %s: Name of the AI model being tested */ printf(esc_html__('Test %s', 'upkyk-assistant-ai'), 'gpt-3.5-turbo'); ?></button>
<input type="text" id="custom-openai-model-name" style="margin: 0 5px; width: 250px;" placeholder="<?php esc_attr_e('Or enter custom OpenAI model name', 'upkyk-assistant-ai'); ?>">
<button class="button test-model-button" id="test-custom-openai-model" data-provider="openai"><?php esc_html_e('Test Custom Model', 'upkyk-assistant-ai'); ?></button>
</div>
</div>
<?php else: ?>
<div class="model-tester">
<div style="margin: 15px 0;" class="model-selector">
<p><?php esc_html_e('Custom provider detected. Enter a model name to test:', 'upkyk-assistant-ai'); ?></p>
<div style="display: flex; flex-wrap: wrap; gap: 10px; align-items: center;">
<input type="text" id="custom-model-name" style="margin: 0 5px; width: 250px;" placeholder="<?php esc_attr_e('Enter model name', 'upkyk-assistant-ai'); ?>">
<button class="button test-model-button" id="test-custom-model" data-provider="<?php echo esc_attr($provider); ?>"><?php esc_html_e('Test Model', 'upkyk-assistant-ai'); ?></button>
</div>
</div>
</div>
<?php endif; ?>
<div id="model-test-results" style="margin: 20px 0; padding: 15px; background: #f8f8f8; border: 1px solid #e5e5e5; border-radius: 3px; display: none;" class="upkyk-test-results">
<h3 style="margin-top: 0; font-size: 16px; font-weight: 600;"><?php esc_html_e('Test Results', 'upkyk-assistant-ai'); ?></h3>
<div id="model-test-message" class="notice"></div>
<div id="model-test-details" style="background: #f8f8f8; border: 1px solid #e5e5e5; border-radius: 3px; padding: 10px; margin-bottom: 20px; overflow: auto; max-height: 300px;" class="upkyk-diagnostic-details">
<pre style="margin: 0; white-space: pre-wrap; font-size: 13px; font-family: Consolas, Monaco, monospace;"></pre>
</div>
</div>
<div style="margin-top: 30px;" class="card">
<h2><?php esc_html_e('Troubleshooting & Next Steps', 'upkyk-assistant-ai'); ?></h2>
<p><?php esc_html_e('If you\'re experiencing issues with your API connection, consider the following:', 'upkyk-assistant-ai'); ?></p>
<ol>
<li><?php esc_html_e('If the initial API test fails, check your API key for typos or try regenerating a new key.', 'upkyk-assistant-ai'); ?></li>
<li><?php esc_html_e('Test different models to find one that works with your account.', 'upkyk-assistant-ai'); ?></li>
<li><?php esc_html_e('If you\'re seeing "Authentication Fails" errors, your API key may have been invalidated or revoked.', 'upkyk-assistant-ai'); ?></li>
<li><?php esc_html_e('For persistent issues, contact your API provider\'s support team.', 'upkyk-assistant-ai'); ?></li>
</ol>
</div>
<!-- Database Maintenance -->
<h2><?php esc_html_e('Database Maintenance', 'upkyk-assistant-ai'); ?></h2>
<div class="upkyk-database-maintenance" style="margin-top: 15px; padding: 15px; background-color: #f8f8f8; border: 1px solid #ddd; border-radius: 3px;">
<p><strong><?php esc_html_e('Warning:', 'upkyk-assistant-ai'); ?></strong> <?php esc_html_e('The following database maintenance tools should only be used when experiencing specific issues with the chatbot database.', 'upkyk-assistant-ai'); ?></p>
<!-- Rebuild Tables Section -->
<div class="upkyk-rebuild-section" style="margin-bottom: 20px; padding: 15px; background-color: #fff; border: 1px solid #ddd; border-radius: 3px;">
<h3 style="margin-top: 0;"><?php esc_html_e('Rebuild Database Tables', 'upkyk-assistant-ai'); ?></h3>
<div class="upkyk-maintenance-info" style="margin-bottom: 15px;">
<h4><?php esc_html_e('When to use this tool:', 'upkyk-assistant-ai'); ?></h4>
<ul style="list-style-type: disc; margin-left: 20px;">
<li><?php esc_html_e('If you cannot add or edit custom phrases', 'upkyk-assistant-ai'); ?></li>
<li><?php esc_html_e('If you see database errors mentioning missing columns', 'upkyk-assistant-ai'); ?></li>
<li><?php esc_html_e('If you switched from DeepSeek to OpenAI API (or vice versa) and are having issues', 'upkyk-assistant-ai'); ?></li>
</ul>
<p><strong><?php esc_html_e('Important:', 'upkyk-assistant-ai'); ?></strong> <?php echo wp_kses_post(__('Rebuilding tables will <span style="color: #d63638;">delete all existing phrases and keywords</span>. You will need to re-add them after rebuilding.', 'upkyk-assistant-ai')); ?></p>
</div>
<button type="button" id="rebuild-tables-diag" class="button button-secondary" style="background: #d63638; color: white; border-color: #b32d2e;">
<span class="dashicons dashicons-database-add" style="margin-right: 5px; margin-top: 3px;"></span> <?php esc_html_e('Rebuild Database Tables', 'upkyk-assistant-ai'); ?>
</button>
</div>
<!-- Delete All Tables Section -->
<div class="upkyk-delete-section" style="padding: 15px; background-color: #f8d7da; border: 1px solid #f5c6cb; border-radius: 3px;">
<h3 style="margin-top: 0; color: #721c24;"><?php esc_html_e('Delete All Plugin Tables', 'upkyk-assistant-ai'); ?></h3>
<div class="upkyk-delete-tables-info" style="margin-bottom: 15px;">
<p><strong><?php esc_html_e('WARNING:', 'upkyk-assistant-ai'); ?></strong> <?php echo wp_kses_post(__('This action will permanently delete <span style="color: #d63638; font-weight: bold;">ALL</span> plugin data, including:', 'upkyk-assistant-ai')); ?></p>
<ul style="list-style-type: disc; margin-left: 20px;">
<li><?php esc_html_e('All chat history and conversations', 'upkyk-assistant-ai'); ?></li>
<li><?php esc_html_e('All contact form submissions', 'upkyk-assistant-ai'); ?></li>
<li><?php esc_html_e('All custom phrases', 'upkyk-assistant-ai'); ?></li>
<li><?php esc_html_e('All uploaded documents and training data', 'upkyk-assistant-ai'); ?></li>
</ul>
<p><strong><?php esc_html_e('Use only when:', 'upkyk-assistant-ai'); ?></strong></p>
<ul style="list-style-type: disc; margin-left: 20px;">
<li><?php esc_html_e('You\'re performing a complete fresh start of the plugin', 'upkyk-assistant-ai'); ?></li>
<li><?php esc_html_e('You\'re completely uninstalling the plugin and want to remove all data', 'upkyk-assistant-ai'); ?></li>
<li><?php esc_html_e('You\'re troubleshooting persistent database issues that rebuilding tables doesn\'t fix', 'upkyk-assistant-ai'); ?></li>
</ul>
</div>
<button type="button" id="delete-all-tables" class="button button-secondary" style="background: #000000; color: white; border-color: #000000;">
<span class="dashicons dashicons-trash" style="margin-right: 5px; margin-top: 3px;"></span> <?php esc_html_e('Delete All Plugin Tables', 'upkyk-assistant-ai'); ?>
</button>
</div>
</div>
</div>
</div>
</div>
</div>