* fix pattern route performance

* update namespace

* improve middleware

* improve ProductSchema

* improve error handling

* update identifier

* fix middleware

* update description

* use schema to return the response

* Break down the generate_content method and create the new fetch_dummy_products_to_update method for handling the fetch of dummy products to be updated.

* Ensure the Product endpoint relies on the fetch_dummy_products_to_update method for fetching dummy products to avoid code repetition and add safety checks and handle errors in case certain properties are not available.

* Add error handling for the Products endpoint.

* Remove memory limit increase and update docblocks.

* re-add set_time_limit

---------

Co-authored-by: Patricia Hillebrandt <patriciahillebrandt@gmail.com>
This commit is contained in:
Luigi Teschio 2023-11-07 14:50:19 +01:00 committed by GitHub
parent 61b1272d8a
commit 3bde3b174a
14 changed files with 746 additions and 131 deletions

View File

@ -17,7 +17,7 @@ class ProductUpdater {
* @param array $images The array of images.
* @param string $business_description The business description.
*
* @return bool|WP_Error True if the content was generated successfully, WP_Error otherwise.
* @return array|WP_Error The generated content for the products. An error if the content could not be generated.
*/
public function generate_content( $ai_connection, $token, $images, $business_description ) {
if ( empty( $business_description ) ) {
@ -28,16 +28,48 @@ class ProductUpdater {
if ( $last_business_description === $business_description ) {
if ( is_string( $business_description ) && is_string( $last_business_description ) ) {
return true;
return array(
'product_content' => array(),
);
} else {
return new \WP_Error( 'business_description_not_found', __( 'No business description provided for generating AI content.', 'woo-gutenberg-products-block' ) );
}
}
$ai_selected_products_images = $this->get_images_information( $images );
$products_information_list = $this->assign_ai_selected_images_to_dummy_products_information_list( $ai_selected_products_images );
$response = $this->generate_product_content( $ai_connection, $token, $products_information_list );
if ( is_wp_error( $response ) ) {
$error_msg = $response;
} elseif ( empty( $response ) || ! isset( $response['completion'] ) ) {
$error_msg = new \WP_Error( 'missing_completion_key', __( 'The response from the AI service is empty or missing the completion key.', 'woo-gutenberg-products-block' ) );
}
if ( isset( $error_msg ) ) {
return $error_msg;
}
$product_content = json_decode( $response['completion'], true );
return array(
'product_content' => $product_content,
);
}
/**
* Return all dummy products that were not modified by the store owner.
*
* @return array|WP_Error An array with the dummy products that need to have their content updated by AI.
*/
public function fetch_dummy_products_to_update() {
$real_products = $this->fetch_product_ids();
if ( is_array( $real_products ) && count( $real_products ) > 0 ) {
return true;
return array(
'product_content' => array(),
);
}
$dummy_products = $this->fetch_product_ids( 'dummy' );
@ -82,62 +114,7 @@ class ProductUpdater {
}
}
if ( empty( $dummy_products_to_update ) ) {
return true;
}
$ai_selected_products_images = $this->get_images_information( $images );
$products_information_list = $this->assign_ai_selected_images_to_dummy_products_information_list( $ai_selected_products_images );
$response = $this->generate_product_content( $ai_connection, $token, $products_information_list );
if ( is_wp_error( $response ) ) {
$error_msg = $response;
} elseif ( empty( $response ) || ! isset( $response['completion'] ) ) {
$error_msg = new \WP_Error( 'missing_completion_key', __( 'The response from the AI service is empty or missing the completion key.', 'woo-gutenberg-products-block' ) );
}
if ( isset( $error_msg ) ) {
$this->update_dummy_products( $dummy_products_to_update, $products_information_list );
return $error_msg;
}
$product_content = json_decode( $response['completion'], true );
if ( is_null( $product_content ) ) {
$this->update_dummy_products( $dummy_products_to_update, $products_information_list );
return new \WP_Error( 'invalid_json', __( 'The response from the AI service is not a valid JSON.', 'woo-gutenberg-products-block' ) );
}
// This is required to allow the usage of the media_sideload_image function outside the context of /wp-admin/.
// See https://developer.wordpress.org/reference/functions/media_sideload_image/ for more details.
require_once ABSPATH . 'wp-admin/includes/media.php';
require_once ABSPATH . 'wp-admin/includes/file.php';
require_once ABSPATH . 'wp-admin/includes/image.php';
$this->update_dummy_products( $dummy_products_to_update, $product_content );
return true;
}
/**
* Update the dummy products with the content from the information list.
*
* @param array $dummy_products_to_update The dummy products to update.
* @param array $products_information_list The products information list.
*/
public function update_dummy_products( $dummy_products_to_update, $products_information_list ) {
$i = 0;
foreach ( $dummy_products_to_update as $dummy_product ) {
if ( ! isset( $products_information_list[ $i ] ) ) {
continue;
}
$this->update_product_content( $dummy_product, $products_information_list[ $i ] );
++$i;
}
return $dummy_products_to_update;
}
/**
@ -273,11 +250,15 @@ class ProductUpdater {
if ( ! isset( $ai_generated_product_content['image']['src'] ) || ! isset( $ai_generated_product_content['image']['alt'] ) || ! isset( $ai_generated_product_content['title'] ) || ! isset( $ai_generated_product_content['description'] ) ) {
return;
}
require_once ABSPATH . 'wp-admin/includes/media.php';
require_once ABSPATH . 'wp-admin/includes/file.php';
require_once ABSPATH . 'wp-admin/includes/image.php';
// Since the media_sideload_image function is expensive and can take longer to complete
// the process of downloading the external image and uploading it to the media library,
// here we are increasing the time limit and the memory limit to avoid any issues.
// here we are increasing the time limit to avoid any issues.
set_time_limit( 60 );
wp_raise_memory_limit();
$product_image_id = media_sideload_image( $ai_generated_product_content['image']['src'], $product->get_id(), $ai_generated_product_content['image']['alt'], 'id' );

View File

@ -0,0 +1,89 @@
<?php
namespace Automattic\WooCommerce\StoreApi\Routes\V1\AI;
use Automattic\WooCommerce\Blocks\Patterns\ProductUpdater;
use Automattic\WooCommerce\StoreApi\Routes\V1\AbstractRoute;
/**
* BusinessDescription class.
*
* @internal
*/
class BusinessDescription extends AbstractRoute {
/**
* The route identifier.
*
* @var string
*/
const IDENTIFIER = 'ai/business-description';
/**
* The schema item identifier.
*
* @var string
*/
const SCHEMA_TYPE = 'ai/business-description';
/**
* Get the path of this REST route.
*
* @return string
*/
public function get_path() {
return '/ai/business-description';
}
/**
* Get method arguments for this REST route.
*
* @return array An array of endpoints.
*/
public function get_args() {
return [
[
'methods' => \WP_REST_Server::CREATABLE,
'callback' => [ $this, 'get_response' ],
'permission_callback' => [ Middleware::class, 'is_authorized' ],
'args' => [
'business_description' => [
'description' => __( 'The business description for a given store.', 'woo-gutenberg-products-block' ),
'type' => 'string',
],
],
],
'schema' => [ $this->schema, 'get_public_item_schema' ],
'allow_batch' => [ 'v1' => true ],
];
}
/**
* Update the last business description.
*
* @param \WP_REST_Request $request Request object.
*
* @return bool|string|\WP_Error|\WP_REST_Response
*/
protected function get_route_post_response( \WP_REST_Request $request ) {
$business_description = $request->get_param( 'business_description' );
if ( ! $business_description ) {
return $this->error_to_response(
new \WP_Error(
'invalid_business_description',
__( 'Invalid business description.', 'woo-gutenberg-products-block' )
)
);
}
update_option( 'last_business_description_with_ai_content_generated', $business_description );
return rest_ensure_response(
array(
'ai_content_generated' => true,
)
);
}
}

View File

@ -0,0 +1,118 @@
<?php
namespace Automattic\WooCommerce\StoreApi\Routes\V1\AI;
use Automattic\WooCommerce\Blocks\AI\Connection;
use Automattic\WooCommerce\Blocks\Images\Pexels;
use Automattic\WooCommerce\StoreApi\Routes\V1\AbstractRoute;
/**
* Patterns class.
*/
class Images extends AbstractRoute {
/**
* The route identifier.
*
* @var string
*/
const IDENTIFIER = 'ai/images';
/**
* The schema item identifier.
*
* @var string
*/
const SCHEMA_TYPE = 'ai/images';
/**
* Get the path of this REST route.
*
* @return string
*/
public function get_path() {
return '/ai/images';
}
/**
* Get method arguments for this REST route.
*
* @return array An array of endpoints.
*/
public function get_args() {
return [
[
'methods' => \WP_REST_Server::CREATABLE,
'callback' => [ $this, 'get_response' ],
'permission_callback' => [ Middleware::class, 'is_authorized' ],
'args' => [
'business_description' => [
'description' => __( 'The business description for a given store.', 'woo-gutenberg-products-block' ),
'type' => 'string',
],
],
],
'schema' => [ $this->schema, 'get_public_item_schema' ],
'allow_batch' => [ 'v1' => true ],
];
}
/**
* Generate Images from Pexels
*
* @param \WP_REST_Request $request Request object.
*
* @return bool|string|\WP_Error|\WP_REST_Response
*/
protected function get_route_post_response( \WP_REST_Request $request ) {
$business_description = sanitize_text_field( wp_unslash( $request['business_description'] ) );
if ( empty( $business_description ) ) {
$business_description = get_option( 'woo_ai_describe_store_description' );
}
$last_business_description = get_option( 'last_business_description_with_ai_content_generated' );
if ( $last_business_description === $business_description ) {
return rest_ensure_response(
$this->prepare_item_for_response(
[
'ai_content_generated' => true,
'images' => array(),
],
$request
)
);
}
$ai_connection = new Connection();
$site_id = $ai_connection->get_site_id();
if ( is_wp_error( $site_id ) ) {
return $this->error_to_response( $site_id );
}
$token = $ai_connection->get_jwt_token( $site_id );
if ( is_wp_error( $token ) ) {
return $this->error_to_response( $token );
}
$images = ( new Pexels() )->get_images( $ai_connection, $token, $business_description );
if ( is_wp_error( $images ) ) {
return $this->error_to_response( $images );
}
return rest_ensure_response(
$this->prepare_item_for_response(
[
'ai_content_generated' => true,
'images' => $images,
],
$request
)
);
}
}

View File

@ -0,0 +1,50 @@
<?php
namespace Automattic\WooCommerce\StoreApi\Routes\V1\AI;
use Automattic\WooCommerce\StoreApi\Exceptions\RouteException;
/**
* Middleware class.
*
* @internal
*/
class Middleware {
/**
* Ensure that the user is allowed to make this request.
*
* @throws RouteException If the user is not allowed to make this request.
* @return boolean
*/
public static function is_authorized() {
try {
if ( ! current_user_can( 'manage_options' ) ) {
throw new RouteException( 'woocommerce_rest_invalid_user', __( 'You are not allowed to make this request. Please make sure you are logged in.', 'woo-gutenberg-products-block' ), 403 );
}
} catch ( RouteException $error ) {
return new \WP_Error(
$error->getErrorCode(),
$error->getMessage(),
array( 'status' => $error->getCode() )
);
}
$allow_ai_connection = get_option( 'woocommerce_blocks_allow_ai_connection' );
if ( ! $allow_ai_connection ) {
try {
throw new RouteException( 'ai_connection_not_allowed', __( 'AI content generation is not allowed on this store. Update your store settings if you wish to enable this feature.', 'woo-gutenberg-products-block' ), 403 );
} catch ( RouteException $error ) {
return new \WP_Error(
$error->getErrorCode(),
$error->getMessage(),
array( 'status' => $error->getCode() )
);
}
}
return true;
}
}

View File

@ -0,0 +1,94 @@
<?php
namespace Automattic\WooCommerce\StoreApi\Routes\V1\AI;
use Automattic\WooCommerce\Blocks\AI\Connection;
use Automattic\WooCommerce\Blocks\Patterns\PatternUpdater;
use Automattic\WooCommerce\StoreApi\Routes\V1\AbstractRoute;
/**
* Patterns class.
*
* @internal
*/
class Patterns extends AbstractRoute {
/**
* The route identifier.
*
* @var string
*/
const IDENTIFIER = 'ai/patterns';
/**
* The schema item identifier.
*
* @var string
*/
const SCHEMA_TYPE = 'ai/patterns';
/**
* Get the path of this REST route.
*
* @return string
*/
public function get_path() {
return '/ai/patterns';
}
/**
* Get method arguments for this REST route.
*
* @return array An array of endpoints.
*/
public function get_args() {
return [
[
'methods' => \WP_REST_Server::CREATABLE,
'callback' => [ $this, 'get_response' ],
'permission_callback' => [ Middleware::class, 'is_authorized' ],
'args' => [
'business_description' => [
'description' => __( 'The business description for a given store.', 'woo-gutenberg-products-block' ),
'type' => 'string',
],
'images' => [
'description' => __( 'The images for a given store.', 'woo-gutenberg-products-block' ),
'type' => 'object',
],
],
],
'schema' => [ $this->schema, 'get_public_item_schema' ],
'allow_batch' => [ 'v1' => true ],
];
}
/**
* Update patterns with the content and images powered by AI.
*
* @param \WP_REST_Request $request Request object.
*
* @return bool|string|\WP_Error|\WP_REST_Response
*/
protected function get_route_post_response( \WP_REST_Request $request ) {
$business_description = sanitize_text_field( wp_unslash( $request['business_description'] ) );
$ai_connection = new Connection();
$site_id = $ai_connection->get_site_id();
if ( is_wp_error( $site_id ) ) {
return $this->error_to_response( $site_id );
}
$token = $ai_connection->get_jwt_token( $site_id );
$images = $request['images'];
try {
( new PatternUpdater() )->generate_content( $ai_connection, $token, $images, $business_description );
return rest_ensure_response( array( 'ai_content_generated' => true ) );
} catch ( \WP_Error $e ) {
return $this->error_to_response( $e );
}
}
}

View File

@ -0,0 +1,111 @@
<?php
namespace Automattic\WooCommerce\StoreApi\Routes\V1\AI;
use Automattic\WooCommerce\Blocks\Patterns\ProductUpdater;
use Automattic\WooCommerce\StoreApi\Routes\V1\AbstractRoute;
/**
* Product class.
*
* @internal
*/
class Product extends AbstractRoute {
/**
* The route identifier.
*
* @var string
*/
const IDENTIFIER = 'ai/product';
/**
* The schema item identifier.
*
* @var string
*/
const SCHEMA_TYPE = 'ai/product';
/**
* Get the path of this REST route.
*
* @return string
*/
public function get_path() {
return '/ai/product';
}
/**
* Get method arguments for this REST route.
*
* @return array An array of endpoints.
*/
public function get_args() {
return [
[
'methods' => \WP_REST_Server::CREATABLE,
'callback' => [ $this, 'get_response' ],
'permission_callback' => [ Middleware::class, 'is_authorized' ],
'args' => [
'index' => [
'description' => __( 'The business description for a given store.', 'woo-gutenberg-products-block' ),
'type' => 'integer',
],
'products_information' => [
'description' => __( 'Data generated by AI for updating dummy products.', 'woo-gutenberg-products-block' ),
'type' => 'object',
],
],
],
'schema' => [ $this->schema, 'get_public_item_schema' ],
'allow_batch' => [ 'v1' => true ],
];
}
/**
* Update product with the content and image powered by AI.
*
* @param \WP_REST_Request $request Request object.
*
* @return bool|string|\WP_Error|\WP_REST_Response
*/
protected function get_route_post_response( \WP_REST_Request $request ) {
$product_updater = new ProductUpdater();
$dummy_products = $product_updater->fetch_dummy_products_to_update();
if ( empty( $dummy_products ) ) {
return rest_ensure_response(
array(
'ai_content_generated' => true,
)
);
}
$index = $request['index'];
if ( ! is_numeric( $index ) ) {
return rest_ensure_response(
array(
'ai_content_generated' => false,
)
);
}
$products_information = $request['products_information'] ?? array();
if ( ! isset( $dummy_products[ $index ] ) ) {
return rest_ensure_response(
array(
'ai_content_generated' => false,
)
);
}
$product_updater->update_product_content( $dummy_products[ $index ], $products_information );
return rest_ensure_response(
array(
'ai_content_generated' => true,
)
);
}
}

View File

@ -1,30 +1,30 @@
<?php
namespace Automattic\WooCommerce\StoreApi\Routes\V1;
namespace Automattic\WooCommerce\StoreApi\Routes\V1\AI;
use Automattic\WooCommerce\Blocks\AI\Connection;
use Automattic\WooCommerce\Blocks\Images\Pexels;
use Automattic\WooCommerce\Blocks\Patterns\PatternUpdater;
use Automattic\WooCommerce\Blocks\Patterns\ProductUpdater;
use Automattic\WooCommerce\StoreApi\Exceptions\RouteException;
use Automattic\WooCommerce\StoreApi\Routes\V1\AbstractRoute;
/**
* Patterns class.
* Products class.
*
* @internal
*/
class Patterns extends AbstractRoute {
class Products extends AbstractRoute {
/**
* The route identifier.
*
* @var string
*/
const IDENTIFIER = 'patterns';
const IDENTIFIER = 'ai/products';
/**
* The schema item identifier.
*
* @var string
*/
const SCHEMA_TYPE = 'patterns';
const SCHEMA_TYPE = 'ai/products';
/**
* Get the path of this REST route.
@ -32,7 +32,7 @@ class Patterns extends AbstractRoute {
* @return string
*/
public function get_path() {
return '/patterns';
return '/ai/products';
}
/**
@ -45,12 +45,16 @@ class Patterns extends AbstractRoute {
[
'methods' => \WP_REST_Server::CREATABLE,
'callback' => [ $this, 'get_response' ],
'permission_callback' => [ $this, 'is_authorized' ],
'permission_callback' => [ Middleware::class, 'is_authorized' ],
'args' => [
'business_description' => [
'description' => __( 'The business description for a given store.', 'woo-gutenberg-products-block' ),
'type' => 'string',
],
'images' => [
'description' => __( 'The images for a given store.', 'woo-gutenberg-products-block' ),
'type' => 'object',
],
],
],
'schema' => [ $this->schema, 'get_public_item_schema' ],
@ -59,30 +63,7 @@ class Patterns extends AbstractRoute {
}
/**
* Permission callback.
*
* @throws RouteException If the user is not allowed to make this request.
*
* @return true|\WP_Error
*/
public function is_authorized() {
try {
if ( ! current_user_can( 'manage_options' ) ) {
throw new RouteException( 'woocommerce_rest_invalid_user', __( 'You are not allowed to make this request. Please make sure you are logged in.', 'woo-gutenberg-products-block' ), 403 );
}
} catch ( RouteException $error ) {
return new \WP_Error(
$error->getErrorCode(),
$error->getMessage(),
array( 'status' => $error->getCode() )
);
}
return true;
}
/**
* Ensure the content and images in patterns are powered by AI.
* Generate the content for the products.
*
* @param \WP_REST_Request $request Request object.
*
@ -115,6 +96,7 @@ class Patterns extends AbstractRoute {
$this->prepare_item_for_response(
[
'ai_content_generated' => true,
'product_content' => null,
],
$request
)
@ -126,46 +108,34 @@ class Patterns extends AbstractRoute {
$site_id = $ai_connection->get_site_id();
if ( is_wp_error( $site_id ) ) {
return $site_id;
return $this->error_to_response( $site_id );
}
$token = $ai_connection->get_jwt_token( $site_id );
if ( is_wp_error( $token ) ) {
return $token;
return $this->error_to_response( $token );
}
$images = ( new Pexels() )->get_images( $ai_connection, $token, $business_description );
$images = $request['images'];
if ( is_wp_error( $images ) ) {
$response = $this->error_to_response( $images );
} else {
$populate_patterns = ( new PatternUpdater() )->generate_content( $ai_connection, $token, $images, $business_description );
$populate_products = ( new ProductUpdater() )->generate_content( $ai_connection, $token, $images, $business_description );
if ( is_wp_error( $populate_patterns ) ) {
$response = $this->error_to_response( $populate_patterns );
}
$populate_products = ( new ProductUpdater() )->generate_content( $ai_connection, $token, $images, $business_description );
if ( is_wp_error( $populate_products ) ) {
$response = $this->error_to_response( $populate_products );
}
if ( true === $populate_patterns && true === $populate_products ) {
update_option( 'last_business_description_with_ai_content_generated', $business_description );
}
if ( is_wp_error( $populate_products ) ) {
return $this->error_to_response( $populate_products );
}
if ( ! isset( $response ) ) {
$response = $this->prepare_item_for_response(
[
'ai_content_generated' => true,
],
$request
);
if ( ! isset( $populate_products['product_content'] ) ) {
return $this->error_to_response( new \WP_Error( 'product_content_not_found', __( 'Product content not found.', 'woo-gutenberg-products-block' ) ) );
}
return rest_ensure_response( $response );
$product_content = $populate_products['product_content'];
$item = array(
'ai_content_generated' => true,
'product_content' => $product_content,
);
return rest_ensure_response( $item );
}
}

View File

@ -1,7 +1,6 @@
<?php
namespace Automattic\WooCommerce\StoreApi;
use Automattic\WooCommerce\Blocks\Package;
use Automattic\WooCommerce\StoreApi\Routes\V1\AbstractRoute;
/**
@ -30,7 +29,7 @@ class RoutesController {
public function __construct( SchemaController $schema_controller ) {
$this->schema_controller = $schema_controller;
$this->routes = [
'v1' => [
'v1' => [
Routes\V1\Batch::IDENTIFIER => Routes\V1\Batch::class,
Routes\V1\Cart::IDENTIFIER => Routes\V1\Cart::class,
Routes\V1\CartAddItem::IDENTIFIER => Routes\V1\CartAddItem::class,
@ -48,7 +47,6 @@ class RoutesController {
Routes\V1\Checkout::IDENTIFIER => Routes\V1\Checkout::class,
Routes\V1\CheckoutOrder::IDENTIFIER => Routes\V1\CheckoutOrder::class,
Routes\V1\Order::IDENTIFIER => Routes\V1\Order::class,
Routes\V1\Patterns::IDENTIFIER => Routes\V1\Patterns::class,
Routes\V1\ProductAttributes::IDENTIFIER => Routes\V1\ProductAttributes::class,
Routes\V1\ProductAttributesById::IDENTIFIER => Routes\V1\ProductAttributesById::class,
Routes\V1\ProductAttributeTerms::IDENTIFIER => Routes\V1\ProductAttributeTerms::class,
@ -61,6 +59,14 @@ class RoutesController {
Routes\V1\ProductsById::IDENTIFIER => Routes\V1\ProductsById::class,
Routes\V1\ProductsBySlug::IDENTIFIER => Routes\V1\ProductsBySlug::class,
],
// @todo Migrate internal AI routes to WooCommerce Core codebase.
'private' => [
Routes\V1\AI\Images::IDENTIFIER => Routes\V1\AI\Images::class,
Routes\V1\AI\Patterns::IDENTIFIER => Routes\V1\AI\Patterns::class,
Routes\V1\AI\Product::IDENTIFIER => Routes\V1\AI\Product::class,
Routes\V1\AI\Products::IDENTIFIER => Routes\V1\AI\Products::class,
Routes\V1\AI\BusinessDescription::IDENTIFIER => Routes\V1\AI\BusinessDescription::class,
],
];
}
@ -70,6 +76,7 @@ class RoutesController {
public function register_all_routes() {
$this->register_routes( 'v1', 'wc/store' );
$this->register_routes( 'v1', 'wc/store/v1' );
$this->register_routes( 'private', 'wc/private' );
}
/**

View File

@ -49,12 +49,16 @@ class SchemaController {
Schemas\V1\OrderCouponSchema::IDENTIFIER => Schemas\V1\OrderCouponSchema::class,
Schemas\V1\OrderFeeSchema::IDENTIFIER => Schemas\V1\OrderFeeSchema::class,
Schemas\V1\OrderSchema::IDENTIFIER => Schemas\V1\OrderSchema::class,
Schemas\V1\PatternsSchema::IDENTIFIER => Schemas\V1\PatternsSchema::class,
Schemas\V1\ProductSchema::IDENTIFIER => Schemas\V1\ProductSchema::class,
Schemas\V1\ProductAttributeSchema::IDENTIFIER => Schemas\V1\ProductAttributeSchema::class,
Schemas\V1\ProductCategorySchema::IDENTIFIER => Schemas\V1\ProductCategorySchema::class,
Schemas\V1\ProductCollectionDataSchema::IDENTIFIER => Schemas\V1\ProductCollectionDataSchema::class,
Schemas\V1\ProductReviewSchema::IDENTIFIER => Schemas\V1\ProductReviewSchema::class,
Schemas\V1\AI\ImagesSchema::IDENTIFIER => Schemas\V1\AI\ImagesSchema::class,
Schemas\V1\AI\PatternsSchema::IDENTIFIER => Schemas\V1\AI\PatternsSchema::class,
Schemas\V1\AI\ProductSchema::IDENTIFIER => Schemas\V1\AI\ProductSchema::class,
Schemas\V1\AI\ProductsSchema::IDENTIFIER => Schemas\V1\AI\ProductsSchema::class,
Schemas\V1\AI\BusinessDescriptionSchema::IDENTIFIER => Schemas\V1\AI\BusinessDescriptionSchema::class,
],
];
}

View File

@ -0,0 +1,47 @@
<?php
namespace Automattic\WooCommerce\StoreApi\Schemas\V1\AI;
use Automattic\WooCommerce\StoreApi\Schemas\V1\AbstractSchema;
/**
* BusinessDescriptionSchema class.
*
* @internal
*/
class BusinessDescriptionSchema extends AbstractSchema {
/**
* The schema item name.
*
* @var string
*/
protected $title = 'ai/business-description';
/**
* The schema item identifier.
*
* @var string
*/
const IDENTIFIER = 'ai/business-description';
/**
* Business Description schema properties.
*
* @return array
*/
public function get_properties() {
return [];
}
/**
* Get the Business Description response.
*
* @param array $item Item to get response for.
*
* @return array
*/
public function get_item_response( $item ) {
return [
'ai_content_generated' => true,
];
}
}

View File

@ -0,0 +1,45 @@
<?php
namespace Automattic\WooCommerce\StoreApi\Schemas\V1\AI;
use Automattic\WooCommerce\StoreApi\Schemas\V1\AbstractSchema;
/**
* ImagesSchema class.
*
* @internal
*/
class ImagesSchema extends AbstractSchema {
/**
* The schema item name.
*
* @var string
*/
protected $title = 'ai/images';
/**
* The schema item identifier.
*
* @var string
*/
const IDENTIFIER = 'ai/images';
/**
* Images schema properties.
*
* @return array
*/
public function get_properties() {
return [];
}
/**
* Get the Images response.
*
* @param array $item Item to get response for.
*
* @return array
*/
public function get_item_response( $item ) {
return $item;
}
}

View File

@ -1,8 +1,12 @@
<?php
namespace Automattic\WooCommerce\StoreApi\Schemas\V1;
namespace Automattic\WooCommerce\StoreApi\Schemas\V1\AI;
use Automattic\WooCommerce\StoreApi\Schemas\V1\AbstractSchema;
/**
* OrderSchema class.
* PatternsSchema class.
*
* @internal
*/
class PatternsSchema extends AbstractSchema {
/**
@ -10,14 +14,14 @@ class PatternsSchema extends AbstractSchema {
*
* @var string
*/
protected $title = 'patterns';
protected $title = 'ai/patterns';
/**
* The schema item identifier.
*
* @var string
*/
const IDENTIFIER = 'patterns';
const IDENTIFIER = 'ai/patterns';
/**
* Patterns schema properties.

View File

@ -0,0 +1,47 @@
<?php
namespace Automattic\WooCommerce\StoreApi\Schemas\V1\AI;
use Automattic\WooCommerce\StoreApi\Schemas\V1\AbstractSchema;
/**
* ProductSchema class.
*
* @internal
*/
class ProductSchema extends AbstractSchema {
/**
* The schema item name.
*
* @var string
*/
protected $title = 'ai/product';
/**
* The schema item identifier.
*
* @var string
*/
const IDENTIFIER = 'ai/product';
/**
* Patterns schema properties.
*
* @return array
*/
public function get_properties() {
return [];
}
/**
* Get the Product response.
*
* @param array $item Item to get response for.
*
* @return array
*/
public function get_item_response( $item ) {
return [
'ai_content_generated' => true,
];
}
}

View File

@ -0,0 +1,48 @@
<?php
namespace Automattic\WooCommerce\StoreApi\Schemas\V1\AI;
use Automattic\WooCommerce\StoreApi\Schemas\V1\AbstractSchema;
/**
* ProductsSchema class.
*
* @internal
*/
class ProductsSchema extends AbstractSchema {
/**
* The schema item name.
*
* @var string
*/
protected $title = 'ai/products';
/**
* The schema item identifier.
*
* @var string
*/
const IDENTIFIER = 'ai/products';
/**
* Products schema properties.
*
* @return array
*/
public function get_properties() {
return [];
}
/**
* Get the Products response.
*
* @param array $item Item to get response for.
*
* @return array
*/
public function get_item_response( $item ) {
return [
'ai_content_generated' => $item['ai_content_generated'],
'product_content' => $item['product_content'],
];
}
}