diff --git a/hookdocs/meta.json b/hookdocs/meta.json index 0c2acd6ec..85430403c 100644 --- a/hookdocs/meta.json +++ b/hookdocs/meta.json @@ -7,5 +7,8 @@ }, "migration-guide-v2-to-v3": { "title": "Migration guide (version 2 to version 3)" + }, + "prompt-examples": { + "title": "Prompt examples" } } diff --git a/hookdocs/prompt-examples.md b/hookdocs/prompt-examples.md new file mode 100644 index 000000000..9db1e2efe --- /dev/null +++ b/hookdocs/prompt-examples.md @@ -0,0 +1,19 @@ +ClassifAI comes with multiple Features that utilize generative AI. These Features use prompts to generate content. ClassifAI ships with default prompts that have been crafted to work for a wide variety of use cases. However, these prompts may not work best for your use case. To help with this, ClassifAI allows you to create custom prompts that you can tailor to your specific needs. + +The following are some example prompts for specific Features and use cases that can be used in place of the default prompts that ship with ClassifAI. + +## Image Processing + +### Descriptive Text Generator + +Generate just alt text for an image: + +> You are an assistant that generates alt text for images that are used on a website. Alternative (Alt) Text is a brief text description of an image, and is an essential part of making content accessible. Alt Text is read aloud by screen readers to provide information about the image to the reader. You will be provided with an image and will generate alt text for that image. Try and follow the following guidelines when generating Alt Text: 1. Keep it short, usually 1-2 sentences. 2. Consider key elements of the image, instead of describing every little detail. 3. No need to say "image of" or "picture of". Before returning the text, re-evaluate your response and ensure you're following the above points, in particular ensuring the alt text is short, 1-2 sentences max. + +Generate just an image caption: + +> You are an assistant that generates captions for images that are used on a website. You will be provided with an image and will generate a caption for that image. Please describe the main item you see in the image, giving details but staying concise. There is no need to say "the image contains" or similar, just describe what is actually in the image. + +Generate just an image description: + +> You are an assistant that generates descriptions of images that are used on a website. You will be provided with an image and will describe the main item you see in the image, giving details but staying concise. There is no need to say "the image contains" or similar, just describe what is actually in the image. Ensure it is descriptive and accurate but not overly verbose. diff --git a/includes/Classifai/Admin/Notifications.php b/includes/Classifai/Admin/Notifications.php index 9acdf9564..60f51ebc2 100644 --- a/includes/Classifai/Admin/Notifications.php +++ b/includes/Classifai/Admin/Notifications.php @@ -117,8 +117,8 @@ public function render_activation_notice() { /** * Display a dismissable admin notice when a threshold may need updating. * - * We used to recommend thresholds between 70-75% but in the latest - * version of the AI Vision API, seems 55% is a better threshold. + * We used to recommend thresholds between 50-55% but in the latest + * version of the AI Vision API, seems 70% is a better threshold. */ public function thresholds_update_notice() { $features = [ @@ -144,7 +144,7 @@ public function thresholds_update_notice() { switch ( $feature_instance::ID ) { case DescriptiveTextGenerator::ID: $key = 'descriptive_confidence_threshold'; - $message = __( 'The previous recommended threshold for descriptive text generation was 75% but we find better results now at around 55%.', 'classifai' ); + $message = __( 'The previous recommended threshold for descriptive text generation was 55% but we find better results now at around 70%.', 'classifai' ); break; } @@ -153,8 +153,8 @@ public function thresholds_update_notice() { continue; } - // Don't show the notice if the threshold is already at 55% or lower. - if ( $key && isset( $settings[ $key ] ) && $settings[ $key ] <= 55 ) { + // Don't show the notice if the threshold is already at 70% or higher. + if ( $key && isset( $settings[ $key ] ) && $settings[ $key ] >= 70 ) { continue; } ?> @@ -165,9 +165,9 @@ public function thresholds_update_notice() { echo wp_kses_post( sprintf( // translators: %1$s: Feature specific message; %2$s: URL to Feature settings. - __( 'ClassifAI has updated to the v3.2 of the Azure AI Vision API. %1$s Click here to adjust those settings.', 'classifai' ), + __( 'ClassifAI has updated to the v4.0 of the Azure AI Vision API. %1$s Click here to adjust those settings.', 'classifai' ), esc_html( $message ), - esc_url( admin_url( "tools.php?page=classifai&tab=image_processing&feature=$name" ) ) + esc_url( admin_url( "tools.php?page=classifai#/image_processing/$name" ) ) ) ); ?> diff --git a/includes/Classifai/Features/DescriptiveTextGenerator.php b/includes/Classifai/Features/DescriptiveTextGenerator.php index 0002a4694..180410194 100644 --- a/includes/Classifai/Features/DescriptiveTextGenerator.php +++ b/includes/Classifai/Features/DescriptiveTextGenerator.php @@ -3,6 +3,7 @@ namespace Classifai\Features; use Classifai\Providers\Azure\ComputerVision; +use Classifai\Providers\OpenAI\ChatGPT; use Classifai\Services\ImageProcessing; use WP_REST_Server; use WP_REST_Request; @@ -21,6 +22,13 @@ class DescriptiveTextGenerator extends Feature { */ const ID = 'feature_descriptive_text_generator'; + /** + * Prompt for generating descriptive text. + * + * @var string + */ + public $prompt = 'You are an assistant that generates descriptions of images that are used on a website. You will be provided with an image and will describe the main item you see in the image, giving details but staying concise. There is no need to say "the image contains" or similar, just describe what is actually in the image. This text will be important for screen readers, so make sure it is descriptive and accurate but not overly verbose. Before returning the text, re-evaluate your response and ensure you are following the above points, in particular ensuring the text is concise.'; + /** * Constructor. */ @@ -33,6 +41,7 @@ public function __construct() { // Contains just the providers this feature supports. $this->supported_providers = [ ComputerVision::ID => __( 'Microsoft Azure AI Vision', 'classifai' ), + ChatGPT::ID => __( 'OpenAI', 'classifai' ), ]; } diff --git a/includes/Classifai/Helpers.php b/includes/Classifai/Helpers.php index ab9c8a33a..6ec89c371 100644 --- a/includes/Classifai/Helpers.php +++ b/includes/Classifai/Helpers.php @@ -152,7 +152,7 @@ function computer_vision_max_filesize(): int { * * @return {int} Filtered filesize in bytes. */ - return apply_filters( 'classifai_computer_vision_max_filesize', 4 * MB_IN_BYTES ); // 4MB default. + return apply_filters( 'classifai_computer_vision_max_filesize', 20 * MB_IN_BYTES ); // 20MB default. } /** diff --git a/includes/Classifai/Providers/Azure/ComputerVision.php b/includes/Classifai/Providers/Azure/ComputerVision.php index 0edd90dc9..99d4cede6 100644 --- a/includes/Classifai/Providers/Azure/ComputerVision.php +++ b/includes/Classifai/Providers/Azure/ComputerVision.php @@ -15,7 +15,7 @@ use WP_Error; use function Classifai\computer_vision_max_filesize; -use function Classifai\get_largest_acceptable_image_url; +use function Classifai\get_largest_size_and_dimensions_image_url; use function Classifai\get_modified_image_source_url; class ComputerVision extends Provider { @@ -25,7 +25,23 @@ class ComputerVision extends Provider { /** * @var string URL fragment to the analyze API endpoint */ - protected $analyze_url = 'vision/v3.2/analyze'; + protected $analyze_url = 'computervision/imageanalysis:analyze?api-version=2024-02-01'; + + /** + * Image types to process. + * + * @var array + */ + private $image_types_to_process = [ + 'bmp', + 'gif', + 'jpeg', + 'png', + 'webp', + 'ico', + 'tiff', + 'mpo', + ]; /** * ComputerVision constructor. @@ -115,7 +131,7 @@ public function add_descriptive_text_generation_fields() { 'min' => 1, 'step' => 1, 'default_value' => $settings['descriptive_confidence_threshold'], - 'description' => esc_html__( 'Minimum confidence score for automatically added generated text, numeric value from 0-100. Recommended to be set to at least 55.', 'classifai' ), + 'description' => esc_html__( 'Minimum confidence score for automatically added generated text, numeric value from 0-100. Recommended to be set to at least 70.', 'classifai' ), 'class' => 'classifai-provider-field hidden provider-scope-' . static::ID, // Important to add this. ] ); @@ -164,7 +180,7 @@ public function get_default_provider_settings(): array { return array_merge( $common_settings, [ - 'descriptive_confidence_threshold' => 55, + 'descriptive_confidence_threshold' => 70, ] ); @@ -377,23 +393,17 @@ public function smart_crop_image( array $metadata, int $attachment_id ) { * * @since 1.6.0 * - * @param array $metadata Attachment metadata. - * @param int $attachment_id Attachment ID. + * @param string $image_url URL of image to process. + * @param int $attachment_id Attachment ID. * @return string|WP_Error */ - public function ocr_processing( array $metadata = [], int $attachment_id = 0 ) { + public function ocr_processing( string $image_url, int $attachment_id = 0 ) { if ( ! wp_attachment_is_image( $attachment_id ) ) { return new WP_Error( 'invalid', esc_html__( 'This attachment can\'t be processed.', 'classifai' ) ); } - $feature = new ImageTextExtraction(); - $settings = $feature->get_settings( static::ID ); - - if ( ! is_array( $metadata ) || ! is_array( $settings ) ) { - return new WP_Error( 'invalid', esc_html__( 'Invalid data found. Please check your settings and try again.', 'classifai' ) ); - } - - $should_ocr_scan = $feature->is_feature_enabled(); + $feature = new ImageTextExtraction(); + $rtn = ''; /** * Filters whether to run OCR scanning on the current image. @@ -401,25 +411,61 @@ public function ocr_processing( array $metadata = [], int $attachment_id = 0 ) { * @since 1.6.0 * @hook classifai_should_ocr_scan_image * - * @param {bool} $should_ocr_scan Whether to run OCR scanning. The default value is set in ComputerVision settings. - * @param {array} $metadata Image metadata. - * @param {int} $attachment_id The attachment ID. + * @param {bool} $should_scan Whether to run OCR scanning. Defaults to feature being enabled. + * @param {string} $image_url URL of image to process. + * @param {int} $attachment_id The attachment ID. * * @return {bool} Whether to run OCR scanning. */ - if ( ! apply_filters( 'classifai_should_ocr_scan_image', $should_ocr_scan, $metadata, $attachment_id ) ) { + if ( ! apply_filters( 'classifai_should_ocr_scan_image', $feature->is_feature_enabled(), $image_url, $attachment_id ) ) { return ''; } - $image_url = wp_get_attachment_url( $attachment_id ); - $scan = $this->scan_image( $image_url, $feature ); + $details = $this->scan_image( $image_url, $feature ); + + if ( is_wp_error( $details ) ) { + return $details; + } + + set_transient( 'classifai_azure_computer_vision_image_text_extraction_latest_response', $details, DAY_IN_SECONDS * 30 ); - $ocr = new OCR( $settings, $scan ); - $response = $ocr->generate_ocr_data( $metadata, $attachment_id ); + if ( isset( $details->readResult ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase + $text = []; + + // Iterate down the chain to find the text we want. + foreach ( $details->readResult as $result ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase + foreach ( $result as $block ) { + foreach ( $block as $lines ) { + foreach ( $lines as $line ) { + if ( isset( $line->text ) ) { + $text[] = $line->text; + } + } + } + } + } - set_transient( 'classifai_azure_computer_vision_image_text_extraction_latest_response', $scan, DAY_IN_SECONDS * 30 ); + if ( ! empty( $text ) ) { - return $response; + /** + * Filter the text returned from the API. + * + * @since 1.6.0 + * @hook classifai_ocr_text + * + * @param {string} $text The returned text data. + * @param {object} $details The full scan results from the API. + * + * @return {string} The filtered text data. + */ + $rtn = apply_filters( 'classifai_ocr_text', implode( ' ', $text ), $details ); + + // Save all the results for later + update_post_meta( $attachment_id, 'classifai_computer_vision_ocr', $details ); + } + } + + return $rtn; } /** @@ -443,45 +489,48 @@ public function generate_alt_tags( string $image_url, int $attachment_id ) { return $details; } - $captions = $details->description->captions ?? []; + $caption = isset( $details->captionResult ) ? (array) $details->captionResult : []; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase set_transient( 'classifai_azure_computer_vision_descriptive_text_latest_response', $details, DAY_IN_SECONDS * 30 ); /** - * Filter the captions returned from the API. + * Filter the caption returned from the API. * * @since 1.4.0 * @hook classifai_computer_vision_captions * - * @param {array} $captions The returned caption data. + * @param {array} $caption The returned caption data. * * @return {array} The filtered caption data. */ - $captions = apply_filters( 'classifai_computer_vision_captions', $captions ); + $caption = apply_filters( 'classifai_computer_vision_captions', $caption ); - // Process the returned captions to see if they pass the threshold. - if ( is_array( $captions ) && ! empty( $captions ) ) { + // Process the returned caption to see if it passes the threshold. + if ( is_array( $caption ) && ! empty( $caption ) ) { $settings = $feature->get_settings( static::ID ); $threshold = $settings['descriptive_confidence_threshold']; - // Check the first caption to see if it passes the threshold. - if ( $captions[0]->confidence * 100 > $threshold ) { - $rtn = $captions[0]->text; + // Check the caption to see if it passes the threshold. + if ( isset( $caption['confidence'] ) && $caption['confidence'] * 100 > $threshold ) { + $rtn = ucfirst( $caption['text'] ?? '' ); } else { + /* translators: 1: Confidence score, 2: Threshold setting */ + $rtn = new WP_Error( 'threshold', sprintf( esc_html__( 'Caption confidence score is %1$d%% which is lower than your threshold setting of %2$d%%', 'classifai' ), $caption['confidence'] * 100, $threshold ) ); + /** * Fires if there were no captions returned. * * @since 1.5.0 * @hook classifai_computer_vision_caption_failed * - * @param {array} $tags The caption data. + * @param {array} $caption The caption data. * @param {int} $threshold The caption_threshold setting. */ - do_action( 'classifai_computer_vision_caption_failed', $captions, $threshold ); + do_action( 'classifai_computer_vision_caption_failed', $caption, $threshold ); } - // Save all the results for later. - update_post_meta( $attachment_id, 'classifai_computer_vision_captions', $captions ); + // Save full results for later. + update_post_meta( $attachment_id, 'classifai_computer_vision_captions', $caption ); } return $rtn; @@ -540,7 +589,7 @@ public function generate_image_tags( string $image_url, int $attachment_id ) { return $details; } - $tags = $details->tags ?? []; + $tags = $details->tagsResult->values ?? []; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase set_transient( 'classifai_azure_computer_vision_image_tags_latest_response', $details, DAY_IN_SECONDS * 30 ); @@ -674,14 +723,18 @@ protected function prep_api_url( ?\Classifai\Features\Feature $feature = null ): $api_features = []; if ( $feature instanceof DescriptiveTextGenerator && $feature->is_feature_enabled() && ! empty( $feature->get_alt_text_settings() ) ) { - $api_features[] = 'Description'; + $api_features[] = 'caption'; } if ( $feature instanceof ImageTagsGenerator && $feature->is_feature_enabled() ) { - $api_features[] = 'Tags'; + $api_features[] = 'tags'; } - $endpoint = add_query_arg( 'visualFeatures', implode( ',', $api_features ), trailingslashit( $settings['endpoint_url'] ) . $this->analyze_url ); + if ( $feature instanceof ImageTextExtraction && $feature->is_feature_enabled() ) { + $api_features[] = 'read'; + } + + $endpoint = add_query_arg( 'features', implode( ',', $api_features ), trailingslashit( $settings['endpoint_url'] ) . $this->analyze_url ); return $endpoint; } @@ -743,22 +796,36 @@ public function rest_endpoint_callback( $attachment_id, string $route_to_call = return new WP_Error( 'invalid', esc_html__( 'No valid metadata found.', 'classifai' ) ); } - switch ( $route_to_call ) { - case 'ocr': - return $this->ocr_processing( $metadata, $attachment_id ); + if ( 'crop' === $route_to_call ) { + return $this->smart_crop_image( $metadata, $attachment_id ); + } + + // Check if the image is of a type we can process. + $mime_type = get_post_mime_type( $attachment_id ); + $matched_extensions = explode( '|', array_search( $mime_type, wp_get_mime_types(), true ) ); + $process = false; - case 'crop': - return $this->smart_crop_image( $metadata, $attachment_id ); + foreach ( $matched_extensions as $ext ) { + if ( in_array( $ext, $this->image_types_to_process, true ) ) { + $process = true; + break; + } + } + + if ( ! $process ) { + return new WP_Error( 'invalid', esc_html__( 'Image does not match a valid mime type.', 'classifai' ) ); } $image_url = get_modified_image_source_url( $attachment_id ); if ( empty( $image_url ) || ! filter_var( $image_url, FILTER_VALIDATE_URL ) ) { if ( isset( $metadata['sizes'] ) && is_array( $metadata['sizes'] ) ) { - $image_url = get_largest_acceptable_image_url( + $image_url = get_largest_size_and_dimensions_image_url( get_attached_file( $attachment_id ), wp_get_attachment_url( $attachment_id ), - $metadata['sizes'], + $metadata, + [ 50, 16000 ], + [ 50, 16000 ], computer_vision_max_filesize() ); } else { @@ -767,13 +834,16 @@ public function rest_endpoint_callback( $attachment_id, string $route_to_call = } if ( empty( $image_url ) ) { - return new WP_Error( 'error', esc_html__( 'Valid image size not found. Make sure the image is less than 4MB.', 'classifai' ) ); + return new WP_Error( 'error', esc_html__( 'Image does not meet size requirements. Please ensure it is at least 50x50 but less than 16000x16000 and smaller than 20MB.', 'classifai' ) ); } switch ( $route_to_call ) { case 'descriptive_text': return $this->generate_alt_tags( $image_url, $attachment_id ); + case 'ocr': + return $this->ocr_processing( $image_url, $attachment_id ); + case 'tags': return $this->generate_image_tags( $image_url, $attachment_id ); } diff --git a/includes/Classifai/Providers/Azure/OCR.php b/includes/Classifai/Providers/Azure/OCR.php deleted file mode 100644 index 5ee7b70be..000000000 --- a/includes/Classifai/Providers/Azure/OCR.php +++ /dev/null @@ -1,323 +0,0 @@ -settings = $settings; - $this->scan = $scan; - } - - /** - * Builds the API url. - * - * @since 1.6.0 - * - * @return string - */ - public function get_api_url(): string { - return sprintf( '%s%s', trailingslashit( $this->settings['endpoint_url'] ), static::API_PATH ); - } - - /** - * Returns whether OCR processing should be applied to the attachment - * - * @since 1.6.0 - * - * @param int $attachment_id Attachment ID. - * @return bool - */ - public function should_process( int $attachment_id ): bool { - $mime_type = get_post_mime_type( $attachment_id ); - $matched_extensions = explode( '|', array_search( $mime_type, wp_get_mime_types(), true ) ); - $process = false; - - /** - * Filters the media types that should be processed - * - * @since 1.6.0 - * @hook classifai_ocr_approved_media_types - * - * @param {array} $media_types The media types to process. - * @param {int} $attachment_id The attachment ID. - * - * @return {array} Filtered media types. - */ - $approved_media_types = apply_filters( 'classifai_ocr_approved_media_types', $this->media_to_process, $attachment_id ); - - foreach ( $matched_extensions as $ext ) { - if ( in_array( $ext, $approved_media_types, true ) ) { - $process = true; - } - } - - // If we have a proper image and a previous image scan, check - // to see if we have proper tags set, with a high confidence - if ( $process && $this->scan && ! empty( $this->scan->tags ) && is_array( $this->scan->tags ) ) { - - /** - * Filters the tags we check for OCR processing - * - * @since 1.6.0 - * @hook classifai_ocr_tags - * - * @param {array} $tags Tags to look for. Default handwriting and text. - * @param {int} $attachment_id The attachment ID. - * @param {bool|object} $scan Previously run scan. - * - * @return {array} Filtered tags. - */ - $tags = apply_filters( 'classifai_ocr_tags', [ 'handwriting', 'text' ], $attachment_id, $this->scan ); - - /** - * Filters the tag confidence level for OCR processing - * - * @since 1.6.0 - * @hook classifai_ocr_tag_confidence - * - * @param {int} $confidence The minimum confidence level. Default 90. - * @param {int} $attachment_id The attachment ID. - * @param {bool|object} $scan Previously run scan. - * - * @return {int} Confidence level. - */ - $tag_confidence = apply_filters( 'classifai_ocr_tag_confidence', 90, $attachment_id, $this->scan ); - - foreach ( $this->scan->tags as $tag ) { - if ( in_array( $tag->name, $tags, true ) && $tag->confidence * 100 >= $tag_confidence ) { - $process = true; - break; - } - } - } - - /** - * Filters whether to run OCR processing on this media item - * - * @since 1.6.0 - * @hook classifai_ocr_should_process - * - * @param {bool} $process Whether to run OCR processing or not. - * @param {int} $attachment_id The attachment ID. - * @param {bool|object} $scan Previously run scan. - * - * @return {bool} Whether this attachment should have OCR processing. - */ - return apply_filters( 'classifai_ocr_should_process', $process, $attachment_id, $this->scan ); - } - - /** - * Get the OCR data - * - * @since 1.6.0 - * - * @param array $metadata Attachment metadata. - * @param integer $attachment_id Attachment ID. - * @return string|WP_Error - */ - public function generate_ocr_data( array $metadata, int $attachment_id ) { - $rtn = ''; - - if ( ! $this->should_process( $attachment_id ) ) { - return new WP_Error( 'process_error', esc_html__( 'Image does not meet processing requirements.', 'classifai' ), $metadata ); - } - - $url = get_largest_size_and_dimensions_image_url( - get_attached_file( $attachment_id ), - wp_get_attachment_url( $attachment_id ), - $metadata, - [ 50, 4200 ], - [ 50, 4200 ], - computer_vision_max_filesize() - ); - - // If a properly sized image isn't found, return - if ( ! $url ) { - return new WP_Error( 'size_error', esc_html__( 'Image does not meet size requirements. Please ensure it is at least 50x50 but less than 4200x4200 and smaller than 4MB.', 'classifai' ), $metadata ); - } - - $scan = $this->process( $url ); - - set_transient( 'classifai_azure_computer_vision_ocr_latest_response', $scan, DAY_IN_SECONDS * 30 ); - - if ( ! is_wp_error( $scan ) && isset( $scan->regions ) ) { - $text = []; - - // Iterate down the chain to find the text we want - foreach ( $scan->regions as $region ) { - foreach ( $region->lines as $lines ) { - foreach ( $lines->words as $word ) { - if ( isset( $word->text ) ) { - $text[] = $word->text; - } - } - } - } - - if ( ! empty( $text ) ) { - - /** - * Filter the text returned from the API. - * - * @since 1.6.0 - * @hook classifai_ocr_text - * - * @param {string} $text The returned text data. - * @param {object} $scan The full scan results from the API. - * - * @return {string} The filtered text data. - */ - $rtn = apply_filters( 'classifai_ocr_text', implode( ' ', $text ), $scan ); - - // Save all the results for later - update_post_meta( $attachment_id, 'classifai_computer_vision_ocr', $scan ); - } - } else { - $rtn = $scan; - } - - return $rtn; - } - - /** - * Run OCR processing using the Azure API - * - * @since 1.6.0 - * - * @param string $url Media URL. - * @return object|WP_Error - */ - public function process( string $url ) { - // Check if valid authentication is in place. - if ( empty( $this->settings ) || ( isset( $this->settings['authenticated'] ) && false === $this->settings['authenticated'] ) ) { - return new WP_Error( 'auth', esc_html__( 'Please set up valid authentication with Azure.', 'classifai' ) ); - } - - $response = wp_remote_post( - $this->get_api_url(), - [ - 'body' => wp_json_encode( - [ - 'url' => $url, - ] - ), - 'headers' => [ - 'Content-Type' => 'application/json', - 'Ocp-Apim-Subscription-Key' => $this->settings['api_key'], - ], - ] - ); - - /** - * Fires after the request to the ocr endpoint has run. - * - * @since 1.6.0 - * @hook classifai_ocr_after_request - * - * @param {array|WP_Error} Response data or a WP_Error if the request failed. - * @param {string} The attachment URL. - */ - do_action( 'classifai_ocr_after_request', $response, $url ); - - if ( ! is_wp_error( $response ) ) { - $body = json_decode( wp_remote_retrieve_body( $response ) ); - - if ( isset( $body->message ) ) { - $error_message = $body->message; - } elseif ( isset( $body->error->message ) ) { - $error_message = $body->error->message; - } else { - $error_message = false; - } - - if ( 200 !== wp_remote_retrieve_response_code( $response ) && $error_message ) { - /** - * Fires when the ocr API response did not succeed. - * - * @since 1.6.0 - * @hook classifai_ocr_unsuccessful_response - * - * @param {array|WP_Error} Response data or a WP_Error if the request failed. - * @param {string} The attachment URL. - */ - do_action( 'classifai_ocr_unsuccessful_response', $response, $url ); - - $rtn = new WP_Error( $body->code ?? 'error', $error_message, $body ); - } else { - $rtn = $body; - } - } else { - $rtn = $response; - } - - return $rtn; - } -} diff --git a/includes/Classifai/Providers/OpenAI/ChatGPT.php b/includes/Classifai/Providers/OpenAI/ChatGPT.php index 6a50aab76..7e126b11f 100644 --- a/includes/Classifai/Providers/OpenAI/ChatGPT.php +++ b/includes/Classifai/Providers/OpenAI/ChatGPT.php @@ -6,6 +6,7 @@ namespace Classifai\Providers\OpenAI; use Classifai\Features\ContentResizing; +use Classifai\Features\DescriptiveTextGenerator; use Classifai\Features\ExcerptGeneration; use Classifai\Features\TitleGeneration; use Classifai\Providers\Provider; @@ -14,6 +15,8 @@ use function Classifai\get_default_prompt; use function Classifai\sanitize_number_of_responses_field; +use function Classifai\get_modified_image_source_url; +use function Classifai\get_largest_size_and_dimensions_image_url; class ChatGPT extends Provider { @@ -132,6 +135,17 @@ public function get_default_provider_settings(): array { case TitleGeneration::ID: $common_settings['number_of_suggestions'] = 1; break; + + case DescriptiveTextGenerator::ID: + $common_settings['prompt'] = [ + [ + 'title' => esc_html__( 'ClassifAI default', 'classifai' ), + 'prompt' => $this->feature_instance->prompt, + 'original' => 1, + 'default' => 1, + ], + ]; + break; } return $common_settings; @@ -189,6 +203,9 @@ public function rest_endpoint_callback( $post_id = 0, string $route_to_call = '' // Handle all of our routes. switch ( $route_to_call ) { + case 'descriptive_text': + $return = $this->generate_descriptive_text( $post_id, $args ); + break; case 'excerpt': $return = $this->generate_excerpt( $post_id, $args ); break; @@ -203,6 +220,130 @@ public function rest_endpoint_callback( $post_id = 0, string $route_to_call = '' return $return; } + /** + * Generate descriptive text of an image. + * + * @param int $post_id The attachment ID we're processing. + * @param array $args Optional arguments. + * @return string|WP_Error + */ + public function generate_descriptive_text( int $post_id = 0, array $args = [] ) { + // Check to be sure the attachment exists and is an image. + if ( ! wp_attachment_is_image( $post_id ) ) { + return new WP_Error( 'invalid', esc_html__( 'This attachment can\'t be processed.', 'classifai' ) ); + } + + $metadata = wp_get_attachment_metadata( $post_id ); + + if ( ! $metadata || ! is_array( $metadata ) ) { + return new WP_Error( 'invalid', esc_html__( 'No valid metadata found.', 'classifai' ) ); + } + + $image_url = get_modified_image_source_url( $post_id ); + + if ( empty( $image_url ) || ! filter_var( $image_url, FILTER_VALIDATE_URL ) ) { + if ( isset( $metadata['sizes'] ) && is_array( $metadata['sizes'] ) ) { + $image_url = get_largest_size_and_dimensions_image_url( + get_attached_file( $post_id ), + wp_get_attachment_url( $post_id ), + $metadata, + [ 512, 2000 ], + [ 512, 2000 ], + 100 * MB_IN_BYTES + ); + } else { + $image_url = wp_get_attachment_url( $post_id ); + } + } + + if ( empty( $image_url ) ) { + return new WP_Error( 'error', esc_html__( 'Valid image size not found. Make sure the image is bigger than 512x512px.', 'classifai' ) ); + } + + $feature = new DescriptiveTextGenerator(); + $settings = $feature->get_settings(); + + // These checks (and the one above) happen in the REST permission_callback, + // but we run them again here in case this method is called directly. + if ( empty( $settings ) || ( isset( $settings[ static::ID ]['authenticated'] ) && false === $settings[ static::ID ]['authenticated'] ) || ( ! $feature->is_feature_enabled() && ( ! defined( 'WP_CLI' ) || ! WP_CLI ) ) ) { + return new WP_Error( 'not_enabled', esc_html__( 'Descriptive text generation is disabled or OpenAI authentication failed. Please check your settings.', 'classifai' ) ); + } + + $request = new APIRequest( $settings[ static::ID ]['api_key'] ?? '', $feature->get_option_name() ); + + /** + * Filter the prompt we will send to ChatGPT. + * + * @since 3.2.0 + * @hook classifai_chatgpt_descriptive_text_prompt + * + * @param {string} $prompt Prompt we are sending to ChatGPT. + * @param {int} $post_id ID of attachment we are describing. + * + * @return {string} Prompt. + */ + $prompt = apply_filters( 'classifai_chatgpt_descriptive_text_prompt', get_default_prompt( $settings[ static::ID ]['prompt'] ?? [] ) ?? $feature->prompt, $post_id ); + + /** + * Filter the request body before sending to ChatGPT. + * + * @since 3.2.0 + * @hook classifai_chatgpt_descriptive_text_request_body + * + * @param {array} $body Request body that will be sent to ChatGPT. + * @param {int} $post_id ID of attachment we are describing. + * + * @return {array} Request body. + */ + $body = apply_filters( + 'classifai_chatgpt_descriptive_text_request_body', + [ + 'model' => $this->chatgpt_model, + 'messages' => [ + [ + 'role' => 'system', + 'content' => $prompt, + ], + [ + 'role' => 'user', + 'content' => [ + [ + 'type' => 'image_url', + 'image_url' => [ + 'url' => $image_url, + 'detail' => 'auto', + ], + ], + ], + ], + ], + 'temperature' => 0.2, + 'max_tokens' => 300, + ], + $post_id + ); + + // Make our API request. + $response = $request->post( + $this->chatgpt_url, + [ + 'body' => wp_json_encode( $body ), + ] + ); + + // Extract out the text response, if it exists. + if ( ! is_wp_error( $response ) && ! empty( $response['choices'] ) ) { + foreach ( $response['choices'] as $choice ) { + if ( isset( $choice['message'], $choice['message']['content'] ) ) { + // ChatGPT often adds quotes to strings, so remove those as well as extra spaces. + $response = sanitize_text_field( trim( $choice['message']['content'], ' "\'' ) ); + } + } + } + + return $response; + } + /** * Generate an excerpt using ChatGPT. * diff --git a/includes/Classifai/Services/ImageProcessing.php b/includes/Classifai/Services/ImageProcessing.php index 981f22f19..bd508ea17 100644 --- a/includes/Classifai/Services/ImageProcessing.php +++ b/includes/Classifai/Services/ImageProcessing.php @@ -55,6 +55,7 @@ public static function get_service_providers(): array { 'classifai_image_processing_service_providers', [ 'Classifai\Providers\Azure\ComputerVision', + 'Classifai\Providers\OpenAI\ChatGPT', 'Classifai\Providers\OpenAI\DallE', ] ); diff --git a/package-lock.json b/package-lock.json index 87bb05ef5..66f4f33e2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,7 +18,7 @@ "devDependencies": { "@10up/cypress-wp-utils": "^0.4.0", "@wordpress/env": "^10.9.0", - "@wordpress/scripts": "30.6.0", + "@wordpress/scripts": "^30.6.0", "cypress": "^13.15.0", "cypress-file-upload": "^5.0.8", "cypress-mochawesome-reporter": "^3.8.2", @@ -2184,6 +2184,57 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@formatjs/ecma402-abstract": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-2.3.1.tgz", + "integrity": "sha512-Ip9uV+/MpLXWRk03U/GzeJMuPeOXpJBSB5V1tjA6kJhvqssye5J5LoYLc7Z5IAHb7nR62sRoguzrFiVCP/hnzw==", + "dev": true, + "dependencies": { + "@formatjs/fast-memoize": "2.2.5", + "@formatjs/intl-localematcher": "0.5.9", + "decimal.js": "10", + "tslib": "2" + } + }, + "node_modules/@formatjs/fast-memoize": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-2.2.5.tgz", + "integrity": "sha512-6PoewUMrrcqxSoBXAOJDiW1m+AmkrAj0RiXnOMD59GRaswjXhm3MDhgepXPBgonc09oSirAJTsAggzAGQf6A6g==", + "dev": true, + "dependencies": { + "tslib": "2" + } + }, + "node_modules/@formatjs/icu-messageformat-parser": { + "version": "2.9.7", + "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.9.7.tgz", + "integrity": "sha512-cuEHyRM5VqLQobANOjtjlgU7+qmk9Q3fDQuBiRRJ3+Wp3ZoZhpUPtUfuimZXsir6SaI2TaAJ+SLo9vLnV5QcbA==", + "dev": true, + "dependencies": { + "@formatjs/ecma402-abstract": "2.3.1", + "@formatjs/icu-skeleton-parser": "1.8.11", + "tslib": "2" + } + }, + "node_modules/@formatjs/icu-skeleton-parser": { + "version": "1.8.11", + "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.8.11.tgz", + "integrity": "sha512-8LlHHE/yL/zVJZHAX3pbKaCjZKmBIO6aJY1mkVh4RMSEu/2WRZ4Ysvv3kKXJ9M8RJLBHdnk1/dUQFdod1Dt7Dw==", + "dev": true, + "dependencies": { + "@formatjs/ecma402-abstract": "2.3.1", + "tslib": "2" + } + }, + "node_modules/@formatjs/intl-localematcher": { + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.5.9.tgz", + "integrity": "sha512-8zkGu/sv5euxbjfZ/xmklqLyDGQSxsLqg8XOq88JW3cmJtzhCP8EtSJXlaKZnVO4beEaoiT9wj4eIoCQ9smwxA==", + "dev": true, + "dependencies": { + "tslib": "2" + } + }, "node_modules/@hapi/hoek": { "version": "9.3.0", "dev": true, @@ -2795,6 +2846,12 @@ "node": ">= 8" } }, + "node_modules/@paulirish/trace_engine": { + "version": "0.0.32", + "resolved": "https://registry.npmjs.org/@paulirish/trace_engine/-/trace_engine-0.0.32.tgz", + "integrity": "sha512-KxWFdRNbv13U8bhYaQvH6gLG9CVEt2jKeosyOOYILVntWEVWhovbgDrbOiZ12pJO3vjZs0Zgbd3/Zgde98woEA==", + "dev": true + }, "node_modules/@pkgr/core": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", @@ -2886,88 +2943,6 @@ "url": "https://opencollective.com/popperjs" } }, - "node_modules/@puppeteer/browsers": { - "version": "1.4.6", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.4.6.tgz", - "integrity": "sha512-x4BEjr2SjOPowNeiguzjozQbsc6h437ovD/wu+JpaenxVLm3jkgzHY2xOslMTp50HoTvQreMjiexiGQw1sqZlQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "debug": "4.3.4", - "extract-zip": "2.0.1", - "progress": "2.0.3", - "proxy-agent": "6.3.0", - "tar-fs": "3.0.4", - "unbzip2-stream": "1.4.3", - "yargs": "17.7.1" - }, - "bin": { - "browsers": "lib/cjs/main-cli.js" - }, - "engines": { - "node": ">=16.3.0" - }, - "peerDependencies": { - "typescript": ">= 4.7.4" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@puppeteer/browsers/node_modules/extract-zip": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", - "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "debug": "^4.1.1", - "get-stream": "^5.1.0", - "yauzl": "^2.10.0" - }, - "bin": { - "extract-zip": "cli.js" - }, - "engines": { - "node": ">= 10.17.0" - }, - "optionalDependencies": { - "@types/yauzl": "^2.9.1" - } - }, - "node_modules/@puppeteer/browsers/node_modules/tar-fs": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.4.tgz", - "integrity": "sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==", - "dev": true, - "license": "MIT", - "dependencies": { - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^3.1.5" - } - }, - "node_modules/@puppeteer/browsers/node_modules/yargs": { - "version": "17.7.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", - "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", - "dev": true, - "license": "MIT", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/@remix-run/router": { "version": "1.20.0", "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.20.0.tgz", @@ -2983,132 +2958,85 @@ "dev": true, "license": "MIT" }, - "node_modules/@sentry/core": { - "version": "6.19.7", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-6.19.7.tgz", - "integrity": "sha512-tOfZ/umqB2AcHPGbIrsFLcvApdTm9ggpi/kQZFkej7kMphjT+SGBiQfYtjyg9jcRW+ilAR4JXC9BGKsdEQ+8Vw==", + "node_modules/@sentry-internal/tracing": { + "version": "7.120.1", + "resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.120.1.tgz", + "integrity": "sha512-MwZlhQY27oM4V05m2Q46WB2F7jqFu8fewg14yRcjCuK3tdxvQoLsXOEPMZxLxpoXPTqPCm3Ig7mA4GwdlCL41w==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { - "@sentry/hub": "6.19.7", - "@sentry/minimal": "6.19.7", - "@sentry/types": "6.19.7", - "@sentry/utils": "6.19.7", - "tslib": "^1.9.3" + "@sentry/core": "7.120.1", + "@sentry/types": "7.120.1", + "@sentry/utils": "7.120.1" }, "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/@sentry/core/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true, - "license": "0BSD" - }, - "node_modules/@sentry/hub": { - "version": "6.19.7", - "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.19.7.tgz", - "integrity": "sha512-y3OtbYFAqKHCWezF0EGGr5lcyI2KbaXW2Ik7Xp8Mu9TxbSTuwTe4rTntwg8ngPjUQU3SUHzgjqVB8qjiGqFXCA==", + "node_modules/@sentry/core": { + "version": "7.120.1", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.120.1.tgz", + "integrity": "sha512-tXpJlf/8ngsSCpcRD+4DDvh4TqUbY0MlvE9Mpc/jO5GgYl/goAH2H1COw6W/UNfkr/l80P2jejS0HLPk0moi0A==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { - "@sentry/types": "6.19.7", - "@sentry/utils": "6.19.7", - "tslib": "^1.9.3" + "@sentry/types": "7.120.1", + "@sentry/utils": "7.120.1" }, "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/@sentry/hub/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true, - "license": "0BSD" - }, - "node_modules/@sentry/minimal": { - "version": "6.19.7", - "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.19.7.tgz", - "integrity": "sha512-wcYmSJOdvk6VAPx8IcmZgN08XTXRwRtB1aOLZm+MVHjIZIhHoBGZJYTVQS/BWjldsamj2cX3YGbGXNunaCfYJQ==", + "node_modules/@sentry/integrations": { + "version": "7.120.1", + "resolved": "https://registry.npmjs.org/@sentry/integrations/-/integrations-7.120.1.tgz", + "integrity": "sha512-dshhLZUN+pYpyZiS5QRYKaYSqvWYtmsbwmBlH4SCGOnN9sbY4nZn0h8njr+xKT8UFnPxoTlbZmkcrVY3qPVMfg==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { - "@sentry/hub": "6.19.7", - "@sentry/types": "6.19.7", - "tslib": "^1.9.3" + "@sentry/core": "7.120.1", + "@sentry/types": "7.120.1", + "@sentry/utils": "7.120.1", + "localforage": "^1.8.1" }, "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/@sentry/minimal/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true, - "license": "0BSD" - }, "node_modules/@sentry/node": { - "version": "6.19.7", - "resolved": "https://registry.npmjs.org/@sentry/node/-/node-6.19.7.tgz", - "integrity": "sha512-gtmRC4dAXKODMpHXKfrkfvyBL3cI8y64vEi3fDD046uqYcrWdgoQsffuBbxMAizc6Ez1ia+f0Flue6p15Qaltg==", + "version": "7.120.1", + "resolved": "https://registry.npmjs.org/@sentry/node/-/node-7.120.1.tgz", + "integrity": "sha512-YF/TDUCtUOQeUMwL4vcUWGNv/8Qz9624xBnaL8nXW888xNBoSRr2vH/zMrmTup5zfmWAh9lVbp98BZFF6F0WJg==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { - "@sentry/core": "6.19.7", - "@sentry/hub": "6.19.7", - "@sentry/types": "6.19.7", - "@sentry/utils": "6.19.7", - "cookie": "^0.4.1", - "https-proxy-agent": "^5.0.0", - "lru_map": "^0.3.3", - "tslib": "^1.9.3" + "@sentry-internal/tracing": "7.120.1", + "@sentry/core": "7.120.1", + "@sentry/integrations": "7.120.1", + "@sentry/types": "7.120.1", + "@sentry/utils": "7.120.1" }, "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/@sentry/node/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true, - "license": "0BSD" - }, "node_modules/@sentry/types": { - "version": "6.19.7", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.19.7.tgz", - "integrity": "sha512-jH84pDYE+hHIbVnab3Hr+ZXr1v8QABfhx39KknxqKWr2l0oEItzepV0URvbEhB446lk/S/59230dlUUIBGsXbg==", + "version": "7.120.1", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.120.1.tgz", + "integrity": "sha512-f/WT7YUH8SA2Jhez/hYz/dA351AJqr1Eht/URUdYsqMFecXr/blAcNKRVFccSsvQeTqWVV9HVQ9BXUSjPJOvFA==", "dev": true, - "license": "BSD-3-Clause", "engines": { - "node": ">=6" + "node": ">=8" } }, "node_modules/@sentry/utils": { - "version": "6.19.7", - "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.19.7.tgz", - "integrity": "sha512-z95ECmE3i9pbWoXQrD/7PgkBAzJYR+iXtPuTkpBjDKs86O3mT+PXOT3BAn79w2wkn7/i3vOGD2xVr1uiMl26dA==", + "version": "7.120.1", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.120.1.tgz", + "integrity": "sha512-4boeo5Y3zw3gFrWZmPHsYOIlTh//eBaGBgWL25FqLbLObO23gFE86G6O6knP1Gamm1DGX2IWH7w4MChYuBm6tA==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { - "@sentry/types": "6.19.7", - "tslib": "^1.9.3" + "@sentry/types": "7.120.1" }, "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/@sentry/utils/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true, - "license": "0BSD" - }, "node_modules/@sideway/address": { "version": "4.1.5", "dev": true, @@ -3413,41 +3341,6 @@ "node": ">=10" } }, - "node_modules/@tannin/compile": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@tannin/compile/-/compile-1.1.0.tgz", - "integrity": "sha512-n8m9eNDfoNZoxdvWiTfW/hSPhehzLJ3zW7f8E7oT6mCROoMNWCB4TYtv041+2FMAxweiE0j7i1jubQU4MEC/Gg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@tannin/evaluate": "^1.2.0", - "@tannin/postfix": "^1.1.0" - } - }, - "node_modules/@tannin/evaluate": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@tannin/evaluate/-/evaluate-1.2.0.tgz", - "integrity": "sha512-3ioXvNowbO/wSrxsDG5DKIMxC81P0QrQTYai8zFNY+umuoHWRPbQ/TuuDEOju9E+jQDXmj6yI5GyejNuh8I+eg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@tannin/plural-forms": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@tannin/plural-forms/-/plural-forms-1.1.0.tgz", - "integrity": "sha512-xl9R2mDZO/qiHam1AgMnAES6IKIg7OBhcXqy6eDsRCdXuxAFPcjrej9HMjyCLE0DJ/8cHf0i5OQTstuBRhpbHw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@tannin/compile": "^1.1.0" - } - }, - "node_modules/@tannin/postfix": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@tannin/postfix/-/postfix-1.1.0.tgz", - "integrity": "sha512-oocsqY7g0cR+Gur5jRQLSrX2OtpMLMse1I10JQBm8CdGMrDkh1Mg2gjsiquMHRtBs4Qwu5wgEp5GgIYHk4SNPw==", - "dev": true, - "license": "MIT" - }, "node_modules/@tootallnate/once": { "version": "2.0.0", "dev": true, @@ -4405,21 +4298,6 @@ } } }, - "node_modules/@wordpress/api-fetch": { - "version": "6.55.0", - "resolved": "https://registry.npmjs.org/@wordpress/api-fetch/-/api-fetch-6.55.0.tgz", - "integrity": "sha512-1HrCUsJdeRY5Y0IjplotINwqMRO81e7O7VhBScuKk7iOuDm/E1ioKv2uLGnPNWziYu+Zf025byxOqVzXDyM2gw==", - "dev": true, - "license": "GPL-2.0-or-later", - "dependencies": { - "@babel/runtime": "^7.16.0", - "@wordpress/i18n": "^4.58.0", - "@wordpress/url": "^3.59.0" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/@wordpress/babel-plugin-import-jsx-pragma": { "version": "4.41.0", "resolved": "https://registry.npmjs.org/@wordpress/babel-plugin-import-jsx-pragma/-/babel-plugin-import-jsx-pragma-4.41.0.tgz", @@ -4491,24 +4369,21 @@ } }, "node_modules/@wordpress/e2e-test-utils-playwright": { - "version": "0.26.0", - "resolved": "https://registry.npmjs.org/@wordpress/e2e-test-utils-playwright/-/e2e-test-utils-playwright-0.26.0.tgz", - "integrity": "sha512-4KFyQ3IsYIJaIvOQ1qhAHhRISs9abNToF/bktfMNxQiEJsmbNn7lq/IbaY+shqwdBWVg8TQtLcL4MpSl0ISaxQ==", + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/@wordpress/e2e-test-utils-playwright/-/e2e-test-utils-playwright-1.14.0.tgz", + "integrity": "sha512-G9r3ZysgzAmUbR4bjGAEEP6P2RCIAG8uMU7yyzxOAHegINSbF3shEZKvVNBeKxNwHKAVa9koh/niGN3U4Kr6Rw==", "dev": true, - "license": "GPL-2.0-or-later", "dependencies": { - "@wordpress/api-fetch": "^6.55.0", - "@wordpress/keycodes": "^3.58.0", - "@wordpress/url": "^3.59.0", "change-case": "^4.1.2", "form-data": "^4.0.0", "get-port": "^5.1.1", - "lighthouse": "^10.4.0", + "lighthouse": "^12.2.2", "mime": "^3.0.0", - "web-vitals": "^3.5.0" + "web-vitals": "^4.2.1" }, "engines": { - "node": ">=12" + "node": ">=18.12.0", + "npm": ">=8.19.2" }, "peerDependencies": { "@playwright/test": ">=1" @@ -4672,40 +4547,6 @@ "node": ">= 6" } }, - "node_modules/@wordpress/hooks": { - "version": "3.58.0", - "resolved": "https://registry.npmjs.org/@wordpress/hooks/-/hooks-3.58.0.tgz", - "integrity": "sha512-9LB0ZHnZRQlORttux9t/xbAskF+dk2ujqzPGsVzc92mSKpQP3K2a5Wy74fUnInguB1vLUNHT6nrNdkVom5qX1Q==", - "dev": true, - "license": "GPL-2.0-or-later", - "dependencies": { - "@babel/runtime": "^7.16.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@wordpress/i18n": { - "version": "4.58.0", - "resolved": "https://registry.npmjs.org/@wordpress/i18n/-/i18n-4.58.0.tgz", - "integrity": "sha512-VfvS3BWv/RDjRKD6PscIcvYfWKnGJcI/DEqyDgUMhxCM6NRwoL478CsUKTiGJIymeyRodNRfprdcF086DpGKYw==", - "dev": true, - "license": "GPL-2.0-or-later", - "dependencies": { - "@babel/runtime": "^7.16.0", - "@wordpress/hooks": "^3.58.0", - "gettext-parser": "^1.3.1", - "memize": "^2.1.0", - "sprintf-js": "^1.1.1", - "tannin": "^1.2.0" - }, - "bin": { - "pot-to-php": "tools/pot-to-php.js" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/@wordpress/icons": { "version": "10.9.0", "resolved": "https://registry.npmjs.org/@wordpress/icons/-/icons-10.9.0.tgz", @@ -4755,20 +4596,6 @@ "jest": ">=29" } }, - "node_modules/@wordpress/keycodes": { - "version": "3.58.0", - "resolved": "https://registry.npmjs.org/@wordpress/keycodes/-/keycodes-3.58.0.tgz", - "integrity": "sha512-Q/LRKpx8ndzuHlkxSQ2BD+NTYYKQPIneNNMng8hTAfyU7RFwXpqj06HpeOFGh4XIdPKCs/8hmucoLJRmmLmZJA==", - "dev": true, - "license": "GPL-2.0-or-later", - "dependencies": { - "@babel/runtime": "^7.16.0", - "@wordpress/i18n": "^4.58.0" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/@wordpress/npm-package-json-lint-config": { "version": "4.43.0", "resolved": "https://registry.npmjs.org/@wordpress/npm-package-json-lint-config/-/npm-package-json-lint-config-4.43.0.tgz", @@ -5334,20 +5161,6 @@ "stylelint": "^14.2" } }, - "node_modules/@wordpress/url": { - "version": "3.59.0", - "resolved": "https://registry.npmjs.org/@wordpress/url/-/url-3.59.0.tgz", - "integrity": "sha512-GxvoMjYCav0w4CiX0i0h3qflrE/9rhLIZg5aPCQjbrBdwTxYR3Exfw0IJYcmVaTKXQOUU8fOxlDxULsbLmKe9w==", - "dev": true, - "license": "GPL-2.0-or-later", - "dependencies": { - "@babel/runtime": "^7.16.0", - "remove-accents": "^0.5.0" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/@wordpress/warning": { "version": "2.58.0", "resolved": "https://registry.npmjs.org/@wordpress/warning/-/warning-2.58.0.tgz", @@ -6002,11 +5815,10 @@ "license": "MIT" }, "node_modules/axe-core": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.10.0.tgz", - "integrity": "sha512-Mr2ZakwQ7XUAjp7pAwQWRhhK8mQQ6JAaNWSjmjxil0R8BPioMtQsTLOolGYkji1rcL++3dCqZA3zWqpT+9Ew6g==", + "version": "4.10.2", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.10.2.tgz", + "integrity": "sha512-RE3mdQ7P3FRSe7eqCWoeQ/Z9QXrtniSjp1wUjt5nRC3WIpz5rSCve6o3fsZ2aCpJtrZjSZgjwXAoTO5k4tEI0w==", "dev": true, - "license": "MPL-2.0", "engines": { "node": ">=4" } @@ -6417,9 +6229,10 @@ "license": "MIT" }, "node_modules/body-parser": { - "version": "1.20.2", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", "dev": true, - "license": "MIT", "dependencies": { "bytes": "3.1.2", "content-type": "~1.0.5", @@ -6429,7 +6242,7 @@ "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.11.0", + "qs": "6.13.0", "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" @@ -6441,24 +6254,27 @@ }, "node_modules/body-parser/node_modules/bytes": { "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/body-parser/node_modules/debug": { "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "license": "MIT", "dependencies": { "ms": "2.0.0" } }, "node_modules/body-parser/node_modules/iconv-lite": { "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, - "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -6468,22 +6284,9 @@ }, "node_modules/body-parser/node_modules/ms": { "version": "2.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/body-parser/node_modules/qs": { - "version": "6.11.0", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true }, "node_modules/bonjour-service": { "version": "1.2.1", @@ -6938,16 +6741,15 @@ } }, "node_modules/chrome-launcher": { - "version": "0.15.2", - "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.15.2.tgz", - "integrity": "sha512-zdLEwNo3aUVzIhKhTtXfxhdvZhUghrnmkvcAq2NoDd+LeOHKf03H5jwZ8T/STsAlzyALkBVK552iaG1fGf1xVQ==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-1.1.2.tgz", + "integrity": "sha512-YclTJey34KUm5jB1aEJCq807bSievi7Nb/TU4Gu504fUYi3jw3KCIaH6L7nFWQhdEgH3V+wCh+kKD1P5cXnfxw==", "dev": true, - "license": "Apache-2.0", "dependencies": { "@types/node": "*", "escape-string-regexp": "^4.0.0", "is-wsl": "^2.2.0", - "lighthouse-logger": "^1.0.0" + "lighthouse-logger": "^2.0.1" }, "bin": { "print-chrome-path": "bin/print-chrome-path.js" @@ -7313,7 +7115,6 @@ "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "dot-prop": "^5.2.0", "graceful-fs": "^4.1.2", @@ -7331,7 +7132,6 @@ "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", "dev": true, - "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4", "is-typedarray": "^1.0.0", @@ -7371,8 +7171,9 @@ }, "node_modules/content-type": { "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -7382,16 +7183,6 @@ "dev": true, "license": "MIT" }, - "node_modules/cookie": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/cookie-signature": { "version": "1.0.6", "dev": true, @@ -7648,7 +7439,6 @@ "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } @@ -7657,8 +7447,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/csp_evaluator/-/csp_evaluator-1.1.1.tgz", "integrity": "sha512-N3ASg0C4kNPUaNxt1XAvzHIVuzdtr8KLgfk1O8WDyimp1GisPAHESupArO2ieHk9QWbrJ/WkQODyh21Ps/xhxw==", - "dev": true, - "license": "Apache-2.0" + "dev": true }, "node_modules/css": { "version": "2.2.4", @@ -8672,16 +8461,18 @@ }, "node_modules/depd": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/destroy": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8", "npm": "1.2.8000 || >= 1.4.16" @@ -8703,11 +8494,10 @@ "license": "MIT" }, "node_modules/devtools-protocol": { - "version": "0.0.1155343", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1155343.tgz", - "integrity": "sha512-oD9vGBV2wTc7fAzAM6KC0chSgs234V8+qDEeK+mcbRj2UvcuA7lgBztGi/opj/iahcXD3BSj8Ymvib628yy9FA==", - "dev": true, - "license": "BSD-3-Clause" + "version": "0.0.1312386", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1312386.tgz", + "integrity": "sha512-DPnhUXvmvKT2dFA/j7B+riVLUt9Q6RKJlcppojL5CoRywJJKLDYnRlw0gTFKfgDPHP5E04UoB71SxoJlVZy8FA==", + "dev": true }, "node_modules/diff": { "version": "5.0.0", @@ -8848,7 +8638,6 @@ "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", "dev": true, - "license": "MIT", "dependencies": { "is-obj": "^2.0.0" }, @@ -8874,8 +8663,9 @@ }, "node_modules/ee-first": { "version": "1.1.1", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true }, "node_modules/electron-to-chromium": { "version": "1.5.29", @@ -8913,9 +8703,10 @@ } }, "node_modules/encodeurl": { - "version": "1.0.2", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -10138,8 +9929,9 @@ }, "node_modules/etag": { "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -10292,36 +10084,37 @@ "license": "MIT" }, "node_modules/express": { - "version": "4.19.2", + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", "dev": true, - "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.2", + "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.6.0", + "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.2.0", + "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", + "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", + "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", - "qs": "6.11.0", + "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", + "send": "0.19.0", + "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", @@ -10330,12 +10123,17 @@ }, "engines": { "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/express/node_modules/cookie": { - "version": "0.6.0", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -10353,20 +10151,6 @@ "dev": true, "license": "MIT" }, - "node_modules/express/node_modules/qs": { - "version": "6.11.0", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -10626,12 +10410,13 @@ } }, "node_modules/finalhandler": { - "version": "1.2.0", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", "dev": true, - "license": "MIT", "dependencies": { "debug": "2.6.9", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", @@ -10644,16 +10429,18 @@ }, "node_modules/finalhandler/node_modules/debug": { "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "license": "MIT", "dependencies": { "ms": "2.0.0" } }, "node_modules/finalhandler/node_modules/ms": { "version": "2.0.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true }, "node_modules/find-cache-dir": { "version": "4.0.0", @@ -10957,8 +10744,9 @@ }, "node_modules/fresh": { "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -11219,17 +11007,6 @@ "assert-plus": "^1.0.0" } }, - "node_modules/gettext-parser": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/gettext-parser/-/gettext-parser-1.4.0.tgz", - "integrity": "sha512-sedZYLHlHeBop/gZ1jdg59hlUEcpcZJofLq2JFwJT1zTqAU3l2wFv6IsuwFHGqbiT9DWzMUW4/em2+hspnmMMA==", - "dev": true, - "license": "MIT", - "dependencies": { - "encoding": "^0.1.12", - "safe-buffer": "^5.1.1" - } - }, "node_modules/glob": { "version": "7.2.3", "dev": true, @@ -11669,8 +11446,9 @@ }, "node_modules/http-errors": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", "dev": true, - "license": "MIT", "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", @@ -11687,7 +11465,6 @@ "resolved": "https://registry.npmjs.org/http-link-header/-/http-link-header-1.1.3.tgz", "integrity": "sha512-3cZ0SRL8fb9MUlU3mKM61FcQvPfXx2dBrZW3Vbg5CXa8jFlK8OaEpePenLe1oEXQduhz8b0QjsqfS59QP4AJDQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.0.0" } @@ -11892,8 +11669,13 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/image-ssim/-/image-ssim-0.2.0.tgz", "integrity": "sha512-W7+sO6/yhxy83L0G7xR8YAc5Z5QFtYEXXRV6EaE8tuYBZJnA3gVgp3q7X7muhLZVodeb9UfvjSbwt9VJwjIYAg==", - "dev": true, - "license": "MIT" + "dev": true + }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "dev": true }, "node_modules/immutable": { "version": "4.3.5", @@ -12039,23 +11821,17 @@ } }, "node_modules/intl-messageformat": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-4.4.0.tgz", - "integrity": "sha512-z+Bj2rS3LZSYU4+sNitdHrwnBhr0wO80ZJSW8EzKDBowwUe3Q/UsvgCGjrwa+HPzoGCLEb9HAjfJgo4j2Sac8w==", + "version": "10.7.10", + "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-10.7.10.tgz", + "integrity": "sha512-hp7iejCBiJdW3zmOe18FdlJu8U/JsADSDiBPQhfdSeI8B9POtvPRvPh3nMlvhYayGMKLv6maldhR7y3Pf1vkpw==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { - "intl-messageformat-parser": "^1.8.1" + "@formatjs/ecma402-abstract": "2.3.1", + "@formatjs/fast-memoize": "2.2.5", + "@formatjs/icu-messageformat-parser": "2.9.7", + "tslib": "2" } }, - "node_modules/intl-messageformat-parser": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/intl-messageformat-parser/-/intl-messageformat-parser-1.8.1.tgz", - "integrity": "sha512-IMSCKVf0USrM/959vj3xac7s8f87sc+80Y/ipBzdKy4ifBv5Gsj2tZ41EAaURVg01QU71fYr77uA8Meh6kELbg==", - "deprecated": "We've written a new parser that's 6x faster and is backwards compatible. Please use @formatjs/icu-messageformat-parser", - "dev": true, - "license": "BSD-3-Clause" - }, "node_modules/ip-address": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", @@ -12450,7 +12226,6 @@ "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } @@ -13586,15 +13361,13 @@ "version": "0.4.4", "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.4.tgz", "integrity": "sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==", - "dev": true, - "license": "BSD-3-Clause" + "dev": true }, "node_modules/js-library-detector": { "version": "6.7.0", "resolved": "https://registry.npmjs.org/js-library-detector/-/js-library-detector-6.7.0.tgz", "integrity": "sha512-c80Qupofp43y4cJ7+8TTDN/AsDwLi5oOm/plBrWI+iQt485vKXCco+yVmOwEgdo9VOdsYTuV0UlTeetVPTriXA==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" } @@ -14014,235 +13787,104 @@ "node": ">= 0.8.0" } }, + "node_modules/lie": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz", + "integrity": "sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==", + "dev": true, + "dependencies": { + "immediate": "~3.0.5" + } + }, "node_modules/lighthouse": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/lighthouse/-/lighthouse-10.4.0.tgz", - "integrity": "sha512-XQWHEWkJ8YxSPsxttBJORy5+hQrzbvGkYfeP3fJjyYKioWkF2MXfFqNK4ZuV4jL8pBu7Z91qnQP6In0bq1yXww==", + "version": "12.2.2", + "resolved": "https://registry.npmjs.org/lighthouse/-/lighthouse-12.2.2.tgz", + "integrity": "sha512-avoiiFeGN1gkWhp/W1schJoXOsTPxRKWV3+uW/rGHuov2g/HGB+4SN9J/av1GNSh13sEYgkHL3iJOp1+mBVKYQ==", "dev": true, - "license": "Apache-2.0", "dependencies": { - "@sentry/node": "^6.17.4", - "axe-core": "4.7.2", - "chrome-launcher": "^0.15.2", + "@paulirish/trace_engine": "0.0.32", + "@sentry/node": "^7.0.0", + "axe-core": "^4.10.2", + "chrome-launcher": "^1.1.2", "configstore": "^5.0.1", "csp_evaluator": "1.1.1", - "devtools-protocol": "0.0.1155343", + "devtools-protocol": "0.0.1312386", "enquirer": "^2.3.6", "http-link-header": "^1.1.1", - "intl-messageformat": "^4.4.0", + "intl-messageformat": "^10.5.3", "jpeg-js": "^0.4.4", - "js-library-detector": "^6.6.0", - "lighthouse-logger": "^1.4.1", - "lighthouse-stack-packs": "1.11.0", - "lodash": "^4.17.21", + "js-library-detector": "^6.7.0", + "lighthouse-logger": "^2.0.1", + "lighthouse-stack-packs": "1.12.2", + "lodash-es": "^4.17.21", "lookup-closest-locale": "6.2.0", "metaviewport-parser": "0.3.0", - "open": "^8.4.0", - "parse-cache-control": "1.0.1", - "ps-list": "^8.0.0", - "puppeteer-core": "^20.8.0", - "robots-parser": "^3.0.0", - "semver": "^5.3.0", - "speedline-core": "^1.4.3", - "third-party-web": "^0.23.3", - "ws": "^7.0.0", - "yargs": "^17.3.1", - "yargs-parser": "^21.0.0" - }, - "bin": { - "chrome-debug": "core/scripts/manual-chrome-launcher.js", - "lighthouse": "cli/index.js", - "smokehouse": "cli/test/smokehouse/frontends/smokehouse-bin.js" - }, - "engines": { - "node": ">=16.16" - } - }, - "node_modules/lighthouse-logger": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-1.4.2.tgz", - "integrity": "sha512-gPWxznF6TKmUHrOQjlVo2UbaL2EJ71mb2CCeRs/2qBpi4L/g4LUVc9+3lKQ6DTUZwJswfM7ainGrLO1+fOqa2g==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "debug": "^2.6.9", - "marky": "^1.2.2" - } - }, - "node_modules/lighthouse-logger/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/lighthouse-logger/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" - }, - "node_modules/lighthouse-stack-packs": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/lighthouse-stack-packs/-/lighthouse-stack-packs-1.11.0.tgz", - "integrity": "sha512-sRr0z1S/I26VffRLq9KJsKtLk856YrJlNGmcJmbLX8dFn3MuzVPUbstuChEhqnSxZb8TZmVfthuXuwhG9vRoSw==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/lighthouse/node_modules/axe-core": { - "version": "4.7.2", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.7.2.tgz", - "integrity": "sha512-zIURGIS1E1Q4pcrMjp+nnEh+16G56eG/MUllJH8yEvw7asDo7Ac9uhC9KIH5jzpITueEZolfYglnCGIuSBz39g==", - "dev": true, - "license": "MPL-2.0", - "engines": { - "node": ">=4" - } - }, - "node_modules/lighthouse/node_modules/cross-fetch": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", - "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", - "dev": true, - "license": "MIT", - "dependencies": { - "node-fetch": "^2.6.12" - } - }, - "node_modules/lighthouse/node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "dev": true, - "license": "MIT", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" + "open": "^8.4.0", + "parse-cache-control": "1.0.1", + "puppeteer-core": "^23.8.0", + "robots-parser": "^3.0.1", + "semver": "^5.3.0", + "speedline-core": "^1.4.3", + "third-party-web": "^0.26.1", + "tldts-icann": "^6.1.16", + "ws": "^7.0.0", + "yargs": "^17.3.1", + "yargs-parser": "^21.0.0" }, - "peerDependencies": { - "encoding": "^0.1.0" + "bin": { + "chrome-debug": "core/scripts/manual-chrome-launcher.js", + "lighthouse": "cli/index.js", + "smokehouse": "cli/test/smokehouse/frontends/smokehouse-bin.js" }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } + "engines": { + "node": ">=18.16" } }, - "node_modules/lighthouse/node_modules/puppeteer-core": { - "version": "20.9.0", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.9.0.tgz", - "integrity": "sha512-H9fYZQzMTRrkboEfPmf7m3CLDN6JvbxXA3qTtS+dFt27tR+CsFHzPsT6pzp6lYL6bJbAPaR0HaPO6uSi+F94Pg==", + "node_modules/lighthouse-logger": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-2.0.1.tgz", + "integrity": "sha512-ioBrW3s2i97noEmnXxmUq7cjIcVRjT5HBpAYy8zE11CxU9HqlWHHeRxfeN1tn8F7OEMVPIC9x1f8t3Z7US9ehQ==", "dev": true, - "license": "Apache-2.0", "dependencies": { - "@puppeteer/browsers": "1.4.6", - "chromium-bidi": "0.4.16", - "cross-fetch": "4.0.0", - "debug": "4.3.4", - "devtools-protocol": "0.0.1147663", - "ws": "8.13.0" - }, - "engines": { - "node": ">=16.3.0" - }, - "peerDependencies": { - "typescript": ">= 4.7.4" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "debug": "^2.6.9", + "marky": "^1.2.2" } }, - "node_modules/lighthouse/node_modules/puppeteer-core/node_modules/chromium-bidi": { - "version": "0.4.16", - "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.16.tgz", - "integrity": "sha512-7ZbXdWERxRxSwo3txsBjjmc/NLxqb1Bk30mRb0BMS4YIaiV6zvKZqL/UAH+DdqcDYayDWk2n/y8klkBDODrPvA==", + "node_modules/lighthouse-logger/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "license": "Apache-2.0", "dependencies": { - "mitt": "3.0.0" - }, - "peerDependencies": { - "devtools-protocol": "*" + "ms": "2.0.0" } }, - "node_modules/lighthouse/node_modules/puppeteer-core/node_modules/devtools-protocol": { - "version": "0.0.1147663", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1147663.tgz", - "integrity": "sha512-hyWmRrexdhbZ1tcJUGpO95ivbRhWXz++F4Ko+n21AY5PNln2ovoJw+8ZMNDTtip+CNFQfrtLVh/w4009dXO/eQ==", - "dev": true, - "license": "BSD-3-Clause" + "node_modules/lighthouse-logger/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true }, - "node_modules/lighthouse/node_modules/puppeteer-core/node_modules/ws": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", - "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } + "node_modules/lighthouse-stack-packs": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/lighthouse-stack-packs/-/lighthouse-stack-packs-1.12.2.tgz", + "integrity": "sha512-Ug8feS/A+92TMTCK6yHYLwaFMuelK/hAKRMdldYkMNwv+d9PtWxjXEg6rwKtsUXTADajhdrhXyuNCJ5/sfmPFw==", + "dev": true }, "node_modules/lighthouse/node_modules/semver": { "version": "5.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, - "license": "ISC", "bin": { "semver": "bin/semver" } }, - "node_modules/lighthouse/node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true, - "license": "MIT" - }, - "node_modules/lighthouse/node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true, - "license": "BSD-2-Clause" - }, - "node_modules/lighthouse/node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dev": true, - "license": "MIT", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, "node_modules/lighthouse/node_modules/ws": { "version": "7.5.10", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=8.3.0" }, @@ -14886,6 +14528,15 @@ "node": ">=8.9.0" } }, + "node_modules/localforage": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/localforage/-/localforage-1.10.0.tgz", + "integrity": "sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==", + "dev": true, + "dependencies": { + "lie": "3.1.1" + } + }, "node_modules/locate-path": { "version": "6.0.0", "dev": true, @@ -14905,6 +14556,12 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", + "dev": true + }, "node_modules/lodash.debounce": { "version": "4.0.8", "dev": true, @@ -15024,8 +14681,7 @@ "version": "6.2.0", "resolved": "https://registry.npmjs.org/lookup-closest-locale/-/lookup-closest-locale-6.2.0.tgz", "integrity": "sha512-/c2kL+Vnp1jnV6K6RpDTHK3dgg0Tu2VVp+elEiJpjfS1UyY7AjOYHohRug6wT0OpoX2qFgNORndE9RqesfVxWQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/loose-envify": { "version": "1.4.0", @@ -15052,13 +14708,6 @@ "node": ">=8" } }, - "node_modules/lru_map": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz", - "integrity": "sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==", - "dev": true, - "license": "MIT" - }, "node_modules/lru-cache": { "version": "5.1.1", "dev": true, @@ -15069,8 +14718,9 @@ }, "node_modules/make-dir": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", "dev": true, - "license": "MIT", "dependencies": { "semver": "^6.0.0" }, @@ -15252,8 +14902,7 @@ "version": "1.2.5", "resolved": "https://registry.npmjs.org/marky/-/marky-1.2.5.tgz", "integrity": "sha512-q9JtQJKjpsVxCRVgQ+WapguSbKC3SQ5HEzFGPAJMStgh3QjCawp00UKv3MTTAArTmGmmPUvllHZoNbZ3gs0I+Q==", - "dev": true, - "license": "Apache-2.0" + "dev": true }, "node_modules/mathml-tag-names": { "version": "2.1.3", @@ -15278,8 +14927,9 @@ }, "node_modules/media-typer": { "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -15295,13 +14945,6 @@ "node": ">= 4.0.0" } }, - "node_modules/memize": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/memize/-/memize-2.1.0.tgz", - "integrity": "sha512-yywVJy8ctVlN5lNPxsep5urnZ6TTclwPEyigM9M3Bi8vseJBOfqNrGWN/r8NzuIt3PovM323W04blJfGQfQSVg==", - "dev": true, - "license": "MIT" - }, "node_modules/meow": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/meow/-/meow-9.0.0.tgz", @@ -15366,9 +15009,13 @@ } }, "node_modules/merge-descriptors": { - "version": "1.0.1", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", "dev": true, - "license": "MIT" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/merge-stream": { "version": "2.0.0", @@ -15387,8 +15034,7 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/metaviewport-parser/-/metaviewport-parser-0.3.0.tgz", "integrity": "sha512-EoYJ8xfjQ6kpe9VbVHvZTZHiOl4HL1Z18CrZ+qahvLXT7ZO4YTC2JMyt5FaUp9JJp6J4Ybb/z7IsCXZt86/QkQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/methods": { "version": "1.1.2", @@ -15615,13 +15261,6 @@ "node": ">=0.10.0" } }, - "node_modules/mitt": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.0.tgz", - "integrity": "sha512-7dX2/10ITVyqh4aOSVI9gdape+t9l2/8QxHrFmUXu4EEUpdlxl6RudZUPZoc+zuY2hk1j7XxVroIVIan/pD/SQ==", - "dev": true, - "license": "MIT" - }, "node_modules/mixin-object": { "version": "2.0.1", "dev": true, @@ -15653,11 +15292,6 @@ "mkdirp": "bin/cmd.js" } }, - "node_modules/mkdirp-classic": { - "version": "0.5.3", - "dev": true, - "license": "MIT" - }, "node_modules/mocha": { "version": "10.3.0", "dev": true, @@ -16527,8 +16161,9 @@ }, "node_modules/on-finished": { "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "dev": true, - "license": "MIT", "dependencies": { "ee-first": "1.1.1" }, @@ -16996,9 +16631,10 @@ "license": "MIT" }, "node_modules/path-to-regexp": { - "version": "0.1.7", - "dev": true, - "license": "MIT" + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "dev": true }, "node_modules/path-type": { "version": "4.0.0", @@ -17978,102 +17614,11 @@ "node": ">= 0.10" } }, - "node_modules/proxy-agent": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.3.0.tgz", - "integrity": "sha512-0LdR757eTj/JfuU7TL2YCuAZnxWXu3tkJbg4Oq3geW/qFNT/32T0sp2HnZ9O0lMR4q3vwAt0+xCA8SR0WAD0og==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.0.2", - "debug": "^4.3.4", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.0", - "lru-cache": "^7.14.1", - "pac-proxy-agent": "^7.0.0", - "proxy-from-env": "^1.1.0", - "socks-proxy-agent": "^8.0.1" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/proxy-agent/node_modules/agent-base": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", - "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/proxy-agent/node_modules/http-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", - "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/proxy-agent/node_modules/https-proxy-agent": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", - "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.0.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/proxy-agent/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/proxy-agent/node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "dev": true, - "license": "MIT" - }, "node_modules/proxy-from-env": { "version": "1.0.0", "dev": true, "license": "MIT" }, - "node_modules/ps-list": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/ps-list/-/ps-list-8.1.1.tgz", - "integrity": "sha512-OPS9kEJYVmiO48u/B9qneqhkMvgCxT+Tm28VCEJpheTpl8cJ0ffZRRNgS5mrQRTrX5yRTpaJ+hRDeefXYmmorQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/pseudomap": { "version": "1.0.2", "dev": true, @@ -18378,8 +17923,9 @@ }, "node_modules/raw-body": { "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "dev": true, - "license": "MIT", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -18392,16 +17938,18 @@ }, "node_modules/raw-body/node_modules/bytes": { "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/raw-body/node_modules/iconv-lite": { "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, - "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -18775,13 +18323,6 @@ "jsesc": "bin/jsesc" } }, - "node_modules/remove-accents": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/remove-accents/-/remove-accents-0.5.0.tgz", - "integrity": "sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A==", - "dev": true, - "license": "MIT" - }, "node_modules/request-progress": { "version": "3.0.0", "dev": true, @@ -18975,7 +18516,6 @@ "resolved": "https://registry.npmjs.org/robots-parser/-/robots-parser-3.0.1.tgz", "integrity": "sha512-s+pyvQeIKIZ0dx5iJiQk1tPLJAWln39+MI5jtM8wnyws+G5azk+dMnMX0qfbqNetKKNgcWWOdi0sfm+FbQbgdQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=10.0.0" } @@ -19269,9 +18809,10 @@ } }, "node_modules/send": { - "version": "0.18.0", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "dev": true, - "license": "MIT", "dependencies": { "debug": "2.6.9", "depd": "2.0.0", @@ -19293,21 +18834,33 @@ }, "node_modules/send/node_modules/debug": { "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "license": "MIT", "dependencies": { "ms": "2.0.0" } }, "node_modules/send/node_modules/debug/node_modules/ms": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", "dev": true, - "license": "MIT" + "engines": { + "node": ">= 0.8" + } }, "node_modules/send/node_modules/mime": { "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "dev": true, - "license": "MIT", "bin": { "mime": "cli.js" }, @@ -19317,8 +18870,9 @@ }, "node_modules/send/node_modules/ms": { "version": "2.1.3", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true }, "node_modules/sentence-case": { "version": "3.0.4", @@ -19410,14 +18964,15 @@ } }, "node_modules/serve-static": { - "version": "1.15.0", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "dev": true, - "license": "MIT", "dependencies": { - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.18.0" + "send": "0.19.0" }, "engines": { "node": ">= 0.8.0" @@ -19462,8 +19017,9 @@ }, "node_modules/setprototypeof": { "version": "1.2.0", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true }, "node_modules/shallow-clone": { "version": "0.1.2", @@ -19859,7 +19415,6 @@ "resolved": "https://registry.npmjs.org/speedline-core/-/speedline-core-1.4.3.tgz", "integrity": "sha512-DI7/OuAUD+GMpR6dmu8lliO2Wg5zfeh+/xsdyJZCzd8o5JgFUjCeLsBDuZjIQJdwXS3J0L/uZYrELKYqx+PXog==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*", "image-ssim": "^0.2.0", @@ -19928,8 +19483,9 @@ }, "node_modules/statuses": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -20609,16 +20165,6 @@ "dev": true, "license": "BSD-2-Clause" }, - "node_modules/tannin": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/tannin/-/tannin-1.2.0.tgz", - "integrity": "sha512-U7GgX/RcSeUETbV7gYgoz8PD7Ni4y95pgIP/Z6ayI3CfhSujwKEBlGFTCRN+Aqnuyf4AN2yHL+L8x+TCGjb9uA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@tannin/plural-forms": "^1.1.0" - } - }, "node_modules/tapable": { "version": "2.2.1", "dev": true, @@ -20836,11 +20382,10 @@ "license": "MIT" }, "node_modules/third-party-web": { - "version": "0.23.4", - "resolved": "https://registry.npmjs.org/third-party-web/-/third-party-web-0.23.4.tgz", - "integrity": "sha512-kwYnSZRhEvv0SBW2fp8SBBKRglMoBjV8xz6C31m0ewqOtknB5UL+Ihg+M81hyFY5ldkZuGWPb+e4GVDkzf/gYg==", - "dev": true, - "license": "MIT" + "version": "0.26.2", + "resolved": "https://registry.npmjs.org/third-party-web/-/third-party-web-0.26.2.tgz", + "integrity": "sha512-taJ0Us0lKoYBqcbccMuDElSUPOxmBfwlHe1OkHQ3KFf+RwovvBHdXhbFk9XJVQE2vHzxbTwvwg5GFsT9hbDokQ==", + "dev": true }, "node_modules/throttleit": { "version": "1.0.1", @@ -20867,6 +20412,21 @@ "@popperjs/core": "^2.9.0" } }, + "node_modules/tldts-core": { + "version": "6.1.67", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.67.tgz", + "integrity": "sha512-12K5O4m3uUW6YM5v45Z7wc6NTSmAYj4Tq3de7eXghZkp879IlfPJrUWeWFwu1FS94U5t2vwETgJ1asu8UGNKVQ==", + "dev": true + }, + "node_modules/tldts-icann": { + "version": "6.1.67", + "resolved": "https://registry.npmjs.org/tldts-icann/-/tldts-icann-6.1.67.tgz", + "integrity": "sha512-CJLFTYBgbnkP6nB8rqSYzd1oyWbM02SeQx9hrEpB6fTjx2+5FJ1lSkovxIWCjMgvzE7Nv54LCrf3lVW0zhupxQ==", + "dev": true, + "dependencies": { + "tldts-core": "^6.1.67" + } + }, "node_modules/tmp": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", @@ -20897,8 +20457,9 @@ }, "node_modules/toidentifier": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.6" } @@ -21116,8 +20677,9 @@ }, "node_modules/type-is": { "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", "dev": true, - "license": "MIT", "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" @@ -21219,7 +20781,6 @@ "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", "dev": true, - "license": "MIT", "dependencies": { "is-typedarray": "^1.0.0" } @@ -21318,7 +20879,6 @@ "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", "dev": true, - "license": "MIT", "dependencies": { "crypto-random-string": "^2.0.0" }, @@ -21336,8 +20896,9 @@ }, "node_modules/unpipe": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -21643,11 +21204,10 @@ } }, "node_modules/web-vitals": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-3.5.2.tgz", - "integrity": "sha512-c0rhqNcHXRkY/ogGDJQxZ9Im9D19hDihbzSQJrsioex+KnFgmMzBiy57Z1EjkhX/+OjyBpclDCzz2ITtjokFmg==", - "dev": true, - "license": "Apache-2.0" + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-4.2.4.tgz", + "integrity": "sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==", + "dev": true }, "node_modules/webidl-conversions": { "version": "7.0.0", @@ -22342,7 +21902,6 @@ "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } diff --git a/src/js/settings/components/feature-additional-settings/content-resizing.js b/src/js/settings/components/feature-additional-settings/content-resizing.js index a312112ab..51d1a9610 100644 --- a/src/js/settings/components/feature-additional-settings/content-resizing.js +++ b/src/js/settings/components/feature-additional-settings/content-resizing.js @@ -33,7 +33,7 @@ export const ContentResizingSettings = () => { > { + setPrompts={ ( prompts ) => { setFeatureSettings( { condense_text_prompt: prompts, } ); @@ -47,7 +47,7 @@ export const ContentResizingSettings = () => { > { + setPrompts={ ( prompts ) => { setFeatureSettings( { expand_text_prompt: prompts, } ); diff --git a/src/js/settings/components/feature-additional-settings/excerpt-generation.js b/src/js/settings/components/feature-additional-settings/excerpt-generation.js index 9d21ddf12..26ae9254f 100644 --- a/src/js/settings/components/feature-additional-settings/excerpt-generation.js +++ b/src/js/settings/components/feature-additional-settings/excerpt-generation.js @@ -28,7 +28,7 @@ export const ExcerptGenerationSettings = () => { ); const { excerptPostTypes } = window.classifAISettings; const { setFeatureSettings } = useDispatch( STORE_NAME ); - const setPromts = ( prompts ) => { + const setPrompts = ( prompts ) => { setFeatureSettings( { generate_excerpt_prompt: prompts, } ); @@ -45,7 +45,7 @@ export const ExcerptGenerationSettings = () => { > { const [ showConfirmDialog, setShowConfirmDialog ] = useState( false ); const [ activeIndex, setActiveIndex ] = useState( null ); - const { prompts = [], setPromts } = props; + const { prompts = [], setPrompts } = props; const placeholder = prompts?.filter( ( prompt ) => prompt.original )[ 0 ]?.prompt || ''; // Add a new prompt. const addPrompt = () => { - setPromts( [ + setPrompts( [ ...prompts, { default: 0, original: 0, prompt: '', title: '' }, ] ); @@ -42,7 +42,7 @@ export const PromptRepeater = ( props ) => { if ( prompt[ 0 ]?.default ) { prompts[ 0 ].default = 1; } - setPromts( [ ...prompts ] ); + setPrompts( [ ...prompts ] ); }; // Update prompt. @@ -60,7 +60,7 @@ export const PromptRepeater = ( props ) => { ...prompts[ index ], ...changes, }; - setPromts( [ ...prompts ] ); + setPrompts( [ ...prompts ] ); }; // Confirm dialog to remove prompt. diff --git a/src/js/settings/components/feature-additional-settings/title-generation.js b/src/js/settings/components/feature-additional-settings/title-generation.js index e696434e3..dc279bc73 100644 --- a/src/js/settings/components/feature-additional-settings/title-generation.js +++ b/src/js/settings/components/feature-additional-settings/title-generation.js @@ -23,7 +23,7 @@ export const TitleGenerationSettings = () => { select( STORE_NAME ).getFeatureSettings() ); const { setFeatureSettings } = useDispatch( STORE_NAME ); - const setPromts = ( prompts ) => { + const setPrompts = ( prompts ) => { setFeatureSettings( { generate_title_prompt: prompts, } ); @@ -39,7 +39,7 @@ export const TitleGenerationSettings = () => { > ); diff --git a/src/js/settings/components/provider-settings/azure-ai-vision.js b/src/js/settings/components/provider-settings/azure-ai-vision.js index f34a27e21..77957d154 100644 --- a/src/js/settings/components/provider-settings/azure-ai-vision.js +++ b/src/js/settings/components/provider-settings/azure-ai-vision.js @@ -78,7 +78,7 @@ export const AzureAIVisionSettings = ( { isConfigured = false } ) => { @@ -87,7 +87,7 @@ export const AzureAIVisionSettings = ( { isConfigured = false } ) => { type="number" value={ providerSettings.descriptive_confidence_threshold || - 55 + 70 } onChange={ ( value ) => onChange( { diff --git a/src/js/settings/components/provider-settings/openai-chatgpt.js b/src/js/settings/components/provider-settings/openai-chatgpt.js index 12cf8191b..e4de4faa8 100644 --- a/src/js/settings/components/provider-settings/openai-chatgpt.js +++ b/src/js/settings/components/provider-settings/openai-chatgpt.js @@ -12,6 +12,7 @@ import { __ } from '@wordpress/i18n'; import { SettingsRow } from '../settings-row'; import { STORE_NAME } from '../../data/store'; import { useFeatureContext } from '../feature-settings/context'; +import { PromptRepeater } from '../feature-additional-settings/prompt-repeater'; /** * Component for OpenAI ChatGPT Provider settings. @@ -32,6 +33,11 @@ export const OpenAIChatGPTSettings = ( { isConfigured = false } ) => { ); const { setProviderSettings } = useDispatch( STORE_NAME ); const onChange = ( data ) => setProviderSettings( providerName, data ); + const setPrompts = ( prompts ) => { + setProviderSettings( providerName, { + prompt: prompts, + } ); + }; const Description = () => ( <> @@ -45,6 +51,23 @@ export const OpenAIChatGPTSettings = ( { isConfigured = false } ) => { { __( 'in order to get your API key.', 'classifai' ) } ); + const promptExamples = ( + <> + { __( 'Add a custom prompt, if desired. ', 'classifai' ) } + { __( 'See our ', 'classifai' ) } + + { __( 'documentation', 'classifai' ) } + + { __( + ' for some example prompts you can try that have been tested for specific use cases.', + 'classifai' + ) } + + ); return ( <> @@ -82,6 +105,19 @@ export const OpenAIChatGPTSettings = ( { isConfigured = false } ) => { /> ) } + { [ 'feature_descriptive_text_generator' ].includes( + featureName + ) && ( + + + + ) } ); }; diff --git a/tests/Classifai/Azure/ComputerVisionTest.php b/tests/Classifai/Azure/ComputerVisionTest.php index 1abb424e1..ed32d9398 100644 --- a/tests/Classifai/Azure/ComputerVisionTest.php +++ b/tests/Classifai/Azure/ComputerVisionTest.php @@ -42,7 +42,7 @@ public function test_get_debug_information() { $this->assertEquals( [ 'Generate descriptive text' => '0, 0, 0', - 'Confidence threshold' => 55, + 'Confidence threshold' => 70, 'Latest response:' => 'N/A', ], $this->provider->get_debug_information( diff --git a/tests/Classifai/Providers/Azure/ComputerVisionTest.php b/tests/Classifai/Providers/Azure/ComputerVisionTest.php index e20a2e9c9..d08eba908 100644 --- a/tests/Classifai/Providers/Azure/ComputerVisionTest.php +++ b/tests/Classifai/Providers/Azure/ComputerVisionTest.php @@ -60,40 +60,6 @@ public function test_smart_crop_image() { remove_filter( 'classifai_should_smart_crop_image', '__return_true' ); } - /** - * Ensure that settings returns default settings array if the `classifai_computer_vision` is not set. - */ - public function test_no_computer_vision_option_set() { - delete_option( 'classifai_computer_vision' ); - - $defaults = []; - - $expected = array_merge( - $defaults, - [ - 'status' => '0', - 'roles' => [], - 'users' => [], - 'user_based_opt_out' => 'no', - 'descriptive_text_fields' => [ - 'alt' => 'alt', - 'caption' => 0, - 'description' => 0, - ], - 'provider' => 'ms_computer_vision', - 'ms_computer_vision' => [ - 'endpoint_url' => '', - 'api_key' => '', - 'authenticated' => false, - 'descriptive_confidence_threshold' => 55, - ], - ] - ); - $settings = ( new \Classifai\Features\DescriptiveTextGenerator() )->get_settings(); - - $this->assertSame( $expected, $settings ); - } - /** * Ensure that attachment meta is being set. */ diff --git a/tests/cypress/integration/image-processing/image-processing-openai-chatgpt.test.js b/tests/cypress/integration/image-processing/image-processing-openai-chatgpt.test.js new file mode 100644 index 000000000..10b560105 --- /dev/null +++ b/tests/cypress/integration/image-processing/image-processing-openai-chatgpt.test.js @@ -0,0 +1,235 @@ +import { getChatGPTData } from '../../plugins/functions'; + +describe( 'OpenAI Image Processing Tests', () => { + let imageEditLink = ''; + let mediaModelLink = ''; + + before( () => { + cy.login(); + + const imageProcessingFeatures = [ + 'feature_descriptive_text_generator', + ]; + + imageProcessingFeatures.forEach( ( feature ) => { + cy.visitFeatureSettings( `image_processing/${ feature }` ); + cy.enableFeature(); + cy.selectProvider( 'openai_chatgpt' ); + cy.get( '#openai_chatgpt_api_key' ).clear().type( 'password' ); + cy.allowFeatureToAdmin(); + cy.get( '.classifai-settings__user-based-opt-out input' ).uncheck(); + + // Disable access for all users. + cy.disableFeatureForUsers(); + + cy.saveFeatureSettings(); + } ); + + cy.optInAllFeatures(); + } ); + + beforeEach( () => { + cy.login(); + } ); + + it( 'Can see Image Processing actions on edit media page and verify generated data.', () => { + cy.visitFeatureSettings( + 'image_processing/feature_descriptive_text_generator' + ); + cy.get( '.classifai-descriptive-text-fields input#alt' ).check(); + cy.saveFeatureSettings(); + cy.visit( '/wp-admin/upload.php?mode=grid' ); // Ensure grid mode is enabled. + cy.visit( '/wp-admin/media-new.php' ); + cy.get( '#plupload-upload-ui' ).should( 'exist' ); + cy.get( '#plupload-upload-ui input[type=file]' ).attachFile( + '../../../assets/img/onboarding-1.png' + ); + + cy.get( '#media-items .media-item a.edit-attachment', { + timeout: 20000, + } ).should( 'exist' ); + cy.get( '#media-items .media-item a.edit-attachment' ) + .invoke( 'attr', 'href' ) + .then( ( editLink ) => { + imageEditLink = editLink; + cy.visit( editLink ); + } ); + + // Verify Metabox with Image processing actions. + cy.get( '.postbox-header h2, #classifai_image_processing h2' ) + .first() + .contains( 'ClassifAI Image Processing' ); + cy.get( + '#classifai_image_processing label[for=rescan-captions]' + ).contains( 'No descriptive text? Rescan image' ); + + // Verify generated Data. + const imageData = getChatGPTData(); + cy.get( '#attachment_alt' ).should( 'have.value', imageData ); + } ); + + it( 'Can see Image Processing actions on media modal', () => { + const imageId = imageEditLink.split( 'post=' )[ 1 ]?.split( '&' )[ 0 ]; + mediaModelLink = `wp-admin/upload.php?item=${ imageId }`; + cy.visit( mediaModelLink ); + cy.get( '.media-modal' ).should( 'exist' ); + + // Verify Image processing actions. + cy.get( '#classifai-rescan-alt-tags' ).contains( 'Rescan' ); + } ); + + it( 'Can disable Image Processing features', () => { + const options = { + imageEditLink, + mediaModelLink, + }; + + // Disable features + cy.visitFeatureSettings( + 'image_processing/feature_descriptive_text_generator' + ); + cy.wait( 1000 ); + cy.get( '.classifai-descriptive-text-fields input#alt' ).uncheck(); + cy.get( '.classifai-descriptive-text-fields input#caption' ).uncheck(); + cy.get( + '.classifai-descriptive-text-fields input#description' + ).uncheck(); + cy.saveFeatureSettings(); + + // Verify that the feature is not available. + cy.wait( 1000 ); + cy.visit( options.imageEditLink ); + cy.get( + '#classifai_image_processing label[for=rescan-captions]' + ).should( 'not.exist' ); + cy.visit( options.mediaModelLink ); + cy.get( '.media-modal' ).should( 'exist' ); + cy.get( '#classifai-rescan-alt-tags' ).should( 'not.exist' ); + + // Enable features. + cy.visitFeatureSettings( + 'image_processing/feature_descriptive_text_generator' + ); + cy.get( '.classifai-descriptive-text-fields input#alt' ).check(); + cy.get( '.classifai-descriptive-text-fields input#caption' ).check(); + cy.get( + '.classifai-descriptive-text-fields input#description' + ).check(); + cy.wait( 1500 ); + cy.enableFeature(); + cy.saveFeatureSettings(); + + // Verify that the feature is available. + cy.wait( 1000 ); + cy.visit( options.imageEditLink ); + cy.get( + '#classifai_image_processing label[for=rescan-captions]' + ).should( 'exist' ); + cy.visit( options.mediaModelLink ); + cy.get( '.media-modal' ).should( 'exist' ); + cy.get( '#classifai-rescan-alt-tags' ).should( 'exist' ); + } ); + + it( 'Can enable/disable Image Processing features by roles', () => { + const options = { + imageEditLink, + mediaModelLink, + }; + + // Enable features. + cy.visitFeatureSettings( + 'image_processing/feature_descriptive_text_generator' + ); + cy.enableFeature(); + cy.get( '.classifai-descriptive-text-fields input#alt' ).check(); + cy.wait( 500 ); + cy.saveFeatureSettings(); + + // Disable access to admin role. + cy.disableFeatureForRoles( 'feature_descriptive_text_generator', [ + 'administrator', + ] ); + + // Verify that the feature is not available. + cy.wait( 1000 ); + cy.visit( options.imageEditLink ); + cy.get( + '#classifai_image_processing label[for=rescan-captions]' + ).should( 'not.exist' ); + cy.visit( options.mediaModelLink ); + cy.get( '.media-modal' ).should( 'exist' ); + cy.get( '#classifai-rescan-alt-tags' ).should( 'not.exist' ); + } ); + + it( 'Can enable/disable Image Processing features by user', () => { + const options = { + imageEditLink, + mediaModelLink, + }; + + // Disable access to admin role. + cy.disableFeatureForRoles( 'feature_descriptive_text_generator', [ + 'administrator', + ] ); + + // Verify that the feature is not available. + cy.wait( 1000 ); + cy.visit( options.imageEditLink ); + cy.get( + '#classifai_image_processing label[for=rescan-captions]' + ).should( 'not.exist' ); + cy.visit( options.mediaModelLink ); + cy.get( '.media-modal' ).should( 'exist' ); + cy.get( '#classifai-rescan-alt-tags' ).should( 'not.exist' ); + + cy.enableFeatureForUsers( 'feature_descriptive_text_generator', [ + 'admin', + ] ); + + // Verify that the feature is available. + cy.wait( 1000 ); + cy.visit( options.imageEditLink ); + cy.get( + '#classifai_image_processing label[for=rescan-captions]' + ).should( 'exist' ); + cy.visit( options.mediaModelLink ); + cy.get( '.media-modal' ).should( 'exist' ); + cy.get( '#classifai-rescan-alt-tags' ).should( 'exist' ); + } ); + + it( 'User can opt-out of Image Processing features', () => { + const options = { + imageEditLink, + mediaModelLink, + }; + + // Enable user based opt-out. + cy.enableFeatureOptOut( 'feature_descriptive_text_generator' ); + + // opt-out + cy.optOutFeature( 'feature_descriptive_text_generator' ); + + // Verify that the feature is not available. + cy.wait( 1000 ); + cy.visit( options.imageEditLink ); + cy.get( + '#classifai_image_processing label[for=rescan-captions]' + ).should( 'not.exist' ); + cy.visit( options.mediaModelLink ); + cy.get( '.media-modal' ).should( 'exist' ); + cy.get( '#classifai-rescan-alt-tags' ).should( 'not.exist' ); + + // opt-in + cy.optInFeature( 'feature_descriptive_text_generator' ); + + // Verify that the feature is available. + cy.wait( 1000 ); + cy.visit( options.imageEditLink ); + cy.get( + '#classifai_image_processing label[for=rescan-captions]' + ).should( 'exist' ); + cy.visit( options.mediaModelLink ); + cy.get( '.media-modal' ).should( 'exist' ); + cy.get( '#classifai-rescan-alt-tags' ).should( 'exist' ); + } ); +} ); diff --git a/tests/cypress/plugins/functions.js b/tests/cypress/plugins/functions.js index 014016904..fbb9d8fa3 100644 --- a/tests/cypress/plugins/functions.js +++ b/tests/cypress/plugins/functions.js @@ -3,7 +3,6 @@ import * as chatgptData from '../../test-plugin/chatgpt.json'; import * as chatgptCustomExcerptData from '../../test-plugin/chatgpt-custom-excerpt-prompt.json'; import * as chatgptCustomTitleData from '../../test-plugin/chatgpt-custom-title-prompt.json'; import * as dalleData from '../../test-plugin/dalle.json'; -import * as ocrData from '../../test-plugin/ocr.json'; import * as whisperData from '../../test-plugin/whisper.json'; import * as imageData from '../../test-plugin/image_analyze.json'; import * as pdfData from '../../test-plugin/pdf.json'; @@ -99,7 +98,7 @@ export const getWhisperData = () => { */ export const getOCRData = () => { const words = []; - ocrData.regions.forEach( ( el ) => { + imageData.readResult.blocks.forEach( ( el ) => { el.lines.forEach( ( el2 ) => { el2.words.forEach( ( el3 ) => { words.push( el3.text ); @@ -116,10 +115,8 @@ export const getOCRData = () => { */ export const getImageData = () => { const data = { - altText: imageData.description.captions.filter( - ( el ) => el.confidence > 0.75 - )[ 0 ].text, - tags: imageData.tags + altText: imageData.captionResult.text, + tags: imageData.tagsResult.values .filter( ( el ) => el.confidence > 0.7 ) .map( ( el ) => el.name ), }; diff --git a/tests/test-plugin/e2e-test-plugin.php b/tests/test-plugin/e2e-test-plugin.php index 6753215d3..3659f1ffd 100644 --- a/tests/test-plugin/e2e-test-plugin.php +++ b/tests/test-plugin/e2e-test-plugin.php @@ -80,10 +80,8 @@ function classifai_test_mock_http_requests( $preempt, $parsed_args, $url ) { strpos( $url, 'https://e2e-test-azure-openai-embeddings.test/openai/deployments' ) !== false ) { $response = file_get_contents( __DIR__ . '/embeddings.json' ); - } elseif ( strpos( $url, 'http://e2e-test-image-processing.test/vision/v3.2/analyze' ) !== false ) { + } elseif ( strpos( $url, 'http://e2e-test-image-processing.test/computervision/imageanalysis:analyze?api-version=2024-02-01' ) !== false ) { $response = file_get_contents( __DIR__ . '/image_analyze.json' ); - } elseif ( strpos( $url, 'http://e2e-test-image-processing.test/vision/v3.2/ocr' ) !== false ) { - $response = file_get_contents( __DIR__ . '/ocr.json' ); } elseif ( strpos( $url, 'http://e2e-test-image-processing.test/vision/v3.2/generateThumbnail' ) !== false ) { $response = file_get_contents( __DIR__ . '../classifai/assets/img/icon256x256.png' ); } elseif ( strpos( $url, 'http://e2e-test-image-processing.test/pdf-read-result' ) !== false ) { diff --git a/tests/test-plugin/image_analyze.json b/tests/test-plugin/image_analyze.json index 5e0e58943..d2dbcb351 100644 --- a/tests/test-plugin/image_analyze.json +++ b/tests/test-plugin/image_analyze.json @@ -1,81 +1,173 @@ { - "tags": [ - { - "name": "text", - "confidence": 0.9854570031166077 - }, - { - "name": "design", - "confidence": 0.9676092863082886 - }, - { - "name": "screenshot", - "confidence": 0.9044408798217773 - }, - { - "name": "graphic", - "confidence": 0.8791931867599487 - }, - { - "name": "red", - "confidence": 0.8448371887207031 - }, - { - "name": "font", - "confidence": 0.8189171552658081 - }, - { - "name": "graphics", - "confidence": 0.7044017314910889 - }, - { - "name": "logo", - "confidence": 0.6639798283576965 - }, - { - "name": "typography", - "confidence": 0.6407877802848816 - }, - { - "name": "maroon", - "confidence": 0.6387392282485962 - }, - { - "name": "illustration", - "confidence": 0.6350329518318176 - }, - { - "name": "carmine", - "confidence": 0.6345877647399902 - }, - { - "name": "abstract", - "confidence": 0.624541163444519 - }, - { - "name": "vector graphics", - "confidence": 0.21607014536857605 - }, - { - "name": "clipart", - "confidence": 0.20682862401008606 - } - ], - "description": { - "tags": [ - "text" - ], - "captions": [ - { - "text": "text", - "confidence": 0.8448402285575867 + "modelVersion": "2023-10-01", + "metadata": { + "height": 250, + "width": 772 + }, + "tagsResult": { + "values": [ + { + "name": "text", + "confidence": 0.9854570031166077 + }, + { + "name": "design", + "confidence": 0.9676092863082886 + }, + { + "name": "screenshot", + "confidence": 0.9044408798217773 + }, + { + "name": "graphic", + "confidence": 0.8791931867599487 + }, + { + "name": "red", + "confidence": 0.8448371887207031 + }, + { + "name": "font", + "confidence": 0.8189171552658081 + }, + { + "name": "graphics", + "confidence": 0.7044017314910889 + }, + { + "name": "logo", + "confidence": 0.6639798283576965 + }, + { + "name": "typography", + "confidence": 0.6407877802848816 + }, + { + "name": "maroon", + "confidence": 0.6387392282485962 + }, + { + "name": "illustration", + "confidence": 0.6350329518318176 + }, + { + "name": "carmine", + "confidence": 0.6345877647399902 + }, + { + "name": "abstract", + "confidence": 0.624541163444519 + }, + { + "name": "vector graphics", + "confidence": 0.21607014536857605 + }, + { + "name": "clipart", + "confidence": 0.20682862401008606 } ] }, - "requestId": "50fdeac0-9ef5-4e81-9e05-d392d15907ca", - "metadata": { - "height": 250, - "width": 772, - "format": "Png" + "captionResult": { + "text": "Text", + "confidence": 0.8448402285575867 + }, + "readResult": { + "blocks": [ + { + "lines": [ + { + "text": "CLASSIFAI_", + "boundingPolygon": [ + { + "x": 193, + "y": 337 + }, + { + "x": 614, + "y": 348 + }, + { + "x": 617, + "y": 507 + }, + { + "x": 187, + "y": 510 + } + ], + "words": [ + { + "text": "CLASSIFAI_", + "boundingPolygon": [ + { + "x": 188, + "y": 337 + }, + { + "x": 600, + "y": 341 + }, + { + "x": 599, + "y": 511 + }, + { + "x": 187, + "y": 510 + } + ], + "confidence": 0.991 + } + ] + }, + { + "text": "Test", + "boundingPolygon": [ + { + "x": 193, + "y": 337 + }, + { + "x": 614, + "y": 348 + }, + { + "x": 617, + "y": 507 + }, + { + "x": 187, + "y": 510 + } + ], + "words": [ + { + "text": "Test", + "boundingPolygon": [ + { + "x": 188, + "y": 337 + }, + { + "x": 600, + "y": 341 + }, + { + "x": 599, + "y": 511 + }, + { + "x": 187, + "y": 510 + } + ], + "confidence": 0.991 + } + ] + } + ] + } + ] } } diff --git a/tests/test-plugin/ocr.json b/tests/test-plugin/ocr.json deleted file mode 100644 index 1b98a7e05..000000000 --- a/tests/test-plugin/ocr.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "language": "en", - "textAngle": 0.0, - "orientation": "Up", - "regions": [ - { - "boundingBox": "319,188,904,146", - "lines": [ - { - "boundingBox": "319,188,899,59", - "words": [ - { - "boundingBox": "319,188,250,48", - "text": "ClassifAI" - }, - { - "boundingBox": "588,188,180,59", - "text": "Brings" - }, - { - "boundingBox": "783,191,56,44", - "text": "Al" - }, - { - "boundingBox": "856,190,104,46", - "text": "and" - }, - { - "boundingBox": "979,188,239,48", - "text": "Machine" - } - ] - }, - { - "boundingBox": "320,275,903,59", - "words": [ - { - "boundingBox": "320,275,245,59", - "text": "Learning" - }, - { - "boundingBox": "582,275,245,48", - "text": "Services" - }, - { - "boundingBox": "841,281,56,42", - "text": "to" - }, - { - "boundingBox": "912,277,311,46", - "text": "WordPress" - } - ] - } - ] - } - ], - "modelVersion": "2021-04-01" -}