ai_content_lifecycle-1.0.0/src/Form/ContentLifecycleSettingsForm.php

src/Form/ContentLifecycleSettingsForm.php
<?php

namespace Drupal\ai_content_lifecycle\Form;

use Drupal\ai\AiProviderPluginManager;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Config\TypedConfigManagerInterface;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Configure AI Content Lifecycle settings.
 */
class ContentLifecycleSettingsForm extends ConfigFormBase {

  /**
   * Config settings.
   *
   * @var string
   */
  const SETTINGS = 'ai_content_lifecycle.settings';

  public const DEFAULT_SYSTEM_PROMPT = '
Format:
 ------
Respond XTRUE or XFALSE, nothing else, no pleasantries or other things.

Variables:
 ---------
 Today is [ai_content_lifecycle:date]

INSTRUCTIONS
------------
return XTRUE when the content
[conditions]

Otherwise return XFALSE

This is the content you have evaluate:
----------------------------------------
[context]
  ';

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * The entity type bundle info.
   *
   * @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
   */
  protected $entityTypeBundleInfo;

  /**
   * The AI provider manager.
   *
   * @var \Drupal\ai\AiProviderPluginManager
   */
  protected $aiProviderManager;

  /**
   * The example prompt.
   *
   * @var string
   */
  protected $example;

