The best way to implement new functionality in Drupal is the modules. So in order to implement OpenAI I need to create a module. Below you can see a typical Drupal 9 module info file.
File open_ai_integration/open_ai_integration.info.yml
name: Open AI integration
type: module
description: Open AI integration.
package: Custom
core_version_requirement: ^8 || ^9
configure: open_ai_integration.settings_form
Next, let’s create a configuration form. It is a good way to store the settings required to use in Drupal 9 in the configurations, instead of writing them directly in the code. And the first thing we need to create is permission, so the form can be accessed only by the users we want to allow to. Here is the permission implementation:
File open_ai_integration/open_ai_integration.permissions.yml
administer open ai configuration:
title: 'Administer Open AI configuration'
Next in Drupal 9 in order to implement a form, it is a good idea to create a route, by which you can access this form. It is not always a required thing, but in our case it is a necessary step, especially because we already used the name for the new form route in the module info file. Here’s the implementation:
File open_ai_integration/open_ai_integration.routing.yml
open_ai_integration.settings_form:
path: '/admin/config/system/open-ai'
defaults:
_title: 'Open AI settings'
_form: 'Drupal\open_ai_integration\Form\SettingsForm'
requirements:
_permission: 'administer open ai configuration'
And for the last, after all the preparation, I can create the form itself. Firstly, it is a good idea to decide which settings need to be saved. I decided to save the API url, API key and model. All values put into the fields are then saved, using the Drupal configuration system and now can be transported between different environments. You could already see the name of the class I used for the form creation in the route configuration, so here’s the whole form implementation:
File open_ai_integration/src/Form/SettingsForm.php
<?php
namespace Drupal\open_ai_integration\Form;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
/**
* Configure Open AI settings.
*/
class SettingsForm extends ConfigFormBase {
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'open_ai_integration_settings';
}
/**
* {@inheritdoc}
*/
protected function getEditableConfigNames() {
return ['open_ai_integration.settings'];
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$form['api_token'] = [
'#type' => 'textarea',
'#required' => TRUE,
'#title' => $this->t('OpenAI token'),
'#default_value' => $this->config('open_ai_integration.settings')
->get('api_token'),
];
$form['api_url'] = [
'#type' => 'textfield',
'#required' => TRUE,
'#title' => $this->t('OpenAI API url'),
'#default_value' => $this->config('open_ai_integration.settings')
->get('api_url'),
];
$form['model'] = [
'#type' => 'textfield',
'#required' => TRUE,
'#title' => $this->t('OpenAI model'),
'#default_value' => $this->config('open_ai_integration.settings')
->get('model'),
];
return parent::buildForm($form, $form_state);
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$this->config('open_ai_integration.settings')
->set('api_token', $form_state->getValue('api_token'))
->set('api_url', $form_state->getValue('api_url'))
->set('model', $form_state->getValue('model'))
->save();
parent::submitForm($form, $form_state);
}
}
Next, let’s implement the method, which will allow us to make a request to the Open AI API. In the Drupal 9 it is generally a good idea to use services, when creating functionality, which could be used globally across the Drupal website. So here’s the implementation of such a service:
File open_ai_integration/src/OpenAiClient.php
<?php
namespace Drupal\open_ai_integration;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Drupal\Core\Logger\LoggerChannelInterface;
use GuzzleHttp\Client;
class OpenAiClient {
/**
* Configuration factory.
*
* @var \Drupal\Core\Config\ConfigFactoryInterface
*/
protected ConfigFactoryInterface $configFactory;
/**
* Open AI logger channel object.
*
* @var \Drupal\Core\Logger\LoggerChannelInterface
*/
protected LoggerChannelInterface $loggerChannel;
/**
* HTTP client.
*
* @var \GuzzleHttp\Client
*/
protected Client $httpClient;
public function __construct(ConfigFactoryInterface $config_factory, LoggerChannelFactoryInterface $logger_factory, Client $http_client) {
$this->configFactory = $config_factory;
$this->loggerChannel = $logger_factory->get('open_ai_integration');
$this->httpClient = $http_client;
}
/**
* Sends https query to the Open AI.
*
* @param array $messages
* Messages to send array. Example:
* [
* [
* 'role' => 'user',
* 'content' => 'Message",
* ],
* ]
*
* @return \Psr\Http\Message\ResponseInterface
* Open AI request response
*/
public function query(array $messages) {
$open_ai_config = $this->configFactory->get('open_ai_integration.settings');
try {
return $this->httpClient->post($open_ai_config->get('api_url'), [
'headers' => [
'Authorization' => 'Bearer ' . $open_ai_config->get('api_token'),
],
'json' => [
'model' => $open_ai_config->get('model'),
'messages' => $messages,
]
]);
}
catch (\Exception $e) {
$this->loggerChannel->error($e->getMessage());
return NULL;
}
}
}
This file contains service implementation. Most important of it is the query() function, which is used to send requests to Open AI service. Also, to use API data, stored using configuration settings form, I am using configuration factory.
But, that is not all, that is required. In Drupal 9 you need to define a created class, as a service in order for it to be service. So here’s the YAML configurations, which define the created class as a service:
File open_ai_integration/open_ai_integration.services.yml
services:
open_ai_integration.client:
class: Drupal\open_ai_integration\OpenAiClient
arguments: ['@config.factory', '@logger.factory', '@http_client']
So, that is all that is required to implement a service, which allows us to make requests to the Open AI and receive the answers in Drupal 9. But how exactly will it look? Allow me to show you the example in the next section.