Add AI writing assistant plugin with local backend, brave search, and image generation support
- Implement local backend AI provider with Ollama integration - Add Brave Search API integration for real-time search suggestions - Add image generation manager with multiple AI providers - Create hybrid provider system with local/cloud fallback - Add comprehensive settings UI with provider management - Implement Gutenberg sidebar with writing assistance controls - Add SEO schema generation for AI-generated content - Multiple provider support: OpenRouter, local backend, Codex
This commit is contained in:
@@ -50,6 +50,7 @@ class WP_Agentic_Writer_Settings_V2 {
|
||||
add_action( 'wp_ajax_wpaw_debug_models', array( $this, 'ajax_debug_models' ) );
|
||||
add_action( 'wp_ajax_wpaw_save_custom_model', array( $this, 'ajax_save_custom_model' ) );
|
||||
add_action( 'wp_ajax_wpaw_delete_custom_model', array( $this, 'ajax_delete_custom_model' ) );
|
||||
add_action( 'wp_ajax_wpaw_test_local_backend', array( $this, 'ajax_test_local_backend' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -79,9 +80,17 @@ class WP_Agentic_Writer_Settings_V2 {
|
||||
wp_enqueue_style( 'wpaw-agentic-components', WP_AGENTIC_WRITER_URL . 'assets/css/agentic-components.css', array( 'wpaw-agentic-variables' ), WP_AGENTIC_WRITER_VERSION );
|
||||
|
||||
// Legacy plugin styles
|
||||
wp_enqueue_style( 'wp-agentic-writer-admin-v2', WP_AGENTIC_WRITER_URL . 'assets/css/admin-v2.css', array( 'bootstrap', 'select2-bootstrap-5' ), WP_AGENTIC_WRITER_VERSION );
|
||||
wp_enqueue_style( 'wp-agentic-writer-settings-v2', WP_AGENTIC_WRITER_URL . 'assets/css/settings-v2.css', array( 'wpaw-agentic-components' ), WP_AGENTIC_WRITER_VERSION );
|
||||
wp_enqueue_style( 'wp-agentic-writer-cost-log-grouped', WP_AGENTIC_WRITER_URL . 'assets/css/cost-log-grouped.css', array( 'wp-agentic-writer-settings-v2' ), WP_AGENTIC_WRITER_VERSION );
|
||||
$css_admin_path = WP_AGENTIC_WRITER_DIR . 'assets/css/admin-v2.css';
|
||||
$css_settings_path = WP_AGENTIC_WRITER_DIR . 'assets/css/settings-v2.css';
|
||||
$css_log_path = WP_AGENTIC_WRITER_DIR . 'assets/css/cost-log-grouped.css';
|
||||
|
||||
$ver_admin = file_exists($css_admin_path) ? filemtime($css_admin_path) : WP_AGENTIC_WRITER_VERSION;
|
||||
$ver_settings = file_exists($css_settings_path) ? filemtime($css_settings_path) : WP_AGENTIC_WRITER_VERSION;
|
||||
$ver_log = file_exists($css_log_path) ? filemtime($css_log_path) : WP_AGENTIC_WRITER_VERSION;
|
||||
|
||||
wp_enqueue_style( 'wp-agentic-writer-admin-v2', WP_AGENTIC_WRITER_URL . 'assets/css/admin-v2.css', array( 'bootstrap', 'select2-bootstrap-5' ), $ver_admin );
|
||||
wp_enqueue_style( 'wp-agentic-writer-settings-v2', WP_AGENTIC_WRITER_URL . 'assets/css/settings-v2.css', array( 'wpaw-agentic-components' ), $ver_settings );
|
||||
wp_enqueue_style( 'wp-agentic-writer-cost-log-grouped', WP_AGENTIC_WRITER_URL . 'assets/css/cost-log-grouped.css', array( 'wp-agentic-writer-settings-v2' ), $ver_log );
|
||||
|
||||
// Plugin scripts
|
||||
wp_enqueue_script( 'wp-agentic-writer-settings-v2', WP_AGENTIC_WRITER_URL . 'assets/js/settings-v2.js', array( 'jquery', 'bootstrap', 'select2' ), WP_AGENTIC_WRITER_VERSION, true );
|
||||
@@ -968,8 +977,13 @@ class WP_Agentic_Writer_Settings_V2 {
|
||||
public function sanitize_settings( $input ) {
|
||||
$sanitized = array();
|
||||
|
||||
// Sanitize API key
|
||||
$sanitized['openrouter_api_key'] = trim( $input['openrouter_api_key'] ?? '' );
|
||||
// Sanitize API keys (allow empty values to clear them)
|
||||
if ( isset( $input['openrouter_api_key'] ) ) {
|
||||
$sanitized['openrouter_api_key'] = trim( $input['openrouter_api_key'] );
|
||||
}
|
||||
if ( isset( $input['brave_search_api_key'] ) ) {
|
||||
$sanitized['brave_search_api_key'] = trim( $input['brave_search_api_key'] );
|
||||
}
|
||||
|
||||
// Sanitize model names (6 models)
|
||||
$sanitized['chat_model'] = sanitize_text_field( $input['chat_model'] ?? 'google/gemini-2.5-flash' );
|
||||
@@ -988,6 +1002,7 @@ class WP_Agentic_Writer_Settings_V2 {
|
||||
$sanitized['web_search_enabled'] = isset( $input['web_search_enabled'] ) && '1' === $input['web_search_enabled'];
|
||||
$sanitized['cost_tracking_enabled'] = isset( $input['cost_tracking_enabled'] ) && '1' === $input['cost_tracking_enabled'];
|
||||
$sanitized['enable_clarification_quiz'] = isset( $input['enable_clarification_quiz'] ) && '1' === $input['enable_clarification_quiz'];
|
||||
$sanitized['enable_faq_schema'] = isset( $input['enable_faq_schema'] ) ? '1' === $input['enable_faq_schema'] : false;
|
||||
|
||||
// Sanitize search options
|
||||
$sanitized['search_engine'] = in_array( $input['search_engine'] ?? '', array( 'auto', 'native', 'exa' ), true )
|
||||
@@ -1030,6 +1045,38 @@ class WP_Agentic_Writer_Settings_V2 {
|
||||
$sanitized['custom_languages'] = array();
|
||||
}
|
||||
|
||||
// Sanitize Local Backend settings (Fix for settings wiping out)
|
||||
if ( isset( $input['local_backend_url'] ) ) {
|
||||
$sanitized['local_backend_url'] = esc_url_raw( trim( $input['local_backend_url'] ) );
|
||||
}
|
||||
if ( isset( $input['local_backend_key'] ) ) {
|
||||
$sanitized['local_backend_key'] = sanitize_text_field( trim( $input['local_backend_key'] ) );
|
||||
}
|
||||
if ( isset( $input['local_backend_model'] ) ) {
|
||||
$sanitized['local_backend_model'] = sanitize_text_field( trim( $input['local_backend_model'] ) );
|
||||
}
|
||||
|
||||
// Sanitize Task Providers Routing
|
||||
if ( isset( $input['task_providers'] ) && is_array( $input['task_providers'] ) ) {
|
||||
$sanitized_providers = array();
|
||||
$allowed_tasks = array( 'chat', 'clarity', 'planning', 'writing', 'refinement', 'image' );
|
||||
$allowed_providers_text = array( 'openrouter', 'local_backend', 'codex' );
|
||||
|
||||
foreach ( $input['task_providers'] as $task => $provider ) {
|
||||
$task = sanitize_text_field( $task );
|
||||
$provider = sanitize_text_field( $provider );
|
||||
|
||||
if ( in_array( $task, $allowed_tasks, true ) ) {
|
||||
if ( 'image' === $task && 'openrouter' === $provider ) {
|
||||
$sanitized_providers[ $task ] = $provider;
|
||||
} elseif ( 'image' !== $task && in_array( $provider, $allowed_providers_text, true ) ) {
|
||||
$sanitized_providers[ $task ] = $provider;
|
||||
}
|
||||
}
|
||||
}
|
||||
$sanitized['task_providers'] = $sanitized_providers;
|
||||
}
|
||||
|
||||
return $sanitized;
|
||||
}
|
||||
|
||||
@@ -1058,6 +1105,7 @@ class WP_Agentic_Writer_Settings_V2 {
|
||||
private function prepare_view_data( $settings ) {
|
||||
// Extract settings (6 models)
|
||||
$api_key = $settings['openrouter_api_key'] ?? '';
|
||||
$brave_search_api_key = $settings['brave_search_api_key'] ?? '';
|
||||
$chat_model = $settings['chat_model'] ?? 'google/gemini-2.5-flash';
|
||||
$clarity_model = $settings['clarity_model'] ?? 'google/gemini-2.5-flash';
|
||||
$planning_model = $settings['planning_model'] ?? 'google/gemini-2.5-flash';
|
||||
@@ -1071,6 +1119,7 @@ class WP_Agentic_Writer_Settings_V2 {
|
||||
$monthly_budget = $settings['monthly_budget'] ?? 600;
|
||||
$chat_history_limit = $settings['chat_history_limit'] ?? 20;
|
||||
$enable_clarification_quiz = $settings['enable_clarification_quiz'] ?? true;
|
||||
$enable_faq_schema = $settings['enable_faq_schema'] ?? false;
|
||||
$clarity_confidence_threshold = $settings['clarity_confidence_threshold'] ?? '0.6';
|
||||
$required_context_categories = $settings['required_context_categories'] ?? array(
|
||||
'target_outcome',
|
||||
@@ -1085,6 +1134,12 @@ class WP_Agentic_Writer_Settings_V2 {
|
||||
$custom_languages = $settings['custom_languages'] ?? array();
|
||||
$custom_models = get_option( 'wp_agentic_writer_custom_models', array() );
|
||||
|
||||
// Local Backend settings
|
||||
$local_backend_url = $settings['local_backend_url'] ?? '';
|
||||
$local_backend_key = $settings['local_backend_key'] ?? 'dummy';
|
||||
$local_backend_model = $settings['local_backend_model'] ?? 'claude-local';
|
||||
$task_providers = $settings['task_providers'] ?? array();
|
||||
|
||||
// Get cost tracking data
|
||||
$cost_tracker = WP_Agentic_Writer_Cost_Tracker::get_instance();
|
||||
$monthly_used = $cost_tracker->get_monthly_total();
|
||||
@@ -1093,6 +1148,7 @@ class WP_Agentic_Writer_Settings_V2 {
|
||||
|
||||
return compact(
|
||||
'api_key',
|
||||
'brave_search_api_key',
|
||||
'chat_model',
|
||||
'clarity_model',
|
||||
'planning_model',
|
||||
@@ -1106,6 +1162,7 @@ class WP_Agentic_Writer_Settings_V2 {
|
||||
'monthly_budget',
|
||||
'chat_history_limit',
|
||||
'enable_clarification_quiz',
|
||||
'enable_faq_schema',
|
||||
'clarity_confidence_threshold',
|
||||
'required_context_categories',
|
||||
'preferred_languages',
|
||||
@@ -1113,7 +1170,12 @@ class WP_Agentic_Writer_Settings_V2 {
|
||||
'custom_models',
|
||||
'monthly_used',
|
||||
'budget_percent',
|
||||
'budget_status'
|
||||
'budget_status',
|
||||
'local_backend_url',
|
||||
'local_backend_key',
|
||||
'local_backend_model',
|
||||
'task_providers',
|
||||
'settings'
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1151,4 +1213,37 @@ class WP_Agentic_Writer_Settings_V2 {
|
||||
'Swedish' => 'Swedish (Svenska)',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX handler: Test local backend connection
|
||||
*
|
||||
* @since 0.2.0
|
||||
*/
|
||||
public function ajax_test_local_backend() {
|
||||
check_ajax_referer( 'wpaw_test_local_backend', 'nonce' );
|
||||
|
||||
if ( ! current_user_can( 'manage_options' ) ) {
|
||||
wp_send_json_error( array( 'message' => 'Insufficient permissions' ) );
|
||||
}
|
||||
|
||||
$url = sanitize_text_field( wp_unslash( $_POST['url'] ?? '' ) );
|
||||
|
||||
if ( empty( $url ) ) {
|
||||
wp_send_json_error( array( 'message' => 'URL required' ) );
|
||||
}
|
||||
|
||||
// Temporarily create provider with this URL
|
||||
$temp_settings = get_option( 'wp_agentic_writer_settings', array() );
|
||||
$temp_settings['local_backend_url'] = $url;
|
||||
update_option( 'wp_agentic_writer_settings', $temp_settings );
|
||||
|
||||
$provider = new WP_Agentic_Writer_Local_Backend_Provider();
|
||||
$result = $provider->test_connection();
|
||||
|
||||
if ( is_wp_error( $result ) ) {
|
||||
wp_send_json_error( array( 'message' => $result->get_error_message() ) );
|
||||
}
|
||||
|
||||
wp_send_json_success( $result );
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user