array( 'Content-Type' => 'application/json', 'Authorization' => 'Bearer ' . $api_key, ), 'body' => wp_json_encode( $payload ), 'timeout' => absint( $timeout ), ) ); return $this->normalize_response( $response ); } /** * Retrieve a response by id from the OpenAI Responses API. * * @param string $response_id OpenAI response id. * @param string $api_key OpenAI API key. * @param int $timeout OpenAI HTTP timeout in seconds. * @return array|WP_Error */ public function retrieve_response( $response_id, $api_key, $timeout = 120 ) { $response = wp_remote_get( 'https://api.openai.com/v1/responses/' . rawurlencode( $response_id ), array( 'headers' => array( 'Authorization' => 'Bearer ' . $api_key, ), 'timeout' => absint( $timeout ), ) ); return $this->normalize_response( $response ); } /** * Cancel a background response via the OpenAI Responses API. * * @param string $response_id OpenAI response id. * @param string $api_key OpenAI API key. * @return array|WP_Error */ public function cancel_response( $response_id, $api_key ) { $response = wp_remote_post( 'https://api.openai.com/v1/responses/' . rawurlencode( $response_id ) . '/cancel', array( 'headers' => array( 'Content-Type' => 'application/json', 'Authorization' => 'Bearer ' . $api_key, ), 'timeout' => 120, ) ); return $this->normalize_response( $response ); } /** * Build a user-facing error response for OpenAI API errors. * * @param array $response_data OpenAI response data. * @param int $http_status HTTP status code. * @return WP_REST_Response */ public function build_error_response( $response_data, $http_status ) { if ( isset( $response_data['error']['code'] ) && 'model_not_found' === $response_data['error']['code'] ) { $error_message = __( 'You do not have access to this GPT model. Please choose a different model from Settings -> AI Editor.', 'ai-editor' ); } else { $error_message = isset( $response_data['error']['message'] ) ? $response_data['error']['message'] : __( 'Unknown error.', 'ai-editor' ); } return new WP_REST_Response( array( 'error' => true, 'message' => $error_message, 'status' => $http_status, ), $http_status ); } /** * Normalize a WordPress HTTP response. * * @param array|WP_Error $response WordPress HTTP response. * @return array|WP_Error */ private function normalize_response( $response ) { if ( is_wp_error( $response ) ) { return new WP_Error( 'request_failed', $response->get_error_message(), array( 'status' => 500 ) ); } $body = wp_remote_retrieve_body( $response ); $response_data = json_decode( $body, true ); if ( JSON_ERROR_NONE !== json_last_error() ) { return new WP_Error( 'json_error', __( 'JSON parsing error: ', 'ai-editor' ) . json_last_error_msg(), array( 'status' => 500 ) ); } return array( 'data' => $response_data, 'meta' => array( 'status' => wp_remote_retrieve_response_code( $response ), ), ); } }