Подключаем OpenAI к Telegram Bot

Pavel Loginov
8 min readMar 3, 2023

В статье затрагивается краткое описание OpenAI, регистрация и получение токена, разворачивание проекта c телеграм ботом на aiogram 3, установка зависимостей, структура запросов к OpenAI и выполнение простых запросов к OpenAI из Telegram бота.

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

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

Получение OpenAI API токена

Чтобы использовать API, вам необходимо получить токен. Токен можно получить на сайте OpenAI. Если вы находитесь в России, у вас могут возникнуть трудности с доступом к сайту. Для преодоления блокировки необходимо иметь VPN и заграничный телефонный номер, чтобы получить СМС для регистрации. В статье на Хабр подробно и точно описано как обойти блокировку. У меня это заняло примерно 10 минут и 20 рублей. Ссылка на статью: Как получить доступ к chatGPT в России.

Если вы получили доступ к платформе OpenAI и смогли зайти на Chat GPT, тогда мы можем продолжать.

Сперва перейдем на страницу входа в аккаунт OpenAI: https://platform.openai.com/signup

После входа вас должно направить на страницу: https://platform.openai.com/overview

В меню находим View API keys и переходим туда:

Тут у вас отображается список имеющихся токенов и есть кнопка создания нового, нажимаем на неё:

После нажатия на кнопку у вас сгенерируется новый токен. Вам покажут его только один раз, поэтому необходимо сразу же его сохранить в доступном и надёжном месте. Далее он нам понадобится.

Разворачиваем проект

Для начала нам нужен проект с телеграм ботом. Вы можете использовать свой проект или сделать клон этого проекта (дальше будем работать в нем): https://github.com/welel/bp-integrate-openai-telegram

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

Клонируем проект

git clone git@github.com:welel/bp-integrate-openai-telegram.git

Создаем виртуальное окружение и устанавливаем зависимости

Подробнее о виртуальном окружении и зависимостях можно узнать в официальной документации.

# Переходим в дерикторию проекта
cd bp-integrate-openai-telegram

# Создаем виртуальное окружение Python 3.10+
python3.10 -m venv env

# Активируем окружение
source env/bin/activate

# Устанавливаем зависимости
pip install -r requirements.txt

У вас установятся следующие зависимости:

aiogram==3.0.0b7      # Для работы с Telegram
openai==0.26.5 # Для работы с OpenAI API
python-dotenv==1.0.0 # Для работы с переменными окружения

Заполняем конфиг

Предполагается, что вы знаете как создавать нового бота в телеграм и получить токен бота, если нет, то можете прочитать об этом здесь: https://stepik.org/lesson/759381/step/1?unit=761397

В структуре проекта найдите файл под названием .env.dist и сделайте копию с названием .env рядом. Там будут храниться наши токены. Откройте файл и вставьте туда имеющиеся токены — токен телеграм бота и токен OpenAI.

# Telegram Bot Token
BOT_TOKEN=5497937168:AAHASDAIlWeh4-8jYvo72eZeq23-1P2DQmaY

# OpenAI Token
OPENAI_TOKEN=sk-BhC44232lf3VNgLVVADS3BlbkFJtPs00ADSJK21tjPVu7bzl

Чтобы проверить работоспособность, запускаем бота:

python bot.py

Если всё работает правильно, то на любое текстовое сообщение в чат с вашим ботом, он будет отвечать “echo”.

Возможности OpenAI API

OpenAI имеет широкий спектр возможностей, они отражены на странице Example. На ней вы можете изучить способы применения OpenAI API. Возвращаемся к сайту OpenAI, там переходим на страницу: https://platform.openai.com/examples

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

Инструкция

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

Текст

Если послать в модель текст без контекста и повелительных оттенков в нем, то модель попытается завершить его.

Текст с обучением

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

Например, научим модель сокращать слово по одной букве.

Видно, что она поняла что надо делать, но сделала это с ошибками. Такое бывает, модели часто ошибаются, это надо учитывать. Для улучшения следует дать ей больше примеров.

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

Ведение диалога

Это как текст с обучением, только в структуре запроса задается диалог. В начале диалога можно добавить контекстную окраску беседы. Пример структуры запроса (зеленым отмечены ответы модели):

Сделано два запроса, модель поняла настроение беседы и свою роль. Всё что требовалось от нас — описать контекст беседы в первой строке, написать пару реплик за персонажей, тем самым задавая структуру диалога, и “пригласить” модель отвечать завершив запрос сочетанием Девушка:. Таким образом, вы можете задавать более сложный контекст беседе и использовать различных персонажей, включая известных личностей героев из книг, фильмов и так далее. Чем больше модель знает о персонаже, тем лучше она будет отвечать за него.

Получаем типовой запрос для ведения диалога:

[Контекст]

[Персонаж пользователя]: [Затравка беседы]
[Персонаж модели]:

Затравка диалога может быть в несколько реплик, если требуется.

Далее, в реализации, мы будем каждый раз использовать один и тот же запрос (не изменяя его), поэтому модель не будет знать о предыдущих сообщениях. Чтобы модель помнила историю сообщений и имела память в диалоге, необходимо каждый раз изменять запрос, добавляя к нему сообщения пользователя и ответы модели в заданной структуре. Такой подход реализован в проекте: https://github.com/welel/dialog-chat-bot/tree/text-davinci-003

