-
Notifications
You must be signed in to change notification settings - Fork 216
feat: Product image enhancement with AI #2775
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
Important Review skippedReview was skipped as selected files did not have any reviewable changes. 💤 Files selected but had no reviewable changes (1)
You can disable this status message by setting the WalkthroughRefactors intelligence service registration and adds a provider/model abstraction (interfaces, Provider/Model base classes), multiple new provider and model implementations (Gemini, OpenAI variants), expands Manager to support generation types (text/image/video), updates settings and REST request handling to use providers/models, and removes legacy EngineFactory/BaseAIService/AIServiceInterface. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant AdminUI as Admin UI
participant Settings as Settings
participant Manager as Manager
participant Provider as AI Provider
participant Model as AI Model
AdminUI->>Settings: render_ai_settings()
Settings->>Manager: get_text_supported_providers()
Manager->>Provider: get_models_by_type("text")
Provider->>Model: get_id()/get_title()/get_description()
Settings-->>AdminUI: render dynamic provider & model fields
sequenceDiagram
autonumber
participant Client as REST Client
participant REST as AIRequestController
participant Manager as Manager
participant Provider as AI Provider
participant Model as AI Model
Client->>REST: POST /ai-request { type, prompt, ... }
REST->>Manager: get_type_prefix(type) & load provider/model from options
Manager->>Provider: get_model(model_id)
REST->>Model: call process_<type>(prompt, args)
Model->>Model: request(prompt,args) -> API
Model-->>REST: AI response
REST-->>Client: rest_ensure_response(response)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Pre-merge checks (1 passed, 4 warnings)❌ Failed checks (4 warnings)
✅ Passed checks (1 passed)
Poem
Pre-merge checks (1 passed, 4 warnings)❌ Failed checks (4 warnings)
✅ Passed checks (1 passed)
Poem
Pre-merge checks (1 passed, 4 warnings)❌ Failed checks (4 warnings)
✅ Passed checks (1 passed)
Tip 👮 Agentic pre-merge checks are now available in preview!Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.
Please see the documentation for more information. Example: reviews:
pre_merge_checks:
custom_checks:
- name: "Undocumented Breaking Changes"
mode: "warning"
instructions: |
Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).Please share your feedback with us on this Discord post. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 6
🔭 Outside diff range comments (3)
includes/Intelligence/Services/Models/OpenAIGPTThreeDotFiveTurbo.php (1)
108-133: Make the system prompt configurable instead of hardcoding e-commerce specific instructions.The hardcoded system prompt is overly specific to e-commerce product descriptions and limits the model's flexibility for other use cases. Consider making it configurable through settings or accepting it as a parameter.
Apply this diff to make the system prompt configurable:
if ( isset( $args['json_format'] ) ) { + $default_system_prompt = 'You are an AI assistant. Always return the response in strict JSON format without any markdown or special characters.'; + $system_prompt = apply_filters( 'dokan_ai_openai_system_prompt', $default_system_prompt, $prompt, $args ); + array_unshift( $messages, [ 'role' => 'system', - 'content' => 'You are an AI assistant specializing in WooCommerce and e-commerce product. - Your task is to generate SEO-optimized content that helps increase sales and search rankings. - Always return the response in strict JSON format without any markdown or special characters. - Format the response as follows: - { - "title": "<Compelling product title optimized for SEO>", - "short_description": "<A concise, keyword-rich summary (minimum 80-150 words) that attracts buyers and improves search engine visibility>", - "long_description": "<A detailed, engaging product long description including features, benefits, use cases, and persuasive copywriting techniques>" - } - - Guidelines: - — Output language should be the same as the input language strictly matching the prompt. - — Using <p></p> tags for paragraphs instead of newlines. - — Do not use Markdown formatting (** or `#` or `>` characters). - — Do not include backticks (```json or ```) or any non-JSON syntax. - — Do not add extra commentary or explanations—only return the JSON object. - — Ensure readability with short sentences, bullet points, and clear formatting. - — Highlight key features (if need), unique selling points, and benefits. - — Output should be a valid JSON object with the keys: title, short_description, long_description.', + 'content' => $system_prompt, ], ); }includes/Intelligence/Services/Models/GeminiTwoDotFiveFlashLite.php (2)
69-93: Extract duplicated system prompt to a shared location.The hardcoded system prompt for JSON format is duplicated across multiple model implementations (OpenAI and Gemini). This violates the DRY principle and makes maintenance difficult.
Consider creating a shared trait or helper class for common AI prompts:
// In a new file: includes/Intelligence/Services/Traits/AIPromptsTrait.php trait AIPromptsTrait { protected function getProductDescriptionSystemPrompt(): string { return apply_filters( 'dokan_ai_product_description_system_prompt', 'You are an AI assistant specializing in WooCommerce and e-commerce product...' ); } }Then use it in your model classes:
+use WeDevs\Dokan\Intelligence\Services\Traits\AIPromptsTrait; + class GeminiTwoDotFiveFlashLite extends Model implements AITextGenerationInterface { + use AIPromptsTrait; + // ... other code ... protected function get_payload( string $prompt, array $args = [] ): array { if ( isset( $args['json_format'] ) ) { - $pre_prompt = 'You are an AI assistant specializing in WooCommerce and e-commerce product...'; + $pre_prompt = $this->getProductDescriptionSystemPrompt(); $prompt = $pre_prompt . PHP_EOL . $prompt; }
135-137: Remove unnecessary quote stripping logic.Similar to the OpenAI model, this quote stripping logic could corrupt valid JSON strings that legitimately contain quotes.
Apply this diff:
- // if response type of string - if ( gettype( $response ) === 'string' ) { - $response = preg_replace( '/^"(.*)"$/', '$1', $response ); - }
🧹 Nitpick comments (19)
includes/Intelligence/Services/AIImageGenerationInterface.php (1)
5-15: Consider improving type safety and error handling guidance.The interface design is clean, but there are opportunities for improvement:
- The
mixedreturn type is quite broad - consider using a more specific type or union type to better define expected return values- No guidance on error handling - consider documenting expected exceptions or error return patterns
- The
$promptparameter lacks validation constraints (e.g., non-empty string requirements)Consider this more specific approach:
interface AIImageGenerationInterface { /** * Process the image prompt and return the generated image. * * @param string $prompt The input prompt for the AI model (must not be empty). * @param array $args Optional additional data. - * @return mixed The generated image from the AI model. + * @return array|string The generated image data (URL, base64, or structured response). + * @throws \InvalidArgumentException When prompt is empty or invalid. + * @throws \RuntimeException When image generation fails. */ - public function process_image( string $prompt, array $args = [] ); + public function process_image( string $prompt, array $args = [] ): array|string; }includes/Intelligence/Services/AITextGenerationInterface.php (1)
5-15: Apply consistent improvements with AIImageGenerationInterface.This interface has identical design considerations as
AIImageGenerationInterface. For consistency:
- Consider the same type safety improvements (more specific return types)
- Add similar error handling documentation
- Include parameter validation guidance
Additionally, given the structural similarity between text and image generation interfaces, consider whether a base interface would be beneficial:
+interface AIGenerationInterface { + /** + * Process the prompt and return the generated content. + * + * @param string $prompt The input prompt for the AI model. + * @param array $args Optional additional data. + * @return mixed The generated content from the AI model. + */ + public function process( string $prompt, array $args = [] ); +} + -interface AITextGenerationInterface { +interface AITextGenerationInterface extends AIGenerationInterface { /** * Process the text prompt and return the generated response. */ - public function process_text( string $prompt, array $args = [] ); + public function process_text( string $prompt, array $args = [] ): string; }includes/Intelligence/Services/Models/OpenAIChatGPTFourO.php (2)
1-3: Adddeclare(strict_types=1);and a file-level docblockAll new model files omit
strict_types. Enabling strict typing avoids silent coercions and aligns with modern PHP best practices.
Likewise, a short docblock (author, purpose) helps future maintainers.<?php +declare(strict_types=1); + +/** + * Model: OpenAI ChatGPT-4o + * + * @package dokan-lite + */
5-12: Consider making lightweight metadata classesfinalThese classes only provide constants; subclassing them brings no benefit and can introduce accidental overrides. Marking them
finalsignals intent and allows small opcache optimisations.-class OpenAIChatGPTFourO extends OpenAIGPTThreeDotFiveTurbo { +final class OpenAIChatGPTFourO extends OpenAIGPTThreeDotFiveTurbo {includes/Intelligence/Services/Models/OpenAIGPTFourOMini.php (2)
1-3: Apply strict types & docblock (same as other model files)
5-6: Mark asfinalto prevent unintended inheritanceSame rationale as the previous class.
-class OpenAIGPTFourOMini extends OpenAIGPTThreeDotFiveTurbo { +final class OpenAIGPTFourOMini extends OpenAIGPTThreeDotFiveTurbo {includes/Intelligence/Services/Models/OpenAIGPTFourTurbo.php (2)
1-3: Adddeclare(strict_types=1);& header docblock
5-6: Preferfinalkeyword for constant-only classes-class OpenAIGPTFourTurbo extends OpenAIGPTThreeDotFiveTurbo { +final class OpenAIGPTFourTurbo extends OpenAIGPTThreeDotFiveTurbo {includes/Intelligence/Services/Providers/OpenAI.php (3)
1-3: Enable strict types & add file docblockConsistent with other service classes.
<?php +declare(strict_types=1); + +/** + * Provider: OpenAI + * + * @package dokan-lite + */
30-32: Default model choice – isgpt-3.5-turbostill intended?With several GPT-4* variants bundled, shipping the 3.5 model as default may surprise users expecting the newest capabilities.
Consider elevating the default togpt-4-turbo(once verified) or exposing a setting in the UI.
34-36: Hard-coded URL – add constant or configIf the OpenAI dashboard URL ever changes, having it duplicated in code is brittle.
Suggest extracting to a class constant or configuration option.- public function get_api_key_url(): string { - return 'https://platform.openai.com/api-keys'; - } + public function get_api_key_url(): string { + return self::API_KEY_URL; + } + + private const API_KEY_URL = 'https://platform.openai.com/api-keys';includes/Intelligence/Services/Models/GeminiTwoDotFiveFlash.php (4)
5-6: Remove unusedModelimport
use WeDevs\Dokan\Intelligence\Services\Model;is never referenced, violating WPCSUnusedUserule.-use WeDevs\Dokan\Intelligence\Services\Model;
1-3: Missingdeclare(strict_types=1);and docblockSame recommendation as for the OpenAI models.
8-9: Make the classfinalLightweight metadata container – inheritance not required.
-class GeminiTwoDotFiveFlash extends GeminiTwoDotFiveFlashLite implements AITextGenerationInterface { +final class GeminiTwoDotFiveFlash extends GeminiTwoDotFiveFlashLite implements AITextGenerationInterface {
10-30: Mixed tabs and spacesLines 10-30 use tabs, earlier lines use spaces. This will be flagged by PHPCS
Generic.WhiteSpace.DisallowTabIndent. Convert to spaces for consistency.includes/Intelligence/Services/Models/GeminiTwoDotFivePro.php (1)
6-6: Remove unused importThe
Modelclass is imported but not used in this file.-use WeDevs\Dokan\Intelligence\Services\Model;includes/Intelligence/Services/AIProviderInterface.php (1)
69-69: Fix documentation to match the generic parameterThe comment mentions "text models" but the method accepts any model type as a parameter.
- * @return bool True if text models are supported, false otherwise. + * @return bool True if models of the specified type are supported, false otherwise.includes/Intelligence/Services/Provider.php (1)
52-53: Clean up commented code.Remove the commented
array_findcode since it's not available in older PHP versions and the current implementation usingarray_filterworks correctly.- // $model = array_find( $models, fn( $model, $key ) => $model->get_id() === $model_id ); - // Using array_filter to find the model by ID + // Using array_filter to find the model by IDincludes/Intelligence/Manager.php (1)
149-166: Consider adding PHPDoc for the switch cases.The
get_type_prefixmethod would benefit from documenting why certain types have prefixes while text doesn't./** * Get the type prefix for the given generation type. * + * Text generation uses no prefix for backward compatibility, + * while other types use prefixes to namespace their settings. + * * @param string $type The type of generation (e.g., 'text', 'image', 'video'). * * @return string The prefix for the type. */ public function get_type_prefix( string $type ): string {
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (23)
includes/DependencyManagement/Providers/IntelligenceServiceProvider.php(2 hunks)includes/Intelligence/Admin/Settings.php(2 hunks)includes/Intelligence/Manager.php(2 hunks)includes/Intelligence/REST/AIRequestController.php(2 hunks)includes/Intelligence/Services/AIImageGenerationInterface.php(1 hunks)includes/Intelligence/Services/AIModelInterface.php(1 hunks)includes/Intelligence/Services/AIProviderInterface.php(1 hunks)includes/Intelligence/Services/AIServiceInterface.php(0 hunks)includes/Intelligence/Services/AITextGenerationInterface.php(1 hunks)includes/Intelligence/Services/BaseAIService.php(0 hunks)includes/Intelligence/Services/EngineFactory.php(0 hunks)includes/Intelligence/Services/Model.php(1 hunks)includes/Intelligence/Services/Models/GeminiTwoDotFiveFlash.php(1 hunks)includes/Intelligence/Services/Models/GeminiTwoDotFiveFlashLite.php(3 hunks)includes/Intelligence/Services/Models/GeminiTwoDotFivePro.php(1 hunks)includes/Intelligence/Services/Models/OpenAIChatGPTFourO.php(1 hunks)includes/Intelligence/Services/Models/OpenAIGPTFourO.php(1 hunks)includes/Intelligence/Services/Models/OpenAIGPTFourOMini.php(1 hunks)includes/Intelligence/Services/Models/OpenAIGPTFourTurbo.php(1 hunks)includes/Intelligence/Services/Models/OpenAIGPTThreeDotFiveTurbo.php(2 hunks)includes/Intelligence/Services/Provider.php(1 hunks)includes/Intelligence/Services/Providers/Gemini.php(1 hunks)includes/Intelligence/Services/Providers/OpenAI.php(1 hunks)
💤 Files with no reviewable changes (3)
- includes/Intelligence/Services/EngineFactory.php
- includes/Intelligence/Services/AIServiceInterface.php
- includes/Intelligence/Services/BaseAIService.php
🧰 Additional context used
🧬 Code Graph Analysis (2)
includes/Intelligence/Services/AIProviderInterface.php (4)
includes/Intelligence/Services/AIModelInterface.php (3)
get_id(20-20)get_title(27-27)get_description(34-34)includes/Intelligence/Services/Providers/OpenAI.php (4)
get_id(12-14)get_title(19-21)get_description(26-28)get_api_key_url(34-36)includes/Intelligence/Services/Providers/Gemini.php (4)
get_id(12-14)get_title(19-21)get_description(26-28)get_api_key_url(35-37)includes/Intelligence/Services/Provider.php (8)
get_id(25-25)get_title(30-30)get_description(35-35)get_api_key_url(37-37)get_models(42-44)get_model(49-63)get_default_model(68-72)has_model(79-90)
includes/Intelligence/Services/Models/OpenAIGPTFourOMini.php (2)
includes/Intelligence/Services/Models/OpenAIGPTThreeDotFiveTurbo.php (4)
OpenAIGPTThreeDotFiveTurbo(8-140)get_id(15-17)get_title(22-24)get_description(29-31)includes/Intelligence/Services/Model.php (3)
get_id(57-57)get_title(64-64)get_description(71-71)
🪛 PHPMD (2.15.0)
includes/Intelligence/REST/AIRequestController.php
94-94: Avoid using static access to class '\WeDevs\Dokan\Intelligence\Utils\PromptUtils' in method 'handle_request'. (Clean Code Rules)
(StaticAccess)
⏰ Context from checks skipped due to timeout of 90000ms (4)
- GitHub Check: e2e tests (2, 3)
- GitHub Check: e2e tests (3, 3)
- GitHub Check: e2e tests (1, 3)
- GitHub Check: api tests (1, 1)
🔇 Additional comments (20)
includes/Intelligence/Services/Models/OpenAIGPTFourO.php (1)
5-27: LGTM! Clean model implementation.The class correctly extends the base OpenAI model and properly overrides the metadata methods. The use of WordPress localization functions is appropriate, and the model ID follows OpenAI's naming convention.
includes/Intelligence/Services/AIModelInterface.php (1)
14-49: Excellent interface design with comprehensive model contract.This interface provides a well-thought-out contract for AI models with:
- Clear metadata methods for model identification and description
- Flexible
supports()method for checking generation type capabilities- Proper documentation with package and version information
- Clean method signatures with appropriate return types
The design supports the modular architecture goals effectively.
includes/Intelligence/Admin/Settings.php (5)
45-45: Excellent refactoring to dynamic provider management.The move from hardcoded providers to dynamic retrieval using the Manager is a great improvement that supports the new modular architecture.
48-54: Good addition of AI Product Info subsection.The new subsection provides clear organization for AI product generation features, aligning with the PR objectives for product image enhancement.
69-101: Clean dynamic field generation implementation.The dynamic generation of API key and model selection fields is well-implemented:
- Proper use of provider metadata
- Correct conditional field display logic
- Good use of modern PHP arrow functions
103-103: Good practice adding filter hook for extensibility.The addition of the
dokan_ai_settings_fieldsfilter allows for further customization of AI settings, which is excellent for extensibility.
59-67: Default engine change is safe for existing usersThe
default => 'openai'value is only used when no prior setting exists—any installation that has already selected “chatgpt” will continue using that stored value. We only see one hardcoded return of‘chatgpt-4o-latest’inincludes/Intelligence/Services/Models/OpenAIChatGPTFourO.php, which pertains to the model ID and does not affect the provider default. No migration strategy is required.includes/Intelligence/Services/Models/OpenAIChatGPTFourO.php (1)
5-12: Confirm model identifier accuracy
chatgpt-4o-latestis not an official model ID in OpenAI’s public docs (commonlygpt-4oor dated suffixes such asgpt-4o-2024-05-13).
If the back-end passes this literal string to the API, requests will fail with “model_not_found”.Please verify against the current OpenAI reference and adjust accordingly.
includes/Intelligence/Services/Models/OpenAIGPTFourOMini.php (1)
10-12: Validategpt-4o-miniavailabilityDouble-check that
gpt-4o-miniis accepted by the OpenAI endpoint; at time of writing it is still in limited beta.
If the ID is wrong, downstream 404/400 errors will occur.
Run an integration smoke test or feature flag the model until it is generally available.includes/Intelligence/Services/Models/OpenAIGPTFourTurbo.php (1)
10-12: Re-check the model namegpt-4-turboOpenAI’s stable alias was historically
gpt-4-turbo-preview; newer endpoints usegpt-4ovariants. Please confirm the exact string to avoid runtime failures.includes/Intelligence/Services/Models/GeminiTwoDotFivePro.php (1)
8-30: LGTM! Clean implementation of the Gemini 2.5 Pro modelThe class properly extends the base model and provides appropriate metadata through well-structured methods with proper localization.
includes/Intelligence/Services/AIProviderInterface.php (1)
14-72: Well-designed interface for AI providersThe interface provides a clean contract with comprehensive methods for provider metadata, model management, and type checking. The structure promotes extensibility and follows interface segregation principles.
includes/Intelligence/Services/Providers/Gemini.php (1)
30-32: Confirm the correct default Gemini model versionI didn’t find any local model implementations for a 2.5-series Gemini ID—only
get_default_model_id()returns'gemini-2.0-flash'. Please verify which Gemini version should be the default and:
- If you intend to switch to a 2.5 model, add or import the corresponding model classes in
includes/Intelligence/Services/Models/and updateget_default_model_id().- Otherwise, keep the default as
'gemini-2.0-flash', since no 2.5 models are present locally.includes/Intelligence/REST/AIRequestController.php (1)
78-96: Well-structured refactoring to use the new provider/model architectureThe implementation properly resolves providers and models based on configuration, with appropriate error handling for misconfiguration scenarios. The dynamic type support makes the system extensible.
includes/DependencyManagement/Providers/IntelligenceServiceProvider.php (1)
43-48: Clean refactoring of service registrationThe loop-based registration approach reduces code duplication and makes it easier to add new services in the future. Good application of DRY principle.
includes/Intelligence/Services/Models/OpenAIGPTThreeDotFiveTurbo.php (1)
12-39: LGTM! Well-structured metadata methods.The metadata methods are properly implemented with appropriate return values and follow the interface contract.
includes/Intelligence/Services/Provider.php (1)
42-137: Well-structured provider implementation with good extensibility.The provider class provides a solid foundation with:
- Proper use of filters for extensibility
- Clean separation of concerns
- Efficient model filtering and retrieval methods
- Proper hook registration pattern
includes/Intelligence/Services/Models/GeminiTwoDotFiveFlashLite.php (1)
113-115: Confirm thinkingConfig Behavior for Gemini 2.5 Flash-LiteSetting
'thinkingConfig' => [ 'thinkingBudget' => 0, ],turns off the model’s internal “thinking” phase for Gemini 2.5 Flash-Lite, yielding faster, lower-cost responses at the expense of deeper reasoning.
• File: includes/Intelligence/Services/Models/GeminiTwoDotFiveFlashLite.php (lines 113–115)
• Effect: disables all “thinking” tokens for this model
• Intended use case: simple or latency-sensitive scenariosIf you require more thorough reasoning, consider increasing
thinkingBudget(e.g., 512 or 1024). Otherwise, no changes are needed.includes/Intelligence/Services/Model.php (1)
1-206: Well-architected base model class.The abstract Model class provides an excellent foundation with:
- Clear separation of abstract and concrete methods
- Proper constants for generation types
- Comprehensive error handling
- Good use of WordPress filters for extensibility
The only issue is the typo mentioned in the previous comment.
includes/Intelligence/Manager.php (1)
1-167: Excellent Manager implementation with clear separation of concerns.The Manager class effectively handles:
- Multi-type AI engine management
- Provider discovery and filtering
- Type-specific configuration
- Extensibility through WordPress filters
Great architectural design that supports the new AI provider system.
- Fixed typo in method name `is_valid_api_kay` to `is_valid_api_key`. - Added parameter documentation for `has_model` method in `AIProviderInterface`. - Enhanced error handling for unsupported generation types in `AIRequestController`.
|
@mrabbani Bhai, I've resolved the issues and implemented the changes according to your suggestion. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
includes/Intelligence/REST/AIRequestController.php (2)
44-45: Use CREATABLE for POST endpointThis route should accept POST;
EDITABLEmaps to PUT/PATCH in WP REST. Switch toCREATABLE.- 'methods' => WP_REST_Server::EDITABLE, + 'methods' => WP_REST_Server::CREATABLE,
109-120: Return correct HTTP status codes from exceptions400 (bad request/misconfig) is currently turned into 403. Also 429 should return 429, not 401.
- } catch ( Exception $e ) { - if ( in_array( $e->getCode(), [ 401, 429 ], true ) ) { - return new WP_Error( - 'dokan_ai_service_error', - esc_html__( 'Something went wrong in the configuration. Kindly reach out to Marketplace Owner', 'dokan-lite' ), - [ 'status' => 401 ] - ); - } - return new WP_Error( - 'dokan_ai_service_error', - esc_html__( 'Service is not available due to some reason. Kindly reach out to Marketplace Owner', 'dokan-lite' ), - [ 'status' => 403 ] - ); - } + } catch ( Exception $e ) { + $code = (int) $e->getCode(); + $status = in_array( $code, [ 400, 401, 429 ], true ) ? $code : 500; + $message = in_array( $status, [ 400 ] , true ) + ? esc_html__( 'Invalid AI configuration. Kindly reach out to Marketplace Owner', 'dokan-lite' ) + : esc_html__( 'Service is not available due to some reason. Kindly reach out to Marketplace Owner', 'dokan-lite' ); + return new WP_Error( 'dokan_ai_service_error', $message, [ 'status' => $status ] ); + }
♻️ Duplicate comments (1)
includes/Intelligence/REST/AIRequestController.php (1)
95-105: Validate capability before dynamic dispatch (extend previous feedback)You added the
method_existscheck (good), but also verify the model actually supports the requested type to fail fast and avoid misleading 400s.- if ( ! method_exists( $model, $process_call ) ) { + if ( ( method_exists( $model, 'supports' ) && ! $model->supports( $type ) ) || ! method_exists( $model, $process_call ) ) { throw new Exception( // translators: %s: type of generation. sprintf( esc_html__( 'Model does not support %s generation.', 'dokan-lite' ), $type ), 400 ); }
🧹 Nitpick comments (1)
includes/Intelligence/Services/Model.php (1)
113-114: Fix docblock: return value is URL, not API key- * Retrieves the API url required. - * - * @return string The API key. + * Retrieves the API URL for the request. + * + * @return string The endpoint URL.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
includes/Intelligence/REST/AIRequestController.php(2 hunks)includes/Intelligence/Services/AIProviderInterface.php(1 hunks)includes/Intelligence/Services/Model.php(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- includes/Intelligence/Services/AIProviderInterface.php
🧰 Additional context used
🧬 Code graph analysis (2)
includes/Intelligence/REST/AIRequestController.php (6)
includes/Intelligence/Manager.php (2)
Manager(9-167)get_provider(100-108)includes/Intelligence/Services/Model.php (2)
Model(9-205)request(176-204)dokan.php (1)
dokan_get_container(79-83)includes/functions.php (1)
dokan_get_option(1014-1024)includes/Intelligence/Services/AIProviderInterface.php (1)
get_model(57-57)includes/Intelligence/Utils/PromptUtils.php (2)
PromptUtils(5-45)prepare_prompt(28-44)
includes/Intelligence/Services/Model.php (5)
includes/Intelligence/Services/AIModelInterface.php (5)
supports(48-48)get_provider_id(41-41)get_id(20-20)get_title(27-27)get_description(34-34)includes/Intelligence/Services/Provider.php (5)
register_hooks(119-121)enlist(131-137)get_id(25-25)get_title(30-30)get_description(35-35)includes/Intelligence/Services/Models/GeminiTwoDotFiveFlashLite.php (7)
get_provider_id(36-38)get_id(15-17)get_title(22-24)get_description(29-31)get_url(45-47)get_headers(54-58)get_payload(68-118)includes/Intelligence/Services/Models/OpenAIGPTThreeDotFiveTurbo.php (7)
get_provider_id(36-38)get_id(15-17)get_title(22-24)get_description(29-31)get_url(45-47)get_headers(54-59)get_payload(101-139)includes/functions.php (1)
dokan_get_option(1014-1024)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: e2e tests (2, 3)
- GitHub Check: e2e tests (3, 3)
- GitHub Check: api tests (1, 1)
- GitHub Check: e2e tests (1, 3)
🔇 Additional comments (3)
includes/Intelligence/Services/Model.php (3)
20-23: Confirm interfaces exist and are implemented by concrete models
AITextGenerationInterfaceandAIImageGenerationInterfacemust be in the same namespace and implemented by models that declare support. If any model advertises support without implementing,supports()will return false at runtime.
35-37: Provider-model enlist hook looks good
160-165: LGTM: API key validation fixed (typo addressed)
| $manager = dokan_get_container()->get( Manager::class ); | ||
| $prefix = $type === Model::SUPPORTS_TEXT ? '' : sanitize_key( $type ) . '_'; | ||
| $provider_id = dokan_get_option( 'dokan_ai_' . $prefix . 'engine', 'dokan_ai', '' ); | ||
| $model_id = dokan_get_option( 'dokan_ai_' . $prefix . $provider_id . '_model', 'dokan_ai', '' ); | ||
|
|
||
| if ( empty( $provider_id ) || empty( $model_id ) ) { | ||
| throw new Exception( | ||
| esc_html__( 'AI provider or model is not configured properly.', 'dokan-lite' ), | ||
| 400 | ||
| ); | ||
| } | ||
|
|
||
| $provider = $manager->get_provider( $provider_id ); | ||
| $model = $provider->get_model( $model_id ); | ||
| $prompt = PromptUtils::prepare_prompt( $args['field'], $prompt ); | ||
| $process_call = 'process_' . sanitize_key( $type ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Guard against null provider/model and propagate type to the model
get_provider() can return null; calling get_model() on null will fatal. Also ensure the model knows the requested generation type (needed for per-type API key prefixing).
- $manager = dokan_get_container()->get( Manager::class );
- $prefix = $type === Model::SUPPORTS_TEXT ? '' : sanitize_key( $type ) . '_';
+ $manager = dokan_get_container()->get( Manager::class );
+ $type = sanitize_key( $type );
+ $prefix = $manager->get_type_prefix( $type );
$provider_id = dokan_get_option( 'dokan_ai_' . $prefix . 'engine', 'dokan_ai', '' );
$model_id = dokan_get_option( 'dokan_ai_' . $prefix . $provider_id . '_model', 'dokan_ai', '' );
if ( empty( $provider_id ) || empty( $model_id ) ) {
throw new Exception(
esc_html__( 'AI provider or model is not configured properly.', 'dokan-lite' ),
400
);
}
- $provider = $manager->get_provider( $provider_id );
- $model = $provider->get_model( $model_id );
+ $provider = $manager->get_provider( $provider_id );
+ if ( ! $provider ) {
+ throw new Exception( esc_html__( 'Configured AI provider is unavailable.', 'dokan-lite' ), 400 );
+ }
+ $model = $provider->get_model( $model_id );
+ if ( ! $model ) {
+ throw new Exception( esc_html__( 'Configured AI model not found.', 'dokan-lite' ), 400 );
+ }
+ if ( method_exists( $model, 'set_generation_type' ) ) {
+ $model->set_generation_type( $type );
+ }Committable suggestion skipped: line range outside the PR's diff.
| $prompt = PromptUtils::prepare_prompt( $args['field'], $prompt ); | ||
| $process_call = 'process_' . sanitize_key( $type ); | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Ensure image prompts are prefixed with the required guidance
Acceptance criteria require image-generation prompts to be prefixed with a WooCommerce image instruction. Verify PromptUtils::get_personalized_prompt() includes an image-specific variant (e.g., for a product_image field) or add one.
🏁 Script executed:
#!/bin/bash
# Verify presence of image-specific prompt personalization
rg -nC2 -iP 'get_personalized_prompt|dokan_ai_get_prompt|product[_-]?image|image.*prompt' includesLength of output: 6490
🏁 Script executed:
#!/bin/bash
# Locate the AISupportedFields definition
find includes -type f -name 'AISupportedFields.php'Length of output: 49
🏁 Script executed:
#!/bin/bash
# Extract the get_supported_fields function contents for review
rg -nP 'public static function get_supported_fields' -C50 includes/Intelligence/Utils/AISupportedFields.phpLength of output: 981
Add image prompt personalization to AISupportedFields
- includes/Intelligence/Utils/AISupportedFields.php’s get_supported_fields only covers text fields (
post_title,post_excerpt,post_content). It must include an entry for the image field (e.g.product_image) with itspersonalized_promptset to the required WooCommerce image guidance. [mandatory update required]
🤖 Prompt for AI Agents
In includes/Intelligence/REST/AIRequestController.php around lines 94-96 and in
includes/Intelligence/Utils/AISupportedFields.php (update the
get_supported_fields method), the supported-fields list only has text fields;
add a new entry for the image field (e.g., product_image) in
get_supported_fields with keys matching existing entries (key/name/type) and set
personalized_prompt to the required WooCommerce image guidance text described in
the review; ensure the entry’s key matches how sanitize_key/type are used
elsewhere and include any help_text or validation flags used by other field
definitions so image requests are handled the same way as text fields.
| protected function get_type_prefix_for_generation(): string { | ||
| return $this->generation_type === self::SUPPORTS_TEXT ? '' : sanitize_key( $this->generation_type ) . '_'; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Expose a setter for generation type
Base class relies on $generation_type for API key prefixing. Provide a setter so callers (REST) can switch to image/video correctly.
protected function get_type_prefix_for_generation(): string {
return $this->generation_type === self::SUPPORTS_TEXT ? '' : sanitize_key( $this->generation_type ) . '_';
}
+
+ /**
+ * Set the current generation type (e.g., text, image).
+ */
+ public function set_generation_type( string $type ): void {
+ $type = sanitize_key( $type );
+ if ( array_key_exists( $type, $this->get_supports() ) ) {
+ $this->generation_type = $type;
+ }
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| protected function get_type_prefix_for_generation(): string { | |
| return $this->generation_type === self::SUPPORTS_TEXT ? '' : sanitize_key( $this->generation_type ) . '_'; | |
| } | |
| protected function get_type_prefix_for_generation(): string { | |
| return $this->generation_type === self::SUPPORTS_TEXT ? '' : sanitize_key( $this->generation_type ) . '_'; | |
| } | |
| /** | |
| * Set the current generation type (e.g., text, image). | |
| */ | |
| public function set_generation_type( string $type ): void { | |
| $type = sanitize_key( $type ); | |
| if ( array_key_exists( $type, $this->get_supports() ) ) { | |
| $this->generation_type = $type; | |
| } | |
| } |
🤖 Prompt for AI Agents
In includes/Intelligence/Services/Model.php around lines 150-152, add a public
setter method to expose and update the protected $generation_type so callers (eg
REST handlers) can switch types; implement a method like
set_generation_type(string $type): void that validates the incoming $type
against the class' supported generation type constants (e.g.
self::SUPPORTS_TEXT, self::SUPPORTS_IMAGE, self::SUPPORTS_VIDEO) and assigns it
to $this->generation_type (optionally sanitize/normalize the value and
throw/return an error on invalid input).
| protected function request( string $prompt, array $args = [] ): array { | ||
| if ( ! $this->is_valid_api_key() ) { | ||
| throw new Exception( esc_html__( 'API key is not configured', 'dokan-lite' ) ); | ||
| } | ||
| // Make the request | ||
| $response = wp_remote_post( | ||
| $this->get_url(), [ | ||
| 'headers' => $this->get_headers(), | ||
| 'body' => wp_json_encode( $this->get_payload( $prompt, $args ) ), | ||
| 'timeout' => 60, | ||
| ] | ||
| ); | ||
| $codes = [ | ||
| 'invalid_api_key' => 401, | ||
| 'insufficient_quota' => 429, | ||
| ]; | ||
| if ( is_wp_error( $response ) ) { | ||
| throw new Exception( esc_html( $response->get_error_message() ), $codes[ $response->get_error_code() ] ?? 500 ); // phpcs:ignore | ||
| } | ||
|
|
||
| $response_body = wp_remote_retrieve_body( $response ); | ||
| $data = json_decode( $response_body, true ); | ||
|
|
||
| if ( isset( $data['error'] ) ) { | ||
| throw new Exception( esc_html( $data['error']['message'] ), $codes[ $data['error']['code'] ] ?? 500 ); // phpcs:ignore | ||
| } | ||
|
|
||
| return $data; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Harden response parsing and improve resilience
Handle invalid/non-JSON responses and allow timeout override via filter.
- $response = wp_remote_post(
- $this->get_url(), [
- 'headers' => $this->get_headers(),
- 'body' => wp_json_encode( $this->get_payload( $prompt, $args ) ),
- 'timeout' => 60,
- ]
- );
+ $response = wp_remote_post(
+ $this->get_url(),
+ [
+ 'headers' => $this->get_headers(),
+ 'body' => wp_json_encode( $this->get_payload( $prompt, $args ) ),
+ 'timeout' => (int) apply_filters( 'dokan_ai_http_timeout', 60, $this ),
+ ]
+ );
@@
- $response_body = wp_remote_retrieve_body( $response );
- $data = json_decode( $response_body, true );
+ $response_body = wp_remote_retrieve_body( $response );
+ $data = json_decode( $response_body, true );
+ if ( json_last_error() !== JSON_ERROR_NONE ) {
+ throw new Exception( esc_html__( 'Invalid response from AI provider', 'dokan-lite' ), 502 );
+ }|
@mrabbani found an issue with updating the image on insert after generation. talked to @shohag121 bhai; it’s known to him. Overall, good with VRIA AI. To test the other model, need api key of Gemini and OpenAI. @jamil-mahmud |
…consistency - Converted `var` declarations to `const/let` to align with modern JavaScript standards. - Improved formatting and spacing for better clarity. - Replaced function expressions with ES6 method shorthand where applicable. - Added consistent use of arrow functions and parentheses for better readability.
All Submissions:
Changes proposed in this Pull Request:
Related Pull Request(s)
Closes
How to test the changes in this Pull Request:
Changelog entry
No changelog is needed.
Before Changes
Describe the issue before changes with screenshots(s).
After Changes
Describe the issue after changes with screenshot(s).
Feature Video (optional)
Link of detailed video if this PR is for a feature.
PR Self Review Checklist:
FOR PR REVIEWER ONLY:
Summary by CodeRabbit
New Features
Improvements
Bug Fixes
Refactor