enumverse-ai / API_REFERENCE.md
Mercy Babayemi
AfriPed — clean deploy (ENGREG teacher corpus as TXT, no binary files)
5070743
# AfriPed — API Reference
**Base URL:** `POST https://<space>/api/v1/`
**Interactive docs:** `/docs` (Swagger UI) · `/redoc`
---
## Shared building blocks
These objects are reused across multiple request bodies.
### `LearnerProfile`
| Field | Type | Required | Values |
|---|---|---|---|
| `education_level` | string | ✅ | `PRIMARY_1_3`, `PRIMARY_4_6`, `JSS1`, `JSS2`, `JSS3`, `SSS1`, `SSS2`, `SSS3`, `TERTIARY`, `VOCATIONAL_BASIC`, `VOCATIONAL_ADVANCED`, `BEGINNER_COHORT`, `INTERMEDIATE_COHORT`, `ADVANCED_COHORT`, `ADULT_LITERACY`, `YOUTH_GROUP`, `COMMUNITY_GROUP`, `PROFESSIONAL_DEV` |
| `program_type` | string | — | `ACADEMIC`, `VOCATIONAL`, `COMMUNITY`, `LIFE_SKILLS`, `AGRICULTURAL`, `TEACHER_TRAINING`, `YOUTH_ENTERPRISE` |
| `class_size` | int | — | e.g. `40` |
| `prior_knowledge` | string | — | free text |
### `PedagogicalGoals`
| Field | Type | Required | Values |
|---|---|---|---|
| `bloom_level` | string | — | `REMEMBER`, `UNDERSTAND`, `APPLY`, `ANALYZE`, `EVALUATE`, `CREATE` |
| `learning_objectives` | string[] | — | list of objective statements |
| `target_skills` | string[] | — | names from the 99-skill library |
| `duration_minutes` | int | — | e.g. `40` |
### `CulturalContext`
| Field | Type | Default | Notes |
|---|---|---|---|
| `use_local_names` | bool | `true` | Enforces West African names (Tunde, Adaeze, Kofi…) |
| `use_local_examples` | bool | `true` | Uses local contexts (markets, rivers, currencies) |
| `custom_cultural_notes` | string | `""` | Free-text cultural guidance injected into the prompt |
### `ValidationReport` (present in every response)
| Field | Type | Notes |
|---|---|---|
| `status` | string | `PASSED` · `FLAGGED` · `REVISED` · `FAILED` — see status meanings below |
| `rules_passed` | string[] | Names of the 8 rules that passed |
| `rules_failed` | string[] | Names of rules that failed |
| `judge_score` | float \| null | Average TinyLlama score 1–5; only present when judge ran |
| `judge_dimensions` | object \| null | Per-dimension scores: `curriculum_alignment`, `bloom_level`, `cultural_appropriateness`, `language_quality`, `educational_value` |
| `revision_count` | int | Number of rewrite attempts (max 2) |
| `notes` | string[] | Human-readable detail on each failure |
**Validation status meanings:**
| Status | Meaning |
|---|---|
| `PASSED` | All 8 rules passed on first attempt |
| `FLAGGED` | At least one rule failed but TinyLlama judge scored ≥ 3.5 — content approved |
| `REVISED` | Content was rewritten by the model and then passed rules |
| `FAILED` | Hard fail (explicit content) or judge scored < 3.5 after max retries |
---
## Pillar 1 — Curriculum
### `POST /api/v1/curriculum/generate`
#### Request body
```json
{
"request_id": "abc123",
"subject": "mathematics",
"education_level": "SSS1",
"curriculum_board": "NERDC",
"output_type": "SCHEME_OF_WORK",
"num_terms": 3,
"num_weeks_per_term": 13,
"topics": ["Algebra", "Geometry"],
"learner_profile": {
"education_level": "SSS1",
"program_type": "ACADEMIC"
},
"pedagogical_goals": {
"bloom_level": "UNDERSTAND",
"learning_objectives": [],
"target_skills": [],
"duration_minutes": 40
},
"output_language": "en",
"cultural_context": {
"use_local_names": true,
"use_local_examples": true
},
"include_resources": true,
"include_assessment_schedule": true,
"use_rag": true,
"max_tokens": 2048
}
```
| Field | Required | Default | Notes |
|---|---|---|---|
| `subject` | ✅ | — | See enum values below |
| `education_level` | ✅ | — | See `LearnerProfile` |
| `output_type` | ✅ | — | `SCHEME_OF_WORK`, `TERM_PLAN`, `UNIT_PLAN`, `SCOPE_AND_SEQUENCE`, `LEARNING_OUTCOMES` |
| `curriculum_board` | — | `NERDC` | `NERDC`, `WAEC`, `NECO`, `NABTEB`, `UBEC`, `GES_GH`, `WAEC_GH`, `BECE_GH`, `CUSTOM` |
| `num_terms` | — | `3` | 1–4 |
| `num_weeks_per_term` | — | `13` | 1–20 |
| `topics` | — | `[]` | Specific topics to cover |
| `max_tokens` | — | `2048` | 256–4096 |
#### Response body
```json
{
"request_id": "abc123",
"curriculum_output": "## SSS1 Mathematics Scheme of Work...",
"output_type": "SCHEME_OF_WORK",
"subject": "mathematics",
"education_level": "SSS1",
"curriculum_board": "NERDC",
"num_topics_generated": 9,
"skill_tags": [
{ "skill_name": "Critical Thinking", "skill_domain": "cognitive", "parent_skill": null }
],
"validation": { ... },
"rag_metadata": {
"chunks_used": 4,
"sources": ["synthetic"],
"similarity_scores": [0.87, 0.82],
"synthetic_chunks": 4
},
"model_used": "microsoft/Phi-3-mini-4k-instruct",
"generation_time_seconds": 387.4,
"token_count": 412,
"created_at": "2026-02-26T10:44:17Z",
"warnings": []
}
```
---
## Pillar 2 — Content
### `POST /api/v1/content/generate`
#### Request body
```json
{
"request_id": "abc123",
"subject": "mathematics",
"topic": "Pythagoras Theorem",
"content_type": "LESSON_PLAN",
"curriculum_board": "NERDC",
"learner_profile": {
"education_level": "SSS1",
"program_type": "ACADEMIC"
},
"pedagogical_goals": {
"bloom_level": "UNDERSTAND",
"learning_objectives": [
"Students will explain the Pythagorean theorem"
],
"target_skills": ["Critical Thinking", "Problem Solving"],
"duration_minutes": 40
},
"output_language": "en",
"cultural_context": {
"use_local_names": true,
"use_local_examples": true
},
"include_teacher_notes": false,
"include_answer_key": true,
"use_rag": true,
"max_tokens": 512
}
```
| Field | Required | Default | Notes |
|---|---|---|---|
| `subject` | ✅ | — | |
| `topic` | ✅ | — | 3–200 characters |
| `content_type` | ✅ | — | `LESSON_PLAN`, `UNIT_NOTES`, `LECTURE_NOTES`, `STUDY_GUIDE`, `WORKSHEET`, `WORKED_EXAMPLE`, `FLASHCARDS`, `GLOSSARY`, `SUMMARY`, `STORY`, `DIALOGUE`, `CASE_STUDY`, `VOCATIONAL_GUIDE`, `COMMUNITY_AWARENESS`, `EXTENSION_BULLETIN` |
| `curriculum_board` | — | `NERDC` | |
| `include_teacher_notes` | — | `false` | Appends a teacher notes section |
| `include_answer_key` | — | `true` | Appends answer key / marking guide |
| `max_tokens` | — | `1024` | 128–4096 |
#### Response body
```json
{
"request_id": "abc123",
"content": "## Lesson Plan: Pythagoras Theorem...",
"content_type": "LESSON_PLAN",
"subject": "mathematics",
"topic": "Pythagoras Theorem",
"output_language": "en",
"curriculum_board": "NERDC",
"bloom_level": "UNDERSTAND",
"skill_tags": [
{ "skill_name": "Critical Thinking", "skill_domain": "cognitive", "parent_skill": null }
],
"validation": {
"status": "FLAGGED",
"rules_passed": [
"length_check", "language_detection", "bloom_verb_presence",
"cultural_flag_check", "no_hallucinated_dates",
"no_explicit_content", "curriculum_alignment"
],
"rules_failed": ["format_compliance"],
"judge_score": 4.05,
"judge_dimensions": {
"curriculum_alignment": 3.5,
"bloom_level": 4.0,
"cultural_appropriateness": 5.0,
"language_quality": 4.0,
"educational_value": 3.75
},
"revision_count": 0,
"notes": ["format_compliance: Lesson plan missing sections: assessment"]
},
"rag_metadata": { ... },
"model_used": "microsoft/Phi-3-mini-4k-instruct",
"generation_time_seconds": 622.1,
"token_count": 387,
"created_at": "2026-02-26T11:36:58Z",
"warnings": []
}
```
---
## Pillar 3 — Assessment
### `POST /api/v1/assessment/generate`
#### Request body
```json
{
"request_id": "abc123",
"subject": "mathematics",
"topic": "Quadratic Equations",
"assessment_type": "EXAM_QUESTIONS",
"curriculum_board": "WAEC",
"learner_profile": {
"education_level": "SSS3",
"program_type": "ACADEMIC"
},
"bloom_level": "APPLY",
"difficulty": "MIXED",
"question_format": "MIXED",
"num_questions": 10,
"target_skills": ["Numerical Reasoning"],
"output_language": "en",
"cultural_context": { "use_local_names": true },
"include_answer_key": true,
"include_marking_guide": true,
"include_bloom_tags": true,
"include_difficulty_tags": true,
"include_topic_tags": true,
"use_rag": true,
"max_tokens": 2048
}
```
| Field | Required | Default | Notes |
|---|---|---|---|
| `subject` | ✅ | — | |
| `topic` | ✅ | — | 3–200 characters |
| `assessment_type` | ✅ | — | `QUIZ`, `EXAM_QUESTIONS`, `QUESTION_BANK`, `DIAGNOSTIC_TEST`, `MARKING_SCHEME`, `RUBRIC`, `REMEDIATION_EXERCISE` |
| `curriculum_board` | — | `WAEC` | |
| `bloom_level` | — | `UNDERSTAND` | |
| `difficulty` | — | `MEDIUM` | `EASY`, `MEDIUM`, `HARD`, `MIXED` |
| `question_format` | — | `MIXED` | `MULTIPLE_CHOICE`, `TRUE_FALSE`, `SHORT_ANSWER`, `FILL_IN_THE_BLANK`, `ESSAY`, `STRUCTURED`, `MIXED` |
| `num_questions` | — | `10` | 1–100 |
| `max_tokens` | — | `2048` | 256–4096 |
#### Response body
```json
{
"request_id": "abc123",
"assessment_type": "EXAM_QUESTIONS",
"subject": "mathematics",
"topic": "Quadratic Equations",
"curriculum_board": "WAEC",
"questions": [
{
"question_number": 1,
"question_text": "Solve x² - 5x + 6 = 0",
"question_format": "SHORT_ANSWER",
"bloom_level": "APPLY",
"difficulty": "MEDIUM",
"skill_tags": [
{ "skill_name": "Numerical Reasoning", "skill_domain": "cognitive", "parent_skill": null }
],
"topic_tags": ["quadratic", "algebra"],
"options": null,
"answer": "x = 2 or x = 3",
"explanation": "Factorise as (x-2)(x-3) = 0",
"marks": 3
}
],
"raw_output": "Q1. [SHORT_ANSWER] [Bloom: APPLY]...",
"total_marks": 30,
"estimated_duration_minutes": 60,
"bloom_distribution": { "APPLY": 7, "ANALYZE": 3 },
"difficulty_distribution": { "EASY": 2, "MEDIUM": 5, "HARD": 3 },
"skill_distribution": { "Numerical Reasoning": 6, "Critical Thinking": 4 },
"validation": { ... },
"model_used": "microsoft/Phi-3-mini-4k-instruct",
"generation_time_seconds": 598.2,
"created_at": "2026-02-26T10:50:49Z",
"warnings": []
}
```
---
## Pillar 4 — Insights (Diagnostics)
### `POST /api/v1/insights/analyze`
Send existing content to get a quality diagnostic — no generation happens.
#### Request body
```json
{
"request_id": "abc123",
"content": "## Lesson Plan: Pythagoras Theorem...",
"content_type": "LESSON_PLAN",
"subject": "mathematics",
"education_level": "SSS1",
"curriculum_board": "NERDC",
"expected_bloom_level": "UNDERSTAND",
"expected_language": "en",
"expected_skills": ["Critical Thinking", "Problem Solving"],
"run_readability": true,
"run_bloom_analysis": true,
"run_cultural_analysis": true,
"run_skill_gap_analysis": true,
"run_curriculum_gap_analysis": false
}
```
| Field | Required | Notes |
|---|---|---|
| `content` | ✅ | Min 10 characters — the text to analyse |
| `content_type` | ✅ | Free string e.g. `"LESSON_PLAN"` |
| All other fields | — | Optional; used to compute gap analysis |
#### Response body
```json
{
"request_id": "abc123",
"readability": {
"flesch_kincaid_grade": 9.2,
"complexity_band": "secondary"
},
"bloom_analysis": {
"detected_level": "UNDERSTAND",
"verbs_found": ["explain", "describe", "summarise"],
"confidence": 0.91
},
"cultural_analysis": {
"local_name_ratio": 0.78,
"local_example_count": 4,
"flags": []
},
"skill_tags_detected": [
{ "skill_name": "Critical Thinking", "skill_domain": "cognitive", "parent_skill": null }
],
"skill_gap_analysis": {
"expected": ["Critical Thinking", "Problem Solving"],
"detected": ["Critical Thinking"],
"missing": ["Problem Solving"]
},
"curriculum_coverage": null,
"gap_analysis": null,
"overall_quality_score": 0.82,
"recommendations": [
"Add problem-solving activities targeting APPLY level",
"Include local market-based examples"
],
"created_at": "2026-02-26T11:00:00Z"
}
```
---
## Enum quick reference
### `subject`
`mathematics` · `english_language` · `biology` · `chemistry` · `physics` · `further_mathematics` · `economics` · `government` · `geography` · `history` · `civic_education` · `social_studies` · `yoruba_language` · `igbo_language` · `hausa_language` · `french` · `computer_science` · `basic_science` · `agricultural_science` · `home_economics` · `visual_art` · `music` · `physical_education` · `financial_accounting` · `commerce` · `crs` · `irs` · `financial_literacy` · `health_education` · `digital_literacy` · `entrepreneurship` · `agriculture_extension` · `trade_skill` · `custom_subject`
### `output_language`
| Code | Language |
|---|---|
| `en` | English |
| `yo` | Yoruba |
| `ig` | Igbo |
| `ha` | Hausa |
| `pcm` | Nigerian Pidgin |
| `en-yo` | Mixed English–Yoruba |
| `en-ha` | Mixed English–Hausa |
| `en-ig` | Mixed English–Igbo |
| `tw` | Twi (Akan) |
| `ee` | Ewe |
---
## The 8 validation rules
Every generated response includes a `validation` object. These rules run in ~50ms with no LLM involved. The file is `app/validation/rules.py`.
| Rule | What it checks | Fail type |
|---|---|---|
| `length_check` | Content length is between 25% and 600% of `max_tokens` (in chars) | Soft |
| `language_detection` | Detected language matches `output_language` at >85% confidence | Soft |
| `bloom_verb_presence` | At least one Bloom verb for the requested level appears in the text | Soft |
| `cultural_flag_check` | Western name ratio does not exceed 60% of all names found | Soft |
| `format_compliance` | Structural requirements per type (lesson plan needs objective/activity/assessment sections; assessments need question marks; schemes need week/term numbers) | Soft |
| `no_hallucinated_dates` | No years outside 1800–2030 | Soft |
| `no_explicit_content` | No profane or explicit terms (context-aware regex) | **Hard** — blocks immediately, judge never runs |
| `curriculum_alignment` | At least 3 board-specific keywords appear (NERDC: objective, activity, evaluation… WAEC: question, mark, answer…) | Soft |
**Soft fail** → TinyLlama judge runs and scores 1–5. If average ≥ 3.5 the content is approved (`FLAGGED`). If < 3.5 the content is rewritten (up to 2 attempts).
**Hard fail** → content is rejected immediately (`FAILED`), no judge.