У цій лекції наш бот стане розумнішим, бо ми прикрутимо до нього штучний інтелект, а саме — 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.
  • Додали перемикання в режим діалогу.
  • Розібралися як працювати з промптами.
  • Додали відображення меню з командами.