/
max_m_lian
/
EnglishCard
Обзор
Документация
Войти
/
max_m_lian
/
EnglishCard
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
program.py
262 строки
12 KB
maxim-git
Add statistics feature
11 май 2026, 16:00
11 май 2026, 16:00
f546f83
Код
Авторство
О чём код?
""" Модуль интерфейса EnglishCard на Streamlit. Содержит класс StreamlitApp с методами для каждого экрана: приветствие, тренировка, добавление и удаление слов. """ import random import streamlit as st from models import Database class StreamlitApp: """Основной класс приложения. Управляет сессией и отрисовкой экранов.""" def __init__(self): """ Инициализирует состояние сессии и подключение к БД. Сохраняет объект Database в st.session_state, чтобы он не пересоздавался. """ if 'db' not in st.session_state: st.session_state.db = Database() self._init_session_state() self.db = st.session_state.db def run(self): """ Главный диспетчер: выбирает, какой экран показать на основе st.session_state.mode. """ if st.session_state.mode == 'greeting': self.show_greeting() elif st.session_state.mode == 'training': self.show_training() elif st.session_state.mode == 'add_word': self.show_add_word() elif st.session_state.mode == 'delete_word': self.show_delete_word() @staticmethod def _init_session_state(): """ Устанавливает начальные значения для всех ключей сессии, если они отсутствуют. """ defaults = { 'mode': 'greeting', 'user_id': None, 'username': '', 'word_loaded': False, 'target_word': '', 'correct_answer': '', 'options': [], 'feedback': None, 'wrong_guess': None, 'is_start': True } for key, value in defaults.items(): if key not in st.session_state: st.session_state[key] = value def show_greeting(self): """ Показывает приветственный экран с полем ввода имени и кнопкой 'Начать!' в случае, если это первый заход в приложение. В ином случае, отображается экран со статистикой(кол-во слов в общем словаре) и кнопкой "Продолжить!" """ if st.session_state.is_start: st.title('EnglishCard') st.markdown( """ Привет 👋 Давай попрактикуемся в английском языке. Тренировки можешь проходить в удобном для себя темпе. У тебя есть возможность использовать тренажёр, как конструктор, и собирать свою собственную базу для обучения. Для этого воспользуйся инструментами: - добавить слово ➕, - удалить слово 🔙. Ну что, начнём ⬇️ """ ) username = st.text_input('Введи своё имя:', value=st.session_state.username) if st.button('Начать!'): if self._login_user(username): st.session_state.feedback = None st.session_state.mode = 'training' st.rerun() else: st.title('EnglishCard') all_words_cnt = self.db.count_all_words(st.session_state.user_id) total_attempts, correct_answers = self.db.get_statistics(st.session_state.user_id) st.markdown( f""" Привет снова 👋 На данный момент у тебя уже {all_words_cnt} слов для тренировки! Твоя статистика на данный момент: - Общее количество попыток - {total_attempts} - Из них верных ответов - {correct_answers} Напоминаю, у тебя есть возможность использовать тренажёр, как конструктор, и собирать свою собственную базу для обучения. Для этого воспользуйся инструментами: - добавить слово ➕, - удалить слово 🔙. Ну что, продолжим ⬇️ """ ) if st.button('Продолжить!'): if self._login_user(st.session_state.username): st.session_state.feedback = None st.session_state.mode = 'training' st.rerun() def show_training(self): """Основной экран тренировки: показывает слово, варианты, обрабатывает ответы и управляющие кнопки.""" username = st.session_state.username st.session_state.is_start = False all_words_cnt = self.db.count_all_words(st.session_state.user_id) st.header(f'Привет, {st.session_state.username}! На данный момент в твоём словаре уже {all_words_cnt} слов!') if not st.session_state.word_loaded: self._load_new_word() st.header(f'Как переводится слово {st.session_state.target_word}?') st.markdown('') cols = st.columns(2) for idx, eng_word in enumerate(st.session_state.options): if cols[idx % 2].button(eng_word, key=f'opt_{idx}', width=500): if eng_word == st.session_state.correct_answer: st.session_state.feedback = 'correct' self.db.update_statistics(st.session_state.user_id, st.session_state.feedback) else: st.session_state.feedback = 'error' self.db.update_statistics(st.session_state.user_id, st.session_state.feedback) st.session_state.wrong_guess = eng_word st.rerun() if st.session_state.feedback == 'correct': st.success(f'Правильно! Слово {st.session_state.target_word} переводится как "{st.session_state.correct_answer}"') if st.button('Следующее слово', key='next_btn', width=1000): st.session_state.word_loaded = False st.session_state.feedback = None st.rerun() elif st.session_state.feedback == 'error': st.error('Неверно! Попробуй ещё раз') st.markdown('---') if st.button('Добавить слово!', width=1000): self._reset_training_state() if self._login_user(username): st.session_state.mode = 'add_word' st.rerun() if st.button('Удалить слово!', width=1000): self._reset_training_state() if self._login_user(username): st.session_state.mode = 'delete_word' st.rerun() if st.button('Назад', key='back_btn', width=1000): self._reset_training_state() st.session_state.mode = 'greeting' st.rerun() def _login_user(self, username: str | None) -> bool: """ Проверяет, что имя не пустое, и получает/создаёт пользователя в БД. Args: username (str): Имя пользователя. Returns: bool: True при успешной авторизации/создании, False если имя пустое. """ if not username: st.warning('Для начала, введи своё имя!') return False user_id = self.db.get_or_create_user(username) st.session_state.user_id = user_id st.session_state.username = username return True def _load_new_word(self) -> None: """ Загружает случайное слово и четыре варианта ответа (1 правильный + 3 случайных). Сохраняет всё в session_state. """ user_id = st.session_state.user_id words = self.db.get_random_word(user_id) if words is None: st.warning('Ваш словарь пуст. Добавьте слова!') st.session_state.word_loaded = True return russian, english = words st.session_state.target_word = russian st.session_state.correct_answer = english options = self.db.get_four_options(user_id, english) options_list = [row[0] for row in options] + [english] random.shuffle(options_list) st.session_state.options = options_list st.session_state.word_loaded = True st.session_state.feedback = None st.session_state.wrong_guess = None @staticmethod def _reset_training_state(): """ Сбрасывает флаги и данные, связанные с текущим вопросом тренировки: feedback, correct_answer, word_loaded, wrong_guess, target_word. """ st.session_state.feedback = None st.session_state.correct_answer = None st.session_state.word_loaded = False st.session_state.wrong_guess = None st.session_state.target_word = None def show_add_word(self): """ Экран добавления нового слова: текстовые поля для русского и английского слова, кнопки «Добавить» и «Назад». """ user_id = st.session_state.user_id word_to_add = st.text_input('Введи слово, которое необходимо добавить:') eng_word_to_add = st.text_input('А также его английский перевод:') st.markdown('---') if st.button('Добавить', width=1000): if word_to_add and eng_word_to_add: if self.db.add_user_word(user_id, word_to_add, eng_word_to_add): st.success('Слово успешно добавлено!') else: st.warning('Это слово уже есть в твоём словаре!') else: st.error('Введи корректные данные!') if st.button('Назад', width=1000): st.session_state.mode = 'training' st.rerun() def show_delete_word(self): """ Экран удаления личных слов: показывает кнопки с уже добавленными словами. При нажатии на кнопку слово удаляется персонально. """ user_id = st.session_state.user_id cols = st.columns(3) all_words = self.db.get_all_words(user_id) if all_words: for word_id, russian_word, english_word in all_words: if cols[word_id%3].button( f'{russian_word}({english_word})', key=f'del_{word_id}', width=300 ): self.db.delete_word(user_id, russian_word, english_word) st.success('Слово успешно удалено!') st.rerun() else: st.warning('Ты ещё не добавлял слова!') if st.button('Назад', width=1000): st.session_state.mode = 'training' st.rerun()