Когда вы разрабатываете Thatbot, иногда для пользовательского опыта вы не можете попросить вашего пользователя отправлять сообщения, такие как команды. Например, мы хотим построить угадать номер бота. Мы хотим, чтобы бот работает так:
Пользователь: Угадай Бот: От какого числа? Пользователь: : 25 бот: К каком количеству? Пользователь: 100 Бот: Угадай число от 25 до 100 Пользователь: 64 Бот: Слишком маленький Пользователь: 91 Бот: слишком большой …… Пользователь: 83 Бот: Верный! Вы провели 6 раз, чтобы угадать этот номер.
Тем не менее, распространенный способ, которым мы имеем дело с запросами на бэкэнде, является одним-запросом – один ответ. Это было бы катастрофой для отделения многих обработчиков из разговора. Почему? Подумайте, как хранить штаты? В глобальных переменных? Или база данных? Или redis? Как только вы попросите пользователям еще один вопрос, вам нужно изменить схему вашего состояния, и код становится более сложным.
В следующем я покажу вам, как иметь дело с разговорами и писать обработчик простым и простым способом, как это:
def guess(self): '''Game function''' min_value = self.ask_number('From what number?') max_value = self.ask_number('To what number?') secret = randint(min_value, max_value) msg = f'Guess a number between {min_value} to {max_value}' counter = 0 while True: counter += 1 answer = self.ask_number(msg) if answer > secret: msg = 'Too large' elif answer < secret: msg = 'Too small' else: break self.reply(f'You spent {counter} times to guess the secret number.')
Например, я напишу линию бота, но не имеет значения, какую платформу вы развиваете. Я буду использовать Django, и все в порядке, если вы используете другие рамки.
Настройка среды
Это для настройки бота, вы можете пропустить это, если вы это знаете.
Клонировать мое репо:
git clone https://github.com/lancatlin/python-chatbot-context.git cd python-chatbot-context pipenv install pipenv shell
Перейти к Разработчики линии создать бот. Выдайте токен и ваш секрет, положите их в .env
файл.
LINE_TOKEN=YOUR_TOKEN LINE_SECRET=YOUR_SECRET
Затем начните Django.
python manage.py migrate # for first execution python manage.py runserver
Используйте Ngrok или что-то подобное туннелю Localhost: 8000 на общедоступную конечную точку и зарегистрируйте URL-адрес API обмена сообщениями.
Идея описать
Основная идея состоит в том, чтобы заблокировать командный поток, пока не будет получено другое сообщение. Когда программа получает команду «Угадай», она будет выполнена в командной ните. Как только программа нуждается в входе от пользователя, он поместил сообщение в «Очередь запросов» в номере. Затем, когда сообщение входит в другой поток, он проверяет очередь запросов в комнату и помещает сообщение в очередь ответов, если не пусто.
Осуществлять
Мы реализуем это как MessageQueue
класс:
# guess/message_queue.py import queue from threading import RLock from .line import get_room class RequestTimout(Exception): pass class MessageQueue: __lock = RLock() __requests = {} __responses = {} @classmethod def create_if_not_exists(cls, room): '''Create the requests and responses queues for the room if not exists''' with cls.__lock: if room not in cls.__requests: cls.__requests[room] = queue.Queue(maxsize=1) if room not in cls.__responses: cls.__responses[room] = queue.Queue(maxsize=1) @classmethod def handle(cls, event): '''Handle the message, check whether there is room request for''' room = get_room(event) cls.create_if_not_exists(room) try: if not cls.__requests[room].empty(): cls.__responses[room].put(event, timeout=1) cls.__requests[room].get() return True return False except queue.Empty: '''No request, ignore the message''' return False @classmethod def request(cls, room, timeout=30): '''Request a message, block until message comes in or timeout''' try: cls.create_if_not_exists(room) cls.__requests[room].put_nowait(True) return cls.__responses[room].get(timeout=timeout) except queue.Empty: MessageQueue.clear(room) raise RequestTimout @classmethod def clear(cls, room): '''Clear the requests''' cls.create_if_not_exists(room) try: cls.__requests[room].get_nowait() except queue.Empty: pass
С этим мы можем очень легко реализовать наше приложение догадаться.
# guess/guess.py from .message_queue import MessageQueue, RequestTimout from .line import reply_text, get_room, get_msg from random import randint class Guess: '''Guess handle a guess number game''' def __init__(self, event): self.event = event try: self.guess() except RequestTimout: self.reply('Timeout') def guess(self): '''Game function''' min_value = self.ask_number('From what number?') max_value = self.ask_number('To what number?') secret = randint(min_value, max_value) msg = f'Guess a number between {min_value} to {max_value}' counter = 0 while True: counter += 1 answer = self.ask_number(msg) if answer > secret: msg = 'Too large' elif answer < secret: msg = 'Too small' else: break self.reply(f'You spent {counter} times to guess the secret number.') def ask(self, *msg): '''Ask a question to current user''' self.reply(*msg) self.event = MessageQueue.request(get_room(self.event)) return get_msg(self.event) def ask_number(self, *msg): '''Ask a number, if not number, ask again''' try: content = self.ask(*msg) return int(content) except ValueError: return self.ask_number('Please input an integer.', *msg) def reply(self, *msg): '''Reply words to user''' reply_text(self.event, *msg)
Вы можете увидеть, что главная функция проста, с 17 линиями кода. Более того, он может обрабатывать несколько пользовательских входов одновременно.
Получить полный код на Github Отказ
Особая благодарность Юкинамочизуки Для того, чтобы дать мне первоначальную идею от Его понятный бот проект Отказ
Оригинал размещен на Wancat.cc.
Оригинал: “https://dev.to/wancat/how-to-handle-conversation-in-chatbot-in-python-41c5”