Следует рассмотреть ещё одно понятие, прежде чем начинать. Стоп слово — это последовательность символов сигнализирующая модели о завершении генерации ответа. Если модель сгенерирует, заданное вами стоп слово, то она перестанет дальше генерировать ответ, при этом удалит это слово с конца своего ответа. При генерации ответа со структурой диалога, модель может не остановиться на ответе своего персонажа и продолжить генерировать текст и за вашего. Для предотвращения этого в модель передается стоп слово в таком виде — [Ваш персонаж]:. Теперь, если модель решит сгенерировать ответ за вас, она остановится.

Поиграть с моделями вы можете в песочнице: https://platform.openai.com/playground

Интегрируем OpenAI API в Telegram Bot’а

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

Для удобства будем писать весь код в одном файле. В проекте откройте файл handlers/user_handlers.py. В файле имеем следующий код:

from aiogram import F, Router
from aiogram.types import Message


router: Router = Router()


@router.message(F.content_type == 'text')
async def process_message(message: Message):
"""Принимает все текстовые сообщения."""
await message.answer(text="echo")

Импортируем openaiи функцию load_config из модуля config. Библиотека openai предоставляет нам удобный доступ к OpenAI API. Конфиг импортируется из файлов проекта и через него осуществляется доступ к переменным из файла .env, где лежат наши токены. Для успешной работы с openai проинициализируем токен, как указано в последней строке.

import openai

from config import load_config


openai.api_key = load_config().openai_token

Для удобства сразу завернём запрос в функцию chat, которая будет принимать текст сообщения пользователя и возвращать ответ модели. Для использования моделей завершения используется класс Comletion, для совершения запроса используем метод create или acreate для асинхронного запроса. В этот метод передается название модели, текст запроса и дополнительные параметры. Параметры подробно рассматривать не будем, о них можно найти информацию здесь: https://platform.openai.com/docs/api-reference/completions/create.

async def chat(text: str) -> str:
response = await openai.Completion.acreate(
model="text-davinci-003",
prompt=text,
temperature=0.5,
max_tokens=500
)
return response

Пока что возвращаем response, чтобы полностью рассмотреть ответ.

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

@router.message(F.content_type == 'text')
async def process_message(message: Message):
"""Принимает все текстовые сообщения."""
answer = await chat(message.text)
print(answer)

Запускайте бота и отправьте ему текстовое сообщение и наблюдайте за терминалом. Ответ может генерироваться некоторое время. У меня ответ от модели максимальное занимал 20 секунд. Так выглядит ответ модели:

{
"choices": [
{
"finish_reason": "stop",
"index": 0,
"logprobs": null,
"text": "Ответ модели"
}
],
"created": 1677842337,
"id": "cmpl-6pxj7g5SKtbZgG2HiD0bGHiTU65sf",
"model": "text-davinci-003",
"object": "text_completion",
"usage": {
"completion_tokens": 426,
"prompt_tokens": 19,
"total_tokens": 445
}
}

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

Теперь когда мы поняли, где лежит ответ на запрос, можем дописать функцию и обработчик. В функции меняем возвращаемое значение на return response["choices"][0]["text"]. А в обработчике меняем принт на ответ await message.reply(text=answer). Получаем такой код:

from aiogram import F, Router
from aiogram.types import Message
import openai

from config import load_config


openai.api_key = load_config().openai_token
router: Router = Router()


async def chat(text: str) -> dict:
response = await openai.Completion.acreate(
model="text-davinci-003",
prompt=text,
temperature=0.5,
max_tokens=500
)
return response["choices"][0]["text"]


@router.message(F.content_type == 'text')
async def process_message(message: Message):
"""Принимает все текстовые сообщения."""
answer = await chat(message.text)
await message.reply(text=answer)

Пробуем запустить бота и отправить запрос:

Я надеюсь, у вас всё получилось, если нет, то пишите, какие у вас возникли трудности или ошибки, попробуем разобраться.

Добавим один штрих к запросу и получим чат бота, который не просто дает ответы, а отвечает как собеседник.

До этого мы рассмотрели запросы для ведения диалога, воспользуемся следующей структурой:

Раскольников беседует с другом.

Друг: Привет.
Раскольников: Привет.
Друг: {запрос пользователя}
Раскольников:

Перенесем шаблон в Python и в функции chat будем пользоваться форматированием для вставки запроса пользователя.

QUERY = (
"Раскольников беседует с другом.\n\n"
"Друг: Привет.\n"
"Раскольников: Привет.\n"
"Друг: {text}\n"
"Раскольников: "
)

Выносим QUERY в глобальную видимость. Когда передаем запрос модели, используем форматирование и добавляем ещё один параметр — стоп слово Друг:.

...
prompt=QUERY.format(text=text),
stop="Друг:",
...

Можно пробовать беседовать. Учитывайте, что запрос никак не обновляется и модель не помнит предыдущих ваших и своих реплик. Существует специальная модель для ведения диалога, где предоставлен удобный интерфейс для решения этой задачи. В статье рассмотрена модель завершения, она может выполнять больше задач, в том числе и ведение диалога, если реализовать систему контекста, как сделано в этом проекте: https://github.com/welel/dialog-chat-bot/tree/text-davinci-003

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

В этой статье мы кратко рассморели возможности моделей завершения и интеграцию OpenAI в Telegram Bot. Весь код, который представлен в статье можно найти в репозитории: https://github.com/welel/bp-integrate-openai-telegram. В ветке main стартовая точка и в result — конечная.

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

--

--

Pavel Loginov

👨‍💻 Backend Developer 🛠️ Programming enthusiast ✍️ Aspiring writer 🔗 github.com/welel