from aiogram import Bot, Dispatcher, types from aiogram.filters import Command, StateFilter from aiogram.fsm.state import State, StatesGroup from aiogram.fsm.context import FSMContext from aiogram.fsm.storage.memory import MemoryStorage from aiogram.types import KeyboardButton, ReplyKeyboardMarkup, ReplyKeyboardRemove import psycopg2 import psycopg2.extras from datetime import datetime import os from aiogram.types import FSInputFile TOKEN = "ВАШ_TOKEN" bot = Bot(token=TOKEN) dp = Dispatcher(storage=MemoryStorage()) # ===== FSM ===== class Form(StatesGroup): consent = State() fio = State() dob = State() phone = State() city = State() klimov = State() @dp.message(Command("start")) async def start(message: types.Message, state: FSMContext): kb = [[KeyboardButton("✅ Да, согласен"), KeyboardButton("❌ Нет")]] keyboard = ReplyKeyboardMarkup(keyboard=kb, resize_keyboard=True) await message.answer( "Привет! Сначала нужно согласие на обработку персональных данных. Согласны?", reply_markup=keyboard ) await state.set_state(Form.consent) @dp.message(Form.consent) async def consent(message: types.Message, state: FSMContext): if message.text.startswith("✅"): await state.set_state(Form.fio) await message.answer("Введите своё ФИО:", reply_markup=ReplyKeyboardRemove()) else: await message.answer("Без согласия мы не можем продолжить 🙏", reply_markup=ReplyKeyboardRemove()) await state.clear() @dp.message(Form.fio) async def fio(message: types.Message, state: FSMContext): await state.update_data(fio=message.text) await state.set_state(Form.dob) await message.answer("Введите дату рождения (ДД.MM.ГГГГ):") @dp.message(Form.dob) async def dob(message: types.Message, state: FSMContext): await state.update_data(dob=message.text) await state.set_state(Form.phone) await message.answer("Введите номер телефона:") @dp.message(Form.phone) async def phone(message: types.Message, state: FSMContext): await state.update_data(phone=message.text) await state.set_state(Form.city) await message.answer("Из какого ты города?") @dp.message(Form.city) async def city(message: types.Message, state: FSMContext): await state.update_data(city=message.text) data = await state.get_data() # Сохраняем в БД try: dob_parsed = datetime.strptime(data["dob"], "%d.%m.%Y").date() except ValueError: await message.answer("Неверный формат даты. Введите ДД.MM.ГГГГ") await state.set_state(Form.dob) return conn = psycopg2.connect(dbname="botdb", user="botuser", password="tpg44dm*oOas&2geWc^Paw7") cur = conn.cursor() cur.execute(""" INSERT INTO users (telegram_id, fio, dob, phone, city) VALUES (%s,%s,%s,%s,%s) ON CONFLICT (telegram_id) DO UPDATE SET fio=EXCLUDED.fio, dob=EXCLUDED.dob, phone=EXCLUDED.phone, city=EXCLUDED.city """, (message.from_user.id, data["fio"], dob_parsed, data["phone"], data["city"])) conn.commit() cur.close() conn.close() kb = [[KeyboardButton("📘 Тест Климова")]] keyboard = ReplyKeyboardMarkup(keyboard=kb, resize_keyboard=True) await state.clear() await message.answer("Анкета сохранена ✅ Выберите тест:", reply_markup=keyboard) @dp.message(StateFilter(None)) async def select_test(message: types.Message, state: FSMContext): if message.text == "📘 Тест Климова": conn = psycopg2.connect(dbname="botdb", user="botuser", password="ваш_пароль") cur = conn.cursor() cur.execute("SELECT id, text1, category1, text2, category2, image FROM klimov_questions ORDER BY id") questions = cur.fetchall() cur.close() conn.close() await state.update_data(klimov_questions=questions, klimov_index=0, klimov_result={}) await state.set_state(Form.klimov) await send_klimov_question(message.from_user.id, state) else: await message.answer("Пока этот тест не реализован.") async def send_klimov_question(user_id, state: FSMContext): data = await state.get_data() index = data.get("klimov_index", 0) questions = data.get("klimov_questions", []) if index >= len(questions): await send_klimov_result(user_id, state) await state.clear() return q = questions[index] kb = [[KeyboardButton(q[1])], [KeyboardButton(q[3])]] keyboard = ReplyKeyboardMarkup(keyboard=kb, resize_keyboard=True) image_path = q[5] if image_path and os.path.exists(image_path): photo = FSInputFile(image_path) await bot.send_photo( chat_id=user_id, photo=photo, caption=f"Вопрос {index+1} из {len(questions)}:\nВыберите вариант", reply_markup=keyboard ) return await bot.send_message( chat_id=user_id, text=f"Вопрос {index+1} из {len(questions)}:\nВыберите вариант", reply_markup=keyboard ) @dp.message(Form.klimov) async def klimov_answer(message: types.Message, state: FSMContext): data = await state.get_data() index = data["klimov_index"] questions = data["klimov_questions"] result = data["klimov_result"] q = questions[index] if message.text == q[1]: result[q[2]] = result.get(q[2], 0) + 1 elif message.text == q[3]: result[q[4]] = result.get(q[4], 0) + 1 index += 1 await state.update_data(klimov_index=index, klimov_result=result) await send_klimov_question(message.from_user.id, state) async def send_klimov_result(user_id, state: FSMContext): data = await state.get_data() result = data.get("klimov_result", {}) questions = data.get("klimov_questions", []) if not questions: await bot.send_message(user_id, "Вы не ответили ни на один вопрос.") return max_points = {} for q in questions: max_points[q[2]] = max_points.get(q[2], 0) + 1 max_points[q[4]] = max_points.get(q[4], 0) + 1 output = "Ваши результаты:\n" for cat, max_pt in max_points.items(): pts = result.get(cat, 0) percent = (pts / max_pt) * 100 output += f"- {cat}: {percent:.1f}%\n" if result: top_cat = max(result, key=result.get) output += f"\nТип профессии: {top_cat}" await bot.send_message(user_id, output, reply_markup=ReplyKeyboardRemove())