Skip to content
This repository has been archived by the owner on Feb 23, 2024. It is now read-only.

Store Customization > Fetch product images from the Pexels API #11280

Merged
merged 79 commits into from
Oct 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
79 commits
Select commit Hold shift + click to select a range
178a022
Introduce the ProductUpdater class.
nefeline Oct 5, 2023
6df499c
Update the image assignment for the default products content.
nefeline Oct 5, 2023
a754030
Update the default products content.
nefeline Oct 5, 2023
d94eab8
Introduce the generate_content and get_placeholder_products methods.
nefeline Oct 5, 2023
884ad30
Merge branch 'trunk' into add/ai-generated-content-for-products
nefeline Oct 10, 2023
8adfc7f
Update the get_placeholder_products method and introduce the new crea…
nefeline Oct 10, 2023
aa753fb
Verify the hash of the product content and compare it with the hash o…
nefeline Oct 10, 2023
d0688db
Add docblocks and update the structure for the ProductUpdater class.
nefeline Oct 10, 2023
31d5942
Pass the vertical images as a param for the PatternUpdater and the Pr…
nefeline Oct 11, 2023
c6dae0b
Update the provided variable to the PatternUpdater class.
nefeline Oct 11, 2023
057fe93
Update the ProductUpdater class to include the requirements for usage…
nefeline Oct 11, 2023
35b0719
remove unnecessary calls to post/product images.
nefeline Oct 11, 2023
9659d40
Update the loop for generating products.
nefeline Oct 11, 2023
11f6eb7
Further adjustments to the Product Updater.
nefeline Oct 11, 2023
18e7b84
Provide the business_description as a param for the generate_content …
nefeline Oct 11, 2023
f18ebf5
Merge branch 'trunk' into add/ai-generated-content-for-products
nefeline Oct 11, 2023
8838406
Update the default timeout for the AI connection; update the path to …
nefeline Oct 11, 2023
656fb99
Add new neutral placeholder images for products and patterns.
nefeline Oct 13, 2023
7bed64e
Update the prompt and the logic for the placeholder images.
nefeline Oct 13, 2023
cd4fb68
Merge trunk and resolve conflicts.
nefeline Oct 17, 2023
e696300
Remove placeholder images.
nefeline Oct 17, 2023
18f39e4
Pass the AI connection as a param and update the get_images_for_patte…
nefeline Oct 17, 2023
0200da5
update the product updater class to rely on Pexels images and add the…
nefeline Oct 17, 2023
f97deb9
Remove the unused get_random_images method.
nefeline Oct 17, 2023
648b652
Update the patterns endpoint.
nefeline Oct 17, 2023
d5911b1
Delete unused ChatGPTClient class.
nefeline Oct 17, 2023
8a95163
Introduce the new Pexels class.
nefeline Oct 17, 2023
8e85e46
Remove the Verticals references.
nefeline Oct 17, 2023
121d731
Update the reference for the alt description for images.
nefeline Oct 17, 2023
09c22dc
Update the scheduled action to populate patterns and products.
nefeline Oct 17, 2023
a965f55
Remove unused Verticals classes.
nefeline Oct 17, 2023
b859709
Ensure the Pexels class already returns the array with the expected f…
nefeline Oct 18, 2023
d78f2ff
Introduce the select_image_src_based_on_format method.
nefeline Oct 18, 2023
38f3b42
Merge branch 'trunk' into add/ai-generated-content-for-products
nefeline Oct 18, 2023
a506ecc
Merge branch 'add/ai-generated-content-for-products' into update/repl…
nefeline Oct 18, 2023
4f331b8
Increase max execution time
nefeline Oct 19, 2023
fcd471d
Increase max execution time
nefeline Oct 19, 2023
9cea3a9
Update the request to rely on the WP.com external-media endpoint inst…
nefeline Oct 19, 2023
09df952
Merge branch 'trunk' into add/ai-generated-content-for-products
nefeline Oct 19, 2023
88ab322
Merge branch 'add/ai-generated-content-for-products' into update/repl…
nefeline Oct 19, 2023
e5bca84
Improve performance for product content update.
nefeline Oct 20, 2023
39cab0e
Improve quality of images used in products and update queries.
nefeline Oct 20, 2023
806bcf8
Update the products query.
nefeline Oct 20, 2023
88ea1d8
Move the media_sideload_image function dependencies to outside of the…
nefeline Oct 20, 2023
c334df4
Update text content.
nefeline Oct 20, 2023
d5a91c0
Merge base branch
nefeline Oct 20, 2023
a3b02d6
Merge add/ai-generated-content-for-products
nefeline Oct 20, 2023
12d67fa
Introduce the should_update_dummy_product method.
nefeline Oct 20, 2023
ee08f23
Update the method to be triggered on scheduled action to return true.
nefeline Oct 20, 2023
a5f3f1c
Change the image format for products to improve performance.
nefeline Oct 20, 2023
29b3ba1
Merge branch 'trunk' into add/ai-generated-content-for-products
nefeline Oct 20, 2023
61b3eb5
Merge branch 'add/ai-generated-content-for-products' into update/repl…
nefeline Oct 20, 2023
6a392d1
Merge branch 'trunk' into add/ai-generated-content-for-products
nefeline Oct 22, 2023
0918898
Merge branch 'add/ai-generated-content-for-products' into update/repl…
nefeline Oct 22, 2023
28b0f80
Make portrait the default fallback image format.
nefeline Oct 22, 2023
3da76eb
Address code review.
nefeline Oct 24, 2023
6333f15
bail early if no business description provided.
nefeline Oct 24, 2023
5ddb593
Add an extra safety check in case of query errors.
nefeline Oct 24, 2023
6d36768
Merge branch 'add/ai-generated-content-for-products' into update/repl…
nefeline Oct 24, 2023
f97f73d
Address CR.
nefeline Oct 24, 2023
4fcc41e
Merge branch 'trunk' into add/ai-generated-content-for-products
nefeline Oct 24, 2023
dfd988a
Merge branch 'add/ai-generated-content-for-products' into update/repl…
nefeline Oct 24, 2023
862e0ec
Merge branch 'trunk' into add/ai-generated-content-for-products
nefeline Oct 24, 2023
7200b1e
Merge branch 'add/ai-generated-content-for-products' into update/repl…
nefeline Oct 24, 2023
1a656dd
Merge trunk and resolve conflicts.
nefeline Oct 25, 2023
8af0567
Merge branch 'trunk' into update/replace-verticals-api-with-pexels
nefeline Oct 25, 2023
114db02
Raise the default memory limit.
nefeline Oct 25, 2023
be53ddf
Update the prompt for the search term for images.
nefeline Oct 25, 2023
e175385
Make sure the 'woocommerce_blocks_allow_ai_connection' option is set …
nefeline Oct 25, 2023
6d0f99a
Update the prompt for AI generated content in patterns and initialize…
nefeline Oct 25, 2023
7ed6081
Update the prompt for products and introduce the update_dummy_product…
nefeline Oct 26, 2023
3502905
Merge branch 'trunk' into update/replace-verticals-api-with-pexels
nefeline Oct 26, 2023
6c8bfa4
Update the default number of images returned by Pexels.
nefeline Oct 26, 2023
26ba4b4
Update the default fallback for the expected image format.
nefeline Oct 26, 2023
a08cae5
Update the prompt for selecting the images.
nefeline Oct 26, 2023
f2b243f
Add a character limit to the testimonials.
nefeline Oct 26, 2023
69e0a29
Merge branch 'trunk' into update/replace-verticals-api-with-pexels
nefeline Oct 26, 2023
6a28abc
Increase timeout to fetch products data
nefeline Oct 26, 2023
780df8e
Address code review.
nefeline Oct 26, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 61 additions & 10 deletions src/BlockPatterns.php
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<?php
namespace Automattic\WooCommerce\Blocks;

