Шаг 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_.*"))