init commit
This commit is contained in:
553
src/bot.py
Normal file
553
src/bot.py
Normal file
@@ -0,0 +1,553 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Исправленная версия бота с правильным HTML форматированием
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
import random
|
||||
from aiogram import Bot, Dispatcher, F
|
||||
from aiogram.filters import Command, StateFilter
|
||||
from aiogram.fsm.context import FSMContext
|
||||
from aiogram.fsm.state import State, StatesGroup
|
||||
from aiogram.fsm.storage.memory import MemoryStorage
|
||||
from aiogram.types import Message, CallbackQuery, InlineKeyboardMarkup, InlineKeyboardButton, InaccessibleMessage
|
||||
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
||||
import sys
|
||||
import os
|
||||
|
||||
# Добавляем путь к проекту
|
||||
project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
sys.path.insert(0, project_root)
|
||||
|
||||
from config.config import config
|
||||
from src.database.database import DatabaseManager
|
||||
from src.services.csv_service import CSVQuizLoader, QuizGenerator
|
||||
|
||||
# Настройка логирования
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
class QuizStates(StatesGroup):
|
||||
choosing_mode = State()
|
||||
choosing_category = State()
|
||||
choosing_level = State()
|
||||
in_quiz = State()
|
||||
|
||||
class QuizBot:
|
||||
def __init__(self):
|
||||
self.bot = Bot(token=config.bot_token)
|
||||
self.dp = Dispatcher(storage=MemoryStorage())
|
||||
self.db = DatabaseManager(config.database_path)
|
||||
self.csv_loader = CSVQuizLoader(config.csv_data_path)
|
||||
|
||||
# Регистрируем обработчики
|
||||
self.setup_handlers()
|
||||
|
||||
def setup_handlers(self):
|
||||
"""Регистрация всех обработчиков"""
|
||||
# Команды
|
||||
self.dp.message(Command("start"))(self.start_command)
|
||||
self.dp.message(Command("help"))(self.help_command)
|
||||
self.dp.message(Command("stats"))(self.stats_command)
|
||||
self.dp.message(Command("stop"))(self.stop_command)
|
||||
|
||||
# Callback обработчики
|
||||
self.dp.callback_query(F.data == "guest_mode")(self.guest_mode_handler)
|
||||
self.dp.callback_query(F.data == "test_mode")(self.test_mode_handler)
|
||||
self.dp.callback_query(F.data.startswith("category_"))(self.category_handler)
|
||||
self.dp.callback_query(F.data.startswith("level_"))(self.level_handler)
|
||||
self.dp.callback_query(F.data.startswith("answer_"))(self.answer_handler)
|
||||
self.dp.callback_query(F.data == "next_question")(self.next_question)
|
||||
self.dp.callback_query(F.data == "stats")(self.stats_callback_handler)
|
||||
self.dp.callback_query(F.data == "back_to_menu")(self.back_to_menu)
|
||||
|
||||
async def start_command(self, message: Message, state: FSMContext):
|
||||
"""Обработка команды /start"""
|
||||
user = message.from_user
|
||||
|
||||
# Регистрируем пользователя
|
||||
await self.db.register_user(
|
||||
user_id=user.id,
|
||||
username=user.username,
|
||||
first_name=user.first_name,
|
||||
last_name=user.last_name,
|
||||
language_code=user.language_code or 'ru'
|
||||
)
|
||||
|
||||
await state.set_state(QuizStates.choosing_mode)
|
||||
|
||||
keyboard = InlineKeyboardMarkup(inline_keyboard=[
|
||||
[InlineKeyboardButton(text="🎯 Гостевой режим (QUIZ)", callback_data="guest_mode")],
|
||||
[InlineKeyboardButton(text="📚 Тестирование по материалам", callback_data="test_mode")],
|
||||
[InlineKeyboardButton(text="📊 Моя статистика", callback_data="stats")],
|
||||
])
|
||||
|
||||
await message.answer(
|
||||
f"👋 Добро пожаловать в Quiz Bot, {user.first_name}!\n\n"
|
||||
"🎯 <b>Гостевой режим</b> - быстрая викторина для развлечения\n"
|
||||
"📚 <b>Тестирование</b> - серьезное изучение материалов с результатами\n\n"
|
||||
"Выберите режим работы:",
|
||||
reply_markup=keyboard,
|
||||
parse_mode='HTML'
|
||||
)
|
||||
|
||||
async def help_command(self, message: Message):
|
||||
"""Обработка команды /help"""
|
||||
help_text = """🤖 <b>Команды бота:</b>
|
||||
|
||||
/start - Главное меню
|
||||
/help - Справка
|
||||
/stats - Ваша статистика
|
||||
/stop - Остановить текущий тест
|
||||
|
||||
🎯 <b>Гостевой режим:</b>
|
||||
• Быстрые викторины
|
||||
• Показ правильных ответов
|
||||
• Развлекательная атмосфера
|
||||
• 5 случайных вопросов
|
||||
|
||||
📚 <b>Режим тестирования:</b>
|
||||
• Серьезное тестирование знаний
|
||||
• Без показа правильных ответов
|
||||
• Рандомные варианты ответов
|
||||
• 10 вопросов, детальная статистика
|
||||
|
||||
📊 <b>Доступные категории:</b>
|
||||
• Корейский язык (уровни 1-5)
|
||||
• Более 120 уникальных вопросов"""
|
||||
await message.answer(help_text, parse_mode='HTML')
|
||||
|
||||
async def stats_command(self, message: Message):
|
||||
"""Обработка команды /stats"""
|
||||
user_stats = await self.db.get_user_stats(message.from_user.id)
|
||||
|
||||
if not user_stats or user_stats['total_questions'] == 0:
|
||||
await message.answer("📊 У вас пока нет статистики. Пройдите первый тест!")
|
||||
return
|
||||
|
||||
accuracy = (user_stats['correct_answers'] / user_stats['total_questions']) * 100 if user_stats['total_questions'] > 0 else 0
|
||||
|
||||
stats_text = f"""📊 <b>Ваша статистика:</b>
|
||||
|
||||
❓ Всего вопросов: {user_stats['total_questions']}
|
||||
✅ Правильных ответов: {user_stats['correct_answers']}
|
||||
📈 Точность: {accuracy:.1f}%
|
||||
🎯 Завершенных сессий: {user_stats['sessions_completed'] or 0}
|
||||
🏆 Лучший результат: {user_stats['best_score'] or 0:.1f}%
|
||||
📊 Средний балл: {user_stats['average_score'] or 0:.1f}%"""
|
||||
|
||||
keyboard = InlineKeyboardMarkup(inline_keyboard=[
|
||||
[InlineKeyboardButton(text="🏠 Главное меню", callback_data="back_to_menu")]
|
||||
])
|
||||
|
||||
await message.answer(stats_text, reply_markup=keyboard, parse_mode='HTML')
|
||||
|
||||
async def stop_command(self, message: Message):
|
||||
"""Остановка текущего теста"""
|
||||
session = await self.db.get_active_session(message.from_user.id)
|
||||
if session:
|
||||
await self.db.finish_session(message.from_user.id, 0)
|
||||
await message.answer("❌ Текущий тест остановлен.")
|
||||
else:
|
||||
await message.answer("❌ У вас нет активного теста.")
|
||||
|
||||
keyboard = InlineKeyboardMarkup(inline_keyboard=[
|
||||
[InlineKeyboardButton(text="🏠 Главное меню", callback_data="back_to_menu")]
|
||||
])
|
||||
await message.answer("Что бы вы хотели сделать дальше?", reply_markup=keyboard)
|
||||
|
||||
async def guest_mode_handler(self, callback: CallbackQuery, state: FSMContext):
|
||||
"""Обработка выбора гостевого режима"""
|
||||
await state.update_data(mode='guest')
|
||||
await state.set_state(QuizStates.choosing_category)
|
||||
|
||||
keyboard = InlineKeyboardMarkup(inline_keyboard=[
|
||||
[InlineKeyboardButton(text="🇰🇷 Корейский язык", callback_data="category_korean")],
|
||||
[InlineKeyboardButton(text="🔙 Назад", callback_data="back_to_menu")]
|
||||
])
|
||||
|
||||
await callback.message.edit_text(
|
||||
"🎯 <b>Гостевой режим</b>\n\nВыберите категорию для викторины:",
|
||||
reply_markup=keyboard,
|
||||
parse_mode='HTML'
|
||||
)
|
||||
await callback.answer()
|
||||
|
||||
async def test_mode_handler(self, callback: CallbackQuery, state: FSMContext):
|
||||
"""Обработка выбора режима тестирования"""
|
||||
await state.update_data(mode='test')
|
||||
await state.set_state(QuizStates.choosing_category)
|
||||
|
||||
keyboard = InlineKeyboardMarkup(inline_keyboard=[
|
||||
[InlineKeyboardButton(text="🇰🇷 Корейский язык", callback_data="category_korean")],
|
||||
[InlineKeyboardButton(text="🔙 Назад", callback_data="back_to_menu")]
|
||||
])
|
||||
|
||||
await callback.message.edit_text(
|
||||
"📚 <b>Режим тестирования</b>\n\nВыберите категорию для серьезного изучения:",
|
||||
reply_markup=keyboard,
|
||||
parse_mode='HTML'
|
||||
)
|
||||
await callback.answer()
|
||||
|
||||
async def category_handler(self, callback: CallbackQuery, state: FSMContext):
|
||||
"""Обработка выбора категории"""
|
||||
category = callback.data.split("_")[1]
|
||||
await state.update_data(category=category)
|
||||
|
||||
keyboard = InlineKeyboardMarkup(inline_keyboard=[
|
||||
[InlineKeyboardButton(text="🥉 Уровень 1 (начальный)", callback_data="level_1")],
|
||||
[InlineKeyboardButton(text="🥈 Уровень 2 (базовый)", callback_data="level_2")],
|
||||
[InlineKeyboardButton(text="🥇 Уровень 3 (средний)", callback_data="level_3")],
|
||||
[InlineKeyboardButton(text="🏆 Уровень 4 (продвинутый)", callback_data="level_4")],
|
||||
[InlineKeyboardButton(text="💎 Уровень 5 (эксперт)", callback_data="level_5")],
|
||||
[InlineKeyboardButton(text="🔙 Назад", callback_data="back_to_menu")]
|
||||
])
|
||||
|
||||
await callback.message.edit_text(
|
||||
f"🇰🇷 <b>Корейский язык</b>\n\nВыберите уровень сложности:",
|
||||
reply_markup=keyboard,
|
||||
parse_mode='HTML'
|
||||
)
|
||||
await callback.answer()
|
||||
|
||||
async def level_handler(self, callback: CallbackQuery, state: FSMContext):
|
||||
"""Обработка выбора уровня"""
|
||||
level = int(callback.data.split("_")[1])
|
||||
data = await state.get_data()
|
||||
|
||||
# Загружаем вопросы
|
||||
filename = f"{data['category']}_level_{level}.csv"
|
||||
questions = await self.csv_loader.load_questions_from_csv(filename)
|
||||
|
||||
if not questions:
|
||||
await callback.message.edit_text(
|
||||
"❌ Вопросы для этого уровня пока недоступны.",
|
||||
reply_markup=InlineKeyboardMarkup(inline_keyboard=[
|
||||
[InlineKeyboardButton(text="🔙 Назад", callback_data="back_to_menu")]
|
||||
])
|
||||
)
|
||||
await callback.answer()
|
||||
return
|
||||
|
||||
# Определяем количество вопросов
|
||||
questions_count = 5 if data['mode'] == 'guest' else 10
|
||||
|
||||
# Берем случайные вопросы
|
||||
selected_questions = random.sample(questions, min(questions_count, len(questions)))
|
||||
|
||||
# Создаем тестовую запись в БД
|
||||
test_id = await self.db.add_test(
|
||||
name=f"{data['category'].title()} Level {level}",
|
||||
description=f"Тест по {data['category']} языку, уровень {level}",
|
||||
level=level,
|
||||
category=data['category'],
|
||||
csv_file=filename
|
||||
)
|
||||
|
||||
# Начинаем сессию
|
||||
await self.db.start_session(
|
||||
user_id=callback.from_user.id,
|
||||
test_id=test_id or 1,
|
||||
questions=selected_questions,
|
||||
mode=data['mode']
|
||||
)
|
||||
|
||||
await state.set_state(QuizStates.in_quiz)
|
||||
await self.show_question_safe(callback, callback.from_user.id, 0)
|
||||
await callback.answer()
|
||||
|
||||
def shuffle_answers(self, question_data: dict) -> dict:
|
||||
"""Перемешивает варианты ответов и обновляет правильный ответ"""
|
||||
options = [
|
||||
question_data['option1'],
|
||||
question_data['option2'],
|
||||
question_data['option3'],
|
||||
question_data['option4']
|
||||
]
|
||||
|
||||
correct_answer_text = options[question_data['correct_answer'] - 1]
|
||||
|
||||
# Перемешиваем варианты
|
||||
random.shuffle(options)
|
||||
|
||||
# Находим новую позицию правильного ответа
|
||||
new_correct_position = options.index(correct_answer_text) + 1
|
||||
|
||||
# Обновляем данные вопроса
|
||||
shuffled_question = question_data.copy()
|
||||
shuffled_question['option1'] = options[0]
|
||||
shuffled_question['option2'] = options[1]
|
||||
shuffled_question['option3'] = options[2]
|
||||
shuffled_question['option4'] = options[3]
|
||||
shuffled_question['correct_answer'] = new_correct_position
|
||||
|
||||
return shuffled_question
|
||||
|
||||
async def show_question_safe(self, callback: CallbackQuery, user_id: int, question_index: int):
|
||||
"""Безопасный показ вопроса через callback"""
|
||||
session = await self.db.get_active_session(user_id)
|
||||
if not session or question_index >= len(session['questions_data']):
|
||||
return
|
||||
|
||||
question = session['questions_data'][question_index]
|
||||
|
||||
# Перемешиваем варианты ответов только в тестовом режиме
|
||||
if session['mode'] == 'test':
|
||||
question = self.shuffle_answers(question)
|
||||
session['questions_data'][question_index] = question
|
||||
await self.db.update_session_questions(user_id, session['questions_data'])
|
||||
|
||||
total_questions = len(session['questions_data'])
|
||||
|
||||
# Создаем клавиатуру с ответами
|
||||
keyboard_builder = InlineKeyboardBuilder()
|
||||
for i in range(1, 5):
|
||||
keyboard_builder.add(InlineKeyboardButton(
|
||||
text=f"{i}. {question[f'option{i}']}",
|
||||
callback_data=f"answer_{i}"
|
||||
))
|
||||
|
||||
keyboard_builder.adjust(1)
|
||||
|
||||
question_text = (
|
||||
f"❓ <b>Вопрос {question_index + 1}/{total_questions}</b>\n\n"
|
||||
f"<b>{question['question']}</b>"
|
||||
)
|
||||
|
||||
# Безопасная отправка сообщения
|
||||
if callback.message and not isinstance(callback.message, InaccessibleMessage):
|
||||
try:
|
||||
await callback.message.edit_text(question_text, reply_markup=keyboard_builder.as_markup(), parse_mode='HTML')
|
||||
except Exception:
|
||||
await self.bot.send_message(callback.from_user.id, question_text, reply_markup=keyboard_builder.as_markup(), parse_mode='HTML')
|
||||
else:
|
||||
await self.bot.send_message(callback.from_user.id, question_text, reply_markup=keyboard_builder.as_markup(), parse_mode='HTML')
|
||||
|
||||
async def answer_handler(self, callback: CallbackQuery, state: FSMContext):
|
||||
"""Обработка ответа на вопрос"""
|
||||
answer = int(callback.data.split("_")[1])
|
||||
user_id = callback.from_user.id
|
||||
|
||||
session = await self.db.get_active_session(user_id)
|
||||
if not session:
|
||||
await callback.answer("❌ Сессия не найдена")
|
||||
return
|
||||
|
||||
current_q_index = session['current_question']
|
||||
question = session['questions_data'][current_q_index]
|
||||
is_correct = answer == question['correct_answer']
|
||||
mode = session['mode']
|
||||
|
||||
# Обновляем счетчик правильных ответов
|
||||
if is_correct:
|
||||
session['correct_count'] += 1
|
||||
|
||||
# Обновляем прогресс в базе
|
||||
await self.db.update_session_progress(
|
||||
user_id, current_q_index + 1, session['correct_count']
|
||||
)
|
||||
|
||||
# Проверяем, есть ли еще вопросы
|
||||
if current_q_index + 1 >= len(session['questions_data']):
|
||||
# Тест завершен
|
||||
score = (session['correct_count'] / len(session['questions_data'])) * 100
|
||||
await self.db.finish_session(user_id, score)
|
||||
|
||||
keyboard = InlineKeyboardMarkup(inline_keyboard=[
|
||||
[InlineKeyboardButton(text="🏠 Главное меню", callback_data="back_to_menu")],
|
||||
[InlineKeyboardButton(text="📊 Моя статистика", callback_data="stats")]
|
||||
])
|
||||
|
||||
# Разный текст для разных режимов
|
||||
if mode == 'test':
|
||||
final_text = (
|
||||
f"🎉 <b>Тест завершен!</b>\n\n"
|
||||
f"📊 Результат: {session['correct_count']}/{len(session['questions_data'])}\n"
|
||||
f"📈 Точность: {score:.1f}%\n"
|
||||
f"🏆 Оценка: {self.get_grade(score)}\n\n"
|
||||
f"💡 Результат сохранен в вашей статистике"
|
||||
)
|
||||
else:
|
||||
result_text = "✅ Правильно!" if is_correct else f"❌ Неправильно. Правильный ответ: {question['correct_answer']}"
|
||||
final_text = (
|
||||
f"{result_text}\n\n"
|
||||
f"🎉 <b>Викторина завершена!</b>\n\n"
|
||||
f"📊 Результат: {session['correct_count']}/{len(session['questions_data'])}\n"
|
||||
f"📈 Точность: {score:.1f}%\n"
|
||||
f"🏆 Оценка: {self.get_grade(score)}"
|
||||
)
|
||||
|
||||
# Безопасная отправка сообщения
|
||||
if callback.message and not isinstance(callback.message, InaccessibleMessage):
|
||||
try:
|
||||
await callback.message.edit_text(final_text, reply_markup=keyboard, parse_mode='HTML')
|
||||
except Exception:
|
||||
await self.bot.send_message(callback.from_user.id, final_text, reply_markup=keyboard, parse_mode='HTML')
|
||||
else:
|
||||
await self.bot.send_message(callback.from_user.id, final_text, reply_markup=keyboard, parse_mode='HTML')
|
||||
else:
|
||||
# Есть еще вопросы
|
||||
if mode == 'test':
|
||||
# В тестовом режиме сразу переходим к следующему вопросу
|
||||
await self.show_question_safe(callback, callback.from_user.id, current_q_index + 1)
|
||||
else:
|
||||
# В гостевом режиме показываем результат и кнопку "Следующий"
|
||||
result_text = "✅ Правильно!" if is_correct else f"❌ Неправильно. Правильный ответ: {question['correct_answer']}"
|
||||
|
||||
keyboard = InlineKeyboardMarkup(inline_keyboard=[
|
||||
[InlineKeyboardButton(text="➡️ Следующий вопрос", callback_data="next_question")]
|
||||
])
|
||||
|
||||
# Безопасная отправка сообщения
|
||||
if callback.message and not isinstance(callback.message, InaccessibleMessage):
|
||||
try:
|
||||
await callback.message.edit_text(result_text, reply_markup=keyboard)
|
||||
except Exception:
|
||||
await self.bot.send_message(callback.from_user.id, result_text, reply_markup=keyboard)
|
||||
else:
|
||||
await self.bot.send_message(callback.from_user.id, result_text, reply_markup=keyboard)
|
||||
|
||||
await callback.answer()
|
||||
|
||||
async def next_question(self, callback: CallbackQuery):
|
||||
"""Переход к следующему вопросу"""
|
||||
session = await self.db.get_active_session(callback.from_user.id)
|
||||
if session:
|
||||
await self.show_question_safe(callback, callback.from_user.id, session['current_question'])
|
||||
await callback.answer()
|
||||
|
||||
async def stats_callback_handler(self, callback: CallbackQuery):
|
||||
"""Обработчик кнопки статистики через callback"""
|
||||
user_stats = await self.db.get_user_stats(callback.from_user.id)
|
||||
|
||||
if not user_stats or user_stats['total_questions'] == 0:
|
||||
stats_text = "📊 У вас пока нет статистики. Пройдите первый тест!"
|
||||
else:
|
||||
accuracy = (user_stats['correct_answers'] / user_stats['total_questions']) * 100 if user_stats['total_questions'] > 0 else 0
|
||||
|
||||
# Получаем дополнительную статистику
|
||||
recent_results = await self.db.get_recent_results(callback.from_user.id, 3)
|
||||
category_stats = await self.db.get_category_stats(callback.from_user.id)
|
||||
|
||||
best_score = user_stats['best_score'] or 0
|
||||
avg_score = user_stats['average_score'] or 0
|
||||
|
||||
stats_text = f"""📊 <b>Ваша статистика:</b>
|
||||
|
||||
📈 <b>Общие показатели:</b>
|
||||
❓ Всего вопросов: {user_stats['total_questions']}
|
||||
✅ Правильных ответов: {user_stats['correct_answers']}
|
||||
🎯 Общая точность: {accuracy:.1f}%
|
||||
🎪 Завершенных сессий: {user_stats['sessions_completed'] or 0}
|
||||
🏆 Лучший результат: {best_score:.1f}%
|
||||
📊 Средний балл: {avg_score:.1f}%
|
||||
|
||||
🎮 <b>По режимам:</b>
|
||||
🎯 Гостевые викторины: {user_stats['guest_sessions'] or 0}
|
||||
📚 Серьезные тесты: {user_stats['test_sessions'] or 0}"""
|
||||
|
||||
# Добавляем статистику по категориям
|
||||
if category_stats:
|
||||
stats_text += "\n\n🏷️ <b>По категориям:</b>"
|
||||
for cat_stat in category_stats[:2]:
|
||||
cat_accuracy = (cat_stat['correct_answers'] / cat_stat['total_questions']) * 100 if cat_stat['total_questions'] > 0 else 0
|
||||
stats_text += f"\n📖 {cat_stat['category']}: {cat_stat['attempts']} попыток, {cat_accuracy:.1f}% точность"
|
||||
|
||||
# Добавляем последние результаты
|
||||
if recent_results:
|
||||
stats_text += "\n\n📈 <b>Последние результаты:</b>"
|
||||
for result in recent_results:
|
||||
mode_emoji = "🎯" if result['mode'] == 'guest' else "📚"
|
||||
stats_text += f"\n{mode_emoji} {result['score']:.1f}% ({result['correct_answers']}/{result['questions_asked']})"
|
||||
|
||||
keyboard = InlineKeyboardMarkup(inline_keyboard=[
|
||||
[InlineKeyboardButton(text="🏠 Главное меню", callback_data="back_to_menu")],
|
||||
[InlineKeyboardButton(text="🔄 Обновить статистику", callback_data="stats")]
|
||||
])
|
||||
|
||||
# Безопасная отправка сообщения
|
||||
if callback.message and not isinstance(callback.message, InaccessibleMessage):
|
||||
try:
|
||||
await callback.message.edit_text(stats_text, reply_markup=keyboard, parse_mode='HTML')
|
||||
except Exception:
|
||||
await self.bot.send_message(callback.from_user.id, stats_text, reply_markup=keyboard, parse_mode='HTML')
|
||||
else:
|
||||
await self.bot.send_message(callback.from_user.id, stats_text, reply_markup=keyboard, parse_mode='HTML')
|
||||
await callback.answer()
|
||||
|
||||
async def back_to_menu(self, callback: CallbackQuery, state: FSMContext):
|
||||
"""Возврат в главное меню"""
|
||||
await state.clear()
|
||||
|
||||
user = callback.from_user
|
||||
|
||||
# Регистрируем пользователя (если еще не зарегистрирован)
|
||||
await self.db.register_user(
|
||||
user_id=user.id,
|
||||
username=user.username,
|
||||
first_name=user.first_name,
|
||||
last_name=user.last_name,
|
||||
language_code=user.language_code or 'ru'
|
||||
)
|
||||
|
||||
await state.set_state(QuizStates.choosing_mode)
|
||||
|
||||
keyboard = InlineKeyboardMarkup(inline_keyboard=[
|
||||
[InlineKeyboardButton(text="🎯 Гостевой режим (QUIZ)", callback_data="guest_mode")],
|
||||
[InlineKeyboardButton(text="📚 Тестирование по материалам", callback_data="test_mode")],
|
||||
[InlineKeyboardButton(text="📊 Моя статистика", callback_data="stats")],
|
||||
])
|
||||
|
||||
text = (f"👋 Добро пожаловать в Quiz Bot, {user.first_name}!\n\n"
|
||||
"🎯 <b>Гостевой режим</b> - быстрая викторина для развлечения\n"
|
||||
"📚 <b>Тестирование</b> - серьезное изучение материалов с результатами\n\n"
|
||||
"Выберите режим работы:")
|
||||
|
||||
if callback.message and not isinstance(callback.message, InaccessibleMessage):
|
||||
try:
|
||||
await callback.message.edit_text(text, reply_markup=keyboard, parse_mode='HTML')
|
||||
except Exception:
|
||||
await self.bot.send_message(callback.from_user.id, text, reply_markup=keyboard, parse_mode='HTML')
|
||||
else:
|
||||
await self.bot.send_message(callback.from_user.id, text, reply_markup=keyboard, parse_mode='HTML')
|
||||
await callback.answer()
|
||||
|
||||
def get_grade(self, score: float) -> str:
|
||||
"""Получение оценки по проценту правильных ответов"""
|
||||
if score >= 90:
|
||||
return "Отлично! 🌟"
|
||||
elif score >= 70:
|
||||
return "Хорошо! 👍"
|
||||
elif score >= 50:
|
||||
return "Удовлетворительно 📚"
|
||||
else:
|
||||
return "Нужно подтянуть знания 📖"
|
||||
|
||||
async def start(self):
|
||||
"""Запуск бота"""
|
||||
# Проверяем токен
|
||||
if not config.bot_token or config.bot_token in ['your_bot_token_here', 'test_token_for_demo_purposes']:
|
||||
print("❌ Ошибка: не настроен BOT_TOKEN в файле .env")
|
||||
return False
|
||||
|
||||
# Инициализируем базу данных
|
||||
await self.db.init_database()
|
||||
|
||||
print("✅ Bot starting...")
|
||||
print(f"🗄️ Database: {config.database_path}")
|
||||
print(f"📁 CSV files: {config.csv_data_path}")
|
||||
|
||||
try:
|
||||
await self.dp.start_polling(self.bot)
|
||||
except Exception as e:
|
||||
logging.error(f"Error starting bot: {e}")
|
||||
return False
|
||||
|
||||
async def main():
|
||||
"""Главная функция"""
|
||||
bot = QuizBot()
|
||||
await bot.start()
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
Reference in New Issue
Block a user