Писал код для телеграмм бота. По ТЗ суб. подрядчик может задать вопрос ген. подрядчику (его представителям), а тот (те) на него ответить. Также вшита "защита" от повторных ответов.
Через ChatGPT написал основу этого механизма:
import telebot
import threading
from telebot import types
bot = telebot.TeleBot("тут токен") # токен бота (на данный момент тест)
genpod_id = "genpod_id.txt" # Файл с ID зарегестрированных представителей ген. подрядчика.
# Кнопки
def choise_markup():
markup = types.InlineKeyboardMarkup(row_width=True)
gen_key = types.InlineKeyboardButton(text="Ген. Подрядчик", callback_data="gen_key_check")
sub_key = types.InlineKeyboardButton(text="Суб. Подрядчик", callback_data="sub_key_check")
markup.add(gen_key, sub_key)
return markup
def sub_func_markup():
markup = types.InlineKeyboardMarkup(row_width=True)
report_key = types.InlineKeyboardButton(text="Оставить отчет", callback_data="report_key")
callback_key = types.InlineKeyboardButton(text="Задать вопрос", callback_data="callback_key")
markup.add(report_key, callback_key)
return markup
def callback_markup():
markup = types.InlineKeyboardMarkup(row_width=True)
ask_question_key = types.InlineKeyboardButton(text="Написать вопрос", callback_data="ask_question")
markup.add(ask_question_key)
return markup
# Комманды
@bot.message_handler(commands=["start"])
def start(message):
bot.send_message(message.chat.id, "Добрый день!\nПредставьтесь, пожалуйста:", reply_markup=choise_markup())
# Вывод функционала по выбору
def sub_functional(message):
bot.delete_message(message.chat.id, message.message_id)
bot.send_message(message.chat.id, "Что вы хотите сделать?", reply_markup=sub_func_markup())
# Обработка callback и вывод конкретного функционала
@bot.callback_query_handler(func= lambda call: True)
def callback(call):
if call.data == "sub_key_check":
thread = threading.Thread(target=sub_functional, args=(call.message,))
thread.start()
if call.data == "callback_key":
thread = threading.Thread(target=get_callback, args=(call.message,))
thread.start()
# if call.data == "ask_question":
# thread = threading.Thread(target=write_callback, args=(call.message,))
# thread.start()
# Вопросы
def get_callback(message):
bot.send_message(message.chat.id, "Вы можете задать вопрос Ген. Подрядчику.", reply_markup=callback_markup())
@bot.callback_query_handler(func=lambda call: call.data == 'ask_question')
def write_callback(call):
chat_id = call.message.chat.id
bot.send_message(chat_id, "Введите наименование вашей организации:")
bot.register_next_step_handler_by_chat_id(chat_id, get_company_name)
def get_company_name(message):
chat_id = message.chat.id
company_name = message.text
bot.send_message(chat_id, "Напишите вопрос:")
bot.register_next_step_handler(message, get_question, company_name)
def get_question(message, company_name):
chat_id = message.chat.id
question = message.text
# Сохраним информацию о вопросе для последующего ответа
if not hasattr(bot, 'questions'):
bot.questions = {}
question_id = len(bot.questions) + 1
bot.questions[question_id] = {'chat_id': chat_id, 'company_name': company_name, 'question': question, 'answered': False}
with open(genpod_id, 'r') as file:
genpod_ids = [int(line.strip()) for line in file.readlines()]
for genpod in genpod_ids:
markup = types.InlineKeyboardMarkup()
button_reply = types.InlineKeyboardButton("Ответить", callback_data=f'reply_{question_id}')
markup.add(button_reply)
bot.send_message(genpod, f" Новый вопрос от {company_name}.\n{question}", reply_markup=markup)
bot.send_message(chat_id, "✅ Ваш вопрос принят.")
@bot.callback_query_handler(func=lambda call: call.data.startswith('reply_'))
def reply_to_question(call):
question_id = int(call.data.split('_')[1])
question_data = bot.questions.get(question_id)
if not question_data:
bot.answer_callback_query(call.id, "⚠️ Вопрос не найден!", show_alert=True)
return
if question_data['answered']:
bot.answer_callback_query(call.id, "⚠️ На этот вопрос уже ответили!", show_alert=True)
return
bot.send_message(call.message.chat.id, "Напишите ответ на вопрос:")
bot.register_next_step_handler_by_chat_id(call.message.chat.id, send_answer, question_id)
def send_answer(message, question_id):
answer = message.text
question_data = bot.questions.get(question_id)
if question_data and not question_data['answered']:
original_chat_id = question_data['chat_id']
bot.send_message(original_chat_id, f" Ответ от генерального подрядчика:\n{answer}")
question_data['answered'] = True
else:
bot.send_message(message.chat.id, "⚠️ На этот вопрос уже ответили!")
bot.polling(none_stop=True)
Проблема в том, что при нажатии инлайн-кнопок "Написать вопрос" и "Ответить", от них игнорируется call: call.data == 'ask_question' (и, как потом выяснил, call: call.data.startswith('reply_')). Не понимаю, из-за чего это происходит.
Как это можно исправить?