Spaces:
Sleeping
Sleeping
Seed all 24 syllabus trees and document Gemini model tiers
Browse files- Add seed_syllabi.py: AI-authored topic/lesson trees for every subject,
posted to /v1/admin/seed-structures (fixes empty topics and 0-of-0 lessons)
- Annotate the two valid Gemini model names (lite default, 3.5-flash heavy)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- main.py +4 -0
- seed_syllabi.py +605 -0
main.py
CHANGED
|
@@ -59,6 +59,10 @@ except Exception as e:
|
|
| 59 |
logger.error(f"FATAL GenAI init: {e}")
|
| 60 |
raise SystemExit(1)
|
| 61 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 62 |
EMBED_MODEL = os.environ.get("GEMINI_EMBED_MODEL", "text-embedding-004")
|
| 63 |
TEXT_MODEL = os.environ.get("GEMINI_TEXT_MODEL", "gemini-3.1-flash-lite")
|
| 64 |
|
|
|
|
| 59 |
logger.error(f"FATAL GenAI init: {e}")
|
| 60 |
raise SystemExit(1)
|
| 61 |
|
| 62 |
+
# Gemini model tiers across the Marka ecosystem (only two valid chat names):
|
| 63 |
+
# gemini-3.1-flash-lite — default, cheapest, highest availability
|
| 64 |
+
# gemini-3.5-flash — stronger, for quality-critical generation
|
| 65 |
+
# This service only embeds + (optionally) does light text, so it stays on lite.
|
| 66 |
EMBED_MODEL = os.environ.get("GEMINI_EMBED_MODEL", "text-embedding-004")
|
| 67 |
TEXT_MODEL = os.environ.get("GEMINI_TEXT_MODEL", "gemini-3.1-flash-lite")
|
| 68 |
|
seed_syllabi.py
ADDED
|
@@ -0,0 +1,605 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Seed syllabus structure trees for every subject in the registry.
|
| 3 |
+
|
| 4 |
+
Why this exists
|
| 5 |
+
---------------
|
| 6 |
+
The data API ships with a SUBJECT_REGISTRY (24 Cambridge/ZIMSEC subjects) but the
|
| 7 |
+
syllabus trees in Firebase were never populated. With no tree, the app server has
|
| 8 |
+
nothing to scaffold a learning path on, so every subject showed empty topic lists
|
| 9 |
+
and "0 of 0 lessons". Lessons and quizzes are generated by AI at runtime per node,
|
| 10 |
+
so a subject only needs a faithful tree of topic -> [lessons] to become usable.
|
| 11 |
+
|
| 12 |
+
This script holds an AI-authored structure for each subject (real syllabus topics
|
| 13 |
+
and the sub-lessons under them), turns it into the tree shape the app expects, and
|
| 14 |
+
POSTs the whole batch to the data API's /v1/admin/seed-structures endpoint.
|
| 15 |
+
|
| 16 |
+
Tree node shape consumed by the app:
|
| 17 |
+
{ "id": "...", "title": "...", "type": "topic" | "lesson", "children": [...] }
|
| 18 |
+
|
| 19 |
+
Usage
|
| 20 |
+
-----
|
| 21 |
+
python seed_syllabi.py # seed the live data API
|
| 22 |
+
DATA_API_BASE_URL=http://localhost:7860/v1 python seed_syllabi.py
|
| 23 |
+
python seed_syllabi.py --dry-run # print what would be sent, send nothing
|
| 24 |
+
"""
|
| 25 |
+
|
| 26 |
+
import os
|
| 27 |
+
import sys
|
| 28 |
+
import json
|
| 29 |
+
import requests
|
| 30 |
+
|
| 31 |
+
DATA_API_BASE_URL = os.environ.get(
|
| 32 |
+
"DATA_API_BASE_URL", "https://rairo-marka-data-api.hf.space/v1"
|
| 33 |
+
)
|
| 34 |
+
|
| 35 |
+
# -----------------------------------------------------------------------------
|
| 36 |
+
# Authored syllabus content.
|
| 37 |
+
# remote_id -> { topic_title: [lesson_title, ...], ... }
|
| 38 |
+
# Topic order is the intended teaching order; lessons sit under each topic.
|
| 39 |
+
# -----------------------------------------------------------------------------
|
| 40 |
+
|
| 41 |
+
SYLLABI = {
|
| 42 |
+
# ===================== A-LEVEL =====================
|
| 43 |
+
"A_9706": { # Accounting
|
| 44 |
+
"The Accounting Cycle": [
|
| 45 |
+
"Double-entry bookkeeping", "Books of prime entry",
|
| 46 |
+
"The ledger and trial balance", "Accounting concepts and conventions",
|
| 47 |
+
],
|
| 48 |
+
"Financial Statements": [
|
| 49 |
+
"Income statement", "Statement of financial position",
|
| 50 |
+
"Accruals and prepayments", "Depreciation of non-current assets",
|
| 51 |
+
"Irrecoverable and doubtful debts",
|
| 52 |
+
],
|
| 53 |
+
"Partnership Accounts": [
|
| 54 |
+
"Appropriation of profit", "Capital and current accounts",
|
| 55 |
+
"Goodwill", "Admission and retirement of partners",
|
| 56 |
+
],
|
| 57 |
+
"Company Accounts": [
|
| 58 |
+
"Share capital and reserves", "Issue of shares and debentures",
|
| 59 |
+
"Published financial statements", "Statement of cash flows",
|
| 60 |
+
],
|
| 61 |
+
"Cost and Management Accounting": [
|
| 62 |
+
"Cost classification", "Marginal costing", "Absorption costing",
|
| 63 |
+
"Break-even analysis", "Budgeting and budgetary control",
|
| 64 |
+
],
|
| 65 |
+
"Analysis and Communication": [
|
| 66 |
+
"Accounting ratios", "Interpretation of financial statements",
|
| 67 |
+
],
|
| 68 |
+
},
|
| 69 |
+
"A_9700": { # Biology
|
| 70 |
+
"Cell Structure": [
|
| 71 |
+
"Microscopy and magnification", "Prokaryotic and eukaryotic cells",
|
| 72 |
+
"Cell organelles", "Cell membranes and transport",
|
| 73 |
+
],
|
| 74 |
+
"Biological Molecules": [
|
| 75 |
+
"Carbohydrates", "Lipids", "Proteins", "Water and inorganic ions", "Enzymes",
|
| 76 |
+
],
|
| 77 |
+
"Genetic Information": [
|
| 78 |
+
"DNA structure and replication", "Protein synthesis",
|
| 79 |
+
"Mitosis and the cell cycle", "Meiosis and variation",
|
| 80 |
+
],
|
| 81 |
+
"Transport Systems": [
|
| 82 |
+
"Transport in plants", "Transport in mammals",
|
| 83 |
+
"The mammalian heart", "Haemoglobin and gas transport",
|
| 84 |
+
],
|
| 85 |
+
"Disease and Immunity": [
|
| 86 |
+
"Infectious diseases", "Antibiotics", "The immune system", "Vaccination",
|
| 87 |
+
],
|
| 88 |
+
"Energy and Coordination": [
|
| 89 |
+
"Photosynthesis", "Respiration", "Homeostasis", "Nervous coordination",
|
| 90 |
+
],
|
| 91 |
+
},
|
| 92 |
+
"A_9609": { # Business
|
| 93 |
+
"Business and its Environment": [
|
| 94 |
+
"Enterprise and entrepreneurs", "Business structure",
|
| 95 |
+
"Size of business", "Business objectives", "Stakeholders in business",
|
| 96 |
+
],
|
| 97 |
+
"Human Resource Management": [
|
| 98 |
+
"Motivation theories", "Leadership and management styles",
|
| 99 |
+
"Human resource planning", "Organisation structure",
|
| 100 |
+
],
|
| 101 |
+
"Marketing": [
|
| 102 |
+
"Marketing planning", "Market research", "The marketing mix", "Marketing strategy",
|
| 103 |
+
],
|
| 104 |
+
"Operations Management": [
|
| 105 |
+
"Operations planning", "Inventory management",
|
| 106 |
+
"Capacity utilisation", "Quality management", "Lean production",
|
| 107 |
+
],
|
| 108 |
+
"Finance and Accounting": [
|
| 109 |
+
"Sources of finance", "Costs and break-even",
|
| 110 |
+
"Budgets and variances", "Investment appraisal",
|
| 111 |
+
],
|
| 112 |
+
"Strategic Management": [
|
| 113 |
+
"Strategic analysis (SWOT and PEST)", "Strategic choice", "Managing change",
|
| 114 |
+
],
|
| 115 |
+
},
|
| 116 |
+
"A_9701": { # Chemistry
|
| 117 |
+
"Atomic Structure": [
|
| 118 |
+
"Atoms and isotopes", "Electronic configuration",
|
| 119 |
+
"Ionisation energies", "Mass spectrometry",
|
| 120 |
+
],
|
| 121 |
+
"Chemical Bonding": [
|
| 122 |
+
"Ionic bonding", "Covalent bonding", "Shapes of molecules",
|
| 123 |
+
"Intermolecular forces", "Metallic bonding",
|
| 124 |
+
],
|
| 125 |
+
"Chemical Energetics": [
|
| 126 |
+
"Enthalpy changes", "Hess's law", "Bond energies", "Born-Haber cycles",
|
| 127 |
+
],
|
| 128 |
+
"Equilibria": [
|
| 129 |
+
"Reversible reactions", "Kc and Kp", "Le Chatelier's principle",
|
| 130 |
+
"Acids and bases", "pH and buffer calculations",
|
| 131 |
+
],
|
| 132 |
+
"Reaction Kinetics": [
|
| 133 |
+
"Rates of reaction", "Rate equations", "Reaction mechanisms", "Catalysis",
|
| 134 |
+
],
|
| 135 |
+
"Organic Chemistry": [
|
| 136 |
+
"Hydrocarbons", "Halogenoalkanes", "Alcohols and esters",
|
| 137 |
+
"Carbonyl compounds", "Organic analysis",
|
| 138 |
+
],
|
| 139 |
+
},
|
| 140 |
+
"A_9618": { # Computer Science
|
| 141 |
+
"Information Representation": [
|
| 142 |
+
"Number systems", "Binary and hexadecimal", "Data types",
|
| 143 |
+
"Character sets and image representation",
|
| 144 |
+
],
|
| 145 |
+
"Communication and Networking": [
|
| 146 |
+
"Networks and topologies", "Internet technologies", "Protocols",
|
| 147 |
+
],
|
| 148 |
+
"Hardware and Processors": [
|
| 149 |
+
"Logic gates", "Boolean algebra", "CPU architecture", "Assembly language",
|
| 150 |
+
],
|
| 151 |
+
"System Software": [
|
| 152 |
+
"Operating systems", "Language translators", "Memory management",
|
| 153 |
+
],
|
| 154 |
+
"Databases": [
|
| 155 |
+
"Relational databases", "Normalisation", "SQL", "Database management systems",
|
| 156 |
+
],
|
| 157 |
+
"Algorithms and Programming": [
|
| 158 |
+
"Programming paradigms", "Data structures", "Searching and sorting",
|
| 159 |
+
"Recursion", "Abstract data types",
|
| 160 |
+
],
|
| 161 |
+
},
|
| 162 |
+
"A_9708": { # Economics
|
| 163 |
+
"Basic Economic Ideas": [
|
| 164 |
+
"Scarcity and choice", "Factors of production",
|
| 165 |
+
"Production possibility curves", "Specialisation and exchange",
|
| 166 |
+
],
|
| 167 |
+
"The Price System": [
|
| 168 |
+
"Demand and supply", "Elasticities", "Market equilibrium",
|
| 169 |
+
"Consumer and producer surplus",
|
| 170 |
+
],
|
| 171 |
+
"Market Failure": [
|
| 172 |
+
"Externalities", "Public goods", "Information failure",
|
| 173 |
+
"Government intervention",
|
| 174 |
+
],
|
| 175 |
+
"The Macroeconomy": [
|
| 176 |
+
"Aggregate demand and supply", "National income", "Economic growth",
|
| 177 |
+
"Inflation and unemployment",
|
| 178 |
+
],
|
| 179 |
+
"Government Macro Policy": [
|
| 180 |
+
"Fiscal policy", "Monetary policy", "Supply-side policy",
|
| 181 |
+
"Balance of payments",
|
| 182 |
+
],
|
| 183 |
+
"International Economics": [
|
| 184 |
+
"Exchange rates", "Trade and protectionism", "Globalisation",
|
| 185 |
+
],
|
| 186 |
+
},
|
| 187 |
+
"A_9231": { # Further Mathematics
|
| 188 |
+
"Further Pure 1": [
|
| 189 |
+
"Roots of polynomial equations", "Rational functions and graphs",
|
| 190 |
+
"Summation of series", "Matrices", "Polar coordinates",
|
| 191 |
+
],
|
| 192 |
+
"Further Pure 2": [
|
| 193 |
+
"Hyperbolic functions", "Further integration",
|
| 194 |
+
"Complex numbers", "Differential equations",
|
| 195 |
+
],
|
| 196 |
+
"Further Mechanics": [
|
| 197 |
+
"Momentum and impulse", "Circular motion",
|
| 198 |
+
"Work, energy and power", "Simple harmonic motion",
|
| 199 |
+
],
|
| 200 |
+
"Further Probability and Statistics": [
|
| 201 |
+
"Continuous random variables", "Poisson distribution",
|
| 202 |
+
"Hypothesis testing", "Chi-squared tests",
|
| 203 |
+
],
|
| 204 |
+
},
|
| 205 |
+
"A_9489": { # History
|
| 206 |
+
"Modern Europe 1750-1921": [
|
| 207 |
+
"The French Revolution", "The Industrial Revolution",
|
| 208 |
+
"Nationalism and unification", "The Russian Revolution",
|
| 209 |
+
],
|
| 210 |
+
"International Relations 1871-1945": [
|
| 211 |
+
"Origins of the First World War", "The Treaty of Versailles",
|
| 212 |
+
"Rise of dictatorships", "Origins of the Second World War",
|
| 213 |
+
],
|
| 214 |
+
"The Cold War": [
|
| 215 |
+
"Origins of the Cold War", "Berlin and Cuba crises",
|
| 216 |
+
"Détente", "The end of the Cold War",
|
| 217 |
+
],
|
| 218 |
+
"African History": [
|
| 219 |
+
"Colonialism in Africa", "African nationalism",
|
| 220 |
+
"Decolonisation", "Post-independence Africa",
|
| 221 |
+
],
|
| 222 |
+
},
|
| 223 |
+
"A_9695": { # Literature in English
|
| 224 |
+
"Poetry": [
|
| 225 |
+
"Reading and responding to poetry", "Form and structure",
|
| 226 |
+
"Imagery and language", "Comparative analysis",
|
| 227 |
+
],
|
| 228 |
+
"Prose": [
|
| 229 |
+
"The novel and narrative voice", "Characterisation",
|
| 230 |
+
"Themes and context", "Critical interpretation",
|
| 231 |
+
],
|
| 232 |
+
"Drama": [
|
| 233 |
+
"Dramatic techniques", "Tragedy", "Comedy", "Staging and performance",
|
| 234 |
+
],
|
| 235 |
+
"Shakespeare": [
|
| 236 |
+
"Shakespearean language", "Themes and ideas",
|
| 237 |
+
"Character study", "Critical perspectives",
|
| 238 |
+
],
|
| 239 |
+
"Critical Skills": [
|
| 240 |
+
"Unseen criticism", "Contextual analysis", "Essay writing",
|
| 241 |
+
],
|
| 242 |
+
},
|
| 243 |
+
"A_9709": { # Mathematics
|
| 244 |
+
"Pure Mathematics 1": [
|
| 245 |
+
"Quadratics", "Functions", "Coordinate geometry", "Circular measure",
|
| 246 |
+
"Trigonometry", "Series", "Differentiation", "Integration",
|
| 247 |
+
],
|
| 248 |
+
"Pure Mathematics 3": [
|
| 249 |
+
"Algebra", "Logarithmic and exponential functions",
|
| 250 |
+
"Trigonometry", "Differentiation and integration",
|
| 251 |
+
"Numerical solution of equations", "Vectors",
|
| 252 |
+
"Differential equations", "Complex numbers",
|
| 253 |
+
],
|
| 254 |
+
"Mechanics": [
|
| 255 |
+
"Forces and equilibrium", "Kinematics of motion",
|
| 256 |
+
"Newton's laws of motion", "Energy, work and power", "Momentum",
|
| 257 |
+
],
|
| 258 |
+
"Probability and Statistics": [
|
| 259 |
+
"Representation of data", "Permutations and combinations",
|
| 260 |
+
"Probability", "Discrete random variables", "The normal distribution",
|
| 261 |
+
],
|
| 262 |
+
},
|
| 263 |
+
"A_9702": { # Physics
|
| 264 |
+
"Mechanics": [
|
| 265 |
+
"Kinematics", "Dynamics", "Forces and equilibrium",
|
| 266 |
+
"Work, energy and power", "Momentum",
|
| 267 |
+
],
|
| 268 |
+
"Matter and Materials": [
|
| 269 |
+
"Density and pressure", "Deformation of solids", "Phases of matter",
|
| 270 |
+
],
|
| 271 |
+
"Oscillations and Waves": [
|
| 272 |
+
"Wave properties", "Superposition", "Stationary waves",
|
| 273 |
+
"Simple harmonic motion", "The Doppler effect",
|
| 274 |
+
],
|
| 275 |
+
"Electricity and Magnetism": [
|
| 276 |
+
"Electric fields", "Current electricity", "D.C. circuits",
|
| 277 |
+
"Magnetic fields", "Electromagnetic induction",
|
| 278 |
+
],
|
| 279 |
+
"Modern Physics": [
|
| 280 |
+
"Quantum physics", "The photoelectric effect",
|
| 281 |
+
"Atomic and nuclear physics", "Radioactivity",
|
| 282 |
+
],
|
| 283 |
+
"Thermal Physics": [
|
| 284 |
+
"Temperature and thermal energy", "Ideal gases", "Thermodynamics",
|
| 285 |
+
],
|
| 286 |
+
},
|
| 287 |
+
"A_9699": { # Sociology
|
| 288 |
+
"Socialisation and Identity": [
|
| 289 |
+
"Culture and identity", "Socialisation",
|
| 290 |
+
"Social control", "Nature versus nurture",
|
| 291 |
+
],
|
| 292 |
+
"Sociological Theory": [
|
| 293 |
+
"Functionalism", "Marxism", "Feminism", "Social action theory",
|
| 294 |
+
],
|
| 295 |
+
"Family": [
|
| 296 |
+
"Family forms and diversity", "Changing family roles",
|
| 297 |
+
"Marriage and divorce", "Childhood",
|
| 298 |
+
],
|
| 299 |
+
"Education": [
|
| 300 |
+
"The role of education", "Educational achievement",
|
| 301 |
+
"The hidden curriculum", "Education policy",
|
| 302 |
+
],
|
| 303 |
+
"Research Methods": [
|
| 304 |
+
"Quantitative methods", "Qualitative methods",
|
| 305 |
+
"Sampling", "Reliability and validity",
|
| 306 |
+
],
|
| 307 |
+
"Social Inequality": [
|
| 308 |
+
"Class inequality", "Gender inequality", "Ethnicity", "Poverty",
|
| 309 |
+
],
|
| 310 |
+
},
|
| 311 |
+
"A_9395": { # Travel & Tourism
|
| 312 |
+
"The Travel and Tourism Industry": [
|
| 313 |
+
"Structure of the industry", "Types of tourism",
|
| 314 |
+
"Travel organisations", "Sustainable tourism",
|
| 315 |
+
],
|
| 316 |
+
"Features of Destinations": [
|
| 317 |
+
"Destination appeal", "Tourist motivations and typologies",
|
| 318 |
+
"Destination management",
|
| 319 |
+
],
|
| 320 |
+
"Customer Service": [
|
| 321 |
+
"Customer needs", "Quality service", "Handling complaints", "Selling skills",
|
| 322 |
+
],
|
| 323 |
+
"Marketing in Travel and Tourism": [
|
| 324 |
+
"The marketing mix", "Market research", "Promotion", "Branding",
|
| 325 |
+
],
|
| 326 |
+
"Tourism Development": [
|
| 327 |
+
"Economic impacts", "Social and cultural impacts",
|
| 328 |
+
"Environmental impacts", "Managing tourism",
|
| 329 |
+
],
|
| 330 |
+
},
|
| 331 |
+
# ===================== O-LEVEL / IGCSE =====================
|
| 332 |
+
"O_0452": { # Accounting
|
| 333 |
+
"Introduction to Accounting": [
|
| 334 |
+
"The accounting equation", "Double entry bookkeeping",
|
| 335 |
+
"Books of prime entry", "The ledger and trial balance",
|
| 336 |
+
],
|
| 337 |
+
"Financial Statements": [
|
| 338 |
+
"Income statement", "Statement of financial position",
|
| 339 |
+
"Accruals and prepayments", "Depreciation",
|
| 340 |
+
],
|
| 341 |
+
"Accounting for Different Entities": [
|
| 342 |
+
"Sole traders", "Partnerships", "Limited companies",
|
| 343 |
+
"Non-profit organisations",
|
| 344 |
+
],
|
| 345 |
+
"Verification and Control": [
|
| 346 |
+
"Bank reconciliation statements", "Control accounts",
|
| 347 |
+
"Correction of errors", "Suspense accounts",
|
| 348 |
+
],
|
| 349 |
+
"Analysis and Interpretation": [
|
| 350 |
+
"Accounting ratios", "Interpreting accounts",
|
| 351 |
+
],
|
| 352 |
+
},
|
| 353 |
+
"O_0610": { # Biology
|
| 354 |
+
"Characteristics and Cells": [
|
| 355 |
+
"Characteristics of living organisms", "Cell structure",
|
| 356 |
+
"Movement in and out of cells", "Classification",
|
| 357 |
+
],
|
| 358 |
+
"Molecules and Nutrition": [
|
| 359 |
+
"Biological molecules", "Enzymes",
|
| 360 |
+
"Nutrition in plants", "Nutrition in humans",
|
| 361 |
+
],
|
| 362 |
+
"Transport and Respiration": [
|
| 363 |
+
"Transport in plants", "Transport in animals",
|
| 364 |
+
"Gas exchange", "Respiration",
|
| 365 |
+
],
|
| 366 |
+
"Coordination and Homeostasis": [
|
| 367 |
+
"The nervous system", "Hormones", "Homeostasis", "Excretion",
|
| 368 |
+
],
|
| 369 |
+
"Reproduction and Inheritance": [
|
| 370 |
+
"Reproduction in plants", "Reproduction in humans",
|
| 371 |
+
"Inheritance", "Variation and selection",
|
| 372 |
+
],
|
| 373 |
+
"Ecology and Human Impact": [
|
| 374 |
+
"Organisms and their environment",
|
| 375 |
+
"Human influences on ecosystems", "Biotechnology",
|
| 376 |
+
],
|
| 377 |
+
},
|
| 378 |
+
"O_0450": { # Business Studies
|
| 379 |
+
"Business Activity": [
|
| 380 |
+
"Purpose and nature of business", "Classification of business",
|
| 381 |
+
"Enterprise and entrepreneurs", "Business growth",
|
| 382 |
+
],
|
| 383 |
+
"People in Business": [
|
| 384 |
+
"Motivation", "Organisation and management",
|
| 385 |
+
"Recruitment and training", "Communication",
|
| 386 |
+
],
|
| 387 |
+
"Marketing": [
|
| 388 |
+
"Market research", "The marketing mix", "Marketing strategy",
|
| 389 |
+
],
|
| 390 |
+
"Operations Management": [
|
| 391 |
+
"Production methods", "Costs and break-even",
|
| 392 |
+
"Achieving quality", "Location decisions",
|
| 393 |
+
],
|
| 394 |
+
"Finance": [
|
| 395 |
+
"Sources of finance", "Cash flow forecasting",
|
| 396 |
+
"Financial statements", "Ratio analysis",
|
| 397 |
+
],
|
| 398 |
+
},
|
| 399 |
+
"O_0620": { # Chemistry
|
| 400 |
+
"Matter and Atoms": [
|
| 401 |
+
"Particulate nature of matter", "Atomic structure",
|
| 402 |
+
"The periodic table", "Chemical bonding",
|
| 403 |
+
],
|
| 404 |
+
"Stoichiometry": [
|
| 405 |
+
"Formulae and equations", "The mole concept", "Reacting masses",
|
| 406 |
+
],
|
| 407 |
+
"Electrochemistry and Energetics": [
|
| 408 |
+
"Electrolysis", "Energy changes", "Rates of reaction",
|
| 409 |
+
"Reversible reactions",
|
| 410 |
+
],
|
| 411 |
+
"Acids, Bases and Salts": [
|
| 412 |
+
"Acids and bases", "Preparation of salts", "Identification of ions",
|
| 413 |
+
],
|
| 414 |
+
"Metals and Periodicity": [
|
| 415 |
+
"Properties of metals", "The reactivity series", "Extraction of metals",
|
| 416 |
+
],
|
| 417 |
+
"Organic and Environmental Chemistry": [
|
| 418 |
+
"Fuels", "Alkanes and alkenes", "Alcohols", "Air and water",
|
| 419 |
+
],
|
| 420 |
+
},
|
| 421 |
+
"O_0478": { # Computer Science
|
| 422 |
+
"Data Representation": [
|
| 423 |
+
"Binary systems", "Hexadecimal", "Data storage and compression",
|
| 424 |
+
],
|
| 425 |
+
"Communication and Networking": [
|
| 426 |
+
"Data transmission", "Networks", "The internet", "Security",
|
| 427 |
+
],
|
| 428 |
+
"Hardware": [
|
| 429 |
+
"Logic gates", "Input and output devices", "Storage devices", "The CPU",
|
| 430 |
+
],
|
| 431 |
+
"Software": [
|
| 432 |
+
"System software", "Application software", "Operating systems",
|
| 433 |
+
],
|
| 434 |
+
"Programming and Databases": [
|
| 435 |
+
"Algorithm design", "Pseudocode and flowcharts",
|
| 436 |
+
"Programming concepts", "Databases",
|
| 437 |
+
],
|
| 438 |
+
},
|
| 439 |
+
"O_0500": { # English Language
|
| 440 |
+
"Reading Skills": [
|
| 441 |
+
"Comprehension", "Summary writing",
|
| 442 |
+
"Extended response to reading", "Analysing language",
|
| 443 |
+
],
|
| 444 |
+
"Directed Writing": [
|
| 445 |
+
"Writing for purpose", "Audience and tone",
|
| 446 |
+
"Discursive writing", "Argumentative writing",
|
| 447 |
+
],
|
| 448 |
+
"Composition": [
|
| 449 |
+
"Descriptive writing", "Narrative writing", "Planning and structure",
|
| 450 |
+
],
|
| 451 |
+
"Language Techniques": [
|
| 452 |
+
"Vocabulary and style", "Grammar and accuracy", "Punctuation",
|
| 453 |
+
],
|
| 454 |
+
},
|
| 455 |
+
"O_0475": { # English Literature
|
| 456 |
+
"Poetry": [
|
| 457 |
+
"Reading poetry", "Imagery and figurative language",
|
| 458 |
+
"Form and structure", "Comparing poems",
|
| 459 |
+
],
|
| 460 |
+
"Prose": [
|
| 461 |
+
"Studying the novel", "Character and theme",
|
| 462 |
+
"Setting and context", "Close reading",
|
| 463 |
+
],
|
| 464 |
+
"Drama": [
|
| 465 |
+
"Studying plays", "Dramatic devices",
|
| 466 |
+
"Character and conflict", "Themes",
|
| 467 |
+
],
|
| 468 |
+
"Critical Writing": [
|
| 469 |
+
"Essay structure", "Using quotations", "Personal response",
|
| 470 |
+
],
|
| 471 |
+
},
|
| 472 |
+
"O_0680": { # Environmental Management
|
| 473 |
+
"The Lithosphere": [
|
| 474 |
+
"Rocks and minerals", "Mining and extraction", "Soil and its management",
|
| 475 |
+
],
|
| 476 |
+
"The Atmosphere": [
|
| 477 |
+
"Atmosphere and climate", "Air pollution", "Climate change",
|
| 478 |
+
],
|
| 479 |
+
"The Hydrosphere": [
|
| 480 |
+
"Water resources", "Water pollution", "Managing water", "The oceans",
|
| 481 |
+
],
|
| 482 |
+
"The Biosphere": [
|
| 483 |
+
"Ecosystems", "Biodiversity", "Human impact", "Conservation",
|
| 484 |
+
],
|
| 485 |
+
"Population and Sustainability": [
|
| 486 |
+
"Population dynamics", "Resources and energy", "Sustainable development",
|
| 487 |
+
],
|
| 488 |
+
},
|
| 489 |
+
"O_0460": { # Geography
|
| 490 |
+
"Population and Settlement": [
|
| 491 |
+
"Population dynamics", "Migration", "Settlement patterns", "Urbanisation",
|
| 492 |
+
],
|
| 493 |
+
"The Natural Environment": [
|
| 494 |
+
"Plate tectonics", "Rivers", "Coasts", "Weather and climate", "Ecosystems",
|
| 495 |
+
],
|
| 496 |
+
"Economic Development": [
|
| 497 |
+
"Agriculture", "Industry", "Tourism", "Energy", "Development",
|
| 498 |
+
],
|
| 499 |
+
"Geographical Skills": [
|
| 500 |
+
"Map skills", "Data collection", "Interpreting data",
|
| 501 |
+
],
|
| 502 |
+
},
|
| 503 |
+
"O_0470": { # History
|
| 504 |
+
"The Nineteenth Century": [
|
| 505 |
+
"International relations", "Nationalism", "Empire and colonialism",
|
| 506 |
+
],
|
| 507 |
+
"The First World War": [
|
| 508 |
+
"Causes of the First World War", "The course of the war", "Peace treaties",
|
| 509 |
+
],
|
| 510 |
+
"Between the Wars": [
|
| 511 |
+
"The League of Nations", "Rise of dictatorships",
|
| 512 |
+
"Causes of the Second World War",
|
| 513 |
+
],
|
| 514 |
+
"The Cold War": [
|
| 515 |
+
"Origins of the Cold War", "Crises and conflicts", "End of the Cold War",
|
| 516 |
+
],
|
| 517 |
+
"Depth Study": [
|
| 518 |
+
"Germany 1918-1945", "Russia and the USSR", "The United States",
|
| 519 |
+
],
|
| 520 |
+
},
|
| 521 |
+
"O_0625": { # Physics
|
| 522 |
+
"General Physics": [
|
| 523 |
+
"Measurements", "Motion", "Mass, weight and density",
|
| 524 |
+
"Forces", "Energy, work and power", "Pressure",
|
| 525 |
+
],
|
| 526 |
+
"Thermal Physics": [
|
| 527 |
+
"Kinetic theory", "Thermal properties", "Transfer of thermal energy",
|
| 528 |
+
],
|
| 529 |
+
"Waves": [
|
| 530 |
+
"General wave properties", "Light", "Sound",
|
| 531 |
+
"The electromagnetic spectrum",
|
| 532 |
+
],
|
| 533 |
+
"Electricity and Magnetism": [
|
| 534 |
+
"Magnetism", "Static electricity", "Current electricity",
|
| 535 |
+
"Electrical circuits", "Electromagnetic effects",
|
| 536 |
+
],
|
| 537 |
+
"Atomic Physics": [
|
| 538 |
+
"The nuclear atom", "Radioactivity",
|
| 539 |
+
],
|
| 540 |
+
},
|
| 541 |
+
}
|
| 542 |
+
|
| 543 |
+
|
| 544 |
+
def _slug(text: str) -> str:
|
| 545 |
+
keep = [c.lower() if c.isalnum() else "_" for c in text]
|
| 546 |
+
out = "".join(keep)
|
| 547 |
+
while "__" in out:
|
| 548 |
+
out = out.replace("__", "_")
|
| 549 |
+
return out.strip("_")[:40]
|
| 550 |
+
|
| 551 |
+
|
| 552 |
+
def build_tree(subject_content: dict) -> list:
|
| 553 |
+
"""Convert {topic: [lessons]} into the app's tree node shape."""
|
| 554 |
+
tree = []
|
| 555 |
+
for t_index, (topic_title, lessons) in enumerate(subject_content.items(), start=1):
|
| 556 |
+
topic_id = f"t{t_index}_{_slug(topic_title)}"
|
| 557 |
+
children = []
|
| 558 |
+
for l_index, lesson_title in enumerate(lessons, start=1):
|
| 559 |
+
children.append({
|
| 560 |
+
"id": f"{topic_id}_l{l_index}",
|
| 561 |
+
"title": lesson_title,
|
| 562 |
+
"type": "lesson",
|
| 563 |
+
})
|
| 564 |
+
tree.append({
|
| 565 |
+
"id": topic_id,
|
| 566 |
+
"title": topic_title,
|
| 567 |
+
"type": "topic",
|
| 568 |
+
"children": children,
|
| 569 |
+
})
|
| 570 |
+
return tree
|
| 571 |
+
|
| 572 |
+
|
| 573 |
+
def main():
|
| 574 |
+
dry_run = "--dry-run" in sys.argv
|
| 575 |
+
structures = {rid: {"tree": build_tree(content)} for rid, content in SYLLABI.items()}
|
| 576 |
+
|
| 577 |
+
total_topics = sum(len(s["tree"]) for s in structures.values())
|
| 578 |
+
total_lessons = sum(
|
| 579 |
+
len(node["children"]) for s in structures.values() for node in s["tree"]
|
| 580 |
+
)
|
| 581 |
+
print(f"Prepared {len(structures)} subjects, "
|
| 582 |
+
f"{total_topics} topics, {total_lessons} lessons.")
|
| 583 |
+
|
| 584 |
+
if dry_run:
|
| 585 |
+
print(json.dumps(structures["A_9709"], indent=2))
|
| 586 |
+
print("\n[dry-run] Nothing sent.")
|
| 587 |
+
return
|
| 588 |
+
|
| 589 |
+
url = f"{DATA_API_BASE_URL}/admin/seed-structures"
|
| 590 |
+
print(f"POST {url}")
|
| 591 |
+
resp = requests.post(url, json={"structures": structures}, timeout=120)
|
| 592 |
+
print(f"HTTP {resp.status_code}")
|
| 593 |
+
try:
|
| 594 |
+
results = resp.json().get("results", {})
|
| 595 |
+
ok = sum(1 for r in results.values() if r.get("ok"))
|
| 596 |
+
print(f"Seeded OK: {ok}/{len(results)}")
|
| 597 |
+
failures = {k: v for k, v in results.items() if not v.get("ok")}
|
| 598 |
+
if failures:
|
| 599 |
+
print("Failures:", json.dumps(failures, indent=2))
|
| 600 |
+
except Exception:
|
| 601 |
+
print(resp.text[:1000])
|
| 602 |
+
|
| 603 |
+
|
| 604 |
+
if __name__ == "__main__":
|
| 605 |
+
main()
|