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

Шаг 1. Подключаем ChatGPT

Для начала нам понадобится токен chatGPT, это ключ, с помощью которого наш бот сможет общаться с сервером chatGPT. Его можно купить или достать каким-то окольным путем, но вам повезло, поскольку перед этой лекцией вам его уже прислали в бот. Первое наше действие с кодом в этом уроке — скопировать значение присланного токена и вставить его в соответствующее поле. Пример кода:

chatgpt = ChatGptService(token="вот-тут-вы-должны-вставить-ваш-chatgpt-токен") 
Это код нужно написать прямо перед созданием бота:

chatgpt = ChatGptService(token="sk-pUFKDJLKK09898KJKJLJLK87878jkjkkllougTImm") 

app = ApplicationBuilder().token("0980989809:fjkdfjlsdjfisdm").build() 
# подключение хэндреров 
Если вы это сделали – отлично, теперь давайте попробуем отправить нашему ИИ какое-нибудь сообщение. По задумке у нашего бота должен быть особый режим общения с пользователем, когда пользователь может задавать вопросы прямо ИИ. Это режим называется gpt, и для него есть аналогичная команда. Давайте добавим в наш проект функцию gpt. Выглядеть она может, например так:

async def gpt(update, context): 
    await send_text(update, context, "Напишите сообщение *ChatGPT*:")
Также нам нужно связать эту функцию с командой /gpt. Для этого добавим приложению нашего бота еще один хэндлер:

app = ApplicationBuilder().token("0980989809:fjkdfjlsdjfisdm").build() 
app.add_handler(CommandHandler("start", start)) 
app.add_handler(CommandHandler("gpt", gpt)) 

app.run_polling() 

Шаг 2. Режимы диалога

Теперь мы должны научить наш бот общаться в разных режимах. Вчера это было просто обучающее общение ни о чем, сегодня, но только после клика по команде /gpt, это должно быть общение с ChatGPT. Завтра, после ввода команды /date, это уже будет тренировка в переписке со знаменитостями. Поэтому нам нужно добавить в наш чат-бот такое понятие как «режим диалога» где хранить текущий режим. Можно их назвать по именам команд. Например, так:
  • main – режим общения по умолчанию (или клика по команде start)
  • gpt – режим общения с чатом GPT.
  • date – тренировка переписки и т.д.
Давайте создадим специальную переменную, dialog_mode, в которой и будем хранит этот режим. А эту глобальную переменную легко можно было изменять из различных функций, мы сделаем хитрый ход:
  • создадим пустой класс Dialog
  • создадим переменную dialog которой присвоим объект типа Dialog
  • атрибуту mode этой переменной присвоим имя режима
Клас Dialog я для вас уже создал, вам нужно только написать:

dialog = Dialog() 
dialog.mode = "main" 
Это код можно разместить в любом месте файла bot.py, но для красоты лучше ближе к концу – можно сразу перед созданием объекта ChatGptService. Теперь в каждой функции, которая обрабатывает команду, нужно переключать режим диалога:

async def gpt(update, context): 
    dialog.mode = "gpt" 
    await send_text(update, context, "Напишите сообщение *ChatGPT*:") 
И тоже для команды start:

async def start(update, context): 
    dialog.mode = "main" 
    text = load_message("main") 
    await send_photo(update, context, "main") 
    await send_text(update, context, text) 

Шаг 3. Отправляем запрос ChatGPT

Для общения пользователя с чатом GPT мы создадим отдельную функцию – gpt_dialog. В ней мы будем делать 3 вещи:
  1. Получаем сообщение от пользователя.
  2. Пересылаем сообщение пользователя чату-gpt.
  3. Ответ чата-gpt публикуем пользователю в чат.
Пример:

async def gpt_dialog(update, context): 
    text = update.message.text 
    answer = chatgpt.send_question(text) 
    send_text(update, context, answer)
К этому коду есть 2 замечания:
  • функции send_question() и send_text() – асинхронные, перед их вызовом нужно использовать ключевое слово await.
  • Метод send_question() принимает не 1, а 2 параметра: prompt и вопрос пользователя
Нам нужен промпт для ChatGPT – это некое задание, которое говорит ChatGPT о том, в каком ключе он должен вести дальнейшую беседу. Тут есть 2 варианта: мы можем придумать простой prompt сами или загрузить готовый из подготовленных – они хранятся в папке resources. Давайте начнем с варианта попроще:

