rairo Claude Opus 4.8 commited on
Commit
f36156f
·
1 Parent(s): be0e58c

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>

Files changed (2) hide show
  1. main.py +4 -0
  2. 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()