From e449681953eec7b2ba77704e0d50d75020e38b9c Mon Sep 17 00:00:00 2001 From: Bartholomew Date: Mon, 11 Mar 2024 18:40:24 +0100 Subject: [PATCH] Removed the `completions` and `edit` endpoints which have been deprecated by OpenAI. Feeds using these endpoints will be automatically converted to the `chat/completions` endpoint. * Removed `completions` `edits` endpoints and transform their feeds to `chat/completions` * fix lint * Updated to make "Advanced Settings: Chat Completions" collapsiable and collapsed by default. * Feedback fixes * Feedback fixes * Fix phpsc * Feedback fixes * Fix phpsc --------- Co-authored-by: David Smith --- class-gwiz-gf-openai.php | 500 +++++++++++---------------------------- 1 file changed, 142 insertions(+), 358 deletions(-) diff --git a/class-gwiz-gf-openai.php b/class-gwiz-gf-openai.php index 4d99e48..9b1e04e 100644 --- a/class-gwiz-gf-openai.php +++ b/class-gwiz-gf-openai.php @@ -20,14 +20,6 @@ class GWiz_GF_OpenAI extends GFFeedAddOn { * @var array The default settings to pass to OpenAI */ public $default_settings = array( - 'completions' => array( - 'max_tokens' => 500, - 'temperature' => 1, - 'top_p' => 1, - 'frequency_penalty' => 0, - 'presence_penalty' => 0, - 'timeout' => 15, - ), 'chat/completions' => array( 'max_tokens' => 1000, 'temperature' => 1, @@ -36,11 +28,6 @@ class GWiz_GF_OpenAI extends GFFeedAddOn { 'presence_penalty' => 0, 'timeout' => 15, ), - 'edits' => array( - 'temperature' => 1, - 'top_p' => 1, - 'timeout' => 15, - ), 'moderations' => array( 'timeout' => 5, ), @@ -153,6 +140,7 @@ public function pre_init() { add_filter( 'gform_export_form', array( $this, 'export_feeds_with_form' ) ); add_action( 'gform_forms_post_import', array( $this, 'import_feeds_with_form' ) ); + add_action( 'admin_footer', array( $this, 'add_warning_css' ) ); } /** @@ -272,32 +260,6 @@ public function init() { */ public function get_openai_models() { $models = array( - 'completions' => array( - 'text-davinci-003' => array( - 'type' => 'GPT-3', - 'description' => __( 'Most capable GPT-3 model. Can do any task the other models can do, often with higher quality, longer output and better instruction-following. Also supports inserting completions within text.', 'gravityforms-openai' ), - ), - 'text-curie-001' => array( - 'type' => 'GPT-3', - 'description' => __( 'Very capable, but faster and lower cost than Davinci.', 'gravityforms-openai' ), - ), - 'text-babbage-001' => array( - 'type' => 'GPT-3', - 'description' => __( 'Capable of straightforward tasks, very fast, and lower cost.', 'gravityforms-openai' ), - ), - 'text-ada-001' => array( - 'type' => 'GPT-3', - 'description' => __( 'Capable of very simple tasks, usually the fastest model in the GPT-3 series, and lowest cost.', 'gravityforms-openai' ), - ), - 'code-davinci-002' => array( - 'type' => 'Codex', - 'description' => __( 'Most capable Codex model. Particularly good at translating natural language to code. In addition to completing code, also supports inserting completions within code.', 'gravityforms-openai' ), - ), - 'code-cushman-001' => array( - 'type' => 'Codex', - 'description' => __( 'Almost as capable as Davinci Codex, but slightly faster. This speed advantage may make it preferable for real-time applications.', 'gravityforms-openai' ), - ), - ), 'chat/completions' => array( 'gpt-3.5-turbo' => array( 'description' => __( 'The same model used by ChatGPT.', 'gravityforms-openai' ), @@ -315,16 +277,6 @@ public function get_openai_models() { 'description' => __( 'The latest GPT-4 model with improved instruction following, JSON mode, reproducible outputs, parallel function calling, and more. Returns a maximum of 4,096 output tokens.', 'gravityforms-openai' ), ), ), - 'edits' => array( - 'text-davinci-edit-001' => array( - 'type' => 'GPT-3', - 'description' => __( 'Most capable GPT-3 model. Can do any task the other models can do, often with higher quality, longer output and better instruction-following. Also supports inserting completions within text.', 'gravityforms-openai' ), - ), - 'code-davinci-edit-001' => array( - 'type' => 'Codex', - 'description' => __( 'Most capable Codex model. Particularly good at translating natural language to code. In addition to completing code, also supports inserting completions within code.', 'gravityforms-openai' ), - ), - ), 'moderations' => array( 'text-moderation-stable' => array( 'type' => 'Moderation', @@ -461,9 +413,7 @@ public function tooltips( $tooltips ) { } } - $tooltips['openai_endpoint_completions'] = __( 'Given a prompt, the model will return one or more predicted completions, and can also return the probabilities of alternative tokens at each position.', 'gravityforms-openai' ); $tooltips['openai_endpoint_chat_completions'] = __( 'Given a single message, the model will return a model-generated message as an output.', 'gravityforms-openai' ); - $tooltips['openai_endpoint_edits'] = __( 'Given a prompt and an instruction, the model will return an edited version of the prompt.', 'gravityforms-openai' ); $tooltips['openai_endpoint_moderations'] = __( 'Given a input text, outputs if the model classifies it as violating OpenAI\'s content policy.', 'gravityforms-openai' ); return $tooltips; @@ -524,21 +474,11 @@ public function feed_settings_fields() { 'label' => __( 'OpenAI Endpoint', 'gravityforms-openai' ), 'type' => 'radio', 'choices' => array( - array( - 'value' => 'completions', - 'label' => __( 'Completions', 'gravityforms-openai' ), - 'tooltip' => 'openai_endpoint_completions', - ), array( 'value' => 'chat/completions', 'label' => __( 'Chat Completions', 'gravityforms-openai' ), 'tooltip' => 'openai_endpoint_chat_completions', ), - array( - 'value' => 'edits', - 'label' => __( 'Edits', 'gravityforms-openai' ), - 'tooltip' => 'openai_endpoint_edits', - ), array( 'value' => 'moderations', 'label' => __( 'Moderations', 'gravityforms-openai' ), @@ -549,38 +489,6 @@ public function feed_settings_fields() { ), ), ), - array( - 'title' => 'Completions', - 'fields' => array( - array( - 'name' => 'completions_model', - 'tooltip' => 'Select the OpenAI model to use.', - 'label' => __( 'OpenAI Model', 'gravityforms-openai' ), - 'type' => 'radio', - 'choices' => $this->get_openai_model_choices( 'completions' ), - 'required' => true, - ), - array( - 'name' => 'completions_prompt', - 'tooltip' => 'Enter the prompt to send to OpenAI.', - 'label' => 'Prompt', - 'type' => 'textarea', - 'class' => 'medium merge-tag-support mt-position-right', - 'required' => true, - ), - $this->feed_setting_enable_merge_tag( 'completions' ), - $this->feed_setting_map_result_to_field( 'completions' ), - ), - 'dependency' => array( - 'live' => true, - 'fields' => array( - array( - 'field' => 'endpoint', - 'values' => array( 'completions' ), - ), - ), - ), - ), array( 'title' => 'Chat Completions', 'fields' => array( @@ -613,46 +521,6 @@ public function feed_settings_fields() { ), ), ), - array( - 'title' => 'Edits', - 'fields' => array( - array( - 'name' => 'edits_model', - 'tooltip' => 'Select the OpenAI model to use.', - 'label' => __( 'OpenAI Model', 'gravityforms-openai' ), - 'type' => 'radio', - 'choices' => $this->get_openai_model_choices( 'edits' ), - 'required' => true, - ), - array( - 'name' => 'edits_input', - 'tooltip' => __( 'The input text to use as a starting point for the edit.', 'gravityforms-openai' ), - 'label' => 'Input', - 'type' => 'textarea', - 'class' => 'medium merge-tag-support mt-position-right', - 'required' => false, - ), - array( - 'name' => 'edits_instruction', - 'tooltip' => __( 'The instruction that tells the model how to edit the prompt.', 'gravityforms-openai' ), - 'label' => __( 'Instruction', 'gravityforms-openai' ), - 'type' => 'textarea', - 'class' => 'medium merge-tag-support mt-position-right', - 'required' => true, - ), - $this->feed_setting_enable_merge_tag( 'edits' ), - $this->feed_setting_map_result_to_field( 'edits' ), - ), - 'dependency' => array( - 'live' => true, - 'fields' => array( - array( - 'field' => 'endpoint', - 'values' => array( 'edits' ), - ), - ), - ), - ), array( 'title' => 'Moderations', 'fields' => array( @@ -735,28 +603,9 @@ public function feed_settings_fields() { ), ), array( - 'title' => 'Advanced Settings: Completions', - 'fields' => array( - $this->feed_advanced_setting_timeout( 'completions' ), - $this->feed_advanced_setting_max_tokens( 'completions' ), - $this->feed_advanced_setting_temperature( 'completions' ), - $this->feed_advanced_setting_top_p( 'completions' ), - $this->feed_advanced_setting_frequency_penalty( 'completions' ), - $this->feed_advanced_setting_presence_penalty( 'completions' ), - ), - 'dependency' => array( - 'live' => true, - 'fields' => array( - array( - 'field' => 'endpoint', - 'values' => array( 'completions' ), - ), - ), - ), - ), - array( - 'title' => 'Advanced Settings: Chat Completions', - 'fields' => array( + 'title' => 'Advanced Settings: Chat Completions', + 'id' => 'advanced_settings_chat_completions', + 'fields' => array( $this->feed_advanced_setting_timeout( 'chat/completions' ), $this->feed_advanced_setting_max_tokens( 'chat/completions' ), $this->feed_advanced_setting_temperature( 'chat/completions' ), @@ -764,7 +613,9 @@ public function feed_settings_fields() { $this->feed_advanced_setting_frequency_penalty( 'chat/completions' ), $this->feed_advanced_setting_presence_penalty( 'chat/completions' ), ), - 'dependency' => array( + 'collapsible' => true, + 'is_collapsed' => ! isset( $_POST['gform_settings_section_collapsed_advanced_settings_chat_completions'] ), + 'dependency' => array( 'live' => true, 'fields' => array( array( @@ -775,28 +626,14 @@ public function feed_settings_fields() { ), ), array( - 'title' => 'Advanced Settings: Edits', - 'fields' => array( - $this->feed_advanced_setting_timeout( 'edits' ), - $this->feed_advanced_setting_temperature( 'edits' ), - $this->feed_advanced_setting_top_p( 'edits' ), - ), - 'dependency' => array( - 'live' => true, - 'fields' => array( - array( - 'field' => 'endpoint', - 'values' => array( 'edits' ), - ), - ), - ), - ), - array( - 'title' => 'Advanced Settings: Moderations', - 'fields' => array( + 'title' => 'Advanced Settings: Moderations', + 'id' => 'advanced_settings_moderations', + 'fields' => array( $this->feed_advanced_setting_timeout( 'moderations' ), ), - 'dependency' => array( + 'collapsible' => true, + 'is_collapsed' => ! isset( $_POST['gform_settings_section_collapsed_advanced_settings_moderations'] ), + 'dependency' => array( 'live' => true, 'fields' => array( array( @@ -819,10 +656,7 @@ public function feed_setting_enable_merge_tag( $endpoint ) { 'name' => $endpoint . '_enable_merge_tag', 'type' => 'checkbox', 'label' => __( 'Merge Tag', 'gravityforms-openai' ), - 'description' => __( 'Enable getting the output of the OpenAI result using a merge tag. -

- Pro Tip: This works with Gravity Forms Populate Anything\'s - Live Merge Tags!', 'gravityforms-openai' ), + 'description' => __( 'Enable getting the output of the OpenAI result using a merge tag.', 'gravityforms-openai' ), 'choices' => array( array( 'name' => $endpoint . '_enable_merge_tag', @@ -1039,21 +873,14 @@ public function feed_advanced_setting_presence_penalty( $endpoint ) { * @return array|void|null */ public function process_feed( $feed, $entry, $form ) { + $feed = $this->transform_feed( $feed ); $endpoint = $feed['meta']['endpoint']; switch ( $endpoint ) { - case 'completions': - $entry = $this->process_endpoint_completions( $feed, $entry, $form ); - break; - case 'chat/completions': $entry = $this->process_endpoint_chat_completions( $feed, $entry, $form ); break; - case 'edits': - $entry = $this->process_endpoint_edits( $feed, $entry, $form ); - break; - case 'moderations': $this->process_endpoint_moderations( $feed, $entry, $form ); break; @@ -1067,60 +894,6 @@ public function process_feed( $feed, $entry, $form ) { return $entry; } - /** - * Process completions endpoint. - * - * @param $feed array The current feed being processed. - * @param $entry array The current entry being processed. - * @param $form array The current form being processed. - * - * @return array Modified entry. - */ - public function process_endpoint_completions( $feed, $entry, $form ) { - $model = $feed['meta']['completions_model']; - $prompt = $feed['meta']['completions_prompt']; - - // Parse the merge tags in the prompt. - $prompt = GFCommon::replace_variables( $prompt, $form, $entry, false, false, false, 'text' ); - - GFAPI::add_note( $entry['id'], 0, 'OpenAI Request (' . $feed['meta']['feed_name'] . ')', sprintf( __( 'Sent request to OpenAI completions endpoint.', 'gravityforms-openai' ) ) ); - - // translators: placeholders are the feed name, model, prompt - $this->log_debug( __METHOD__ . '(): ' . sprintf( __( 'Sent request to OpenAI. Feed: %1$s, Endpoint: completions, Model: %2$s, Prompt: %3$s', 'gravityforms-openai' ), $feed['meta']['feed_name'], $model, $prompt ) ); - - $response = $this->make_request( 'completions', array( - 'prompt' => $prompt, - 'model' => $model, - ), $feed ); - - if ( is_wp_error( $response ) ) { - // If there was an error, log it and return. - $this->add_feed_error( $response->get_error_message(), $feed, $entry, $form ); - return $entry; - } - - // Parse the response and add it as an entry note. - $response_data = json_decode( $response['body'], true ); - - if ( rgar( $response_data, 'error' ) ) { - $this->add_feed_error( $response_data['error']['message'], $feed, $entry, $form ); - return $entry; - } - - $text = $this->get_text_from_response( $response_data ); - - if ( ! is_wp_error( $text ) ) { - GFAPI::add_note( $entry['id'], 0, 'OpenAI Response (' . $feed['meta']['feed_name'] . ')', $text ); - $entry = $this->maybe_save_result_to_field( $feed, $entry, $form, $text ); - } else { - $this->add_feed_error( $text->get_error_message(), $feed, $entry, $form ); - } - - gform_add_meta( $entry['id'], 'openai_response_' . $feed['id'], $response['body'] ); - - return $entry; - } - /** * Process chat endpoint. * @@ -1183,64 +956,6 @@ public function process_endpoint_chat_completions( $feed, $entry, $form ) { return $entry; } - /** - * Process edits endpoint. - * - * @param $feed array The current feed being processed. - * @param $entry array The current entry being processed. - * @param $form array The current form being processed. - * - * @return array Modified entry. - */ - public function process_endpoint_edits( $feed, $entry, $form ) { - $model = $feed['meta']['edits_model']; - $input = $feed['meta']['edits_input']; - $instruction = $feed['meta']['edits_instruction']; - - // Parse the merge tags in the input and instruction - $input = GFCommon::replace_variables( $input, $form, $entry, false, false, false, 'text' ); - $instruction = GFCommon::replace_variables( $instruction, $form, $entry, false, false, false, 'text' ); - - GFAPI::add_note( $entry['id'], 0, 'OpenAI Request (' . $feed['meta']['feed_name'] . ')', sprintf( __( 'Sent request to OpenAI edits endpoint.', 'gravityforms-openai' ) ) ); - - // translators: placeholders are the feed name, model, prompt - $this->log_debug( __METHOD__ . '(): ' . sprintf( __( 'Sent request to OpenAI. Feed: %1$s, Endpoint: edits, Model: %2$s, Input: %3$s, instruction: %4$s', 'gravityforms-openai' ), $feed['meta']['feed_name'], $model, $input, $instruction ) ); - - $response = $this->make_request( 'edits', array( - 'input' => $input, - 'instruction' => $instruction, - 'model' => $model, - ), $feed ); - - if ( is_wp_error( $response ) ) { - // If there was an error, log it and return. - $this->add_feed_error( $response->get_error_message(), $feed, $entry, $form ); - return $entry; - } - - // Parse the response and add it as an entry note. - $response_data = json_decode( $response['body'], true ); - - if ( rgar( $response_data, 'error' ) ) { - $this->add_feed_error( $response_data['error']['message'], $feed, $entry, $form ); - return $entry; - } - - $text = $this->get_text_from_response( $response_data ); - - if ( ! is_wp_error( $text ) ) { - GFAPI::add_note( $entry['id'], 0, 'OpenAI Response (' . $feed['meta']['feed_name'] . ')', $text ); - $entry = $this->maybe_save_result_to_field( $feed, $entry, $form, $text ); - } else { - $this->add_feed_error( $text->get_error_message(), $feed, $entry, $form ); - } - - gform_add_meta( $entry['id'], 'openai_response_' . $feed['id'], $response['body'] ); - - return $entry; - } - - /** * Saves the result to the selected field if configured. * @@ -1553,27 +1268,6 @@ public function get_merge_tag_replacement( $form, $entry, $feed_id, $url_encode, $response_data = array(); switch ( $endpoint ) { - case 'completions': - $model = $feed['meta']['completions_model']; - $prompt = $feed['meta']['completions_prompt']; - - $prompt = GFCommon::replace_variables( $prompt, $form, $entry, false, false, false, 'text' ); - - // If prompt is empty, do not generate any completion response, skip with blank. - if ( empty( $prompt ) ) { - return ''; - } - - $response = $this->make_request( 'completions', array( - 'model' => $model, - 'prompt' => $prompt, - ), $feed ); - - if ( ! is_wp_error( $response ) ) { - $response_data = json_decode( $response['body'], true ); - } - break; - case 'chat/completions': $model = $feed['meta']['chat_completions_model']; $message = $feed['meta']['chat_completions_message']; @@ -1603,30 +1297,6 @@ public function get_merge_tag_replacement( $form, $entry, $feed_id, $url_encode, } break; - case 'edits': - $model = $feed['meta']['edits_model']; - $input = $feed['meta']['edits_input']; - $instruction = $feed['meta']['edits_instruction']; - - $input = GFCommon::replace_variables( $input, $form, $entry, false, false, false, 'text' ); - $instruction = GFCommon::replace_variables( $instruction, $form, $entry, false, false, false, 'text' ); - - // If input or instruction is empty, do not generate any edit response, skip with blank. - if ( empty( $input ) || empty( $instruction ) ) { - return ''; - } - - $response = $this->make_request( 'edits', array( - 'model' => $model, - 'input' => $input, - 'instruction' => $instruction, - ), $feed ); - - if ( ! is_wp_error( $response ) ) { - $response_data = json_decode( $response['body'], true ); - } - break; - default: return ''; } @@ -1705,14 +1375,6 @@ public function make_request( $endpoint, $body, $feed ) { } switch ( $endpoint ) { - case 'completions': - $body['max_tokens'] = (float) rgar( $feed['meta'], $endpoint . '_' . 'max_tokens', $this->default_settings['completions']['max_tokens'] ); - $body['temperature'] = (float) rgar( $feed['meta'], $endpoint . '_' . 'temperature', $this->default_settings['completions']['temperature'] ); - $body['top_p'] = (float) rgar( $feed['meta'], $endpoint . '_' . 'top_p', $this->default_settings['completions']['top_p'] ); - $body['frequency_penalty'] = (float) rgar( $feed['meta'], $endpoint . '_' . 'frequency_penalty', $this->default_settings['completions']['frequency_penalty'] ); - $body['presence_penalty'] = (float) rgar( $feed['meta'], $endpoint . '_' . 'presence_penalty', $this->default_settings['completions']['presence_penalty'] ); - break; - case 'chat/completions': $body['max_tokens'] = (float) rgar( $feed['meta'], $endpoint . '_' . 'max_tokens', $this->default_settings['chat/completions']['max_tokens'] ); $body['temperature'] = (float) rgar( $feed['meta'], $endpoint . '_' . 'temperature', $this->default_settings['chat/completions']['temperature'] ); @@ -1720,11 +1382,6 @@ public function make_request( $endpoint, $body, $feed ) { $body['frequency_penalty'] = (float) rgar( $feed['meta'], $endpoint . '_' . 'frequency_penalty', $this->default_settings['chat/completions']['frequency_penalty'] ); $body['presence_penalty'] = (float) rgar( $feed['meta'], $endpoint . '_' . 'presence_penalty', $this->default_settings['chat/completions']['presence_penalty'] ); break; - - case 'edits': - $body['temperature'] = (float) rgar( $feed['meta'], $endpoint . '_' . 'temperature', $this->default_settings['edits']['temperature'] ); - $body['top_p'] = (float) rgar( $feed['meta'], $endpoint . '_' . 'top_p', $this->default_settings['edits']['top_p'] ); - break; } $body = apply_filters( 'gf_openai_request_body', $body, $endpoint, $feed ); @@ -1792,6 +1449,133 @@ public function get_headers() { return $headers; } + public function get_feed( $id ) { + $feed = parent::get_feed( $id ); + + if ( $this->should_transform_feed( $feed ) ) { + return $this->transform_feed( $feed ); + } + + return $feed; + } + + public function feed_edit_page( $form, $feed_id ) { + $feed = parent::get_feed( $feed_id ); + + if ( $this->should_transform_feed( $feed ) ) { + $endpoint = rgars( $feed, 'meta/endpoint' ); + $notice = $this->get_transform_message( $endpoint ); + $this->get_settings_renderer()->set_postback_message_callback( function( $message ) use ( $notice ) { + return $notice; + } ); + } + + parent::feed_edit_page( $form, $feed_id ); + } + + public function get_feeds( $form_id = null ) { + $feeds = parent::get_feeds( $form_id ); + + return array_map( function( $feed ) { + return $this->transform_feed( $feed ); + }, $feeds ); + } + + /** + * Transforms completion or edits feed to Chat\Completion + * + * @param array $feed The feed being processed. + * + * @return array + */ + public function transform_feed( $feed ) { + $endpoint = rgars( $feed, 'meta/endpoint' ); + + if ( $endpoint === 'completions' ) { + $feed['meta'] = array_merge( + $feed['meta'], + array( + 'endpoint' => 'chat/completions', + 'chat_completions_model' => 'gpt-3.5-turbo', + 'chat_completions_message' => rgars( $feed, 'meta/completions_prompt' ), + 'chat/completions_enable_merge_tag' => rgars( $feed, 'meta/completions_enable_merge_tag' ), + 'chat/completions_map_result_to_field' => rgars( $feed, 'meta/completions_map_result_to_field' ), + 'chat/completions_timeout' => rgars( $feed, 'meta/completions_timeout' ), + 'chat/completions_max_tokens' => rgars( $feed, 'meta/completions_max_tokens' ), + 'chat/completions_temperature' => rgars( $feed, 'meta/completions_temperature' ), + 'chat/completions_top_p' => rgars( $feed, 'meta/completions_top_p' ), + 'chat/completions_frequency_penalty' => rgars( $feed, 'meta/completions_frequency_penalty' ), + 'chat/completions_presence_penalty' => rgars( $feed, 'meta/completions_presence_penalty' ), + 'feed_condition_conditional_logic_object' => rgars( $feed, 'meta/feed_condition_conditional_logic_object' ), + 'feed_condition_conditional_logic' => rgars( $feed, 'meta/feed_condition_conditional_logic' ), + ) + ); + } + + if ( $endpoint === 'edits' ) { + $completion_message = rgars( $feed, 'meta/edits_instruction' ) . "\r\n\r\n" . rgars( $feed, 'meta/edits_input' ); + $feed['meta'] = array_merge( + $feed['meta'], + array( + 'endpoint' => 'chat/completions', + 'chat_completions_model' => 'gpt-3.5-turbo', + 'chat_completions_message' => $completion_message, + 'chat/completions_enable_merge_tag' => rgars( $feed, 'meta/edits_enable_merge_tag' ), + 'chat/completions_map_result_to_field' => rgars( $feed, 'meta/edits_map_result_to_field' ), + 'chat/completions_timeout' => rgars( $feed, 'meta/edits_timeout' ), + 'chat/completions_temperature' => rgars( $feed, 'meta/edits_temperature' ), + 'chat/completions_top_p' => rgars( $feed, 'meta/edits_top_p' ), + 'feed_condition_conditional_logic_object' => rgars( $feed, 'meta/feed_condition_conditional_logic_object' ), + 'feed_condition_conditional_logic' => rgars( $feed, 'meta/feed_condition_conditional_logic' ), + ) + ); + } + + return $feed; + } + + /** + * @param string $end feed endpoint. + * + * @return string + */ + public function get_transform_message( $endpoint ) { + // translators: placeholder is a string + return sprintf( __( 'This feed has been updated to use the "Chat Completions" endpoint, replacing the "%s" endpoint which has been deprecated by OpenAI. Save this feed to dismiss this message.', 'gravityforms-openai' ), ucfirst( $endpoint ) ); + } + + public function should_transform_feed( $feed ) { + $endpoint = rgars( $feed, 'meta/endpoint' ); + + if ( in_array( $endpoint, array( 'completions', 'edits' ) ) ) { + return true; + } + + return false; + } + + public function add_warning_css() { + $messages = json_encode( + array( + $this->get_transform_message( 'completions' ), + $this->get_transform_message( 'edits' ), + ) + ); + + if ( $this->is_feed_edit_page() ) { + ?> + +