Как реализовать диалог между 2 пользователями через бота Телеграм
Как реализовать диалог между 2 пользователями через бота Телеграм Python. Возможно использование библиотек PyTelegramBotAPI или AioGram. Нужно чтобы пользователь заходил в бота, писал сообщение и оно отправлялось другому пользователю в чат бота. То есть, обычный чат, но с посредником в виде бота. Если можно, то пример реализации или кода. Спасибо!
Отслеживать
задан 16 дек 2021 в 15:38
25 7 7 бронзовых знаков
1 ответ 1
Сортировка: Сброс на вариант по умолчанию
В самом начале придется получить и прописать в коде chat_id обоих собеседников, а дальше довольно просто.
user1_chat_id = "chat_id" user2_chat_id = "chat_id" @bot.message_handler(content_types=["text"]) def messanger(message): if message.from_user.chat_id == user1_chat_id: bot.send_message(user2_chat_id, message.text) else: bot.send_message(user1_chat_id, message.text)
Это что касается только текстовых сообщений, но можно тоже самое для остальных видов сообщений сделать
Собственные диалоговые окна, класс Dialog
На этом занятии продолжим тему диалоговых окон и посмотрим как можно создавать свои собственные диалоги. Это делается очень просто. Все диалоговые окна наследуются от класса Dialog, имеющий следующий синтаксис:
- parent – ссылка на родительское окно (или значение None);
- id – идентификатор окна;
- title – заголовок окна;
- pos, size – позиция и размер окна;
- style – стилизация окна.
- wx.CAPTION – разрешает заголовок окна;
- wx.DEFAULT_DIALOG_STYLE (комбинация констант: wx.CAPTION, wx.CLOSE_BOX и wx.SYSTEM_MENU);
- wx.RESIZE_BORDER – разрешает изменять размеры окна;
- wx.SYSTEM_MENU – для отображения системного меню;
- wx.CLOSE_BOX – для отображения кнопки закрытия (с крестиком);
- wx.MAXIMIZE_BOX – для возможности распахивания окна;
- wx.MINIMIZE_BOX – для возможности свертывания окна;
- wx.STAY_ON_TOP – для отображения окна поверх всех остальных.
class MyDlg(wx.Dialog): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs)
Смотрите, мы здесь объявили свой конструктор, в который можно передавать произвольные параметры *args и именованные параметры **kwargs. Затем, вызываем конструктор базового класса, то есть, Dialog и передаем ему все те же самые параметры: *args и **kwargs. Благодаря этому мы можем через класс MyDlg создавать диалоговые окна с разной стилизацией. Далее, в классе MyFrame создадим тулбар с двумя кнопками и вторую свяжем с вызовом диалога:
class MyFrame(wx.Frame): def __init__(self, parent, title): super().__init__(parent, title=title, size=(600, 300)) toolbar = self.CreateToolBar() br_quit = toolbar.AddTool(wx.ID_ANY, "Выход", wx.Bitmap("exit32.png")) toolbar.AddSeparator() dialog = toolbar.AddTool(wx.ID_ANY, "Диалог", wx.Bitmap("sound32.png")) toolbar.Realize() self.Bind(wx.EVT_TOOL, self.onQuit, br_quit) self.Bind(wx.EVT_TOOL, self.onDialog, dialog)
Сами обработчики будут следующими:
def onDialog(self, e): dlg = MyDlg(self, title="Мой диалог. ") res = dlg.ShowModal() dlg.Destroy() print(res) def onQuit(self, e): self.Close()
В обработчике onDialog мы создаем экземпляр класса MyDlg, указывая родительское окно MyFrame и заголовок title. Затем, отображаем окно как модальное с помощью метода ShowModal. Данный метод возвращает id элемента, через который произошло закрытие этого окна. И следующей строчкой мы должны вызвать метод Destroy для уничтожения окна. Иначе оно просто будет скрыто, но продолжит существовать в памяти компьютера. При запуске этой программы увидим вот такой результат диалогового окна: А в консоли появится значение wx.ID_CANCEL, равное 5101. Мы в этом можем легко убедиться, если запишем:
print(res, wx.ID_CANCEL)
Модальные и немодальные окна
Запустим программу еще раз и обратим внимание на такой факт: пока не закроем это диалоговое окно, другие окна программы будут для нас недоступны. Про такие окна говорят, что они модальные. То есть, мы можем взаимодействовать только с ним, пока его не закроем. Для модальных окон создается свой независимый цикл обработки событий. Условно это можно изобразить так: В нашей программе модальное окно создается благодаря вызову метода ShowModal и программа переходит на следующую строчку dlg.Destroy() только после закрытия диалога. Однако, мы можем изменить это поведение и отобразить диалоговое окно как немодальное, вызвав метод Show:
res = dlg.Show()
Смотрите, теперь при запуске наше окно показывается и тут же исчезает, так как программа сразу идет дальше и вызывается метод dlg.Destroy(). Давайте поставим его в комментарий и снова запустим программу. Теперь наше окно не исчезло и, кроме того, мы можем взаимодействовать и с главным окном, например, открыть еще одно диалоговое окно. Здесь уже нет отдельного цикла событий и потому интерфейс реагирует на действия пользователя. Вот в этом основные отличия модальных и немодальных окон. Конечно, я здесь привел только пример отображения окна как немодального. По идее, в таком случае нужно контролировать их число и, например, не показывать более одного. Для этого к классе MyFrame создадим локальное свойство:
self.dlg = None
и в обработчике onDialog запишем:
if self.dlg is None: self.dlg = MyDlg(self, title="Мой диалог. ") self.dlg.Show()
То есть, прежде чем создать новое окно, мы проверяем значение свойства self.dlg и если оно равно None, то делаем вывод, что окно еще не отображено, создаем его и показываем на экране. А в конструкторе класса MyDlg добавим обязательный параметр parent:
class MyDlg(wx.Dialog): def __init__(self, parent, *args, **kwargs): super().__init__(parent, *args, **kwargs) self.parent = parent
и сохраним его в отдельном локальном свойстве этого класса. Далее, здесь же мы должны добавить обработчик события wx.EVT_CLOSE:
self.Bind(wx.EVT_CLOSE, self.onClose)
а сам обработчик запишем следующим образом:
def onClose(self, e): self.Destroy() self.parent.dlg = None
В нем мы уничтожаем окно с помощью метода Destroy и свойство dlg класса MyFrame снова устанавливаем в None. Запустим программу, и теперь отображается только одно диалоговое окно. Конечно, это лишь пример того, как можно работать с такими немодальными окнами. Логика обработки вполне может быть и другой. Все зависит от конкретной решаемой задачи.
Отображение модального окна через менеджер контекста
Давайте вернем окно в модальный режим, запишем обработчик onDialog в виде:
def onDialog(self, e): dlg = MyDlg(self, title="Мой диалог. ") res = dlg.ShowModal() dlg.Destroy() print(res)
В этом фрагменте программы есть один недостаток: в случае каких-либо ошибок (исключений) метод Destroy может быть не вызван и окно останется в памяти. Конечно, мы можем воспользоваться конструкцией try/except/finally, чтобы решить эту проблему и записать все вот в таком виде:
def onDialog(self, e): try: dlg = MyDlg(self, title="Мой диалог. ") res = dlg.ShowModal() print(res) except Exception as e: print(e) finally: dlg.Destroy()
Но это не лучший способ. В Python часто при отображении модальных диалоговых окон используют менеджер контекста, который автоматически уничтожает окно (вызывает метод Destroy) после выполнения тела контекста. (Если вы не знаете что такое менеджер контекста, то вот ссылка на это занятие). В нашем случае это можно реализовать так:
with MyDlg(self, title="Мой диалог. ") as dlg: res = dlg.ShowModal() print(res)
Здесь в менеджере создается экземпляр окна и далее, через ссылку dlg, мы отображаем это окно как модальное. При выходе из этого менеджера диалоговое окно будет автоматически уничтожено. Мы в этом можем легко убедиться, если переопределим в классе MyDlg этот метод:
def Destroy(self): print("Вызван метод Destroy") super().Destroy()
Теперь при закрытии окна увидим сообщение, что был вызван метод Destroy.
Стилизация диалоговых окон
Давайте теперь посмотрим на различные способы стилизации диалоговых окон. И для начала вызовем окно со стандартными стилями:
with MyDlg(self, title="Мой диалог. ", style=wx.CAPTION | wx.CLOSE_BOX | wx.SYSTEM_MENU) as dlg:
Далее, уберем стиль wx.CLOSE_BOX:
with MyDlg(self, title="Мой диалог. ", style=wx.CAPTION | wx.SYSTEM_MENU) as dlg:
и смотрите, кнопка закрытия окна неактивна, окно можно закрыть лишь комбинацией клавиш Alt+F4. Если убрать все стили:
with MyDlg(self, title="Мой диалог. ", style=0) as dlg:
то получим окно в виде вот такого полотна. Его также можно закрыть комбинацией клавиш Alt+F4. Добавим туда wx.CAPTION, wx.CLOSE_BOX и еще wx.RESIZE_BORDER:
with MyDlg(self, title="Мой диалог. ", style=wx.CAPTION | wx.CLOSE_BOX | wx.RESIZE_BORDER) as dlg:
Теперь наше окно можно менять в размерах. И так далее, комбинируя стили различным образом можно получать окна с разными свойствами.
Стандартные элементы управления
Давайте разместим в нашем окне текстовое поле ввода и две кнопки «Да» и «Отмена». Класс MyDlg можно представить так:
class MyDlg(wx.Dialog): def __init__(self, parent, *args, **kwargs): super().__init__(parent, *args, **kwargs) self.SetSize(500, 150) vb = wx.BoxSizer(wx.VERTICAL) vb.Add(wx.TextCtrl(self, wx.ID_ANY), flag=wx.EXPAND | wx.ALL, border=10) vh = wx.BoxSizer(wx.HORIZONTAL) bOk = wx.Button(self, wx.ID_ANY, label="Да", size=(100, 30)) bCn = wx.Button(self, wx.ID_ANY, label="Отмена", size=(100, 30)) vh.Add(bOk, flag=wx.LEFT, border = 10) vh.Add(bCn, flag=wx.LEFT, border=10) vb.Add(vh, flag=wx.ALIGN_CENTER|wx.ALL, border=10) self.SetSizer(vb)
Запустим нашу программу и смотрите, при нажатии на кнопки ничего не происходит, что, впрочем, ожидаемо, так как мы не назначали им никаких обработчиков. Если решать эту задачу «в лоб», то можно это реализовать так. На первую кнопку «Да» повесить обработчик onOk:
bOk.Bind(wx.EVT_BUTTON, self.onOk)
и реализовать его в следующем виде:
def onOk(self, event): self.EndModal(wx.ID_OK)
Смотрите, мы здесь вызываем метод EndModal класса Dialog, который завершает цикл выполнения диалогового окна и определяет возвращаемое значение в виде константы ID_OK. И, затем, переменная res в обработчике onDialog будет принимать это значение. То есть, мы можем сделать такую проверку:
if res == wx.ID_OK: print("Нажата кнопка да")
Но это не лучший подход к обработке стандартных элементов управления в диалогах. Гораздо проще и удобнее у кнопки bOk прописать этот стандартный id:
bOk = wx.Button(self, wx.ID_OK, label="Да", size=(100, 30))
а назначение обработчика убрать. При запуске программы получим абсолютно такой же функционал для этой кнопки. По аналогии объявим и кнопку bCn:
bCn = wx.Button(self, wx.ID_CANCEL, label="Отмена", size=(100, 30))
В результате у нас будут две кнопки со стандартным поведением. Вот так создаются свои собственные диалоговые окна в wxPython.
Как реализовать систему диалогов на Python?
Скрипт ищет в файле Dialog.txt строку, соответствующую введенному тексту и выводит следующую, если скрипт не находит строку, то он выводит текст типа: «Прости, но я не знаю, как мне отвечать на эту фразу, как мне ответить на нее в следующий раз?», и пользователь писал пример.(Для этого я использовал исключения)
Пример содержания файла Dialog.txt:
Это шрифт вводимой фразы
Это шрифт ответа
Привет
Здравствуйте
Как твои дела?
Ничего нового, так как я очень медленно развиваюсь.
Это очень примитивно. Вы можете пожалуйста посоветовать какой-нибудь способ получше?
P.S. без использования нейросетей, т.к. я в них пока не шарю.
- Вопрос задан более трёх лет назад
- 635 просмотров
5 комментариев
Простой 5 комментариев
Диалог с пользователем через командную строку: программа Yes/No на Python
Диалоговые программы используются везде, примером может служить любое приложение на вашем компьютере (браузер, видеоплееры, текстовые редакторы и т. д.). Диалог Yes/No — это простой пример диалоговой программы, работающей с командной строкой.
Что такое диалоговая программа и зачем она нужна
Программа, в которой предусмотрено взаимодействие с пользователем, называется диалоговой (интерактивной).
Ввод текста, нажатия на кнопки, загрузка файлов — всё это способы взаимодействия пользователя с приложением.
Диалог между программой и пользователем — это важная часть любого проекта. Если программа работает с одними строго определенными данными, она не несёт какого-либо практического смысла.
Диалоговая программа Yes/No на Python
Диалог может вестись как через графический интерфейс, так и через командную строку. С помощью Python можно реализовать и то и другое, однако общение с пользователем через терминал имеет более простую реализацию и требует меньше кода.
Суть такой программы проста: пользователь отвечает на вопросы, вводя в консоль Yes – да, или No – нет. Не стоит думать, что сейчас актуально взаимодействовать с программой только через графический интерфейс, командная строка также используется.
Например, в операционной системе Linux часто устанавливают программы через командную строку. Система может приостановить процесс и спросить пользователя, желает ли он продолжить установку «Do you want to continue [Y/n]?», для подтверждения он должен ввести Y, иначе N.
Понятно, что диалог через командную строку чаще используется продвинутыми пользователями или техническими специалистами, которых не пугает работа в режиме текстовых команд.
Консольный диалог Yes/No особенно актуален, потому что не требует реализовывать графический интерфейс, который может быть бесполезен для выполнения определённых задач.
Реализация функции диалога Yes/No на Python
Написать консольную диалоговую программу на Python очень просто, однако нужно учесть и продумать некоторые нюансы, такие как неверный ввод от пользователя. Yes/no легко можно заменить на Да/нет, но давайте следовать общепринятым стандартам и использовать английский язык.
Объявление функции
Поместим всю логику диалоговой программы в отдельную функцию, которую объявим так:
def yes_no_dialog(question, default_answer="yes"):
Здесь аргументы означают следующее:
- question – это вопрос, который выводится в командную строку, и на который пользователь должен дать ответ «yes» или «no».
- default_ answer – это необязательный параметр, который будет использоваться в том случае, если пользователь не введет ответ, а просто нажмет Enter.
Начальные настройки
Предположим, что пользователь может вводить не только «yes», но и «y» или «ye». Обработка каждого вариант с помощью условных операторов if — else нецелесообразна и требует много лишнего кода. Поэтому поместим все варианты ответа в словарь:
answers =
default_answer позволяет указать предпочтительный вариант ответа, однако это не очевидно для обычного пользователя. В зависимости от содержимого default_answer будем выводить соответствующую подсказку:
if default_answer == None: # Если ответ по умолчанию не определен tip = " [y/n] " # выводим обе буквы в нижнем регистре elif default_answer == "yes": # Если ответ по умолчанию "yes" tip = " [Y/n] " # Выделяем Y elif default_answer == "no": # Если ответ по умолчанию "no" tip = " [y/N] " else: raise ValueError(f'Неверное значение: ')
При вводе аргумента default_answer тоже можно допустить ошибку, поэтому в блоке else мы возбуждаем исключение, которое указывает на неверный ввод.
Основной цикл
Необходимо продумать следующие ситуации, когда пользователь:
- Ничего не вводит, но определен default_answer .
- Вводит верный ответ.
- Вводит неверный ответ.
Для реализации лучше использовать бесконечный цикл. Сначала необходимо вывести вопрос и подсказку, а затем получить ввод пользователя:
while True: print(question + tip + ": ", end="") user_answer = input().lower() # приводим к нижнему регистру
Подробнее про ввод и вывод данных можно почитать здесь.
Теперь ввод необходимо обработать так, чтобы при правильном вводе происходил выход из цикла, а при неправильном цикл начинался заново:
# Если default_answer определен, а пользователь ничего не ввёл if default_answer is not None and user_answer == '': # Выходим из функции, возвращая значение, соответствующее default_answer return answers[default_answer] # Если пользователь ввел верный ответ elif user_answer in answers: return answers[user_answer] # Если ответ неверен, выводим сообщение и продолжаем цикл else: print("Пожалуйста, введите yes/y или no/n\n")
Полный код функции
Соединив все вместе, получаем готовую к использованию функцию для диалога с пользователем:
def yes_no_dialog(question, default_answer="yes"): answers = if default_answer == None: tip = " [y/n] " elif default_answer == "yes": tip = " [Y/n] " elif default_answer == "no": tip = " [y/N] " else: raise ValueError(f'Неверное значение: ') while True: print(question + tip + ": ", end="") user_answer = input().lower() if default_answer is not None and user_answer == '': return answers[default_answer] elif user_answer in answers: return answers[user_answer] else: print("Пожалуйста, введите yes/y или no/n\n")
Пример программы
Предположим, что функция получает несколько вопросов из файла, результаты ответов записываются в другой файл, тогда код программы будет выглядеть так:
a = open("qst.txt", "r", encoding="utf-8") # открываем файл для чтения results = [] for line in a: # читаем файл построчно # Для каждой строки вызываем нашу функцию и помещаем возвращаемое # ею значение в список result results.append(yes_no_dialog(line.strip())) a.close() b = open("results.txt", "w") # Открываем файл для записи for elem in results: # Записываем каждый элемент списка в файл через пробел b.write(str(elem) + " ") b.close()
С помощью метода строк strip удалим лишние символы.
Перед запуском программы на Python надо не забыть подготовить файл с вопросами qst.txt такого вида:
Первый вопрос Второй вопрос Третий вопрос
Чтобы русские буквы корректно отображались — правильно указываем кодировку при открытии файла. В моём случае это encoding=»utf-8″ .
Результатом выполнения будет следующее:
Первый вопрос [Y/n] : Y Второй вопрос [Y/n] : no Третий вопрос [Y/n] : yes
Содержимое файла результата будет следующим:
