import requests import aiohttp from aiogram import Bot, Dispatcher, types from aiogram.contrib.fsm_storage.memory import MemoryStorage from aiogram.dispatcher.filters.state import State, StatesGroup from aiogram.utils import executor import re from aiogram.types import ReplyKeyboardMarkup, KeyboardButton import asyncio from aiogram.dispatcher import FSMContext from aiogram import types from aiogram.dispatcher.filters import Command from datetime import datetime, timedelta TOKEN = '6476840022:AAFlOlYHCH4UKbGlOfILw8xcIUG0AD354X8' bot = Bot(token=TOKEN) storage = MemoryStorage() dp = Dispatcher(bot, storage=storage) # Кнопка для перезапуска restart_button = ReplyKeyboardMarkup(resize_keyboard=True) restart_button.add(KeyboardButton("Перезапустить бота")) MAX_ATTEMPTS = 3 # Максимальное количество попыток ввода кода TIMEOUT = 30 # Время в секундах # Словарь для хранения данных о пользователях user_data = {} last_bot_message_id = {} # Словарь для хранения данных о сообщениях пользователей user_messages = {} class Form(StatesGroup): telegram_id = State() existing_patient = State() phone_number = State() fio = State() birthday = State() verification_code = State() confirm_fio = State() confirm_phone_number = State() @dp.message_handler(lambda message: message.text in ["📝 Запись", "🧰 Услуги", "⭐️ Специалисты", "🌍 Контакты", "📞 Связь"]) async def handle_menu_selection(message: types.Message): user_id = message.from_user.id if message.text == "📝 Запись": await bot.send_message(user_id,"Вы выбрали 'Запись'. Здесь можно записаться на прием.") elif message.text == "🧰 Услуги": await bot.send_message(user_id,"Вы выбрали 'Услуги'. Здесь можно ознакомиться с нашими услугами.") elif message.text == "⭐️ Специалисты": await bot.send_message(user_id,"Вы выбрали 'Специалисты'. Здесь можно узнать о наших специалистах.") elif message.text == "🌍 Контакты": await bot.send_message(user_id,"Вы выбрали 'Контакты'. Здесь указаны контактные данные.") elif message.text == "📞 Связь": await bot.send_message(user_id,"Вы выбрали 'Связь'. Здесь можно связаться с нами.") @dp.message_handler(commands=['test']) async def handle_help(message: types.Message): user_id = message.from_user.id await bot.send_message(user_id,"тестирование кнопок меню", reply_markup=generate_markup_menu()) @dp.message_handler(commands=['help']) async def handle_help(message: types.Message): #await save_message_data(message) user_id = message.from_user.id help_message = "Список доступных команд:\n" help_message += "/start - начать взаимодействие с ботом\n" help_message += "/registration - регистрация\n" help_message += "/help - показать список команд и их описания\n" sent_message = await bot.send_message(user_id, help_message) last_bot_message_id[user_id] = sent_message.message_id @dp.message_handler(Command("start"), state="*") async def handle_start(message: types.Message, state: FSMContext): # Завершаем текущее состояние и очищаем данные пользователя await state.finish() # Завершает текущее состояние await state.storage.reset_data(user=message.from_user.id) # Удаляет все данные пользователя в FSM хранилище # Отправляем фото with open("s-blob-v1-IMAGE-tdNCrEv8Ldo.png", "rb") as photo: await bot.send_photo( chat_id=message.from_user.id, photo=photo, caption=("Добро пожаловать!\nЯ чат-бот Клиники и Ваш надежный виртуальный помощник.\nЧтобы узнать, что я могу для Вас сделать, просто введите /help\nДля начала работы нажмите кнопку /registration внизу."), reply_markup=generate_markup_registration() # Кнопка для продолжения ) @dp.message_handler(commands=['registration']) async def handle_registration1(message: types.Message): #await save_message_data(message) user_id = message.from_user.id user_data[user_id] = {"step": "telegram_id"} sent_message = await bot.send_message(user_id, "Для продолжения регистрации отправьте, пожалуйста, свой Telegram ID, нажав на кнопку ниже.\nЕсли Вы хотите начать общение с ботом заново, нажмите /start.", reply_markup=generate_markup_telegram_id()) last_bot_message_id[user_id] = sent_message.message_id await Form.telegram_id.set() def generate_markup_telegram_id(): markup = types.ReplyKeyboardMarkup(row_width=2, resize_keyboard=True) item3 = types.KeyboardButton("Отправить Telegram ID") markup.add(item3) return markup def generate_markup_registration(): markup = types.ReplyKeyboardMarkup(row_width=1, resize_keyboard=True) item_registration = types.KeyboardButton("/registration") markup.add(item_registration) return markup @dp.message_handler(lambda message: message.text == "Отправить Telegram ID", state=Form.telegram_id) async def handle_telegram_id(message: types.Message): #await save_message_data(message) user_id = message.from_user.id telegram_id = message.from_user.id user_data[user_id]["telegram_id"] = telegram_id sent_message = await bot.send_message(user_id, f"Ваш Telegram ID: {telegram_id}. Вы уже являетесь пациентом нашей Клиники?\nЕсли Вы хотите начать общение с ботом заново, нажмите /start.", reply_markup=yes_no_markup()) last_bot_message_id[user_id] = sent_message.message_id await Form.existing_patient.set() @dp.message_handler(state=Form.existing_patient) async def handle_existing_patient(message: types.Message, state: FSMContext): #await save_message_data(message) user_id = message.from_user.id print(message.text.lower()) if message.text.lower() == "да": sent_message = await bot.send_message(user_id, "Введите ваш контактный номер телефона в формате 7XXXXXXXXX\nЕсли Вы хотите начать общение с ботом заново, нажмите /start.") last_bot_message_id[user_id] = sent_message.message_id await Form.phone_number.set() elif message.text.lower() == "нет": sent_message = await bot.send_message(user_id, "Затычка") last_bot_message_id[user_id] = sent_message.message_id await state.finish() # Завершаем состояние # Дополнительно добавляем условие для завершения работы состояния else: await bot.send_message(user_id, "Пожалуйста, выберите 'Да' или 'Нет' с помощью кнопок.") @dp.message_handler(state=Form.phone_number) async def process_phone_number(message: types.Message): #await save_message_data(message) user_id = message.from_user.id phone_number = message.text.strip() # Удаляем лишние пробелы user_data[user_id]["phone_number"] = phone_number # Регулярное выражение для проверки номера телефона if not re.match(r'^7\d{10}$', phone_number): sent_message = await bot.send_message(user_id, "Номер телефона должен начинаться с '7' и содержать 11 цифр. Пожалуйста, введите номер ещё раз\nЕсли Вы хотите начать общение с ботом заново, нажмите /start.") last_bot_message_id[user_id] = sent_message.message_id return # Отправляем номер телефона для подтверждения markup = types.ReplyKeyboardMarkup(resize_keyboard=True) item_good = types.KeyboardButton("Всё верно") item_no_good = types.KeyboardButton("Указать номер ещё раз") markup.row(item_good, item_no_good) sent_message = await bot.send_message(user_id, f"Проверьте, пожалуйста, свой номер телефона: {phone_number}.\nНажмите кнопку ниже\nЕсли Вы хотите начать общение с ботом заново, нажмите /start.", reply_markup=markup) last_bot_message_id[user_id] = sent_message.message_id await Form.confirm_phone_number.set() # Переход к состоянию подтверждения номера телефона @dp.message_handler(state=Form.confirm_phone_number) async def confirm_phone_number(message: types.Message): user_id = message.from_user.id if message.text.lower() == "всё верно": # Если номер телефона подтвержден, переходим к следующему шагу sent_message = await bot.send_message(user_id, "Укажите ФИО пациента строго в формате “Фамилия Имя Отчество”.\nЕсли пациентом является Ваш ребенок, введите только ФИО ребенка.\nПример: Иванов Иван Иванович\nЕсли Вы хотите начать общение с ботом заново, нажмите /start.") last_bot_message_id[user_id] = sent_message.message_id await Form.fio.set() # Переход к состоянию ввода ФИО elif message.text.lower() == "указать номер ещё раз": # Если номер телефона нужно указать снова, возвращаемся к вводу номера телефона sent_message = await bot.send_message(user_id, "Пожалуйста, введите номер телефона снова:\nЕсли Вы хотите начать общение с ботом заново, нажмите /start.") last_bot_message_id[user_id] = sent_message.message_id await Form.phone_number.set() # Возвращаемся к состоянию ввода номера телефона @dp.message_handler(state=Form.fio) async def handle_fio_process(message: types.Message): #await save_message_data(message) user_id = message.from_user.id fio_parts = message.text.strip().split() if len(fio_parts) == 3: last_name, first_name, middle_name = fio_parts user_data[user_id]["last_name"] = last_name user_data[user_id]["first_name"] = first_name user_data[user_id]["middle_name"] = middle_name sent_message = await bot.send_message(user_id, f"Проверьте, пожалуйста, в правильном ли формате вы ввели ФИО пациента:\nФамилия - {last_name}, Имя - {first_name}, Отчество - {middle_name}.\nНажмите кнопку ниже\nЕсли Вы хотите начать общение с ботом заново, нажмите /start.", reply_markup=markup2()) last_bot_message_id[user_id] = sent_message.message_id await Form.confirm_fio.set() # Переход к состоянию подтверждения ФИО else: sent_message = await bot.send_message(user_id, "Пожалуйста, введите ФИО в формате 'Фамилия Имя Отчество'.\nЕсли Вы хотите начать общение с ботом заново, нажмите /start.") last_bot_message_id[user_id] = sent_message.message_id @dp.message_handler(state=Form.confirm_fio) async def handle_fio_confirmation(message: types.Message): user_id = message.from_user.id if message.text.lower() == "всё верно": sent_message = await bot.send_message(user_id,"Укажите год рождения пациента в формате YYYY.\nЕсли пациентом является Ваш ребенок, введите только год рождения ребенка в формате YYYY.\nПример: 2003\nЕсли Вы хотите начать общение с ботом заново, нажмите /start.") last_bot_message_id[user_id] = sent_message.message_id await Form.birthday.set() # Переход к запросу года рождения elif message.text.lower() == "указать фио ещё раз": user_data[user_id].pop("last_name", None) user_data[user_id].pop("first_name", None) user_data[user_id].pop("middle_name", None) sent_message = await bot.send_message(user_id, "Укажите ФИО пациента строго в формате 'Фамилия Имя Отчество'.\nЕсли Вы хотите начать общение с ботом заново, нажмите /start.") last_bot_message_id[user_id] = sent_message.message_id await Form.fio.set() # Возвращаемся к запросу ФИО else: await bot.send_message(user_id, "Пожалуйста, выберите 'Всё верно' или 'Указать ФИО ещё раз' с помощью кнопок.\nЕсли Вы хотите начать общение с ботом заново, нажмите /start.") @dp.message_handler(state=Form.birthday) async def handle_birthday(message: types.Message): #await save_message_data(message) user_id = message.from_user.id birthday = message.text # Проверяем, что введённый год состоит из 4 цифр и является числом if len(birthday) != 4 or not birthday.isdigit(): sent_message = await bot.send_message(user_id, "Укажите год рождения пациента в формате YYYY.\nПример: 2003.\nЕсли Вы хотите начать общение с ботом заново, нажмите /start.") last_bot_message_id[user_id] = sent_message.message_id return # Преобразуем введённый год в целое число birth_year = int(birthday) current_year = datetime.now().year # Проверка возраста на не более 100 лет if birth_year < current_year - 100 or birth_year > current_year: sent_message = await bot.send_message(user_id, f"Укажите корректный год рождения. Пациенту не может быть больше 100 лет. Пример: 2003.\nЕсли Вы хотите начать общение с ботом заново, нажмите /start.") last_bot_message_id[user_id] = sent_message.message_id return # Сохранение года рождения user_data[user_id]["birthday"] = birthday # Отправка данных на сервер для проверки server_response = send_registration_request(user_data[user_id]) # Проверяем ответ от сервера if server_response != "OK": # Если пользователь не найден в базе, отправляем сообщение sent_message = await bot.send_message( user_id, "К сожалению, мы не смогли найти Вас в нашей базе. Возможно, у нас указаны другие данные, или Вы ни разу не были в нашей Клинике.\n\n" "Попробуйте пройти регистрацию еще раз. Если не получится, обратитесь в регистратуру Клиники или свяжитесь с нами по тел. (342) 207-03-03.\n\nБудьте здоровы!\n\n/start", reply_markup=generate_start_markup() ) last_bot_message_id[user_id] = sent_message.message_id return # Если пользователь найден, продолжаем процесс регистрации phone_number = user_data[user_id]["phone_number"] verification_code = send_verification_call(user_id, phone_number) if verification_code: # Показываем последние 4 цифры номера для верификации print(f"Последние 4 цифры номера телефона: {str(verification_code)[-4:]}") # Переход к состоянию ввода кода верификации sent_message = await bot.send_message( user_id, "В течение нескольких секунд на указанный номер телефона поступит звонок-сброс с уникального номера. Введите последние 4 цифры этого номера.\nПример: 3487\nЕсли звонок не поступил, пожалуйста, пройдите регистрацию заново, введя команду /start." ) last_bot_message_id[user_id] = sent_message.message_id await Form.verification_code.set() else: sent_message = await bot.send_message(user_id, "Произошла ошибка при отправке звонка. Пожалуйста, пройдите регистрацию заново, введя команду /start.", reply_markup=generate_markup_registration()) last_bot_message_id[user_id] = sent_message.message_id @dp.message_handler(state=Form.verification_code) async def handle_verification_code(message: types.Message, state: FSMContext): user_id = message.from_user.id code_entered = message.text.strip() # Удаляем пробелы на случай ошибки markup = generate_markup_menu() # Если это первая попытка, инициализируем счетчик попыток if "attempts" not in user_data[user_id]: user_data[user_id]["attempts"] = 0 if "verification_code" not in user_data[user_id]: await bot.send_message(user_id, "Процесс верификации не был инициализирован. Пожалуйста, начните регистрацию заново, введя команду /start.") await state.finish() return # Функция для проверки тайм-аута (будет вызвана автоматически через 30 секунд) async def verification_timeout(): await asyncio.sleep(TIMEOUT) # Ждем 30 секунд # Проверяем, если процесс регистрации всё еще не завершён if user_id in user_data and "verification_code" in user_data[user_id]: await bot.send_message(user_id, "Время на верификацию истекло. Пожалуйста, начните регистрацию заново, введя команду /start.") await state.finish() # Завершаем состояние del user_data[user_id]["verification_code"] # Удаляем код из данных пользователя del user_data[user_id]["attempts"] # Сбрасываем счетчик попыток # Запускаем тайм-аут в фоновом режиме asyncio.create_task(verification_timeout()) # Проверка на корректность кода expected_code = str(user_data[user_id]["verification_code"]) print(f"Ожидаемый код: {expected_code}, Введенный код: {code_entered}") # Если введенный код совпадает с ожидаемым if expected_code == code_entered: sent_message = await bot.send_message(user_id, "Верификация прошла успешно! Вы успешно зарегистрированы.\nЧем могу быть Вам полезен?", reply_markup=markup) last_bot_message_id[user_id] = sent_message.message_id # Удаление кода из данных и завершение состояния del user_data[user_id]["verification_code"] await state.finish() # Завершаем состояние # Отправка данных на сервер (если нужно) server_response = send_registration_request(user_data[user_id]) else: # Увеличиваем счетчик попыток user_data[user_id]["attempts"] += 1 # Если количество попыток больше максимального, завершаем процесс if user_data[user_id]["attempts"] >= MAX_ATTEMPTS: await bot.send_message(user_id, f"Вы превысили максимальное количество попыток ({MAX_ATTEMPTS}). Пожалуйста, начните регистрацию заново, введя команду /start.") await state.finish() # Завершаем состояние del user_data[user_id]["verification_code"] # Удаляем код из данных del user_data[user_id]["attempts"] # Сбрасываем счетчик попыток return sent_message = await bot.send_message(user_id, f"Неверный код верификации. Попытка {user_data[user_id]['attempts']} из {MAX_ATTEMPTS}. Пожалуйста, попробуйте еще раз.\nЕсли Вы хотите начать общение с ботом заново, нажмите /start.") last_bot_message_id[user_id] = sent_message.message_id print("Ошибка верификации: код не совпадает.") def send_verification_call(user_id, phone_number): url = "https://sms.ru/code/call" data = { "phone": phone_number, "api_id": "2ED72E61-76C8-5637-3587-2792D47B698C" } response = requests.post(url, data=data) json_data = response.json() verification_code = None if json_data and json_data["status"] == "OK": verification_code = json_data["code"] # Сохраняем код в user_data user_data[user_id]["verification_code"] = verification_code print(f"Код верификации, отправленный пользователю: {verification_code}") else: print("Звонок не может быть выполнен.") print("Текст ошибки:", json_data.get("status_text")) return verification_code async def save_message_data(message: types.Message, reply_to_message_id=None): user_id = message.from_user.id reply_to_message_id = last_bot_message_id.get(user_id, None) user_messages[message.message_id] = { "message_id": message.message_id, "text": message.text, "date": message.date.isoformat(), # Исправлено "user_id": message.from_user.id, "reply_to_message_id": reply_to_message_id } print(f"Сообщение пользователя {user_id} сохранено: {user_messages[message.message_id]}") await send_message_to_server(user_messages[message.message_id]) def send_registration_request(user_data): HEADER = { "Content-Type": "application/json" } data = { "telegram_id": user_data.get("telegram_id"), "first_name": user_data["first_name"], "second_name": user_data["middle_name"], "last_name": user_data["last_name"], "mobile_phone": user_data["phone_number"], "birthday": user_data["birthday"] } print("Отправляемые данные на сервер:", data) response = requests.post("http://46.146.229.242:1980/AppFindPac", headers=HEADER, json=data) if response.status_code == 200: result = response.json() print("Результат JSON:", result) return result.get('result') else: print(f"Ошибка при отправке данных. Статус-код: {response.status_code}") return "error" async def send_message_to_server(message_data): url = "http://46.146.229.242:1980/AppSaveMessage" headers = {"Content-Type": "application/json"} async with aiohttp.ClientSession() as session: async with session.post(url, headers=headers, json=message_data) as response: if response.status == 200: print(f"Сообщение {message_data['message_id']} успешно отправлено на сервер.") else: print(f"Ошибка при отправке сообщения {message_data['message_id']} на сервер. Статус-код: {response.status}") def yes_no_markup(): markup = types.ReplyKeyboardMarkup(row_width=2, resize_keyboard=True) item_yes = types.KeyboardButton("Да") item_no = types.KeyboardButton("Нет") markup.add(item_yes, item_no) return markup def markup2(): markup = types.ReplyKeyboardMarkup(row_width=2, resize_keyboard=True) item_good = types.KeyboardButton("Всё верно") item_no_good = types.KeyboardButton("Указать ФИО ещё раз") markup.add(item_good, item_no_good) return markup def generate_start_markup(): markup = types.ReplyKeyboardMarkup(row_width=1, resize_keyboard=True) start_button = types.KeyboardButton("/start") markup.add(start_button) return markup def generate_markup_menu(): # Создаем клавиши buttons = [ KeyboardButton("📝 Запись"), KeyboardButton("🧰 Услуги"), KeyboardButton("⭐️ Специалисты"), KeyboardButton("🌍 Контакты"), KeyboardButton("📞 Связь"), ] # Создаем и настраиваем клавиатуру markup = ReplyKeyboardMarkup(resize_keyboard=True, one_time_keyboard=False) # Добавляем кнопки в столбик (по одной в строке) markup.add(*buttons) return markup @dp.message_handler(content_types=types.ContentType.TEXT) async def handle_message(message: types.Message): await save_message_data(message) if __name__ == '__main__': executor.start_polling(dp, skip_updates=True)