Skip to content
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

AI Module(Simplified Version) #2555

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open

Conversation

kzamanbd
Copy link
Contributor

@kzamanbd kzamanbd commented Feb 4, 2025

All Submissions:

  • My code follow the WordPress' coding standards
  • My code satisfies feature requirements
  • My code is tested
  • My code passes the PHPCS tests
  • My code has proper inline documentation
  • I've included related pull request(s) (optional)
  • I've included developer documentation (optional)
  • I've added proper labels to this pull request

Changes proposed in this Pull Request:

Related Pull Request(s)

  • Full PR Link

Closes

  • Closes #

How to test the changes in this Pull Request:

  • Steps or issue link

Changelog entry

  1. Core AI Features: Basic text generation, summarization, and Q&A.
  2. Fast and Efficient: Optimized for quick responses with minimal latency.
  3. AI Models Supported: ChatGPT & Gemini integrated for enhanced responses.

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:

  • Code is not following code style guidelines
  • Bad naming: make sure you would understand your code if you read it a few months from now.
  • KISS: Keep it simple, Sweetie (not stupid!).
  • DRY: Don't Repeat Yourself.
  • Code that is not readable: too many nested 'if's are a bad sign.
  • Performance issues
  • Complicated constructions that need refactoring or comments: code should almost always be self-explanatory.
  • Grammar errors.

FOR PR REVIEWER ONLY:

As a reviewer, your feedback should be focused on the idea, not the person. Seek to understand, be respectful, and focus on constructive dialog.

As a contributor, your responsibility is to learn from suggestions and iterate your pull request should it be needed based on feedback. Seek to collaborate and produce the best possible contribution to the greater whole.

  • Correct — Does the change do what it’s supposed to? ie: code 100% fulfilling the requirements?
  • Secure — Would a nefarious party find some way to exploit this change? ie: everything is sanitized/escaped appropriately for any SQL or XSS injection possibilities?
  • Readable — Will your future self be able to understand this change months down the road?
  • Elegant — Does the change fit aesthetically within the overall style and architecture?

Summary by CodeRabbit

  • New Features

    • Introduced AI-powered content generation, enabling users to generate and insert content through a new interactive modal.
    • Expanded support for multiple AI engines, offering more options for high-quality content.
  • Chores/Dependencies

    • Upgraded core dependencies and libraries for enhanced performance and maintenance.
  • Style

    • Refined UI styling for modal interactions, delivering a smoother and modern user experience.

Copy link
Contributor

coderabbitai bot commented Feb 4, 2025

Walkthrough

This pull request integrates AI capabilities into the project by adding new dependency management classes and services alongside a dedicated REST controller and API endpoints. Key additions include an IntelligenceServiceProvider with registration logic, several intelligence service classes (including model-specific implementations), and a Manager to orchestrate AI configuration. A new React component and associated modules enable a UI for prompt input and content generation. Additional utility modules, type declarations, and dependency updates support the expanded functionality.

Changes

File(s) Change Summary
includes/DependencyManagement/Providers/IntelligenceServiceProvider.php
includes/DependencyManagement/Providers/ServiceProvider.php
Introduces the new IntelligenceServiceProvider for AI-related dependency management and updates the boot method in ServiceProvider to register it.
includes/Intelligence/Manager.php
includes/Intelligence/REST/AIRequestController.php
Adds the Manager class for handling AI configurations and a new REST controller for processing AI generation requests.
includes/Intelligence/Services/AIResponseServiceInterface.php
includes/Intelligence/Services/AbstractAIService.php
includes/Intelligence/Services/ChatgptResponseService.php
includes/Intelligence/Services/GeminiResponseService.php
includes/Intelligence/Services/ServiceLocator.php
Implements the AI service infrastructure including a response service interface, an abstract request-handling class, model-specific service classes, and a service locator to resolve the appropriate AI service.
includes/Intelligence/Utils/AISupportedFields.php
includes/Intelligence/Utils/PromptUtils.php
Introduces utilities for retrieving supported fields and preparing personalized prompts for AI services.
src/intelligence/components/DokanAI.tsx
src/intelligence/main.tsx
src/intelligence/styles/modal.css
src/intelligence/types/index.ts
src/intelligence/utils/api.ts
src/intelligence/utils/dom.ts
Adds a React component for the AI modal interface, entry point initialization, associated CSS styling, type definitions, API utilities for prompt submission, and DOM updating functions to integrate with WordPress fields.
package.json
webpack.config.js
Updates Tailwind CSS version and adds new dependencies (typescript, @getdokan/dokan-ui, @wordpress/element) while configuring Webpack for TypeScript and JSX file resolution along with a new entry point.

Sequence Diagram(s)

sequenceDiagram
    participant U as User
    participant UI as DokanAI Component
    participant AP as API Module (generateAiContent)
    participant RC as AIRequestController
    participant SL as ServiceLocator
    participant AS as AI Service (ChatGPT / Gemini)
    
    U->>UI: Enter prompt and submit
    UI->>AP: Call generateAiContent(prompt, field)
    AP->>RC: Send POST request to /dokan/v1/ai/generate
    RC->>SL: Resolve service based on AI engine
    SL->>AS: Instantiate appropriate AI service
    AS->>AS: Process prompt and send API request
    AS-->>RC: Return generated content or error
    RC-->>AP: Return REST response with content
    AP-->>UI: Deliver AI-generated content
    UI->>U: Display generated response in modal
