1511 lines
84 KiB
Python
1511 lines
84 KiB
Python
"""
|
||
CEFR Level Vocabulary Tests & Assessment Engine (A1, A2, B1, B2).
|
||
Oxford 3000 / 5000 based curated benchmark Cloze Tap questions.
|
||
100% offline, zero-dependency, pure Python stdlib + SQLite.
|
||
Features:
|
||
- Fast 1-tap Cloze Tap quiz format.
|
||
- Automated Gap Ingestion: mistakes automatically create/update vocabulary cards
|
||
with status 'learning' in the user's SRS active deck with level tags.
|
||
- Per-level progress tracking (mastered, learning, percentage).
|
||
"""
|
||
|
||
import json
|
||
import sqlite3
|
||
import random
|
||
from typing import Dict, Any, List, Optional
|
||
from datetime import datetime
|
||
|
||
CEFR_LEVELS = ["A1", "A2", "B1", "B2"]
|
||
|
||
# Curated High-Yield CEFR Question Bank (Oxford 3000/5000)
|
||
# 40 items per level = 160 questions total
|
||
CURATED_CEFR_QUESTIONS: List[Dict[str, Any]] = [
|
||
# =========================================================================
|
||
# LEVEL A1 (Beginner: Daily life, basic items, common verbs & adjectives)
|
||
# =========================================================================
|
||
{
|
||
"level": "A1", "term": "expensive", "pos": "adjective", "phonetic": "/ɪkˈspen.sɪv/",
|
||
"translation": "дорогой (по цене)",
|
||
"sentence": "This watch is too ___ for me to buy right now.",
|
||
"options": ["expensive", "cheap", "simple", "clean"],
|
||
"explanation": "Expensive (дорогой) — имеет высокую стоимость. В контексте: слишком дорого, чтобы купить сейчас.",
|
||
},
|
||
{
|
||
"level": "A1", "term": "weather", "pos": "noun", "phonetic": "/ˈweð.ər/",
|
||
"translation": "погода",
|
||
"sentence": "The ___ today is sunny and wonderfully warm.",
|
||
"options": ["weather", "season", "journey", "holiday"],
|
||
"explanation": "Weather (погода) — состояние атмосферы на данный момент (солнечно, тепло).",
|
||
},
|
||
{
|
||
"level": "A1", "term": "remember", "pos": "verb", "phonetic": "/rɪˈmem.bər/",
|
||
"translation": "помнить, вспоминать",
|
||
"sentence": "I cannot ___ his phone number without looking at my phone.",
|
||
"options": ["remember", "forget", "decide", "repeat"],
|
||
"explanation": "Remember (помнить) — удерживать информацию в памяти.",
|
||
},
|
||
{
|
||
"level": "A1", "term": "careful", "pos": "adjective", "phonetic": "/ˈkeə.fəl/",
|
||
"translation": "осторожный, внимательный",
|
||
"sentence": "Be ___ when you cross the busy street!",
|
||
"options": ["careful", "boring", "dangerous", "wrong"],
|
||
"explanation": "Careful (осторожный) — обращающий внимание на безопасность.",
|
||
},
|
||
{
|
||
"level": "A1", "term": "breakfast", "pos": "noun", "phonetic": "/ˈbrek.fəst/",
|
||
"translation": "завтрак",
|
||
"sentence": "She always eats eggs and toast for ___.",
|
||
"options": ["breakfast", "dinner", "kitchen", "uniform"],
|
||
"explanation": "Breakfast (завтрак) — первый утренний прием пищи.",
|
||
},
|
||
{
|
||
"level": "A1", "term": "decide", "pos": "verb", "phonetic": "/dɪˈsaɪd/",
|
||
"translation": "решать, принимать решение",
|
||
"sentence": "We need to ___ where to go for our summer vacation.",
|
||
"options": ["decide", "invite", "listen", "travel"],
|
||
"explanation": "Decide (решать) — делать выбор между вариантами.",
|
||
},
|
||
{
|
||
"level": "A1", "term": "village", "pos": "noun", "phonetic": "/ˈvɪl.ɪdʒ/",
|
||
"translation": "деревня, село",
|
||
"sentence": "My grandparents live in a quiet ___ in the mountains.",
|
||
"options": ["village", "airport", "hospital", "library"],
|
||
"explanation": "Village (деревня) — небольшой населенный пункт за городом.",
|
||
},
|
||
{
|
||
"level": "A1", "term": "dangerous", "pos": "adjective", "phonetic": "/ˈdeɪn.dʒər.əs/",
|
||
"translation": "опасный",
|
||
"sentence": "Swimming in this stormy river is very ___.",
|
||
"options": ["dangerous", "exciting", "healthy", "wonderful"],
|
||
"explanation": "Dangerous (опасный) — способный причинить вред или травму.",
|
||
},
|
||
{
|
||
"level": "A1", "term": "invite", "pos": "verb", "phonetic": "/ɪnˈvaɪt/",
|
||
"translation": "приглашать",
|
||
"sentence": "They want to ___ all their classmates to the birthday party.",
|
||
"options": ["invite", "address", "listen", "welcome"],
|
||
"explanation": "Invite (приглашать) — звать кого-то на мероприятие.",
|
||
},
|
||
{
|
||
"level": "A1", "term": "borrow", "pos": "verb", "phonetic": "/ˈbɒr.əʊ/",
|
||
"translation": "одалживать, брать взаймы",
|
||
"sentence": "Can I ___ your pencil for a minute, please?",
|
||
"options": ["borrow", "lend", "spend", "repeat"],
|
||
"explanation": "Borrow (брать взаймы) — брать вещь во временное пользование.",
|
||
},
|
||
{
|
||
"level": "A1", "term": "healthy", "pos": "adjective", "phonetic": "/ˈhel.θi/",
|
||
"translation": "здоровый, полезный для здоровья",
|
||
"sentence": "Eating fresh fruit and vegetables keeps your body ___.",
|
||
"options": ["healthy", "boring", "wrong", "famous"],
|
||
"explanation": "Healthy (здоровый) — способствующий хорошему самочувствию.",
|
||
},
|
||
{
|
||
"level": "A1", "term": "journey", "pos": "noun", "phonetic": "/ˈdʒɜː.ni/",
|
||
"translation": "путешествие, поездка",
|
||
"sentence": "It was a long ___ by train across the entire country.",
|
||
"options": ["journey", "ticket", "minute", "station"],
|
||
"explanation": "Journey (путешествие, поездка) — передвижение из одного места в другое.",
|
||
},
|
||
{
|
||
"level": "A1", "term": "simple", "pos": "adjective", "phonetic": "/ˈsɪm.pəl/",
|
||
"translation": "простой, несложный",
|
||
"sentence": "The recipe is very ___ and only takes ten minutes.",
|
||
"options": ["simple", "expensive", "dangerous", "careful"],
|
||
"explanation": "Simple (простой) — легкий для понимания или выполнения.",
|
||
},
|
||
{
|
||
"level": "A1", "term": "foreign", "pos": "adjective", "phonetic": "/ˈfɒr.ən/",
|
||
"translation": "иностранный, зарубежный",
|
||
"sentence": "She enjoys learning ___ languages and studying their grammar.",
|
||
"options": ["foreign", "famous", "careful", "boring"],
|
||
"explanation": "Foreign (иностранный) — принадлежащий другой стране.",
|
||
},
|
||
{
|
||
"level": "A1", "term": "neighbor", "pos": "noun", "phonetic": "/ˈneɪ.bər/",
|
||
"translation": "сосед",
|
||
"sentence": "Our next-door ___ has three friendly dogs.",
|
||
"options": ["neighbor", "student", "parent", "person"],
|
||
"explanation": "Neighbor (сосед) — человек, живущий рядом.",
|
||
},
|
||
{
|
||
"level": "A1", "term": "exciting", "pos": "adjective", "phonetic": "/ɪkˈsaɪ.tɪŋ/",
|
||
"translation": "захватывающий, увлекательный",
|
||
"sentence": "Watching the championship final was really ___!",
|
||
"options": ["exciting", "boring", "wrong", "cheap"],
|
||
"explanation": "Exciting (захватывающий) — вызывающий сильные положительные эмоции.",
|
||
},
|
||
{
|
||
"level": "A1", "term": "listen", "pos": "verb", "phonetic": "/ˈlɪs.ən/",
|
||
"translation": "слушать",
|
||
"sentence": "You should ___ carefully to the teacher's instructions.",
|
||
"options": ["listen", "invite", "decide", "repeat"],
|
||
"explanation": "Listen (слушать) — обращать слуховое внимание на речь или звук.",
|
||
},
|
||
{
|
||
"level": "A1", "term": "hospital", "pos": "noun", "phonetic": "/ˈhɒs.pɪ.təl/",
|
||
"translation": "больница, госпиталь",
|
||
"sentence": "The doctor works in the largest city ___.",
|
||
"options": ["hospital", "airport", "station", "library"],
|
||
"explanation": "Hospital (больница) — медицинское учреждение для лечения больных.",
|
||
},
|
||
{
|
||
"level": "A1", "term": "ticket", "pos": "noun", "phonetic": "/ˈtɪk.ɪt/",
|
||
"translation": "билет",
|
||
"sentence": "Don't forget to buy a metro ___ before entering.",
|
||
"options": ["ticket", "package", "message", "question"],
|
||
"explanation": "Ticket (билет) — документ на право проезда или посещения.",
|
||
},
|
||
{
|
||
"level": "A1", "term": "boring", "pos": "adjective", "phonetic": "/ˈbɔː.rɪŋ/",
|
||
"translation": "скучный",
|
||
"sentence": "The lecture was so ___ that half the audience fell asleep.",
|
||
"options": ["boring", "exciting", "wonderful", "healthy"],
|
||
"explanation": "Boring (скучный) — не вызывающий интереса.",
|
||
},
|
||
{
|
||
"level": "A1", "term": "airport", "pos": "noun", "phonetic": "/ˈeə.pɔːt/",
|
||
"translation": "аэропорт",
|
||
"sentence": "We arrived at the ___ two hours before our departure.",
|
||
"options": ["airport", "hospital", "station", "village"],
|
||
"explanation": "Airport (аэропорт) — комплекс для взлета, посадки и обслуживания самолетов.",
|
||
},
|
||
{
|
||
"level": "A1", "term": "clothes", "pos": "noun", "phonetic": "/kləʊðz/",
|
||
"translation": "одежда",
|
||
"sentence": "He bought warm winter ___ because it was snowing outside.",
|
||
"options": ["clothes", "luggage", "tickets", "packages"],
|
||
"explanation": "Clothes (одежда) — предметы гардероба, надеваемые на тело.",
|
||
},
|
||
{
|
||
"level": "A1", "term": "repeat", "pos": "verb", "phonetic": "/rɪˈpiːt/",
|
||
"translation": "повторять",
|
||
"sentence": "Could you please ___ that question? I didn't hear you.",
|
||
"options": ["repeat", "decide", "invite", "borrow"],
|
||
"explanation": "Repeat (повторять) — сказать или сделать что-то еще раз.",
|
||
},
|
||
{
|
||
"level": "A1", "term": "famous", "pos": "adjective", "phonetic": "/ˈfeɪ.məs/",
|
||
"translation": "знаменитый, известный",
|
||
"sentence": "She is a very ___ actress known around the globe.",
|
||
"options": ["famous", "careful", "wrong", "simple"],
|
||
"explanation": "Famous (знаменитый) — широко известный многим людям.",
|
||
},
|
||
{
|
||
"level": "A1", "term": "message", "pos": "noun", "phonetic": "/ˈmes.ɪdʒ/",
|
||
"translation": "сообщение",
|
||
"sentence": "He sent me a text ___ to confirm the meeting time.",
|
||
"options": ["message", "question", "address", "ticket"],
|
||
"explanation": "Message (сообщение) — переданная информация в письменном или голосовом виде.",
|
||
},
|
||
{
|
||
"level": "A1", "term": "wonderful", "pos": "adjective", "phonetic": "/ˈwʌn.də.fəl/",
|
||
"translation": "замечательный, чудесный",
|
||
"sentence": "We had a ___ weekend walking by the lake.",
|
||
"options": ["wonderful", "dangerous", "boring", "wrong"],
|
||
"explanation": "Wonderful (чудесный) — приносящий огромное удовольствие или восхищение.",
|
||
},
|
||
{
|
||
"level": "A1", "term": "station", "pos": "noun", "phonetic": "/ˈsteɪ.ʃən/",
|
||
"translation": "станция, вокзал",
|
||
"sentence": "The train arrived at the central railway ___ on schedule.",
|
||
"options": ["station", "airport", "hospital", "village"],
|
||
"explanation": "Station (станция, вокзал) — остановочный пункт поездов или автобусов.",
|
||
},
|
||
{
|
||
"level": "A1", "term": "library", "pos": "noun", "phonetic": "/ˈlaɪ.brər.i/",
|
||
"translation": "библиотека",
|
||
"sentence": "Students go to the quiet ___ to read textbooks.",
|
||
"options": ["library", "hospital", "station", "airport"],
|
||
"explanation": "Library (библиотека) — учреждение для хранения и выдачи книг.",
|
||
},
|
||
{
|
||
"level": "A1", "term": "package", "pos": "noun", "phonetic": "/ˈpæk.ɪdʒ/",
|
||
"translation": "посылка, пакет",
|
||
"sentence": "The courier delivered a heavy cardboard ___ to my door.",
|
||
"options": ["package", "ticket", "message", "minute"],
|
||
"explanation": "Package (посылка, сверток) — упакованный груз для доставки.",
|
||
},
|
||
{
|
||
"level": "A1", "term": "travel", "pos": "verb", "phonetic": "/ˈtræv.əl/",
|
||
"translation": "путешествовать",
|
||
"sentence": "They plan to ___ across Europe during their holidays.",
|
||
"options": ["travel", "decide", "listen", "repeat"],
|
||
"explanation": "Travel (путешествовать) — совершать поездки в другие города или страны.",
|
||
},
|
||
{
|
||
"level": "A1", "term": "address", "pos": "noun", "phonetic": "/əˈdres/",
|
||
"translation": "адрес",
|
||
"sentence": "Please write down your postal ___ on the delivery form.",
|
||
"options": ["address", "message", "question", "ticket"],
|
||
"explanation": "Address (адрес) — указание места жительства или нахождения здания.",
|
||
},
|
||
{
|
||
"level": "A1", "term": "wrong", "pos": "adjective", "phonetic": "/rɒŋ/",
|
||
"translation": "неправильный, неверный",
|
||
"sentence": "I took the ___ bus and ended up in another neighborhood.",
|
||
"options": ["wrong", "simple", "healthy", "famous"],
|
||
"explanation": "Wrong (неправильный) — несоответствующий правде или правильному направлению.",
|
||
},
|
||
{
|
||
"level": "A1", "term": "yesterday", "pos": "adverb", "phonetic": "/ˈjes.tə.deɪ/",
|
||
"translation": "вчера",
|
||
"sentence": "I bought some new shoes ___ afternoon.",
|
||
"options": ["yesterday", "tomorrow", "always", "together"],
|
||
"explanation": "Yesterday (вчера) — в день, предшествующий сегодняшнему.",
|
||
},
|
||
{
|
||
"level": "A1", "term": "tomorrow", "pos": "adverb", "phonetic": "/təˈmɒr.əʊ/",
|
||
"translation": "завтра",
|
||
"sentence": "The bank will open again ___ morning at nine.",
|
||
"options": ["tomorrow", "yesterday", "always", "together"],
|
||
"explanation": "Tomorrow (завтра) — в день, следующий за сегодняшним.",
|
||
},
|
||
{
|
||
"level": "A1", "term": "holiday", "pos": "noun", "phonetic": "/ˈhɒl.ə.deɪ/",
|
||
"translation": "праздник, отпуск",
|
||
"sentence": "We booked a sunny two-week ___ by the Mediterranean sea.",
|
||
"options": ["holiday", "journey", "station", "airport"],
|
||
"explanation": "Holiday (отпуск, праздник) — период отдыха от работы или учебы.",
|
||
},
|
||
{
|
||
"level": "A1", "term": "uniform", "pos": "noun", "phonetic": "/ˈjuː.nɪ.fɔːm/",
|
||
"translation": "форма, униформа",
|
||
"sentence": "Police officers must wear a neat ___ on duty.",
|
||
"options": ["uniform", "clothes", "package", "ticket"],
|
||
"explanation": "Uniform (униформа) — установленная служебная форма одежды.",
|
||
},
|
||
{
|
||
"level": "A1", "term": "between", "pos": "preposition", "phonetic": "/bɪˈtwiːn/",
|
||
"translation": "между",
|
||
"sentence": "The pharmacy is situated ___ the bakery and the bank.",
|
||
"options": ["between", "together", "always", "because"],
|
||
"explanation": "Between (между) — в пространстве, разделяющем два объекта.",
|
||
},
|
||
{
|
||
"level": "A1", "term": "together", "pos": "adverb", "phonetic": "/təˈɡeð.ər/",
|
||
"translation": "вместе",
|
||
"sentence": "Let's work ___ to complete the project faster.",
|
||
"options": ["together", "between", "yesterday", "tomorrow"],
|
||
"explanation": "Together (вместе) — совместно с кем-либо.",
|
||
},
|
||
{
|
||
"level": "A1", "term": "welcome", "pos": "noun", "phonetic": "/ˈwel.kəm/",
|
||
"translation": "теплый прием, приветствие",
|
||
"sentence": "The host gave a cheerful ___ to all the guests.",
|
||
"options": ["welcome", "address", "message", "journey"],
|
||
"explanation": "Welcome (приветствие, радушный прием) — доброе отношение к прибывшим.",
|
||
},
|
||
{
|
||
"level": "A1", "term": "question", "pos": "noun", "phonetic": "/ˈkwes.tʃən/",
|
||
"translation": "вопрос",
|
||
"sentence": "If you are confused, raise your hand and ask a ___.",
|
||
"options": ["question", "message", "address", "ticket"],
|
||
"explanation": "Question (вопрос) — обращение с целью получить ответ.",
|
||
},
|
||
|
||
# =========================================================================
|
||
# LEVEL A2 (Elementary: Practical everyday conversation, work, actions)
|
||
# =========================================================================
|
||
{
|
||
"level": "A2", "term": "necessary", "pos": "adjective", "phonetic": "/ˈnes.ə.ser.i/",
|
||
"translation": "необходимый, нужный",
|
||
"sentence": "Good sleep is ___ for maintaining proper physical health.",
|
||
"options": ["necessary", "temporary", "available", "convenient"],
|
||
"explanation": "Necessary (необходимый) — требуется или обязательно для чего-либо.",
|
||
},
|
||
{
|
||
"level": "A2", "term": "improve", "pos": "verb", "phonetic": "/ɪmˈpruːv/",
|
||
"translation": "улучшать, совершенствовать",
|
||
"sentence": "Reading articles in English helps to ___ your vocabulary.",
|
||
"options": ["improve", "damage", "refuse", "doubt"],
|
||
"explanation": "Improve (улучшать) — делать что-то лучше или качественнее.",
|
||
},
|
||
{
|
||
"level": "A2", "term": "environment", "pos": "noun", "phonetic": "/ɪnˈvaɪ.rən.mənt/",
|
||
"translation": "окружающая среда",
|
||
"sentence": "Solar energy is clean and protects the ___.",
|
||
"options": ["environment", "culture", "condition", "experience"],
|
||
"explanation": "Environment (окружающая среда) — природный мир вокруг нас.",
|
||
},
|
||
{
|
||
"level": "A2", "term": "believe", "pos": "verb", "phonetic": "/bɪˈliːv/",
|
||
"translation": "верить, полагать",
|
||
"sentence": "I truly ___ that consistent effort brings great results.",
|
||
"options": ["believe", "remind", "avoid", "refuse"],
|
||
"explanation": "Believe (верить) — быть уверенным в правдивости чего-либо.",
|
||
},
|
||
{
|
||
"level": "A2", "term": "experience", "pos": "noun", "phonetic": "/ɪkˈspɪə.ri.əns/",
|
||
"translation": "опыт",
|
||
"sentence": "The applicant has four years of direct practical ___.",
|
||
"options": ["experience", "opinion", "solution", "culture"],
|
||
"explanation": "Experience (опыт) — знания и навыки, полученные в процессе деятельности.",
|
||
},
|
||
{
|
||
"level": "A2", "term": "describe", "pos": "verb", "phonetic": "/dɪˈskraɪb/",
|
||
"translation": "описывать",
|
||
"sentence": "Can you ___ what the missing backpack looks like?",
|
||
"options": ["describe", "connect", "afford", "damage"],
|
||
"explanation": "Describe (описывать) — рассказывать о признаках или свойствах предмета.",
|
||
},
|
||
{
|
||
"level": "A2", "term": "choice", "pos": "noun", "phonetic": "/tʃɔɪs/",
|
||
"translation": "выбор",
|
||
"sentence": "Customers have a wide ___ of fresh dishes on the menu.",
|
||
"options": ["choice", "condition", "reason", "degree"],
|
||
"explanation": "Choice (выбор) — возможность предпочесть один вариант другому.",
|
||
},
|
||
{
|
||
"level": "A2", "term": "condition", "pos": "noun", "phonetic": "/kənˈdɪʃ.ən/",
|
||
"translation": "состояние, условие",
|
||
"sentence": "The used bicycle is still in nearly perfect ___.",
|
||
"options": ["condition", "solution", "opinion", "culture"],
|
||
"explanation": "Condition (состояние) — физическая форма или сохранность объекта.",
|
||
},
|
||
{
|
||
"level": "A2", "term": "explain", "pos": "verb", "phonetic": "/ɪkˈspleɪn/",
|
||
"translation": "объяснять",
|
||
"sentence": "The engineer will ___ how to configure the router.",
|
||
"options": ["explain", "refuse", "avoid", "doubt"],
|
||
"explanation": "Explain (объяснять) — делать понятным логику или механизм.",
|
||
},
|
||
{
|
||
"level": "A2", "term": "reason", "pos": "noun", "phonetic": "/ˈriː.zən/",
|
||
"translation": "причина, повод",
|
||
"sentence": "The main ___ for his absence was a sudden fever.",
|
||
"options": ["reason", "effect", "degree", "habit"],
|
||
"explanation": "Reason (причина) — основание или повод для какого-либо события.",
|
||
},
|
||
{
|
||
"level": "A2", "term": "succeed", "pos": "verb", "phonetic": "/səkˈsiːd/",
|
||
"translation": "преуспевать, добиваться успеха",
|
||
"sentence": "If you prepare thoroughly, you will ___ in your exam.",
|
||
"options": ["succeed", "fail", "refuse", "avoid"],
|
||
"explanation": "Succeed (преуспевать) — достигать желаемой цели.",
|
||
},
|
||
{
|
||
"level": "A2", "term": "afford", "pos": "verb", "phonetic": "/əˈfɔːd/",
|
||
"translation": "позволить себе (финансово)",
|
||
"sentence": "We cannot ___ to rent such an expensive apartment right now.",
|
||
"options": ["afford", "connect", "damage", "manage"],
|
||
"explanation": "Afford (позволить себе) — иметь достаточно денег или ресурсов.",
|
||
},
|
||
{
|
||
"level": "A2", "term": "arrange", "pos": "verb", "phonetic": "/əˈreɪndʒ/",
|
||
"translation": "организовывать, договариваться",
|
||
"sentence": "Let's ___ a video call for Friday morning.",
|
||
"options": ["arrange", "refuse", "damage", "doubt"],
|
||
"explanation": "Arrange (организовывать) — согласовать план или встречу.",
|
||
},
|
||
{
|
||
"level": "A2", "term": "avoid", "pos": "verb", "phonetic": "/əˈvɔɪd/",
|
||
"translation": "избегать, уклоняться",
|
||
"sentence": "Drivers should always ___ speeding in residential areas.",
|
||
"options": ["avoid", "afford", "protect", "support"],
|
||
"explanation": "Avoid (избегать) — стараться не допустить нежелательного действия.",
|
||
},
|
||
{
|
||
"level": "A2", "term": "compare", "pos": "verb", "phonetic": "/kəmˈpeər/",
|
||
"translation": "сравнивать",
|
||
"sentence": "It is useful to ___ prices before buying airline tickets.",
|
||
"options": ["compare", "connect", "damage", "refuse"],
|
||
"explanation": "Compare (сравнивать) — сопоставлять объекты для выявления различий.",
|
||
},
|
||
{
|
||
"level": "A2", "term": "complete", "pos": "verb", "phonetic": "/kəmˈpliːt/",
|
||
"translation": "завершать, заполнять",
|
||
"sentence": "Please ___ the online registration form to continue.",
|
||
"options": ["complete", "remind", "manage", "avoid"],
|
||
"explanation": "Complete (завершать, заполнять) — доводить дело или форму до конца.",
|
||
},
|
||
{
|
||
"level": "A2", "term": "connect", "pos": "verb", "phonetic": "/kəˈnekt/",
|
||
"translation": "соединять, подключать",
|
||
"sentence": "Plug in the cable to ___ your phone to the computer.",
|
||
"options": ["connect", "damage", "refuse", "doubt"],
|
||
"explanation": "Connect (подключать) — устанавливать физическую или логическую связь.",
|
||
},
|
||
{
|
||
"level": "A2", "term": "contain", "pos": "verb", "phonetic": "/kənˈteɪn/",
|
||
"translation": "содержать в себе",
|
||
"sentence": "These citrus fruits ___ large quantities of vitamin C.",
|
||
"options": ["contain", "expect", "manage", "refuse"],
|
||
"explanation": "Contain (содержать) — включать в свой состав.",
|
||
},
|
||
{
|
||
"level": "A2", "term": "crowd", "pos": "noun", "phonetic": "/kraʊd/",
|
||
"translation": "толпа людей",
|
||
"sentence": "A cheering ___ filled the stadium during the game.",
|
||
"options": ["crowd", "flight", "future", "habit"],
|
||
"explanation": "Crowd (толпа) — большое скопление людей в одном месте.",
|
||
},
|
||
{
|
||
"level": "A2", "term": "culture", "pos": "noun", "phonetic": "/ˈkʌl.tʃər/",
|
||
"translation": "культура",
|
||
"sentence": "Living abroad exposes you to a totally different ___.",
|
||
"options": ["culture", "condition", "degree", "solution"],
|
||
"explanation": "Culture (культура) — традиции, обычаи и образ жизни народа.",
|
||
},
|
||
{
|
||
"level": "A2", "term": "damage", "pos": "noun", "phonetic": "/ˈdæm.ɪdʒ/",
|
||
"translation": "ущерб, повреждение",
|
||
"sentence": "The hailstorm caused severe ___ to the parked cars.",
|
||
"options": ["damage", "effect", "reason", "choice"],
|
||
"explanation": "Damage (ущерб) — физический вред или разрушение предметов.",
|
||
},
|
||
{
|
||
"level": "A2", "term": "degree", "pos": "noun", "phonetic": "/dɪˈɡriː/",
|
||
"translation": "градус, степень",
|
||
"sentence": "The temperature dropped by five ___ during the night.",
|
||
"options": ["degree", "condition", "reason", "choice"],
|
||
"explanation": "Degree (градус) — единица измерения температуры или угла.",
|
||
},
|
||
{
|
||
"level": "A2", "term": "depend", "pos": "verb", "phonetic": "/dɪˈpend/",
|
||
"translation": "зависеть",
|
||
"sentence": "Whether we go hiking will ___ on the weather tomorrow.",
|
||
"options": ["depend", "expect", "manage", "refuse"],
|
||
"explanation": "Depend (зависеть) — определяться внешними факторами.",
|
||
},
|
||
{
|
||
"level": "A2", "term": "discover", "pos": "verb", "phonetic": "/dɪˈskʌv.ər/",
|
||
"translation": "открывать, обнаруживать",
|
||
"sentence": "Researchers hope to ___ cleaner methods of energy production.",
|
||
"options": ["discover", "damage", "avoid", "refuse"],
|
||
"explanation": "Discover (обнаруживать) — находить ранее неизвестное.",
|
||
},
|
||
{
|
||
"level": "A2", "term": "discuss", "pos": "verb", "phonetic": "/dɪˈskʌs/",
|
||
"translation": "обсуждать",
|
||
"sentence": "Let's gather in the conference room to ___ the roadmap.",
|
||
"options": ["discuss", "refuse", "damage", "avoid"],
|
||
"explanation": "Discuss (обсуждать) — обмениваться мнениями по вопросу.",
|
||
},
|
||
{
|
||
"level": "A2", "term": "doubt", "pos": "noun", "phonetic": "/daʊt/",
|
||
"translation": "сомнение",
|
||
"sentence": "There is no ___ that he is telling the absolute truth.",
|
||
"options": ["doubt", "habit", "crowd", "flight"],
|
||
"explanation": "Doubt (сомнение) — отсутствие твердой уверенности.",
|
||
},
|
||
{
|
||
"level": "A2", "term": "effect", "pos": "noun", "phonetic": "/ɪˈfekt/",
|
||
"translation": "эффект, следствие",
|
||
"sentence": "The new law had a noticeable positive ___ on the economy.",
|
||
"options": ["effect", "reason", "degree", "choice"],
|
||
"explanation": "Effect (эффект) — результат или последствие определенного действия.",
|
||
},
|
||
{
|
||
"level": "A2", "term": "energy", "pos": "noun", "phonetic": "/ˈen.ə.dʒi/",
|
||
"translation": "энергия, силы",
|
||
"sentence": "Running every morning gives me a lot of positive ___.",
|
||
"options": ["energy", "culture", "condition", "solution"],
|
||
"explanation": "Energy (энергия) — физическая или моральная сила для действий.",
|
||
},
|
||
{
|
||
"level": "A2", "term": "expect", "pos": "verb", "phonetic": "/ɪkˈspekt/",
|
||
"translation": "ожидать, рассчитывать",
|
||
"sentence": "We ___ the parcel to arrive before five in the afternoon.",
|
||
"options": ["expect", "refuse", "damage", "avoid"],
|
||
"explanation": "Expect (ожидать) — рассчитывать на наступление события.",
|
||
},
|
||
{
|
||
"level": "A2", "term": "fail", "pos": "verb", "phonetic": "/feɪl/",
|
||
"translation": "потерпеть неудачу, провалить",
|
||
"sentence": "If students do not study, they may ___ the final test.",
|
||
"options": ["fail", "succeed", "manage", "support"],
|
||
"explanation": "Fail (провалить) — не справиться с поставленной задачей.",
|
||
},
|
||
{
|
||
"level": "A2", "term": "flight", "pos": "noun", "phonetic": "/flaɪt/",
|
||
"translation": "рейс, полет",
|
||
"sentence": "Their transatlantic ___ was smooth and arrived on time.",
|
||
"options": ["flight", "crowd", "habit", "future"],
|
||
"explanation": "Flight (рейс, полет) — путешествие на воздушном судне.",
|
||
},
|
||
{
|
||
"level": "A2", "term": "future", "pos": "noun", "phonetic": "/ˈfjuː.tʃər/",
|
||
"translation": "будущее",
|
||
"sentence": "Artificial intelligence will transform the ___ of work.",
|
||
"options": ["future", "culture", "flight", "condition"],
|
||
"explanation": "Future (будущее) — время, которое еще предстоит пережить.",
|
||
},
|
||
{
|
||
"level": "A2", "term": "guess", "pos": "noun", "phonetic": "/ɡes/",
|
||
"translation": "догадка, предположение",
|
||
"sentence": "If you don't know the exact answer, make an educated ___.",
|
||
"options": ["guess", "choice", "reason", "degree"],
|
||
"explanation": "Guess (догадка) — предположение без точных данных.",
|
||
},
|
||
{
|
||
"level": "A2", "term": "habit", "pos": "noun", "phonetic": "/ˈhæb.ɪt/",
|
||
"translation": "привычка",
|
||
"sentence": "Brushing your teeth before bed is a healthy personal ___.",
|
||
"options": ["habit", "crowd", "flight", "future"],
|
||
"explanation": "Habit (привычка) — регулярное автоматическое действие.",
|
||
},
|
||
{
|
||
"level": "A2", "term": "happen", "pos": "verb", "phonetic": "/ˈhæp.ən/",
|
||
"translation": "случаться, происходить",
|
||
"sentence": "Nobody predicted that such an accident could ___.",
|
||
"options": ["happen", "refuse", "avoid", "damage"],
|
||
"explanation": "Happen (происходить) — иметь место, совершаться.",
|
||
},
|
||
{
|
||
"level": "A2", "term": "imagine", "pos": "verb", "phonetic": "/ɪˈmædʒ.ɪn/",
|
||
"translation": "представлять, воображать",
|
||
"sentence": "It is hard to ___ modern life without high-speed internet.",
|
||
"options": ["imagine", "refuse", "damage", "avoid"],
|
||
"explanation": "Imagine (воображать) — создавать мысленный образ в голове.",
|
||
},
|
||
{
|
||
"level": "A2", "term": "manage", "pos": "verb", "phonetic": "/ˈmæn.ɪdʒ/",
|
||
"translation": "справляться, суметь сделать",
|
||
"sentence": "Despite heavy traffic, she did ___ to reach the office on time.",
|
||
"options": ["manage", "refuse", "avoid", "damage"],
|
||
"explanation": "Manage (справляться) — успешно преодолеть трудность и выполнить дело.",
|
||
},
|
||
{
|
||
"level": "A2", "term": "nature", "pos": "noun", "phonetic": "/ˈneɪ.tʃər/",
|
||
"translation": "природа",
|
||
"sentence": "A weekend hike in the woods lets you enjoy pure ___.",
|
||
"options": ["nature", "culture", "crowd", "flight"],
|
||
"explanation": "Nature (природа) — естественный мир растений, животных и ландшафтов.",
|
||
},
|
||
{
|
||
"level": "A2", "term": "notice", "pos": "verb", "phonetic": "/ˈnəʊ.tɪs/",
|
||
"translation": "замечать, обращать внимание",
|
||
"sentence": "Did you ___ that the bookstore moved to another street?",
|
||
"options": ["notice", "refuse", "damage", "avoid"],
|
||
"explanation": "Notice (замечать) — зафиксировать что-то зрением или вниманием.",
|
||
},
|
||
{
|
||
"level": "A2", "term": "opinion", "pos": "noun", "phonetic": "/əˈpɪn.jən/",
|
||
"translation": "мнение, точка зрения",
|
||
"sentence": "In my humble ___, this is the tastiest coffee in town.",
|
||
"options": ["opinion", "condition", "solution", "reason"],
|
||
"explanation": "Opinion (мнение) — личная оценка или суждение о предмете.",
|
||
},
|
||
|
||
# =========================================================================
|
||
# LEVEL B1 (Intermediate: Abstract concepts, professional life, reasoning)
|
||
# =========================================================================
|
||
{
|
||
"level": "B1", "term": "decision", "pos": "noun", "phonetic": "/dɪˈsɪʒ.ən/",
|
||
"translation": "решение",
|
||
"sentence": "Choosing a career path is a major life ___.",
|
||
"options": ["decision", "opportunity", "relationship", "behavior"],
|
||
"explanation": "Decision (решение) — сделанный выбор или заключение после размышлений.",
|
||
},
|
||
{
|
||
"level": "B1", "term": "achieve", "pos": "verb", "phonetic": "/əˈtʃiːv/",
|
||
"translation": "достигать (цели)",
|
||
"sentence": "With persistent practice, you can ___ fluency in English.",
|
||
"options": ["achieve", "interrupt", "hesitate", "negotiate"],
|
||
"explanation": "Achieve (достигать) — успешно завершить запланированное упорным трудом.",
|
||
},
|
||
{
|
||
"level": "B1", "term": "community", "pos": "noun", "phonetic": "/kəˈmjuː.nə.ti/",
|
||
"translation": "сообщество, общественность",
|
||
"sentence": "The local ___ gathered to build a new playground.",
|
||
"options": ["community", "relationship", "behavior", "mystery"],
|
||
"explanation": "Community (сообщество) — группа людей, объединенных общим местом или интересами.",
|
||
},
|
||
{
|
||
"level": "B1", "term": "convenient", "pos": "adjective", "phonetic": "/kənˈviː.ni.ənt/",
|
||
"translation": "удобный, подходящий",
|
||
"sentence": "Living near a subway station is extremely ___ for commuting.",
|
||
"options": ["convenient", "generous", "jealous", "temporary"],
|
||
"explanation": "Convenient (удобный) — подходящий по расположению или времени, экономящий силы.",
|
||
},
|
||
{
|
||
"level": "B1", "term": "develop", "pos": "verb", "phonetic": "/dɪˈvel.əp/",
|
||
"translation": "развивать, разрабатывать",
|
||
"sentence": "Our engineering squad will ___ a modern backend service.",
|
||
"options": ["develop", "hesitate", "interrupt", "negotiate"],
|
||
"explanation": "Develop (разрабатывать) — создавать, улучшать и развивать продукт.",
|
||
},
|
||
{
|
||
"level": "B1", "term": "opportunity", "pos": "noun", "phonetic": "/ˌɒp.əˈtʃuː.nə.ti/",
|
||
"translation": "возможность, шанс",
|
||
"sentence": "An internship abroad provides a rare ___ to gain global experience.",
|
||
"options": ["opportunity", "consequence", "requirement", "behavior"],
|
||
"explanation": "Opportunity (возможность) — благоприятное стечение обстоятельств.",
|
||
},
|
||
{
|
||
"level": "B1", "term": "relationship", "pos": "noun", "phonetic": "/rɪˈleɪ.ʃən.ʃɪp/",
|
||
"translation": "отношения, взаимосвязь",
|
||
"sentence": "Mutual trust is essential for building a lasting professional ___.",
|
||
"options": ["relationship", "community", "behavior", "mystery"],
|
||
"explanation": "Relationship (отношения) — связь и взаимодействие между людьми.",
|
||
},
|
||
{
|
||
"level": "B1", "term": "behavior", "pos": "noun", "phonetic": "/bɪˈheɪ.vjər/",
|
||
"translation": "поведение",
|
||
"sentence": "The teacher commended the student for respectful classroom ___.",
|
||
"options": ["behavior", "community", "decision", "mystery"],
|
||
"explanation": "Behavior (поведение) — манера вести себя и действовать.",
|
||
},
|
||
{
|
||
"level": "B1", "term": "challenge", "pos": "noun", "phonetic": "/ˈtʃæl.ɪndʒ/",
|
||
"translation": "сложная задача, вызов",
|
||
"sentence": "Migrating a legacy database is always a serious technical ___.",
|
||
"options": ["challenge", "opportunity", "consequence", "requirement"],
|
||
"explanation": "Challenge (вызов) — сложная задача, требующая усилий.",
|
||
},
|
||
{
|
||
"level": "B1", "term": "consequence", "pos": "noun", "phonetic": "/ˈkɒn.sɪ.kwəns/",
|
||
"translation": "последствие",
|
||
"sentence": "Losing your data is a direct ___ of not keeping backups.",
|
||
"options": ["consequence", "community", "behavior", "opportunity"],
|
||
"explanation": "Consequence (последствие) — результат, вытекающий из действия.",
|
||
},
|
||
{
|
||
"level": "B1", "term": "consider", "pos": "verb", "phonetic": "/kənˈsɪd.ər/",
|
||
"translation": "обдумывать, учитывать",
|
||
"sentence": "You should carefully ___ all pros and cons before signing.",
|
||
"options": ["consider", "hesitate", "interrupt", "negotiate"],
|
||
"explanation": "Consider (обдумывать) — взвешивать факторы перед решением.",
|
||
},
|
||
{
|
||
"level": "B1", "term": "definitely", "pos": "adverb", "phonetic": "/ˈdef.ɪ.nət.li/",
|
||
"translation": "определенно, точно",
|
||
"sentence": "I will ___ finish this pull request before leaving today.",
|
||
"options": ["definitely", "fluently", "generously", "logically"],
|
||
"explanation": "Definitely (определенно) — без малейших сомнений.",
|
||
},
|
||
{
|
||
"level": "B1", "term": "disappointed", "pos": "adjective", "phonetic": "/ˌdɪs.əˈpɔɪn.tɪd/",
|
||
"translation": "разочарованный",
|
||
"sentence": "We felt ___ when our favorite restaurant was closed.",
|
||
"options": ["disappointed", "confident", "generous", "sensible"],
|
||
"explanation": "Disappointed (разочарованный) — огорченный несбывшимися ожиданиями.",
|
||
},
|
||
{
|
||
"level": "B1", "term": "encourage", "pos": "verb", "phonetic": "/ɪnˈkʌr.ɪdʒ/",
|
||
"translation": "поощрять, подбадривать",
|
||
"sentence": "Mentors should always ___ beginners when learning new skills.",
|
||
"options": ["encourage", "interrupt", "hesitate", "negotiate"],
|
||
"explanation": "Encourage (поощрять) — вселять уверенность и поддерживать.",
|
||
},
|
||
{
|
||
"level": "B1", "term": "essential", "pos": "adjective", "phonetic": "/ɪˈsen.ʃəl/",
|
||
"translation": "существенный, неотъемлемый",
|
||
"sentence": "Writing tests is an ___ part of production software engineering.",
|
||
"options": ["essential", "temporary", "jealous", "modest"],
|
||
"explanation": "Essential (существенный) — фундаментально важный.",
|
||
},
|
||
{
|
||
"level": "B1", "term": "fluent", "pos": "adjective", "phonetic": "/ˈfluː.ənt/",
|
||
"translation": "беглый, свободно говорящий",
|
||
"sentence": "After years in London, she became completely ___ in English.",
|
||
"options": ["fluent", "generous", "modest", "logical"],
|
||
"explanation": "Fluent (беглый) — способный свободно и без запинок говорить на языке.",
|
||
},
|
||
{
|
||
"level": "B1", "term": "generous", "pos": "adjective", "phonetic": "/ˈdʒen.ər.əs/",
|
||
"translation": "щедрый, великодушный",
|
||
"sentence": "The sponsor made a very ___ contribution to the charity.",
|
||
"options": ["generous", "jealous", "temporary", "sensible"],
|
||
"explanation": "Generous (щедрый) — готовый охотно делиться ресурсами.",
|
||
},
|
||
{
|
||
"level": "B1", "term": "hesitate", "pos": "verb", "phonetic": "/ˈhez.ɪ.teɪt/",
|
||
"translation": "колебаться, сомневаться",
|
||
"sentence": "Please do not ___ to ask if any requirement is unclear.",
|
||
"options": ["hesitate", "negotiate", "achieve", "interrupt"],
|
||
"explanation": "Hesitate (колебаться) — медлить из-за сомнений или нерешительности.",
|
||
},
|
||
{
|
||
"level": "B1", "term": "influence", "pos": "noun", "phonetic": "/ˈɪn.flu.əns/",
|
||
"translation": "влияние, воздействие",
|
||
"sentence": "Good books have a deep positive ___ on personal growth.",
|
||
"options": ["influence", "behavior", "mystery", "challenge"],
|
||
"explanation": "Influence (влияние) — сила воздействия на мысли или действия других.",
|
||
},
|
||
{
|
||
"level": "B1", "term": "interrupt", "pos": "verb", "phonetic": "/ˌɪn.təˈrʌpt/",
|
||
"translation": "перебивать, прерывать",
|
||
"sentence": "It is impolite to ___ colleagues while they present their ideas.",
|
||
"options": ["interrupt", "hesitate", "encourage", "negotiate"],
|
||
"explanation": "Interrupt (перебивать) — нарушать ход чьей-то речи или действия.",
|
||
},
|
||
{
|
||
"level": "B1", "term": "jealous", "pos": "adjective", "phonetic": "/ˈdʒel.əs/",
|
||
"translation": "ревнивый, завистливый",
|
||
"sentence": "He was slightly ___ of his friend's new sports car.",
|
||
"options": ["jealous", "generous", "sensible", "modest"],
|
||
"explanation": "Jealous (завистливый) — испытывающий досаду от чужого успеха или имущества.",
|
||
},
|
||
{
|
||
"level": "B1", "term": "maintain", "pos": "verb", "phonetic": "/meɪnˈteɪn/",
|
||
"translation": "поддерживать, сохранять",
|
||
"sentence": "It takes daily habit to ___ high code quality in a repo.",
|
||
"options": ["maintain", "interrupt", "hesitate", "negotiate"],
|
||
"explanation": "Maintain (поддерживать) — сохранять объект в надлежащем состоянии.",
|
||
},
|
||
{
|
||
"level": "B1", "term": "mystery", "pos": "noun", "phonetic": "/ˈmɪs.tər.i/",
|
||
"translation": "тайна, загадка",
|
||
"sentence": "The origin of that ancient ruined temple remains an unsolved ___.",
|
||
"options": ["mystery", "behavior", "relationship", "decision"],
|
||
"explanation": "Mystery (загадка) — то, что трудно объяснить или понять.",
|
||
},
|
||
{
|
||
"level": "B1", "term": "negotiate", "pos": "verb", "phonetic": "/nəˈɡəʊ.ʃi.eɪt/",
|
||
"translation": "вести переговоры, договариваться",
|
||
"sentence": "The founders met to ___ the terms of their partnership.",
|
||
"options": ["negotiate", "interrupt", "hesitate", "encourage"],
|
||
"explanation": "Negotiate (вести переговоры) — обсуждать условия для достижения соглашения.",
|
||
},
|
||
{
|
||
"level": "B1", "term": "obvious", "pos": "adjective", "phonetic": "/ˈɒb.vi.əs/",
|
||
"translation": "очевидный, явный",
|
||
"sentence": "It is ___ that system security must be prioritized from day one.",
|
||
"options": ["obvious", "modest", "temporary", "jealous"],
|
||
"explanation": "Obvious (очевидный) — легко заметный и понятный без объяснений.",
|
||
},
|
||
{
|
||
"level": "B1", "term": "particular", "pos": "adjective", "phonetic": "/pəˈtɪk.jə.lər/",
|
||
"translation": "конкретный, определенный",
|
||
"sentence": "Was there any ___ reason why the service crashed?",
|
||
"options": ["particular", "fluent", "generous", "jealous"],
|
||
"explanation": "Particular (конкретный) — относящийся именно к данному случаю или лицу.",
|
||
},
|
||
{
|
||
"level": "B1", "term": "persuade", "pos": "verb", "phonetic": "/pəˈsweɪd/",
|
||
"translation": "убеждать",
|
||
"sentence": "She was able to ___ the manager with well-prepared statistics.",
|
||
"options": ["persuade", "interrupt", "hesitate", "maintain"],
|
||
"explanation": "Persuade (убеждать) — склонять к своей точке зрения доводами.",
|
||
},
|
||
{
|
||
"level": "B1", "term": "reliable", "pos": "adjective", "phonetic": "/rɪˈlaɪ.ə.bəl/",
|
||
"translation": "надежный",
|
||
"sentence": "We need a ___ database that does not lose data on restart.",
|
||
"options": ["reliable", "jealous", "temporary", "disappointed"],
|
||
"explanation": "Reliable (надежный) — верный, заслуживающий доверия.",
|
||
},
|
||
{
|
||
"level": "B1", "term": "requirement", "pos": "noun", "phonetic": "/rɪˈkwaɪə.mənt/",
|
||
"translation": "требование, условие",
|
||
"sentence": "Having Python installed is a mandatory ___ for this script.",
|
||
"options": ["requirement", "consequence", "community", "behavior"],
|
||
"explanation": "Requirement (требование) — обязательное условие.",
|
||
},
|
||
{
|
||
"level": "B1", "term": "sensible", "pos": "adjective", "phonetic": "/ˈsen.sə.bəl/",
|
||
"translation": "благоразумный, разумный",
|
||
"sentence": "Wearing a warm jacket in sub-zero weather is a very ___ choice.",
|
||
"options": ["sensible", "jealous", "temporary", "disappointed"],
|
||
"explanation": "Sensible (благоразумный) — продиктованный здравым смыслом.",
|
||
},
|
||
{
|
||
"level": "B1", "term": "suitable", "pos": "adjective", "phonetic": "/ˈsuː.tə.bəl/",
|
||
"translation": "подходящий, годный",
|
||
"sentence": "This quiet study room is very ___ for reading long texts.",
|
||
"options": ["suitable", "jealous", "disappointed", "fluent"],
|
||
"explanation": "Suitable (подходящий) — соответствующий целям и потребностям.",
|
||
},
|
||
{
|
||
"level": "B1", "term": "temporary", "pos": "adjective", "phonetic": "/ˈtem.pər.ər.i/",
|
||
"translation": "временный",
|
||
"sentence": "The detour is only ___ while the bridge is repaired.",
|
||
"options": ["temporary", "essential", "reliable", "fluent"],
|
||
"explanation": "Temporary (временный) — действующий лишь ограниченный период времени.",
|
||
},
|
||
{
|
||
"level": "B1", "term": "universal", "pos": "adjective", "phonetic": "/ˌjuː.nɪˈvɜː.səl/",
|
||
"translation": "всеобщий, универсальный",
|
||
"sentence": "Curiosity is a ___ characteristic of human nature.",
|
||
"options": ["universal", "temporary", "jealous", "modest"],
|
||
"explanation": "Universal (универсальный) — применимый повсеместно.",
|
||
},
|
||
{
|
||
"level": "B1", "term": "valuable", "pos": "adjective", "phonetic": "/ˈvæl.jə.bəl/",
|
||
"translation": "ценный, полезный",
|
||
"sentence": "Her feedback on our design provided ___ insights.",
|
||
"options": ["valuable", "jealous", "temporary", "disappointed"],
|
||
"explanation": "Valuable (ценный) — обладающий большой пользой или ценностью.",
|
||
},
|
||
{
|
||
"level": "B1", "term": "vulnerable", "pos": "adjective", "phonetic": "/ˈvʌl.nər.ə.bəl/",
|
||
"translation": "уязвимый",
|
||
"sentence": "Unpatched systems are highly ___ to automated cyber attacks.",
|
||
"options": ["vulnerable", "generous", "fluent", "sensible"],
|
||
"explanation": "Vulnerable (уязвимый) — слабо защищенный от вредоносных факторов.",
|
||
},
|
||
{
|
||
"level": "B1", "term": "ambitious", "pos": "adjective", "phonetic": "/æmˈbɪʃ.əs/",
|
||
"translation": "амбициозный, целеустремленный",
|
||
"sentence": "The startup announced an ___ plan to launch ten satellites.",
|
||
"options": ["ambitious", "jealous", "disappointed", "temporary"],
|
||
"explanation": "Ambitious (амбициозный) — ставящий смелые, масштабные цели.",
|
||
},
|
||
{
|
||
"level": "B1", "term": "confident", "pos": "adjective", "phonetic": "/ˈkɒn.fɪ.dənt/",
|
||
"translation": "уверенный в себе",
|
||
"sentence": "He gave a clear presentation because he felt ___ in his results.",
|
||
"options": ["confident", "disappointed", "jealous", "temporary"],
|
||
"explanation": "Confident (уверенный) — не сомневающийся в своих силах.",
|
||
},
|
||
{
|
||
"level": "B1", "term": "curious", "pos": "adjective", "phonetic": "/ˈkjʊə.ri.əs/",
|
||
"translation": "любознательный, любопытный",
|
||
"sentence": "Young children are endlessly ___ about the world around them.",
|
||
"options": ["curious", "disappointed", "jealous", "fluent"],
|
||
"explanation": "Curious (любознательный) — стремящийся узнать что-то новое.",
|
||
},
|
||
{
|
||
"level": "B1", "term": "efficient", "pos": "adjective", "phonetic": "/ɪˈfɪʃ.ənt/",
|
||
"translation": "эффективный, продуктивный",
|
||
"sentence": "Using keyboard shortcuts makes editing text much more ___.",
|
||
"options": ["efficient", "jealous", "temporary", "modest"],
|
||
"explanation": "Efficient (эффективный) — дающий максимальный результат при минимуме затрат.",
|
||
},
|
||
{
|
||
"level": "B1", "term": "reasonable", "pos": "adjective", "phonetic": "/ˈriː.zən.ə.bəl/",
|
||
"translation": "разумный, приемлемый",
|
||
"sentence": "The hotel offered comfortable clean rooms at a very ___ price.",
|
||
"options": ["reasonable", "jealous", "disappointed", "temporary"],
|
||
"explanation": "Reasonable (разумный, приемлемый) — адекватный, справедливый по цене или требованиям.",
|
||
},
|
||
|
||
# =========================================================================
|
||
# LEVEL B2 (Upper-Intermediate: Academic, nuanced, debate, precision)
|
||
# =========================================================================
|
||
{
|
||
"level": "B2", "term": "compromise", "pos": "noun", "phonetic": "/ˈkɒm.prə.maɪz/",
|
||
"translation": "компромисс, взаимная уступка",
|
||
"sentence": "After intense negotiations, both sides reached a workable ___.",
|
||
"options": ["compromise", "consensus", "ambiguity", "contradiction"],
|
||
"explanation": "Compromise (компромисс) — соглашение на основе взаимных уступок.",
|
||
},
|
||
{
|
||
"level": "B2", "term": "inevitable", "pos": "adjective", "phonetic": "/ɪnˈev.ɪ.tə.bəl/",
|
||
"translation": "неизбежный, неотвратимый",
|
||
"sentence": "Some degree of change is ___ in any growing organization.",
|
||
"options": ["inevitable", "plausible", "arbitrary", "versatile"],
|
||
"explanation": "Inevitable (неизбежный) — то, что невозможно предотвратить.",
|
||
},
|
||
{
|
||
"level": "B2", "term": "elaborate", "pos": "verb", "phonetic": "/ɪˈlæb.ə.reɪt/",
|
||
"translation": "вдаваться в детали, подробно разъяснять",
|
||
"sentence": "Could you please ___ on how this algorithm handles edge cases?",
|
||
"options": ["elaborate", "diminish", "facilitate", "terminate"],
|
||
"explanation": "Elaborate (подробно разъяснять) — раскрывать тему с дополнительными деталями.",
|
||
},
|
||
{
|
||
"level": "B2", "term": "coherent", "pos": "adjective", "phonetic": "/kəʊˈhɪə.rənt/",
|
||
"translation": "связный, логичный, последовательный",
|
||
"sentence": "She outlined a remarkably clear and ___ architectural design.",
|
||
"options": ["coherent", "arbitrary", "reluctant", "ambiguous"],
|
||
"explanation": "Coherent (связный, последовательный) — логически выстроенный без внутренних противоречий.",
|
||
},
|
||
{
|
||
"level": "B2", "term": "sophisticated", "pos": "adjective", "phonetic": "/səˈfɪs.tɪ.keɪ.tɪd/",
|
||
"translation": "сложный, утонченный, высокотехнологичный",
|
||
"sentence": "Modern network firewalls utilize ___ pattern detection.",
|
||
"options": ["sophisticated", "arbitrary", "preliminary", "reluctant"],
|
||
"explanation": "Sophisticated (высокотехнологичный) — обладающий высоким уровнем сложности и развития.",
|
||
},
|
||
{
|
||
"level": "B2", "term": "resilient", "pos": "adjective", "phonetic": "/rɪˈzɪl.jənt/",
|
||
"translation": "устойчивый к сбоям, жизнестойкий",
|
||
"sentence": "The distributed cluster proved ___ even when two nodes went down.",
|
||
"options": ["resilient", "reluctant", "arbitrary", "plausible"],
|
||
"explanation": "Resilient (жизнестойкий, отказоустойчивый) — способный быстро восстанавливаться после потрясений.",
|
||
},
|
||
{
|
||
"level": "B2", "term": "ambiguity", "pos": "noun", "phonetic": "/ˌæm.bɪˈɡjuː.ə.ti/",
|
||
"translation": "двусмысленность, неопределенность",
|
||
"sentence": "Good API specifications avoid any semantic ___.",
|
||
"options": ["ambiguity", "consensus", "compromise", "versatility"],
|
||
"explanation": "Ambiguity (двусмысленность) — наличие нескольких противоречивых трактовок.",
|
||
},
|
||
{
|
||
"level": "B2", "term": "comprehensive", "pos": "adjective", "phonetic": "/ˌkɒm.prɪˈhen.sɪv/",
|
||
"translation": "всесторонний, исчерпывающий",
|
||
"sentence": "The documentation provides a ___ guide to all SDK methods.",
|
||
"options": ["comprehensive", "reluctant", "arbitrary", "preliminary"],
|
||
"explanation": "Comprehensive (исчерпывающий) — охватывающий предмет целиком и во всех деталях.",
|
||
},
|
||
{
|
||
"level": "B2", "term": "profound", "pos": "adjective", "phonetic": "/prəˈfaʊnd/",
|
||
"translation": "глубокий, фундаментальный",
|
||
"sentence": "The discovery of antibiotics had a ___ impact on human longevity.",
|
||
"options": ["profound", "reluctant", "arbitrary", "plausible"],
|
||
"explanation": "Profound (глубокий) — оказывающий огромное и фундаментальное влияние.",
|
||
},
|
||
{
|
||
"level": "B2", "term": "contradictory", "pos": "adjective", "phonetic": "/ˌkɒn.trəˈdɪk.tər.i/",
|
||
"translation": "противоречивый",
|
||
"sentence": "The witness gave two completely ___ accounts of what occurred.",
|
||
"options": ["contradictory", "versatile", "preliminary", "resilient"],
|
||
"explanation": "Contradictory (противоречивый) — взаимоисключающий.",
|
||
},
|
||
{
|
||
"level": "B2", "term": "enhance", "pos": "verb", "phonetic": "/ɪnˈhɑːns/",
|
||
"translation": "усиливать, повышать качество",
|
||
"sentence": "Adding indexes to foreign keys will significantly ___ query speed.",
|
||
"options": ["enhance", "diminish", "terminate", "undermine"],
|
||
"explanation": "Enhance (усиливать) — увеличивать качество, силу или ценность.",
|
||
},
|
||
{
|
||
"level": "B2", "term": "facilitate", "pos": "verb", "phonetic": "/fəˈsɪl.ɪ.teɪt/",
|
||
"translation": "облегчать, способствовать",
|
||
"sentence": "Clean APIs ___ integration with third-party mobile applications.",
|
||
"options": ["facilitate", "undermine", "fluctuate", "terminate"],
|
||
"explanation": "Facilitate (способствовать) — делать процесс проще и быстрее.",
|
||
},
|
||
{
|
||
"level": "B2", "term": "advocate", "pos": "verb", "phonetic": "/ˈæd.və.keɪt/",
|
||
"translation": "выступать в защиту, отстаивать",
|
||
"sentence": "Senior developers strongly ___ for automated testing pipelines.",
|
||
"options": ["advocate", "terminate", "undermine", "fluctuate"],
|
||
"explanation": "Advocate (отстаивать) — публично поддерживать идею или принцип.",
|
||
},
|
||
{
|
||
"level": "B2", "term": "diminish", "pos": "verb", "phonetic": "/dɪˈmɪn.ɪʃ/",
|
||
"translation": "уменьшаться, ослабевать",
|
||
"sentence": "Regular backups help to ___ the risks of sudden data loss.",
|
||
"options": ["diminish", "enhance", "facilitate", "advocate"],
|
||
"explanation": "Diminish (уменьшать) — сокращать величину, масштаб или силу.",
|
||
},
|
||
{
|
||
"level": "B2", "term": "feasible", "pos": "adjective", "phonetic": "/ˈfiː.zə.bəl/",
|
||
"translation": "осуществимый, реальный",
|
||
"sentence": "Completing this migration in one sprint is technically ___.",
|
||
"options": ["feasible", "reluctant", "arbitrary", "ambiguous"],
|
||
"explanation": "Feasible (осуществимый) — вполне выполнимый при имеющихся ресурсах.",
|
||
},
|
||
{
|
||
"level": "B2", "term": "substantial", "pos": "adjective", "phonetic": "/səbˈstæn.ʃəl/",
|
||
"translation": "существенный, значительный",
|
||
"sentence": "We noticed a ___ reduction in server memory usage after tuning.",
|
||
"options": ["substantial", "preliminary", "reluctant", "arbitrary"],
|
||
"explanation": "Substantial (значительный) — весомый по объему или значению.",
|
||
},
|
||
{
|
||
"level": "B2", "term": "subsequent", "pos": "adjective", "phonetic": "/ˈsʌb.sɪ.kwənt/",
|
||
"translation": "последующий",
|
||
"sentence": "The initial build broke, but all ___ builds passed cleanly.",
|
||
"options": ["subsequent", "reluctant", "arbitrary", "versatile"],
|
||
"explanation": "Subsequent (последующий) — происходящий после чего-либо.",
|
||
},
|
||
{
|
||
"level": "B2", "term": "perceive", "pos": "verb", "phonetic": "/pəˈsiːv/",
|
||
"translation": "воспринимать, осознавать",
|
||
"sentence": "Different users ___ software latency in very distinct ways.",
|
||
"options": ["perceive", "allocate", "terminate", "undermine"],
|
||
"explanation": "Perceive (воспринимать) — осознавать через органы чувств или разум.",
|
||
},
|
||
{
|
||
"level": "B2", "term": "convey", "pos": "verb", "phonetic": "/kənˈveɪ/",
|
||
"translation": "передавать, выражать (мысль)",
|
||
"sentence": "Clear charts can ___ complex statistical insights at a glance.",
|
||
"options": ["convey", "allocate", "terminate", "fluctuate"],
|
||
"explanation": "Convey (передавать) — делать мысль или значение понятными другим.",
|
||
},
|
||
{
|
||
"level": "B2", "term": "crucial", "pos": "adjective", "phonetic": "/ˈkruː.ʃəl/",
|
||
"translation": "решающий, критически важный",
|
||
"sentence": "Code reviews are ___ for maintaining high quality in shared repos.",
|
||
"options": ["crucial", "arbitrary", "reluctant", "plausible"],
|
||
"explanation": "Crucial (критически важный) — определяющий успех или провал.",
|
||
},
|
||
{
|
||
"level": "B2", "term": "deduce", "pos": "verb", "phonetic": "/dɪˈdʒuːs/",
|
||
"translation": "делать логический вывод, выводить",
|
||
"sentence": "From the error stack trace, we can easily ___ the exact root cause.",
|
||
"options": ["deduce", "allocate", "undermine", "fluctuate"],
|
||
"explanation": "Deduce (делать вывод) — приходить к умозаключению на основе фактов.",
|
||
},
|
||
{
|
||
"level": "B2", "term": "discrete", "pos": "adjective", "phonetic": "/dɪˈskriːt/",
|
||
"translation": "дискретный, раздельный, обособленный",
|
||
"sentence": "The protocol breaks streaming data into small ___ chunks.",
|
||
"options": ["discrete", "reluctant", "arbitrary", "plausible"],
|
||
"explanation": "Discrete (дискретный) — состоящий из отдельных четких единиц.",
|
||
},
|
||
{
|
||
"level": "B2", "term": "explicit", "pos": "adjective", "phonetic": "/ɪkˈsplɪs.ɪt/",
|
||
"translation": "явный, четко выраженный",
|
||
"sentence": "The configuration provides ___ timeout limits for network calls.",
|
||
"options": ["explicit", "ambiguous", "reluctant", "arbitrary"],
|
||
"explanation": "Explicit (явный, точный) — сформулированный прямо и без двусмысленности.",
|
||
},
|
||
{
|
||
"level": "B2", "term": "fundamental", "pos": "adjective", "phonetic": "/ˌfʌn.dəˈmen.təl/",
|
||
"translation": "фундаментальный, основополагающий",
|
||
"sentence": "Understanding pointers is a ___ concept in systems programming.",
|
||
"options": ["fundamental", "arbitrary", "reluctant", "preliminary"],
|
||
"explanation": "Fundamental (основополагающий) — служащий базисом для всего остального.",
|
||
},
|
||
{
|
||
"level": "B2", "term": "hierarchical", "pos": "adjective", "phonetic": "/ˌhaɪəˈrɑː.kɪ.kəl/",
|
||
"translation": "иерархический",
|
||
"sentence": "Filesystems organize documents in a strict ___ folder tree.",
|
||
"options": ["hierarchical", "arbitrary", "reluctant", "plausible"],
|
||
"explanation": "Hierarchical (иерархический) — построенный по принципу соподчинения уровней.",
|
||
},
|
||
{
|
||
"level": "B2", "term": "implicit", "pos": "adjective", "phonetic": "/ɪmˈplɪs.ɪt/",
|
||
"translation": "неявный, подразумеваемый",
|
||
"sentence": "There is an ___ trust assumption between these internal services.",
|
||
"options": ["implicit", "explicit", "arbitrary", "versatile"],
|
||
"explanation": "Implicit (неявный, подразумеваемый) — не выраженный прямо, но очевидный по смыслу.",
|
||
},
|
||
{
|
||
"level": "B2", "term": "inherent", "pos": "adjective", "phonetic": "/ɪnˈher.ənt/",
|
||
"translation": "присущий, неотъемлемый",
|
||
"sentence": "Network latency is an ___ property of distributed cloud systems.",
|
||
"options": ["inherent", "preliminary", "reluctant", "arbitrary"],
|
||
"explanation": "Inherent (присущий) — составляющий неотъемлемую природную черту объекта.",
|
||
},
|
||
{
|
||
"level": "B2", "term": "integrate", "pos": "verb", "phonetic": "/ˈɪn.tɪ.ɡreɪt/",
|
||
"translation": "интегрировать, объединять",
|
||
"sentence": "We want to ___ the payment gateway seamlessly into the checkout.",
|
||
"options": ["integrate", "undermine", "terminate", "fluctuate"],
|
||
"explanation": "Integrate (интегрировать) — соединять части в единое целое.",
|
||
},
|
||
{
|
||
"level": "B2", "term": "justify", "pos": "verb", "phonetic": "/ˈdʒʌs.tɪ.faɪ/",
|
||
"translation": "оправдывать, обосновывать",
|
||
"sentence": "You should bring performance metrics to ___ the rewrite.",
|
||
"options": ["justify", "undermine", "terminate", "fluctuate"],
|
||
"explanation": "Justify (обосновывать) — приводить разумные доводы в защиту решения.",
|
||
},
|
||
{
|
||
"level": "B2", "term": "preliminary", "pos": "adjective", "phonetic": "/prɪˈlɪm.ɪ.nər.i/",
|
||
"translation": "предварительный",
|
||
"sentence": "These are only the ___ benchmark results; full tests run tonight.",
|
||
"options": ["preliminary", "reluctant", "arbitrary", "versatile"],
|
||
"explanation": "Preliminary (предварительный) — предшествующий окончательному этапу.",
|
||
},
|
||
{
|
||
"level": "B2", "term": "random", "pos": "adjective", "phonetic": "/ˈræn.dəm/",
|
||
"translation": "случайный, произвольный",
|
||
"sentence": "The program selects test samples using a uniform ___ distribution.",
|
||
"options": ["random", "reluctant", "plausible", "resilient"],
|
||
"explanation": "Random (случайный) — выбранный без закономерности или предвзятости.",
|
||
},
|
||
{
|
||
"level": "B2", "term": "reluctant", "pos": "adjective", "phonetic": "/rɪˈlʌk.tənt/",
|
||
"translation": "неохотный, сомневающийся",
|
||
"sentence": "He was ___ to rewrite working code without clear justification.",
|
||
"options": ["reluctant", "resilient", "versatile", "plausible"],
|
||
"explanation": "Reluctant (неохотный) — делающий что-либо с неохотой или сомнением.",
|
||
},
|
||
{
|
||
"level": "B2", "term": "simultaneous", "pos": "adjective", "phonetic": "/ˌsɪm.əlˈteɪ.ni.əs/",
|
||
"translation": "одновременный",
|
||
"sentence": "The database engine easily handles hundreds of ___ read queries.",
|
||
"options": ["simultaneous", "reluctant", "arbitrary", "preliminary"],
|
||
"explanation": "Simultaneous (одновременный) — происходящий в одно и то же мгновение.",
|
||
},
|
||
{
|
||
"level": "B2", "term": "undermine", "pos": "verb", "phonetic": "/ˌʌn.dəˈmaɪn/",
|
||
"translation": "подрывать, ослаблять",
|
||
"sentence": "Skipping validation steps will inevitably ___ system reliability.",
|
||
"options": ["undermine", "facilitate", "enhance", "advocate"],
|
||
"explanation": "Undermine (подрывать) — постепенно разрушать или ослаблять основы.",
|
||
},
|
||
{
|
||
"level": "B2", "term": "accommodate", "pos": "verb", "phonetic": "/əˈkɒm.ə.deɪt/",
|
||
"translation": "вмещать, приспосабливать",
|
||
"sentence": "The new server cluster can easily ___ millions of daily visitors.",
|
||
"options": ["accommodate", "undermine", "terminate", "fluctuate"],
|
||
"explanation": "Accommodate (вмещать) — иметь достаточно места или ресурсов для кого-либо.",
|
||
},
|
||
{
|
||
"level": "B2", "term": "allocate", "pos": "verb", "phonetic": "/ˈæl.ə.keɪt/",
|
||
"translation": "выделять (ресурсы, память)",
|
||
"sentence": "We need to ___ sufficient RAM for the in-memory cache.",
|
||
"options": ["allocate", "undermine", "terminate", "fluctuate"],
|
||
"explanation": "Allocate (выделять) — распределять или закреплять ресурсы под задачу.",
|
||
},
|
||
{
|
||
"level": "B2", "term": "arbitrary", "pos": "adjective", "phonetic": "/ˈɑː.bɪ.trər.i/",
|
||
"translation": "произвольный, случайный (без четкого правила)",
|
||
"sentence": "Do not pick an ___ timeout value; measure actual latencies.",
|
||
"options": ["arbitrary", "resilient", "coherent", "versatile"],
|
||
"explanation": "Arbitrary (произвольный) — основанный на случайном выборе, а не на правиле.",
|
||
},
|
||
{
|
||
"level": "B2", "term": "consensus", "pos": "noun", "phonetic": "/kənˈsen.səs/",
|
||
"translation": "консенсус, общее согласие",
|
||
"sentence": "The architecture committee finally reached a general ___.",
|
||
"options": ["consensus", "ambiguity", "contradiction", "compromise"],
|
||
"explanation": "Consensus (консенсус) — общее единогласие мнений всех сторон.",
|
||
},
|
||
{
|
||
"level": "B2", "term": "fluctuate", "pos": "verb", "phonetic": "/ˈflʌk.tʃu.eɪt/",
|
||
"translation": "колебаться, меняться",
|
||
"sentence": "Internet speeds can ___ depending on peak network hours.",
|
||
"options": ["fluctuate", "undermine", "terminate", "advocate"],
|
||
"explanation": "Fluctuate (колебаться) — непрерывно изменяться вверх и вниз.",
|
||
},
|
||
{
|
||
"level": "B2", "term": "plausible", "pos": "adjective", "phonetic": "/ˈplɔː.zə.bəl/",
|
||
"translation": "правдоподобный, вероятный",
|
||
"sentence": "His explanation for the memory leak sounded completely ___.",
|
||
"options": ["plausible", "reluctant", "arbitrary", "preliminary"],
|
||
"explanation": "Plausible (правдоподобный) — заслуживающий доверия, вероятный.",
|
||
},
|
||
]
|
||
|
||
|
||
def seed_cefr_questions(conn: sqlite3.Connection) -> int:
|
||
"""
|
||
Populates cefr_questions table with curated Oxford 3000/5000 benchmark questions.
|
||
Safe and idempotent (using INSERT OR IGNORE).
|
||
"""
|
||
inserted = 0
|
||
for q in CURATED_CEFR_QUESTIONS:
|
||
options_str = json.dumps(q["options"], ensure_ascii=False)
|
||
cursor = conn.execute(
|
||
"""
|
||
INSERT OR IGNORE INTO cefr_questions (
|
||
level, term, translation, pos, phonetic, sentence, options_json, explanation
|
||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||
""",
|
||
(
|
||
q["level"],
|
||
q["term"],
|
||
q["translation"],
|
||
q.get("pos", ""),
|
||
q.get("phonetic", ""),
|
||
q["sentence"],
|
||
options_str,
|
||
q.get("explanation", ""),
|
||
),
|
||
)
|
||
if cursor.rowcount > 0:
|
||
inserted += 1
|
||
return inserted
|
||
|
||
|
||
def get_cefr_level_summaries(conn: sqlite3.Connection, user_id: int) -> List[Dict[str, Any]]:
|
||
"""
|
||
Computes real-time progress metrics for each CEFR level (A1, A2, B1, B2) for user.
|
||
"""
|
||
summaries = []
|
||
level_titles = {
|
||
"A1": "Beginner (Начальный)",
|
||
"A2": "Elementary (Базовый)",
|
||
"B1": "Intermediate (Средний)",
|
||
"B2": "Upper-Intermediate (Продвинутый)",
|
||
}
|
||
|
||
for lvl in CEFR_LEVELS:
|
||
total_q = conn.execute(
|
||
"SELECT COUNT(*) FROM cefr_questions WHERE level = ?", (lvl,)
|
||
).fetchone()[0]
|
||
|
||
row = conn.execute(
|
||
"""
|
||
SELECT
|
||
SUM(CASE WHEN is_mastered = 1 THEN 1 ELSE 0 END) as mastered_cnt,
|
||
SUM(CASE WHEN mistakes > 0 AND is_mastered = 0 THEN 1 ELSE 0 END) as in_learning_cnt,
|
||
COUNT(*) as attempted_cnt
|
||
FROM cefr_progress
|
||
WHERE user_id = ? AND level = ?
|
||
""",
|
||
(user_id, lvl),
|
||
).fetchone()
|
||
|
||
mastered = row["mastered_cnt"] or 0
|
||
in_learning = row["in_learning_cnt"] or 0
|
||
attempted = row["attempted_cnt"] or 0
|
||
|
||
# Also count active SRS cards with this level tag
|
||
srs_tag = f"level-{lvl.lower()}"
|
||
active_vocab_cards = conn.execute(
|
||
"""
|
||
SELECT COUNT(*) FROM vocabulary_cards
|
||
WHERE user_id = ? AND tags LIKE ?
|
||
""",
|
||
(user_id, f"%{srs_tag}%"),
|
||
).fetchone()[0]
|
||
|
||
pct = int(round((mastered / total_q) * 100)) if total_q > 0 else 0
|
||
|
||
summaries.append({
|
||
"level": lvl,
|
||
"title": level_titles.get(lvl, lvl),
|
||
"total_questions": total_q,
|
||
"mastered_count": mastered,
|
||
"in_learning_count": in_learning,
|
||
"attempted_count": attempted,
|
||
"srs_cards_count": active_vocab_cards,
|
||
"progress_percent": pct,
|
||
})
|
||
|
||
return summaries
|
||
|
||
|
||
def get_cefr_quiz_batch(
|
||
conn: sqlite3.Connection,
|
||
user_id: int,
|
||
level: str,
|
||
count: int = 10,
|
||
mode: str = "all",
|
||
) -> List[Dict[str, Any]]:
|
||
"""
|
||
Fetches next batch of Cloze Tap questions for the selected level.
|
||
If mode == 'mistakes', returns questions where user made mistakes and hasn't mastered yet.
|
||
Otherwise prioritizes unattempted questions, then review of mistakes.
|
||
Options are randomized per question. Correct answer is kept hidden from client.
|
||
"""
|
||
clean_level = level.upper().strip()
|
||
if clean_level not in CEFR_LEVELS:
|
||
clean_level = "A1"
|
||
count = max(1, min(count, 30))
|
||
|
||
if mode == "mistakes":
|
||
rows = conn.execute(
|
||
"""
|
||
SELECT q.id, q.level, q.sentence, q.translation, q.pos, q.options_json
|
||
FROM cefr_questions q
|
||
JOIN cefr_progress p ON q.id = p.question_id
|
||
WHERE p.user_id = ? AND q.level = ? AND p.is_mastered = 0 AND p.mistakes > 0
|
||
ORDER BY p.last_tested_at ASC
|
||
LIMIT ?
|
||
""",
|
||
(user_id, clean_level, count),
|
||
).fetchall()
|
||
else:
|
||
# 1. Unattempted questions
|
||
rows = conn.execute(
|
||
"""
|
||
SELECT q.id, q.level, q.sentence, q.translation, q.pos, q.options_json
|
||
FROM cefr_questions q
|
||
LEFT JOIN cefr_progress p ON q.id = p.question_id AND p.user_id = ?
|
||
WHERE q.level = ? AND (p.question_id IS NULL OR p.is_mastered = 0)
|
||
ORDER BY CASE WHEN p.question_id IS NULL THEN 0 ELSE 1 END,
|
||
p.last_tested_at ASC,
|
||
q.id ASC
|
||
LIMIT ?
|
||
""",
|
||
(user_id, clean_level, count),
|
||
).fetchall()
|
||
|
||
# If not enough, fill with any from this level
|
||
if len(rows) < count:
|
||
needed = count - len(rows)
|
||
existing_ids = [r["id"] for r in rows]
|
||
placeholders = ",".join(["?"] * len(existing_ids)) if existing_ids else "-1"
|
||
extra = conn.execute(
|
||
f"""
|
||
SELECT q.id, q.level, q.sentence, q.translation, q.pos, q.options_json
|
||
FROM cefr_questions q
|
||
WHERE q.level = ? AND q.id NOT IN ({placeholders})
|
||
ORDER BY q.id ASC
|
||
LIMIT ?
|
||
""",
|
||
[clean_level] + existing_ids + [needed],
|
||
).fetchall()
|
||
rows = list(rows) + list(extra)
|
||
|
||
quiz_items = []
|
||
for r in rows:
|
||
try:
|
||
options = json.loads(r["options_json"])
|
||
except Exception:
|
||
options = []
|
||
# Randomize options order
|
||
shuffled_options = list(options)
|
||
random.shuffle(shuffled_options)
|
||
|
||
quiz_items.append({
|
||
"id": r["id"],
|
||
"level": r["level"],
|
||
"sentence": r["sentence"],
|
||
"clue": r["translation"],
|
||
"pos": r["pos"] or "",
|
||
"options": shuffled_options,
|
||
})
|
||
|
||
return quiz_items
|
||
|
||
|
||
def process_cefr_answer(
|
||
conn: sqlite3.Connection,
|
||
user_id: int,
|
||
question_id: int,
|
||
selected_option: str,
|
||
) -> Dict[str, Any]:
|
||
"""
|
||
Validates user's Cloze Tap choice.
|
||
- If correct: marks question mastered.
|
||
- If mistake:
|
||
- marks mistake in cefr_progress
|
||
- AUTOMATIC GAP INGESTION: creates or updates vocabulary_card in user's dictionary
|
||
with srs_state='learning', interval=0, next_review=now, level tags so it appears
|
||
in daily morning SRS training!
|
||
"""
|
||
q_row = conn.execute(
|
||
"SELECT * FROM cefr_questions WHERE id = ?", (question_id,)
|
||
).fetchone()
|
||
|
||
if not q_row:
|
||
return {"error": "Question not found"}
|
||
|
||
target_term = q_row["term"].strip()
|
||
selected_clean = (selected_option or "").strip()
|
||
is_correct = selected_clean.lower() == target_term.lower()
|
||
explanation = q_row["explanation"] or ""
|
||
level = q_row["level"]
|
||
phonetic = q_row["phonetic"] or ""
|
||
pos = q_row["pos"] or ""
|
||
translation = q_row["translation"] or ""
|
||
sentence_with_term = q_row["sentence"].replace("___", target_term)
|
||
|
||
# 1. Update or Insert into cefr_progress
|
||
prog_row = conn.execute(
|
||
"SELECT * FROM cefr_progress WHERE user_id = ? AND question_id = ?",
|
||
(user_id, question_id),
|
||
).fetchone()
|
||
|
||
if prog_row:
|
||
new_attempts = prog_row["attempts"] + 1
|
||
new_mistakes = prog_row["mistakes"] + (0 if is_correct else 1)
|
||
new_mastered = 1 if is_correct else 0
|
||
conn.execute(
|
||
"""
|
||
UPDATE cefr_progress
|
||
SET is_mastered = ?, attempts = ?, mistakes = ?, last_tested_at = CURRENT_TIMESTAMP
|
||
WHERE id = ?
|
||
""",
|
||
(new_mastered, new_attempts, new_mistakes, prog_row["id"]),
|
||
)
|
||
else:
|
||
conn.execute(
|
||
"""
|
||
INSERT INTO cefr_progress (user_id, question_id, level, is_mastered, attempts, mistakes, last_tested_at)
|
||
VALUES (?, ?, ?, ?, 1, ?, CURRENT_TIMESTAMP)
|
||
""",
|
||
(user_id, question_id, level, 1 if is_correct else 0, 0 if is_correct else 1),
|
||
)
|
||
|
||
# 2. Activity log entry for heatmap streak calculation
|
||
# We log to srs_logs if card exists or placeholder so streak increases
|
||
card_created = False
|
||
card_updated = False
|
||
target_card_id = None
|
||
|
||
if not is_correct:
|
||
# =====================================================================
|
||
# AUTOMATED GAP INGESTION (Crucial Pedagogical Requirement)
|
||
# =====================================================================
|
||
existing_card = conn.execute(
|
||
"SELECT * FROM vocabulary_cards WHERE user_id = ? AND lower(trim(term)) = ?",
|
||
(user_id, target_term.lower()),
|
||
).fetchone()
|
||
|
||
level_tag = f"level-{level.lower()}"
|
||
col_name = f"Уровни CEFR ({level})"
|
||
|
||
if not existing_card:
|
||
# Create fresh card in 'learning' state for daily SRS
|
||
cur = conn.execute(
|
||
"""
|
||
INSERT INTO vocabulary_cards (
|
||
user_id, term, translation, context_sentence, phonetic, audio_url,
|
||
part_of_speech, definition_en, tags, notes, collection,
|
||
srs_reps, srs_interval, srs_ease, srs_state, error_count,
|
||
srs_next_review
|
||
) VALUES (?, ?, ?, ?, ?, '', ?, ?, ?, ?, ?, 0, 0, 2.5, 'learning', 1, CURRENT_TIMESTAMP)
|
||
""",
|
||
(
|
||
user_id,
|
||
target_term,
|
||
translation,
|
||
sentence_with_term,
|
||
phonetic,
|
||
pos,
|
||
explanation,
|
||
f"{level_tag}, cefr-test, test-mistake",
|
||
f"Добавлено из теста уровня {level}",
|
||
col_name,
|
||
),
|
||
)
|
||
target_card_id = cur.lastrowid
|
||
card_created = True
|
||
else:
|
||
# Card already in library: adjust state and bring into today's SRS queue
|
||
target_card_id = existing_card["id"]
|
||
existing_tags = set([t.strip() for t in (existing_card["tags"] or "").split(",") if t.strip()])
|
||
existing_tags.add(level_tag)
|
||
existing_tags.add("cefr-test")
|
||
updated_tags = ", ".join(sorted(existing_tags))
|
||
|
||
updated_context = existing_card["context_sentence"] or ""
|
||
if sentence_with_term and sentence_with_term not in updated_context:
|
||
updated_context = f"{updated_context}\n\n{sentence_with_term}".strip()
|
||
|
||
conn.execute(
|
||
"""
|
||
UPDATE vocabulary_cards
|
||
SET srs_state = 'learning',
|
||
srs_next_review = CURRENT_TIMESTAMP,
|
||
error_count = error_count + 1,
|
||
tags = ?,
|
||
context_sentence = ?
|
||
WHERE id = ?
|
||
""",
|
||
(updated_tags, updated_context, target_card_id),
|
||
)
|
||
card_updated = True
|
||
|
||
# Log mistake in srs_logs
|
||
if target_card_id:
|
||
conn.execute(
|
||
"""
|
||
INSERT INTO srs_logs (user_id, card_id, rating, interval, ease, reviewed_at)
|
||
VALUES (?, ?, 1, 0, 2.5, CURRENT_TIMESTAMP)
|
||
""",
|
||
(user_id, target_card_id),
|
||
)
|
||
else:
|
||
# On correct answer, if user has this card in library, record a positive review log
|
||
existing_card = conn.execute(
|
||
"SELECT id FROM vocabulary_cards WHERE user_id = ? AND lower(trim(term)) = ?",
|
||
(user_id, target_term.lower()),
|
||
).fetchone()
|
||
if existing_card:
|
||
conn.execute(
|
||
"""
|
||
INSERT INTO srs_logs (user_id, card_id, rating, interval, ease, reviewed_at)
|
||
VALUES (?, ?, 4, 1, 2.5, CURRENT_TIMESTAMP)
|
||
""",
|
||
(user_id, existing_card["id"]),
|
||
)
|
||
|
||
return {
|
||
"correct": is_correct,
|
||
"correct_option": target_term,
|
||
"phonetic": phonetic,
|
||
"translation": translation,
|
||
"explanation": explanation,
|
||
"card_created": card_created,
|
||
"card_updated": card_updated,
|
||
"card_id": target_card_id,
|
||
"card_term": target_term,
|
||
}
|
||
|
||
|
||
def reset_user_cefr_level(conn: sqlite3.Connection, user_id: int, level: str) -> int:
|
||
"""
|
||
Resets progress for a specific CEFR level for user.
|
||
"""
|
||
clean_level = level.upper().strip()
|
||
cursor = conn.execute(
|
||
"DELETE FROM cefr_progress WHERE user_id = ? AND level = ?",
|
||
(user_id, clean_level),
|
||
)
|
||
return cursor.rowcount
|