async def gpt_dialog(update, context): 
    text = update.message.text 
    answer = await chatgpt.send_question("Дай четкий и короткий ответ на вопрос",  text)  
    await send_text(update, context, answer) 
Такой код будет работать. Ну почти. Мы же нигде не связали функцию gpt_dialog с нашим ботом. Сейчас все сообщения пользователя идут в функцию hello(). Предлагаю в начале это функции проверить режим диалога, и если он gpt, передать туда вызов:

async def hello(update, context): 
    if dialog.mode == "gpt": 
        await gpt_dialog(update, context) 
    else: 
        await send_text(update, context, "Привет!") 
        await send_text(update, context, "Как дела, *дружище*?") 
        await send_text(update, context, "Ты написал " + update.message.text) 
Вот теперь все отлично: если диалог в режиме gpt, то все сообщения пользователя будет обрабатывать функция gpt_dialo(), иначе – hello().

Шаг 4. Использование prompt для ChatGPT

Также предлагаю использовать заготовленный prompt из папки resources\prompts, и немного подправить нашу функцию gpt_dialog:

async def gpt_dialog(update, context): 
    prompt = load_prompt("gpt") 
    text = update.message.text 
    answer = await chatgpt.send_question(prompt,  text)  
    await send_text(update, context, answer) 

Шаг 5. Добавляем отправку приветственных картинок.

Каждый раз, когда пользователь переключает режим диалога с помощью ввода команды, нужно присылать ему приветственную картинку и сообщение, чтобы он знал, что диалог переключился в новый режим. У меня уже есть заготовленные сообщения и картинки на этот случай. Имена заготовленных картинок и сообщений совпадают с именами режимов диалога («main» для /start, «gpt» для /gpt и т.д.) Загрузить заготовленное сообщение можно с помощью функции load_message(). Пример функции start():

async def start(update, context): 
    dialog.mode = "main" 
    text = load_message("main") 
    await send_photo(update, context, "main") 
    await send_text(update, context, text) 
Функция gpt() имеет вид:

async def gpt(update, context): 
    dialog.mode = "gpt" 
    await send_photo(update, context, "gpt") 
    await send_text(update, context, "Напишите сообщение *ChatGPT*:") 

Шаг 6. Показываем меню с командами

Давайте еще немного украсим наш Telegram-бот. Для этого мы отобразим ему снизу меню с командами. Выглядеть оно будет примерно так: Дополнение и конспект к занятию №2 - 1Чтобы отобразить меню, нам понадобиться всего одна функция – show_main_menu(). В нее нужно передать параметры update, context, а также список команд в фигурных скобках – так же, как мы передавали, например, в функцию sent_text_buttons() Пример:

    await show_main_menu(update, context, { 
        "start": "главное меню бота", 
        "gpt": "задать вопрос ChatGPT" 
    }) 
Слева (до знака равно) мы перечисляем именно имена команд (не режимов диалога). Каждый раз, когда пользователь кликнет на такой пункт меню, в чат отправится соответствующая команда.

Шаг 7. Отображаем наш список команд в меню

Ну и давайте сделаем наше меню красивше. Можно взять список будущих команд из файла resources\messages\main.txt Он будет таким:
1. /start – главное меню бота 2. /profile – генерация Tinder-профиля 😎 3. /opener – сообщение для знакомства 🥰 4. /message – переписка от вашего имени 😈 5. /date – переписка со звездами 🔥 6. /gpt – задать вопрос чату GPT 🧠
Все смайлики отлично отображаются и в main.txt, и в коде в PyCharm и в Telegram, поэтому просто скопируйте тексты и поправьте вызов метода show_main_menu(), чтобы там были все 6 команд.

Шаг 8. Выводы

Таким образом к концу этой лекции мы можем общаться с чатом тремя способами:
  • нажать на команду в приветственном сообщении
  • ввести команду в формате /команда
  • кликнуть по меню и выбрать соответствующую команду.
На этой лекции мы:
  • прикрутили ChatGPT
  • добавили обработку команды /gpt
  • добавили переключение в режим диалога
  • разобрались как работать с промптами
  • добавили отображение меню с командами