Крок 1. Підключаємо режим дейтингу /date

Ви вже знаєте, як додавати нові команди і нові режими діалогу для них. За аналогією зі вчорашнім днем додайте функцію date() з аналогічним функціоналом:
  • режим діалогу — date
  • відображаємо вітальне повідомлення — date
  • відображаємо картинку — date
Не забудьте додати хендлер наприкінці файлу, щоб пов'язати цю функцію з нашим ботом.

Крок 2. Відображаємо список кнопок

У вітальному повідомленні ми запропонували користувачеві нашого бота вибрати собі знаменитість для спілкування. Наприклад, ви хочете поспілкуватися з:
  • Мерилін Монро
  • Мішель Обамою
  • Жаклін Кеннеді
Тоді вам потрібно написати код типу:

await send_text_buttons(update, context, text, {
    "date_monro": " Мерилін Монро",
    "date_obama": "Мішель Обама",
    "date_kenedy": "Жаклін Кеннеді"
})
Важливо! Реальний список імен ви дізнаєтеся тільки на марафоні 😊

Крок 3. Обробляємо натискання кнопки

Якщо користувач вашого бота вибрав якусь зірку, вам потрібно додати функцію, яка викликалася б у відповідь на клік на кнопку. Для цього додайте собі ще одну функцію — date_button. Приклад:

async def date_button(update, context):
    query = update.callback_query.data
    await update.callback_query.answer()
    await send_text(update, context, "Користувач натиснув кнопку: "+query)
Не забудьте додати для неї хендлер наприкінці файлу.

Крок 4. Діалог

Під час спілкування з чатом-gpt у нас була функція gpt_dialog, у якій ми пересилали всі повідомлення ChatGPT. Тепер нам знадобиться аналогічна. Додайте до свого коду функцію date_dialog(), і скопіюйте туди код із gpt_dialog. Приклад:

async def date_dialog(update, context):
    prompt = load_prompt("gpt")
    text = update.message.text
    answer = await chatgpt.send_question(prompt,  text)
    await send_text(update, context, answer)
Не забудьте додати виклик функції date_dialog() у функцію hello. Важливо! Поміняйте ім'я промпта з «gpt» на «date».

Крок 5. ПеремикаємоChatGPT у режим емуляції дівчини

Щоб ChatGPT у подальшому листуванні поводився як дівчина, яку ми хочемо запросити на побачення, потрібно зробити 3 речі:

1. Переключити ChatGPT у режим діалогового спілкування.

Раніше він відповідав на наші запитання в режимі запитання-відповідь. Зараз же ми хочемо, щоб усі повідомлення ChatGPT сприймав як одне листування. Для цього потрібно кожне нове повідомлення відправляти йому не за допомогою методу send_question(), а за допомогою методу add_message(). Але ще потрібно якось передати йому prompt. Цей промпт можна передати, просто викликавши метод set_prompt Приклад:

async def date_button(update, context):
    query = update.callback_query.data
    await update.callback_query.answer()

    await send_photo(update, context, query)
    await send_text(update, context, "Чудовий вибір! ")

    prompt = load_prompt(query)
    chatgpt.set_prompt(prompt)
У мене є заздалегідь заготовлені хороші промпти — просто оберіть один. Функція set_prompt() не асинхронна, використовувати оператор await при її виклику не потрібно.

Крок 6. Обробка довгих відповідей

Іноді ChatGPT може відповідати по 10 секунд. Щоб у користувача не виникало відчуття, що наш бот тупить, можна зробити так: відправити користувачеві текст типу «ChatGPT думає» відправити запит ChatGPT дочекатися відповіді від ChatGPT поміняти старе повідомлення «ChatGPT думає» на нове — відповідь ChatGPT. Ось як це може виглядати для функції gpt_dialog():

async def gpt_dialog(update, context):
    my_message = await send_text(update, context, "ChatGPT думає. Очікуйте...")
    prompt = load_prompt("gpt")
    text = update.message.text
    answer = await chatgpt.send_question(prompt, text)
    await my_message.edit_text(answer)
