feat: Update plugin to version 1.2.0 with new image context features

- Added support for image context in product prompts, allowing images to be sent as URLs or Base64.
- Introduced a new settings page for managing prompt configurations.
- Implemented caching for allowed models per provider to enhance performance.
- Enhanced logging to include image context usage details.
- Added model exclusions management to prevent the use of specific models.
- Updated AJAX controller to handle image context in requests.
- Refactored prompt builder to support image context in prompts.
This commit is contained in:
2025-12-11 20:01:46 +00:00
parent 0a605cf165
commit 732c7ad393
12 changed files with 728 additions and 34 deletions

View File

@@ -125,7 +125,7 @@ class Groq_AI_Prompt_Builder {
return $normalized;
}
public function build_product_context_block( $post_id, $fields ) {
public function build_product_context_block( $post_id, $fields, $image_mode = 'url' ) {
$post_id = absint( $post_id );
if ( ! $post_id ) {
@@ -162,6 +162,13 @@ class Groq_AI_Prompt_Builder {
}
}
if ( ! empty( $fields['images'] ) && 'url' === $image_mode ) {
$images = $this->get_product_images_text( $post_id );
if ( $images ) {
$parts[] = sprintf( __( 'Afbeeldingen: %s', 'groq-ai-product-text' ), $images );
}
}
return implode( "\n\n", array_filter( $parts ) );
}
@@ -350,4 +357,144 @@ class Groq_AI_Prompt_Builder {
return implode( '; ', $lines );
}
private function get_product_images_text( $post_id ) {
$image_ids = $this->get_product_image_ids( $post_id );
if ( empty( $image_ids ) ) {
return '';
}
$entries = [];
foreach ( $image_ids as $index => $attachment_id ) {
$descriptor = $this->describe_product_image( $attachment_id, $index + 1 );
if ( ! $descriptor ) {
continue;
}
$entries[] = sprintf( '%s - %s', $descriptor['label'], $descriptor['url'] );
}
return implode( '; ', array_filter( $entries ) );
}
public function get_product_image_payloads( $post_id, $limit = 3, $max_filesize = 1572864 ) {
$image_ids = array_slice( $this->get_product_image_ids( $post_id ), 0, max( 1, (int) $limit ) );
if ( empty( $image_ids ) ) {
return [];
}
$payloads = [];
foreach ( $image_ids as $index => $attachment_id ) {
$descriptor = $this->describe_product_image( $attachment_id, $index + 1 );
if ( ! $descriptor || empty( $descriptor['path'] ) ) {
continue;
}
$path = $descriptor['path'];
if ( ! file_exists( $path ) || ! is_readable( $path ) ) {
continue;
}
$filesize = filesize( $path );
if ( false !== $filesize && $filesize > $max_filesize ) {
continue;
}
$data = @file_get_contents( $path );
if ( false === $data ) {
continue;
}
$payloads[] = [
'attachment_id' => $attachment_id,
'label' => $descriptor['label'],
'mime_type' => $descriptor['mime_type'],
'data' => base64_encode( $data ),
'url' => $descriptor['url'],
];
}
return $payloads;
}
public function get_product_image_count( $post_id ) {
return count( $this->get_product_image_ids( $post_id ) );
}
private function get_product_image_ids( $post_id ) {
$post_id = absint( $post_id );
if ( ! $post_id ) {
return [];
}
$image_ids = [];
$featured_id = get_post_thumbnail_id( $post_id );
if ( $featured_id ) {
$image_ids[] = $featured_id;
}
$gallery_ids = [];
if ( function_exists( 'wc_get_product' ) ) {
$product = wc_get_product( $post_id );
if ( $product ) {
$gallery_ids = (array) $product->get_gallery_image_ids();
}
}
if ( empty( $gallery_ids ) ) {
$raw_gallery = get_post_meta( $post_id, '_product_image_gallery', true );
if ( is_string( $raw_gallery ) && '' !== trim( $raw_gallery ) ) {
$gallery_ids = array_filter( array_map( 'absint', explode( ',', $raw_gallery ) ) );
}
}
if ( ! empty( $gallery_ids ) ) {
$image_ids = array_merge( $image_ids, $gallery_ids );
}
return array_values( array_unique( array_filter( array_map( 'absint', $image_ids ) ) ) );
}
private function describe_product_image( $attachment_id, $position ) {
$url = wp_get_attachment_url( $attachment_id );
if ( ! $url ) {
return null;
}
$label = trim( (string) get_post_meta( $attachment_id, '_wp_attachment_image_alt', true ) );
if ( '' === $label ) {
$label = get_the_title( $attachment_id );
}
$label = trim( wp_strip_all_tags( (string) $label ) );
if ( '' === $label ) {
$label = sprintf( __( 'Afbeelding %d', 'groq-ai-product-text' ), $position );
}
$path = get_attached_file( $attachment_id );
$mime = get_post_mime_type( $attachment_id );
if ( ! $mime && $path ) {
$mime = wp_get_image_mime( $path );
}
if ( $mime && 0 !== strpos( $mime, 'image/' ) ) {
$mime = '';
}
return [
'attachment_id' => $attachment_id,
'label' => $label,
'url' => esc_url_raw( $url ),
'path' => $path,
'mime_type' => $mime ? $mime : 'image/jpeg',
];
}
}