use Automattic\WooCommerce\Blocks\AI\Connection;
use Automattic\WooCommerce\Blocks\Images\Pexels;
use Automattic\WooCommerce\Blocks\Domain\Package;
use Automattic\WooCommerce\Blocks\Patterns\PatternUpdater;
use Automattic\WooCommerce\Blocks\Patterns\ProductUpdater;
use Automattic\WooCommerce\Blocks\Verticals\Client;
use Automattic\WooCommerce\Blocks\Verticals\VerticalsSelector;

/**
* Registers patterns under the `./patterns/` directory and updates their content.
Expand Down Expand Up @@ -53,10 +53,37 @@ public function __construct( Package $package ) {

add_action( 'init', array( $this, 'register_block_patterns' ) );
add_action( 'update_option_woo_ai_describe_store_description', array( $this, 'schedule_on_option_update' ), 10, 2 );
add_action( 'update_option_woo_ai_describe_store_description', array( $this, 'update_ai_connection_allowed_option' ), 10, 2 );
add_action( 'upgrader_process_complete', array( $this, 'schedule_on_plugin_update' ), 10, 2 );
add_action( 'woocommerce_update_patterns_content', array( $this, 'update_patterns_content' ) );
}

/**
* Make sure the 'woocommerce_blocks_allow_ai_connection' option is set to true if the site is connected to AI.
*
* @param string $option The option name.
* @param string $value The option value.
*
* @return bool
*/
public function update_ai_connection_allowed_option( $option, $value ): bool {
$ai_connection = new Connection();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: Should this class be a Singleton? Every time that we get the jwt_token, we do a fetch request.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call, I'm doing this change on a separate PR 👍 !


$site_id = $ai_connection->get_site_id();

if ( is_wp_error( $site_id ) ) {
return update_option( 'woocommerce_blocks_allow_ai_connection', false );
}

$token = $ai_connection->get_jwt_token( $site_id );

if ( is_wp_error( $token ) ) {
return update_option( 'woocommerce_blocks_allow_ai_connection', false );
}

return update_option( 'woocommerce_blocks_allow_ai_connection', true );
}

/**
* Registers the block patterns and categories under `./patterns/`.
*/
Expand Down Expand Up @@ -262,7 +289,7 @@ public function schedule_patterns_content_update( $business_description ) {
*
* @param string $value The new value saved for the add_option_woo_ai_describe_store_description option.
*
* @return bool|int|string|\WP_Error
* @return bool|string|\WP_Error
*/
public function update_patterns_content( $value ) {
$allow_ai_connection = get_option( 'woocommerce_blocks_allow_ai_connection' );
Expand All @@ -274,16 +301,40 @@ public function update_patterns_content( $value ) {
);
}

$vertical_id = ( new VerticalsSelector() )->get_vertical_id( $value );
$ai_connection = new Connection();

$site_id = $ai_connection->get_site_id();

if ( is_wp_error( $site_id ) ) {
return $site_id->get_error_message();
}

$token = $ai_connection->get_jwt_token( $site_id );

if ( is_wp_error( $token ) ) {
return $token->get_error_message();
}

$business_description = get_option( 'woo_ai_describe_store_description' );

$images = ( new Pexels() )->get_images( $ai_connection, $token, $business_description );

if ( is_wp_error( $vertical_id ) ) {
return $vertical_id;
if ( is_wp_error( $images ) ) {
return $images->get_error_message();
}

$vertical_images = ( new Client() )->get_vertical_images( $vertical_id );
$business_description = get_option( VerticalsSelector::STORE_DESCRIPTION_OPTION_KEY );
$populate_patterns = ( new PatternUpdater() )->generate_content( $ai_connection, $token, $images, $business_description );

if ( is_wp_error( $populate_patterns ) ) {
return $populate_patterns->get_error_message();
}

$populate_products = ( new ProductUpdater() )->generate_content( $ai_connection, $token, $images, $business_description );

if ( is_wp_error( $populate_products ) ) {
return $populate_products->get_error_message();
}

( new PatternUpdater() )->generate_content( $vertical_images, $business_description );
( new ProductUpdater() )->generate_content( $vertical_images, $business_description );
return true;
nefeline marked this conversation as resolved.
Show resolved Hide resolved
}
}
97 changes: 97 additions & 0 deletions src/Images/Pexels.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
<?php

namespace Automattic\WooCommerce\Blocks\Images;

use Automattic\WooCommerce\Blocks\AI\Connection;

/**
* Pexels API client.
*
* @internal
*/
class Pexels {
nefeline marked this conversation as resolved.
Show resolved Hide resolved

/**
* The Pexels API endpoint.
*/
const EXTERNAL_MEDIA_PEXELS_ENDPOINT = '/wpcom/v2/external-media/list/pexels';

/**
* Returns the list of images for the given search criteria.
*
* @param Connection $ai_connection The AI connection.
* @param string $token The JWT token.
* @param string $business_description The business description.
*
* @return array|\WP_Error Array of images, or WP_Error if the request failed.
*/
public function get_images( $ai_connection, $token, $business_description ) {
$search_term = $this->define_search_term( $ai_connection, $token, $business_description );

if ( is_wp_error( $search_term ) ) {
return $search_term;
}

return $this->request( $search_term );
}

/**
* Define the search term to be used on Pexels using the AI endpoint.
*
* The search term is a shorter description of the business.
*
* @param Connection $ai_connection The AI connection.
* @param string $token The JWT token.
* @param string $business_description The business description.
*
* @return mixed|\WP_Error
*/
private function define_search_term( $ai_connection, $token, $business_description ) {
$prompt = sprintf( 'Based on the description "%s", provide a one-word product description for the store\'s item. Do not include any adjectives or descriptions of the qualities of the product. The returned word should be simple.', $business_description );

$response = $ai_connection->fetch_ai_response( $token, $prompt );

if ( is_wp_error( $response ) || ! isset( $response['completion'] ) ) {
return new \WP_Error( 'search_term_definition_failed', __( 'The search term definition failed.', 'woo-gutenberg-products-block' ) );
}

return $response['completion'];
}

/**
* Make a request to the Pexels API.
*
* @param string $search_term The search term to use.
* @param int $per_page The number of images to return.
*
* @return array|\WP_Error The response body, or WP_Error if the request failed.
*/
private function request( string $search_term, int $per_page = 90 ) {
$request = new \WP_REST_Request( 'GET', self::EXTERNAL_MEDIA_PEXELS_ENDPOINT );

$request->set_param( 'search', esc_html( $search_term ) );
$request->set_param( 'number', $per_page );

$response = rest_do_request( $request );
$response_data = $response->get_data();

if ( $response->is_error() ) {
$error_msg = [
'code' => $response->get_status(),
'data' => $response_data,
];

return new \WP_Error( 'pexels_api_error', __( 'Request to the Pexels API failed.', 'woo-gutenberg-products-block' ), $error_msg );
}

$response = $response_data['media'] ?? $response_data;

if ( is_array( $response ) ) {
shuffle( $response );

return $response;
}

return array();
}
}
Loading
Loading