Skip to content
Snippets Groups Projects
Commit 564f2cc7 authored by Kevin Quillen's avatar Kevin Quillen
Browse files

Issue #3342260 by kevinquillen: 'open_ai' config related errors

parent ac739fc9
No related branches found
Tags 1.0.0-alpha2
No related merge requests found
Showing
with 163 additions and 633 deletions
openai_api.settings:
type: config_object
label: 'OpenAI API settings'
mapping:
api_key:
type: string
label: 'OpenAI API key'
api_token:
type: string
label: 'OpenAI API key'
api_org:
type: string
label: 'OpenAI organization'
services:
openai_api.article_generation.commands:
class: \Drupal\openai_api\Commands\BatchArticleGenerationCommands
openai_api.content_generation.commands:
class: \Drupal\openai_api\Commands\ContentGenerationCommand
tags:
- { name: drush.command }
openai_api.media_generation.commands:
......
#openai_api.api_settings:
# title: OpenAI API settings
# description: Manage OpenAI API settings.
# parent: system.admin_config_services
# route_name: openai_api.api_settings
# weight: 10
openai_api.article_generation_config:
title: Article generation
description: Form to generate article
parent: system.admin_content
route_name: openai_api.article_generation_config
weight: 10
openai_api.content_generation_config:
title: Content generation
description: Demonstrates basic content generation.
parent: openai.admin_config_openai
route_name: openai_api.content_generation_config
weight: 2
openai_api.image_generation_config:
title: Image generation
description: Form to generate image
parent: system.admin_content
route_name: openai_api.image_generation_config
weight: 10
#openai_api.image_generation_config:
# title: Image generation
# description: Demonstrates basic image generation.
# parent: openai.admin_config_openai
# route_name: openai_api.image_generation_config
# weight: 10
#openai_api.api_settings:
# path: '/admin/config/system/api/openai/settings'
# defaults:
# _title: 'OpenAI API settings'
# _form: 'Drupal\openai_api\Form\ApiSettingsForm'
# requirements:
# _permission: 'administer site configuration'
openai_api.article_generation_config:
path: '/admin/config/system/article-generation'
openai_api.content_generation_config:
path: '/admin/config/openai/openai-api/content-generation'
defaults:
_title: 'Articles Generation'
_form: 'Drupal\openai_api\Form\ArticleGenerationConfigForm'
_title: 'Content Generation'
_form: 'Drupal\openai_api\Form\ContentGenerationConfigForm'
requirements:
_permission: 'administer site configuration'
openai_api.image_generation_config:
path: '/admin/config/system/image-generation'
path: '/admin/config/openai/openai-api/image-generation'
defaults:
_title: 'Image Generation'
_form: 'Drupal\openai_api\Form\ImageGenerationConfigForm'
......
services:
openai_api.client:
class: Drupal\openai_api\Client
arguments: ['@config.factory']
factory: ['@openai_api.client_factory', create]
openai_api.client_factory:
class: Drupal\openai_api\ClientFactory
arguments: ['@config.factory']
logger.channel.openai_api:
parent: logger.channel_base
arguments: ['openai_api']
openai_api.openai.service:
class: Drupal\openai_api\OpenAIService
arguments: ['@config.factory']
openai_api.generation.service:
class: Drupal\openai_api\GenerationService
openai_api.article_generation.commands:
class: \Drupal\openai_api\Commands\BatchArticleGenerationCommands
openai_api.content_generation.commands:
class: \Drupal\openai_api\Commands\ContentGenerationCommand
tags:
- { name: drush.command }
openai_api.media_generation.commands:
......
......@@ -2,7 +2,7 @@
namespace Drupal\openai_api\Commands;
use Drupal\openai_api\Controller\OpenAIApiController;
use Drupal\openai_api\Controller\GenerationController;
use Drush\Commands\DrushCommands;
use Symfony\Component\Console\Output\ConsoleOutput;
......@@ -17,7 +17,7 @@ use Symfony\Component\Console\Output\ConsoleOutput;
* - http://cgit.drupalcode.org/devel/tree/src/Commands/DevelCommands.php
* - http://cgit.drupalcode.org/devel/tree/drush.services.yml
*/
class BatchArticleGenerationCommands extends DrushCommands {
class ContentGenerationCommand extends DrushCommands {
const IMAGE_RESOLUTION = [
'256x256' => '256x256',
......@@ -45,12 +45,12 @@ class BatchArticleGenerationCommands extends DrushCommands {
}
/**
* Generate article.
* Generate content.
*
* @command openai:generate-article
* @command openai:generate-content
* @aliases oga
*
* @usage generate:article
* @usage generate:content
*
*/
public function generateArticleDrushCommand() {
......@@ -98,6 +98,9 @@ class BatchArticleGenerationCommands extends DrushCommands {
'nbr_article_generated' => $batchId,
'subject' => $datas[$i]['subject'],
'model' => $datas[$i]['model'],
'content_type' => $datas[$i]['content_type'],
'title' => $datas[$i]['title'],
'body' => $datas[$i]['body'],
'max_token' => $datas[$i]['max_token'],
'temperature' => $datas[$i]['temperature'],
'image_prompt' => $datas[$i]['image_prompt'],
......@@ -150,7 +153,7 @@ class BatchArticleGenerationCommands extends DrushCommands {
->ask('Your subject for the article type ' . ($i + 1) . ' ?', 'The story of Henry');
}
else {
$openAiController = new OpenAIApiController(\Drupal::service('openai_api.openai.service'), \Drupal::service('config.factory'));
$openAiController = new GenerationController(\Drupal::service('openai.client'), \Drupal::service('config.factory'));
$subjects = $openAiController->getSubjectsVocabularyTerms();
if ($subjects) {
$articles[$i]['subject'] = $this->io()
......
......@@ -5,18 +5,18 @@ namespace Drupal\openai_api\Controller;
use Drupal\Core\Config\ConfigFactory;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Entity\EntityTypeManager;
use OpenAI\Client;
use Drupal\Core\File\FileSystemInterface;
use Drupal\file\Entity\File;
use Drupal\image\Entity\ImageStyle;
use Drupal\media\Entity\Media;
use Drupal\node\Entity\Node;
use Drupal\openai_api\OpenAIService;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Returns responses for openai api routes.
*/
class OpenAIApiController extends ControllerBase {
class GenerationController extends ControllerBase {
const MODELS_OPTIONS = [
'text-davinci-003',
......@@ -33,22 +33,22 @@ class OpenAIApiController extends ControllerBase {
protected $configFactory;
/**
* Defining the openAiService object.
* The OpenAI client.
*
* @var \Drupal\openai_api\OpenAIService
* @var \OpenAI\Client
*/
protected OpenAIService $openAiService;
protected Client $client;
/**
* Defining a constructor for dependencies.
*
* @param \Drupal\openai_api\OpenAIService $openaiService
* The openAIService object.
* @param \OpenAI\Client
* The OpenAI client.
* @param \Drupal\Core\Config\ConfigFactory $config_factory The config
* factory.
*/
public function __construct(OpenAIService $openaiService, ConfigFactory $config_factory) {
$this->openAiService = $openaiService;
public function __construct(Client $client, ConfigFactory $config_factory) {
$this->client = $client;
$this->configFactory = $config_factory;
}
......@@ -58,12 +58,12 @@ class OpenAIApiController extends ControllerBase {
* @param \Symfony\Component\DependencyInjection\ContainerInterface $container
* The ContainerInterface object.
*
* @return \Drupal\openai_api\Controller\OpenAIApiController
* The OpenAIApiController object.
* @return \Drupal\openai_api\Controller\GenerationController
* The GenerationController object.
*/
public static function create(ContainerInterface $container): OpenAIApiController {
public static function create(ContainerInterface $container): GenerationController {
return new static(
$container->get('openai_api.openai.service'),
$container->get('openai.client'),
$container->get('openai_api.settings')
);
}
......@@ -85,22 +85,15 @@ class OpenAIApiController extends ControllerBase {
$max_token,
$temperature
): string {
$textCall = $this->openAiService->getText(
$model,
$text,
$max_token,
$temperature
);
if ($textCall->getStatusCode() === 200) {
$completion = $this->openAiService->getResponseBody($textCall);
$return = $completion['choices'][0]['text'];
}
else {
$return = '';
}
$response = $this->client->completions()->create([
'model' => $model,
'prompt' => trim($text),
'temperature' => (int) $temperature,
'max_tokens' => (int) $max_token,
]);
return $return;
$result = $response->toArray();
return trim($result["choices"][0]["text"]) ?? '';
}
/**
......@@ -116,13 +109,13 @@ class OpenAIApiController extends ControllerBase {
$prompt,
$size,
): string {
$imgCall = $this->openAiService->getImageUrl(
$imgCall = $this->client->getImageUrl(
$prompt,
$size,
);
if ($imgCall->getStatusCode() === 200) {
$imgUrl = $this->openAiService->getResponseBody($imgCall);
$imgUrl = $this->client->getResponseBody($imgCall);
$return = $imgUrl['data'][0]['url'];
}
else {
......@@ -141,10 +134,10 @@ class OpenAIApiController extends ControllerBase {
* @throws \GuzzleHttp\Exception\GuzzleException
*/
public function getModelsResponseBodyData(): array {
$modelsCall = $this->openAiService->getModels();
$modelsCall = $this->client->getModels();
if ($modelsCall->getStatusCode() === 200) {
$models = $this->openAiService->getResponseBody($modelsCall);
$models = $this->client->getResponseBody($modelsCall);
$return = $models['data'];
}
else {
......@@ -189,12 +182,12 @@ class OpenAIApiController extends ControllerBase {
*
* @throws \Drupal\Core\Entity\EntityStorageException
*/
public function generateArticle(array $data, string $body, ?string $img = NULL): int {
public function generateArticle(array $data, string $body, string $content_type, string $title_field, string $body_field, ?string $img = NULL): int {
$config = $this->configFactory->get('openai_api.settings');
$article = Node::create(['type' => $config->get('content_type')]);
$article->set($config->get('field_title'), $data['subject']);
$article->set($config->get('field_body'), $body);
$article = Node::create(['type' => $content_type]);
$article->set($title_field, $data['subject']);
$article->set($body_field, $body);
// Set article img if prompt are provided in form.
if ($img !== NULL) {
......
<?php
namespace Drupal\openai_api\Form;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
/**
* Configure OpenAI api settings for this site.
*/
class ApiSettingsForm extends ConfigFormBase {
//
// const NOT_ALLOWED_FIELDS = [
// 'nid',
// 'uuid',
// 'vid',
// 'langcode',
// 'revision_timestamp',
// 'revision_uid',
// 'revision_log',
// 'status',
// 'uid',
// 'created',
// 'changed',
// 'promote',
// 'sticky',
// 'default_langcode',
// 'revision_default',
// 'revision_translation_affected',
// 'path',
// 'type',
// ];
/**
* {@inheritdoc}
*
* @return string
* The unique string identifying the form.
*/
public function getFormId() {
return 'openai_api_api_settings';
}
/**
* {@inheritdoc}
*
* @return array
*/
protected function getEditableConfigNames() {
return ['openai_api.settings'];
}
/**
* {@inheritdoc}
*
* @param array $form
* The settings form.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The form state.
*
* @return array
*/
public function buildForm(array $form, FormStateInterface $form_state) {
// $form['api_settings_container'] = [
// '#type' => 'details',
// '#title' => $this->t('API settings'),
// '#open' => FALSE,
// '#required' => TRUE,
// ];
$api_key = $this->config('openai_api.settings')->get('api_token') ?? $this->config('openai_api.settings')->get('api_key');
$form['api_key'] = [
'#required' => TRUE,
'#type' => 'textfield',
'#title' => $this->t('API Key'),
'#default_value' => $api_key,
'#description' => $this->t('The API key is required to interface with OpenAI services. Get your API key by signing up on the <a href="@link" target="_blank">OpenAI website</a>.', ['@link' => 'https://openai.com/api']),
];
$form['api_org'] = [
'#type' => 'textfield',
'#title' => $this->t('Organization name/ID'),
'#default_value' => $this->config('openai_api.settings')->get('api_org'),
'#description' => $this->t('The organization name or ID on your OpenAI account. This is required for some OpenAI services to work correctly.'),
];
// $form['article_settings_container'] = [
// '#type' => 'details',
// '#title' => $this->t('Article settings'),
// '#open' => TRUE,
// '#required' => TRUE,
// ];
//
// $types = [];
// $contentTypes = \Drupal::service('entity_type.manager')
// ->getStorage('node_type')
// ->loadMultiple();
// foreach ($contentTypes as $contentType) {
// $types[$contentType->id()] = $contentType->label();
// }
// $form['article_settings_container']['content_type'] = [
// '#required' => TRUE,
// '#type' => 'select',
// '#title' => $this->t('Content type'),
// '#options' => $types,
// '#empty_option' => $this->t("- Choose a content type -"),
// '#description' => $this->t("Content type for generating article."),
// '#default_value' => $this->config('openai_api.settings')
// ->get('content_type'),
// '#ajax' => [
// 'callback' => '::rebuild_form',
// 'effect' => 'fade',
// 'wrapper' => 'js-article-setting-wrapper',
// 'event' => 'change',
// 'progress' => [
// 'type' => 'throbber',
// ],
// ],
// ];
//
// $form['article_settings_container']['fields_container'] = [
// '#type' => 'container',
// '#prefix' => '<div id="js-article-setting-wrapper">',
// '#suffix' => '</div>',
// ];
//
// $field_options = $this->get_field_options($form, $form_state);
// $form['article_settings_container']['fields_container']['field_title'] = [
// '#type' => 'select',
// '#title' => t('Field for title'),
// '#options' => !empty($field_options) ? $field_options : ['' => "- No field -"],
// '#description' => $this->t("Choose a field for your article title."),
// '#default_value' => $this->config('openai_api.settings')
// ->get('field_title'),
// ];
//
// $form['article_settings_container']['fields_container']['field_body'] = [
// '#type' => 'select',
// '#title' => t('Field for body'),
// '#options' => !empty($field_options) ? $field_options : ['' => "- No field -"],
// '#description' => $this->t("Choose a field for your article body."),
// '#default_value' => $this->config('openai_api.settings')
// ->get('field_body'),
// ];
//
// $form['article_settings_container']['fields_container']['field_image'] = [
// '#type' => 'select',
// '#title' => t('Field for image'),
// '#options' => !empty($field_options) ? $field_options : ['' => "- No field -"],
// '#description' => $this->t("Choose a field for your article image."),
// '#default_value' => $this->config('openai_api.settings')
// ->get('field_image'),
// ];
//
// $vocabulary = $this->get_vocabulary_options();
// $form['article_settings_container']['vocabulary'] = [
// '#type' => 'select',
// '#title' => t('Subject vocabulary'),
// '#options' => !empty($vocabulary) ? $vocabulary : ['' => "- Choose a vocabulary -"],
// '#description' => $this->t("Choose a vocabulary for filling subjects."),
// '#default_value' => $this->config('openai_api.settings')
// ->get('vocabulary'),
// ];
return parent::buildForm($form, $form_state);
}
public function rebuild_form($form, &$form_state) {
// $form_state->setRebuild();
// return $form['article_settings_container']['fields_container'];
}
public function get_field_options($form, $form_state): array {
// $options = [];
// $content_type = $form_state->getValue('content_type');
// if ($content_type == null) {
// $content_type = $this->config('openai_api.settings')->get('content_type');
// }
// if ($content_type !== NULL) {
// $entityFieldManager = \Drupal::service('entity_field.manager');
// $fields = $entityFieldManager->getFieldDefinitions('node', $content_type);
//
// /** @var \Drupal\Core\Field\FieldDefinition $field */
// foreach ($fields as $field) {
// if (!in_array($field->getName(), self::NOT_ALLOWED_FIELDS)) {
// $options[$field->getName()] = $field->getName();
// }
// }
// }
//
// return $options;
}
public function get_vocabulary_options(): array {
// $vocabulary_options = [];
// $vocabularies = Vocabulary::loadMultiple();
//
// /** @var \Drupal\taxonomy\Entity\Vocabulary $vocabulary */
// foreach ($vocabularies as $vocabulary) {
// $vocabulary_options[$vocabulary->id()] = $vocabulary->label();
// }
//
// return $vocabulary_options;
}
/**
* {@inheritdoc}
*
* @param array $form The form.
* @param \Drupal\Core\Form\FormStateInterface $form_state The form state.
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$this->config('openai_api.settings')
->set('api_key', $form_state->getValue('api_key'))
->set('api_token', $form_state->getValue('api_token'))
->set('api_org', $form_state->getValue('api_org'))
// ->set('api_url', $form_state->getValue('api_url'))
// ->set('content_type', $form_state->getValue('content_type'))
// ->set('vocabulary', $form_state->getValue('vocabulary'))
// ->set('field_title', $form_state->getValue('field_title'))
// ->set('field_body', $form_state->getValue('field_body'))
// ->set('field_image', $form_state->getValue('field_image'))
->save();
parent::submitForm($form, $form_state);
}
}
......@@ -3,19 +3,20 @@
namespace Drupal\openai_api\Form;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Entity\EntityTypeManager;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Link;
use Drupal\openai_api\Commands\BatchArticleGenerationCommands;
use Drupal\openai_api\Controller\OpenAIApiController;
use Drupal\openai_api\OpenAIService;
use Drupal\openai_api\Commands\ContentGenerationCommand;
use Drupal\openai_api\Controller\GenerationController;
use Symfony\Component\DependencyInjection\ContainerInterface;
use OpenAI\Client;
/**
* Configure openai api settings for this site.
* Content generator.
*/
class ArticleGenerationConfigForm extends ConfigFormBase {
class ContentGenerationConfigForm extends ConfigFormBase {
const IMAGE_RESOLUTION = [
'256x256' => '256x256',
......@@ -43,18 +44,25 @@ class ArticleGenerationConfigForm extends ConfigFormBase {
protected EntityTypeManager $entityTypeManager;
/**
* The OpenAIService object.
* The entity field manager service.
*
* @var \Drupal\openai_api\OpenAIService
* @var \Drupal\Core\Entity\EntityFieldManagerInterface
*/
protected OpenAIService $openaiService;
protected EntityFieldManagerInterface $entityFieldManager;
/**
* The OpenAI client.
*
* @var \OpenAI\Client
*/
protected Client $client;
/**
* Defining the BatchArticleGenerationCommands object.
*
* @var \Drupal\openai_api\Commands\BatchArticleGenerationCommands
* @var \Drupal\openai_api\Commands\ContentGenerationCommand
*/
protected BatchArticleGenerationCommands $batchArticleGeneration;
protected ContentGenerationCommand $contentGenerationCommand;
/**
* Constructs the class for dependencies.
......@@ -63,27 +71,29 @@ class ArticleGenerationConfigForm extends ConfigFormBase {
* The factory for configuration objects.
* @param \Drupal\Core\Entity\EntityTypeManager $entityTypeManager
* The entity type manager.
* @param \Drupal\openai_api\OpenAIService $openaiService
* The OpenAIService object.
* @param \Drupal\openai_api\Commands\BatchArticleGenerationCommands $batchArticleGeneration
* @param \OpenAI\Client $client
* The client object.
* @param \Drupal\openai_api\Commands\ContentGenerationCommand $command
* The BatchArticleGenerationCommands object.
*/
public function __construct(ConfigFactoryInterface $config_factory, EntityTypeManager $entityTypeManager, OpenAIService $openaiService, BatchArticleGenerationCommands $batchArticleGeneration) {
public function __construct(ConfigFactoryInterface $config_factory, EntityTypeManager $entityTypeManager, EntityFieldManagerInterface $entity_field_manager, Client $client, ContentGenerationCommand $command) {
parent::__construct($config_factory);
$this->entityTypeManager = $entityTypeManager;
$this->openaiService = $openaiService;
$this->batchArticleGeneration = $batchArticleGeneration;
$this->entityFieldManager = $entity_field_manager;
$this->client = $client;
$this->contentGenerationCommand = $command;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container): ArticleGenerationConfigForm|ConfigFormBase|static {
public static function create(ContainerInterface $container): ContentGenerationConfigForm|ConfigFormBase|static {
return new static(
$container->get('config.factory'),
$container->get('entity_type.manager'),
$container->get('openai_api.openai.service'),
$container->get('openai_api.article_generation.commands')
$container->get('entity_field.manager'),
$container->get('openai.client'),
$container->get('openai_api.content_generation.commands')
);
}
......@@ -91,7 +101,7 @@ class ArticleGenerationConfigForm extends ConfigFormBase {
* {@inheritdoc}
*/
public function getFormId() {
return 'openai_api_article_generation_config';
return 'openai_api_content_generation_config';
}
/**
......@@ -106,22 +116,31 @@ class ArticleGenerationConfigForm extends ConfigFormBase {
*
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$config = $this->configFactory->get('openai_api.settings');
$config_link = Link::createFromRoute('OpenAI settings form', 'openai_api.api_settings');
$openAiController = new OpenAIApiController(\Drupal::service('openai_api.openai.service'), \Drupal::service('config.factory'));
$config = $this->configFactory->get('openai.settings');
$config_link = Link::createFromRoute('OpenAI settings form', 'openai.api_settings');
$openAiController = new GenerationController(\Drupal::service('openai.client'), \Drupal::service('config.factory'));
$subjects = $openAiController->getSubjectsVocabularyTerms();
$content_types = $this->entityTypeManager->getStorage('node_type')->loadMultiple();
$field_options = [];
$options = [];
foreach ($content_types as $machine_name => $type) {
$options[$machine_name] = $type->label();
if (
!$config->getRawData()
|| !$config->getRawData()['api_token']
|| !$config->getRawData()['api_url']
|| !$config->getRawData()['field_title']
|| !$config->getRawData()['field_body']
|| !$config->getRawData()['field_image']
) {
foreach ($this->entityFieldManager->getFieldDefinitions('node', $machine_name) as $field_name => $field_definition) {
if (!empty($field_definition->getTargetBundle()) && (str_contains($field_definition->getType(), 'string') || str_contains($field_definition->getType(), 'text'))) {
$field_options[$type->label()][$field_name] = $field_definition->getLabel();
}
}
// Title property needs to be appended.
$field_options[$type->label()]['title'] = $this->t('Title');
}
if (!$config->get('api_key')) {
$form['no_config'] = [
'#type' => 'markup',
'#markup' => 'Please fill openai api settings in ' . $config_link->toString()
'#markup' => 'API key missing, please enter your OpenAI API key first to continue at ' . $config_link->toString()
->getGeneratedLink(),
];
}
......@@ -136,7 +155,7 @@ class ArticleGenerationConfigForm extends ConfigFormBase {
for ($i = 1; $i <= $this->number; $i++) {
$form['article_generate_container']['container_for_article_fields_'.$i] = [
'#type' => 'vertical_tabs',
'#title' => 'Fields group for subject '.$i,
'#title' => 'Field group for subject #'.$i,
'#prefix' => '<div id="subject-fields-group-'.$i.'">',
'#suffix' => '</div>',
];
......@@ -195,11 +214,38 @@ class ArticleGenerationConfigForm extends ConfigFormBase {
'#weight' => 2,
];
$form['article_generate_container']['container_for_article_fields_'.$i]['options_container_'.$i]['content_type_'.$i] = [
'#type' => 'select',
'#options' => $options,
'#required' => TRUE,
'#default_value' => array_key_first($options),
'#title' => $this->t('Content type'),
'#description' => $this->t('Select the content type to generate.'),
];
$form['article_generate_container']['container_for_article_fields_'.$i]['options_container_'.$i]['title_field_'.$i] = [
'#type' => 'select',
'#options' => $field_options,
'#required' => TRUE,
'#default_value' => array_key_first($field_options),
'#title' => $this->t('Title field'),
'#description' => $this->t('Select the title field.'),
];
$form['article_generate_container']['container_for_article_fields_'.$i]['options_container_'.$i]['body_field_'.$i] = [
'#type' => 'select',
'#options' => $field_options,
'#required' => TRUE,
'#default_value' => array_key_first($field_options),
'#title' => $this->t('Body'),
'#description' => $this->t('Select the body field.'),
];
$form['article_generate_container']['container_for_article_fields_'.$i]['options_container_'.$i]['model_'.$i] = [
'#type' => 'select',
'#options' => self::MODELS_OPTIONS,
'#required' => TRUE,
'#default_value' => 'text-ada-001',
'#default_value' => 'text-davinci-003',
'#title' => $this->t('Models'),
'#description' => $this->t('
A set of models that can understand and generate natural language<br>
......@@ -213,34 +259,34 @@ class ArticleGenerationConfigForm extends ConfigFormBase {
$form['article_generate_container']['container_for_article_fields_'.$i]['options_container_'.$i]['max_token_'.$i] = [
'#type' => 'number',
'#min' => 50,
'#max' => 2000,
'#step' => 50,
'#min' => 64,
'#max' => 4096,
'#step' => 1,
'#title' => $this->t('Maximum length'),
'#required' => TRUE,
'#default_value' => 100,
'#default_value' => 128,
'#description' => $this->t('The maximum number of tokens to generate in the completion.'),
];
$form['article_generate_container']['container_for_article_fields_'.$i]['options_container_'.$i]['temperature_'.$i] = [
'#type' => 'number',
'#min' => 0,
'#max' => 0.9,
'#min' => 0.1,
'#max' => 1,
'#step' => 0.1,
'#title' => $this->t('Temperature'),
'#required' => TRUE,
'#default_value' => 0,
'#description' => $this->t('Higher values means the model will take more risks. Try 0.9 for more creative applications, and 0 for ones with a well-defined answer.'),
'#description' => $this->t('Higher values means the model will take more risks. Try 1 for more creative applications, and 0 for ones with a well-defined answer.'),
];
$form['article_generate_container']['container_for_article_fields_'.$i]['options_container_'.$i]['number_for_prompt_'.$i] = [
'#type' => 'number',
'#min' => 1,
'#max' => 100,
'#title' => $this->t('Number of article(s)'),
'#title' => $this->t('Number of node(s)'),
'#required' => FALSE,
'#default_value' => 1,
'#description' => $this->t('Number of Article(s) for this subject.'),
'#description' => $this->t('Number of node(s) to generate with the above options.'),
];
$form['article_generate_container']['container_for_article_fields_'.$i]['image_container_'.$i] = [
......@@ -328,6 +374,9 @@ class ArticleGenerationConfigForm extends ConfigFormBase {
$articles[$i]['subject'] = $subject;
$articles[$i]['model'] = $form_state->getValue('model_'.$i+1);
$articles[$i]['content_type'] = $form_state->getValue('content_type_'.$i+1);
$articles[$i]['title'] = $form_state->getValue('title_field_'.$i+1);
$articles[$i]['body'] = $form_state->getValue('body_field_'.$i+1);
$articles[$i]['max_token'] = $form_state->getValue('max_token_'.$i+1);
$articles[$i]['temperature'] = $form_state->getValue('temperature_'.$i+1);
$articles[$i]['image_prompt'] = $form_state->getValue('article_image_prompt_'.$i+1);
......@@ -335,7 +384,7 @@ class ArticleGenerationConfigForm extends ConfigFormBase {
$articles[$i]['number_for_prompt'] = $form_state->getValue('number_for_prompt_'.$i+1);
}
$this->batchArticleGeneration->generateArticles($articles);
$this->contentGenerationCommand->generateArticles($articles);
}
}
......@@ -70,7 +70,7 @@ class ImageGenerationConfigForm extends ConfigFormBase {
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container): ArticleGenerationConfigForm|ConfigFormBase|static {
public static function create(ContainerInterface $container): ContentGenerationConfigForm|ConfigFormBase|static {
return new static(
$container->get('config.factory'),
$container->get('entity_type.manager'),
......@@ -109,14 +109,10 @@ class ImageGenerationConfigForm extends ConfigFormBase {
* @throws \GuzzleHttp\Exception\GuzzleException
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$config = $this->configFactory->get('openai_api.settings');
$config_link = Link::createFromRoute('OpenAI settings form', 'openai_api.api_settings');
if (
!$config->getRawData()
|| !$config->getRawData()['api_token']
|| !$config->getRawData()['api_url']
) {
$config = $this->configFactory->get('openai.settings');
$config_link = Link::createFromRoute('OpenAI settings form', 'openai.api_settings');
if ($config->get('api_key')) {
$form['image_generate_container']['no_config'] = [
'#type' => 'markup',
'#markup' => 'Please fill openai api settings in ' . $config_link->toString()
......
......@@ -2,7 +2,7 @@
namespace Drupal\openai_api;
use Drupal\openai_api\Controller\OpenAIApiController;
use Drupal\openai_api\Controller\GenerationController;
/**
* Defines functionality related to openai content generation.
......@@ -21,9 +21,9 @@ class GenerationService {
* @throws \GuzzleHttp\Exception\GuzzleException
*/
public static function generate_article(array $data, $operation_details, &$context): void {
$openAiController = new OpenAIApiController(\Drupal::service('openai_api.openai.service'), \Drupal::service('config.factory'));
$openAiController = new GenerationController(\Drupal::service('openai.client'), \Drupal::service('config.factory'));
$context['results'][] = $data['nbr_article_generated'];
$context['message'] = t('Generating article @subject @iteration.',
$context['message'] = t('Generating article @subject #@iteration.',
[
'@iteration' => $data['iteration'],
'@subject' => $data['subject'],
......@@ -35,7 +35,7 @@ class GenerationService {
// Get generated image image url.
$img = (new GenerationService)->generate_image($data);
$openAiController->generateArticle($data, $body, $img);
$openAiController->generateArticle($data, $body, $data['content_type'], $data['title'], $data['body'], $img);
}
/**
......@@ -47,7 +47,7 @@ class GenerationService {
public function generate_image($data): ?string {
$img = NULL;
if ($data['image_prompt'] !== "") {
$openAiController = new OpenAIApiController(\Drupal::service('openai_api.openai.service'), \Drupal::service('config.factory'));
$openAiController = new GenerationController(\Drupal::service('openai.client'), \Drupal::service('config.factory'));
$img = $openAiController->getImageUrlResponseBodyData($data['image_prompt'], $data['image_resolution']);
}
......@@ -85,7 +85,7 @@ class GenerationService {
* @throws \GuzzleHttp\Exception\GuzzleException
*/
public static function generate_media(array $data, $operation_details, &$context): void {
$openAiController = new OpenAIApiController(\Drupal::service('openai_api.openai.service'), \Drupal::service('config.factory'));
$openAiController = new GenerationController(\Drupal::service('openai.client'), \Drupal::service('config.factory'));
$context['results'][] = $data['nbr_media_generated'];
$context['message'] = t('Generating @image_prompt n°@iteration.',
[
......
<?php
namespace Drupal\openai_api;
use Drupal\Core\Config\ConfigFactory;
use Drupal\Core\Messenger\MessengerInterface;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Psr7\Response;
use GuzzleHttp\Client;
use Psr\Http\Message\ResponseInterface;
/**
* Defines functionality related to openai API.
*/
class OpenAIService {
/**
* Drupal\profiler\Config\ConfigFactoryWrapper definition.
*
* @var \Drupal\Core\Config\ConfigFactory
*/
protected ConfigFactory $configFactory;
/**
* Defines the url for the API.
*
* @var string|null
*/
protected ?string $apiUrl = null;
/**
* Defines the token for the API.
*
* @var string|null
*/
protected ?string $apiToken = null;
/**
* Defines the URI for the API.
*
* @var string|null
*/
protected ?string $apiUri;
/**
* Constructs a new OpenAIService object.
*
* @param \Drupal\Core\Config\ConfigFactory $config_factory The config
* factory.
*/
public function __construct(ConfigFactory $config_factory) {
$this->configFactory = $config_factory;
$config = $this->configFactory->get('openai_api.settings');
$apiUrl = $config->get('api_url') ?? 'https://api.openai.com/v1';
$apiToken = $config->get('api_token');
if (!empty($apiUrl) && !empty($apiToken)) {
$this->apiUrl = $apiUrl;
$this->apiToken = $apiToken;
}
}
/**
* Gets the text.
*
* @param string $models
* Defines the models.
* @param string $text
* Defines the text.
* @param int $max_token
* Defines the max token.
* @param float $temperature
* Defines the temperature.
*
* @return \GuzzleHttp\Psr7\Response|\Psr\Http\Message\ResponseInterface
* Returns a response interface.
*
* @throws \GuzzleHttp\Exception\GuzzleException
*/
public function getText(string $models, string $text, int $max_token, float $temperature): Response|ResponseInterface {
$this->setApiUri('/completions');
$content = [
"model" => $models,
"prompt" => $text . '.',
"max_tokens" => $max_token,
"temperature" => $temperature,
];
$params = array_merge(['json' => $content], $this->_getHeaderParams());
return $this->callApi('post', $params);
}
/**
* @param string $prompt
* @param string $size
*
* @return \GuzzleHttp\Psr7\Response|\Psr\Http\Message\ResponseInterface
* Returns a response interface.
*
* @throws \GuzzleHttp\Exception\GuzzleException
*/
public function getImageUrl(string $prompt, string $size): Response|ResponseInterface {
$this->setApiUri('/images/generations');
$content = [
"prompt" => $prompt,
"n" => 1,
"size" => $size,
];
$params = array_merge(['json' => $content], $this->_getHeaderParams());
return $this->callApi('post', $params);
}
/**
* Gets the models.
*
* @return \GuzzleHttp\Psr7\Response|\Psr\Http\Message\ResponseInterface
* Returns a response interface.
*
* @throws \GuzzleHttp\Exception\GuzzleException
*/
public function getModels(): Response|ResponseInterface {
$this->setApiUri('/models');
$params = array_merge([], $this->_getHeaderParams());
return $this->callApi('get', $params);
}
/**
* All API call.
*
* @param mixed $method
* Takes in the HTTP method.
* @param array $params
* Takes in an array of relevant parameters.
*
* @return \GuzzleHttp\Psr7\Response|\Psr\Http\Message\ResponseInterface
* Returns a response interface.
*
* @throws \GuzzleHttp\Exception\GuzzleException
*/
protected function callApi($method, array $params = []): Response|ResponseInterface {
$uri = $this->getApiUrl() . $this->getApiUri();
$params = count($params) ? $params : [];
try {
$response = $this->getClient()->request($method, $uri, $params);
} catch (RequestException $e) {
$response = new Response(
$e->getCode(), $e->getResponse()
->getHeaders(), $e->getResponse()->getBody()
);
}
return $response;
}
/**
* Gets the header params.
*
* @return array|\string[][]
* An array/string indicating the header params.
*/
private function _getHeaderParams(): array {
$header = [
'headers' => [
'content-type' => 'application/json;charset=utf-8',
'Accept' => 'application/json',
],
];
$header['headers']['Authorization'] = "Bearer " . $this->getApiToken();
return $header;
}
/**
* Gets the API Url.
*
* @return string|null apiUrl
* A string indicating the API url.
*/
public function getApiUrl(): mixed {
return $this->apiUrl;
}
/**
* Gets the API token.
*
* @return string|null apiToken
* A string indicating the API token.
*/
public function getApiToken(): mixed {
return $this->apiToken;
}
/**
* Gets the API URI.
*
* @return string|null apiUri
* A string indicating the API URI.
*/
public function getApiUri(): ?string {
return $this->apiUri;
}
/**
* Sets the API URI.
*
* @param string|null $apiUri
* A string indicating API URI.
*/
public function setApiUri(?string $apiUri): void {
$this->apiUri = $apiUri;
}
/**
* Gets the HTTP Client Object.
*
* @return \GuzzleHttp\Client
* The client object.
*/
public function getClient(): Client {
return new Client();
}
/**
* Gets the Response body.
*
* @param object $response
* Takes in the response object.
*
* @return mixed|void
* Returns the json decoded body.
*/
public static function getResponseBody(Response $response): array {
if (gettype($response) !== 'boolean') {
return \json_decode($response->getBody()->getContents(), TRUE);
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment