commit 1909a9b75f3e2216889eb1100555c9037b5d4cdf Author: Ilya_Chis Date: Thu Jan 16 17:48:56 2025 +0500 проект Bot_Polimed diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0cafc1c --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.venv/ \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..891d263 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..e15ec35 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/pythonProject.iml b/.idea/pythonProject.iml new file mode 100644 index 0000000..9638eba --- /dev/null +++ b/.idea/pythonProject.iml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/BotPM.py b/BotPM.py new file mode 100644 index 0000000..dfa55fa --- /dev/null +++ b/BotPM.py @@ -0,0 +1,676 @@ +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 +import gspread +from oauth2client.service_account import ServiceAccountCredentials +import re +from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton, WebAppInfo +import logging +from aiogram.types import ReplyKeyboardRemove + + +TOKEN = '7907319434:AAEEM55xbWHhp5uPAlJ5AS2vNoleES_z_Kk' +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 = {} + + +# Авторизация и доступ к таблице +scope = ["https://spreadsheets.google.com/feeds", "https://www.googleapis.com/auth/drive"] +credentials = ServiceAccountCredentials.from_json_keyfile_name("botforclinic-436512-0c117dd103a8.json", scope) +client = gspread.authorize(credentials) +sheet = client.open("Пациенты клиники").sheet1 # Открытие таблицы, используйте название вашей таблицы + + +# Словарь для хранения данных о сообщениях пользователей +user_messages = {} + +# История состояний для каждого пользователя +user_states = {} + + + + +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() + + + +# Создаем состояния +class QuestionForm(StatesGroup): + waiting_for_question = State() + + +from aiogram import types + + + + + + + + + +# Настройка логирования +logging.basicConfig(level=logging.INFO) + +# Главное меню +main_menu = InlineKeyboardMarkup(row_width=2).add( + InlineKeyboardButton("🌍 Контакты", callback_data="menu_contacts"), + InlineKeyboardButton("📞 Связь", callback_data="menu_contact") +) + +# Подменю "контакты" +contacts_menu = InlineKeyboardMarkup(row_width=1).add( + InlineKeyboardButton("▶️ Назад", callback_data="main_menu") +) + + +# Меню связь +contact_menu = InlineKeyboardMarkup(row_width=1).add( + InlineKeyboardButton("💬 Отправить сообщение администратору Клиники", callback_data="contact_administrator"), + InlineKeyboardButton("🛎 Заказать звонок от администратора Клиники", callback_data="order_call"), + InlineKeyboardButton("▶️ Назад", callback_data="main_menu"), +) + + +administrator_contact = InlineKeyboardMarkup(row_width=1).add( + InlineKeyboardButton("✍🏼 Написать сообщение", callback_data="message_admin"), + InlineKeyboardButton("▶️ Назад", callback_data="menu_contact"), + InlineKeyboardButton("🔘 Главное меню", callback_data="main_menu") +) + +message_ad = InlineKeyboardMarkup(row_width=1).add( + InlineKeyboardButton("▶️ Назад", callback_data="contact_administrator"), + InlineKeyboardButton("🔘 Главное меню", callback_data="main_menu") +) + + +call_order = InlineKeyboardMarkup(row_width=1).add( +InlineKeyboardButton("📞 Позвонить мне", callback_data="call_me"), + InlineKeyboardButton("▶️ Назад", callback_data="menu_contact"), + InlineKeyboardButton("🔘 Главное меню", callback_data="main_menu") +) + +return_call_me = InlineKeyboardMarkup(row_width=1).add( + InlineKeyboardButton("▶️ Назад", callback_data="order_call"), + InlineKeyboardButton("🔘 Главное меню", callback_data="main_menu") +) + +whatsapp = InlineKeyboardMarkup(row_width=1).add( + InlineKeyboardButton("🔘 Главное меню", callback_data="main_menu") +) + + +# Обработка нажатий на инлайн-кнопки +@dp.callback_query_handler(lambda c: c.data.startswith("menu_") or c.data == "main_menu") +async def handle_main_menu(call: types.CallbackQuery): + if call.data == "main_menu": + await call.message.edit_text("В настоящее время я, как Ваш виртуальный помощник, активно развиваюсь." + " В ближайшее время у меня появятся новые функции и возможности." + " А пока Вы можете ознакомиться с текущим меню.", reply_markup=main_menu) + elif call.data == "menu_contacts": + await call.message.edit_text("Клиники им. проф. Е.Н.Оленевой\n\n" + "Клиника УХО•ГОРЛО•НОС\n" + "Записаться на приём, задать вопрос:\n" + "📞 +7 (342) 207-03-03\n\n" + "Больше информации о клинике и врачах на нашем 🔗САЙТЕ\n" + "📍г. Пермь, ул. К. Цеткин, 9\n" + "(ост. Строительный факультет)\n" + "Построить маршрут\n\n" + "--------------\n\n" + "Клиника лечения КАШЛЯ•АЛЛЕРГИИ\n" + "Записаться на приём, задать вопрос:\n" + "📞 +7 (342) 200-02-03\n\n" + "Больше информации о клинике и врачах на нашем 🔗САЙТЕ\n\n" + "📍г. Пермь, ул. Пермь, ул. Г. Звезда, 31А\n" + "(ост. Г. Звезда)\n" + "Построить маршрут\n\n" + "--------------\n\n" + "Центр ДИАГНОСТИКИ И РЕАБИЛИТАЦИИ \n" + "📞 +7 (342) 287-16-94\n\n" + "Больше информации о клинике и врачах на нашем 🔗САЙТЕ\n\n" + "📍 г. Пермь, ул. Пермь, ул. Г. Звезда, 31А\n" + " (ост. Г. Звезда)\n" + "Построить маршрут\n\n" + "Присоединяйтесь к нашему каналу новостей в Telegram.", reply_markup=contacts_menu, parse_mode="HTML") + elif call.data == "menu_contact": + await call.message.edit_text("Выберите способ связи", reply_markup=contact_menu) + + +# Обработка нажатия на "Запись на исследование" +@dp.callback_query_handler(lambda c: c.data == "contact_administrator") +async def handle_call_menu(call: types.CallbackQuery): + await call.message.edit_text("💬 Для отправки сообщения администратору Клиники нажмите кнопку ниже 'Написать сообщение'.", reply_markup=administrator_contact) + +# Обработка нажатия на "Запись на исследование" +@dp.callback_query_handler(lambda c: c.data == "order_call") +async def handle_admin_call_menu(call: types.CallbackQuery): + await call.message.edit_text("Для получения обратного звонка от администратора Клиники нажмите кнопку ниже 'Позвонить мне'.", reply_markup=call_order) + + + +@dp.callback_query_handler(lambda c: c.data == "call_me") +async def handle_ad_call_menu(call: types.CallbackQuery): + try: + user_id = call.from_user.id # ID пользователя + records = sheet.get_all_records() + + # Получаем данные пользователя из таблицы + user_data = next((entry for entry in records if str(entry['Telegram ID']) == str(user_id)), None) + if not user_data: + await call.message.answer("Ваши данные не найдены.", reply_markup=return_call_me) + return + + phone_number = user_data['Номер телефона'] + text = "Позвонить мне" + message_id = call.message.message_id + date = call.message.date.isoformat() # Конвертация даты + reply_to_message_id = call.message.reply_to_message.message_id if call.message.reply_to_message else None + + # Передаём данные на сервер + await send_message_server(phone_number, text, message_id, user_id, date, reply_to_message_id) + + await call.message.edit_text( + "Администратор Клиники свяжется с Вами в ближайшее время в рабочие часы и проконсультирует по всем вопросам.", + reply_markup=return_call_me + ) + except Exception as e: + logging.error(f"Ошибка при обработке запроса: {e}") + await call.message.edit_text("Произошла ошибка. Попробуйте снова позже.", reply_markup=return_call_me) + + +# Обработчик кнопки "message_admin" +@dp.callback_query_handler(lambda c: c.data == "message_admin") +async def handle_ad_message(call: types.CallbackQuery, state: FSMContext): + user_id = str(call.from_user.id) # Преобразуем в строку для сравнения + + try: + # Получение всех записей из таблицы + records = sheet.get_all_records() + + # Поиск пользователя по Telegram ID + user_data = next((entry for entry in records if str(entry['Telegram ID']) == user_id), None) + + if not user_data: + await call.message.answer("Ваши данные не найдены.", reply_markup=message_ad) + return + + # Переход в состояние ожидания вопроса + prompt_message = await call.message.edit_text( + "Пожалуйста, отправьте Ваш вопрос администратору одним сообщением.", + reply_markup=message_ad + ) + + # Сохраняем ID сообщения + async with state.proxy() as data: + data["prompt_message_id"] = prompt_message.message_id + + await QuestionForm.waiting_for_question.set() # Устанавливаем состояние ожидания= + + except Exception as e: + logging.error(f"Ошибка при доступе к таблице: {e}") + await call.message.edit_text("Произошла ошибка. Попробуйте снова позже.", reply_markup=message_ad) + + +# Обработчик ввода вопроса +@dp.message_handler(state=QuestionForm.waiting_for_question, content_types=types.ContentTypes.TEXT) +async def handle_user_question(message: types.Message, state: FSMContext): + user_id = str(message.from_user.id) # ID пользователя + text = message.text # Сообщение пользователя + + try: + # Удаление предыдущего сообщения + async with state.proxy() as data: + if "prompt_message_id" in data: + await bot.delete_message(chat_id=message.chat.id, message_id=data["prompt_message_id"]) + + # Отправка сообщения пользователя на сервер + await send_message_server2(user_id, text, message.message_id, user_id, message.date.isoformat(), None) + + # Ответ пользователю + await message.answer( + "Ваше сообщение успешно отправлено! Администратор Клиники ответит Вам в ближайшее время в рабочие часы. Спасибо за Ваше обращение!", + reply_markup=message_ad + ) + except Exception as e: + logging.error(f"Ошибка при обработке вопроса: {e}") + await message.answer( + "Произошла ошибка при отправке вопроса. Попробуйте позже.", + reply_markup=message_ad + ) + + # Завершаем состояние + await state.finish() + + + + + + +# Хранилище для уже обработанных пользователей +processed_users = set() + +# Обработка нажатия на кнопку "Проверить данные" +@dp.callback_query_handler(lambda c: c.data == 'check_verification') +async def process_check_verification(callback_query: types.CallbackQuery, state: FSMContext): + user_id = callback_query.from_user.id + try: + # Чтение всех строк таблицы + records = sheet.get_all_records() + user_data_verified = False + + for row in records: + fio = str(row.get("ФИО", "")).strip() + phone = str(row.get("Номер телефона", "")).strip() + telegram_id = str(row.get("Telegram ID", "")).strip() + + # Проверяем, если в таблице есть данные для этого пользователя + if telegram_id == str(user_id): + user_data_verified = True + break + + if user_data_verified: + await send_success_message(user_id) # Отправляем сообщение о успешной регистрации + else: + await bot.send_message( + user_id, + "Мы не нашли ваших данных в системе. Пожалуйста, проверьте, что вы правильно заполнили форму и попробуйте снова.", + reply_markup=InlineKeyboardMarkup().add( + InlineKeyboardButton("Попробовать снова", callback_data="check_verification") + ) + ) + except Exception as e: + print(f"Ошибка при проверке верификации: {e}") + await bot.send_message(user_id, "Произошла ошибка при проверке данных. Попробуйте позже.") + + + + +# Функция отправки сообщения об успешной регистрации +async def send_success_message(user_id): + try: + await bot.send_message( + chat_id=user_id, + text=("Ура! Ваша регистрация прошла успешно! 🥳\n\n" + "Теперь все уведомления о записи на приём будут приходить сюда, в чат-бот. " + "Если Вы также получаете рассылку в WhatsApp, то сообщения будут дублироваться. " + "Для получения рассылки только в чат-бот Telegram, нажмите кнопку ниже 'Не дублировать сообщения в WhatsApp'."), + reply_markup=InlineKeyboardMarkup().add( + InlineKeyboardButton("Не дублировать сообщения в WhatsApp", callback_data="stop_replying"), + InlineKeyboardButton("🔘 Главное меню", callback_data="main_menu") + ) + ) + except Exception as e: + print(f"Ошибка при отправке сообщения пользователю {user_id}: {e}") + + + +@dp.callback_query_handler(lambda c: c.data == "stop_replying") +async def stop_replying_handler(call: types.CallbackQuery): + user_id = str(call.from_user.id) # Преобразуем в строку для сравнения + + try: + # Получение всех записей из таблицы + records = sheet.get_all_records() + + # Поиск пользователя по Telegram ID + user_data = next((entry for entry in records if str(entry['Telegram ID']) == user_id), None) + + if not user_data: + await call.message.answer("Ваши данные не найдены.", reply_markup=whatsapp) + return + + phone_number = user_data['Номер телефона'] # Измените на название вашего столбца + text = "Отключить дублирование в WhatsApp" + message_id = call.message.message_id + date = call.message.date.isoformat() + reply_to_message_id = call.message.reply_to_message.message_id if call.message.reply_to_message else None + + # Отправка данных на сервер + await send_message_server(phone_number, text, message_id, call.from_user.id, date, reply_to_message_id) + + # Ответ пользователю + await call.message.edit_text("Рассылка уведомлений в WhatsApp отключена.", reply_markup=whatsapp) + + except Exception as e: + logging.error(f"Ошибка при доступе к таблице: {e}") + await call.message.edit_text("Произошла ошибка. Попробуйте снова позже.", reply_markup=whatsapp) + + + + + + +@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'], chat_type=types.ChatType.PRIVATE) +async def handle_registration(message: types.Message): + user_id = message.from_user.id + sent_message = await bot.send_message(user_id, "Вы уже являетесь пациентом нашей Клиники?\nЕсли Вы хотите начать общение с ботом заново, нажмите /start.", + reply_markup=yes_no_markup()) + last_bot_message_id[user_id] = sent_message.message_id + await Form.existing_patient.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 + + +def generate_back_button(): + """Создает клавиатуру с кнопкой 'Назад'.""" + markup = ReplyKeyboardMarkup(row_width=1, resize_keyboard=True) + back_button = KeyboardButton("Назад") # Текст кнопки "Назад" + markup.add(back_button) + return markup + +@dp.message_handler(state=Form.existing_patient) +async def handle_existing_patient(message: types.Message, state: FSMContext): + user_id = message.from_user.id + form_url = f"https://tgbotpolimed.pirogov.ai/?user_id={user_id}" + + if not message.text.strip(): + await message.answer( + "Пожалуйста, выберите 'Да' или 'Нет' с помощью кнопок.", + reply_markup=ReplyKeyboardRemove() + ) + return + + if message.text.lower() == "да": + await message.answer( + "В соответствии с Федеральным законом № 152-ФЗ «О персональных данных», для идентификации Вас как пациента нашей Клиники, просим заполнить форму, нажав на кнопку ниже.", + reply_markup=ReplyKeyboardRemove() + ) + await message.answer( + "Ввод персональных данных", + reply_markup=InlineKeyboardMarkup().add( + InlineKeyboardButton( + text="Заполнить форму", + web_app=WebAppInfo(url=form_url) + ) + ) + ) + + # Отправляем кнопку для проверки данных + await message.answer( + "После того как Вы заполните форму, нажмите на кнопку ниже для проверки данных.\n" + "Если Вы хотите начать общение с ботом заново, нажмите /start.", + reply_markup=InlineKeyboardMarkup().add( + InlineKeyboardButton( + text="Проверить данные", + callback_data="check_verification" + ) + ) + ) + await state.finish() + + elif message.text.lower() == "нет": + await bot.send_message( + user_id, + "Полный доступ к функциям сервиса предоставляется только пациентам нашей Клиники.\n\n" + "Вы можете связаться с нами по тел.: +7 (342) 207-03-03 или посетить Клинику лично для заключения договора по следующим адресам:\n" + "г. Пермь, ул. Клары Цеткин, д. 9; ул. Газеты Звезда, д. 31-а.\n\n" + "Будьте здоровы!\n" + "Если Вы хотите начать общение с ботом заново, нажмите /start.", + reply_markup=generate_back_button() # Клавиатура с кнопкой "Назад" + ) + await state.finish() + + else: + await bot.send_message( + user_id, + "Пожалуйста, выберите 'Да' или 'Нет' с помощью кнопок.", + reply_markup=ReplyKeyboardRemove() + ) + await state.finish() + +# Обработчик кнопки "Назад" +@dp.message_handler(lambda message: message.text == "Назад") +async def handle_back_button(message: types.Message): + await handle_registration(message) # Вызываем функцию обработки команды /registration + + + + + +def find_patients_by_id(telegram_id): + records = sheet.get_all_records() # Получаем все строки таблицы + patients = [] + for record in records: + if str(record["Telegram ID"]) == str(telegram_id): + patients.append(record) + return patients + +async def prompt_patient_selection(user_id, patient_records): + # Создаем кнопки с ФИО пациентов + markup = ReplyKeyboardMarkup(row_width=1, resize_keyboard=True) + for record in patient_records: + markup.add(KeyboardButton(record["ФИО"])) + + # Сохраняем данные пациентов временно + user_data[user_id]["patients"] = patient_records + + await bot.send_message( + user_id, + "Найдено несколько записей с вашим Telegram ID. Пожалуйста, выберите пациента:", + reply_markup=markup, + ) + await Form.fio.set() + + +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]) + + + +async def send_message_to_server(message_data): + url = "http://192.168.1.10:8080/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}") + + + +# Функция для выполнения POST-запроса и получения списка врачей +def get_doctors(): + url = "http://192.168.1.10:8080/AppZaprSpecDoc" + # Данные для отправки в запросе + data = {"spec_id": 1} + + # Выполняем POST-запрос + response = requests.post(url, json=data) + + # Проверяем статус ответа + if response.status_code == 200: + # Если запрос успешен, возвращаем данные + return response.json() + else: + # Если запрос не удался, выводим ошибку + print(f"Ошибка: {response.status_code}") + return [] + + +def yes_no_markup(): + markup = types.ReplyKeyboardMarkup(row_width=2, resize_keyboard=True) + item_no = types.KeyboardButton("Нет") + item_yes = 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 + + +async def send_message_server(phone_number, text, message_id, user_id, date, reply_to_message_id=None): + url = "http://192.168.1.10:8080/AppSaveMessage" + headers = {"Content-Type": "application/json"} + + message_data = { + "message_id": message_id, + "text": text, + "date": date, + "user_id": user_id, # Передача ID пользователя + "reply_to_message_id": reply_to_message_id, # Если нужно указать reply_to_message_id + "phone_number": phone_number + } + + async with aiohttp.ClientSession() as session: + async with session.post(url, json=message_data, headers=headers) as response: + if response.status == 200: + print(message_data) + logging.info("Сообщение успешно отправлено на сервер") + else: + logging.error(f"Ошибка при отправке сообщения: {response.status}") + + +async def send_message_server2(user_id, text, message_id, from_user_id, date, reply_to_message_id): + url = "http://192.168.1.10:8080/AppSaveMessage" + headers = {"Content-Type": "application/json"} + + message_data = { + "user_id": user_id, + "text": text, + "message_id": message_id, + "from_user_id": from_user_id, + "date": date, + "reply_to_message_id": reply_to_message_id, + } + + async with aiohttp.ClientSession() as session: + async with session.post(url, json=message_data, headers=headers) as response: + if response.status == 200: + logging.info("Сообщение успешно отправлено на сервер") + else: + logging.error(f"Ошибка при отправке сообщения: {response.status}") + + + + + +def find_patient_by_id(telegram_id): + records = sheet.get_all_records() # Получаем все строки таблицы + for record in records: + if str(record["Telegram ID"]) == str(telegram_id): # Сравнение с Telegram ID + phone_raw = record["Номер телефона"] + # Удаляем все нецифровые символы + phone_formatted = re.sub(r"\D", "", phone_raw) + + # Проверка на правильную длину номера и корректировка, если необходимо + if len(phone_formatted) == 11: + if phone_formatted.startswith("8"): # Если номер начинается с 8, заменяем на 7 + phone_formatted = "7" + phone_formatted[1:] + return phone_formatted + else: + return None # Возвращаем None, если номер неправильной длины + return None + + + + +def authorize_google(): + # google_json = {} + # for key in config["GOOGLE"].keys(): + # google_json[key] = config["GOOGLE"][key] + scope = ["https://spreadsheets.google.com/feeds", "https://www.googleapis.com/auth/drive"] + creds = ServiceAccountCredentials.from_json_keyfile_name("botforclinic-436512-0c117dd103a8.json", scope) + # creds = ServiceAccountCredentials.from_json_keyfile_dict(google_json, scope) + client = gspread.authorize(creds) + return client + +@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) \ No newline at end of file diff --git a/PM.py b/PM.py new file mode 100644 index 0000000..3633e7b --- /dev/null +++ b/PM.py @@ -0,0 +1,564 @@ +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 +import gspread +from oauth2client.service_account import ServiceAccountCredentials +import re +from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton, WebAppInfo +import logging +from aiogram.types import ReplyKeyboardRemove + + +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 = {} + + +# Авторизация и доступ к таблице +scope = ["https://spreadsheets.google.com/feeds", "https://www.googleapis.com/auth/drive"] +credentials = ServiceAccountCredentials.from_json_keyfile_name("botforclinic-436512-0c117dd103a8.json", scope) +client = gspread.authorize(credentials) +sheet = client.open("Пациенты клиники").sheet1 # Открытие таблицы, используйте название вашей таблицы + + +# Словарь для хранения данных о сообщениях пользователей +user_messages = {} + +# История состояний для каждого пользователя +user_states = {} + + + + +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() + + + + + + +from aiogram import types + + + +# Настройка логирования +logging.basicConfig(level=logging.INFO) + +# Главное меню +main_menu = InlineKeyboardMarkup(row_width=2).add( + InlineKeyboardButton("📝 Запись", callback_data="menu_record"), + InlineKeyboardButton("🧰 Услуги", callback_data="menu_services"), + InlineKeyboardButton("⭐️ Специалисты", callback_data="menu_specialists"), + InlineKeyboardButton("🌍 Контакты", callback_data="menu_contacts"), + InlineKeyboardButton("📞 Связь", callback_data="menu_contact") +) + +# Подменю "Запись" +record_menu = InlineKeyboardMarkup(row_width=1).add( + InlineKeyboardButton("Запись на приём", callback_data="record_appointment"), + InlineKeyboardButton("Запись на исследование", callback_data="record_research"), + InlineKeyboardButton("Запись на терапию", callback_data="record_therapy"), + InlineKeyboardButton("Назад", callback_data="main_menu") +) + + +# Меню исследований +research_menu = InlineKeyboardMarkup(row_width=1).add( + InlineKeyboardButton("УЗИ", callback_data="research_uzi"), + InlineKeyboardButton("КТ", callback_data="research_kt"), + InlineKeyboardButton("ЭКГ", callback_data="research_ekg"), + InlineKeyboardButton("КСП (скарификационные пробы)", callback_data="research_ksp"), + InlineKeyboardButton("Назад", callback_data="menu_record"), + InlineKeyboardButton("Главное меню", callback_data="main_menu") +) + +# Меню терапии +therapy_menu = InlineKeyboardMarkup(row_width=1).add( + InlineKeyboardButton("Слухопротезирование", callback_data="therapy_hearing"), + InlineKeyboardButton("АСИТ-терапия", callback_data="therapy_asit"), + InlineKeyboardButton("ФДТ (фотодинамическая терапия)", callback_data="therapy_fdt"), + InlineKeyboardButton("Галотерапия (соляная комната)", callback_data="therapy_halo"), + InlineKeyboardButton("Назад", callback_data="menu_record"), + InlineKeyboardButton("Главное меню", callback_data="main_menu") +) + + +# Обработка нажатий на инлайн-кнопки +@dp.callback_query_handler(lambda c: c.data.startswith("menu_") or c.data == "main_menu") +async def handle_main_menu(call: types.CallbackQuery): + if call.data == "main_menu": + await call.message.edit_text("Главное меню:", reply_markup=main_menu) + elif call.data == "menu_record": + await call.message.edit_text("Выберите тип записи:", reply_markup=record_menu) + +# Обработка нажатия на "Запись на исследование" +@dp.callback_query_handler(lambda c: c.data == "record_research") +async def handle_research_menu(call: types.CallbackQuery): + await call.message.edit_text("Выберите тип исследования:", reply_markup=research_menu) + +# Обработка нажатия на "Запись на терапию" +@dp.callback_query_handler(lambda c: c.data == "record_therapy") +async def handle_therapy_menu(call: types.CallbackQuery): + await call.message.edit_text("Выберите тип терапии:", reply_markup=therapy_menu) + + + +# Обработка нажатий на инлайн-кнопки +@dp.callback_query_handler(lambda c: c.data.startswith("menu_") or c.data == "main_menu") +async def handle_main_menu(call: types.CallbackQuery): + if call.data == "main_menu": + await call.message.edit_text("Главное меню:", reply_markup=main_menu) + elif call.data == "menu_record": + await call.message.edit_text("Выберите тип записи:", reply_markup=record_menu) + +# Обработка нажатия на "Запись на приём" +@dp.callback_query_handler(lambda c: c.data == "record_appointment") +async def show_specialties(call: types.CallbackQuery): + spec_url = "http://46.146.229.242:1980/AppZaprSpec" + try: + response = requests.post(spec_url) + logging.info(f"Ответ от сервера специальностей: {response.text}") + + if response.status_code == 200: + specialties = response.json() + specialties_menu = InlineKeyboardMarkup(row_width=1) + + for spec in specialties: + if 'MSP_ID' in spec and 'MSP_NAME' in spec: + specialties_menu.add( + InlineKeyboardButton( + spec['MSP_NAME'], callback_data=f"spec_{spec['MSP_ID']}" + ) + ) + + specialties_menu.add( + InlineKeyboardButton("Назад", callback_data="menu_record"), + InlineKeyboardButton("Главное меню", callback_data="main_menu") + ) + await call.message.edit_text("Выберите специальность:", reply_markup=specialties_menu) + else: + await call.message.answer(f"Ошибка сервера. Код ответа: {response.status_code}") + except Exception as e: + logging.error(f"Ошибка получения специальностей: {e}") + await call.message.answer("Произошла ошибка при получении специальностей.") + +# Обработка выбора специальности +@dp.callback_query_handler(lambda c: c.data.startswith("spec_")) +async def show_doctors(call: types.CallbackQuery): + spec_id = call.data.split('_')[1] + doc_url = "http://46.146.229.242:1980/AppZaprSpecDoc" + + try: + doc_response = requests.post(doc_url, json={"spec_id": int(spec_id)}) + logging.info(f"Ответ от сервера врачей: {doc_response.text}") + + if doc_response.status_code == 200: + doctors = doc_response.json() + if not doctors: + await call.message.answer("Врачи по этой специальности не найдены.") + return + + doctors_menu = InlineKeyboardMarkup(row_width=1) + + for doc in doctors: + if 'DOC_FIO' in doc and 'DOC_ID' in doc: + doctors_menu.add( + InlineKeyboardButton( + f"{doc['DOC_FIO']}", callback_data=f"doc_{doc['DOC_ID']}" + ) + ) + + doctors_menu.add( + InlineKeyboardButton("Назад", callback_data="record_appointment"), + InlineKeyboardButton("Главное меню", callback_data="main_menu") + ) + await call.message.edit_text("Выберите врача:", reply_markup=doctors_menu) + else: + await call.message.answer(f"Ошибка сервера. Код ответа: {doc_response.status_code}") + except Exception as e: + logging.error(f"Ошибка получения врачей: {e}") + await call.message.answer("Произошла ошибка при получении списка врачей.") + + +@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=main_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'], chat_type=types.ChatType.PRIVATE) +async def handle_registration(message: types.Message): + user_id = message.from_user.id + sent_message = await bot.send_message(user_id, "Вы уже являетесь пациентом нашей Клиники?\nЕсли Вы хотите начать общение с ботом заново, нажмите /start.", + reply_markup=yes_no_markup()) + last_bot_message_id[user_id] = sent_message.message_id + await Form.existing_patient.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(state=Form.existing_patient) +async def handle_existing_patient(message: types.Message, state: FSMContext): + user_id = message.from_user.id + form_url = f"https://tgbotpolimed.pirogov.ai/?user_id={user_id}" + + if message.text.lower() == "да": + # Удаляем кнопки и отправляем ссылку на форму + await message.answer( + "В соответствии с Федеральным законом № 152-ФЗ «О персональных данных», для идентификации Вас как пациента нашей Клиники, просим заполнить форму, нажав на кнопку ниже.", + reply_markup=ReplyKeyboardRemove() + ) + await message.answer( + "Заполнить форму:", + reply_markup=InlineKeyboardMarkup().add( + InlineKeyboardButton( + text="Заполнить форму", + web_app=WebAppInfo(url=form_url) + ) + ) + ) + + elif message.text.lower() == "нет": + await bot.send_message( + user_id, + "Полный доступ к функциям сервиса доступен только пациентам нашей Клиники.\n" + "Вы можете связаться с нами по тел.+7 (342) 207-03-03 или посетить Клинику лично по адресам:\n" + "г. Пермь, ул. Клары Цеткин, д. 9; ул. Газеты Звезда, д. 31- а.\n\n" + "Будьте здоровы!", + reply_markup=ReplyKeyboardRemove() + ) + await state.finish() + + else: + await bot.send_message( + user_id, + "Пожалуйста, выберите 'Да' или 'Нет' с помощью кнопок.", + reply_markup=ReplyKeyboardRemove() + ) + + +@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() + expected_code = user_data.get(user_id, {}).get("verification_code") + + if expected_code and str(code_entered) == str(expected_code): + await bot.send_message(user_id, "Верификация прошла успешно! Пожалуйста, подождите...") + # Поиск данных пациента по Telegram ID + patient_records = find_patients_by_id(user_id) + + if len(patient_records) == 0: + await bot.send_message(user_id, "Пациенты с данным Telegram ID не найдены в базе данных.") + await state.finish() + elif len(patient_records) == 1: + # Если только одна запись, сразу берём данные + await process_patient_data(user_id, patient_records[0], state) + else: + # Если несколько записей, предлагаем выбрать пациента + await prompt_patient_selection(user_id, patient_records) + else: + await bot.send_message(user_id, "Неверный код. Попробуйте снова.") + +def find_patients_by_id(telegram_id): + records = sheet.get_all_records() # Получаем все строки таблицы + patients = [] + for record in records: + if str(record["Telegram ID"]) == str(telegram_id): + patients.append(record) + return patients + +async def prompt_patient_selection(user_id, patient_records): + # Создаем кнопки с ФИО пациентов + markup = ReplyKeyboardMarkup(row_width=1, resize_keyboard=True) + for record in patient_records: + markup.add(KeyboardButton(record["ФИО"])) + + # Сохраняем данные пациентов временно + user_data[user_id]["patients"] = patient_records + + await bot.send_message( + user_id, + "Найдено несколько записей с вашим Telegram ID. Пожалуйста, выберите пациента:", + reply_markup=markup, + ) + await Form.fio.set() + +@dp.message_handler(state=Form.fio) +async def handle_patient_selection(message: types.Message, state: FSMContext): + user_id = message.from_user.id + selected_fio = message.text.strip() + + # Поиск выбранного пациента + patients = user_data[user_id].get("patients", []) + selected_patient = next((p for p in patients if p["ФИО"] == selected_fio), None) + + if selected_patient: + await process_patient_data(user_id, selected_patient, state) + else: + await bot.send_message(user_id, "Ошибка: выбранный пациент не найден. Попробуйте ещё раз.") + +async def process_patient_data(user_id, patient_record, state: FSMContext): + # Форматирование данных + fio_parts = patient_record["ФИО"].split()[:3] # Берем первые три слова из ФИО + formatted_phone = find_patient_by_id(user_id) # Используем функцию для получения номера телефона + + if formatted_phone: + # Сохранение в словарь + user_data[user_id] = { + "telegram_id": user_id, + "first_name": fio_parts[0], + "middle_name": fio_parts[1] if len(fio_parts) > 1 else "", + "last_name": fio_parts[2] if len(fio_parts) > 2 else "", + "phone_number": formatted_phone, + "birthday": patient_record["Дата рождения"], + } + + # Отправка на сервер + result = send_registration_request(user_data[user_id]) + + if result == "success": + await bot.send_message(user_id, "Регистрация успешно завершена!") + else: + await bot.send_message(user_id, "Произошла ошибка при регистрации. Пожалуйста, попробуйте позже.") + else: + await bot.send_message(user_id, "Не удалось найти номер телефона для вашего аккаунта.") + + await state.finish() + + +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.get("status") == "OK": + verification_code = json_data.get("code") # Получаем код + if not verification_code: + print("Ошибка: Код отсутствует в ответе API.") + return None + + # Сохраняем код для пользователя + if user_id not in user_data: + user_data[user_id] = {} + user_data[user_id]["verification_code"] = verification_code + + # Логируем код для отладки + print(f"Код верификации, отправленный пользователю {user_id}: {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}") + + + +# Функция для выполнения POST-запроса и получения списка врачей +def get_doctors(): + url = "http://46.146.229.242:1980/AppZaprSpecDoc" + # Данные для отправки в запросе + data = {"spec_id": 1} + + # Выполняем POST-запрос + response = requests.post(url, json=data) + + # Проверяем статус ответа + if response.status_code == 200: + # Если запрос успешен, возвращаем данные + return response.json() + else: + # Если запрос не удался, выводим ошибку + print(f"Ошибка: {response.status_code}") + return [] + + +def yes_no_markup(): + markup = types.ReplyKeyboardMarkup(row_width=2, resize_keyboard=True) + item_no = types.KeyboardButton("Нет") + item_yes = 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 find_patient_by_id(telegram_id): + records = sheet.get_all_records() # Получаем все строки таблицы + for record in records: + if str(record["Telegram ID"]) == str(telegram_id): # Сравнение с Telegram ID + phone_raw = record["Номер телефона"] + # Удаляем все нецифровые символы + phone_formatted = re.sub(r"\D", "", phone_raw) + + # Проверка на правильную длину номера и корректировка, если необходимо + if len(phone_formatted) == 11: + if phone_formatted.startswith("8"): # Если номер начинается с 8, заменяем на 7 + phone_formatted = "7" + phone_formatted[1:] + return phone_formatted + else: + return None # Возвращаем None, если номер неправильной длины + return None + + + + +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) \ No newline at end of file diff --git a/__pycache__/BotPM.cpython-38.pyc b/__pycache__/BotPM.cpython-38.pyc new file mode 100644 index 0000000..aa2ba45 Binary files /dev/null and b/__pycache__/BotPM.cpython-38.pyc differ diff --git a/botforclinic-436512-0c117dd103a8.json b/botforclinic-436512-0c117dd103a8.json new file mode 100644 index 0000000..1ab70e3 --- /dev/null +++ b/botforclinic-436512-0c117dd103a8.json @@ -0,0 +1,13 @@ +{ + "type": "service_account", + "project_id": "botforclinic-436512", + "private_key_id": "0c117dd103a890d20705d9e66bbfde56f9d65a05", + "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC4XOtHBzxPR4lb\nqiX8grd2XBfBxXZLgLKTkz4WRcncgBpACXKms5AtKF707uKCvgUD8SwTpzvfY3oz\nvzLQs0uZoM9RALw5ui9dlimdoYQGsuH5LAUX68w0oPyour36XeBqacxNoEeO5C2F\nbb4+ql4gC2qJT86aBt2kwKpTxnTPZxvYoKZ0TwsmN8gj9vNckONbSSZteMKpQA50\nRqpoLM0EpsB64HRSiu8mH+bkdLK9ZMEZGmOG7pNDijctGkgAy9rK9vurH4PRgIMt\n7j+q/EeBQDuZX2SSVIaMkiFkDhHVGd84CFzcodBIYOSiCDer7aIcv8SrcYGZ0QJD\nnIzTqZMrAgMBAAECggEAW3HHR2dI3D/s2xkVl15U1nHOXM/vIXsX2EgH2y9JdUPb\nAVlOU24sPKHSG6YjltrejPqCNMtV0LM8SU90Sn0sKerP+esl8XIujTpusN+Mp2/x\n0tApRJiyJIaXW6+ojHck2VNZwUUXSUJXa9+npdiGMFnJQYtivBZcuJvRwBTnGnm/\ntuwQUcQREPy8IaaX5j+xPf390KeXqNOopULW7FtItkHthM18fr6706X1GQ77ua23\nzz1DT2PfIxOu2e3uPJ1O1CsQ8UiTIAm3J0nNgbpau1nP2+ea62vCrjmuqcyn5dfb\nhpgGD7Qe8uRvU+EICr67sOW47ikjAqkM38lZFgufuQKBgQDmypfFTYke7oDTZ8GE\nZFHZKn+ri5s94pDzjeeb8HxmeEC85cA6+jOr6f1QncwHON+tD2FRO7HHp/yVVyZY\nU2RSxaLaFleRL4CwlQkiMoqynLFWbqQthqdeJx2onNyGoO8uBDqfMJVBhOjwb8jI\n3SZt1Z6BJ076CMMOiLI7moZsWQKBgQDMgBdWND+uTR0SHXWqF1hj/+UgwHBqQKio\nyWbnIO28uFyMscfBAgh7JJbqcJIh6A+M9NdD4TveqZWoYBaUHkMBg5VGcmWrCH+L\nJOlAVJmhy4GgpE2nkYE0ZgDd0qlViYeTOKaLSKchPrLxRKNI9eeWkKqrk/a7wBHh\nsGJbt8p7IwKBgQCvFYaqAbZCpwFIX/ApNcn6DAmq5FAzVIxOmJrabEiTnCrQoyOA\nGovUocCwxeUgnX7i1UYo0DaAlupBiUnnu+vh91kiRczMsdLZI1c4gEtEUScfwPQA\nLaUPAnG3lrid0b1hlYe7eKnieKgWr1cNOuiKboK+zElX2gnQHtfH6+SKkQKBgDYW\nsxVz4FwDvWqrLBH+9rwMVNgizhjsXS+3hWYgiYDe6mu0IfdkyEV52gjMGXqqXGKV\n59HmYuVzyUetkos+rc5atULawxVHvCRbcO448iGfJ/wLORbXH2tyh0wkifE73QYN\nd89jOgFLCh1SYDXOBKEIRnv3OM1T8ebVtk44AHAtAoGAfOprlkWEDyVnfHQjGxxx\nTrxhEAjw3+ikM+wQJj7vumnpg91eAFNcwRUa/ykbVOmj6z/fBnStAbsG7mMQwa1M\nyIVPTvUogrsTHvf9GaG0IaAVJn/Su2DVNqQeL/ZpDmu2+wC959g8z665BKLzm3S8\nFc0eV1a7FN4GOpKNvXuDMBc=\n-----END PRIVATE KEY-----\n", + "client_email": "clinic-chats-bot@botforclinic-436512.iam.gserviceaccount.com", + "client_id": "105253150604049743778", + "auth_uri": "https://accounts.google.com/o/oauth2/auth", + "token_uri": "https://oauth2.googleapis.com/token", + "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", + "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/clinic-chats-bot%40botforclinic-436512.iam.gserviceaccount.com", + "universe_domain": "googleapis.com" +} diff --git a/doctors.json b/doctors.json new file mode 100644 index 0000000..f782cb3 --- /dev/null +++ b/doctors.json @@ -0,0 +1,122 @@ +[ + { + "DOC_ID": 228, + "DOC_FIO": "Акутина Алёна Владимировна" + }, + { + "DOC_ID": 50, + "DOC_FIO": "Анфилатов Андрей Викторович" + }, + { + "DOC_ID": 40, + "DOC_FIO": "Верещагина Лидия Владимировна" + }, + { + "DOC_ID": 127, + "DOC_FIO": "Волкова Надежда Геннадьевна" + }, + { + "DOC_ID": 81, + "DOC_FIO": "Ворончихина Наталия Валерьевна" + }, + { + "DOC_ID": 72, + "DOC_FIO": "Гашеева Ирина Валерьевна" + }, + { + "DOC_ID": 121, + "DOC_FIO": "Генеральчук Людмила Владимировна" + }, + { + "DOC_ID": 193, + "DOC_FIO": "Гилязова Лариса Левоновна" + }, + { + "DOC_ID": 91, + "DOC_FIO": "Головач Светлана Вячеславовна" + }, + { + "DOC_ID": 140, + "DOC_FIO": "Давлятшина Олеся Алексеевна" + }, + { + "DOC_ID": 17, + "DOC_FIO": "Долгих Елена Павловна" + }, + { + "DOC_ID": 44, + "DOC_FIO": "Зыкин Олег Владимирович" + }, + { + "DOC_ID": 223, + "DOC_FIO": "Иванова Анастасия Александровна" + }, + { + "DOC_ID": 269, + "DOC_FIO": "Козенкова Юлия Александровна" + }, + { + "DOC_ID": 171, + "DOC_FIO": "Коротаева Владлена Александровна" + }, + { + "DOC_ID": 2, + "DOC_FIO": "Лебединская Елена Александровна" + }, + { + "DOC_ID": 272, + "DOC_FIO": "Лобанова Ирина Юрьевна" + }, + { + "DOC_ID": 5, + "DOC_FIO": "Макарова Людмила Германовна" + }, + { + "DOC_ID": 75, + "DOC_FIO": "Операционная " + }, + { + "DOC_ID": 119, + "DOC_FIO": "Осадчий Антон Павлович" + }, + { + "DOC_ID": 47, + "DOC_FIO": "Семерикова Наталия Александровна" + }, + { + "DOC_ID": 19, + "DOC_FIO": "Синдяев Алексей Викторович" + }, + { + "DOC_ID": 267, + "DOC_FIO": "Суднева Анна Руслановна" + }, + { + "DOC_ID": 41, + "DOC_FIO": "Сушков Михаил Германович" + }, + { + "DOC_ID": 3, + "DOC_FIO": "Терво Светлана Олеговна" + }, + { + "DOC_ID": 4, + "DOC_FIO": "Уткина Наталия Павловна" + }, + { + "DOC_ID": 253, + "DOC_FIO": "Хмелёва Марина Александровна" + }, + { + "DOC_ID": 38, + "DOC_FIO": "Шайдурова Валентина Николаевна" + }, + { + "DOC_ID": 224, + "DOC_FIO": "Шевырина Наталья Григорьевна" + }, + { + "DOC_ID": 139, + "DOC_FIO": "Юрков Владислав Сергеевич" + } +] \ No newline at end of file diff --git a/proba1PM.py b/proba1PM.py new file mode 100644 index 0000000..6d4046f --- /dev/null +++ b/proba1PM.py @@ -0,0 +1,461 @@ +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) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..f4e7570 Binary files /dev/null and b/requirements.txt differ diff --git a/s-blob-v1-IMAGE-tdNCrEv8Ldo.png b/s-blob-v1-IMAGE-tdNCrEv8Ldo.png new file mode 100644 index 0000000..9dcb20f Binary files /dev/null and b/s-blob-v1-IMAGE-tdNCrEv8Ldo.png differ