Loading

Possibly related PRs

Suggested labels

Needs: Dev Review, Test Automation

Poem

I'm a little rabbit with a happy code beat,
Hopping through new classes with nimble little feet.
AI services sprout like carrots in the ground,
From REST routes to React, creativity is found.
With each new function and tag so bright,
I celebrate these changes deep into the night! 🐰

Code so fresh, it makes my whiskers twitch in delight!

Tip

🌐 Web search-backed reviews and chat
  • We have enabled web search-based reviews and chat for all users. This feature allows CodeRabbit to access the latest documentation and information on the web.
  • You can disable this feature by setting web_search: false in the knowledge_base settings.
  • Please share any feedback in the Discord discussion.
✨ Finishing Touches
  • 📝 Generate Docstrings (Beta)

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@kzamanbd kzamanbd requested a review from mrabbani February 4, 2025 06:44
@kzamanbd kzamanbd added the Needs: Dev Review It requires a developer review and approval label Feb 4, 2025
@kzamanbd kzamanbd self-assigned this Feb 4, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 16

🧹 Nitpick comments (18)
includes/Intelligence/Services/AbstractAIService.php (3)

7-20: Consider adding a descriptive class-level docblock and constructor documentation.

Currently, there's no high-level docblock explaining the purpose and usage of this abstract class. Adding a short summary can help maintainers and consumers quickly understand its responsibilities. Similarly, documenting what load_configuration is expected to do will reduce confusion for subclass implementers.


29-34: Use consistent error handling patterns for API key checks.

While validate_api_key returns a boolean, your other methods often return WP_Error objects if critical data is missing. Consider returning a WP_Error here or merging validation steps into a single place to keep error-handling consistent.


42-56: Add JSON headers and a timeout to wp_remote_post.

When sending JSON via wp_remote_post, it's best practice to include 'Content-Type' => 'application/json'. Also consider a short timeout to prevent lengthy stalls, for instance: 'timeout' => 15.

 'headers' => array_merge(
+    [ 'Content-Type' => 'application/json' ],
     $params['headers'] ?? []
 ),
 'body' => wp_json_encode( $params['data'] ),
+ 'timeout' => 15,
src/intelligence/types/index.ts (1)

1-5: Add JSDoc documentation for the Field interface.

Consider adding comprehensive JSDoc documentation to explain:

  • The purpose of the Field interface
  • Expected values and use cases for each property
  • Specific meaning of 'section' type
+/**
+ * Represents a field configuration for AI content generation
+ * @interface Field
+ * @property {string} id - Unique identifier for the field
+ * @property {string} title - Display title of the field
+ * @property {'input' | 'section'} type - Type of the field:
+ *   - 'input': For user input fields
+ *   - 'section': For content section containers
+ */
 export interface Field {
     id: string;
     title: string;
     type: 'input' | 'section'; // Update types based on API response
 }
includes/Intelligence/Services/AIResponseServiceInterface.php (3)

13-13: Add return type hint for process method.

The method should specify its return type for better type safety.

-    public function process( string $prompt, $payload = null );
+    public function process( string $prompt, $payload = null ): mixed;

15-15: Add parameter and return type hints for send_request method.

The method should specify parameter types and return type for better type safety.

-    public function send_request( array $params );
+    public function send_request( array $params ): mixed;

5-22: Enhance interface documentation.

Consider adding comprehensive PHPDoc blocks for each method to explain:

  • Expected parameter values
  • Return value format
  • Possible exceptions
 interface AIResponseServiceInterface {
+    /**
+     * Process the AI request and return a response.
+     *
+     * @param string $prompt The input prompt for the AI.
+     * @param mixed|null $payload Optional additional data.
+     * @return mixed The response from the AI.
+     * @throws \Exception When AI processing fails.
+     */
     public function process( string $prompt, $payload = null ): mixed;

+    /**
+     * Send a request to the AI service.
+     *
+     * @param array $params Request parameters.
+     * @return mixed Response from the AI service.
+     * @throws \Exception When request fails.
+     */
     public function send_request( array $params ): mixed;

+    /**
+     * Set the API key for the AI service.
+     *
+     * @throws \Exception When API key is invalid or missing.
+     */
     public function set_api_key(): void;

+    /**
+     * Get available AI models.
+     *
+     * @return array List of available models.
+     */
     public function get_models(): array;

+    /**
+     * Validate the API key.
+     *
+     * @return bool True if API key is valid, false otherwise.
+     */
     public function validate_api_key(): bool;
 }
includes/Intelligence/Utils/PromptUtils.php (2)

12-20: Add input validation and caching for supported fields.

The method could benefit from input validation and caching of supported fields to improve performance.

