diff --git a/SitiWebUpdater.php b/SitiWebUpdater.php index 5037ca5..ed01a4a 100644 --- a/SitiWebUpdater.php +++ b/SitiWebUpdater.php @@ -88,6 +88,14 @@ class SitiWebUpdater { $this->get_repository_info(); // Get the repo info + if ( empty( $this->github_response ) || empty( $this->github_response['tag_name'] ) ) { + return $transient; + } + + if ( empty( $checked[ $this->basename ] ) ) { + return $transient; + } + $out_of_date = version_compare( $this->github_response['tag_name'], $checked[ $this->basename ], 'gt' ); // Check if we're out of date if( $out_of_date ) { @@ -114,11 +122,15 @@ class SitiWebUpdater { public function plugin_popup( $result, $action, $args ) { if( ! empty( $args->slug ) ) { // If there is a slug - + if( $args->slug == current( explode( '/' , $this->basename ) ) ) { // And it's our slug $this->get_repository_info(); // Get our repo info + if ( empty( $this->github_response ) || empty( $this->github_response['tag_name'] ) ) { + return $result; + } + // Set it to an array $plugin = array( 'name' => $this->plugin["Name"], @@ -175,4 +187,4 @@ class SitiWebUpdater { return $result; } -} \ No newline at end of file +} diff --git a/assets/js/settings.js b/assets/js/settings.js index 6b799a9..628b82f 100644 --- a/assets/js/settings.js +++ b/assets/js/settings.js @@ -18,6 +18,7 @@ const modelSelect = document.getElementById('groq-ai-model-select'); const refreshButton = document.getElementById('groq-ai-refresh-models'); const refreshStatus = document.getElementById('groq-ai-refresh-models-status'); + const excludedModels = data.excludedModels || {}; let currentModelValue = (modelSelect && modelSelect.dataset.currentModel) || data.currentModel || ''; function toggleProviderRows() { @@ -42,6 +43,32 @@ }); } + function isModelAllowed(model, providerOverride) { + if (!model) { + return true; + } + + const provider = providerOverride || (providerSelect ? providerSelect.value : data.currentProvider); + if (!provider || !excludedModels[provider]) { + return true; + } + + return excludedModels[provider].indexOf(model) === -1; + } + + function ensureCurrentModelAllowed(providerOverride) { + if (!currentModelValue) { + return; + } + + if (!isModelAllowed(currentModelValue, providerOverride)) { + currentModelValue = ''; + if (modelSelect) { + modelSelect.dataset.currentModel = ''; + } + } + } + function buildModelOptions() { if (!modelSelect || !data.providers) { return; @@ -53,6 +80,8 @@ return; } + ensureCurrentModelAllowed(provider); + const models = Array.isArray(providerData.models) ? providerData.models : []; const frag = document.createDocumentFragment(); const placeholder = document.createElement('option'); @@ -63,6 +92,9 @@ let hasCurrent = false; models.forEach(function (model) { + if (!isModelAllowed(model, provider)) { + return; + } const option = document.createElement('option'); option.value = model; option.textContent = model; @@ -72,7 +104,7 @@ frag.appendChild(option); }); - if (currentModelValue && !hasCurrent) { + if (currentModelValue && !hasCurrent && isModelAllowed(currentModelValue, provider)) { const extraOption = document.createElement('option'); extraOption.value = currentModelValue; extraOption.textContent = currentModelValue; diff --git a/groq-ai-product-text.php b/groq-ai-product-text.php index a8c16fd..75cb742 100644 --- a/groq-ai-product-text.php +++ b/groq-ai-product-text.php @@ -2,7 +2,7 @@ /** * Plugin Name: SitiAI Product Teksten * Description: Genereer productteksten met diverse AI-aanbieders rechtstreeks vanuit WooCommerce. - * Version: 1.1.1 + * Version: 1.2.0 * Author: SitiAI */ @@ -32,6 +32,7 @@ if ( ! defined( 'GROQ_AI_DEBUG_TRACE_ADDED' ) && defined( 'WP_DEBUG' ) && WP_DEB } require_once __DIR__ . '/includes/Core/class-groq-ai-service-container.php'; +require_once __DIR__ . '/includes/Core/class-groq-ai-model-exclusions.php'; require_once __DIR__ . '/includes/Core/class-groq-ai-ajax-controller.php'; require_once __DIR__ . '/includes/Contracts/interface-groq-ai-provider.php'; require_once __DIR__ . '/includes/Providers/class-groq-ai-abstract-openai-provider.php'; @@ -60,6 +61,7 @@ $updater->initialize(); final class Groq_AI_Product_Text_Plugin { const OPTION_KEY = 'groq_ai_product_text_settings'; const CONVERSATION_OPTION_KEY = 'groq_ai_product_text_conversations'; + const MODELS_CACHE_OPTION_KEY = 'groq_ai_product_text_models'; private static $instance = null; @@ -260,6 +262,10 @@ final class Groq_AI_Product_Text_Plugin { return $this->get_settings_manager()->is_response_format_compat_enabled( $settings ); } + public function get_image_context_mode( $settings = null ) { + return $this->get_settings_manager()->get_image_context_mode( $settings ); + } + public function should_use_response_format( Groq_AI_Provider_Interface $provider, $settings ) { return ! $this->is_response_format_compat_enabled( $settings ) && $provider->supports_response_format(); } @@ -289,7 +295,78 @@ final class Groq_AI_Product_Text_Plugin { } public function get_selected_model( Groq_AI_Provider_Interface $provider, $settings ) { - return ! empty( $settings['model'] ) ? $settings['model'] : $provider->get_default_model(); + $provider_key = $provider->get_key(); + $model = ! empty( $settings['model'] ) ? $settings['model'] : ''; + $model = Groq_AI_Model_Exclusions::ensure_allowed( $provider_key, $model ); + + if ( '' === $model ) { + $default = Groq_AI_Model_Exclusions::ensure_allowed( $provider_key, $provider->get_default_model() ); + if ( '' !== $default ) { + return $default; + } + + $available = Groq_AI_Model_Exclusions::filter_models( $provider_key, $provider->get_available_models() ); + if ( ! empty( $available ) ) { + return $available[0]; + } + } + + return $model; + } + + public function get_cached_models_for_provider( $provider ) { + $provider = sanitize_key( (string) $provider ); + $cache = $this->get_models_cache(); + + return isset( $cache[ $provider ] ) ? $cache[ $provider ] : []; + } + + public function update_cached_models_for_provider( $provider, $models ) { + $provider = sanitize_key( (string) $provider ); + $models = $this->sanitize_models_list( $models ); + + $cache = $this->get_models_cache(); + $cache[ $provider ] = $models; + + update_option( self::MODELS_CACHE_OPTION_KEY, $cache ); + + return $models; + } + + private function get_models_cache() { + $cache = get_option( self::MODELS_CACHE_OPTION_KEY, [] ); + + if ( ! is_array( $cache ) ) { + $cache = []; + } + + foreach ( $cache as $provider => $models ) { + $cache[ $provider ] = $this->sanitize_models_list( $models ); + } + + return $cache; + } + + private function sanitize_models_list( $models ) { + if ( ! is_array( $models ) ) { + return []; + } + + $models = array_map( 'sanitize_text_field', $models ); + $models = array_filter( + $models, + function ( $model ) { + return '' !== $model; + } + ); + + $models = array_values( array_unique( $models ) ); + + if ( ! empty( $models ) ) { + sort( $models, SORT_NATURAL | SORT_FLAG_CASE ); + } + + return $models; } public function log_debug( $message, $context = [] ) { diff --git a/includes/Admin/class-groq-ai-logs-table.php b/includes/Admin/class-groq-ai-logs-table.php index 4099397..b3170e4 100644 --- a/includes/Admin/class-groq-ai-logs-table.php +++ b/includes/Admin/class-groq-ai-logs-table.php @@ -136,6 +136,7 @@ class Groq_AI_Logs_Table extends WP_List_Table { protected function column_created_at( $item ) { $date = esc_html( mysql2date( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $item['created_at'] ) ); + $usage = $this->get_usage_meta( $item ); $payload = [ 'created_at' => $item['created_at'], 'user' => $this->column_default( $item, 'user_id' ), @@ -149,6 +150,7 @@ class Groq_AI_Logs_Table extends WP_List_Table { 'prompt' => $item['prompt'], 'response' => $item['response'], 'error_message' => $item['error_message'], + 'image_context' => isset( $usage['image_context'] ) ? $usage['image_context'] : null, ]; $encoded = esc_attr( wp_json_encode( $payload ) ); return sprintf( @@ -157,4 +159,14 @@ class Groq_AI_Logs_Table extends WP_List_Table { $date ); } + + private function get_usage_meta( $item ) { + if ( empty( $item['usage_json'] ) ) { + return []; + } + + $data = json_decode( $item['usage_json'], true ); + + return is_array( $data ) ? $data : []; + } } diff --git a/includes/Admin/class-groq-ai-settings-page.php b/includes/Admin/class-groq-ai-settings-page.php index c23ac37..678dbca 100644 --- a/includes/Admin/class-groq-ai-settings-page.php +++ b/includes/Admin/class-groq-ai-settings-page.php @@ -41,6 +41,15 @@ class Groq_AI_Product_Text_Settings_Page { [ $this, 'render_logs_page' ] ); + add_submenu_page( + 'options-general.php', + __( 'Siti AI Prompt instellingen', 'groq-ai-product-text' ), + __( 'Siti AI Prompt instellingen', 'groq-ai-product-text' ), + 'manage_options', + 'groq-ai-product-text-prompts', + [ $this, 'render_prompt_settings_page' ] + ); + } public function hide_menu_links() { @@ -50,7 +59,8 @@ class Groq_AI_Product_Text_Settings_Page { ?> @@ -96,36 +106,51 @@ class Groq_AI_Product_Text_Settings_Page { ); } + add_settings_section( + 'groq_ai_product_text_prompts', + __( 'Prompt instellingen', 'groq-ai-product-text' ), + '__return_false', + 'groq-ai-product-text-prompts' + ); + add_settings_field( 'groq_ai_store_context', __( 'Winkelcontext', 'groq-ai-product-text' ), [ $this, 'render_store_context_field' ], - 'groq-ai-product-text', - 'groq_ai_product_text_general' + 'groq-ai-product-text-prompts', + 'groq_ai_product_text_prompts' ); add_settings_field( 'groq_ai_default_prompt', __( 'Standaard prompt', 'groq-ai-product-text' ), [ $this, 'render_default_prompt_field' ], - 'groq-ai-product-text', - 'groq_ai_product_text_general' + 'groq-ai-product-text-prompts', + 'groq_ai_product_text_prompts' ); add_settings_field( 'groq_ai_context_fields', __( 'Standaard productcontext', 'groq-ai-product-text' ), [ $this, 'render_context_fields_field' ], - 'groq-ai-product-text', - 'groq_ai_product_text_general' + 'groq-ai-product-text-prompts', + 'groq_ai_product_text_prompts' ); add_settings_field( 'groq_ai_response_format_compat', __( 'Response-format compatibiliteit', 'groq-ai-product-text' ), [ $this, 'render_response_format_compat_field' ], - 'groq-ai-product-text', - 'groq_ai_product_text_general' + 'groq-ai-product-text-prompts', + 'groq_ai_product_text_prompts' + ); + + add_settings_field( + 'groq_ai_image_context_mode', + __( 'Afbeeldingen toevoegen', 'groq-ai-product-text' ), + [ $this, 'render_image_context_mode_field' ], + 'groq-ai-product-text-prompts', + 'groq_ai_product_text_prompts' ); add_settings_section( @@ -144,6 +169,26 @@ class Groq_AI_Product_Text_Settings_Page { ); } + public function render_image_context_mode_field() { + $settings = $this->plugin->get_settings(); + $mode = isset( $settings['image_context_mode'] ) ? $settings['image_context_mode'] : 'url'; + $options = [ + 'none' => __( 'Nee, geen afbeeldingen', 'groq-ai-product-text' ), + 'url' => __( 'Ja, voeg afbeeldings-URL’s toe aan de prompt', 'groq-ai-product-text' ), + 'base64' => __( 'Ja, verstuur afbeeldingen als Base64 (indien ondersteund)', 'groq-ai-product-text' ), + ]; + ?> + +

+ +

+

+ + + @@ -161,19 +209,14 @@ class Groq_AI_Product_Text_Settings_Page {

-

+

+ ?>
-
-

-

- -
plugin->get_settings(); + ?> +
+

+

+ + + +

+

+
+ +
+
+

+

+ +
+
+ — +
+
+ + +
+
+ + +
+
+ + +
+
@@ -256,6 +344,7 @@ class Groq_AI_Product_Text_Settings_Page { .groq-ai-log-fields label{display:block;margin-bottom:15px;} .groq-ai-log-fields textarea{width:100%;} .groq-ai-log-tokens{display:flex;gap:20px;margin-top:10px;} + .groq-ai-log-images{display:flex;gap:20px;margin-top:10px;} .groq-ai-log-row{display:inline-block;}