• Время чтения ~2 мин
  • 14.12.2022

ИИ — это модное словечко или нам следует задуматься? С выпуском пакета OpenAI мы можем погрузиться в приложения Laravel на базе ИИ.

Итак, что такое OpenAI? Что мы можем с этим сделать? В основном это касается обработки естественного языка. Мы передаем ему какой-то текст, а он взамен может удивить нас многими вещами. От полных текстовых примеров до примеров кода и всего, что вам нужно. Основным ограничением является ваше воображение и его текущие возможности.

Нуно выпустил PHP-клиент OpenAI некоторое время назад - но что мы можем сделать с этим? Часто я обнаруживаю, что самой сложной частью работы с этой технологией является понимание того, что вы можете с ней сделать.

Просматривая примеры OpenAI, я нашел множество примеров, которые, вероятно, подойдут мне и обычному использованию. Пройдемся по модели «Реклама из описания товара». Я выбираю это, потому что мы часто собираем текст, вводимый нашими пользователями, а затем должны вывести его позже по разным причинам. Представьте, что вы управляете интернет-магазином и вам нужно записать описания продуктов для ваших товаров, и вы хотите добавить какой-нибудь убойный текст в стиле «рекламы», чтобы побудить людей нажимать на продукт.

Давайте прыгать.

Я не буду проводить вас через процесс установки PHP-клиента OpenAI. Поскольку вы читаете это, я предполагаю, что мне не нужно учить вас этой части. Тем не менее, я расскажу, как я буду использовать этот пакет, который, вероятно, будет отличаться от других руководств.

Первое, что я бы сделал, это привязал класс OpenAI Client к моему контейнеру, чтобы мне не нужно было использовать фасад или создавать экземпляр клиента.

final class AppServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        $this->app->singleton(
            abstract: Client::class,
            concrete: fn () => OpenAI::client(
                apiToken: strval(config('openai.api_key')),
            ),
        );
    }
}

Теперь каждый раз, когда я пытаюсь внедрить класс клиента OpenAI в конструктор или куда-либо еще, он будет предварительно настроен для меня.

Наш вариант использования — это когда мы сохраняем продукт с описанием. Мы хотим автоматически генерировать рекламный текст для продукта. На самом деле, лучшее место для этого — работа. Один мы можем отправить как часть процесса создания самой модели.

Я не буду рассказывать о создании модели, так как хочу убедиться, что получил все необходимые знания из этого урока.

Когда мы отправляем фоновое задание, мы передаем в конструктор то, что хотим сериализовать, а затем в методе handle мы можем разрешать экземпляры из контейнера DI.

Давайте посмотрим, как это выглядело бы, если бы мы подходили к этому просто.

final class GenerateAdFromProduct implements ShouldQueue
{
    use Dispatchable;
    use InteractsWithQueue;
    use Queueable;
    use SerializesModels;

    public function __construct(
        public readonly string $text,
        public readonly int $product,
    ) {}
    public function handle(Client $client): void
    {
        $response = $client->completions()->create([
            'model' => 'text-davinci-003',
            'prompt' => $this->text,
            'temperature' => 0.5,
            'max_tokens' => 100,
            'top_p' => 1.0,
            'frequency_penalty' => 0.0,
            'presence_penalty' => 0.0,
        ]);
        DB::transaction(fn () => Product::query()->find(
            id: $this->product,
        ))->update(['ai_description' => $response['choices'][0]['text']]);
    }
}

При этом используются настройки, описанные на странице с примером, не углубляясь в нее. Конечно, если вы делаете это в продакшене, очень рекомендую смотреть на эти настройки внимательнее.

Можем ли мы улучшить это? Конечно, мы можем - я Стив, и я самоуверен... Давайте сделаем еще один шаг.

Что мы тут делаем? Мы используем предопределенную модель для генерации и возврата ответа от OpenAI. Используемые нами настройки предопределены в примерах. Конечно, их можно настроить, но мы можем использовать это, чтобы сделать еще один шаг вперед.

