Повторение — мать учения

Выучил конспект — и через неделю помнишь только заголовок. Знакомо. Память хранит то, что достаёшь регулярно, а не то, что один раз прочитал. Поэтому повторять надо не перечитыванием, а вопросами: вспомнил сам — закрепил, не вспомнил — посмотрел ответ и вернулся к этому месту позже.
Раньше вопросы приходилось придумывать вручную. Сейчас достаточно скормить материал ChatGPT или NotebookLM и попросить из него тест. Дальше — файл, который понимает бот: он принимает его, проверяет формат и ведёт по вопросам.
Сначала — материал
Подойдёт что угодно, что вы хотите запомнить: конспект лекции, PDF, статья, транскрипт видео, свои заметки.
- NotebookLM хорош, когда источников несколько и важно, чтобы модель не выдумывала: он отвечает только по загруженным документам и показывает, откуда взял факт.
- ChatGPT удобнее, когда материал уже текстом в переписке или его надо переупаковать: сократить, разбить на темы, перевести.
Один файл — одна тема. Не надо мешать в один тест три лекции и полкниги: повторять такое невозможно.
Промт
Скопируйте целиком и вставьте материал в конец. Если материал большой — приложите файлом и напишите «материал в приложенном файле».
Ты — методист, который делает тренировочный тест по материалу ниже. Материал — единственный источник фактов: ничего не добавляй от себя.
Сделай 12–20 вопросов, которые проверяют понимание и вспоминание, а не узнавание. Больше половины вопросов — с кнопками (inline_choice, situational_scenario), чтобы ученик тапал, а не печатал. Остальные — с вводом текста (how_to_say, text_input_translation, fill_blank, error_correction, word_order). Текстовые ответы должны быть короткими — не длиннее 3–4 слов.
Верни ТОЛЬКО валидный JSON без markdown-обёрток, без комментариев и без текста до и после. Результат должен быть JSON-файлом (не ответами на тест и не пояснениями) — сохрани его как .json файл. Схема:
{
"format": "tift-quiz-v4",
"version": 4,
"language": "ru",
"title": "короткое название темы",
"description": "одно предложение о том, что проверяет файл",
"topics": [
{"id": "latinitsey_s_podchyorkivaniem", "title": "Название темы"}
],
"rules_summary": [
{
"rule_id": "RULE_ZAGLAVNIMI",
"title": "Правило или факт",
"category": "Раздел",
"summary": "формулировка правила в 1–2 предложениях",
"formula_or_pattern": "формула или шаблон, если есть",
"source_ref": "откуда факт: файл, слайд, раздел"
}
],
"questions": [ ... ]
}
Поля вопроса:
id — уникальная строка: q1, q2, q3 и так далее;
exercise_type — один из: inline_choice, situational_scenario, how_to_say, text_input_translation, fill_blank, error_correction, word_order, new_word;
topic — ровно один id из topics;
difficulty — 1, 2 или 3;
prompt — текст задания;
explanation — 1–2 предложения, почему ответ правильный;
rule_reference — {"rule_id": "<id из rules_summary>", "title": "<title правила>"};
source — откуда взят вопрос.
hint — необязательная ссылка на публичный источник (документация, статья, официальная страница), который поможет ученику прочитать подробнее; в Telegram показывается как подсказка после ответа.
Поле с ответом зависит от типа:
inline_choice: "inline_keyboard": [["вариант 1"], ["вариант 2"], ["вариант 3"]], "correct_answer": "точная копия правильного варианта";
situational_scenario: "options": ["вариант 1", "вариант 2", "вариант 3"], "correct_answer": "точная копия правильного варианта";
how_to_say, text_input_translation, fill_blank, error_correction, word_order, new_word: "expected_input": ["допустимый ответ", "ещё один допустимый вариант"];
Требования:
1. expected_input — все формулировки, которые считаются правильными: с точкой и без, с сокращением и без, цифрой и словом. Только реально верные варианты, без мусора.
2. correct_answer обязан дословно совпадать с одним из вариантов.
3. В inline_choice — 3–4 варианта, неверные должны быть правдоподобными.
4. Не ставь таймкоды (00:00:00) в source и source_ref, если не уверен, что они реальные. Если ставишь — минуты и секунды должны быть от 0 до 59.
6. id, rule_id и topic — латиницей; текст заданий — на русском; ответы — на изучаемом языке, если учим язык.
7. Никаких ```json, никаких многоточий, никаких // комментариев. JSON должен парситься как есть.
8. По возможности добавляй поле `hint` со ссылкой на публичный источник (официальная документация, статья, Wikipedia), чтобы ученик мог прочитать подробнее. В Telegram подсказка показывается после ответа.
Материал:
[ВСТАВЬТЕ СЮДА КОНСПЕКТ, ТЕКСТ ИЛИ ПРИЛОЖИТЕ ФАЙЛ]
Промт длинный намеренно: модель ломает формат ровно там, где ей дали свободу. Чем жёстче схема, тем меньше правок потом.
Что должно получиться
Файл — обычный JSON. Минимальный рабочий пример с тремя типами вопросов:
{
"format": "tift-quiz-v4",
"version": 4,
"language": "ru",
"title": "Present Perfect Continuous",
"description": "Тренировка по конспекту урока 3.",
"topics": [
{ "id": "tenses", "title": "Времена" }
],
"rules_summary": [
{
"rule_id": "RULE_PPC",
"title": "Present Perfect Continuous",
"category": "Грамматика",
"summary": "Действие началось в прошлом и продолжается сейчас.",
"formula_or_pattern": "have/has + been + V-ing",
"source_ref": "конспект, урок 3"
}
],
"questions": [
{
"id": "q1",
"exercise_type": "inline_choice",
"topic": "tenses",
"difficulty": 1,
"prompt": "Выберите правильный вариант: I ___ English for two years.",
"inline_keyboard": [["learn"], ["am learning"], ["have been learning"]],
"correct_answer": "have been learning",
"explanation": "Есть for two years — действие длится до сих пор.",
"rule_reference": { "rule_id": "RULE_PPC", "title": "Present Perfect Continuous" },
"source": "конспект, урок 3"
},
{
"id": "q2",
"exercise_type": "fill_blank",
"topic": "tenses",
"difficulty": 1,
"prompt": "Вставьте пропущенное: I have been waiting ___ 9 утра.",
"expected_input": ["since"],
"explanation": "since — точка отсчёта, for — длительность.",
"rule_reference": { "rule_id": "RULE_PPC", "title": "Present Perfect Continuous" },
"source": "конспект, урок 3"
},
{
"id": "q3",
"exercise_type": "error_correction",
"topic": "tenses",
"difficulty": 2,
"prompt": "Найдите и исправьте ошибку: I have been waiting since two hours.",
"expected_input": ["I have been waiting for two hours."],
"explanation": "since — точка отсчёта, for — длительность.",
"rule_reference": { "rule_id": "RULE_PPC", "title": "Present Perfect Continuous" },
"source": "конспект, урок 3",
"hint": "https://www.grammarly.com/blog/since-vs-for/"
}
]
}
Что проверяет бот
Перед запуском бот читает файл целиком и собирает все проблемы сразу — не по одной. Достаточно, чтобы в файле было:
| Поле | Требование |
|---|---|
format |
начинается с tift-quiz; для этой версии — tift-quiz-v4 |
questions |
непустой список |
id |
есть у каждого вопроса и не повторяется |
prompt |
непустой текст задания |
exercise_type |
одно из восьми значений выше |
topic |
есть и совпадает с одним из topics[].id, если topics заполнен |
rule_reference.rule_id |
есть и совпадает с одним из rules_summary[].rule_id, если rules_summary заполнен |
| ответ | поле, соответствующее типу: correct_answer, expected_input или pairs |
source, source_ref |
таймкоды, если они есть, должны быть реальными: минуты и секунды от 0 до 59 |
Если topics или rules_summary оставить пустыми, проверка на совпадение пропускается. Но тогда topic и rule_reference.rule_id всё равно должны быть непустыми. Проще заполнить оба списка и следить, чтобы вопросы ссылались на них.
Как скормить файл боту
- Сохраните ответ модели в файл с расширением
.json, напримерquiz.json, в кодировке UTF-8. Проверьте, что он начинается с{и заканчивается}— без ```json и без «Вот ваш файл:». - В боте должен быть шаг Wait Input с типом ввода File upload. Бот приостанавливается на нём и ждёт документ.
- Отправьте
quiz.jsonботу как документ. Текст сообщением не подойдёт: шаг ждёт именно файл. - Файл сохраняется на сервере, и следующий узел — условие Uploaded quiz file is valid — скачивает его и проверяет.
- Если формат сломан, бот уходит в ветку «нет» и показывает на её сообщении список проблем — их берёт из
{ $user->extra.quiz_problems }. Исправьте всё из списка и отправьте файл снова — проверка ничего не запоминает, каждый раз читает файл заново. - Если файл валиден, сценарий идёт по ветке «да»: бот ведёт quiz по вопросам из файла, а ответы складывает в запись пользователя — как отвечать на каждый тип вопроса, написано в разделе Как проходит квиз.
Своя последовательность узлов выглядит так:
/start → Wait Input (File upload) → Condition (Uploaded quiz file is valid)
├── да → quiz по файлу
└── нет → «файл не подошёл, пришлите другой»
Как проходит квиз
Когда файл прошёл проверку, бот ведёт ученика по вопросам по одному:
| Тип вопроса | Как отвечают |
|---|---|
inline_choice, situational_scenario |
по кнопке на каждый вариант; ученик нажимает одну |
how_to_say, text_input_translation, fill_blank, error_correction, word_order |
ученик вводит ответ текстом |
match_pairs |
бот показывает термины и определения двумя списками, определения в другом порядке; ученик вводит каждую пару строкой в формате термин - определение |
После каждого ответа бот убирает вопрос из чата, показывает вердикт (✅ Correct! или ❌ Not quite) коротким сообщением без звука, отправляет пояснение следующим сообщением, а затем — следующий вопрос. Повторное нажатие на уже отвеченный вопрос игнорируется, поэтому один и тот же вопрос в чате не дублируется. В конце — счёт: сколько ответов верных, сколько неверных и сколько вопросов в файле. Ответы остаются в записи пользователя, так что неверный можно показать позже.
Два правила решают, засчитан ли введённый ответ:
- Текстовый ответ сравнивается целиком, без учёта регистра и пробелов вокруг. Он должен совпадать с одним из вариантов в
expected_input— правильная формулировка, которой в списке нет, считается ошибкой. - Ответ на
match_pairsсверяется по парам: строки могут идти в любом порядке, разделителем может быть-,:или=, регистр не важен — но все пары должны быть на месте и должны совпадать с файлом. После неверной попытки бот показывает правильное соответствие.
Частые ошибки
- Обёртка ```json. Модель любит добавлять её «для красоты». Уберите: файл должен начинаться с
{. - Умные кавычки. «Ёлочки» и
“лапки”вместо"ломают JSON. Замените на обычные. - Дубли
id. Дваq3— файл не примут. Нумеруйте по порядку. correct_answerне совпадает с вариантом. Даже лишний пробел в конце делает ответ неверным.- Пустой
expected_input. Список должен содержать хотя бы одну непустую строку. - Нереальный таймкод.
00:96:00не существует; бот это заметит. topicне изtopics. Если списки заполнены, ссылки должны совпадать точно.
Зачем повторять
Один тест — это не экзамен, а способ найти дыры. Пройдите его, посмотрите, что забылось, вернитесь к этим местам в конспекте. Через день пройдите снова, через неделю — ещё раз. Пять минут в день работают лучше, чем три часа перед дедлайном: вспоминание само по себе закрепляет материал, а ошибки показывают, что именно надо доучить.