PyCards - это настольное приложение для обучения методом интервальных повторений (аналог Anki). Пользователь создаёт колоды карточек формата "вопрос -> ответ" и повторяет по расписанию, которое автоматически строится на основе упрощённого алгоритма интервальных повторений, вдохновлённый SM-2, также присутствует функция импорта карточек из CSV-файлов.
| Компонент | Решение |
|---|---|
| Язык | Python |
| GUI | customtkinter |
| База данных | SQLite (файл cards.db) |
| Импорт данных | CSV (Стандартная библиотека csv) |
| Тип приложения | Desktop, работа без интернета |
| Система контроля версий | Git |
Коллекция карточек собранных по какому-либо признаку.
[!Примеры] "Математика - интегралы" "Английские слова"
Содержит вопрос, ответ и данные для повторений:
- вопрос (question)
- ответ (answer)
- интервал в часах (interval)
- количество успешных повторений (repetitions)
- множитель интервала (ease_factor)
- дата и время следующего повторения (next_review)
Файл: cards.db СУБД: SQLite.
SQLite не имеет отдельного типа DATE/DATETIME - все даты хранятся как TEXT в формате ISO 8601:
YYYY-MM-DD HH:MM:SS
Пример: 2025-10-15 14:30:00. Этот формат гарантирует корректную сортировку и фильтрацию стандартными строковыми операциями SQLite. Для получения текущего времени будем использовать функцию datetime('now')
Карточки выбираются запросом:
SELECT * FROM cards
WHERE deck_id = ? AND next_review <= datetime('now')
ORDER BY next_review ASCСортировка по next_review ASC гарантирует, что первыми идут просроченные карточки (давно не повторявшиеся), затем - новые.
| Название | Тип данных |
|---|---|
| id | integer |
| name | text |
| created_at | text (datetime('now')) |
CREATE TABLE decks (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT UNIQUE NOT NULL,
created_at TEXT DEFAULT (datetime('now'))
);| Название | Тип данных |
|---|---|
| id | integer |
| deck_id | integer |
| question | text |
| answer | text |
| interval | integer |
| repetitions | integer |
| ease_factor | real |
| next_review | text (datetime('now')) |
| created_at | text (datetime('now')) |
CREATE TABLE cards (
id INTEGER PRIMARY KEY AUTOINCREMENT,
deck_id INTEGER NOT NULL,
question TEXT NOT NULL,
answer TEXT NOT NULL,
interval INTEGER DEFAULT 1,
repetitions INTEGER DEFAULT 0,
ease_factor REAL DEFAULT 2.5,
next_review TEXT DEFAULT (datetime('now')),
created_at TEXT DEFAULT (datetime('now')),
FOREIGN KEY(deck_id) REFERENCES decks(id) ON DELETE CASCADE
);cards.deck_id - внешний ключ к decks.id Каскадное удаление, при удалении колоды удаляются все карточки
[!info] Примечание interval хранится в часах. next_review по умолчанию = datetime('now'), новые карточки доступны к повторению сразу после импорта.
pycards/
main.py # Точка входа
db.py # Инициализация БД
deck_model.py # Работа с таблицей колод
card_model.py # Работа с таблицей карточек
scheduler.py # SM-2
csv_io.py # Импорт и экспорт CSV
ui/
constants.py
main_window.py
editor_window.py
review_window.py
utils.py
data/
cards.db
Две кнопки:
- Обучение
- Редактор
Единое окно для управления колодами и карточками. Работает в двух состояниях: список колод и список карточек выбранной колоды.
Состояние 1 - список колод (открывается по умолчанию):
- Отображает все колоды с прокруткой. Рядом с названием - количество карточек:
Математика (42)
- Кнопка "Создать колоду" в верхней части окна - открывает диалог ввода названия. Дубликаты названий не допускаются
- У каждой колоды три кнопки:
- "Открыть" - переключает окно в состояние 2 (список карточек этой колоды)
- "Настройки" - открывает диалог переименования колоды. Дубликаты названий не допускаются
- "Удалить" - удаление с подтверждением: "Вы уверены, что хотите удалить колоду?". Каскадное удаление
Состояние 2 - список карточек колоды:
- Заголовок окна показывает название открытой колоды. Кнопка "<- Назад" возвращает в состояние 1
- Список карточек с прокруткой - отображает вопрос и начало ответа
- Кнопка "Создать карточку" в верхней части - открывает диалог с полями "Вопрос" и "Ответ". Карточка создается с interval =1Ч, next_review=now
- Кнопки "Импорт" и "Экспорт" в верхней части - каждая открывает своё диалоговое окно:
- "Импорт": поля "Путь к файлу" (с кнопкой "Обзор" и авто-определением кодировки через chardet) и "Кодировка" (подставляется автоматически, можно изменить вручную). Карточки импортируются в текущую открытую колоду
- "Экспорт": поля "Название файла" и "Путь для сохранения"
- У каждой карточки две кнопки:
- "Настройки" - открывает диалог редактирования: поля "Вопрос", "Ответ" и выпадающий список "Колода" (можно перенести карточку в другую колоду). Поля SM-2 (interval, repetitions, next_review) не меняются
- "Удалить" - удаление с подтверждением: "Вы уверены, что хотите удалить карточку?"
Поведение:
- Пользователь выбирает колоду
- Если карточек для повторения нет - сообщение "Карточек к обучению нет" и возврат к выбору колоды
- В верхней части окна отображается счётчик прогресса: "Осталось X / Повторено: Y"
- Карточки показываются по одной: сначала только вопрос, затем по кнопке - ответ
- После показа ответа - четыре кнопки оценки: Плохо / Нормально / Хорошо / Легко
- При оценке "Плохо" карточка возвращается в конец очереди текущей сессии и не считается повторённой. При оценке >= Нормально карточка считается повторённой и выбывает из сессии. Счётчик "Повторено" отражает только карточки, закрытые с оценкой >= "Нормально"
Режим просмотра позволяет листать карточки колоды без влияния на алгоритм планирования:
- Доступен из окна выбора колоды - отдельная кнопка "Просмотр"
- Показываются все карточки колоды по одной (вопрос -> ответ), без фильтрации по next_review
- Кнопки оценки отсутствуют - только "Следующая" и "Назад"
- interval, repetitions и next_review не изменяются
- Используется для первичного знакомства с материалом перед началом повторений
Разделитель: запятая ( , )
вопрос,ответПример:
Что обозначает символ C в формулах интегралов?,Константу интегрирования.- Пустые строки игнорируются
- Строки менее чем с 2 колонками пропускаются, ошибка показывается в всплывающем окне
- Лишние колонки игнорируются
- Дубликаты: если карточка с таким же вопросом уже существует в данной колоде - строка пропускается. Проверка дублей выполняется по (deck_id, question), поэтому одинаковый вопрос в разных колодах допустим
CSV-файлы из Excel на Windows часто сохраняются в Windows-1251, а не в UTF-8. Для корректного импорта:
- Кодировка определяется автоматически через
chardetпри выборе файла ("Обзор") и подставляется в поле. При необходимости можно указать вручную - Файл открывается с указанной кодировкой
- При ошибке декодирования (UnicodeDecodeError) импорт прерывается с всплывающим окном: "Ошибка чтения файла. Попробуйте сменить кодировку"
SM-2 (SuperMemo 2) - алгоритм интервальных повторений, который автоматически планирует время следующего показа карточки в зависимости от того, насколько хорошо пользователь её помнит. Чем лучше карточка усвоена - тем реже она показывается. Карточки, которые вызывают затруднения, возвращаются быстро.
В PyCard используется упрощенная версия SM-2: ease_factor фиксирован (2.5) и не изменяется в процессе повторений.
| Поле | Начальное значение | Описание |
|---|---|---|
| interval | 1 час | Через сколько часов показать карточку снова |
| repetitions | 0 | Счётчик успешных повторений подряд (оценка >= Нормально). Сбрасывается в 0 при оценке "Плохо". Зарезервировано для полного SM-2 |
| ease_factor | 2.5 | Множитель интервала. Не изменяется |
| next_review | текущая дата | Дата и время следующего обязательного показа карточки. |
После того как пользователь оценил карточку, выполняются следующие шаги:
- Считать текущее значение interval из базы данных
- Обновить repetitions согласно оценке
- Вычислить новый interval, применив множитель к текущему значению из БД
- Применить ограничение: interval не может быть меньше 1 часа
- Вычислить next_review = datetime('now', '+N hours'), где N = новый интервал
- Сохранить изменения в базе данных
| Оценка | Действие с interval | Действие с repetitions |
|---|---|---|
| Плохо | interval = 1 час | repetitions = 0 |
| Нормально | interval без изменений (x1) | repetitions += 1 |
| Хорошо | interval x2 | repetitions += 1 |
| Легко | interval x3 | repetitions += 1 |
- Минимальное значение interval = 1 час (не может быть меньше)
- При оценке "Плохо" repetitions всегда сбрасывается в 0, независимо от предыдущего значения
- Новая карточка создается с interval = 1 час и next_review = datetime('now') - доступна к повторению сразу после импорта
- Карточка попадает в сессию повторения, если next_review <= текущее время
| Повторение | Оценка | interval | repetitions | Следующий показ |
|---|---|---|---|---|
| Импорт | - | 1 ч | 0 | через 1 час |
| 1-е | Плохо | 1 ч | 0 | через 1 час |
| 2-е | Нормально | 1 ч | 1 | через 1 час |
| 3-е | Хорошо | 2 ч | 2 | через 2 часа |
| 4-е | Хорошо | 4 ч | 3 | через 4 часа |
| 5-е | Легко | 12 ч | 4 | через 12 часов |
Обязательные функции:
- Создание и удаление колод
- Импорт карточек из CSV
- Ручное создание, редактирование и удаление карточек через GUI
- Перенос карточки между колодами через настройки карточки
- Хранение данных в SQLite
- Режим повторения с показом "Вопрос -> Ответ"
- Оценка знания (4 кнопки)
- Автоматическое планирование по упрощённой версии SM-2
- Счётчик прогресса в окне повторения
- Выбор кодировки CSV при импорте
- Режим просмотра - листание карточек без записи результатов и изменения интервалов
[!bug] Замечание Формулы LaTeX на первом этапе отображаются как обычный текст.
Следующие возможности могут быть реализованы в будущем и не входят в MVP: Алгоритм и логика:
- Полный SM-2 (ease_factor меняется)
Контент:
- Поддержка LaTeX
- Изображения в карточках
Статистика:
- Граф прогресса по дням
Удобство:
- Поиск по карточкам
- Тёмная/светлая тема