За аналогією можна зробити і date_dialog():

async def date_dialog(update, context):
    text = update.message.text
    my_message = await send_text(update, context, "Дівчина друкує...")
    answer = await chatgpt.add_message(text)
    await my_message.edit_text(answer)

Крок 7. Обробка команди /message

Обробка команди message дуже схожа на команду date з трьома невеликими відмінностями.

Відмінність перша:

Ми спочатку накопичуємо у себе історію листування користувача, а потім одним повідомленням відсилаємо її в ChatGPT.

Відмінність друга:

Ми відображаємо 2 кнопки під вітальним повідомленням:
  • «message_next": «Написати повідомлення»,
  • «message_date": “Запросити на побачення”,
Користувач сам вирішує, що йому зробити після відправлення боту історії свого листування — спробувати написати ще одне повідомлення або відразу запросити на побачення.

Відмінність третя:

При введенні користувачем повідомлення ми просто додаємо його до історії його листування, а не відправляємо ChatGPT. А тепер давайте пройдемося по них трохи докладніше.

Крок 8. Накопичуємо листування

Щоб накопичити історію листування користувача, потрібно завести для неї окремий список. Давайте додамо його до об'єкта dialog:

dialog = Dialog()
dialog.mode = “main”
dialog.list = []
У цей список ми будемо додавати всі повідомлення користувача, які він нам пише — тобто ті, які потрапляють у функцію message_dialog()

async def message_dialog(update, context):
    text = update.message.text
    dialog.list.append(text)
І нарешті, історію листування іноді потрібно чистити. Наприклад, під час кліку користувача по команді /message:

async def message(update, context):
    dialog.mode = "message"
    text = load_message("message")
    await send_photo(update, context, "message")
    await send_text_buttons(update, context, text, {
        "message_next": "Написати повідомлення",
        "message_date": "Запросити на побачення",
    })
    dialog.list.clear()

Крок 9. Надсилаємо листування ChatGPT

Щоб відправити ChatGPT листування, потрібно зробити 3 речі:
  • завантажити відповідний prompt
  • об'єднати все листування в один рядок
  • відправити його ChatGPT
Приклад:

async def message_button(update, context):
    query = update.callback_query.data
    await update.callback_query.answer()

    prompt = load_prompt(query)
    user_chat_history = "\n\n".join(dialog.list)
    my_message = await send_text(update, context, "ChatGPT думає над варіантами відповіді...")
    answer = await chatgpt.send_question(prompt, user_chat_history)
    await my_message.edit_text(answer)
Зверніть увагу: щоб об'єднати список повідомлень користувача, потрібно використовувати функцію join. Для цього потрібно написати код вигляду:

"рядок розділювач".join(список)
Ми як роздільник вибрали два порожні рядки — два символи «\n»

Крок 10. Шаблони для хендлерів

У вас зараз додано 2 хендлери, які будуть заважати один одному:

app.add_handler(CallbackQueryHandler(date_button))
app.add_handler(CallbackQueryHandler(message_button))
Обидва будуть викликатися, коли користувач клікає на кнопку, приєднану до повідомлення. Щоб розділити наші кнопки, ми вирішили дати їм різні префікси:
  • кнопки для режиму date починаються з префікса «date_»
  • кнопки для режиму message починаються з префікса «message_»
Тепер потрібно прив'язати CallbackQueryHandler не просто до нашої функції, а ще й до певних типів повідомлень. Для цього потрібно вказати другий параметр — pattern:

app.add_handler(CallbackQueryHandler(date_button, pattern="date_monro"))
Але якщо ви хочете, щоб цей хендлер реагував на префікси кількох повідомлень, то вам потрібно задати pattern у вигляді регулярного виразу.

^prefix.*
Де:
  • символ «^» позначає початок рядка
  • символ «.» означає будь-який символ
  • символи «.*» позначають будь-яку кількість будь-яких символів
Приклад готових хендлерів:

app.add_handler(CallbackQueryHandler(date_button, pattern="^date_.*"))
app.add_handler(CallbackQueryHandler(message_button, pattern="^message_.*"))