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

@@ -36,9 +36,43 @@ class Groq_AI_Ajax_Controller {
$system_prompt = $prompt_builder->build_system_prompt( $settings, $conversation_id );
$model = $this->plugin->get_selected_model( $provider, $settings );
$context_fields = $prompt_builder->parse_context_fields_from_request( isset( $_POST['context_fields'] ) ? $_POST['context_fields'] : '', $settings );
$product_context_text = $prompt_builder->build_product_context_block( $post_id, $context_fields );
$image_context_mode = $this->plugin->get_image_context_mode( $settings );
if ( 'none' === $image_context_mode ) {
$context_fields['images'] = false;
}
$image_context_enabled = ! empty( $context_fields['images'] );
$use_base64_payloads = $image_context_enabled && 'base64' === $image_context_mode && $provider->supports_image_context();
$image_context_count = $image_context_enabled ? $prompt_builder->get_product_image_count( $post_id ) : 0;
$prompt_image_mode = 'none';
if ( $image_context_enabled ) {
if ( $use_base64_payloads ) {
$prompt_image_mode = 'base64';
} else {
$prompt_image_mode = 'url';
}
if ( 'base64' === $image_context_mode && ! $provider->supports_image_context() ) {
$prompt_image_mode = 'url';
}
}
$product_context_text = $prompt_builder->build_product_context_block( $post_id, $context_fields, $prompt_image_mode );
$image_context_payloads = [];
if ( $use_base64_payloads ) {
$image_context_payloads = $prompt_builder->get_product_image_payloads( $post_id );
}
$prompt_with_context = $prompt_builder->prepend_context_to_prompt( $prompt, $product_context_text );
$image_context_meta = [
'requested_mode' => $image_context_mode,
'effective_mode' => $prompt_image_mode,
'available' => $image_context_count,
'base64_sent' => $use_base64_payloads ? count( $image_context_payloads ) : 0,
];
$response_format = null;
$use_response_format = $this->plugin->should_use_response_format( $provider, $settings );
if ( $use_response_format ) {
@@ -57,6 +91,7 @@ class Groq_AI_Ajax_Controller {
'temperature' => 0.7,
'conversation_id' => $conversation_id,
'response_format' => $response_format,
'image_context' => $image_context_payloads,
]
);
@@ -67,7 +102,9 @@ class Groq_AI_Ajax_Controller {
'model' => $model,
'prompt' => $final_prompt,
'response' => '',
'usage' => [],
'usage' => [
'image_context' => $image_context_meta,
],
'post_id' => $post_id,
'status' => 'error',
'error_message' => $result->get_error_message(),
@@ -78,6 +115,10 @@ class Groq_AI_Ajax_Controller {
$response_text = $this->extract_content_text( $result );
$response_usage = is_array( $result ) && isset( $result['usage'] ) ? $result['usage'] : [];
if ( ! is_array( $response_usage ) ) {
$response_usage = [];
}
$response_usage['image_context'] = $image_context_meta;
$response = $prompt_builder->parse_structured_response( $response_text, $settings );
@@ -143,7 +184,10 @@ class Groq_AI_Ajax_Controller {
wp_send_json_error( [ 'message' => $result->get_error_message() ], 500 );
}
wp_send_json_success( [ 'models' => array_values( array_unique( $result ) ) ] );
$models = Groq_AI_Model_Exclusions::filter_models( $provider_key, array_values( array_unique( $result ) ) );
$models = $this->plugin->update_cached_models_for_provider( $provider_key, $models );
wp_send_json_success( [ 'models' => $models ] );
}
private function extract_content_text( $result ) {

View File

@@ -0,0 +1,155 @@
<?php
final class Groq_AI_Model_Exclusions {
private const DEFAULT_EXCLUSIONS = [
'groq' => [
'playai-tts-arabic',
'moonshotai/kimi-k2-instruct',
'meta-llama/llama-prompt-guard-2-22m',
'groq/compound-mini',
'meta-llama/llama-guard-4-12b',
'openai/gpt-oss-20b',
'groq/compound',
'openai/gpt-oss-safeguard-20b',
'whisper-large-v3-turbo',
'meta-llama/llama-4-scout-17b-16e-instruct',
'allam-2-7b',
'playai-tts',
'moonshotai/kimi-k2-instruct-0905',
'whisper-large-v3',
'meta-llama/llama-prompt-guard-2-86m',
],
'openai' => [],
'google' => [
'embedding-gecko-001',
'embedding-001',
'text-embedding-004',
'gemini-embedding-exp-03-07',
'gemini-embedding-exp',
'gemini-embedding-001',
'gemini-2.5-flash-image-preview',
'gemini-2.5-flash-image',
'gemini-2.5-flash-preview-tts',
'gemini-2.5-pro-preview-tts',
'gemini-2.5-flash-native-audio-latest',
'gemini-2.5-flash-native-audio-preview-09-2025',
'gemini-2.5-computer-use-preview-10-2025',
'gemini-3-pro-image-preview',
'nano-banana-pro-preview',
'gemini-robotics-er-1.5-preview',
'deep-research-pro-preview-12-2025',
'aqa',
'imagen-4.0-generate-preview-06-06',
'imagen-4.0-ultra-generate-preview-06-06',
'imagen-4.0-generate-001',
'imagen-4.0-ultra-generate-001',
'imagen-4.0-fast-generate-001',
'veo-2.0-generate-001',
'veo-3.0-generate-001',
'veo-3.0-fast-generate-001',
'veo-3.1-generate-preview',
'veo-3.1-fast-generate-preview',
],
];
/**
* Geeft de volledige lijst met uitgesloten modellen terug, gegroepeerd per aanbieder.
*
* @return array<string, string[]>
*/
public static function get_all() {
$list = apply_filters( 'groq_ai_model_exclusions', self::DEFAULT_EXCLUSIONS );
if ( ! is_array( $list ) ) {
$list = [];
}
$normalized = [];
foreach ( $list as $provider => $models ) {
$normalized[ self::normalize_provider( $provider ) ] = self::normalize_models_list( $models );
}
return $normalized;
}
/**
* @param string $provider
* @return string[]
*/
public static function get_for_provider( $provider ) {
$provider = self::normalize_provider( $provider );
$list = self::get_all();
return isset( $list[ $provider ] ) ? $list[ $provider ] : [];
}
public static function is_excluded( $provider, $model ) {
if ( '' === $model ) {
return false;
}
$model = sanitize_text_field( $model );
$provider = self::normalize_provider( $provider );
$list = self::get_for_provider( $provider );
return in_array( $model, $list, true );
}
/**
* @param string $provider
* @param string $model
* @return string
*/
public static function ensure_allowed( $provider, $model ) {
if ( self::is_excluded( $provider, $model ) ) {
return '';
}
return $model;
}
/**
* @param string $provider
* @param array $models
* @return array
*/
public static function filter_models( $provider, $models ) {
if ( ! is_array( $models ) ) {
return [];
}
$provider = self::normalize_provider( $provider );
return array_values(
array_filter(
array_map(
'sanitize_text_field',
$models
),
function ( $model ) use ( $provider ) {
return ! self::is_excluded( $provider, $model );
}
)
);
}
private static function normalize_provider( $provider ) {
return sanitize_key( (string) $provider );
}
private static function normalize_models_list( $models ) {
if ( ! is_array( $models ) ) {
$models = [];
}
$models = array_map( 'sanitize_text_field', $models );
$models = array_filter(
$models,
function ( $model ) {
return '' !== $model;
}
);
return array_values( array_unique( $models ) );
}
}