  /**
   * Constructor for ContentLifecycleSettingsForm.
   *
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
   *   The config factory.
   * @param \Drupal\Core\Config\TypedConfigManagerInterface $typedConfigManager
   *   The typed config manager.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   * @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_type_bundle_info
   *   The entity type bundle info.
   * @param \Drupal\ai\AiProviderPluginManager $aiProviderManager
   *   The AI provider plugin manager.
   */
  public function __construct(
    ConfigFactoryInterface $config_factory,
    TypedConfigManagerInterface $typedConfigManager,
    EntityTypeManagerInterface $entity_type_manager,
    EntityTypeBundleInfoInterface $entity_type_bundle_info,
    AiProviderPluginManager $aiProviderManager,
  ) {
    parent::__construct($config_factory, $typedConfigManager);
    $this->entityTypeManager = $entity_type_manager;
    $this->entityTypeBundleInfo = $entity_type_bundle_info;
    $this->aiProviderManager = $aiProviderManager;
    $this->example = $this->t("- it mentions the queen of england.\n- it mentions the king of Germany.\n- it contains inconsistencies or contradictions\n- you are really sure that it is outdated and a human should check it");

  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('config.factory'),
      $container->get('config.typed'),
      $container->get('entity_type.manager'),
      $container->get('entity_type.bundle.info'),
      $container->get('ai.provider')
    );
  }

  /**
   * {@inheritdoc}
   */
  protected function getEditableConfigNames() {
    return [
      static::SETTINGS,
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'ai_content_lifecycle_settings';
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state) {
    $config = $this->config(static::SETTINGS);

    // Ai configuration hidden below.
    $form['ai_settings'] = [
      '#title' => $this->t('Advanced LLM settings'),
      '#type' => 'details',
      '#tree' => TRUE,
      '#open' => FALSE,
      '#weight' => 4,
    ];

    // Model selection.
    $llm_model_options = $this->aiProviderManager->getSimpleProviderModelOptions('chat');
    array_shift($llm_model_options);
    $form['ai_settings']['default_model'] = [
      '#type' => 'select',
      "#empty_option" => $this->t('-- Default from AI module (chat) --'),
      '#title' => $this->t('LLM to use for content evaluation.'),
      '#default_value' => $config->get('default_model'),
      '#options' => $llm_model_options,
      '#description' => $this->t('Select which provider to use for this plugin. See the <a href=":link">Provider overview</a> for details about each provider.', [':link' => '/admin/config/ai/providers']),
    ];

    // Pre prompt.
    $form['ai_settings']['pre_prompt'] = [
      '#type' => 'textarea',
      '#rows' => 25,
      '#title' => $this->t('Pre prompt'),
      '#default_value' => $config->get('pre_prompt') ?: static::DEFAULT_SYSTEM_PROMPT,
      '#description' => $this->t('The prompt used for marking content. you can use the following tokens:
      <br><b>[conditions]</b> (the reasons mentioned above why content might be requiring an update)
      <br><b>[ai_content_lifecycle:date]</b> The current date
      <br><b>[lang]</b> The current language of the admin interface'),
    ];

    // Things to mark for updating.
    $form['default_prompt'] = [
      '#type' => 'textarea',
      '#title' => $this->t('Mark my content when'),
      '#default_value' => $config->get('default_prompt'),
      '#description' => $this->t('Type something like "it mentions the old tax rate of 19% which is now 21%."'),
      '#rows' => 4,
      '#placeholder' => $this->example,
    ];

    $form['description'] = [
      '#markup' => $this->t('<p>Select which content entities should be checked by the AI Content Lifecycle system.</p>'),
    ];

    // Get all content entity types that have bundles.
    $content_entity_types = $this->getAvailableContentEntityTypes();

    $form['entity_types'] = [
      '#type' => 'details',
      '#title' => $this->t('What to check'),
      '#tree' => TRUE,
      '#open' => FALSE,
    ];

    // Get saved settings.
    $enabled_entity_types = $config->get('enabled_entity_types') ?: [];
    $enabled_bundles = $config->get('enabled_bundles') ?: [];
    $bundle_prompts = $config->get('bundle_prompts') ?: [];
    $view_modes = $config->get('view_modes') ?: [];

    // For each content entity type, let admin choose which bundles to enable.
    foreach ($content_entity_types as $entity_type_id => $entity_type) {
      $form['entity_types'][$entity_type_id] = [
        '#type' => 'details',
        '#title' => $entity_type->getLabel(),
        '#open' => !empty($enabled_entity_types[$entity_type_id]),
      ];

      $form['entity_types'][$entity_type_id]['enabled'] = [
        '#type' => 'checkbox',
        '#title' => $this->t('Check contents of @type', ['@type' => $entity_type->getLabel()]),
        '#default_value' => $enabled_entity_types[$entity_type_id] ?? FALSE,
      ];

      // Add view mode selection.
      $view_mode_options = $this->getViewModeOptions($entity_type_id);
      if (!empty($view_mode_options)) {
        $form['entity_types'][$entity_type_id]['view_mode'] = [
          '#type' => 'select',
          '#title' => $this->t('View mode for content extraction'),
          '#options' => $view_mode_options,
          '#default_value' => $view_modes[$entity_type_id] ?? 'search_index',
          '#required' => TRUE,
          '#description' => $this->t('Select which view mode to use when extracting content for AI analysis.'),
          '#states' => [
            'visible' => [
              ':input[name="entity_types[' . $entity_type_id . '][enabled]"]' => ['checked' => TRUE],
            ],
          ],
        ];
      }

      // Get all bundles for the entity type.
      $bundles = $this->entityTypeBundleInfo->getBundleInfo($entity_type_id);

      if (!empty($bundles)) {
        $bundle_options = [];
        foreach ($bundles as $bundle_id => $bundle_info) {
          $bundle_options[$bundle_id] = $bundle_info['label'];
        }

        $form['entity_types'][$entity_type_id]['bundles'] = [
          '#type' => 'checkboxes',
          '#title' => $this->t('Bundles to check'),
          '#options' => $bundle_options,
          '#default_value' => $enabled_bundles[$entity_type_id] ?? [],
          '#states' => [
            'visible' => [
              ':input[name="entity_types[' . $entity_type_id . '][enabled]"]' => ['checked' => TRUE],
            ],
          ],
        ];

        // Add bundle-specific prompt configurations
        $form['entity_types'][$entity_type_id]['prompt_config'] = [
          '#type' => 'details',
          '#title' => $this->t('Prompt specifically for @type', ['@type' => $entity_type->getLabel()]),
          '#open' => FALSE,
          '#states' => [
            'visible' => [
              ':input[name="entity_types[' . $entity_type_id . '][enabled]"]' => ['checked' => TRUE],
            ],
          ],
        ];

        foreach ($bundles as $bundle_id => $bundle_info) {
          $prompt_id = $entity_type_id . '_' . $bundle_id;
          $form['entity_types'][$entity_type_id]['prompt_config'][$prompt_id] = [
            '#type' => 'textarea',
            '#title' => $this->t('Mark @bundle when', ['@bundle' => $bundle_info['label']]),
            '#default_value' => is_array($bundle_prompts[$entity_type_id][$bundle_id] ?? NULL)
              ? ($bundle_prompts[$entity_type_id][$bundle_id]['value'] ?? '')
              : ($bundle_prompts[$entity_type_id][$bundle_id] ?? ''),
            '#description' => $this->t('AI prompt template for content lifecycle checks for @bundle items. Use [entity:field_name] tokens to include entity field values.',
              ['@bundle' => $bundle_info['label']]),
            '#placeholder' => $this->example,
            '#rows' => 6,
            '#states' => [
              'visible' => [
                ':input[name="entity_types[' . $entity_type_id . '][bundles][' . $bundle_id . ']"]' => ['checked' => TRUE],
              ],
            ],
          ];
        }
      }
      else {
        $form['entity_types'][$entity_type_id]['no_bundles'] = [
          '#markup' => $this->t('This entity type does not have bundles.'),
        ];

        // For entity types without bundles, add a single prompt configuration
        $prompt_id = $entity_type_id;
        $form['entity_types'][$entity_type_id]['prompt_config'] = [
          '#type' => 'text_format',
          '#title' => $this->t('Prompt input for @type', ['@type' => $entity_type->getLabel()]),
          '#default_value' => $bundle_prompts[$entity_type_id]['default']['value'] ?? '',
          '#format' => $bundle_prompts[$entity_type_id]['default']['format'] ?? 'plain_text',
          '#description' => $this->t('AI prompt template for content lifecycle checks. Use [entity:field_name] tokens to include entity field values.'),
          '#rows' => 6,
          '#states' => [
            'visible' => [
              ':input[name="entity_types[' . $entity_type_id . '][enabled]"]' => ['checked' => TRUE],
            ],
          ],
        ];
      }
    }

    // Add batch create button as a submit button
    $form['actions']['batch_create'] = [
      '#type' => 'submit',
      '#value' => $this->t('Analyze content'),
      '#button_type' => 'primary',
      '#submit' => ['::submitForm', '::redirectToConfirm'],
      '#weight' => 5,
    ];

    return parent::buildForm($form, $form_state);
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $config = $this->config(static::SETTINGS);
    $content_entity_types = $this->getAvailableContentEntityTypes();

    // Save the default prompt
    $config->set('default_prompt', $form_state->getValue('default_prompt'));
    $config->set('default_model', $form_state->getValue('ai_settings')['default_model']);
    $config->set('pre_prompt', $form_state->getValue('ai_settings')['pre_prompt']);

    $enabled_entity_types = [];
    $enabled_bundles = [];
    $bundle_prompts = [];
    $view_modes = [];

    // Get all values from the form
    $values = $form_state->getValues();
    $entity_types = $values['entity_types'];

    foreach (array_keys($content_entity_types) as $entity_type_id) {
      // Check if this entity type section exists in the submitted form values.
      if (isset($entity_types[$entity_type_id]['enabled']) && $entity_types[$entity_type_id]['enabled']) {
        $enabled_entity_types[$entity_type_id] = TRUE;

        // Check if this entity type has bundles.
        if (isset($entity_types[$entity_type_id]['bundles'])) {
          $enabled_bundles[$entity_type_id] = array_filter($entity_types[$entity_type_id]['bundles']);

          // Save prompts for each bundle.
          foreach (array_keys(array_filter($entity_types[$entity_type_id]['bundles'])) as $bundle_id) {
            $prompt_id = $entity_type_id . '_' . $bundle_id;
            if (isset($entity_types[$entity_type_id]['prompt_config'][$prompt_id])) {
              $bundle_prompts[$entity_type_id][$bundle_id] = $entity_types[$entity_type_id]['prompt_config'][$prompt_id];
            }
            if (isset($entity_types[$entity_type_id]['view_mode'])) {
              $view_modes[$entity_type_id][$bundle_id] = $entity_types[$entity_type_id]['view_mode'];
            }
          }
        }
        else {
          // For entity types without bundles.
          if (isset($entity_types[$entity_type_id]['prompt_config'])) {
            $bundle_prompts[$entity_type_id]['default'] = $entity_types[$entity_type_id]['prompt_config'];
          }
        }
      }
    }
    $config
      ->set('enabled_entity_types', $enabled_entity_types)
      ->set('enabled_bundles', $enabled_bundles)
      ->set('bundle_prompts', $bundle_prompts)
      ->set('view_modes', $view_modes)
      ->save();

    parent::submitForm($form, $form_state);
  }

  /**
   * Redirects to the confirmation page after form submission.
   */
  public function redirectToConfirm(array &$form, FormStateInterface $form_state) {
    $form_state->setRedirect('ai_content_lifecycle.batch_confirm');
  }

  /**
   * Get available content entity types.
   *
   * @return \Drupal\Core\Entity\EntityTypeInterface[]
   *   Array of content entity types.
   */
  protected function getAvailableContentEntityTypes() {
    $entity_types = [];
    $definitions = $this->entityTypeManager->getDefinitions();

    foreach ($definitions as $entity_type_id => $entity_type) {
      // Only include content entities (skip config entities).
      if ($entity_type->entityClassImplements('\Drupal\Core\Entity\ContentEntityInterface')) {
        $entity_types[$entity_type_id] = $entity_type;
      }
    }

    // Sort by label.
    uasort($entity_types, function ($a, $b) {
      return strnatcasecmp($a->getLabel(), $b->getLabel());
    });

    return $entity_types;
  }

  /**
   * Get available view modes for an entity type.
   *
   * @param string $entity_type_id
   *   The entity type ID.
   *
   * @return array
   *   Array of view modes.
   */
  protected function getViewModeOptions($entity_type_id) {
    $view_modes = [];

    $view_mode_storage = $this->entityTypeManager->getStorage('entity_view_mode');
    $view_mode_ids = $view_mode_storage->getQuery()
      ->condition('targetEntityType', $entity_type_id)
      ->execute();

    if (!empty($view_mode_ids)) {
      $view_mode_entities = $view_mode_storage->loadMultiple($view_mode_ids);
      // Add default view mode
      $view_modes['default'] = $this->t('Default');

      foreach ($view_mode_entities as $view_mode) {
        $id = str_replace($entity_type_id . '.', '', $view_mode->id());
        $view_modes[$id] = $view_mode->label();
      }
    }

    if (empty($view_modes)) {
      $view_modes['default'] = $this->t('Default');
    }

    return $view_modes;
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc