Генератор текстов на ChatGPT и Python

Все привет. Меня зовут Роман, я работаю в агентстве Люстей Сергея (Digital Liustei) и делаю разные сервисы на Python. Некоторое время назад у нас возникла задача написать генератор текстов на базе ChatGPT, что и было в итоге реализовано на базе популярного Python фреймворка FastApi. В этой статье я поделюсь своим опытом создания подобного генератора, опишу сам принцип работы и основные детали реализации на программном уровне.

Дисклеймер

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

  • как сделать сервис генерации текстов с api open ai
  • как сделать эту генерацию многопоточной за счет асинхронности
  • как проверить и повысить уникальность текстов с ChatGPT
  • некоторые наблюдения из моего опыта взаимодействия с API OpenAI

Зачем нужен сервис?

Итак, сервис по генерации текстов через ChatGPT. Думаю, стоит начать с того, зачем вообще нужны эти тексты? В нашем случае это оптимизация сайтов под поисковые системы. Сегодня текст уже не так важен для SEO, но до сих пор является полезным инструментом: помогает поднять уникальность вашего сайта или же его релевантность какому - либо поисковому запросу пользователя. Особенно хорош текст в тех случаях, когда вам требуется быстро и недорого повысить релевантность и уникальность большого количества страниц.

Алгоритм работы сервиса

Итак представим что мы имеем список из промптов примерно такого плана:

Давай напишем текст на тему: "Купить колонки JBl в Уфе", используя ключевые слова и словосочетания: бренд, контакты, собственный склад, специалисты, удобное местоположение магазина, парковка, низкие цены, скидка. Длина текста должна быть не менее 2000 символов

Далее процесс генерации текста по нашему промпту разделяется на этапы:

Этап 1. Уникализация промпта

Перед отправкой нашего промпта на сервер OpenAI к нему добавляется дополнительная, сгенерированная случайным образом инструкция. Эта инструкция формируется путём случайного отбора из нескольких наборов строк, по одной строке из каждого набора. Каждая такая строка это дополнительная инструкция, которая добавится в промпт, например:

- использовать или не использовать списки в готовом тексте

- использовать или не использовать подзаголовки в готовом тексте

- указание писать в разных стилях (публицистический, деловой, рекламный)

- какие - то наборы разных групп слов используемых в тематике на тему которой мы генерим наши тексты

Соответственно, проходим по этому списку наборов, на выходе получаем добавочную инструкцию к нашему промпту, например:

статья должна быть написана в деловом стиле, используй списки, не используй подзаголовки, используй в статье слова: история компании, мощность колонок, качественный звук, поддержка профилей, индикация

Зачем нужен эта дополнительная инструкция? Ее задача заключается в повышении уникальности каждого отдельного текста относительно всех других текстов в рамках одной темы. Дело в том что часто тексты генерируются на темы описывающие близкие по сути объекты, различающиеся лишь незначительными параметрами. Например, сделать по одному тексту на 20 видов стальной арматуры, которая отличается только диаметром. Если не добавлять никаких дополнительных инструкций в промпт, мы почти гарантированно получим 20 одинаковых текстов с одними и тем же описанием арматуры. И пусть даже эти тексты и будут уникальны по отношению ко всем текстам существующим на сегодняшний момент в интернете, они не уникальны по отношению друг к другу, а это тоже плохо с точки зрения поисковых систем. И наш "рандомизирующий" промпт позволяет эту проблему решить.

Этап 2. Получение текста с сервера OpenAI

Далее отправляем запрос с нашим промптом к серверу OpenAI к одной из их текстовых моделей (в моем случае это GPTTurbo 3.5). Получаем текст.

Здесь хочется упомянуть про лимиты (usage tier). У меня есть 2 аккаунта с разными tier, и я наблюдаю особенность о которой не упомянуто в документации: на аккаунте с первым tier перед каждым ответом есть задержка примерно в 1 минуту (в отличие от второго моего аккаунта с четвертым tier, где ответ приходит мгновенно).

Повторюсь, о задержке не написано в документации. Там указаны лишь различия в количестве доступных токенов и запросов в минуту для разных уровней. По всей видимости, это временное ограничение (ситуация актуальна на декабрь 2023 года), но на данный момент, если у вас аккаунт с первым уровнем доступа, эта задержка может существенно влиять на скорость генерации текста. Хорошая новость в том что нужно не так уж много потратить, чтобы перейти на следующий уровень лимитов, например для достижения tier 3 достаточно общих трат по аккаунту в 50 долларов. Плюс, вы можете запросить исключение для себя, правда вам потребуется какое - то обоснование. Определить, какой уровень доступа установлен на вашем аккаунте, можно на странице настроек лимитов использования OpenAI.

Этап 3. Проверка текста на нужную длину

Далее, проверяем полученный текст на соответствие нужной длине (да, иногда несмотря на то что мы прямо просим в промпте о нужной длине, все равно итоговый результат бывает меньше, нужно проверять). Если текст ниже нужной нам длины, отправляем его в OpenAI и просим дописать.

Этап 4. Проверка текста на нужную уникальность

После, отправляем текст на проверку уникальности в text.ru. Из тех API проверки уникальности русскоязычных текстов, что я нашел, этот пока самый выгодный по сочетанию цена/качество. Пороговое значение уникальности можно регулировать, обычно мы делаем не ниже 80%. Соответственно, если значение уникальности полученного текста ниже порогового значения, текст отправляется обратно в openai, с примерно таким промптом:

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

Если полученный текст и в этот раз не дотягивает по уникальности, повторяем процедуру. Здесь отмечу что количество таких повторений ограничено, так как во-первых иногда попадаются темы где по каким то причинам Chatgpt сложно написать уникальный текст (либо же повысить его уникальность), а во-вторых у нас была пара случаев когда мы словили временную блокировку со стороны OpenAI после того как подобный запрос повторился много раз.

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

Как сделан сервис на программном уровне

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

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

Соответственно, нужно было найти какую - то быструю и эффективную замену, и я решил остановиться на FastApi. Почему FastApi? Самое главное - асинхронность, что давало возможность отправлять все тексты из набора на генерацию одновременно, а не по очереди, что естественно повышало скорость работы. Дополнительный плюс это хорошая документация и просто очень большое количество информации вследствие высокой популярности фреймворка.

Всего приложение получает данные по api c 2 сервисов: это сам OpenAI и text.ru. Для работы с первым есть готовая python библиотека Openai. Она хорошо документирована и изначально поддерживает асинхронные запросы. А для асинхронных запросов к text.ru я взял библиотеку httpx.

Сгенерированные тексты и данные пользователей хранятся в базе данных. В качестве ORM для работы с базой данных используется SQLAlchemy c асинхронным движком.

Авторизация юзеров - библиотека fastapi-users, передача токена авторизации идет через куку, как самое простое решение.

Для фонового выполнения задач использую модуль FastAPI BackgroundTasks. Для данного генератора его более чем достаточно.

Цена использования сервиса

Ну и напоследок о цене использования. Она складывается из двух компонентов: это стоимость запроса к какой-либо модели OpenAI и стоимость использования API text.ru.

Что касается первой, на данный момент мы используем gpt-3.5-turbo. При использовании модели 3.5 на сегодняшний момент цена за токены следующая: $0.001 на ввод и $0.002 на вывод, что в пересчете на наши рубли по курсу на декабрь 2023 года, дает среднюю цена за 1 тыс символов текста выходит в районе 2 - 2.5 рублей (считая наш промпт который мы отправим в OpenAi). Для сравнения, при использовании GPT-4 Turbo эта стоимость вырастает уже до 7 - 8 рублей

Второй компонент это API text.ru. Здесь цена зависит от объема в вашем тарифе, при средних объемах генерации она будет в районе 70 коп за 1 тыс символов.

Добавлю также, что обычно в рамках генерации текста проверка на требуемую уникальность не всегда проходит с первого раза, следовательно, мы проверяем и пишем текст больше чем 1 раз (в среднем по всем текстам у нас получается в районе 1,7), что тоже нужно учесть при расчете итоговой стоимости.

Итого мы имеем где - то 3,5 рублей + 1,4 рубля = 4,9 рублей за 1000 символов, что является очень неплохим показателем. Для сравнения самый плохой копирайтерский текст (хуже чем тот что вам сгенерит модель 3,5) будет стоить никак не ниже 30 - 50 рублей за 1 тыс символов, так что экономия здесь на лицо.

На этом все, спасибо за внимание к этой статье. С самим кодом сервиса вы можете ознакомиться по ссылке, также буду благодарен за любую обратную связь

11
3 комментария

Странно, что такой офигенный материал не получил должного охвата(

Роман, мы вот бьемся над количеством ключевых слов в статье. Не понятно, gpt вообще понимает запросы типа: используй слово gpt 5 раз в статье?

Во-первых, спасибо за оценку!
Во вторых, да, у текстовых нейросетей очень плохо с арифметическими операциями (да и видимо не только у текстовых, недаром же часто на картинках из midjourney у людей не 5, а 6 пальцев и тд) и видимо поэтому такие задания не работают. Щас, после вашего коммента тоже для себя проверил, попросил в GPT-4 упомянуть в тексте слово какое то количество раз, и даже GPT-4 не справился.
Можно как вариант сначала генерить текст, а потом просить сам же chatgpt проверить правильно ли он выполнил задание, и так до бесконечности, пока не выполнит. Но тогда будет съедаться большое количество токенов, и текст будет по стоимости как копирайтерский