+    private static $supported_fields_cache = null;
+
     public static function get_personalized_prompt( string $id ): ?string {
-        foreach ( AISupportedFields::get_supported_fields() as $field ) {
+        if ( empty( $id ) ) {
+            return null;
+        }
+
+        if ( self::$supported_fields_cache === null ) {
+            self::$supported_fields_cache = AISupportedFields::get_supported_fields();
+        }
+
+        foreach ( self::$supported_fields_cache as $field ) {
             if ( $field['id'] === $id ) {
                 return $field['personalized_prompt'];
             }
         }
-
         return null; // Return null if the key is not found
     }

28-36: Improve string concatenation and validation in prepare_prompt.

Consider using sprintf for string formatting and add input validation.

     public static function prepare_prompt( string $id, string $prompt ): string {
+        if ( empty( $id ) || empty( $prompt ) ) {
+            throw new \InvalidArgumentException( 'ID and prompt cannot be empty' );
+        }
+
         $personalized_prompt = self::get_personalized_prompt( $id );
 
         if ( $personalized_prompt ) {
-            return $personalized_prompt . $prompt;
+            return sprintf( '%s %s', $personalized_prompt, $prompt );
         }
 
         return $prompt;
     }
includes/DependencyManagement/Providers/IntelligenceServiceProvider.php (1)

34-44: Consider adding error handling for service instantiation.

The service instantiation could fail if the class constructor throws an exception.

 public function register(): void {
     foreach ( $this->services as $service ) {
         $definition = $this->getContainer()
             ->addShared(
                 $service, function () use ( $service ) {
-                    return new $service();
+                    try {
+                        return new $service();
+                    } catch ( \Exception $e ) {
+                        error_log( sprintf( 'Failed to instantiate service %s: %s', $service, $e->getMessage() ) );
+                        return null;
+                    }
                 }
             );
         $this->add_tags( $definition, self::TAGS );
     }
 }
includes/Intelligence/Utils/AISupportedFields.php (1)

7-48: LGTM! Well-structured field definitions with proper internationalization.

The implementation follows WordPress coding standards with proper translation functions and provides extensibility through filters.

However, consider adding PHPDoc for the method to document the return type structure.

+    /**
+     * Get the list of AI-supported fields.
+     *
+     * @return array{
+     *   id: string,
+     *   personalized_prompt: string,
+     *   title: string,
+     *   type: 'input'|'section'
+     * }[] List of supported fields.
+     */
     public static function get_supported_fields(): array {
includes/Intelligence/Services/ChatgptResponseService.php (1)

33-67: Add request timeout and rate limiting.

The process method should include timeout configuration and rate limiting to prevent API abuse.

 $params = [
     'url' => self::API_URL,
     'headers' => [
         'Authorization' => 'Bearer ' . $this->api_key,
         'Content-Type' => 'application/json',
     ],
     'data' => $request_data,
+    'timeout' => 30,
 ];
includes/Intelligence/Services/GeminiResponseService.php (1)

43-56: Consider making safety settings configurable.

The safety settings and generation config are hardcoded. Consider making these configurable through WordPress options.

+'safetySettings' => apply_filters('dokan_ai_gemini_safety_settings', [
     [
         'category' => 'HARM_CATEGORY_DANGEROUS_CONTENT',
         'threshold' => 'BLOCK_ONLY_HIGH',
     ],
 ]),
src/intelligence/utils/dom.ts (2)

1-5: Improve type safety for tinymce declaration.

The any type for tinymce should be replaced with a proper type definition.

-        tinymce: any;
+        tinymce: {
+            get: (id: string) => TinyMCEEditor | null;
+        };

47-63: Enhance element selection strategy.

The current selector strategy might be too broad. Consider adding data attributes specifically for AI field targeting.

 const selectors = [
+    `[data-dokan-ai-field="${fieldId}"]`, // Preferred selector
     `input[name="${fieldId}"]`,
     `#${fieldId}`,
     `textarea[name="${fieldId}"]`,
     `[data-id="${fieldId}"]`,
 ];
src/intelligence/components/DokanAI.tsx (1)

7-240: Wrap component with error boundary.

Consider wrapping the component with an error boundary to gracefully handle runtime errors.

Create an error boundary component:

class AIErrorBoundary extends React.Component {
    state = { hasError: false };
    
    static getDerivedStateFromError(error) {
        return { hasError: true };
    }
    
    render() {
        if (this.state.hasError) {
            return <div>Something went wrong with AI generation.</div>;
        }
        return this.props.children;
    }
}

// Usage:
export default function WrappedDokanAI(props) {
    return (
        <AIErrorBoundary>
            <DokanAI {...props} />
        </AIErrorBoundary>
    );
}
src/intelligence/styles/modal.css (2)

22-24: Consider using CSS custom properties for z-index management.

Using a high z-index value directly can lead to z-index wars. Consider using CSS custom properties for better maintainability.

+:root {
+  --dokan-modal-z-index: 1000;
+}
 body:has(.dokan-ai-modal) .z-10[aria-modal="true"][data-headlessui-state="open"] {
-    z-index: 1000;
+    z-index: var(--dokan-modal-z-index);
 }

19-21: Consider more specific selector for padding override.

The current selector might affect unrelated elements. Consider using a more specific selector.

-body:has(.dokan-ai-prompt-icon) .mce-path {
+.dokan-ai-container .mce-path {
     padding: 10px;
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e743934 and 8243543.

⛔ Files ignored due to path filters (2)
  • assets/images/dokan-ai.svg is excluded by !**/*.svg
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (19)
  • includes/DependencyManagement/Providers/IntelligenceServiceProvider.php (1 hunks)
  • includes/DependencyManagement/Providers/ServiceProvider.php (1 hunks)
  • includes/Intelligence/Manager.php (1 hunks)
  • includes/Intelligence/REST/AIRequestController.php (1 hunks)
  • includes/Intelligence/Services/AIResponseServiceInterface.php (1 hunks)
  • includes/Intelligence/Services/AbstractAIService.php (1 hunks)
  • includes/Intelligence/Services/ChatgptResponseService.php (1 hunks)
  • includes/Intelligence/Services/GeminiResponseService.php (1 hunks)
  • includes/Intelligence/Services/ServiceLocator.php (1 hunks)
  • includes/Intelligence/Utils/AISupportedFields.php (1 hunks)
  • includes/Intelligence/Utils/PromptUtils.php (1 hunks)
  • package.json (2 hunks)
  • src/intelligence/components/DokanAI.tsx (1 hunks)
  • src/intelligence/main.tsx (1 hunks)
  • src/intelligence/styles/modal.css (1 hunks)
  • src/intelligence/types/index.ts (1 hunks)
  • src/intelligence/utils/api.ts (1 hunks)
  • src/intelligence/utils/dom.ts (1 hunks)
  • webpack.config.js (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: e2e tests (3, 3)
  • GitHub Check: e2e tests (2, 3)
  • GitHub Check: api tests (1, 1)
  • GitHub Check: e2e tests (1, 3)
🔇 Additional comments (10)
package.json (2)

36-37: Updated TailwindCSS and Added TypeScript Dependency

  • The TailwindCSS dependency is updated from ^3.3.3 to ^3.4.17. Please ensure that any potential breaking changes or required configuration updates with the new version are addressed.
  • The addition of TypeScript ("typescript": "^5.7.3") as a dev dependency is a solid move to enhance type safety, especially with the new AI module components.

54-55: New Production Dependencies Introduced

  • The new dependencies "@getdokan/dokan-ui": "^1.0.19" and "@wordpress/element": "^6.17.0" are now included. Verify that these libraries integrate well with the existing codebase, and that their APIs align with the new UI components and AI module requirements.
includes/Intelligence/Services/AbstractAIService.php (1)

58-78: Guard against malformed or null response data.

json_decode can return null if the body isn't valid JSON. It's good practice to check for null and handle the case where decoding fails, returning a clear WP_Error.

includes/Intelligence/REST/AIRequestController.php (1)

80-109: Verify AI service type and guard against oversized inputs.

Before calling $service->process(...), confirm that $service implements the required interface. Additionally, parsing a very large prompt or payload can degrade performance, so consider limiting payload size or adding additional checks.

includes/Intelligence/Manager.php (2)

30-38: Clean separation of settings vs. configured actions is well-structured.

The conditional branching to either load settings or fully enable AI actions is straightforward and maintainable. Nice job keeping the logic simple.


45-61: Confirm presence and validity of API keys.

When checking dokan_ai_{engine}_api_key, consider validating token format or length. If any new engines are added, update this check logic to maintain consistency.

includes/DependencyManagement/Providers/IntelligenceServiceProvider.php (1)

9-18: LGTM! Well-structured service provider implementation.

The class follows SOLID principles with clear separation of concerns and good documentation.

includes/DependencyManagement/Providers/ServiceProvider.php (1)

65-65: LGTM! Consider load order implications.

The addition of IntelligenceServiceProvider looks good. Ensure it doesn't have dependencies on services from other providers that might not be registered yet.

✅ Verification successful

Service Provider Registration Looks Correct—Load Order Appears Unaffected

The IntelligenceServiceProvider registers its Manager service without relying on other providers’ services, so there aren’t any load order concerns evident in the current implementation. Just ensure that if additional dependencies are added in the future, they’re loaded appropriately.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for service dependencies
ast-grep --pattern 'class IntelligenceServiceProvider {
  $$$
  public function register() {
    $$$
  }
  $$$
}'

Length of output: 115


Script:

#!/bin/bash
# Search for the class definition of IntelligenceServiceProvider using rg
echo ">>> Searching for 'class IntelligenceServiceProvider' occurrences:"
rg -n "class\s\+IntelligenceServiceProvider" .

echo ""
# Show the context around the IntelligenceServiceProvider class definition to inspect its register method
echo ">>> Showing context for IntelligenceServiceProvider (first 50 lines after definition):"
rg -n "class\s\+IntelligenceServiceProvider" -A 50

echo ""
# Additionally, search for any call to the register method within files mentioning IntelligenceServiceProvider
echo ">>> Searching for 'function register(' within files that mention IntelligenceServiceProvider:"
rg -n "class\s\+IntelligenceServiceProvider" -A 100 | rg -n "function\s\+register\s*\("

Length of output: 748


Script:

#!/bin/bash
# First, search for any files named IntelligenceServiceProvider.php in the repository
echo ">>> Searching for IntelligenceServiceProvider.php files:"
fd -HI "IntelligenceServiceProvider\.php"

echo ""
# If any files are found, display their contents (limited to the first 200 lines for brevity)
echo ">>> Displaying contents of IntelligenceServiceProvider.php (first 200 lines):"
fd -HI "IntelligenceServiceProvider\.php" -x head -n 200 {}

Length of output: 1976

webpack.config.js (2)

61-62: LGTM! Entry point correctly configured.

The new entry point for the AI module is properly integrated into the webpack configuration.


75-75: LGTM! TypeScript support properly configured.

The resolve.extensions array correctly includes TypeScript file extensions (.ts, .tsx).

Comment on lines +56 to +58
public function get_items_permissions_check( $request ): bool {
return true;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Restricting the permission callback is strongly recommended.

Granting unconditional access (always returning true) may expose the endpoint to unauthorized users. Implement capability checks or role restrictions to secure this route.

Comment on lines +60 to +78
public function get_request_args(): array {
return [
'prompt' => [
'type' => 'string',
'required' => true,
'description' => __( 'Prompt to process', 'dokan-lite' ),
],
'id' => [ // Added id parameter
'type' => 'string',
'required' => true,
'description' => __( 'ID of the field for personalized prompt', 'dokan-lite' ),
],
'payload' => [
'type' => 'array',
'required' => false,
'description' => __( 'Optional data payload', 'dokan-lite' ),
],
];
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Enhance request argument validation and sanitization.

Although 'prompt' and 'id' are declared as strings, consider sanitizing them. Also, add length or character checks if large or special inputs can harm performance or cause security issues (e.g., injection attempts).

Comment on lines +124 to +202
public function render_ai_settings( array $settings_fields ): array {
$gpt_response_service = new ChatgptResponseService();
$gemini_response_service = new GeminiResponseService();

$chatgpt_models = $gpt_response_service->get_models();
$gemini_models = $gemini_response_service->get_models();

$settings_fields['dokan_ai'] = [
'dokan_ai_engine' => [
'name' => 'dokan_ai_engine',
'label' => __( 'Engine', 'dokan-lite' ),
'type' => 'select',
'options' => $this->engines,
'desc' => __( 'Select AI engine', 'dokan-lite' ),
'default' => 'chatgpt',
],
'dokan_ai_chatgpt_model' => [
'name' => 'dokan_ai_chatgpt_model',
'label' => __( 'ChatGPT Model', 'dokan-lite' ),
'type' => 'select',
'options' => $chatgpt_models,
'desc' => __( 'Select your model', 'dokan-lite' ),
'default' => 'gpt-3.5-turbo',
'show_if' => [
'dokan_ai_engine' => [
'equal' => 'chatgpt',
],
],
],
'dokan_ai_gemini_model' => [
'name' => 'dokan_ai_gemini_model',
'label' => __( 'Gemini Model', 'dokan-lite' ),
'type' => 'select',
'options' => $gemini_models,
'desc' => __( 'Select your model', 'dokan-lite' ),
'default' => 'gemini-1.5-flash',
'show_if' => [
'dokan_ai_engine' => [
'equal' => 'gemini',
],
],
],
'dokan_ai_gemini_api_key' => [
'name' => 'dokan_ai_gemini_api_key',
'label' => __( 'Gemini API Key', 'dokan-lite' ),
'type' => 'text',
'desc' => __( 'Enter your API key', 'dokan-lite' ),
'default' => '',
'secret_text' => true,
'show_if' => [
'dokan_ai_engine' => [
'equal' => 'gemini',
],
],
],
'dokan_ai_chatgpt_api_key' => [
'name' => 'dokan_ai_chatgpt_api_key',
'label' => __( 'ChatGPT API Key', 'dokan-lite' ),
'type' => 'text',
'desc' => __( 'Enter your API key', 'dokan-lite' ),
'default' => '',
'secret_text' => true,
'show_if' => [
'dokan_ai_engine' => [
'equal' => 'chatgpt',
],
],
],
'dokan_ai_max_tokens_for_marketplace' => [
'name' => 'dokan_ai_max_tokens_for_marketplace',
'label' => __( 'Max Output Tokens for Marketplace', 'dokan-lite' ),
'type' => 'number',
'desc' => __( 'Set the maximum number of tokens for marketplace.', 'dokan-lite' ),
'default' => '200',
],
];

return $settings_fields;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Align default tokens in the UI with the localized script.

In the fields 'dokan_ai_max_tokens_for_marketplace', the default is 200, yet 'max_tokens' => ... '250' is used in the localized script. This can confuse users. Synchronize the defaults for consistency.

- 'dokan_ai_max_tokens_for_marketplace' => [
-     'default' => '200',
- ],
+ 'dokan_ai_max_tokens_for_marketplace' => [
+     'default' => '250',
+ ],

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +209 to +245
public function enqueue_ai_assets() {
if ( ! dokan_is_seller_dashboard() ) {
return;
}

wp_register_style(
'dokan-ai-style',
DOKAN_PLUGIN_ASSEST . '/css/dokan-intelligence.css',
[],
filemtime( DOKAN_DIR . '/assets/css/dokan-intelligence.css' )
);

wp_register_script(
'dokan-ai-script',
DOKAN_PLUGIN_ASSEST . '/js/dokan-intelligence.js',
[ 'wp-element', 'wp-i18n', 'wp-api-fetch' ],
filemtime( DOKAN_DIR . '/assets/js/dokan-intelligence.js' ),
true
);

wp_enqueue_style( 'dokan-ai-style' );
wp_enqueue_script( 'dokan-ai-script' );

$supported_fields = AISupportedFields::get_supported_fields();

$settings = [
'engine' => dokan_get_option( 'dokan_ai_engine', 'dokan_ai', 'chatgpt' ),
'gemini_model' => dokan_get_option( 'dokan_ai_gemini_model', 'dokan_ai', 'gemini-1.5-flash' ),
'chatgpt_model' => dokan_get_option( 'dokan_ai_chatgpt_model', 'dokan_ai', 'gpt-3.5-turbo' ),
'temperature' => dokan_get_option( 'dokan_ai_temperature', 'dokan_ai', '0.7' ),
'max_tokens' => dokan_get_option( 'dokan_ai_max_tokens_for_marketplace', 'dokan_ai', '250' ),
'is_configured' => true,
'fields' => $supported_fields,
];

wp_localize_script( 'dokan-ai-script', 'dokanAiSettings', $settings );
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Ensure 'is_configured' flag reflects actual status.

Even if $this->is_ai_configured is false, 'is_configured' => true is set in dokanAiSettings. Consider referencing $this->is_ai_configured directly to avoid confusion or UI misrepresentation.

- 'is_configured' => true,
+ 'is_configured' => $this->is_ai_configured,
📝 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.

Suggested change
public function enqueue_ai_assets() {
if ( ! dokan_is_seller_dashboard() ) {
return;
}
wp_register_style(
'dokan-ai-style',
DOKAN_PLUGIN_ASSEST . '/css/dokan-intelligence.css',
[],
filemtime( DOKAN_DIR . '/assets/css/dokan-intelligence.css' )
);
wp_register_script(
'dokan-ai-script',
DOKAN_PLUGIN_ASSEST . '/js/dokan-intelligence.js',
[ 'wp-element', 'wp-i18n', 'wp-api-fetch' ],
filemtime( DOKAN_DIR . '/assets/js/dokan-intelligence.js' ),
true
);
wp_enqueue_style( 'dokan-ai-style' );
wp_enqueue_script( 'dokan-ai-script' );
$supported_fields = AISupportedFields::get_supported_fields();
$settings = [
'engine' => dokan_get_option( 'dokan_ai_engine', 'dokan_ai', 'chatgpt' ),
'gemini_model' => dokan_get_option( 'dokan_ai_gemini_model', 'dokan_ai', 'gemini-1.5-flash' ),
'chatgpt_model' => dokan_get_option( 'dokan_ai_chatgpt_model', 'dokan_ai', 'gpt-3.5-turbo' ),
'temperature' => dokan_get_option( 'dokan_ai_temperature', 'dokan_ai', '0.7' ),
'max_tokens' => dokan_get_option( 'dokan_ai_max_tokens_for_marketplace', 'dokan_ai', '250' ),
'is_configured' => true,
'fields' => $supported_fields,
];
wp_localize_script( 'dokan-ai-script', 'dokanAiSettings', $settings );
}
public function enqueue_ai_assets() {
if ( ! dokan_is_seller_dashboard() ) {
return;
}
wp_register_style(
'dokan-ai-style',
DOKAN_PLUGIN_ASSEST . '/css/dokan-intelligence.css',
[],
filemtime( DOKAN_DIR . '/assets/css/dokan-intelligence.css' )
);
wp_register_script(
'dokan-ai-script',
DOKAN_PLUGIN_ASSEST . '/js/dokan-intelligence.js',
[ 'wp-element', 'wp-i18n', 'wp-api-fetch' ],
filemtime( DOKAN_DIR . '/assets/js/dokan-intelligence.js' ),
true
);
wp_enqueue_style( 'dokan-ai-style' );
wp_enqueue_script( 'dokan-ai-script' );
$supported_fields = AISupportedFields::get_supported_fields();
$settings = [
'engine' => dokan_get_option( 'dokan_ai_engine', 'dokan_ai', 'chatgpt' ),
'gemini_model' => dokan_get_option( 'dokan_ai_gemini_model', 'dokan_ai', 'gemini-1.5-flash' ),
'chatgpt_model' => dokan_get_option( 'dokan_ai_chatgpt_model', 'dokan_ai', 'gpt-3.5-turbo' ),
'temperature' => dokan_get_option( 'dokan_ai_temperature', 'dokan_ai', '0.7' ),
'max_tokens' => dokan_get_option( 'dokan_ai_max_tokens_for_marketplace', 'dokan_ai', '250' ),
'is_configured' => $this->is_ai_configured,
'fields' => $supported_fields,
];
wp_localize_script( 'dokan-ai-script', 'dokanAiSettings', $settings );
}

Comment on lines +25 to +27
// @ts-ignore
const content = data.response || data;
return content || __( 'No content generated', 'dokan' );
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Remove @ts-ignore and improve type safety.

Instead of using @ts-ignore, define proper types for the API response.

-    // @ts-ignore
-    const content = data.response || data;
-    return content || __( 'No content generated', 'dokan' );
+    interface AIResponse {
+        response?: string;
+        [key: string]: unknown;
+    }
+    const responseData = data as AIResponse;
+    return responseData.response || __( 'No content generated', 'dokan' );
📝 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.

Suggested change
// @ts-ignore
const content = data.response || data;
return content || __( 'No content generated', 'dokan' );
interface AIResponse {
response?: string;
[key: string]: unknown;
}
const responseData = data as AIResponse;
return responseData.response || __( 'No content generated', 'dokan' );

Comment on lines +63 to +66
return [
'response' => $response['choices'][0]['message']['content'] ?? '',
'prompt' => $prompt,
];
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Codebase verification

Enhance Response Structure Validation in ChatgptResponseService

  • The method directly accesses $response['choices'][0]['message']['content'] without verifying that the intermediate keys (choices, the index 0, and message) exist.
  • Relying solely on the null coalescing operator (?? '') masks cases where the response structure is malformed instead of explicitly handling the error.
  • It is recommended to validate the response data (for example, using explicit isset checks) or return/log a descriptive error when the structure is unexpected.
🔗 Analysis chain

Enhance error response handling.

The response structure should be validated before accessing array indices to prevent undefined index errors.


I'll generate a new script to inspect the snippet of code in question so that we can confirm if additional error handling is required.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for error handling patterns in the codebase
rg -A 5 "choices\[0\]\['message'\]\['content'\]" --type php

Length of output: 73


Script:

#!/bin/bash
# Display lines 60 to 70 of the file to verify the context around error handling.
sed -n '60,70p' includes/Intelligence/Services/ChatgptResponseService.php

Length of output: 262

Comment on lines +58 to +60
$params = [
'url' => self::API_URL . '?key=' . $this->api_key,
'headers' => [
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Security concern: API key exposure in URL.

The API key should be passed in the Authorization header instead of as a URL parameter to prevent key exposure in logs.

-    'url' => self::API_URL . '?key=' . $this->api_key,
+    'url' => self::API_URL,
     'headers' => [
         'Content-Type' => 'application/json',
+        'Authorization' => 'Bearer ' . $this->api_key,
     ],
📝 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.

Suggested change
$params = [
'url' => self::API_URL . '?key=' . $this->api_key,
'headers' => [
$params = [
'url' => self::API_URL,
'headers' => [
'Content-Type' => 'application/json',
'Authorization' => 'Bearer ' . $this->api_key,
],
];

Comment on lines +17 to +21
const handleLabelClick = ( event: any ) => {
event.preventDefault();
event.stopPropagation();
setIsOpen( true );
};
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add proper TypeScript event type.

Replace any with the correct event type for better type safety.

-const handleLabelClick = ( event: any ) => {
+const handleLabelClick = ( event: React.MouseEvent<SVGSVGElement> ) => {
📝 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.

Suggested change
const handleLabelClick = ( event: any ) => {
event.preventDefault();
event.stopPropagation();
setIsOpen( true );
};
const handleLabelClick = ( event: React.MouseEvent<SVGSVGElement> ) => {
event.preventDefault();
event.stopPropagation();
setIsOpen( true );
};

Comment on lines +31 to +50
const generateContent = async () => {
setError( '' );
if ( ! prompt.trim() ) {
setError( __( 'Please enter a prompt.', 'dokan' ) );
return;
}
setIsLoading( true );
try {
const content = await generateAiContent( prompt, field );
setResponse( content );
setResponseHistory( ( prevState ) => {
return [ ...prevState, content ];
} );
setCurrentIndex( responseHistory.length );
} catch ( err ) {
setError( err.message );
} finally {
setIsLoading( false );
}
};
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Prevent memory leaks in async operations.

Add cleanup logic to handle component unmounting during async operations.

 const generateContent = async () => {
+    let isSubscribed = true;
     setError( '' );
     if ( ! prompt.trim() ) {
         setError( __( 'Please enter a prompt.', 'dokan' ) );
         return;
     }
     setIsLoading( true );
     try {
         const content = await generateAiContent( prompt, field );
+        if (isSubscribed) {
             setResponse( content );
             setResponseHistory( ( prevState ) => {
                 return [ ...prevState, content ];
             } );
             setCurrentIndex( responseHistory.length );
+        }
     } catch ( err ) {
+        if (isSubscribed) {
             setError( err.message );
+        }
     } finally {
+        if (isSubscribed) {
             setIsLoading( false );
+        }
     }
+    return () => {
+        isSubscribed = false;
+    };
 };

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +73 to +113
<svg
onClick={ handleLabelClick }
width="24"
height="24"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M8.67091 4.01777C8.84169 3.32602 9.82508 3.32602 9.99586 4.01777V4.01777C10.7248 6.97053 13.0303 9.27598 15.9831 10.0049V10.0049C16.6749 10.1757 16.6749 11.1591 15.9831 11.3299V11.3299C13.0303 12.0588 10.7248 14.3642 9.99586 17.317V17.317C9.82508 18.0087 8.84169 18.0087 8.67091 17.317V17.317C7.94194 14.3642 5.63643 12.0588 2.68366 11.3299V11.3299C1.99189 11.1591 1.99189 10.1757 2.68366 10.0049V10.0049C5.63643 9.27598 7.94194 6.97053 8.67091 4.01777V4.01777Z"
fill="url(#paint0_linear_231_101)"
/>
<path
d="M15.9535 1.08615C16.0226 0.806151 16.4207 0.806151 16.4898 1.08615V1.08615C16.7848 2.28131 17.718 3.21447 18.9132 3.50951V3.50951C19.1932 3.57863 19.1932 3.97668 18.9132 4.0458V4.0458C17.718 4.34084 16.7848 5.274 16.4898 6.46916V6.46916C16.4207 6.74916 16.0226 6.74916 15.9535 6.46916V6.46916C15.6584 5.274 14.7253 4.34084 13.5301 4.0458V4.0458C13.2501 3.97668 13.2501 3.57863 13.5301 3.50951V3.50951C14.7253 3.21447 15.6584 2.28131 15.9535 1.08615V1.08615Z"
fill="url(#paint1_linear_231_101)"
/>
<defs>
<linearGradient
id="paint0_linear_231_101"
x1="9.33338"
y1="1.33435"
x2="9.33338"
y2="20.0004"
gradientUnits="userSpaceOnUse"
>
<stop stopColor="#A875FF" />
<stop offset="1" stopColor="#7D60D6" />
</linearGradient>
<linearGradient
id="paint1_linear_231_101"
x1="16.2216"
y1="0"
x2="16.2216"
y2="7.55531"
gradientUnits="userSpaceOnUse"
>
<stop stopColor="#A875FF" />
<stop offset="1" stopColor="#7D60D6" />
</linearGradient>
</defs>
</svg>
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add ARIA attributes for accessibility.

The SVG icon needs proper accessibility attributes.

 <svg
     onClick={ handleLabelClick }
+    role="button"
+    aria-label={ __( 'Open AI content generator', 'dokan' ) }
     width="24"
     height="24"
     viewBox="0 0 20 20"
     fill="none"
     xmlns="http://www.w3.org/2000/svg"
 >
📝 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.

Suggested change
<svg
onClick={ handleLabelClick }
width="24"
height="24"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M8.67091 4.01777C8.84169 3.32602 9.82508 3.32602 9.99586 4.01777V4.01777C10.7248 6.97053 13.0303 9.27598 15.9831 10.0049V10.0049C16.6749 10.1757 16.6749 11.1591 15.9831 11.3299V11.3299C13.0303 12.0588 10.7248 14.3642 9.99586 17.317V17.317C9.82508 18.0087 8.84169 18.0087 8.67091 17.317V17.317C7.94194 14.3642 5.63643 12.0588 2.68366 11.3299V11.3299C1.99189 11.1591 1.99189 10.1757 2.68366 10.0049V10.0049C5.63643 9.27598 7.94194 6.97053 8.67091 4.01777V4.01777Z"
fill="url(#paint0_linear_231_101)"
/>
<path
d="M15.9535 1.08615C16.0226 0.806151 16.4207 0.806151 16.4898 1.08615V1.08615C16.7848 2.28131 17.718 3.21447 18.9132 3.50951V3.50951C19.1932 3.57863 19.1932 3.97668 18.9132 4.0458V4.0458C17.718 4.34084 16.7848 5.274 16.4898 6.46916V6.46916C16.4207 6.74916 16.0226 6.74916 15.9535 6.46916V6.46916C15.6584 5.274 14.7253 4.34084 13.5301 4.0458V4.0458C13.2501 3.97668 13.2501 3.57863 13.5301 3.50951V3.50951C14.7253 3.21447 15.6584 2.28131 15.9535 1.08615V1.08615Z"
fill="url(#paint1_linear_231_101)"
/>
<defs>
<linearGradient
id="paint0_linear_231_101"
x1="9.33338"
y1="1.33435"
x2="9.33338"
y2="20.0004"
gradientUnits="userSpaceOnUse"
>
<stop stopColor="#A875FF" />
<stop offset="1" stopColor="#7D60D6" />
</linearGradient>
<linearGradient
id="paint1_linear_231_101"
x1="16.2216"
y1="0"
x2="16.2216"
y2="7.55531"
gradientUnits="userSpaceOnUse"
>
<stop stopColor="#A875FF" />
<stop offset="1" stopColor="#7D60D6" />
</linearGradient>
</defs>
</svg>
<svg
onClick={ handleLabelClick }
role="button"
aria-label={ __( 'Open AI content generator', 'dokan' ) }
width="24"
height="24"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M8.67091 4.01777C8.84169 3.32602 9.82508 3.32602 9.99586 4.01777V4.01777C10.7248 6.97053 13.0303 9.27598 15.9831 10.0049V10.0049C16.6749 10.1757 16.6749 11.1591 15.9831 11.3299V11.3299C13.0303 12.0588 10.7248 14.3642 9.99586 17.317V17.317C9.82508 18.0087 8.84169 18.0087 8.67091 17.317V17.317C7.94194 14.3642 5.63643 12.0588 2.68366 11.3299V11.3299C1.99189 11.1591 1.99189 10.1757 2.68366 10.0049V10.0049C5.63643 9.27598 7.94194 6.97053 8.67091 4.01777V4.01777Z"
fill="url(#paint0_linear_231_101)"
/>
<path
d="M15.9535 1.08615C16.0226 0.806151 16.4207 0.806151 16.4898 1.08615V1.08615C16.7848 2.28131 17.718 3.21447 18.9132 3.50951V3.50951C19.1932 3.57863 19.1932 3.97668 18.9132 4.0458V4.0458C17.718 4.34084 16.7848 5.274 16.4898 6.46916V6.46916C16.4207 6.74916 16.0226 6.74916 15.9535 6.46916V6.46916C15.6584 5.274 14.7253 4.34084 13.5301 4.0458V4.0458C13.2501 3.97668 13.2501 3.57863 13.5301 3.50951V3.50951C14.7253 3.21447 15.6584 2.28131 15.9535 1.08615V1.08615Z"
fill="url(#paint1_linear_231_101)"
/>
<defs>
<linearGradient
id="paint0_linear_231_101"
x1="9.33338"
y1="1.33435"
x2="9.33338"
y2="20.0004"
gradientUnits="userSpaceOnUse"
>
<stop stopColor="#A875FF" />
<stop offset="1" stopColor="#7D60D6" />
</linearGradient>
<linearGradient
id="paint1_linear_231_101"
x1="16.2216"
y1="0"
x2="16.2216"
y2="7.55531"
gradientUnits="userSpaceOnUse"
>
<stop stopColor="#A875FF" />
<stop offset="1" stopColor="#7D60D6" />
</linearGradient>
</defs>
</svg>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs: Dev Review It requires a developer review and approval
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant