$timeout, 'method' => $method, 'headers' => [ 'Authorization' => 'Bearer ' . $api_key, 'Content-Type' => 'application/json', ], ]; if ($body !== null) { $args['body'] = wp_json_encode($body); } $response = wp_remote_request('https://api.openai.com/v1/' . ltrim($endpoint, '/'), $args); if (is_wp_error($response)) { if (class_exists('AIWEST_Logger')) { AIWEST_Logger::error('OpenAI HTTP request failed.', [ 'endpoint' => $endpoint, 'error' => $response->get_error_message() ]); } return $response; } $code = wp_remote_retrieve_response_code($response); $raw = wp_remote_retrieve_body($response); $json = json_decode($raw, true); if ($code < 200 || $code >= 300) { $msg = $json['error']['message'] ?? $raw ?: __('Unknown API error.', 'ai-webmaster-studio'); if (class_exists('AIWEST_Logger')) { AIWEST_Logger::error('OpenAI API error.', [ 'endpoint' => $endpoint, 'code' => $code, 'message' => $msg ]); } return new WP_Error('openai_api_error', 'OpenAI API error [' . $code . ']: ' . $msg); } return [ 'status' => $code, 'body' => $json, 'raw' => $raw, ]; } public static function list_models() { return self::request('models', 'GET', null, 45); } public static function chat($messages, $temperature = 0.4, $model = null) { $model = $model ?: self::get_model(); $body=['model'=>$model,'messages'=>$messages,'max_completion_tokens'=>preg_match('/^(gpt-[56]|o[1-9])/',$model)?16384:4096]; if (!preg_match('/^(gpt-[56]|o[1-9])/', $model)) $body['temperature']=$temperature; $result = self::request('chat/completions', 'POST', $body, 120); if (is_wp_error($result)) { return $result; } $choice=$result['body']['choices'][0]??[]; $content=$choice['message']['content']??''; if (($choice['finish_reason']??'')==='length') return new WP_Error('aiwest_incomplete_response',__('The AI response reached its token limit. No automatic changes were applied. Try a narrower task.','ai-webmaster-studio')); if (!is_string($content) || trim($content)==='') return new WP_Error('aiwest_empty_response',__('The AI provider returned no usable text. No automatic changes were applied.','ai-webmaster-studio')); return $content; } public static function image_generation($prompt, $size = '1024x1024') { $model = trim((string) get_option('aiwest_openai_image_model', 'gpt-image-1')); if (!$model) $model = 'gpt-image-1'; $body = [ 'model' => $model, 'prompt' => $prompt, 'size' => $size, 'n' => 1, ]; $result = self::request('images/generations', 'POST', $body, 180); if (is_wp_error($result)) return $result; $data = $result['body']['data'][0] ?? []; if (!empty($data['b64_json'])) { return ['type' => 'b64_json', 'data' => $data['b64_json']]; } if (!empty($data['url'])) { return ['type' => 'url', 'data' => $data['url']]; } return new WP_Error('aiwest_image_no_data', __('OpenAI did not return image data.', 'ai-webmaster-studio')); } public static function test_models_endpoint() { $result = self::list_models(); if (is_wp_error($result)) return $result; $models = []; if (!empty($result['body']['data']) && is_array($result['body']['data'])) { foreach ($result['body']['data'] as $m) { if (!empty($m['id'])) $models[] = $m['id']; } } return [ 'ok' => true, 'count' => count($models), 'models' => array_slice($models, 0, 30), ]; } public static function test_chat_endpoint($model = null) { $result = self::chat([ ['role' => 'system', 'content' => 'Answer in one short sentence in '.AIWEST_Languages::language_name(AIWEST_Languages::locale()).'.'], ['role' => 'user', 'content' => 'Test the chat/completions endpoint connection for AI Webmaster Studio.'] ], 0.1, $model ? sanitize_text_field($model) : null); if (is_wp_error($result)) return $result; return [ 'ok' => true, 'answer' => wp_strip_all_tags($result), ]; } public static function full_diagnostic() { $diagnostic = [ 'api_key_saved' => self::get_api_key() ? true : false, 'selected_model' => self::get_model(), 'models_endpoint' => null, 'chat_endpoint' => null, ]; $models = self::test_models_endpoint(); if (is_wp_error($models)) { $diagnostic['models_endpoint'] = [ 'ok' => false, 'error' => $models->get_error_message(), ]; } else { $diagnostic['models_endpoint'] = $models; } $chat = self::test_chat_endpoint(); if (is_wp_error($chat)) { $diagnostic['chat_endpoint'] = [ 'ok' => false, 'error' => $chat->get_error_message(), ]; } else { $diagnostic['chat_endpoint'] = $chat; } return $diagnostic; } public static function system_prompt() { $profile = class_exists('AIWEST_Memory') ? AIWEST_Memory::get('project_profile', []) : []; $goals = class_exists('AIWEST_Goals') ? AIWEST_Goals::active() : []; $admin_language = AIWEST_Languages::language_name(AIWEST_Languages::locale()); $content_language = AIWEST_Languages::language_name(AIWEST_Languages::content_locale()); return "You are AI Webmaster Studio for a WordPress website. Work only within tasks started or approved by an administrator. Technical, critical or risky actions must be marked as requiring explicit administrator approval. Project profile: " . wp_json_encode($profile, JSON_UNESCAPED_UNICODE) . " Active goals: " . wp_json_encode($goals, JSON_UNESCAPED_UNICODE) . " Administrator-facing summaries and status notes must use this admin runtime language: " . $admin_language . "." . " Default public website content language: " . $content_language . ". Use another language when explicitly requested by the current task. Do not perform destructive actions without consent."; } }