'GPT-4o', 'gpt-4-turbo' => 'GPT-4 Turbo', 'gpt-4' => 'GPT-4', 'gpt-3.5-turbo' => 'GPT-3.5 Turbo', ); } /** * Get required credential fields. * * @return array */ public function get_credential_fields() { return array( 'api_key' => array( 'label' => __( 'API Key', 'ai-internal-links' ), 'type' => 'password', 'description' => __( 'Enter your OpenAI API key. Get it from platform.openai.com', 'ai-internal-links' ), 'required' => true, ), ); } /** * Validate API credentials. * * @param array $credentials API credentials. * @return bool|WP_Error */ public function validate_credentials( $credentials ) { if ( empty( $credentials['api_key'] ) ) { return new WP_Error( 'missing_api_key', __( 'OpenAI API key is required.', 'ai-internal-links' ) ); } // Test API key with a simple GET request to models endpoint. $response = wp_remote_get( 'https://api.openai.com/v1/models', array( 'headers' => array( 'Authorization' => 'Bearer ' . $credentials['api_key'], ), 'timeout' => 10, ) ); if ( is_wp_error( $response ) ) { return $response; } $code = wp_remote_retrieve_response_code( $response ); if ( 200 !== $code ) { $body = json_decode( wp_remote_retrieve_body( $response ), true ); $message = isset( $body['error']['message'] ) ? $body['error']['message'] : __( 'Invalid API key.', 'ai-internal-links' ); return new WP_Error( 'invalid_api_key', $message ); } return true; } /** * Generate internal link suggestions. * * @param string $content Content to analyze. * @param array $available_links Available links for suggestions. * @param array $settings Generation settings. * @return array|WP_Error */ public function generate_suggestions( $content, $available_links, $settings ) { $api_key = isset( $settings['api_key'] ) ? $settings['api_key'] : ''; $model = isset( $settings['model'] ) ? $settings['model'] : 'gpt-4o-mini'; $max_links = isset( $settings['max_links'] ) ? intval( $settings['max_links'] ) : 5; if ( empty( $api_key ) ) { return new WP_Error( 'missing_api_key', __( 'OpenAI API key is not configured.', 'ai-internal-links' ) ); } // Prepare links list. $links_list = $this->format_links_list( $available_links ); // Build prompts. $system_prompt = $this->build_system_prompt( $max_links ); $user_prompt = $this->build_user_prompt( $content, $links_list ); // Make API request. $request_data = array( 'model' => $model, 'messages' => array( array( 'role' => 'system', 'content' => $system_prompt, ), array( 'role' => 'user', 'content' => $user_prompt, ), ), 'temperature' => 0.3, ); $response = wp_remote_post( $this->api_url, array( 'headers' => array( 'Authorization' => 'Bearer ' . $api_key, 'Content-Type' => 'application/json', ), 'body' => wp_json_encode( $request_data ), 'timeout' => 120, ) ); if ( is_wp_error( $response ) ) { return $response; } $code = wp_remote_retrieve_response_code( $response ); $body = wp_remote_retrieve_body( $response ); if ( 200 !== $code ) { $error_data = json_decode( $body, true ); $message = isset( $error_data['error']['message'] ) ? $error_data['error']['message'] : __( 'OpenAI API request failed.', 'ai-internal-links' ); return new WP_Error( 'openai_api_error', $message ); } // Parse response. return $this->parse_response( $body ); } /** * Parse OpenAI response. * * @param string $response_body Response body. * @return array|WP_Error */ private function parse_response( $response_body ) { $data = json_decode( $response_body, true ); if ( ! isset( $data['choices'][0]['message']['content'] ) ) { return new WP_Error( 'invalid_response', __( 'Invalid response from OpenAI.', 'ai-internal-links' ) ); } $content = trim( $data['choices'][0]['message']['content'] ); // Remove markdown code blocks if present. $content = preg_replace( '/^```json\s*|\s*```$/m', '', $content ); $content = trim( $content ); $suggestions = json_decode( $content, true ); if ( json_last_error() !== JSON_ERROR_NONE ) { return new WP_Error( 'json_parse_error', __( 'Failed to parse AI response.', 'ai-internal-links' ) ); } if ( ! is_array( $suggestions ) ) { return new WP_Error( 'invalid_suggestions', __( 'Invalid suggestions format.', 'ai-internal-links' ) ); } // Validate suggestions structure. $validated = array(); foreach ( $suggestions as $suggestion ) { if ( isset( $suggestion['search'] ) && isset( $suggestion['replace'] ) ) { $validated[] = array( 'search' => $suggestion['search'], 'replace' => $suggestion['replace'], ); } } return $validated; } }