Files
igny8/igny8-ai-seo-wp-plugin/ai/writer/images/image-generation.php
2025-11-11 21:16:37 +05:00

535 lines
24 KiB
PHP

<?php
/**
* ==========================
* 🔐 IGNY8 FILE RULE HEADER
* ==========================
* @file : image-generation.php
* @location : /ai/writer/images/image-generation.php
* @type : AI Integration
* @scope : Global
* @allowed : Image generation, AI processing, media creation
* @reusability : Globally Reusable
* @notes : Image generation functions for all modules
*/
// Prevent direct access
if (!defined('ABSPATH')) {
exit;
}
/**
* Generate featured image for post from post meta prompt
*
* @param int $post_id WordPress post ID
* @param string $image_size_type Type of image size to use (featured, desktop, mobile)
* @return array Result with success status and attachment_id or error
*/
function igny8_generate_featured_image_for_post($post_id, $image_size_type = 'featured') {
// Get post
$post = get_post($post_id);
if (!$post) {
return ['success' => false, 'error' => 'Post not found'];
}
// Get featured image prompt from post meta
$featured_image_prompt = get_post_meta($post_id, '_igny8_featured_image_prompt', true);
if (empty($featured_image_prompt)) {
return ['success' => false, 'error' => 'No featured image prompt found in post meta'];
}
// Get image generation settings from prompts page
$image_type = get_option('igny8_image_type', 'realistic');
$image_service = get_option('igny8_image_service', 'openai');
$image_format = get_option('igny8_image_format', 'jpg');
$negative_prompt = get_option('igny8_negative_prompt', 'text, watermark, logo, overlay, title, caption, writing on walls, writing on objects, UI, infographic elements, post title');
// Get image model settings based on service
$image_model = get_option('igny8_image_model', 'dall-e-3');
$runware_model = get_option('igny8_runware_model', 'runware:97@1');
$prompt_template = wp_unslash(get_option('igny8_image_prompt_template', 'Create a high-quality {image_type} image to use as a featured photo for a blog post titled "{post_title}". The image should visually represent the theme, mood, and subject implied by the image prompt: {image_prompt}. Focus on a realistic, well-composed scene that naturally communicates the topic without text or logos. Use balanced lighting, pleasing composition, and photographic detail suitable for lifestyle or editorial web content. Avoid adding any visible or readable text, brand names, or illustrative effects. **And make sure image is not blurry.**'));
// Get dimensions based on image size type and service
$dimensions = igny8_get_image_dimensions($image_size_type, $image_service);
$image_width = $dimensions['width'];
$image_height = $dimensions['height'];
// Get API keys
$openai_key = get_option('igny8_api_key', '');
$runware_key = get_option('igny8_runware_api_key', '');
$required_key = ($image_service === 'runware') ? $runware_key : $openai_key;
if (empty($required_key)) {
return ['success' => false, 'error' => ($image_service === 'runware' ? 'Runware' : 'OpenAI') . ' API key not configured'];
}
// Build final prompt
$prompt = str_replace(
['{image_type}', '{post_title}', '{image_prompt}'],
[$image_type, $post->post_title, $featured_image_prompt],
$prompt_template
);
try {
// Event 7: API request sent
error_log('Igny8: IMAGE_GEN_EVENT_7 - API request sent to ' . $image_service . ' for post: ' . $post_id);
if ($image_service === 'runware') {
// Runware API Call
$payload = [
[
'taskType' => 'authentication',
'apiKey' => $runware_key
],
[
'taskType' => 'imageInference',
'taskUUID' => wp_generate_uuid4(),
'positivePrompt' => $prompt,
'negativePrompt' => $negative_prompt,
'model' => $runware_model,
'width' => $image_width,
'height' => $image_height,
'steps' => 30,
'CFGScale' => 7.5,
'numberResults' => 1,
'outputFormat' => $image_format
]
];
$response = wp_remote_post('https://api.runware.ai/v1', [
'headers' => ['Content-Type' => 'application/json'],
'body' => json_encode($payload),
'timeout' => 150, // Increased to 150 seconds for image generation
'httpversion' => '1.1',
'sslverify' => true
]);
if (is_wp_error($response)) {
error_log('Igny8: IMAGE_GEN_ERROR - Runware API request failed: ' . $response->get_error_message());
return ['success' => false, 'error' => 'Runware API Error: ' . $response->get_error_message()];
}
$response_body = wp_remote_retrieve_body($response);
$response_data = json_decode($response_body, true);
error_log('Igny8: IMAGE_GEN - Runware API response: ' . substr($response_body, 0, 200));
if (isset($response_data['data'][0]['imageURL'])) {
$image_url = $response_data['data'][0]['imageURL'];
// Event 8: Image URL received
error_log('Igny8: IMAGE_GEN_EVENT_8 - Image URL received from ' . $image_service . ' for post: ' . $post_id);
// Generate filename
$filename = sanitize_file_name($post->post_title) . '_featured_' . time() . '.' . $image_format;
// Event 9: Image saved to WordPress
error_log('Igny8: IMAGE_GEN_EVENT_9 - Saving image to WordPress for post: ' . $post_id);
// Download image from Runware URL
require_once(ABSPATH . 'wp-admin/includes/media.php');
require_once(ABSPATH . 'wp-admin/includes/file.php');
require_once(ABSPATH . 'wp-admin/includes/image.php');
error_log('Igny8: IMAGE_GEN - Downloading image from URL: ' . $image_url);
$temp_file = download_url($image_url);
if (is_wp_error($temp_file)) {
error_log('Igny8: IMAGE_GEN_EVENT_9_ERROR - Failed to download image: ' . $temp_file->get_error_message());
return ['success' => false, 'error' => 'Failed to download image: ' . $temp_file->get_error_message()];
}
error_log('Igny8: IMAGE_GEN - Image downloaded to temp file: ' . $temp_file);
// Prepare file array for media_handle_sideload
$file_array = [
'name' => $filename,
'tmp_name' => $temp_file
];
// Upload to WordPress media library
error_log('Igny8: IMAGE_GEN - Uploading to media library with media_handle_sideload');
$attachment_id = media_handle_sideload($file_array, $post_id, $post->post_title . ' Featured Image');
// Clean up temp file
if (file_exists($temp_file)) {
@unlink($temp_file);
}
if (is_wp_error($attachment_id)) {
error_log('Igny8: IMAGE_GEN_EVENT_9_ERROR - media_handle_sideload failed: ' . $attachment_id->get_error_message());
return ['success' => false, 'error' => 'Failed to upload image: ' . $attachment_id->get_error_message()];
}
error_log('Igny8: IMAGE_GEN - Successfully created attachment ID: ' . $attachment_id);
if (!is_wp_error($attachment_id)) {
// Set as featured image
set_post_thumbnail($post_id, $attachment_id);
// Generate attachment metadata
$attachment_data = wp_generate_attachment_metadata($attachment_id, get_attached_file($attachment_id));
wp_update_attachment_metadata($attachment_id, $attachment_data);
// Get attachment URL
$attachment_url = wp_get_attachment_url($attachment_id);
error_log('Igny8: IMAGE_GEN_EVENT_9_SUCCESS - Image saved successfully, attachment ID: ' . $attachment_id);
return [
'success' => true,
'attachment_id' => $attachment_id,
'image_url' => $attachment_url,
'provider' => 'runware'
];
} else {
error_log('Igny8: IMAGE_GEN_EVENT_9_ERROR - Failed to save image: ' . $attachment_id->get_error_message());
return ['success' => false, 'error' => 'Failed to register image: ' . $attachment_id->get_error_message()];
}
} else {
error_log('Igny8: IMAGE_GEN_EVENT_8_ERROR - No image URL in response');
$error_msg = isset($response_data['errors'][0]['message']) ? $response_data['errors'][0]['message'] : 'Unknown Runware API error';
return ['success' => false, 'error' => $error_msg];
}
} else {
// OpenAI API Call with selected model
$data = [
'model' => $image_model,
'prompt' => $prompt,
'n' => 1,
'size' => $image_width . 'x' . $image_height
];
$args = [
'headers' => [
'Content-Type' => 'application/json',
'Authorization' => 'Bearer ' . $openai_key,
],
'body' => json_encode($data),
'timeout' => 60,
];
$response = wp_remote_post('https://api.openai.com/v1/images/generations', $args);
if (is_wp_error($response)) {
return ['success' => false, 'error' => 'OpenAI API Error: ' . $response->get_error_message()];
}
$response_code = wp_remote_retrieve_response_code($response);
$response_body = wp_remote_retrieve_body($response);
if ($response_code === 200) {
$body = json_decode($response_body, true);
if (isset($body['data'][0]['url'])) {
$image_url = $body['data'][0]['url'];
$revised_prompt = $body['data'][0]['revised_prompt'] ?? null;
// Generate filename (OpenAI always returns PNG)
$filename = sanitize_file_name($post->post_title) . '_featured_' . time() . '.png';
// Download and register in WordPress Media Library
$attachment_id = wp_insert_attachment([
'post_mime_type' => 'image/png',
'post_title' => $post->post_title . ' Featured Image',
'post_content' => '',
'post_status' => 'inherit'
], $image_url, $post_id);
if (!is_wp_error($attachment_id)) {
// Set as featured image
set_post_thumbnail($post_id, $attachment_id);
// Get attachment URL
$attachment_url = wp_get_attachment_url($attachment_id);
return [
'success' => true,
'attachment_id' => $attachment_id,
'image_url' => $attachment_url,
'provider' => 'openai',
'revised_prompt' => $revised_prompt
];
} else {
return ['success' => false, 'error' => 'Failed to register image: ' . $attachment_id->get_error_message()];
}
}
} else {
return ['success' => false, 'error' => 'HTTP ' . $response_code . ' error'];
}
}
} catch (Exception $e) {
return ['success' => false, 'error' => 'Exception: ' . $e->getMessage()];
}
return ['success' => false, 'error' => 'Unknown error occurred'];
}
/**
* Generate single article image for post from post meta prompts
*
* @param int $post_id WordPress post ID
* @param string $device_type Device type: 'desktop' or 'mobile'
* @param int $index Image index (1-based)
* @return array Result with success status and attachment_id or error
*/
function igny8_generate_single_article_image($post_id, $device_type = 'desktop', $index = 1) {
// Get post
$post = get_post($post_id);
if (!$post) {
return ['success' => false, 'error' => 'Post not found'];
}
// Get article image prompts from post meta
$article_images_data = get_post_meta($post_id, '_igny8_article_images_data', true);
// Debug: Log the raw data to see what's actually stored
error_log('IGNY8 DEBUG: Raw article_images_data: ' . substr($article_images_data, 0, 200) . '...');
$article_images = json_decode($article_images_data, true);
// Check for JSON decode errors
if (json_last_error() !== JSON_ERROR_NONE) {
error_log('IGNY8 DEBUG: JSON decode error: ' . json_last_error_msg());
error_log('IGNY8 DEBUG: Raw data causing error: ' . $article_images_data);
// Try to clean the data by stripping HTML tags
$cleaned_data = wp_strip_all_tags($article_images_data);
$article_images = json_decode($cleaned_data, true);
if (json_last_error() !== JSON_ERROR_NONE) {
error_log('IGNY8 DEBUG: Still invalid JSON after cleaning: ' . json_last_error_msg());
return ['success' => false, 'error' => 'Invalid JSON in article images data: ' . json_last_error_msg()];
} else {
error_log('IGNY8 DEBUG: Successfully cleaned and parsed JSON');
}
}
if (empty($article_images) || !is_array($article_images)) {
return ['success' => false, 'error' => 'No article image prompts found in post meta'];
}
// Find the prompt for the requested index
$image_key = 'prompt-img-' . $index;
$prompt = '';
foreach ($article_images as $image_data) {
if (isset($image_data[$image_key])) {
$prompt = $image_data[$image_key];
break;
}
}
if (empty($prompt)) {
return ['success' => false, 'error' => 'No prompt found for image index ' . $index];
}
// Get image generation settings
$image_type = get_option('igny8_image_type', 'realistic');
$image_service = get_option('igny8_image_service', 'openai');
$image_format = get_option('igny8_image_format', 'jpg');
$negative_prompt = get_option('igny8_negative_prompt', 'text, watermark, logo, overlay, title, caption, writing on walls, writing on objects, UI, infographic elements, post title');
// Get image model settings based on service
$image_model = get_option('igny8_image_model', 'dall-e-3');
$runware_model = get_option('igny8_runware_model', 'runware:97@1');
// Get dimensions based on device type and service
$dimensions = igny8_get_image_dimensions($device_type, $image_service);
$image_width = $dimensions['width'];
$image_height = $dimensions['height'];
// Get API keys
$openai_key = get_option('igny8_api_key', '');
$runware_key = get_option('igny8_runware_api_key', '');
$required_key = ($image_service === 'runware') ? $runware_key : $openai_key;
if (empty($required_key)) {
return ['success' => false, 'error' => ($image_service === 'runware' ? 'Runware' : 'OpenAI') . ' API key not configured'];
}
// Enhance prompt if needed
$full_prompt = $prompt;
if (strlen($prompt) < 50 || strpos($prompt, 'Create') !== 0) {
$section = "Section " . $index;
$full_prompt = "Create a high-quality {$image_type} image for the section titled '{$section}'. {$prompt}";
}
try {
error_log('Igny8: ARTICLE_IMAGE_GEN - Generating ' . $device_type . ' image for post: ' . $post_id . ', index: ' . $index);
if ($image_service === 'runware') {
// Runware API Call
$payload = [
[
'taskType' => 'authentication',
'apiKey' => $runware_key
],
[
'taskType' => 'imageInference',
'taskUUID' => wp_generate_uuid4(),
'positivePrompt' => $full_prompt,
'negativePrompt' => $negative_prompt,
'model' => $runware_model,
'width' => $image_width,
'height' => $image_height,
'steps' => 30,
'CFGScale' => 7.5,
'numberResults' => 1,
'outputFormat' => $image_format
]
];
$response = wp_remote_post('https://api.runware.ai/v1', [
'headers' => ['Content-Type' => 'application/json'],
'body' => json_encode($payload),
'timeout' => 150,
'httpversion' => '1.1',
'sslverify' => true
]);
if (is_wp_error($response)) {
error_log('Igny8: ARTICLE_IMAGE_GEN_ERROR - Runware API request failed: ' . $response->get_error_message());
return ['success' => false, 'error' => 'Runware API Error: ' . $response->get_error_message()];
}
$response_body = wp_remote_retrieve_body($response);
$response_data = json_decode($response_body, true);
if (isset($response_data['data'][0]['imageURL'])) {
$image_url = $response_data['data'][0]['imageURL'];
// Generate filename
$filename = sanitize_file_name($post->post_title) . '_' . $device_type . '_' . $index . '_' . time() . '.' . $image_format;
// Download image from Runware URL
require_once(ABSPATH . 'wp-admin/includes/media.php');
require_once(ABSPATH . 'wp-admin/includes/file.php');
require_once(ABSPATH . 'wp-admin/includes/image.php');
$temp_file = download_url($image_url);
if (is_wp_error($temp_file)) {
return ['success' => false, 'error' => 'Failed to download image: ' . $temp_file->get_error_message()];
}
// Prepare file array for media_handle_sideload
$file_array = [
'name' => $filename,
'tmp_name' => $temp_file
];
// Upload to WordPress media library
$attachment_id = media_handle_sideload($file_array, $post_id, $post->post_title . ' ' . ucfirst($device_type) . ' Image ' . $index);
// Clean up temp file
if (file_exists($temp_file)) {
@unlink($temp_file);
}
if (is_wp_error($attachment_id)) {
return ['success' => false, 'error' => 'Failed to upload image: ' . $attachment_id->get_error_message()];
}
// Generate attachment metadata
$attachment_data = wp_generate_attachment_metadata($attachment_id, get_attached_file($attachment_id));
wp_update_attachment_metadata($attachment_id, $attachment_data);
// Add custom metadata
update_post_meta($attachment_id, '_igny8_image_type', $device_type);
update_post_meta($attachment_id, '_igny8_provider', 'runware');
update_post_meta($attachment_id, '_igny8_section', 'Section ' . $index);
// Get attachment URL
$attachment_url = wp_get_attachment_url($attachment_id);
error_log('Igny8: ARTICLE_IMAGE_GEN_SUCCESS - ' . $device_type . ' image generated, attachment ID: ' . $attachment_id);
return [
'success' => true,
'attachment_id' => $attachment_id,
'image_url' => $attachment_url,
'provider' => 'runware',
'device_type' => $device_type,
'index' => $index
];
} else {
$error_msg = isset($response_data['errors'][0]['message']) ? $response_data['errors'][0]['message'] : 'Unknown Runware API error';
return ['success' => false, 'error' => $error_msg];
}
} else {
// OpenAI API Call with selected model
$data = [
'model' => $image_model,
'prompt' => $full_prompt,
'n' => 1,
'size' => '1024x1024' // OpenAI only supports square
];
$args = [
'headers' => [
'Content-Type' => 'application/json',
'Authorization' => 'Bearer ' . $openai_key,
],
'body' => json_encode($data),
'timeout' => 60,
];
$response = wp_remote_post('https://api.openai.com/v1/images/generations', $args);
if (is_wp_error($response)) {
return ['success' => false, 'error' => 'OpenAI API Error: ' . $response->get_error_message()];
}
$response_code = wp_remote_retrieve_response_code($response);
$response_body = wp_remote_retrieve_body($response);
if ($response_code === 200) {
$body = json_decode($response_body, true);
if (isset($body['data'][0]['url'])) {
$image_url = $body['data'][0]['url'];
$revised_prompt = $body['data'][0]['revised_prompt'] ?? null;
// Generate filename (OpenAI always returns PNG)
$filename = sanitize_file_name($post->post_title) . '_' . $device_type . '_' . $index . '_' . time() . '.png';
// Download and register in WordPress Media Library
$attachment_id = wp_insert_attachment([
'post_mime_type' => 'image/png',
'post_title' => $post->post_title . ' ' . ucfirst($device_type) . ' Image ' . $index,
'post_content' => '',
'post_status' => 'inherit'
], $image_url, $post_id);
if (!is_wp_error($attachment_id)) {
// Add custom metadata
update_post_meta($attachment_id, '_igny8_image_type', $device_type);
update_post_meta($attachment_id, '_igny8_provider', 'openai');
update_post_meta($attachment_id, '_igny8_section', 'Section ' . $index);
// Get attachment URL
$attachment_url = wp_get_attachment_url($attachment_id);
return [
'success' => true,
'attachment_id' => $attachment_id,
'image_url' => $attachment_url,
'provider' => 'openai',
'device_type' => $device_type,
'index' => $index,
'revised_prompt' => $revised_prompt
];
} else {
return ['success' => false, 'error' => 'Failed to register image: ' . $attachment_id->get_error_message()];
}
}
} else {
return ['success' => false, 'error' => 'HTTP ' . $response_code . ' error'];
}
}
} catch (Exception $e) {
return ['success' => false, 'error' => 'Exception: ' . $e->getMessage()];
}
return ['success' => false, 'error' => 'Unknown error occurred'];
}