diff --git a/apps/cms/config/sync/core.entity_form_display.media.image.default.yml b/apps/cms/config/sync/core.entity_form_display.media.image.default.yml index de860c6b7..f9933e04b 100644 --- a/apps/cms/config/sync/core.entity_form_display.media.image.default.yml +++ b/apps/cms/config/sync/core.entity_form_display.media.image.default.yml @@ -4,7 +4,7 @@ status: true dependencies: config: - field.field.media.image.field_media_image - - image.style.large + - image.style.thumbnail - media.type.image module: - path @@ -16,18 +16,18 @@ mode: default content: created: type: datetime_timestamp - weight: 10 + weight: 4 region: content settings: { } third_party_settings: { } field_media_image: type: image_focal_point_ai - weight: 0 + weight: 1 region: content settings: progress_indicator: throbber - preview_image_style: large - preview_link: false + preview_image_style: thumbnail + preview_link: true offsets: '50,50' third_party_settings: { } langcode: @@ -39,7 +39,7 @@ content: third_party_settings: { } name: type: string_textfield - weight: -5 + weight: 0 region: content settings: size: 60 @@ -47,25 +47,25 @@ content: third_party_settings: { } path: type: path - weight: 30 + weight: 6 region: content settings: { } third_party_settings: { } status: type: boolean_checkbox - weight: 100 + weight: 7 region: content settings: display_label: true third_party_settings: { } translation: - weight: 10 + weight: 5 region: content settings: { } third_party_settings: { } uid: type: entity_reference_autocomplete - weight: 5 + weight: 3 region: content settings: match_operator: CONTAINS diff --git a/apps/cms/config/sync/core.entity_form_display.media.image.media_library.yml b/apps/cms/config/sync/core.entity_form_display.media.image.media_library.yml index a7515775b..c52a325ac 100644 --- a/apps/cms/config/sync/core.entity_form_display.media.image.media_library.yml +++ b/apps/cms/config/sync/core.entity_form_display.media.image.media_library.yml @@ -15,15 +15,17 @@ bundle: image mode: media_library content: field_media_image: - type: image_image_ai - weight: -50 + type: image_focal_point_ai + weight: 0 region: content settings: progress_indicator: throbber preview_image_style: thumbnail + preview_link: true + offsets: '50,50' third_party_settings: { } translation: - weight: 10 + weight: 1 region: content settings: { } third_party_settings: { } diff --git a/apps/cms/config/sync/silverback_image_ai.settings.yml b/apps/cms/config/sync/silverback_image_ai.settings.yml index da0510d22..017e01218 100644 --- a/apps/cms/config/sync/silverback_image_ai.settings.yml +++ b/apps/cms/config/sync/silverback_image_ai.settings.yml @@ -1,8 +1,9 @@ +_core: + default_config_hash: 8qXodhEeMW6xT3pFpm_DCF6p4VYbb3dPEC7sMgHEpTs open_ai_base_uri: 'https://api.openai.com/v1/' open_ai_key: '' ai_model: '' -words_length: 40 -alt_prefix: Silverback -alt_suffix: '' -ai_context: '' -debug_mode: 1 +words_length: 30 +alt_ai_context: 'Silverback is a PHP and Javascript framework to generate decoupled web sites.' +debug_mode: 0 +alt_disclaimer: 'The alternative text is generated by artificial intelligence. Verify for accuracy before publishing.' diff --git a/packages/drupal/silverback_ai/README.md b/packages/drupal/silverback_ai/README.md index 61eb4de9f..57be8039f 100644 --- a/packages/drupal/silverback_ai/README.md +++ b/packages/drupal/silverback_ai/README.md @@ -1,14 +1,29 @@ ## INTRODUCTION -[TDB] + +The Silverback AI module is a base module ## REQUIREMENTS -[TBD] + +- Webform (using some webform elements on reporting) ## INSTALLATION Install as you would normally install a contributed Drupal module. -See: https://www.drupal.org/node/895232 for further information. +See: for further information. ## CONFIGURATION -[TBD] +- Open AI credentials can be set on: `/admin/config/system/silverback-ai-settings`. +It is recommended though to add the Open AI Api key as environment variable (`OPEN_AI_API_KEY`). + +## USAGE TRACKING + +The Silverback AI module tracks OpenAI API token usage for monitoring and cost management purposes: + +- All Silverback AI submodules automatically report their token usage through the `TokenUsage` service +- Usage statistics can be viewed at `/admin/reports/silverback-ai-usage` +- The report shows: + - Total tokens used per module + - Cost estimates based on current OpenAI pricing + - Usage breakdown by time period + - Details of individual API calls diff --git a/packages/drupal/silverback_ai/modules/silverback_image_ai/README.md b/packages/drupal/silverback_ai/modules/silverback_image_ai/README.md index e475b08d2..c84a081d7 100644 --- a/packages/drupal/silverback_ai/modules/silverback_image_ai/README.md +++ b/packages/drupal/silverback_ai/modules/silverback_image_ai/README.md @@ -1,29 +1,35 @@ ## INTRODUCTION -The Silveback Alt AI module is a DESCRIBE_THE_MODULE_HERE. +The Silverback Image AI module provides AI-powered functionality for image management in Drupal. Its main features include: -The primary use case for this module is: +- Automatic generation of alt text for images using AI +- Intelligent image analysis and description +- Accessibility improvements through better image descriptions +- Integration with OpenAI's vision models for image processing -- Use case #1 -- Use case #2 -- Use case #3 +The module aims to enhance the accessibility and SEO of your Drupal site by ensuring all images have meaningful alternative text. ## REQUIREMENTS -DESCRIBE_MODULE_DEPENDENCIES_HERE +- Silveback AI module ## INSTALLATION Install as you would normally install a contributed Drupal module. -See: https://www.drupal.org/node/895232 for further information. +See: for further information. ## CONFIGURATION -- Configuration step #1 -- Configuration step #2 -- Configuration step #3 -## MAINTAINERS +- Base settings form: `/admin/config/system/silverback/image-ai-settings`. -Current maintainers for Drupal 10: +## SERVICES + +### ImageAiUtilities Service + +The `ImageAiUtilities` service provides core functionality for AI-powered image processing. It handles: + +- Generation of ALT text for images using OpenAI's vision models +- Processing of image files and media entities +- Integration with OpenAI's API for image analysis +- Token usage tracking and logging -- FIRST_NAME LAST_NAME (NICKNAME) - https://www.drupal.org/u/NICKNAME diff --git a/packages/drupal/silverback_ai/modules/silverback_image_ai/config/install/silverback_image_ai.settings.yml b/packages/drupal/silverback_ai/modules/silverback_image_ai/config/install/silverback_image_ai.settings.yml index c9a796b8f..011175f09 100644 --- a/packages/drupal/silverback_ai/modules/silverback_image_ai/config/install/silverback_image_ai.settings.yml +++ b/packages/drupal/silverback_ai/modules/silverback_image_ai/config/install/silverback_image_ai.settings.yml @@ -1,6 +1,7 @@ -ai_model: 'gpt-4o-mini' -debug_mode: false -words_length: '40' -alt_prefix: '' -alt_suffix: '' -ai_context: '' +open_ai_base_uri: 'https://api.openai.com/v1/' +open_ai_key: '' +ai_model: '' +words_length: 30 +alt_ai_context: 'Silverback is a PHP and Javascript framework to generate decoupled web sites.' +debug_mode: 0 +alt_disclaimer: 'The alternative text is generated by artificial intelligence. Verify for accuracy before publishing.' diff --git a/packages/drupal/silverback_ai/modules/silverback_image_ai/config/schema/silverback_image_ai.schema.yml b/packages/drupal/silverback_ai/modules/silverback_image_ai/config/schema/silverback_image_ai.schema.yml new file mode 100644 index 000000000..ddd1e7092 --- /dev/null +++ b/packages/drupal/silverback_ai/modules/silverback_image_ai/config/schema/silverback_image_ai.schema.yml @@ -0,0 +1,19 @@ +silverback_image_ai.settings: + type: config_object + label: 'Silverback Image AI settings' + mapping: + ai_model: + label: 'Model' + type: string + words_length: + label: 'Number of ALT text words to generate' + type: integer + alt_ai_context: + label: 'Context' + type: text + debug_mode: + label: 'Debug mode' + type: boolean + alt_disclaimer: + label: 'Disclaimer text' + type: text diff --git a/packages/drupal/silverback_ai/modules/silverback_image_ai/silverback_image_ai.config_translation.yml b/packages/drupal/silverback_ai/modules/silverback_image_ai/silverback_image_ai.config_translation.yml new file mode 100644 index 000000000..66521d111 --- /dev/null +++ b/packages/drupal/silverback_ai/modules/silverback_image_ai/silverback_image_ai.config_translation.yml @@ -0,0 +1,5 @@ +silverback_image_ai.config: + title: 'Silverback Image AI settings' + base_route_name: silverback_image_ai.settings + names: + - silverback_image_ai.settings diff --git a/packages/drupal/silverback_ai/modules/silverback_image_ai/silverback_image_ai.info.yml b/packages/drupal/silverback_ai/modules/silverback_image_ai/silverback_image_ai.info.yml index 24b780573..447786720 100644 --- a/packages/drupal/silverback_ai/modules/silverback_image_ai/silverback_image_ai.info.yml +++ b/packages/drupal/silverback_ai/modules/silverback_image_ai/silverback_image_ai.info.yml @@ -2,6 +2,6 @@ name: 'Silverback Alt AI' type: module description: 'Silverback AI utilities for images' package: Silverback -core_version_requirement: ^10 +core_version_requirement: ^10 || ^11 dependencies: - silverback_ai:silverback_ai diff --git a/packages/drupal/silverback_ai/modules/silverback_image_ai/silverback_image_ai.links.task.yml b/packages/drupal/silverback_ai/modules/silverback_image_ai/silverback_image_ai.links.task.yml new file mode 100644 index 000000000..969192aa2 --- /dev/null +++ b/packages/drupal/silverback_ai/modules/silverback_image_ai/silverback_image_ai.links.task.yml @@ -0,0 +1,5 @@ +silverback_image_ai.settings: + title: 'Settings' + weight: 0 + route_name: silverback_image_ai.settings + base_route: silverback_image_ai.settings diff --git a/packages/drupal/silverback_ai/modules/silverback_image_ai/silverback_image_ai.module b/packages/drupal/silverback_ai/modules/silverback_image_ai/silverback_image_ai.module index 7344f4f40..cee07cce3 100644 --- a/packages/drupal/silverback_ai/modules/silverback_image_ai/silverback_image_ai.module +++ b/packages/drupal/silverback_ai/modules/silverback_image_ai/silverback_image_ai.module @@ -4,15 +4,3 @@ * @file * Primary module hooks for Silveback Alt AI module. */ - -/** - * - */ -function silverback_image_ai_form_alter(&$form, &$form_state, $form_id) { - $service = \Drupal::service('silverback_image_ai.utilities'); - - if ($form_id == 'views_exposed_form') { - // .. - $route_name = \Drupal::routeMatch()->getRouteName(); - } -} diff --git a/packages/drupal/silverback_ai/modules/silverback_image_ai/silverback_image_ai.routing.yml b/packages/drupal/silverback_ai/modules/silverback_image_ai/silverback_image_ai.routing.yml index db18bae8d..b3ed7f4cd 100644 --- a/packages/drupal/silverback_ai/modules/silverback_image_ai/silverback_image_ai.routing.yml +++ b/packages/drupal/silverback_ai/modules/silverback_image_ai/silverback_image_ai.routing.yml @@ -1,7 +1,7 @@ silverback_image_ai.settings: path: '/admin/config/system/silverback/image-ai-settings' defaults: - _title: 'Silverback Alt AI Settings' + _title: 'Silverback Image AI Settings' _form: 'Drupal\silverback_image_ai\Form\ImageAiSettingsForm' requirements: _permission: 'administer site configuration' @@ -9,7 +9,7 @@ silverback_image_ai.settings: silverback_image_ai.image_ai_batch_update: path: '/admin/silverback-ai/update/image' defaults: - _title: 'Image Ai Batch Update' + _title: 'Image AI Batch Update' _form: 'Drupal\silverback_image_ai\Form\ImageAiBatchUpdateForm' requirements: _permission: 'access content' diff --git a/packages/drupal/silverback_ai/modules/silverback_image_ai/src/Drush/Commands/SilverbackImageAiCommands.php b/packages/drupal/silverback_ai/modules/silverback_image_ai/src/Drush/Commands/SilverbackImageAiCommands.php index ccfc5465b..a26592a30 100644 --- a/packages/drupal/silverback_ai/modules/silverback_image_ai/src/Drush/Commands/SilverbackImageAiCommands.php +++ b/packages/drupal/silverback_ai/modules/silverback_image_ai/src/Drush/Commands/SilverbackImageAiCommands.php @@ -69,7 +69,8 @@ public function commandName(array $options = [ try { $media_entities = $this->service->getMediaEntitiesToUpdateWithAlt(); $this->batch->create($media_entities); - } catch (InvalidPluginDefinitionException|PluginNotFoundException $e) { + } + catch (InvalidPluginDefinitionException | PluginNotFoundException $e) { // @todo } } diff --git a/packages/drupal/silverback_ai/modules/silverback_image_ai/src/Form/ImageAiBatchUpdateForm.php b/packages/drupal/silverback_ai/modules/silverback_image_ai/src/Form/ImageAiBatchUpdateForm.php index e61f69382..a9d9575b1 100644 --- a/packages/drupal/silverback_ai/modules/silverback_image_ai/src/Form/ImageAiBatchUpdateForm.php +++ b/packages/drupal/silverback_ai/modules/silverback_image_ai/src/Form/ImageAiBatchUpdateForm.php @@ -153,7 +153,8 @@ public function submitForm(array &$form, FormStateInterface $form_state): void { try { $media_entities = $this->service->getMediaEntitiesToUpdateAll(); $this->batch->create($media_entities); - } catch (InvalidPluginDefinitionException|PluginNotFoundException $e) { + } + catch (InvalidPluginDefinitionException | PluginNotFoundException $e) { // @todo } } diff --git a/packages/drupal/silverback_ai/modules/silverback_image_ai/src/Form/ImageAiSettingsForm.php b/packages/drupal/silverback_ai/modules/silverback_image_ai/src/Form/ImageAiSettingsForm.php index fc905868b..ee51793c0 100644 --- a/packages/drupal/silverback_ai/modules/silverback_image_ai/src/Form/ImageAiSettingsForm.php +++ b/packages/drupal/silverback_ai/modules/silverback_image_ai/src/Form/ImageAiSettingsForm.php @@ -79,32 +79,26 @@ public function buildForm(array $form, FormStateInterface $form_state): array { '#type' => 'number', '#title' => $this->t('Number of ALT text words to generate'), '#description' => $this->t('Define the number of ALT text words to be generated. Should be between 40 and 60 words.'), - '#min' => 20, - '#max' => 60, + '#min' => 10, + '#max' => 40, '#default_value' => $this->config('silverback_image_ai.settings')->get('words_length') ?? 30, '#field_suffix' => $this->t(' words'), ]; - $form['general']['alt_prefix'] = [ + $form['general']['alt_disclaimer'] = [ '#type' => 'textfield', - '#maxlength' => 40, - '#title' => $this->t('Prefix'), - '#default_value' => $this->config('silverback_image_ai.settings')->get('alt_prefix'), - '#description' => $this->t("Optionally you can define a prefix which will be prepended to ALT text upon generation. Keep it short."), + '#title' => $this->t('Disclaimer text'), + '#default_value' => $this->config('silverback_image_ai.settings')->get('alt_disclaimer') + ?? $this->t('The ALT contents are generated by artificial intelligence. Verify for accuracy before publishing.'), + '#description' => $this->t("Define a disclaimer text for the editors. Keep it short."), ]; - $form['general']['alt_suffix'] = [ - '#type' => 'textfield', - '#maxlength' => 40, - '#title' => $this->t('Suffix'), - '#default_value' => $this->config('silverback_image_ai.settings')->get('alt_suffix'), - '#description' => $this->t("Optionally you can define a suffix which will be appended to ALT text upon generation. Keep it short."), - ]; - // Not working as expected. - $form['general']['ai_context'] = [ + + $form['general']['alt_ai_context'] = [ '#type' => 'textarea', '#title' => $this->t('Context'), '#rows' => 3, - '#access' => FALSE, + '#access' => TRUE, + '#default_value' => $this->config('silverback_image_ai.settings')->get('alt_ai_context'), '#description' => $this->t('Optionally, you can use a context to generate your ALT text. Keep it short and precise.'), ]; @@ -126,9 +120,8 @@ public function submitForm(array &$form, FormStateInterface $form_state): void { ->set('ai_model', $form_state->getValue('ai_model')) ->set('debug_mode', $form_state->getValue('debug_mode')) ->set('words_length', intval($form_state->getValue('words_length'))) - ->set('alt_prefix', trim($form_state->getValue('alt_prefix'))) - ->set('alt_suffix', trim($form_state->getValue('alt_suffix'))) - ->set('ai_context', trim($form_state->getValue('ai_context'))) + ->set('alt_disclaimer', trim($form_state->getValue('alt_disclaimer'))) + ->set('alt_ai_context', trim($form_state->getValue('alt_ai_context'))) ->save(); parent::submitForm($form, $form_state); } diff --git a/packages/drupal/silverback_ai/modules/silverback_image_ai/src/ImageAiUtilities.php b/packages/drupal/silverback_ai/modules/silverback_image_ai/src/ImageAiUtilities.php index c1def0438..cb16ae5f1 100644 --- a/packages/drupal/silverback_ai/modules/silverback_image_ai/src/ImageAiUtilities.php +++ b/packages/drupal/silverback_ai/modules/silverback_image_ai/src/ImageAiUtilities.php @@ -74,19 +74,8 @@ public function generateImageAlt(FileInterface $image, string $langcode) { \Drupal::logger('debug')->debug('
' . print_r($response_body, TRUE) . "
"); } - $prefix = $this->configFactory->get('silverback_image_ai.settings')->get('alt_prefix') ?: ''; - $suffix = $this->configFactory->get('silverback_image_ai.settings')->get('alt_suffix') ?: ''; - - if (!empty($prefix)) { - $prefix .= ' | '; - } - - if (!empty($suffix)) { - $suffix = ' | ' . $suffix; - } - if (isset($response_body['choices'][0]['message']['content'])) { - return $prefix . trim($response_body['choices'][0]['message']['content']) . $suffix; + return trim($response_body['choices'][0]['message']['content']); } return NULL; @@ -164,7 +153,15 @@ public function sendOpenAiRequest(string $base_64_data, string $langcode) { $model = $this->configFactory->get('silverback_image_ai.settings')->get('ai_model') ?: self::DEFAULT_AI_MODEL; $words = $this->configFactory->get('silverback_image_ai.settings')->get('words_length') ?: self::DEFAULT_WORD_LENGTH; - $prompt = "Generate a concise and descriptive ALT text for this image. The ALT text should be a single sentence, no more than {$words} words long. The Alt text should be in the {$language_name} language."; + $context = $this->configFactory->get('silverback_image_ai.settings')->get('alt_ai_context'); + + if (!empty($context)) { + $prompt = "Given the following context:\r\n'{$context}' \r\n"; + $prompt .= "generate a concise and descriptive ALT text for this image. The ALT text should be a single sentence, no more than {$words} words long. The Alt text should be in the {$language_name} language."; + } + else { + $prompt = "Generate a concise and descriptive ALT text for this image. The ALT text should be a single sentence, no more than {$words} words long. The Alt text should be in the {$language_name} language."; + } $payload = [ 'model' => $model, diff --git a/packages/drupal/silverback_ai/modules/silverback_image_ai/src/MediaUpdaterBatch.php b/packages/drupal/silverback_ai/modules/silverback_image_ai/src/MediaUpdaterBatch.php index 7a2c4f3ad..77ba7c885 100644 --- a/packages/drupal/silverback_ai/modules/silverback_image_ai/src/MediaUpdaterBatch.php +++ b/packages/drupal/silverback_ai/modules/silverback_image_ai/src/MediaUpdaterBatch.php @@ -6,6 +6,7 @@ use Drupal\Core\Batch\BatchBuilder; use Drupal\Core\Logger\LoggerChannelFactoryInterface; +use Drupal\Core\Logger\LoggerChannelInterface; use Drupal\Core\StringTranslation\StringTranslationTrait; /** @@ -21,7 +22,7 @@ class MediaUpdaterBatch { * * @var \Drupal\Core\Logger\LoggerChannelInterface */ - protected \Drupal\Core\Logger\LoggerChannelInterface $loggerChannel; + protected LoggerChannelInterface $loggerChannel; /** * Constructor. diff --git a/packages/drupal/silverback_ai/modules/silverback_image_ai/src/Plugin/Field/FieldWidget/ImageWidgetAi.php b/packages/drupal/silverback_ai/modules/silverback_image_ai/src/Plugin/Field/FieldWidget/ImageWidgetAi.php index aa2745159..27c39e47a 100644 --- a/packages/drupal/silverback_ai/modules/silverback_image_ai/src/Plugin/Field/FieldWidget/ImageWidgetAi.php +++ b/packages/drupal/silverback_ai/modules/silverback_image_ai/src/Plugin/Field/FieldWidget/ImageWidgetAi.php @@ -30,6 +30,8 @@ */ class ImageWidgetAi extends FileWidget { + private const DEFAULT_LANGCODE = 'en'; + /** * The image factory service. * @@ -201,6 +203,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen */ public static function process($element, FormStateInterface $form_state, $form) { $item = $element['#value']; + $item['fids'] = $element['fids']['#value']; $element['#theme'] = 'image_widget'; @@ -232,33 +235,27 @@ public static function process($element, FormStateInterface $form_state, $form) } } - // Add the additional alt and title fields. - $icon = ' - - '; - $element['ai_container'] = [ '#type' => 'container', '#attributes' => [ 'style' => ['text-align: right'], ], ]; + $element['ai_container']['alt_ai_generate'] = [ '#type' => 'submit', - '#value' => Markup::create('Re-generate Alt text'), + '#value' => new TranslatableMarkup('Re-generate ALT text'), '#weight' => -12, - '#suffix' => Markup::create($icon), '#attributes' => [ 'class' => ['button--extrasmall', 'button', 'js-form-submit', 'form-submit'], - 'style' => ['width: 164px; float: right'], + 'style' => ['padding: 2px 12px'], ], '#ajax' => [ - 'callback' => static::class . '::myAjaxCallback', + 'callback' => static::class . '::generateAjaxCallback', 'event' => 'click', 'wrapper_id' => $element['#attributes']['data-drupal-selector'] . '-alt', - // 'wrapper' => $form['field_media_image']['#id'], 'fids' => $item['fids'], - 'langcode' => $form_state->get('langcode'), + 'langcode' => $form_state->get('langcode') ?? ImageWidgetAi::getLangcode($form, $form_state), 'progress' => [ 'type' => 'throbber', 'message' => t('Generating alt text...'), @@ -266,6 +263,13 @@ public static function process($element, FormStateInterface $form_state, $form) ], ]; + // @todo Add DI + $disclaimer = "
" . \Drupal::config('silverback_image_ai.settings')->get('alt_disclaimer') . "
"; + $element['ai_container']['disclaimer'] = [ + '#type' => 'item', + '#markup' => Markup::create($disclaimer), + ]; + $element['preview'] = [ '#weight' => -10, '#theme' => 'image_style', @@ -281,9 +285,9 @@ public static function process($element, FormStateInterface $form_state, $form) // [AI utilities] if (!isset($item['alt'])) { + $langcode = ImageWidgetAi::getLangcode($form, $form_state); $service = \Drupal::service('silverback_image_ai.utilities'); - $langcode = $form_state->get('langcode') ?? 'en'; - $item['alt'] = $service->generateImageAlt($file, $langcode); + $item['alt'] = $service->generateImageAlt($file, $langcode ?? ImageWidgetAi::DEFAULT_LANGCODE); } // [end AI utilities] } @@ -306,7 +310,7 @@ public static function process($element, FormStateInterface $form_state, $form) '#title' => new TranslatableMarkup('Alternative text'), '#type' => 'textfield', '#default_value' => $item['alt'] ?? '', - '#description' => new TranslatableMarkup('Short description of the image used by screen readers and displayed when the image is not loaded. This is important for accessibility.'), + '#description' => new TranslatableMarkup('Short description of the image used by screen readers and displayed when the image is not loaded. This is important for accessibility and SEO.'), // @see https://www.drupal.org/node/465106#alt-text '#maxlength' => 512, '#weight' => -12, @@ -392,16 +396,14 @@ public function onDependencyRemoval(array $dependencies) { return $changed; } - // Get the value from example select field and fill. - /** * The textbox with the selected text. */ - public static function myAjaxCallback(array &$form, FormStateInterface $form_state) { + public static function generateAjaxCallback(array &$form, FormStateInterface $form_state) { $triggering_element = $form_state->getTriggeringElement(); $wrapper_id = $triggering_element['#ajax']['wrapper_id']; $fids = $triggering_element['#ajax']['fids']; - $langcode = $triggering_element['#ajax']['langcode'] ?? 'en'; + $langcode = $triggering_element['#ajax']['langcode'] ?? ImageWidgetAi::DEFAULT_LANGCODE; // @todo get the file $fid = reset($fids); $file = NULL; @@ -420,4 +422,33 @@ public static function myAjaxCallback(array &$form, FormStateInterface $form_sta return $response; } + /** + * + */ + public static function getLangcode(array &$form, FormStateInterface $form_state) { + // @todo Add DI + $langcode = ImageWidgetAi::DEFAULT_LANGCODE; + + $input = $form_state->getUserInput(); + $langcode = is_array($input['langcode']) ? reset($input['langcode']) : []; + $langcode = $langcode['value'] ?? NULL; + if (!empty($langcode)) { + $language_codes = \Drupal::languageManager()->getLanguages(); + // Make sure the selected langcode exists and it is a real language. + if (empty($language_codes[$langcode])) { + $langcode = ImageWidgetAi::DEFAULT_LANGCODE; + } + } + + if (!$langcode) { + // Try to fetch from entity language. + if ($prefixes = \Drupal::config('language.negotiation')->get('url.prefixes')) { + $language = \Drupal::languageManager()->getCurrentLanguage()->getId(); + $langcode = $prefixes[$language] ?? NULL; + } + } + + return $langcode; + } + } diff --git a/packages/drupal/silverback_ai/silverback_ai.info.yml b/packages/drupal/silverback_ai/silverback_ai.info.yml index 9918ed65a..e08d93929 100644 --- a/packages/drupal/silverback_ai/silverback_ai.info.yml +++ b/packages/drupal/silverback_ai/silverback_ai.info.yml @@ -2,4 +2,6 @@ name: 'Silverback AI' type: module description: 'Silverback AI base module' package: Silverback -core_version_requirement: ^10 +core_version_requirement: ^10 || ^11 +dependencies: + - webform:webform diff --git a/packages/drupal/silverback_ai/src/Controller/UsageDetailsController.php b/packages/drupal/silverback_ai/src/Controller/UsageDetailsController.php index 33de7b286..a261977a5 100644 --- a/packages/drupal/silverback_ai/src/Controller/UsageDetailsController.php +++ b/packages/drupal/silverback_ai/src/Controller/UsageDetailsController.php @@ -59,6 +59,7 @@ public static function create(ContainerInterface $container): self { * * @return array * A render array. + * * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException */