Make your WordPress site irresistible. Natural SEO attraction with: - robots.txt management - sitemap.xml generation - LLMs.txt support - Google integration (Analytics, Search Console, Tag Manager) - Schema.org structured data - Open Graph / Twitter Card meta tags - AMP support - Visual elements gallery - Built-in backup/restore module Includes build.sh and .distignore for WordPress-installable release ZIPs.
388 lines
12 KiB
PHP
388 lines
12 KiB
PHP
<?php
|
|
/**
|
|
* OpenAI-compatible API Client for TigerStyle Heat
|
|
* Provides a simple wrapper around WordPress HTTP API for OpenAI-compatible requests
|
|
*/
|
|
|
|
// Prevent direct access
|
|
if (!defined('ABSPATH')) {
|
|
exit;
|
|
}
|
|
|
|
class TigerStyleSEO_AI_Client {
|
|
private $base_url;
|
|
private $api_key;
|
|
private $default_model;
|
|
private $timeout;
|
|
|
|
public function __construct($base_url, $api_key, $default_model = null) {
|
|
$this->base_url = rtrim($base_url, '/');
|
|
$this->api_key = $api_key;
|
|
$this->default_model = $default_model;
|
|
$this->timeout = 60; // Default 60 second timeout
|
|
}
|
|
|
|
/**
|
|
* Set request timeout
|
|
*/
|
|
public function set_timeout($timeout) {
|
|
$this->timeout = $timeout;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Make a chat completion request
|
|
*/
|
|
public function chat_completion($params) {
|
|
// Set default model if not provided
|
|
if (!isset($params['model']) && $this->default_model) {
|
|
$params['model'] = $this->default_model;
|
|
}
|
|
|
|
// Validate required parameters
|
|
if (!isset($params['model'])) {
|
|
throw new Exception('Model is required for chat completion');
|
|
}
|
|
|
|
if (!isset($params['messages']) || empty($params['messages'])) {
|
|
throw new Exception('Messages array is required for chat completion');
|
|
}
|
|
|
|
// Set default parameters
|
|
$params = array_merge(array(
|
|
'max_tokens' => 1000,
|
|
'temperature' => 0.7,
|
|
'top_p' => 1.0,
|
|
'frequency_penalty' => 0,
|
|
'presence_penalty' => 0
|
|
), $params);
|
|
|
|
return $this->make_request('POST', '/chat/completions', $params);
|
|
}
|
|
|
|
/**
|
|
* Make a text completion request (for older models)
|
|
*/
|
|
public function text_completion($params) {
|
|
// Set default model if not provided
|
|
if (!isset($params['model']) && $this->default_model) {
|
|
$params['model'] = $this->default_model;
|
|
}
|
|
|
|
// Validate required parameters
|
|
if (!isset($params['model'])) {
|
|
throw new Exception('Model is required for text completion');
|
|
}
|
|
|
|
if (!isset($params['prompt'])) {
|
|
throw new Exception('Prompt is required for text completion');
|
|
}
|
|
|
|
// Set default parameters
|
|
$params = array_merge(array(
|
|
'max_tokens' => 1000,
|
|
'temperature' => 0.7,
|
|
'top_p' => 1.0,
|
|
'frequency_penalty' => 0,
|
|
'presence_penalty' => 0
|
|
), $params);
|
|
|
|
return $this->make_request('POST', '/completions', $params);
|
|
}
|
|
|
|
/**
|
|
* List available models
|
|
*/
|
|
public function list_models() {
|
|
return $this->make_request('GET', '/models');
|
|
}
|
|
|
|
/**
|
|
* Get model information
|
|
*/
|
|
public function get_model($model_id) {
|
|
return $this->make_request('GET', '/models/' . $model_id);
|
|
}
|
|
|
|
/**
|
|
* Create embeddings
|
|
*/
|
|
public function create_embeddings($params) {
|
|
// Set default model if not provided
|
|
if (!isset($params['model']) && $this->default_model) {
|
|
$params['model'] = $this->default_model;
|
|
}
|
|
|
|
// Validate required parameters
|
|
if (!isset($params['model'])) {
|
|
throw new Exception('Model is required for embeddings');
|
|
}
|
|
|
|
if (!isset($params['input'])) {
|
|
throw new Exception('Input is required for embeddings');
|
|
}
|
|
|
|
return $this->make_request('POST', '/embeddings', $params);
|
|
}
|
|
|
|
/**
|
|
* Create image generation request (DALL-E style)
|
|
*/
|
|
public function create_image($params) {
|
|
// Validate required parameters
|
|
if (!isset($params['prompt'])) {
|
|
throw new Exception('Prompt is required for image generation');
|
|
}
|
|
|
|
// Set defaults
|
|
$params = array_merge(array(
|
|
'n' => 1,
|
|
'size' => '512x512',
|
|
'response_format' => 'url'
|
|
), $params);
|
|
|
|
return $this->make_request('POST', '/images/generations', $params);
|
|
}
|
|
|
|
/**
|
|
* Moderate content
|
|
*/
|
|
public function moderate_content($params) {
|
|
if (!isset($params['input'])) {
|
|
throw new Exception('Input is required for moderation');
|
|
}
|
|
|
|
return $this->make_request('POST', '/moderations', $params);
|
|
}
|
|
|
|
/**
|
|
* Create fine-tuning job
|
|
*/
|
|
public function create_fine_tune($params) {
|
|
if (!isset($params['training_file'])) {
|
|
throw new Exception('Training file is required for fine-tuning');
|
|
}
|
|
|
|
return $this->make_request('POST', '/fine-tunes', $params);
|
|
}
|
|
|
|
/**
|
|
* List fine-tuning jobs
|
|
*/
|
|
public function list_fine_tunes() {
|
|
return $this->make_request('GET', '/fine-tunes');
|
|
}
|
|
|
|
/**
|
|
* Get fine-tuning job
|
|
*/
|
|
public function get_fine_tune($fine_tune_id) {
|
|
return $this->make_request('GET', '/fine-tunes/' . $fine_tune_id);
|
|
}
|
|
|
|
/**
|
|
* Cancel fine-tuning job
|
|
*/
|
|
public function cancel_fine_tune($fine_tune_id) {
|
|
return $this->make_request('POST', '/fine-tunes/' . $fine_tune_id . '/cancel');
|
|
}
|
|
|
|
/**
|
|
* Upload file
|
|
*/
|
|
public function upload_file($file_path, $purpose = 'fine-tune') {
|
|
if (!file_exists($file_path)) {
|
|
throw new Exception('File not found: ' . $file_path);
|
|
}
|
|
|
|
// For file uploads, we need to use a different approach
|
|
$boundary = wp_generate_password(16, false);
|
|
$file_content = file_get_contents($file_path);
|
|
$filename = basename($file_path);
|
|
|
|
$body = '';
|
|
$body .= '--' . $boundary . "\r\n";
|
|
$body .= 'Content-Disposition: form-data; name="purpose"' . "\r\n\r\n";
|
|
$body .= $purpose . "\r\n";
|
|
|
|
$body .= '--' . $boundary . "\r\n";
|
|
$body .= 'Content-Disposition: form-data; name="file"; filename="' . $filename . '"' . "\r\n";
|
|
$body .= 'Content-Type: application/octet-stream' . "\r\n\r\n";
|
|
$body .= $file_content . "\r\n";
|
|
$body .= '--' . $boundary . '--' . "\r\n";
|
|
|
|
$response = wp_remote_post($this->base_url . '/files', array(
|
|
'headers' => array(
|
|
'Authorization' => 'Bearer ' . $this->api_key,
|
|
'Content-Type' => 'multipart/form-data; boundary=' . $boundary,
|
|
'User-Agent' => 'TigerStyle-SEO/' . TIGERSTYLE_HEAT_VERSION
|
|
),
|
|
'body' => $body,
|
|
'timeout' => $this->timeout
|
|
));
|
|
|
|
return $this->process_response($response);
|
|
}
|
|
|
|
/**
|
|
* List files
|
|
*/
|
|
public function list_files() {
|
|
return $this->make_request('GET', '/files');
|
|
}
|
|
|
|
/**
|
|
* Get file
|
|
*/
|
|
public function get_file($file_id) {
|
|
return $this->make_request('GET', '/files/' . $file_id);
|
|
}
|
|
|
|
/**
|
|
* Delete file
|
|
*/
|
|
public function delete_file($file_id) {
|
|
return $this->make_request('DELETE', '/files/' . $file_id);
|
|
}
|
|
|
|
/**
|
|
* Make HTTP request to OpenAI API
|
|
*/
|
|
private function make_request($method, $endpoint, $params = null) {
|
|
$url = $this->base_url . $endpoint;
|
|
|
|
$args = array(
|
|
'method' => $method,
|
|
'headers' => array(
|
|
'Authorization' => 'Bearer ' . $this->api_key,
|
|
'Content-Type' => 'application/json',
|
|
'User-Agent' => 'TigerStyle-SEO/' . TIGERSTYLE_HEAT_VERSION
|
|
),
|
|
'timeout' => $this->timeout
|
|
);
|
|
|
|
if ($params && ($method === 'POST' || $method === 'PUT' || $method === 'PATCH')) {
|
|
$args['body'] = json_encode($params);
|
|
} elseif ($params && $method === 'GET') {
|
|
$url = add_query_arg($params, $url);
|
|
}
|
|
|
|
$response = wp_remote_request($url, $args);
|
|
|
|
return $this->process_response($response);
|
|
}
|
|
|
|
/**
|
|
* Process API response
|
|
*/
|
|
private function process_response($response) {
|
|
if (is_wp_error($response)) {
|
|
throw new Exception('HTTP Request failed: ' . $response->get_error_message());
|
|
}
|
|
|
|
$status_code = wp_remote_retrieve_response_code($response);
|
|
$body = wp_remote_retrieve_body($response);
|
|
|
|
// Try to decode JSON response
|
|
$data = json_decode($body, true);
|
|
|
|
if ($status_code >= 400) {
|
|
$error_message = 'HTTP ' . $status_code;
|
|
|
|
if ($data && isset($data['error'])) {
|
|
if (is_string($data['error'])) {
|
|
$error_message .= ': ' . $data['error'];
|
|
} elseif (isset($data['error']['message'])) {
|
|
$error_message .= ': ' . $data['error']['message'];
|
|
}
|
|
} else {
|
|
$error_message .= ': ' . $body;
|
|
}
|
|
|
|
throw new Exception($error_message);
|
|
}
|
|
|
|
return $data;
|
|
}
|
|
|
|
/**
|
|
* Helper method to create a simple chat message
|
|
*/
|
|
public function simple_chat($message, $system_prompt = null, $model = null) {
|
|
$messages = array();
|
|
|
|
if ($system_prompt) {
|
|
$messages[] = array('role' => 'system', 'content' => $system_prompt);
|
|
}
|
|
|
|
$messages[] = array('role' => 'user', 'content' => $message);
|
|
|
|
$params = array('messages' => $messages);
|
|
|
|
if ($model) {
|
|
$params['model'] = $model;
|
|
}
|
|
|
|
return $this->chat_completion($params);
|
|
}
|
|
|
|
/**
|
|
* Helper method to extract text from chat response
|
|
*/
|
|
public function extract_text($response) {
|
|
if (isset($response['choices'][0]['message']['content'])) {
|
|
return trim($response['choices'][0]['message']['content']);
|
|
}
|
|
|
|
if (isset($response['choices'][0]['text'])) {
|
|
return trim($response['choices'][0]['text']);
|
|
}
|
|
|
|
throw new Exception('Unable to extract text from response');
|
|
}
|
|
|
|
/**
|
|
* Helper method for SEO-specific prompts
|
|
*/
|
|
public function generate_meta_description($content, $max_length = 155) {
|
|
$prompt = "Generate an SEO-optimized meta description (maximum {$max_length} characters) for the following content. The description should be compelling, include relevant keywords, and encourage clicks:\n\n{$content}";
|
|
|
|
$response = $this->simple_chat($prompt, "You are an SEO expert specializing in creating compelling meta descriptions that improve search engine rankings and click-through rates.");
|
|
|
|
return $this->extract_text($response);
|
|
}
|
|
|
|
/**
|
|
* Helper method to generate SEO title
|
|
*/
|
|
public function generate_seo_title($content, $max_length = 60) {
|
|
$prompt = "Generate an SEO-optimized title (maximum {$max_length} characters) for the following content. The title should be compelling, include relevant keywords, and be click-worthy:\n\n{$content}";
|
|
|
|
$response = $this->simple_chat($prompt, "You are an SEO expert specializing in creating compelling titles that improve search engine rankings and click-through rates.");
|
|
|
|
return $this->extract_text($response);
|
|
}
|
|
|
|
/**
|
|
* Helper method to extract keywords
|
|
*/
|
|
public function extract_keywords($content, $count = 10) {
|
|
$prompt = "Extract the {$count} most important SEO keywords from the following content. Return only the keywords, separated by commas:\n\n{$content}";
|
|
|
|
$response = $this->simple_chat($prompt, "You are an SEO expert specializing in keyword research and content analysis.");
|
|
|
|
$keywords = $this->extract_text($response);
|
|
return array_map('trim', explode(',', $keywords));
|
|
}
|
|
|
|
/**
|
|
* Helper method to analyze content for SEO
|
|
*/
|
|
public function analyze_seo_content($content) {
|
|
$prompt = "Analyze the following content for SEO optimization and provide specific recommendations:\n\n{$content}";
|
|
|
|
$response = $this->simple_chat($prompt, "You are an SEO expert. Analyze content and provide actionable SEO recommendations including keyword usage, content structure, readability, and technical SEO factors.");
|
|
|
|
return $this->extract_text($response);
|
|
}
|
|
} |