проект Bot_Polimed
This commit is contained in:
@@ -0,0 +1 @@
|
||||
.venv/
|
||||
Generated
+3
@@ -0,0 +1,3 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<settings>
|
||||
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||
<version value="1.0" />
|
||||
</settings>
|
||||
</component>
|
||||
Generated
+7
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Black">
|
||||
<option name="sdkName" value="Python 3.8 (Bot_for_clinic)" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.8 (Bot_for_clinic)" project-jdk-type="Python SDK" />
|
||||
</project>
|
||||
Generated
+8
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/pythonProject.iml" filepath="$PROJECT_DIR$/.idea/pythonProject.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
Generated
+10
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.venv" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="Python 3.8 (Bot_for_clinic)" jdkType="Python SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -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"
|
||||
"Больше информации о клинике и врачах на нашем <a href='https://perm.oclinica.ru/lor'>🔗САЙТЕ</a>\n"
|
||||
"📍г. Пермь, ул. К. Цеткин, 9\n"
|
||||
"(ост. Строительный факультет)\n"
|
||||
"<a href='https://tinyurl.com/286a8tv7'>Построить маршрут</a>\n\n"
|
||||
"--------------\n\n"
|
||||
"Клиника лечения КАШЛЯ•АЛЛЕРГИИ\n"
|
||||
"Записаться на приём, задать вопрос:\n"
|
||||
"📞 +7 (342) 200-02-03\n\n"
|
||||
"Больше информации о клинике и врачах на нашем <a href='https://perm.oclinica.ru/allergo'>🔗САЙТЕ</a>\n\n"
|
||||
"📍г. Пермь, ул. Пермь, ул. Г. Звезда, 31А\n"
|
||||
"(ост. Г. Звезда)\n"
|
||||
"<a href='https://tinyurl.com/9a9w5pdu'>Построить маршрут</a>\n\n"
|
||||
"--------------\n\n"
|
||||
"Центр ДИАГНОСТИКИ И РЕАБИЛИТАЦИИ \n"
|
||||
"📞 +7 (342) 287-16-94\n\n"
|
||||
"Больше информации о клинике и врачах на нашем <a href='https://cdr.oclinica.ru/'>🔗САЙТЕ</a>\n\n"
|
||||
"📍 г. Пермь, ул. Пермь, ул. Г. Звезда, 31А\n"
|
||||
" (ост. Г. Звезда)\n"
|
||||
"<a href='https://tinyurl.com/9a9w5pdu'>Построить маршрут</a>\n\n"
|
||||
"Присоединяйтесь к нашему каналу новостей в <a href='https://t.me/permlor'>Telegram</a>.", 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)
|
||||
@@ -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)
|
||||
Binary file not shown.
@@ -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"
|
||||
}
|
||||
+122
@@ -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": "Юрков Владислав Сергеевич"
|
||||
}
|
||||
]
|
||||
+461
@@ -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)
|
||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 246 KiB |
Reference in New Issue
Block a user