-
Notifications
You must be signed in to change notification settings - Fork 2
✨ AI Assistant #230
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
Draft
josephfusco
wants to merge
4
commits into
main
Choose a base branch
from
ai-assistant
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
✨ AI Assistant #230
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| package-lock = false | ||
| shamefully-hoist=true | ||
| legacy-peer-deps=true |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| # AI Assistant Panel for WPGraphQL IDE | ||
|
|
||
| ## Overview | ||
|
|
||
| This plugin integrates an AI assistant into the WPGraphQL IDE to provide contextual query assistance. The assistant leverages Google's Gemini API to analyze GraphQL schemas and provide relevant suggestions. | ||
|
|
||
| ## Functionality | ||
|
|
||
| The assistant provides the following capabilities: | ||
| - Query analysis and error detection | ||
| - Schema-aware field suggestions | ||
| - Natural language query interpretation | ||
| - Performance optimization recommendations | ||
| - Error message clarification | ||
|
|
||
| ## Installation | ||
|
|
||
| ### Prerequisites | ||
| - WPGraphQL IDE | ||
| - Google Gemini API key | ||
|
|
||
| ### Configuration | ||
|
|
||
| 1. Obtain API key via one of the following methods: | ||
| - Google AI Studio: https://makersuite.google.com/app/apikey | ||
| - Google Cloud Console: Enable Generative Language API and create credentials | ||
|
|
||
| 2. Configure the plugin: | ||
| - Navigate to GraphQL → Settings → AI Assistant | ||
| - Enter the API key | ||
| - Save configuration | ||
|
|
||
| 3. Access the assistant via the AI icon in the GraphiQL activity bar. | ||
|
|
||
| ## Usage | ||
|
|
||
| Query the assistant with natural language requests. Examples: | ||
| - Query structure: "Query posts with featured images" | ||
| - Error resolution: "Explain error: [error message]" | ||
| - Optimization: "Optimize query for performance" | ||
|
|
||
| ## Technical Implementation | ||
|
|
||
| ### Architecture | ||
| ``` | ||
| ai-assistant-panel/ | ||
| ├── ai-assistant-panel.php # REST API endpoint | ||
| ├── src/ | ||
| │ └── components/ # React components | ||
| └── build/ # Compiled assets | ||
| ``` | ||
|
|
||
| ### Build Process | ||
| ```bash | ||
| npm run build # Production build | ||
| npm start # Development mode | ||
| ``` | ||
|
|
||
| ## License | ||
|
|
||
| GPL v3 or later |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,280 @@ | ||
| <?php | ||
| /** | ||
| * Plugin Name: AI Assistant Panel | ||
| * Description: AI-powered GraphQL query assistant using Gemini | ||
| */ | ||
|
|
||
| namespace WPGraphQLIDE\AIAssistantPanel; | ||
|
|
||
| if ( ! defined( 'ABSPATH' ) ) { | ||
| exit; | ||
| } | ||
|
|
||
| define( 'WPGRAPHQL_IDE_AI_ASSISTANT_PANEL_DIR_PATH', plugin_dir_path( __FILE__ ) ); | ||
| define( 'WPGRAPHQL_IDE_AI_ASSISTANT_PANEL_URL', plugin_dir_url( __FILE__ ) ); | ||
|
|
||
| /** | ||
| * Enqueues the scripts and styles for the AI Assistant panel. | ||
| * | ||
| * @return void | ||
| */ | ||
| function enqueue_assets(): void { | ||
| $asset_file = null; | ||
| $asset_path = WPGRAPHQL_IDE_AI_ASSISTANT_PANEL_DIR_PATH . 'build/ai-assistant-panel.asset.php'; | ||
|
|
||
| if ( file_exists( $asset_path ) ) { | ||
| $asset_file = include $asset_path; | ||
| } | ||
|
|
||
| if ( empty( $asset_file['dependencies'] ) ) { | ||
| return; | ||
| } | ||
|
|
||
| wp_enqueue_script( | ||
| 'ai-assistant-panel', | ||
| WPGRAPHQL_IDE_AI_ASSISTANT_PANEL_URL . 'build/ai-assistant-panel.js', | ||
| array_merge( $asset_file['dependencies'], [ 'wpgraphql-ide' ] ), | ||
| $asset_file['version'], | ||
| true | ||
| ); | ||
|
|
||
| // Enqueue the CSS file | ||
| wp_enqueue_style( | ||
| 'ai-assistant-panel', | ||
| WPGRAPHQL_IDE_AI_ASSISTANT_PANEL_URL . 'build/ai-assistant-panel.css', | ||
| [ 'wpgraphql-ide-render' ], | ||
| $asset_file['version'] | ||
| ); | ||
|
|
||
| // Localize data for the AI Assistant | ||
| wp_localize_script( | ||
| 'ai-assistant-panel', | ||
| 'WPGRAPHQL_AI_ASSISTANT_DATA', | ||
| [ | ||
| 'nonce' => wp_create_nonce( 'wp_rest' ), | ||
| 'apiUrl' => rest_url( 'wpgraphql-ide/v1/ai-assistant' ), | ||
| ] | ||
| ); | ||
| } | ||
| add_action( 'wpgraphql_ide_enqueue_script', __NAMESPACE__ . '\enqueue_assets' ); | ||
|
|
||
| /** | ||
| * Register REST API routes for the AI Assistant | ||
| */ | ||
| function register_rest_routes(): void { | ||
| register_rest_route( 'wpgraphql-ide/v1', '/ai-assistant/chat', [ | ||
| 'methods' => 'POST', | ||
| 'callback' => __NAMESPACE__ . '\handle_chat_request', | ||
| 'permission_callback' => function() { | ||
| return current_user_can( 'manage_graphql_ide' ); | ||
| }, | ||
| 'args' => [ | ||
| 'message' => [ | ||
| 'required' => true, | ||
| 'type' => 'string', | ||
| 'sanitize_callback' => 'sanitize_text_field', | ||
| ], | ||
| 'context' => [ | ||
| 'type' => 'object', | ||
| 'properties' => [ | ||
| 'query' => [ | ||
| 'type' => 'string', | ||
| ], | ||
| 'variables' => [ | ||
| 'type' => 'string', | ||
| ], | ||
| 'schema' => [ | ||
| 'type' => 'string', | ||
| ], | ||
| ], | ||
| ], | ||
| ], | ||
| ] ); | ||
| } | ||
| add_action( 'rest_api_init', __NAMESPACE__ . '\register_rest_routes' ); | ||
|
|
||
| /** | ||
| * Handle chat requests to the AI assistant | ||
| * | ||
| * @param \WP_REST_Request $request The REST request object | ||
| * @return \WP_REST_Response|\WP_Error | ||
| */ | ||
| function handle_chat_request( \WP_REST_Request $request ) { | ||
| $message = $request->get_param( 'message' ); | ||
| $context = $request->get_param( 'context' ); | ||
|
|
||
| // Try multiple methods to get the API key | ||
| $api_key = ''; | ||
|
|
||
| // Method 1: Check the graphql_ide_ai_settings option (where AI settings are registered) | ||
| $ai_settings = get_option( 'graphql_ide_ai_settings', [] ); | ||
| if ( isset( $ai_settings['graphql_ide_gemini_api_key'] ) ) { | ||
| $api_key = $ai_settings['graphql_ide_gemini_api_key']; | ||
| } | ||
|
|
||
| // Method 2: Check the graphql_ide_settings option (main IDE settings) | ||
| if ( empty( $api_key ) ) { | ||
| $graphql_ide_settings = get_option( 'graphql_ide_settings', [] ); | ||
| if ( isset( $graphql_ide_settings['graphql_ide_gemini_api_key'] ) ) { | ||
| $api_key = $graphql_ide_settings['graphql_ide_gemini_api_key']; | ||
| } | ||
| } | ||
|
|
||
| // Method 3: Direct option (fallback) | ||
| if ( empty( $api_key ) ) { | ||
| $api_key = get_option( 'graphql_ide_gemini_api_key' ); | ||
| } | ||
|
|
||
| // Method 4: Check the WPGraphQL settings option | ||
| if ( empty( $api_key ) ) { | ||
| $wpgraphql_settings = get_option( 'wpgraphql_settings', [] ); | ||
| $api_key = $wpgraphql_settings['graphql_ide_gemini_api_key'] ?? ''; | ||
| } | ||
|
|
||
| if ( empty( $api_key ) ) { | ||
| return new \WP_Error( | ||
| 'no_api_key', | ||
| __( 'Gemini API key not configured. Please add it in the GraphQL settings.', 'wpgraphql-ide' ), | ||
| [ 'status' => 400 ] | ||
| ); | ||
| } | ||
|
|
||
| // Prepare the prompt with context | ||
| $prompt = prepare_ai_prompt( $message, $context ); | ||
|
|
||
| // Call Gemini API | ||
| $response = call_gemini_api( $prompt, $api_key ); | ||
|
|
||
| if ( is_wp_error( $response ) ) { | ||
| return $response; | ||
| } | ||
|
|
||
| $response_code = wp_remote_retrieve_response_code( $response ); | ||
| $body = wp_remote_retrieve_body( $response ); | ||
| $data = json_decode( $body, true ); | ||
|
|
||
| // Check for API errors | ||
| if ( $response_code !== 200 ) { | ||
| $error_message = isset( $data['error']['message'] ) ? $data['error']['message'] : 'Unknown API error'; | ||
| return new \WP_Error( 'api_error', sprintf( __( 'Gemini API Error: %s', 'wpgraphql-ide' ), $error_message ) ); | ||
| } | ||
|
|
||
| if ( empty( $data['candidates'][0]['content']['parts'][0]['text'] ) ) { | ||
| // Log the full response for debugging | ||
| error_log( 'Gemini API Response: ' . print_r( $data, true ) ); | ||
| return new \WP_Error( 'api_error', __( 'Failed to get response from AI - no content returned', 'wpgraphql-ide' ) ); | ||
| } | ||
|
|
||
| return rest_ensure_response( [ | ||
| 'response' => $data['candidates'][0]['content']['parts'][0]['text'], | ||
| 'timestamp' => current_time( 'timestamp' ), | ||
| ] ); | ||
| } | ||
|
|
||
| /** | ||
| * Prepare the AI prompt with GraphQL context | ||
| * | ||
| * @param string $message User's message | ||
| * @param array $context Query context | ||
| * @return string | ||
| */ | ||
| function prepare_ai_prompt( string $message, array $context ): string { | ||
| $prompt = "You are a helpful GraphQL assistant for WordPress developers using WPGraphQL. "; | ||
| $prompt .= "You should provide clear, concise advice about GraphQL queries, schema design, and best practices.\n\n"; | ||
|
|
||
| if ( ! empty( $context['query'] ) ) { | ||
| $prompt .= "Current Query:\n```graphql\n" . $context['query'] . "\n```\n\n"; | ||
| } | ||
|
|
||
| if ( ! empty( $context['variables'] ) ) { | ||
| $prompt .= "Query Variables:\n```json\n" . $context['variables'] . "\n```\n\n"; | ||
| } | ||
|
|
||
| if ( ! empty( $context['schema'] ) ) { | ||
| $prompt .= "Available Schema (truncated):\n" . substr( $context['schema'], 0, 1000 ) . "...\n\n"; | ||
| } | ||
|
|
||
| $prompt .= "User Question: " . $message; | ||
|
|
||
| return $prompt; | ||
| } | ||
|
|
||
| /** | ||
| * Call the Gemini API | ||
| * | ||
| * @param string $prompt The prompt to send | ||
| * @param string $api_key The API key | ||
| * @return string|\WP_Error | ||
| */ | ||
| function call_gemini_api( string $prompt, string $api_key ) { | ||
| $url = 'https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-pro-latest:generateContent?key=' . $api_key; | ||
|
|
||
| $response = wp_remote_post( $url, [ | ||
| 'headers' => [ | ||
| 'Content-Type' => 'application/json', | ||
| ], | ||
| 'body' => wp_json_encode( [ | ||
| 'contents' => [ | ||
| [ | ||
| 'parts' => [ | ||
| [ | ||
| 'text' => $prompt, | ||
| ], | ||
| ], | ||
| ], | ||
| ], | ||
| 'generationConfig' => [ | ||
| 'temperature' => 0.7, | ||
| 'maxOutputTokens' => 1000, | ||
| ], | ||
| ] ), | ||
| 'timeout' => 30, | ||
| ] ); | ||
|
|
||
| if ( is_wp_error( $response ) ) { | ||
| return $response; | ||
| } | ||
|
|
||
| return $response; | ||
| } | ||
|
|
||
| /** | ||
| * Register plugin settings | ||
| */ | ||
| function register_settings() { | ||
| // Add settings section | ||
| if ( function_exists( 'register_graphql_settings_section' ) ) { | ||
| register_graphql_settings_section( | ||
| 'graphql_ide_ai_settings', | ||
| [ | ||
| 'title' => __( 'AI Assistant', 'wpgraphql-ide' ), | ||
| 'desc' => __( 'Configure the AI-powered GraphQL assistant.', 'wpgraphql-ide' ), | ||
| ] | ||
| ); | ||
| } | ||
|
|
||
| // Add settings fields | ||
| if ( function_exists( 'register_graphql_settings_field' ) ) { | ||
| register_graphql_settings_field( | ||
| 'graphql_ide_ai_settings', | ||
| [ | ||
| 'name' => 'graphql_ide_gemini_api_key', | ||
| 'label' => __( 'Gemini API Key', 'wpgraphql-ide' ), | ||
| 'desc' => __( 'Enter your Google Gemini API key to enable AI assistance.', 'wpgraphql-ide' ), | ||
| 'type' => 'password', | ||
| ] | ||
| ); | ||
|
|
||
| register_graphql_settings_field( | ||
| 'graphql_ide_ai_settings', | ||
| [ | ||
| 'name' => 'graphql_ide_ai_enabled', | ||
| 'label' => __( 'Enable AI Assistant', 'wpgraphql-ide' ), | ||
| 'desc' => __( 'Enable the AI assistant in the GraphQL IDE.', 'wpgraphql-ide' ), | ||
| 'type' => 'checkbox', | ||
| 'default' => 'on', | ||
| ] | ||
| ); | ||
| } | ||
| } | ||
| add_action( 'graphql_register_settings', __NAMESPACE__ . '\register_settings' ); | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Maybe dogfood WPGraphQL here instead of using REST?