View File

@@ -37,6 +37,7 @@ class Groq_AI_Settings_Manager {
'google_api_key' => '',
'context_fields' => $this->get_default_context_fields(),
'modules' => $this->get_default_modules_settings(),
'image_context_mode' => 'url',
'response_format_compat' => false,
];
@@ -44,6 +45,19 @@ 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['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';
if ( 'none' === $image_mode ) {
$settings['context_fields']['images'] = false;
$settings['image_context_mode'] = 'none';
} elseif ( in_array( $image_mode, [ 'url', 'base64' ], true ) ) {
$settings['context_fields']['images'] = true;
$settings['image_context_mode'] = $image_mode;
} else {
$settings['context_fields']['images'] = true;
$settings['image_context_mode'] = 'url';
}
return $settings;
}
@@ -65,6 +79,7 @@ class Groq_AI_Settings_Manager {
'google_api_key' => '',
'context_fields' => $this->get_default_context_fields(),
'modules' => $this->get_default_modules_settings(),
'image_context_mode' => 'url',
'response_format_compat' => false,
];
@@ -80,16 +95,34 @@ class Groq_AI_Settings_Manager {
$provider = 'groq';
}
$model = sanitize_text_field( $input['model'] );
$model = Groq_AI_Model_Exclusions::ensure_allowed( $provider, $model );
$image_mode = isset( $input['image_context_mode'] ) ? sanitize_text_field( $input['image_context_mode'] ) : $defaults['image_context_mode'];
$allowed_modes = [ 'none', 'base64', 'url' ];
if ( ! in_array( $image_mode, $allowed_modes, true ) ) {
$image_mode = 'url';
}
$context_fields = $this->normalize_context_fields( $context_posted ? $raw_input['context_fields'] : $defaults['context_fields'] );
if ( 'none' === $image_mode ) {
$context_fields['images'] = false;
} else {
$context_fields['images'] = true;
}
return [
'provider' => $provider,
'model' => sanitize_text_field( $input['model'] ),
'model' => $model,
'store_context' => sanitize_textarea_field( $input['store_context'] ),
'default_prompt' => sanitize_textarea_field( $input['default_prompt'] ),
'groq_api_key' => sanitize_text_field( $input['groq_api_key'] ),
'openai_api_key' => sanitize_text_field( $input['openai_api_key'] ),
'google_api_key' => sanitize_text_field( $input['google_api_key'] ),
'response_format_compat' => ! empty( $raw_input['response_format_compat'] ),
'context_fields' => $this->normalize_context_fields( $context_posted ? $raw_input['context_fields'] : $defaults['context_fields'] ),
'image_context_mode' => $image_mode,
'context_fields' => $context_fields,
'modules' => $this->sanitize_modules_settings(
$modules_posted ? $raw_input['modules'] : [],
$defaults['modules'],
@@ -122,6 +155,11 @@ class Groq_AI_Settings_Manager {
'description' => __( 'Voeg gestructureerde productattributen toe (zoals kleur, maat, materiaal).', 'groq-ai-product-text' ),
'default' => false,
],
'images' => [
'label' => __( 'Afbeeldingen', 'groq-ai-product-text' ),
'description' => __( 'Voeg een korte lijst toe met productafbeeldingen (beschrijving + URL).', 'groq-ai-product-text' ),
'default' => false,
],
];
}
@@ -219,6 +257,17 @@ class Groq_AI_Settings_Manager {
return max( 200, min( 2000, $value ) );
}
public function get_image_context_mode( $settings = null ) {
if ( null === $settings ) {
$settings = $this->all();
}
$mode = isset( $settings['image_context_mode'] ) ? sanitize_text_field( $settings['image_context_mode'] ) : 'url';
$allowed_modes = [ 'none', 'base64', 'url' ];
return in_array( $mode, $allowed_modes, true ) ? $mode : 'url';
}
public function is_response_format_compat_enabled( $settings = null ) {
if ( null === $settings ) {
$settings = $this->all();