sidekick-1.0.x-dev/sidekick.module
sidekick.module
<?php
/**
* @file
* Hooks implementation for the Sidekick module.
*/
use Drupal\Component\Serialization\Json;
use Drupal\Component\Utility\Html;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\HtmlCommand;
use Drupal\Core\Ajax\InvokeCommand;
use Drupal\Core\Ajax\MessageCommand;
use Drupal\Core\Ajax\RemoveCommand;
use Drupal\Core\Ajax\SettingsCommand;
use Drupal\Core\Entity\ContentEntityFormInterface;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\WidgetInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\file\Entity\File;
use Drupal\Core\Url;
use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\RequestOptions;
use Drupal\sidekick\ImageWidget;
/**
* Implements hook_form_node_form_alter().
*/
function sidekick_form_node_form_alter(
array &$form,
FormStateInterface $form_state,
$form_id,
): void {
$config = Drupal::config('sidekick.settings');
$display_type = $config->get('display_type');
if (Drupal::currentUser()->hasPermission('sidekick content generation')
&& $display_type != 'no_display') {
$language_code = $form_state->get('langcode');
$sidekick_service = Drupal::service('sidekick.service');
$sidekickKeyStatus = $sidekick_service->checkKeyStatus(
$language_code,
);
if (!empty($sidekickKeyStatus['status']) && $sidekickKeyStatus['status'] == 200) {
$weight = -11;
$form['sidekick'] = [
'#type' => 'details',
'#title' => t('Sidekick'),
'#group' => 'advanced',
'#open' => TRUE,
'#weight' => $weight,
'#attributes' => ['class' => ['sidekick-frame']],
];
$form['sidekick_message'] = [
'#type' => 'html_tag',
'#tag' => 'div',
'#attributes' => [
'class' => ['sidekick-message'],
],
'#weight' => -100,
];
// --Whole node content.
$node = $form_state->getFormObject()->getEntity();
if ($node->isNew()) {
$form['#attached']['drupalSettings']['sidekick']['nodeDetails'] = [
'version' => '1.0',
'eventName' => 'page-changed',
'data' => [
'url' => '',
'title' => '',
'content' => '',
'structuredContent' => [],
'targetAudience' => $config->get('target_audience'),
'pageBriefing' => $config->get('page_briefing'),
],
];
}
else {
$build = Drupal::service('entity_type.manager')
->getViewBuilder($node->getEntityTypeId())
->view($node, 'default');
$output = Drupal::service('renderer')->render($build);
$content = Html::decodeEntities(strip_tags((string) $output));
$node_url = Drupal::urlGenerator()->generateFromRoute(
'entity.node.canonical',
['node' => $node->id(), ['absolute' => TRUE]]
);
$form['#attached']['drupalSettings']['sidekick']['nodeDetails'] = [
'sidekickData' => [
'version' => '1.0',
'eventName' => 'page-changed',
'data' => [
'url' => $node_url,
'title' => '',
'content' => $content,
'structuredContent' => [],
'targetAudience' => $config->get('target_audience'),
'pageBriefing' => $config->get('page_briefing'),
],
],
];
}
$api_url = Url::fromUri(
'https://assistant.ai-sidekick.app/chat',
[
'query' => $sidekick_service->getQueryParameter(
$language_code
),
]
)->toString();
if ('inline' == $display_type
|| 'inline_closed' == $display_type) {
$form['sidekick']['iframe'] = [
'#type' => 'html_tag',
'#tag' => 'iframe',
'#attributes' => [
'src' => $api_url,
'title' => t('Sidekick'),
'referrerpolicy' => 'origin',
'allow' => 'clipboard-write',
'class' => ['sidekick-iframe'],
],
];
if ('inline_closed' == $display_type) {
$form['sidekick']['#open'] = FALSE;
}
}
else {
$form['iframe'] = [
'#type' => 'html_tag',
'#tag' => 'iframe',
'#attributes' => [
'src' => $api_url,
'title' => t('Sidekick'),
'referrerpolicy' => 'origin',
'allow' => 'clipboard-write',
'class' => ['sidekick-iframe-modal hidden'],
],
];
$form['sidekick']['popup'] = [
'#type' => 'html_tag',
'#tag' => 'a',
'#value' => t('Open Sidekick'),
'#attributes' => [
'class' => ['btn btn-primary button open-sidekick-modal'],
],
];
}
// This for silently send a ajax to get new content render for api.
/* ---- TODO ----
* An AJAX Request to Send the content after each change
*/
$form['sidekick']['sidekick_messaging_button'] = [
'#type' => 'button',
'#name' => 'sidekick-messaging-button',
'#id' => 'sidekick-messaging-button',
'#value' => t('Update messaging api data'),
'#attributes' => [
'class' => [
'sidekick-messaging-button',
'visually-hidden',
],
],
'#ajax' => [
'callback' => 'sidekick_messaging',
'disable-refocus' => TRUE,
'progress' => FALSE,
],
];
$form['#attributes']['class'][] = 'sidekick-messaging-form';
$form['#attached']['library'][] = 'sidekick/sidekick_js';
$form['#attached']['library'][] = 'sidekick/sidekick_css';
}
}
}
/**
* Ajax callback for sidekick messaging.
*/
function sidekick_messaging($form, FormStateInterface $form_state) {
$form_object = $form_state->getFormObject();
if ($form_object instanceof ContentEntityFormInterface) {
/** @var \Drupal\Core\Entity\Display\EntityFormDisplayInterface $form_display */
$entity_form_display = $form_state->get('form_display');
$entity = $form_object->getEntity();
$entity->in_preview = TRUE;
$entity_form_display->extractFormValues($entity, $form, $form_state);
$build = Drupal::service('entity_type.manager')
->getViewBuilder($entity->getEntityTypeId())
->view($entity, 'default');
$output = Drupal::service('renderer')->render($build);
$content = Html::decodeEntities(strip_tags((string) $output));
$config = Drupal::config('sidekick.settings');
$sideKickMessagingApiData = [
'sidekickData' => [
'version' => '1.0',
'eventName' => 'page-changed',
'data' => [
'url' => '',
'title' => $entity->label() ?? '',
'content' => $content,
'structuredContent' => [],
'targetAudience' => $config->get('target_audience'),
'pageBriefing' => $config->get('page_briefing'),
],
],
];
$response = new AjaxResponse();
$response->addCommand(
new SettingsCommand($sideKickMessagingApiData, TRUE),
TRUE
);
return $response;
}
return [];
}
/**
* Implements hook_field_widget_third_party_settings_form().
*/
function sidekick_field_widget_third_party_settings_form(
WidgetInterface $plugin,
FieldDefinitionInterface $field_definition,
$form_mode,
$form,
FormStateInterface $form_state,
) {
$element = [];
if (in_array($plugin->getPluginId(), [
'string_textfield',
'text_textfield',
'string_textarea',
])) {
$sidekick_module_options = $user_input = [];
$language_code = $form_state->get('langcode');
$sidekick_service = Drupal::service('sidekick.service');
// Module.
$modules = $sidekick_service->getModules(
$language_code
);
if (!empty($modules['status']) && $modules['status'] == 401) {
return $element;
}
if ($modules) {
foreach ($modules['message']->data as $module) {
$sidekick_module_options[$module->identifier] = ucfirst(
str_replace('_', ' ', $module->identifier)
);
$user_input[$module->identifier] = $module->user_input;
}
}
// Language.
$languages = $sidekick_service->getLanguages(
$language_code
);
$sidekick_language_options = [
'auto' => t(
'Auto (Select node language)'
),
];
if ($languages) {
foreach ($languages['message']->data as $language) {
$sidekick_language_options[$language->identifier] = $language->name;
}
}
// Writing style.
$writing_styles = $sidekick_service->getWritingStyles(
$language_code
);
$writing_style_options = [];
if ($writing_styles) {
foreach ($writing_styles['message']->data as $writing_style) {
$writing_style_options[$writing_style->identifier] = $writing_style->label;
}
}
// salutation.
$salutation_options = [
'formal' => t('Formal'),
'informal' => t('Informal'),
'avoid' => t('Avoid'),
];
$element['sidekick_enabled'] = [
'#type' => 'checkbox',
'#title' => t('Enable Sidekick'),
'#default_value' => $plugin->getThirdPartySetting(
'sidekick',
'sidekick_enabled'
),
'#description' => t('If checked, Enable Sidekick API.'),
];
$element['sidekick_settings'] = [
'#type' => 'details',
'#group' => 'advanced',
'#open' => TRUE,
'#title' => t('Sidekick API'),
'#states' => [
'visible' => [
':input[name="fields['
. $field_definition->getName()
. '][settings_edit_form][third_party_settings][sidekick][sidekick_enabled]"]'
=> ['checked' => TRUE],
],
],
];
$element['sidekick_settings']['salutation'] = [
'#type' => 'select',
'#title' => t('Salutation'),
'#options' => $salutation_options,
'#default_value' => $plugin->getThirdPartySetting(
'sidekick',
'sidekick_settings'
)['salutation'] ?? 'avoid',
'#description' => t('Sidekick API Salutation to use.'),
];
$element['sidekick_settings']['language'] = [
'#type' => 'select',
'#title' => t('Language'),
'#options' => $sidekick_language_options,
'#default_value' => $plugin->getThirdPartySetting(
'sidekick',
'sidekick_settings'
)['language'] ?? 'auto',
'#description' => t('Sidekick API Language to use.'),
];
$element['sidekick_settings']['writing_style'] = [
'#type' => 'select',
'#title' => t('Writing Style'),
'#options' => $writing_style_options,
'#default_value' => $plugin->getThirdPartySetting(
'sidekick',
'sidekick_settings'
)['writing_style'] ?? 'default',
'#description' => t('Sidekick API Writing Style to use.'),
];
$module = $plugin->getThirdPartySetting(
'sidekick',
'sidekick_settings'
)['module'] ?? 'meta_description';
$element['sidekick_settings']['module'] = [
'#type' => 'select',
'#title' => t('AI Automation'),
'#api_user_input' => json_encode($user_input),
'#field_in_action' => $field_definition->getName(),
'#options' => $sidekick_module_options,
'#default_value' => $module,
'#description' => t('Sidekick API Module to use.'),
'#ajax' => [
'callback' => 'sidekick_create_module_user_input',
'disable-refocus' => FALSE,
'event' => 'change',
'wrapper' => 'user-input-container',
],
];
$element['sidekick_settings']['container'] = [
'#type' => 'container',
'#attributes' => ['id' => 'user-input-container'],
];
$element['sidekick_settings']['tokens'] = [
'#theme' => 'token_tree_link',
'#token_types' => [
'node',
],
];
$element['sidekick_settings']['auto'] = [
'#type' => 'checkbox',
'#title' => t('Only run if empty and entity gets saved'),
'#default_value' => $plugin->getThirdPartySetting(
'sidekick',
'sidekick_settings'
)['auto'] ?? 0,
'#description' => t(
'If checked, auto run if empty and entity gets saved.'
),
];
$element['sidekick_settings']['manual'] = [
'#type' => 'checkbox',
'#title' => t('Show manual trigger button'),
'#default_value' => $plugin->getThirdPartySetting(
'sidekick',
'sidekick_settings'
)['manual'] ?? 0,
'#description' => t('If checked, show manual trigger button.'),
];
if ($module) {
foreach ($user_input[$module] as $inputfield) {
if ($module == 'meta_description' && $inputfield->identifier == 'prefer') {
$element['sidekick_settings']['container'][$module][$inputfield->identifier] = [
'#type' => 'select',
'#title' => ucfirst($inputfield->identifier),
'#default_value' => $plugin->getThirdPartySetting(
'sidekick',
'sidekick_settings'
)['container'][$module][$inputfield->identifier] ?? '',
'#options' => [
'quality' => t('quality'),
'speed' => t('speed'),
],
'#description' => $inputfield->description,
];
}
else {
$element['sidekick_settings']['container'][$module][$inputfield->identifier] = [
'#type' => 'textfield',
'#placeholder' => $inputfield->identifier,
'#title' => ucfirst($inputfield->identifier),
'#default_value' => $plugin->getThirdPartySetting(
'sidekick',
'sidekick_settings'
)['container'][$module][$inputfield->identifier] ?? '',
'#description' => t('Token are supported'),
];
}
}
}
else {
// ---- TODO ----
echo 'Initial load';
}
}
return $element;
}
/**
* Create the user input for Call as per the Selection of Module.
*
* @param array $form
* The form fields for this plugin.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The submitted form state.
*
* @return Drupal\Core\Ajax\AjaxResponse
* Returns AJAX response
*/
function sidekick_create_module_user_input(array $form, FormStateInterface $form_state) {
$api_user_input = json_decode(
$form_state->getTriggeringElement()['#api_user_input']
);
$fieldInAction = $form_state->getTriggeringElement()['#field_in_action'];
$module = $form_state->getTriggeringElement()['#value'];
$previousSelectedModule = $form['fields'][$fieldInAction]['plugin']['settings_edit_form']['third_party_settings']['sidekick']['sidekick_enabled']['#groups']['advanced'][0]['container'];
$element = [];
$setValue = '';
foreach ($api_user_input->$module as $inputfield) {
if ($module == 'meta_description' && $inputfield->identifier == 'prefer') {
$element['sidekick_settings']['container'][$module][$inputfield->identifier] = [
'#type' => 'select',
'#name' => 'fields[' . $fieldInAction . '][settings_edit_form][third_party_settings][sidekick][sidekick_settings][container][' . $module . '][' . $inputfield->identifier . ']',
'#title' => ucfirst($inputfield->identifier),
'#options' => [
'quality' => ucfirst('quality'),
'speed' => ucfirst('speed'),
],
'#description' => $inputfield->description,
];
}
else {
if (isset($previousSelectedModule[$module])) {
$setValue = $previousSelectedModule[$module][$inputfield->identifier]['#value'];
}
$element['sidekick_settings']['container'][$module][$inputfield->identifier] = [
'#type' => 'textfield',
'#name' => 'fields[' . $fieldInAction . '][settings_edit_form][third_party_settings][sidekick][sidekick_settings][container][' . $module . '][' . $inputfield->identifier . ']',
'#title' => ucfirst($inputfield->identifier),
'#placeholder' => $inputfield->identifier,
'#value' => $setValue,
'#description' => t('Token are supported'),
];
/* ---- TODO ----
if(in_array('required', $inputfield->validation)){
$element['sidekick_settings']['container'][$module][
$inputfield->identifier]['#required'] = true;
}*/
}
}
$response = new AjaxResponse();
$response->addCommand(new HtmlCommand('#user-input-container', $element));
return $response;
}
/**
* Implements hook_field_widget_settings_summary_alter().
*/
function sidekick_field_widget_settings_summary_alter(&$summary, $context) {
if (in_array($context['widget']->getPluginId(), [
'string_textfield',
'text_textfield',
'string_textarea',
])) {
if ($context['widget']
->getThirdPartySetting('sidekick', 'sidekick_enabled')) {
$summary[] = t('Sidekick enabled.');
if (isset(
$context['widget']->getThirdPartySetting(
'sidekick', 'sidekick_settings'
)['salutation']
)) {
$salutation = ucfirst(
str_replace('_', ' ',
$context['widget']->getThirdPartySetting(
'sidekick', 'sidekick_settings'
)['salutation']
)
);
$summary[] = new TranslatableMarkup(
'Salutation: :salutation',
[':salutation' => $salutation]
);
}
if (isset(
$context['widget']->getThirdPartySetting(
'sidekick',
'sidekick_settings'
)['module']
)) {
$module = ucfirst(
str_replace('_', ' ',
$context['widget']->getThirdPartySetting(
'sidekick', 'sidekick_settings'
)['module']
)
);
$summary[] = new TranslatableMarkup(
'Module: :salutation',
[':salutation' => $module]
);
}
if (isset(
$context['widget']->getThirdPartySetting(
'sidekick', 'sidekick_settings'
)['language']
)) {
$language = ucfirst(
str_replace('_', ' ',
$context['widget']->getThirdPartySetting(
'sidekick', 'sidekick_settings'
)['language']
)
);
$summary[] = new TranslatableMarkup(
'Language: :language',
[':language' => $language]
);
}
if (isset(
$context['widget']->getThirdPartySetting(
'sidekick', 'sidekick_settings'
)['writing_style']
)) {
$writing_style = ucfirst(
str_replace('_', ' ',
$context['widget']->getThirdPartySetting(
'sidekick', 'sidekick_settings'
)['writing_style']
)
);
$summary[] = new TranslatableMarkup(
'Writing style: :writing_style',
[':writing_style' => $writing_style]
);
}
}
}
}
/**
* Implements hook_field_widget_complete_form_alter().
*/
function sidekick_field_widget_complete_form_alter(
&$field_widget_complete_form,
FormStateInterface $form_state,
$context,
) {
$language_code = $form_state->get('langcode');
$sidekick_service = Drupal::service('sidekick.service');
$sidekickKeyStatus = $sidekick_service->checkKeyStatus(
$language_code,
);
if (!empty($sidekickKeyStatus['status']) && $sidekickKeyStatus['status'] == 200) {
$widget = $context['widget'];
if (in_array($widget->getPluginId(), [
'string_textfield',
'text_textfield',
'string_textarea',
]) && $widget->getThirdPartySetting(
'sidekick',
'sidekick_enabled',
FALSE
)) {
if ($widget->getThirdPartySetting(
'sidekick',
'sidekick_settings'
)['manual']) {
$field_widget_complete_form['#attributes']['class'] = array_merge(
$field_widget_complete_form['#attributes']['class'], ['sidekick-field-wrapper']
);
$field_name = $field_widget_complete_form['widget']['#field_name'];
$wrapper_id = 'edit-' . str_replace(
'_',
'-',
strtolower($field_name)
) . '-0-value';
$field_widget_complete_form[$field_name . '_sidekick'] = [
'#type' => 'button',
'#name' => $wrapper_id . '__sidekick',
'#value' => '',
'#executes_submit_callback' => FALSE,
'#field_in_action' => $field_name,
'#input_type' => $widget->getPluginId(),
'#sidekick_module' => $widget->getThirdPartySetting(
'sidekick',
'sidekick_settings'
)['module'] ?? 'meta_description',
'#sidekick_language' => $widget->getThirdPartySetting(
'sidekick',
'sidekick_settings'
)['language'] ?? 'auto',
'#writing_style' => $widget->getThirdPartySetting(
'sidekick',
'sidekick_settings'
)['writing_style'] ?? 'default',
'#salutation' => $widget->getThirdPartySetting(
'sidekick',
'sidekick_settings'
)['salutation'] ?? 'avoid',
'#user_input' => $widget->getThirdPartySetting(
'sidekick',
'sidekick_settings'
)['container'] ?? '',
'#ajax' => [
'callback' => 'sidekick_ajax_callback',
'wrapper' => $wrapper_id,
],
];
$field_widget_complete_form[$field_name . '_sidekick']['#attributes']['class'][] = 'sidekick-button-icon';
$field_widget_complete_form['#attached']['library'][] = 'sidekick/sidekick_css';
$field_widget_complete_form['#attached']['library'][] = 'sidekick/sidekick_js';
}
}
}
}
/**
* Ajax callback for the Sidekick button.
*/
function sidekick_ajax_callback(array $form, FormStateInterface $form_state) {
$form_object = $form_state->getFormObject();
if ($form_object instanceof ContentEntityFormInterface) {
/** @var \Drupal\Core\Entity\Display\EntityFormDisplayInterface $form_display */
$entity_form_display = $form_state->get('form_display');
$entity = $form_object->getEntity();
$entity->in_preview = TRUE;
$entity_form_display->extractFormValues($entity, $form, $form_state);
$button = $form_state->getTriggeringElement();
$element = '#' . explode('__', $button['#name'])[0];
$build = Drupal::service('entity_type.manager')
->getViewBuilder($entity->getEntityTypeId())
->view($entity, 'default');
$output = Drupal::service('renderer')->render($build);
// Get text content send to sidekick.
$content = Html::decodeEntities(strip_tags((string) $output));
$entity->in_preview = NULL;
$userFormFieldValue = $form_state->getValue(
$button['#field_in_action']
)[0]['value'];
$user_input = [];
if ($button['#user_input']) {
$language_code = $form_state->get('langcode');
$sidekick_service = Drupal::service('sidekick.service');
// Module.
$modules = $sidekick_service->getModules(
$language_code
);
$token_service = Drupal::token();
if ($modules) {
foreach ($modules['message']->data as $module) {
if ($module->identifier == $button['#sidekick_module']) {
foreach ($module->user_input as $key => $input) {
$user_input[$key]['identifier'] = $input->identifier;
$wholePageContent = $token_service->replace(
$content,
['node' => $build['#node']],
['clear' => TRUE]
);
$processedValue = $token_service->replace(
$button['#user_input'][$button['#sidekick_module']][$input->identifier],
['node' => $build['#node']],
['clear' => TRUE]
) . ' ' . $userFormFieldValue . ' ' . $wholePageContent;
if (in_array('array', $input->validation)) {
$user_input[$key]['value'] = [$processedValue];
}
elseif ($input->identifier == 'prefer') {
if (!empty($form['#entity_type']) && $form['#entity_type'] == 'node') {
$entity_type = 'node';
$bundle = $entity->getEntityTypeId();
$form_mode = 'default';
$form_display = Drupal::service('entity_display.repository')
->getFormDisplay($entity_type, $bundle, $form_mode);
$specific_widget_type = $form_display->getComponent($button['#field_in_action']);
}
$user_input[$key]['value'] = $specific_widget_type["third_party_settings"]["sidekick"]["sidekick_settings"]["container"]["meta_description"]['prefer'];
}
else {
$user_input[$key]['value'] = $processedValue;
}
}
}
}
}
}
else {
// To maintain old code working.
$user_input = [
[
"identifier" => "content",
"value" => $content,
],
[
"identifier" => "title",
"value" => $entity->label() ?? '',
],
];
}
$language_code = $button['#sidekick_language'];
if ($language_code == 'auto') {
$language_code = Drupal::languageManager()->getCurrentLanguage(
LanguageInterface::TYPE_CONTENT
)->getId();
}
if (strlen($language_code) == 5) {
// @todo Sidekick accepts only 2 digit language codes, is there a better way to extract this from Drupal?
$language_code = explode('-', $language_code)[0];
}
$sidekick_service = Drupal::service('sidekick.service');
// Chat call.
$chatData = $sidekick_service->getChat(
$button['#sidekick_module'],
$language_code,
$button['#writing_style'],
$button['#salutation'],
$user_input
);
$data_from_sidekick = $chatData['message']->data->message->message ?? $chatData['message'];
$response = new AjaxResponse();
if ($chatData['status'] == 200) {
if (
((str_contains($data_from_sidekick, "1.") !== FALSE &&
str_contains($data_from_sidekick, "2.")) ||
str_contains($data_from_sidekick, "```\n")) &&
(
$button['#input_type'] == 'text_textfield' ||
$button['#input_type'] == 'string_textfield'
)
) {
if (str_contains($data_from_sidekick, "```\n")) {
$parts = explode("```\n", $data_from_sidekick);
}
else {
$parts = explode("\n", $data_from_sidekick);
}
$optionString = '';
foreach ($parts as $key => $option) {
$option = preg_replace('/\d+\.\s/', '', $option);
$option = str_replace('```\n', '', $option);
$option = str_replace('"', '', $option);
if ($key == 0) {
$response->addCommand(
new InvokeCommand($element, 'val', [$option])
);
}
else {
$optionString = $optionString . '<li class="ui-menu-item"><a class="ui-menu-item-wrapper">' . $option . '</a></li>';
}
}
$suggestionsClass = 'sidekick-suggestions-for-' . str_replace('#', '', $element);
$response->addCommand(
new RemoveCommand($suggestionsClass)
);
$response->addCommand(
new InvokeCommand($element, 'after', ['<div class="sidekick-suggestions ' . $suggestionsClass . '"></div>'])
);
$response->addCommand(
new HtmlCommand('.' . $suggestionsClass, '<ul class="ui-menu ui-widget ui-widget-content ui-autocomplete ui-front">' . $optionString . '</ul>')
);
$response->addCommand(new InvokeCommand(NULL, 'initSuggestions', [
$element,
'.' . $suggestionsClass,
]));
}
else {
$response->addCommand(
new InvokeCommand($element, 'val', [$data_from_sidekick])
);
}
$response->addCommand(
new RemoveCommand('.sidekick-message .messages')
);
}
else {
$response->addCommand(
new MessageCommand(
$data_from_sidekick,
'.sidekick-message',
['type' => 'error']
)
);
}
return $response;
}
return [];
}
/**
* Ajax callback for the Sidekick button.
*/
function sidekick_image_ajax_callback(
array $form,
FormStateInterface $form_state,
) {
$form_object = $form_state->getFormObject();
if ($form_object instanceof ContentEntityFormInterface) {
/** @var \Drupal\Core\Entity\Display\EntityFormDisplayInterface $form_display */
$button = $form_state->getTriggeringElement();
$element = '[id^=' . explode('__', $button['#name'])[0] . ']';
$field_name = $button['#field_name'];
$sidekick_module = $button['#sidekick_module'];
$support_languages = [
'de' => 'de',
'en' => 'en_US',
'en_GB' => 'en_GB',
];
$language = $form_object->getEntity()->language()->getId();
$language = $support_languages[$language] ?? 'en';
$file = File::load($form_state->getValue($field_name)[0]['fids'][0]);
$image_url = Drupal::service('file_url_generator')
->generateAbsoluteString($file->getFileUri());
$sidekick_api_key = Drupal::service('config.factory')
->get('sidekick.settings')
->get('api_key');
$client = Drupal::service('http_client');
$api_url = 'https://assistant.ai-sidekick.app/api/v1/chat';
$request_options = [];
$request_options[RequestOptions::QUERY] = ['language' => $language];
$request_options[RequestOptions::BODY] = Json::encode([
'module' => $sidekick_module,
'user_input' => [
[
"identifier" => "url",
"value" => $image_url ?? '',
],
],
]);
$request_options[RequestOptions::HEADERS]['Content-Type'] = 'application/json';
$request_options[RequestOptions::HEADERS]['Accept'] = 'application/json';
$request_options[RequestOptions::HEADERS]['Authorization'] = 'Bearer ' . $sidekick_api_key;
try {
$response = $client->request('POST', $api_url, $request_options);
$data = Json::decode((string) $response->getBody());
$data_from_sidekick = $data['data']['message']['message'] ?? '';
$response = new AjaxResponse();
$response->addCommand(
new InvokeCommand($element, 'val', [$data_from_sidekick])
);
return $response;
}
catch (ClientException $e) {
$response = new AjaxResponse();
return $response->addCommand(
new MessageCommand(
json_decode($e->getResponse()
->getBody()
->getContents())->message,
'.sidekick-message',
['type' => 'error']
)
);
}
}
return [];
}
/**
* Implements hook_field_widget_info_alter().
*/
function sidekick_field_widget_info_alter(array &$info) {
// This make new widget replace default to alter process.
$info['image_image']['class'] = ImageWidget::class;
}
/**
* Implements hook_theme().
*/
function sidekick_theme($existing, $type, $theme, $path) {
return [
'image_widget__default' => [
'base hook' => 'image_widget',
],
'usage_bar' => [
'variables' => [
'sidekickAccountUsage' => NULL,
],
],
];
}
/**
* Implements hook_theme_suggestions_alter().
*/
function sidekick_theme_suggestions_alter(
array &$suggestions,
array $variables,
$hook,
) {
// core/themes/claro/templates/content-edit/image-widget.html.twig.
// grouping alt and title, this make new template to have button between.
if ($hook == 'image_widget') {
$suggestions[] = $hook . '__default';
}
}
/**
* Implements hook_help().
*/
function sidekick_help($route_name, RouteMatchInterface $route_match) {
$settings_form_url = Url::fromRoute('sidekick.settings_form')->toString();
switch ($route_name) {
case 'help.page.sidekick':
$output = '';
$output .= '<p>' . new TranslatableMarkup(
'To save the Sidekick API key, go to <a href=":settings_form_url ">Settings form</a>.',
[':settings_form_url ' => $settings_form_url]
) . '</p>';
$output .= '<p>' . new TranslatableMarkup(
'To configure a field to display a Sidekick button next to the field, go to the <strong>Manage form display</strong> tab for the content type. For example: <em>Structure > Content Types > Article > Manage form display</em>. Click on gear icon and check the Enable Sidekick checkbox. Select dropdown for different options and click on Update.'
) . '</p>';
return [
'#type' => 'markup',
'#markup' => $output,
'#allowed_tags' => ['a', 'p', 'strong', 'em', 'br'],
];
}
}
