diff --git a/SitiWebUpdater.php b/SitiWebUpdater.php
index 9f5c1d1..ef55b8b 100644
--- a/SitiWebUpdater.php
+++ b/SitiWebUpdater.php
@@ -119,7 +119,8 @@ class SitiWebUpdater {
'url' => $this->plugin["PluginURI"],
'slug' => $slug,
'package' => $new_files,
- 'new_version' => $latest_version
+ 'new_version' => $latest_version,
+ 'icons' => $this->prepare_icon_set(),
);
$transient->response[$this->basename] = (object) $plugin; // Return it in response
@@ -160,10 +161,11 @@ class SitiWebUpdater {
'homepage' => $this->plugin["PluginURI"],
'short_description' => $this->plugin["Description"],
'sections' => array(
- 'Description' => $this->plugin["Description"],
- 'Updates' => $this->github_response['body'],
+ 'description' => wp_kses_post( wpautop( $this->plugin["Description"] ) ),
+ 'changelog' => $this->get_release_notes_html(),
),
- 'download_link' => $this->github_response['zipball_url']
+ 'download_link' => $this->github_response['zipball_url'],
+ 'icons' => $this->prepare_icon_set(),
);
return (object) $plugin; // Return the data
@@ -199,4 +201,37 @@ class SitiWebUpdater {
return $result;
}
+
+ private function get_release_notes_html() {
+ $notes = isset( $this->github_response['body'] ) ? (string) $this->github_response['body'] : '';
+
+ if ( '' === trim( $notes ) ) {
+ return __( 'Nog geen changelog beschikbaar.', 'siti-ai-product-content-generator' );
+ }
+
+ return wp_kses_post( wpautop( $notes ) );
+ }
+
+ private function get_plugin_icon_url() {
+ $file = plugin_dir_path( $this->file ) . 'assets/images/plugin-icon.svg';
+ if ( ! file_exists( $file ) ) {
+ return '';
+ }
+
+ return plugins_url( 'assets/images/plugin-icon.svg', $this->file );
+ }
+
+ private function prepare_icon_set() {
+ $icon_url = $this->get_plugin_icon_url();
+ if ( '' === $icon_url ) {
+ return array();
+ }
+
+ return array(
+ '1x' => $icon_url,
+ '2x' => $icon_url,
+ 'svg' => $icon_url,
+ 'default' => $icon_url,
+ );
+ }
}
diff --git a/assets/images/plugin-icon.svg b/assets/images/plugin-icon.svg
new file mode 100644
index 0000000..1196777
--- /dev/null
+++ b/assets/images/plugin-icon.svg
@@ -0,0 +1,11 @@
+
diff --git a/groq-ai-product-text.php b/groq-ai-product-text.php
index 615437b..e07ee56 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.7.0
+ * Version: 1.8.0
* Author: SitiAI
* Text Domain: siti-ai-product-content-generator
* Domain Path: /languages
@@ -350,6 +350,22 @@ final class Groq_AI_Product_Text_Plugin {
return $this->get_settings_manager()->get_term_bottom_description_char_limit( $settings );
}
+ public function get_google_safety_settings( $settings = null ) {
+ return $this->get_settings_manager()->get_google_safety_settings( $settings );
+ }
+
+ public function get_google_safety_categories() {
+ return $this->get_settings_manager()->get_google_safety_categories();
+ }
+
+ public function get_google_safety_thresholds() {
+ return $this->get_settings_manager()->get_google_safety_thresholds();
+ }
+
+ public function get_loggable_settings_snapshot( $settings = null ) {
+ return $this->get_settings_manager()->get_loggable_settings_snapshot( $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();
}
diff --git a/includes/Admin/class-groq-ai-settings-page.php b/includes/Admin/class-groq-ai-settings-page.php
index e7a9c38..2c68cc7 100644
--- a/includes/Admin/class-groq-ai-settings-page.php
+++ b/includes/Admin/class-groq-ai-settings-page.php
@@ -217,6 +217,9 @@ class Groq_AI_Product_Text_Settings_Page {
$google_connected_email = isset( $settings['google_oauth_connected_email'] ) ? (string) $settings['google_oauth_connected_email'] : '';
$google_connected_at = isset( $settings['google_oauth_connected_at'] ) ? absint( $settings['google_oauth_connected_at'] ) : 0;
$oauth_redirect = add_query_arg( 'action', 'groq_ai_google_oauth_callback', admin_url( 'admin-post.php' ) );
+ $google_safety_settings = $this->plugin->get_google_safety_settings( $settings );
+ $google_safety_categories = $this->plugin->get_google_safety_categories();
+ $google_safety_thresholds = $this->plugin->get_google_safety_thresholds();
?>
@@ -281,6 +284,30 @@ class Groq_AI_Product_Text_Settings_Page {
get_label() ) ); ?>
+
+
+
+
+ $info ) :
+ $category_label = isset( $info['label'] ) ? $info['label'] : $category_key;
+ $category_description = isset( $info['description'] ) ? $info['description'] : '';
+ $selected_threshold = isset( $google_safety_settings[ $category_key ] ) ? $google_safety_settings[ $category_key ] : '';
+ $field_id = 'groq-ai-google-safety-' . sanitize_html_class( $category_key );
+ ?>
+
+
+
+
|
@@ -892,6 +919,34 @@ class Groq_AI_Product_Text_Settings_Page {
+
+
+
+
+
+
+
+
+
+
append_response_instructions( $prompt_with_context, $settings );
}
+ $request_parameters = $this->build_request_parameters_snapshot(
+ $settings,
+ [
+ 'provider' => $provider_key,
+ 'conversation_id' => $conversation_id,
+ 'temperature' => 0.7,
+ 'response_format_mode' => $use_response_format ? 'structured' : 'prompt',
+ 'response_format_definition' => $response_format,
+ 'term_context' => [
+ 'term_id' => $term_id,
+ 'taxonomy' => $taxonomy,
+ ],
+ 'term_options' => $usage_meta['term_options'],
+ 'origin' => $origin,
+ 'google_safety_settings' => isset( $settings['google_safety_settings'] ) ? $settings['google_safety_settings'] : [],
+ ]
+ );
+
$model = $this->plugin->get_selected_model( $provider, $settings );
+ $request_parameters['model'] = $model;
$result = $provider->generate_content(
[
'prompt' => $final_prompt,
@@ -212,20 +231,21 @@ class Groq_AI_Ajax_Controller {
);
if ( is_wp_error( $result ) ) {
- if ( $logger ) {
- $logger->log_generation_event(
- [
- 'provider' => $provider_key,
- 'model' => $model,
- 'prompt' => $final_prompt,
- 'response' => '',
- 'usage' => $usage_meta,
- 'status' => 'error',
- 'error_message' => $result->get_error_message(),
- 'post_id' => 0,
- ]
- );
- }
+ if ( $logger ) {
+ $logger->log_generation_event(
+ [
+ 'provider' => $provider_key,
+ 'model' => $model,
+ 'prompt' => $final_prompt,
+ 'response' => '',
+ 'usage' => $usage_meta,
+ 'status' => 'error',
+ 'error_message' => $result->get_error_message(),
+ 'post_id' => 0,
+ 'parameters' => $request_parameters,
+ ]
+ );
+ }
return $result;
}
@@ -241,20 +261,21 @@ class Groq_AI_Ajax_Controller {
$parsed = $prompt_builder->parse_term_structured_response( $response_text, $settings );
}
if ( is_wp_error( $parsed ) ) {
- if ( $logger ) {
- $logger->log_generation_event(
- [
- 'provider' => $provider_key,
- 'model' => $model,
- 'prompt' => $final_prompt,
- 'response' => $response_text,
- 'usage' => $response_usage,
- 'status' => 'error',
- 'error_message' => $parsed->get_error_message(),
- 'post_id' => 0,
- ]
- );
- }
+ if ( $logger ) {
+ $logger->log_generation_event(
+ [
+ 'provider' => $provider_key,
+ 'model' => $model,
+ 'prompt' => $final_prompt,
+ 'response' => $response_text,
+ 'usage' => $response_usage,
+ 'status' => 'error',
+ 'error_message' => $parsed->get_error_message(),
+ 'post_id' => 0,
+ 'parameters' => $request_parameters,
+ ]
+ );
+ }
return $parsed;
}
if ( ! is_array( $parsed ) ) {
@@ -263,19 +284,20 @@ class Groq_AI_Ajax_Controller {
];
}
- if ( $logger ) {
- $logger->log_generation_event(
- [
- 'provider' => $provider_key,
- 'model' => $model,
- 'prompt' => $final_prompt,
- 'response' => $response_text,
- 'usage' => $response_usage,
- 'status' => 'success',
- 'post_id' => 0,
- ]
- );
- }
+ if ( $logger ) {
+ $logger->log_generation_event(
+ [
+ 'provider' => $provider_key,
+ 'model' => $model,
+ 'prompt' => $final_prompt,
+ 'response' => $response_text,
+ 'usage' => $response_usage,
+ 'status' => 'success',
+ 'post_id' => 0,
+ 'parameters' => $request_parameters,
+ ]
+ );
+ }
return [
'top_description' => isset( $parsed['top_description'] ) ? $parsed['top_description'] : ( isset( $parsed['description'] ) ? $parsed['description'] : '' ),
@@ -492,6 +514,23 @@ class Groq_AI_Ajax_Controller {
$final_prompt = $prompt_builder->append_response_instructions( $prompt_with_context, $settings );
}
+ $request_parameters = $this->build_request_parameters_snapshot(
+ $settings,
+ [
+ 'provider' => $provider_key,
+ 'model' => $model,
+ 'post_id' => $post_id,
+ 'conversation_id' => $conversation_id,
+ 'temperature' => 0.7,
+ 'response_format_mode' => $use_response_format ? 'structured' : 'prompt',
+ 'response_format_definition' => $response_format,
+ 'context_fields' => $context_fields,
+ 'attribute_includes' => isset( $settings['product_attribute_includes'] ) ? $settings['product_attribute_includes'] : [],
+ 'image_context' => $image_context_meta,
+ 'google_safety_settings' => isset( $settings['google_safety_settings'] ) ? $settings['google_safety_settings'] : [],
+ ]
+ );
+
$result = $provider->generate_content(
[
'prompt' => $final_prompt,
@@ -518,6 +557,7 @@ class Groq_AI_Ajax_Controller {
'post_id' => $post_id,
'status' => 'error',
'error_message' => $result->get_error_message(),
+ 'parameters' => $request_parameters,
]
);
wp_send_json_error( [ 'message' => $result->get_error_message() ], 500 );
@@ -543,6 +583,7 @@ class Groq_AI_Ajax_Controller {
'post_id' => $post_id,
'status' => 'error',
'error_message' => $response->get_error_message(),
+ 'parameters' => $request_parameters,
]
);
wp_send_json_error( [ 'message' => $response->get_error_message() ], 500 );
@@ -557,6 +598,7 @@ class Groq_AI_Ajax_Controller {
'usage' => $response_usage,
'post_id' => $post_id,
'status' => 'success',
+ 'parameters' => $request_parameters,
]
);
@@ -607,4 +649,16 @@ class Groq_AI_Ajax_Controller {
return (string) $result;
}
+
+ private function build_request_parameters_snapshot( $settings, array $additional = [] ) {
+ $snapshot = [
+ 'settings' => $this->plugin->get_loggable_settings_snapshot( $settings ),
+ ];
+
+ foreach ( $additional as $key => $value ) {
+ $snapshot[ $key ] = $value;
+ }
+
+ return $snapshot;
+ }
}
diff --git a/includes/Providers/class-groq-ai-provider-google.php b/includes/Providers/class-groq-ai-provider-google.php
index ff6465f..49dba52 100644
--- a/includes/Providers/class-groq-ai-provider-google.php
+++ b/includes/Providers/class-groq-ai-provider-google.php
@@ -30,7 +30,7 @@ class Groq_AI_Provider_Google implements Groq_AI_Provider_Interface {
}
public function supports_response_format() {
- return false;
+ return true;
}
public function supports_image_context() {
@@ -153,6 +153,18 @@ class Groq_AI_Provider_Google implements Groq_AI_Provider_Interface {
}
$max_tokens = max( 128, min( 8192, $max_tokens ) );
+ $generation_config = [
+ 'temperature' => isset( $args['temperature'] ) ? (float) $args['temperature'] : 0.7,
+ 'maxOutputTokens' => $max_tokens,
+ ];
+
+ $response_format = isset( $args['response_format'] ) ? $args['response_format'] : null;
+ $schema_payload = $this->prepare_response_schema_payload( $response_format );
+ if ( ! empty( $schema_payload ) ) {
+ $generation_config['responseMimeType'] = 'application/json';
+ $generation_config['responseJsonSchema'] = $schema_payload;
+ }
+
$payload = [
'contents' => [
[
@@ -160,12 +172,17 @@ class Groq_AI_Provider_Google implements Groq_AI_Provider_Interface {
'parts' => $parts,
],
],
- 'generationConfig' => [
- 'temperature' => isset( $args['temperature'] ) ? (float) $args['temperature'] : 0.7,
- 'maxOutputTokens' => $max_tokens,
- ],
+ 'generationConfig' => $generation_config,
];
+ $safety_settings_payload = $this->build_safety_settings_payload(
+ isset( $settings['google_safety_settings'] ) ? $settings['google_safety_settings'] : []
+ );
+
+ if ( ! empty( $safety_settings_payload ) ) {
+ $payload['safetySettings'] = $safety_settings_payload;
+ }
+
$response = wp_remote_post(
$endpoint,
[
@@ -204,7 +221,11 @@ class Groq_AI_Provider_Google implements Groq_AI_Provider_Interface {
}
$content = trim( implode( "\n\n", array_filter( $texts ) ) );
- $usage = isset( $body['usageMetadata'] ) && is_array( $body['usageMetadata'] ) ? $body['usageMetadata'] : [];
+ $usage_metadata = isset( $body['usageMetadata'] ) && is_array( $body['usageMetadata'] ) ? $body['usageMetadata'] : [];
+ $usage = $usage_metadata;
+ if ( ! empty( $usage_metadata ) ) {
+ $usage = array_merge( $usage, $this->map_usage_metadata_counts( $usage_metadata ) );
+ }
$finish_reason = isset( $body['candidates'][0]['finishReason'] ) ? sanitize_text_field( (string) $body['candidates'][0]['finishReason'] ) : '';
if ( '' !== $finish_reason ) {
$usage['finish_reason'] = $finish_reason;
@@ -216,4 +237,112 @@ class Groq_AI_Provider_Google implements Groq_AI_Provider_Interface {
'raw_response' => $body,
];
}
+
+ private function build_safety_settings_payload( $settings ) {
+ if ( empty( $settings ) || ! is_array( $settings ) ) {
+ return [];
+ }
+
+ $categories = class_exists( 'Groq_AI_Settings_Manager' ) ? array_keys( Groq_AI_Settings_Manager::get_google_safety_categories_list() ) : [];
+ $thresholds = class_exists( 'Groq_AI_Settings_Manager' ) ? array_keys( Groq_AI_Settings_Manager::get_google_safety_thresholds_list() ) : [];
+
+ if ( empty( $categories ) || empty( $thresholds ) ) {
+ return [];
+ }
+
+ $payload = [];
+ foreach ( $settings as $category => $threshold ) {
+ $category = sanitize_text_field( (string) $category );
+ $threshold = sanitize_text_field( (string) $threshold );
+
+ if ( ! in_array( $category, $categories, true ) || ! in_array( $threshold, $thresholds, true ) ) {
+ continue;
+ }
+
+ $payload[] = [
+ 'category' => $category,
+ 'threshold' => $threshold,
+ ];
+ }
+
+ return $payload;
+ }
+
+ private function prepare_response_schema_payload( $response_format ) {
+ if ( empty( $response_format ) || ! is_array( $response_format ) ) {
+ return [];
+ }
+
+ if ( isset( $response_format['type'] ) && 'json_schema' === $response_format['type'] ) {
+ if ( isset( $response_format['json_schema']['schema'] ) && is_array( $response_format['json_schema']['schema'] ) ) {
+ return $this->sanitize_schema_definition( $response_format['json_schema']['schema'] );
+ }
+
+ if ( isset( $response_format['schema'] ) && is_array( $response_format['schema'] ) ) {
+ return $this->sanitize_schema_definition( $response_format['schema'] );
+ }
+ }
+
+ return [];
+ }
+
+ private function sanitize_schema_definition( $schema ) {
+ if ( ! is_array( $schema ) ) {
+ return [];
+ }
+
+ $encoded = wp_json_encode( $schema );
+ if ( ! $encoded ) {
+ return [];
+ }
+
+ $decoded = json_decode( $encoded, true );
+
+ if ( ! is_array( $decoded ) ) {
+ return [];
+ }
+
+ $this->remove_disallowed_schema_keys( $decoded );
+
+ return $decoded;
+ }
+
+ private function remove_disallowed_schema_keys( array &$schema ) {
+ $disallowed = [ 'additionalProperties' ];
+
+ foreach ( $schema as $key => &$value ) {
+ if ( in_array( $key, $disallowed, true ) ) {
+ unset( $schema[ $key ] );
+ continue;
+ }
+
+ if ( is_array( $value ) ) {
+ $this->remove_disallowed_schema_keys( $value );
+ }
+ }
+
+ unset( $value );
+ }
+
+ private function map_usage_metadata_counts( $metadata ) {
+ if ( ! is_array( $metadata ) ) {
+ return [];
+ }
+
+ $mapped = [];
+
+ if ( isset( $metadata['promptTokenCount'] ) ) {
+ $mapped['prompt_tokens'] = absint( $metadata['promptTokenCount'] );
+ }
+
+ if ( isset( $metadata['candidatesTokenCount'] ) ) {
+ $mapped['completion_tokens'] = absint( $metadata['candidatesTokenCount'] );
+ }
+
+ if ( isset( $metadata['totalTokenCount'] ) ) {
+ $mapped['total_tokens'] = absint( $metadata['totalTokenCount'] );
+ }
+
+ return $mapped;
+ }
}
diff --git a/includes/Services/Logging/class-groq-ai-generation-logger.php b/includes/Services/Logging/class-groq-ai-generation-logger.php
index fc6793a..ffb7a1c 100644
--- a/includes/Services/Logging/class-groq-ai-generation-logger.php
+++ b/includes/Services/Logging/class-groq-ai-generation-logger.php
@@ -26,9 +26,32 @@ class Groq_AI_Generation_Logger {
$table = $this->get_logs_table_name();
$usage = isset( $args['usage'] ) && is_array( $args['usage'] ) ? $args['usage'] : [];
- $prompt_tokens = isset( $usage['prompt_tokens'] ) ? absint( $usage['prompt_tokens'] ) : null;
- $completion_tokens = isset( $usage['completion_tokens'] ) ? absint( $usage['completion_tokens'] ) : null;
- $total_tokens = isset( $usage['total_tokens'] ) ? absint( $usage['total_tokens'] ) : null;
+ $parameters = isset( $args['parameters'] ) && is_array( $args['parameters'] ) ? $args['parameters'] : [];
+ $prompt_tokens = $this->extract_usage_token_value(
+ $usage,
+ [
+ 'prompt_tokens',
+ 'promptTokenCount',
+ 'input_tokens',
+ 'inputTokenCount',
+ ]
+ );
+ $completion_tokens = $this->extract_usage_token_value(
+ $usage,
+ [
+ 'completion_tokens',
+ 'output_tokens',
+ 'candidatesTokenCount',
+ 'outputTokenCount',
+ ]
+ );
+ $total_tokens = $this->extract_usage_token_value(
+ $usage,
+ [
+ 'total_tokens',
+ 'totalTokenCount',
+ ]
+ );
$wpdb->insert(
$table,
@@ -46,6 +69,7 @@ class Groq_AI_Generation_Logger {
'status' => isset( $args['status'] ) ? sanitize_text_field( $args['status'] ) : 'success',
'error_message' => isset( $args['error_message'] ) ? $args['error_message'] : '',
'usage_json' => ! empty( $usage ) ? wp_json_encode( $usage ) : null,
+ 'request_json' => ! empty( $parameters ) ? wp_json_encode( $parameters ) : null,
]
);
}
@@ -77,6 +101,7 @@ class Groq_AI_Generation_Logger {
public function maybe_create_table() {
if ( get_option( self::OPTION_TABLE_CREATED ) ) {
$this->logs_table_exists = true;
+ $this->maybe_upgrade_table_schema();
return;
}
@@ -106,6 +131,7 @@ class Groq_AI_Generation_Logger {
status varchar(20) NOT NULL,
error_message text DEFAULT NULL,
usage_json longtext DEFAULT NULL,
+ request_json longtext DEFAULT NULL,
PRIMARY KEY (id),
KEY provider (provider),
KEY post_id (post_id)
@@ -117,6 +143,26 @@ class Groq_AI_Generation_Logger {
update_option( self::OPTION_TABLE_CREATED, 1 );
}
+ private function extract_usage_token_value( $usage, $keys ) {
+ foreach ( (array) $keys as $key ) {
+ if ( isset( $usage[ $key ] ) ) {
+ return absint( $usage[ $key ] );
+ }
+ }
+
+ return null;
+ }
+
+ private function maybe_upgrade_table_schema() {
+ global $wpdb;
+
+ $table = $this->get_logs_table_name();
+ $column = $wpdb->get_var( $wpdb->prepare( "SHOW COLUMNS FROM {$table} LIKE %s", 'request_json' ) );
+ if ( ! $column ) {
+ $this->create_table();
+ }
+ }
+
private function get_logs_table_name() {
global $wpdb;
diff --git a/includes/Services/Settings/class-groq-ai-settings-manager.php b/includes/Services/Settings/class-groq-ai-settings-manager.php
index 82a3816..20eed72 100644
--- a/includes/Services/Settings/class-groq-ai-settings-manager.php
+++ b/includes/Services/Settings/class-groq-ai-settings-manager.php
@@ -47,6 +47,7 @@ class Groq_AI_Settings_Manager {
'google_enable_ga' => true,
'google_gsc_site_url' => '',
'google_ga4_property_id' => '',
+ 'google_safety_settings' => [],
'context_fields' => $this->get_default_context_fields(),
'modules' => $this->get_default_modules_settings(),
'image_context_mode' => 'url',
@@ -60,6 +61,7 @@ class Groq_AI_Settings_Manager {
$settings = wp_parse_args( (array) $settings, $defaults );
$settings['context_fields'] = $this->normalize_context_fields( isset( $settings['context_fields'] ) ? $settings['context_fields'] : [] );
$settings['modules'] = $this->sanitize_modules_settings( isset( $settings['modules'] ) ? $settings['modules'] : [] );
+ $settings['google_safety_settings'] = $this->sanitize_google_safety_settings( isset( $settings['google_safety_settings'] ) ? $settings['google_safety_settings'] : [] );
$settings['model'] = Groq_AI_Model_Exclusions::ensure_allowed( $settings['provider'], isset( $settings['model'] ) ? $settings['model'] : '' );
$image_mode = isset( $settings['image_context_mode'] ) ? sanitize_text_field( $settings['image_context_mode'] ) : 'url';
@@ -120,6 +122,7 @@ class Groq_AI_Settings_Manager {
'google_enable_ga' => true,
'google_gsc_site_url' => '',
'google_ga4_property_id' => '',
+ 'google_safety_settings' => [],
'context_fields' => $this->get_default_context_fields(),
'modules' => $this->get_default_modules_settings(),
'image_context_mode' => 'url',
@@ -193,6 +196,7 @@ class Groq_AI_Settings_Manager {
'google_enable_ga' => ! empty( $raw_input['google_enable_ga'] ),
'google_gsc_site_url' => esc_url_raw( (string) $input['google_gsc_site_url'] ),
'google_ga4_property_id' => sanitize_text_field( (string) $input['google_ga4_property_id'] ),
+ 'google_safety_settings' => $this->sanitize_google_safety_settings( isset( $raw_input['google_safety_settings'] ) ? $raw_input['google_safety_settings'] : [] ),
'response_format_compat' => ! empty( $raw_input['response_format_compat'] ),
'image_context_mode' => $image_mode,
'image_context_limit' => $image_limit,
@@ -422,6 +426,94 @@ class Groq_AI_Settings_Manager {
return $this->sanitize_term_description_char_limit_value( $value, 1200 );
}
+ public function get_google_safety_settings( $settings = null ) {
+ if ( null === $settings ) {
+ $settings = $this->all();
+ }
+
+ return $this->sanitize_google_safety_settings( isset( $settings['google_safety_settings'] ) ? $settings['google_safety_settings'] : [] );
+ }
+
+ public function get_google_safety_categories() {
+ return self::get_google_safety_categories_list();
+ }
+
+ public function get_google_safety_thresholds() {
+ return self::get_google_safety_thresholds_list();
+ }
+
+ public function get_loggable_settings_snapshot( $settings = null ) {
+ if ( null === $settings ) {
+ $settings = $this->all();
+ }
+
+ $allowed_keys = [
+ 'store_context',
+ 'default_prompt',
+ 'max_output_tokens',
+ 'product_attribute_includes',
+ 'context_fields',
+ 'modules',
+ 'image_context_mode',
+ 'image_context_limit',
+ 'response_format_compat',
+ 'term_top_description_char_limit',
+ 'term_bottom_description_char_limit',
+ 'term_bottom_description_meta_key',
+ 'google_safety_settings',
+ 'google_enable_gsc',
+ 'google_enable_ga',
+ 'google_gsc_site_url',
+ 'google_ga4_property_id',
+ ];
+
+ $snapshot = [];
+
+ foreach ( $allowed_keys as $key ) {
+ if ( array_key_exists( $key, $settings ) ) {
+ $snapshot[ $key ] = $settings[ $key ];
+ }
+ }
+
+ return $snapshot;
+ }
+
+ public static function get_google_safety_categories_list() {
+ return [
+ 'HARM_CATEGORY_HARASSMENT' => [
+ 'label' => __( 'Harassment & intimidatie', GROQ_AI_PRODUCT_TEXT_DOMAIN ),
+ 'description' => __( 'Detecteert bedreigingen en pesterijen in de output.', GROQ_AI_PRODUCT_TEXT_DOMAIN ),
+ ],
+ 'HARM_CATEGORY_HATE_SPEECH' => [
+ 'label' => __( 'Haatspraak', GROQ_AI_PRODUCT_TEXT_DOMAIN ),
+ 'description' => __( 'Beperkt discriminerende of denigrerende taal.', GROQ_AI_PRODUCT_TEXT_DOMAIN ),
+ ],
+ 'HARM_CATEGORY_SEXUALLY_EXPLICIT' => [
+ 'label' => __( 'Seksueel expliciet', GROQ_AI_PRODUCT_TEXT_DOMAIN ),
+ 'description' => __( 'Filtert beschrijvingen van seksuele handelingen of fetish-content.', GROQ_AI_PRODUCT_TEXT_DOMAIN ),
+ ],
+ 'HARM_CATEGORY_DANGEROUS_CONTENT' => [
+ 'label' => __( 'Gevaarlijke activiteiten', GROQ_AI_PRODUCT_TEXT_DOMAIN ),
+ 'description' => __( 'Voorkomt instructies rond geweld, wapens of gevaarlijke middelen.', GROQ_AI_PRODUCT_TEXT_DOMAIN ),
+ ],
+ 'HARM_CATEGORY_CIVIC_INTEGRITY' => [
+ 'label' => __( 'Civieke integriteit', GROQ_AI_PRODUCT_TEXT_DOMAIN ),
+ 'description' => __( 'Vermindert desinformatie rond verkiezingen en burgerprocessen.', GROQ_AI_PRODUCT_TEXT_DOMAIN ),
+ ],
+ ];
+ }
+
+ public static function get_google_safety_thresholds_list() {
+ return [
+ '' => __( 'Google standaard (niet meesturen)', GROQ_AI_PRODUCT_TEXT_DOMAIN ),
+ 'HARM_BLOCK_THRESHOLD_UNSPECIFIED' => __( 'Onbekende drempel (laat Google beslissen)', GROQ_AI_PRODUCT_TEXT_DOMAIN ),
+ 'BLOCK_LOW_AND_ABOVE' => __( 'Blokkeer lage ernst en hoger', GROQ_AI_PRODUCT_TEXT_DOMAIN ),
+ 'BLOCK_MEDIUM_AND_ABOVE' => __( 'Blokkeer middel en hoger', GROQ_AI_PRODUCT_TEXT_DOMAIN ),
+ 'BLOCK_ONLY_HIGH' => __( 'Blokkeer alleen hoge ernst', GROQ_AI_PRODUCT_TEXT_DOMAIN ),
+ 'BLOCK_NONE' => __( 'Sta alles toe (geen blokkade)', GROQ_AI_PRODUCT_TEXT_DOMAIN ),
+ ];
+ }
+
public function is_response_format_compat_enabled( $settings = null ) {
if ( null === $settings ) {
$settings = $this->all();
@@ -505,4 +597,27 @@ class Groq_AI_Settings_Manager {
return min( 10, $limit );
}
+
+ private function sanitize_google_safety_settings( $settings ) {
+ if ( ! is_array( $settings ) ) {
+ return [];
+ }
+
+ $categories = array_keys( self::get_google_safety_categories_list() );
+ $thresholds = array_keys( self::get_google_safety_thresholds_list() );
+ $clean = [];
+
+ foreach ( $settings as $category => $threshold ) {
+ $category = sanitize_text_field( (string) $category );
+ $threshold = sanitize_text_field( (string) $threshold );
+
+ if ( '' === $threshold || ! in_array( $category, $categories, true ) || ! in_array( $threshold, $thresholds, true ) ) {
+ continue;
+ }
+
+ $clean[ $category ] = $threshold;
+ }
+
+ return $clean;
+ }
}