Наш первый шаг — это сама модель. В настоящее время OpenAI поддерживает только так много доступных — это может измениться в какой-то момент, но пока этого не произойдет. Давайте создадим Enum для модельной части полезной нагрузки:

enum Model: string
{
    case ADA = 'text-ada-001';
    case BABBAGE = 'text-babbage-001';
    case CURIE = 'text-curie-001';
    case DAVINCI = 'text-davinci-003';
}

Первый шаг завершен. Давайте теперь посмотрим на запрос клиента OpenAI.

$client->completions()->create([
    'model' => Model::DAVINCI->value,
    'prompt' => $this->text,
    'temperature' => 0.5,
    'max_tokens' => 100,
    'top_p' => 1.0,
    'frequency_penalty' => 0.0,
    'presence_penalty' => 0.0,
]);

Довольно хорошо. Остальные настройки зависят от модели и результата, которого я пытаюсь добиться, исходя из того, что я могу сказать из документации. Так что это то, что специально настроено, чтобы я мог получать рекламный текст из другого текстового тела. Для меня это рекламный трансформер. Он превращает любую подсказку, которую вы ему даете, в рекламу. Итак, имея это в виду, давайте создадим специальный класс для этого.

final class AdvertisementTransformer
{
    public static function transform(string $prompt): array
    {
        return [
            'model' => Model::DAVINCI->value,
            'prompt' => $prompt,
            'temperature' => 0.5,
            'max_tokens' => 100,
            'top_p' => 1.0,
            'frequency_penalty' => 0.0,
            'presence_penalty' => 0.0,
        ];
    }
}

Мы извлекаем логику создания завершения в выделенный класс, что позволит нам легко использовать его повторно. Давайте теперь вернемся к запросу клиента OpenAI:

$client->completions()->create(
    parameters: AdvertisementTransformer::transform(
        prompt: $this->text,
    ),
);

Это, по крайней мере, для меня чисто и понятно. Глядя на это, я передаю текст из задания на трансформер, который преобразует его в нужные параметры для генератора рекламных текстов.

Результат для этого будет следующим:

{
  "object": "text_completion",
  "created": 1672769063,
  "model": "text-davinci-003",
  "choices": [
    {
      "text": "Are you a #Laravel developer looking to stay up-to-date with the latest news and updates? Look no further than Laravel News! With over 10K users daily, you'll be able to stay informed and learn from the official news outlet for the Laravel ecosystem. #LaravelNews #Developers #Ecosystem",
      "index": 0,
      "logprobs": null,
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 82,
    "completion_tokens": 72,
    "total_tokens": 154
  }
}

Как видите, у нас есть множество вариантов, каждый из которых имеет текстовую клавишу. Чтобы получить это, нам просто нужно получить к нему доступ, как обычно в PHP:

$response = $client->completions()->create(
    parameters: AdvertisementTransformer::transform(
        prompt: $this->text,
    ),
);
DB::transaction(fn () => Product::query()->find(
    id: $this->product,
))->update(['ai_description' => $response['choices'][0]['text']]);

Все, что вам теперь нужно сделать, это создать стандартные преобразователи, которые вы можете использовать в своем приложении, настроить параметры так, чтобы вы знали, что они будут работать для вас, и вы можете продолжать.

Comments

No comments yet
Yurij Finiv

Yurij Finiv

Full stack

Про мене

Professional Fullstack Developer with extensive experience in website and desktop application development. Proficient in a wide range of tools and technologies, including Bootstrap, Tailwind, HTML5, CSS3, PUG, JavaScript, Alpine.js, jQuery, PHP, MODX, and Node.js. Skilled in website development using Symfony, MODX, and Laravel. Experience: Contributed to the development and translation of MODX3 i...

Об авторе CrazyBoy49z
WORK EXPERIENCE
Контакты
Ukraine, Lutsk
+380979856297