Spaces:
Paused
A newer version of the Gradio SDK is available: 6.20.0
API Contract
Version: 1.0
Base URL: /api/v1
Format: JSON
Authentication: Session-based (session_id in headers or cookies)
Table of Contents
- Session Management
- Lesson Initialization
- Vocabulary Endpoints
- Grammar Endpoints
- Exercise Endpoints
- Test Endpoints
- Error Responses
- State Queries
Session Management
Start New Session
Endpoint: POST /session/start
Request:
{
"user_id": "user_123",
"lesson_number": 3
}
Response:
{
"session_id": "sess_abc123",
"user_id": "user_123",
"lesson_number": 3,
"created_at": "2026-04-04T10:30:00Z",
"state": {
"vocab_mode": "not_started",
"grammar_mode": "not_started",
"vocab_batches_completed": [],
"grammar_topics_completed": []
}
}
Get Session State
Endpoint: GET /session/{session_id}
Response:
{
"session_id": "sess_abc123",
"user_id": "user_123",
"lesson_number": 3,
"state": {
"vocab_mode": "batch_quiz",
"current_vocab_batch": 2,
"vocab_batches_completed": [1],
"vocab_batch_scores": {"1": "2/3"},
"vocab_words_missed": ["ู
ูุฏูุฑูุณูุฉ"],
"grammar_mode": "not_started",
"grammar_topics_completed": [],
"current_grammar_topic": null
}
}
Lesson Initialization
Initialize Lesson
Endpoint: POST /lesson/initialize
Description: Loads all content into memory (Agent 3 caches vocabulary + grammar, Agent 2 loads with grading flexibility rules)
Request:
{
"session_id": "sess_abc123",
"lesson_number": 3
}
Response:
{
"success": true,
"lesson_number": 3,
"lesson_structure": {
"vocabulary": {
"total_words": 10,
"batch_structure": [3, 3, 3, 1],
"batches_count": 4
},
"grammar": {
"topics": ["feminine_nouns", "definite_article"],
"topics_count": 2,
"quiz_questions_per_topic": 5
}
},
"message": "Lesson 3 ready! Start with vocabulary or grammar?",
"next_actions": [
{"action": "start_vocab", "label": "Start Vocabulary (10 words)"},
{"action": "start_grammar", "label": "Start Grammar (2 topics)"},
{"action": "vocab_final_test", "label": "Skip to Vocabulary Test"}
]
}
Orchestrator Mapping:
orchestrator.initialize_lesson(lesson_number=3)
Vocabulary Endpoints
Start Vocabulary Section
Endpoint: POST /vocab/start
Request:
{
"session_id": "sess_abc123"
}
Response:
{
"success": true,
"message": "Let's learn 10 new words in 4 batches! Ready to start?",
"total_words": 10,
"batches_count": 4,
"next_action": {
"action": "get_batch",
"batch_number": 1
}
}
Get Vocabulary Batch
Endpoint: GET /vocab/batch/{batch_number}
Request: (batch_number in URL)
Response:
{
"success": true,
"lesson_number": 3,
"batch_number": 1,
"total_batches": 4,
"words": [
{
"word_id": "w1",
"arabic": "ููุชูุงุจ",
"transliteration": "kitaab",
"english": "book"
},
{
"word_id": "w2",
"arabic": "ู
ูุฏูุฑูุณูุฉ",
"transliteration": "madrasa",
"english": "school"
},
{
"word_id": "w3",
"arabic": "ููููู
",
"transliteration": "qalam",
"english": "pen"
}
],
"message": "Let's learn Batch 1! Here are your first 3 words:\n\n๐ ููุชูุงุจ (kitaab) - book\n๐ ู
ูุฏูุฑูุณูุฉ (madrasa) - school\n๐ ููููู
(qalam) - pen\n\nTake your time reviewing these. When you're ready, let's test your knowledge!",
"next_action": {
"action": "start_batch_quiz",
"batch_number": 1
}
}
Orchestrator Mapping:
orchestrator.get_vocab_batch(batch_number=1)
Start Batch Quiz
Endpoint: POST /vocab/batch/{batch_number}/quiz/start
Request:
{
"session_id": "sess_abc123"
}
Response:
{
"success": true,
"batch_number": 1,
"total_questions": 3,
"question_number": 1,
"question": {
"question_id": "q1",
"word_id": "w1",
"type": "arabic_to_english",
"prompt": "What does ููุชูุงุจ mean?",
"arabic": "ููุชูุงุจ",
"transliteration": "kitaab"
}
}
Submit Vocabulary Answer
Endpoint: POST /vocab/batch/{batch_number}/quiz/answer
Request:
{
"session_id": "sess_abc123",
"question_id": "q1",
"word_id": "w1",
"student_answer": "book"
}
Response (Correct):
{
"success": true,
"correct": true,
"feedback": "Correct! โ ููุชูุงุจ = book. Great job!",
"score": {
"current": "1/1",
"progress": "Question 1 of 3 complete"
},
"next_action": {
"action": "next_question",
"question_number": 2
}
}
Response (Incorrect):
{
"success": true,
"correct": false,
"student_answer": "school",
"correct_answer": "book",
"feedback": "Not quite! The word ููุชูุงุจ (kitaab) means 'book', not 'school'. Try to remember: kitaab = book.",
"score": {
"current": "0/1",
"progress": "Question 1 of 3 complete"
},
"next_action": {
"action": "next_question",
"question_number": 2
}
}
Orchestrator Mapping:
orchestrator.handle_vocab_quiz_answer(
batch_number=1,
question_id="q1",
word_id="w1",
student_answer="book"
)
Get Batch Quiz Summary
Endpoint: GET /vocab/batch/{batch_number}/quiz/summary
Response:
{
"success": true,
"batch_number": 1,
"score": "2/3",
"words_correct": ["ููุชูุงุจ", "ููููู
"],
"words_incorrect": [
{
"arabic": "ู
ูุฏูุฑูุณูุฉ",
"transliteration": "madrasa",
"correct_answer": "school",
"student_answer": "house"
}
],
"message": "Good effort! You got 2 out of 3 correct.\n\nYou missed:\nโข ู
ูุฏูุฑูุณูุฉ (madrasa) = school",
"next_action": {
"action": "get_batch",
"batch_number": 2,
"label": "Continue to Batch 2"
}
}
Start Vocabulary Final Test
Endpoint: POST /vocab/final-test/start
Request:
{
"session_id": "sess_abc123"
}
Response:
{
"success": true,
"message": "Final vocabulary test! All 10 words, randomized order.",
"total_questions": 10,
"test_type": "vocabulary_final",
"next_action": {
"action": "get_question",
"question_number": 1
}
}
Submit Final Test Answer
Endpoint: POST /vocab/final-test/answer
Request:
{
"session_id": "sess_abc123",
"question_number": 3,
"word_id": "w5",
"student_answer": "house"
}
Response:
{
"success": true,
"correct": true,
"feedback": "Correct! โ",
"score": {
"current": "3/3",
"total": 10,
"progress": "Question 3 of 10 complete"
},
"next_action": {
"action": "next_question",
"question_number": 4
}
}
Get Final Test Results
Endpoint: GET /vocab/final-test/results
Response:
{
"success": true,
"score": "8/10",
"percentage": 80,
"words_correct": 8,
"words_incorrect": [
{
"arabic": "ู
ูุฏูุฑูุณูุฉ",
"correct_answer": "school",
"student_answer": "house"
},
{
"arabic": "ุจูููุช",
"correct_answer": "house",
"student_answer": "door"
}
],
"message": "Great job! You scored 8 out of 10! ๐\n\nWords to review:\nโข ู
ูุฏูุฑูุณูุฉ (madrasa) = school\nโข ุจูููุช (bayt) = house",
"next_action": {
"action": "start_grammar",
"label": "Start Grammar Section"
}
}
Grammar Endpoints
Start Grammar Section
Endpoint: POST /grammar/start
Request:
{
"session_id": "sess_abc123"
}
Response:
{
"success": true,
"lesson_number": 3,
"topics": [
{
"topic_id": "feminine_nouns",
"topic_name": "Feminine Nouns",
"order": 1
},
{
"topic_id": "definite_article",
"topic_name": "Definite Article",
"order": 2
}
],
"message": "I'll teach you 2 grammar topics:\n1. Feminine Nouns\n2. Definite Article\n\nEach topic has a 5-question quiz. Ready to start?",
"next_action": {
"action": "get_topic",
"topic_id": "feminine_nouns"
}
}
Get Grammar Topic Explanation
Endpoint: GET /grammar/topic/{topic_id}
Response:
{
"success": true,
"lesson_number": 3,
"topic_id": "feminine_nouns",
"topic_name": "Feminine Nouns",
"explanation": "Let's learn about Feminine Nouns! ๐\n\n**The Rule:**\nIn Arabic, most feminine nouns end with ุฉ (taa marbuuta).\n\n**Examples:**\n- ู
ูุฏูุฑูุณูุฉ (madrasa) - school โ (ends in ุฉ)\n- ููุชูุงุจ (kitaab) - book (masculine, no ุฉ)\n\n**Quick Check:** Look at the word ุจูููุช (bint - girl). Does it end in ุฉ?",
"grammar_rule": "Feminine nouns usually end in ุฉ (taa marbuuta)",
"examples": [
{
"arabic": "ู
ูุฏูุฑูุณูุฉ",
"transliteration": "madrasa",
"english": "school",
"is_feminine": true,
"explanation": "ends in ุฉ"
},
{
"arabic": "ููุชูุงุจ",
"transliteration": "kitaab",
"english": "book",
"is_feminine": false,
"explanation": "no ุฉ - masculine"
}
],
"topics_remaining": 1,
"next_action": {
"action": "start_topic_quiz",
"topic_id": "feminine_nouns"
}
}
Orchestrator Mapping:
orchestrator.get_grammar_topic_explanation(topic_id="feminine_nouns")
Start Topic Quiz
Endpoint: POST /grammar/topic/{topic_id}/quiz/start
Request:
{
"session_id": "sess_abc123"
}
Response:
{
"success": true,
"topic_id": "feminine_nouns",
"topic_name": "Feminine Nouns",
"total_questions": 5,
"message": "Now let's test your understanding with 5 questions!",
"next_action": {
"action": "get_question",
"question_number": 1
}
}
Get Topic Quiz Question
Endpoint: GET /grammar/topic/{topic_id}/quiz/question/{question_number}
Response:
{
"success": true,
"topic_id": "feminine_nouns",
"question_number": 1,
"total_questions": 5,
"question": {
"question_id": "gq1",
"type": "identification",
"prompt": "Is 'ู
ูุฏูุฑูุณูุฉ' masculine or feminine?",
"arabic": "ู
ูุฏูุฑูุณูุฉ",
"transliteration": "madrasa",
"options": ["masculine", "feminine"]
}
}
Submit Topic Quiz Answer
Endpoint: POST /grammar/topic/{topic_id}/quiz/answer
Request:
{
"session_id": "sess_abc123",
"question_id": "gq1",
"question_number": 1,
"student_answer": "feminine"
}
Response (Correct):
{
"success": true,
"correct": true,
"feedback": "Correct! โ ู
ูุฏูุฑูุณูุฉ is feminine because it ends in ุฉ (taa marbuuta). You're doing great! (1/1 so far)",
"explanation": "The ุฉ ending is the key indicator of feminine nouns.",
"score": {
"current_topic": "1/1",
"questions_remaining": 4
},
"next_action": {
"action": "next_question",
"question_number": 2
}
}
Response (Incorrect):
{
"success": true,
"correct": false,
"student_answer": "masculine",
"correct_answer": "feminine",
"feedback": "Not quite. ู
ูุฏูุฑูุณูุฉ is feminine because it ends in ุฉ (taa marbuuta). The ุฉ is the key indicator! (0/1 so far)",
"errors": [
{
"error_type": "gender_identification",
"details": "ู
ูุฏูุฑูุณูุฉ ends in ุฉ, which indicates feminine",
"correction": "Look for the ุฉ (taa marbuuta) ending"
}
],
"score": {
"current_topic": "0/1",
"questions_remaining": 4
},
"next_action": {
"action": "next_question",
"question_number": 2
}
}
Orchestrator Mapping:
orchestrator.handle_grammar_quiz_answer(
topic_id="feminine_nouns",
question_id="gq1",
question_number=1,
student_answer="feminine"
)
Get Topic Quiz Results
Endpoint: GET /grammar/topic/{topic_id}/quiz/results
Response (Score >= 4/5):
{
"success": true,
"topic_id": "feminine_nouns",
"topic_name": "Feminine Nouns",
"score": "4/5",
"percentage": 80,
"passed": true,
"message": "Great job! You got 4 out of 5 correct! โ\n\nYou've mastered feminine nouns. Ready for the next topic?",
"questions_correct": 4,
"questions_incorrect": 1,
"next_action": {
"action": "get_topic",
"topic_id": "definite_article",
"label": "Continue to Next Topic"
}
}
Response (Score < 4/5 - Suggest Review):
{
"success": true,
"topic_id": "feminine_nouns",
"topic_name": "Feminine Nouns",
"score": "3/5",
"percentage": 60,
"passed": false,
"message": "You got 3 out of 5. You might want to review feminine nouns.\n\nWeak areas:\n- Identifying ุฉ endings\n- Exceptions to the rule\n\nReview and re-test, or move on?",
"questions_correct": 3,
"questions_incorrect": 2,
"weak_areas": [
"Identifying ุฉ endings",
"Exceptions to the rule"
],
"next_actions": [
{
"action": "review_topic",
"topic_id": "feminine_nouns",
"label": "Review and Re-test"
},
{
"action": "get_topic",
"topic_id": "definite_article",
"label": "Move to Next Topic"
}
]
}
Orchestrator Mapping:
orchestrator.get_topic_quiz_results(topic_id="feminine_nouns")
Exercise Endpoints
Generate Exercises
Endpoint: POST /exercises/generate
Request:
{
"session_id": "sess_abc123",
"lesson_number": 3,
"exercise_type": "fill_in_blank",
"grammar_point": "gender_agreement",
"count": 5
}
Response:
{
"success": true,
"exercise_set_id": "exset_123",
"lesson_number": 3,
"exercise_type": "fill_in_blank",
"count": 5,
"exercises": [
{
"exercise_id": "ex1",
"question": "Complete: ููุชูุงุจ ___",
"options": ["ููุจููุฑ", "ููุจููุฑูุฉ"],
"hint": "ูุชุงุจ is masculine"
},
{
"exercise_id": "ex2",
"question": "Complete: ู
ูุฏูุฑูุณูุฉ ___",
"options": ["ุตูุบููุฑ", "ุตูุบููุฑูุฉ"],
"hint": "ู
ุฏุฑุณุฉ is feminine"
},
{
"exercise_id": "ex3",
"question": "Complete: ููููู
___",
"options": ["ุฌูุฏููุฏ", "ุฌูุฏููุฏูุฉ"],
"hint": "ููู
is masculine"
},
{
"exercise_id": "ex4",
"question": "Complete: ุณููููุงุฑูุฉ ___",
"options": ["ููุจููุฑ", "ููุจููุฑูุฉ"],
"hint": "ุณูุงุฑุฉ is feminine"
},
{
"exercise_id": "ex5",
"question": "Complete: ุจูููุช ___",
"options": ["ุฌูู
ููู", "ุฌูู
ููููุฉ"],
"hint": "ุจูุช is masculine"
}
],
"message": "Here are 5 fill-in-blank exercises to practice gender agreement!"
}
Orchestrator Mapping:
orchestrator.generate_exercises(
lesson_number=3,
exercise_type="fill_in_blank",
grammar_point="gender_agreement",
count=5
)
Submit Exercise Answers
Endpoint: POST /exercises/{exercise_set_id}/submit
Request:
{
"session_id": "sess_abc123",
"answers": [
{"exercise_id": "ex1", "answer": "ููุจููุฑ"},
{"exercise_id": "ex2", "answer": "ุตูุบููุฑูุฉ"},
{"exercise_id": "ex3", "answer": "ุฌูุฏููุฏ"},
{"exercise_id": "ex4", "answer": "ููุจููุฑูุฉ"},
{"exercise_id": "ex5", "answer": "ุฌูู
ููููุฉ"}
]
}
Response:
{
"success": true,
"exercise_set_id": "exset_123",
"total_score": "4/5",
"percentage": 80,
"results": [
{
"exercise_id": "ex1",
"correct": true,
"student_answer": "ููุจููุฑ"
},
{
"exercise_id": "ex2",
"correct": true,
"student_answer": "ุตูุบููุฑูุฉ"
},
{
"exercise_id": "ex3",
"correct": true,
"student_answer": "ุฌูุฏููุฏ"
},
{
"exercise_id": "ex4",
"correct": true,
"student_answer": "ููุจููุฑูุฉ"
},
{
"exercise_id": "ex5",
"correct": false,
"student_answer": "ุฌูู
ููููุฉ",
"correct_answer": "ุฌูู
ููู",
"explanation": "ุจูููุช is masculine, so use ุฌูู
ููู (masculine)"
}
],
"message": "Great work! You got 4 out of 5 correct! ๐\n\nReview:\nโข Exercise 5: ุจูููุช is masculine, use ุฌูู
ููู"
}
Orchestrator Mapping:
orchestrator.grade_exercises(
exercise_set_id="exset_123",
answers=[...]
)
# Internally calls Agent 2 (GradingAgent) for each answer
# Returns {"correct": true/false} for each, with flexible grading:
# - Accepts synonyms (e.g., "instructor" โ "teacher")
# - Accepts minor typos (e.g., "scool" โ "school")
# - Accepts capitalization variations (e.g., "Book" โ "book")
# - For Arabic text: Internal harakaat optional, case endings required
Test Endpoints
Generate Lesson Test
Endpoint: POST /test/generate
Request:
{
"session_id": "sess_abc123",
"lesson_number": 3,
"question_count": 10
}
Response:
{
"success": true,
"test_id": "test_456",
"lesson_number": 3,
"question_count": 10,
"grammar_points": ["feminine_nouns", "definite_article"],
"message": "Lesson 3 Test - 10 questions covering all topics",
"questions": [
{
"question_id": "t1",
"type": "fill_in_blank",
"prompt": "Complete: ุงููุชุงุจ ___",
"options": ["ุงููุจูุฑ", "ูุจูุฑ"]
},
{
"question_id": "t2",
"type": "identification",
"prompt": "Is 'ุจูููุช' masculine or feminine?",
"options": ["masculine", "feminine"]
}
// ... 8 more questions
]
}
Submit Test Answers
Endpoint: POST /test/{test_id}/submit
Request:
{
"session_id": "sess_abc123",
"answers": [
{"question_id": "t1", "answer": "ุงููุจูุฑ"},
{"question_id": "t2", "answer": "feminine"}
// ... all 10 answers
]
}
Response:
{
"success": true,
"test_id": "test_456",
"total_score": "8/10",
"percentage": 80,
"passed": true,
"results_by_topic": {
"feminine_nouns": {
"score": "5/5",
"status": "excellent"
},
"definite_article": {
"score": "3/5",
"status": "needs_review"
}
},
"message": "Well done! You scored 8 out of 10! ๐\n\nStrengths:\n- Excellent at feminine nouns (5/5 correct)\n\nAreas to review:\n- Definite article agreement (3/5 correct)\n\nSuggestion: Review when to use ุงู with adjectives.\n\nReady to move to Lesson 4?",
"next_actions": [
{
"action": "review_topic",
"topic_id": "definite_article",
"label": "Review Definite Article"
},
{
"action": "next_lesson",
"lesson_number": 4,
"label": "Start Lesson 4"
}
]
}
Error Responses
Standard Error Format
All errors follow this structure:
{
"success": false,
"error": {
"code": "ERROR_CODE",
"message": "Human-readable error message",
"details": {}
}
}
Error Codes
Authentication/Session:
INVALID_SESSION(401) - Session ID not found or expiredSESSION_EXPIRED(401) - Session timed outUNAUTHORIZED(401) - User not authorized for this resource
Validation:
INVALID_REQUEST(400) - Malformed JSON or missing required fieldsINVALID_LESSON(400) - Lesson number doesn't existINVALID_BATCH(400) - Batch number out of rangeINVALID_TOPIC(400) - Topic ID not found in lesson
State:
LESSON_NOT_INITIALIZED(400) - Must call/lesson/initializefirstWRONG_MODE(400) - Action not allowed in current mode (e.g., trying to quiz before teaching)QUIZ_NOT_STARTED(400) - Must start quiz before submitting answers
RAG/Content:
CONTENT_NOT_FOUND(404) - Requested content not in RAG databaseRAG_TIMEOUT(504) - RAG query timed out
Agent:
AGENT_ERROR(500) - Agent returned invalid responseGENERATION_TIMEOUT(504) - Exercise/question generation timed outGRADING_ERROR(500) - Agent 2 (GradingAgent) failed to grade or returned invalid JSON
Error Examples
Invalid Session:
{
"success": false,
"error": {
"code": "INVALID_SESSION",
"message": "Session not found or expired",
"details": {
"session_id": "sess_invalid"
}
}
}
Lesson Not Initialized:
{
"success": false,
"error": {
"code": "LESSON_NOT_INITIALIZED",
"message": "Lesson must be initialized before starting vocabulary",
"details": {
"required_action": "POST /lesson/initialize"
}
}
}
Content Not Found:
{
"success": false,
"error": {
"code": "CONTENT_NOT_FOUND",
"message": "Lesson 99 not found in database",
"details": {
"lesson_number": 99,
"available_lessons": [1, 2, 3, 4, 5, 6, 7, 8]
}
}
}
State Queries
Get Current Progress
Endpoint: GET /progress/{session_id}
Response:
{
"success": true,
"lesson_number": 3,
"overall_progress": {
"vocabulary": {
"status": "in_progress",
"batches_completed": 2,
"batches_total": 4,
"scores": {"1": "2/3", "2": "3/3"},
"words_mastered": 5,
"words_total": 10
},
"grammar": {
"status": "not_started",
"topics_completed": 0,
"topics_total": 2,
"scores": {}
}
}
}
Implementation Notes
Session Management
Storage: Redis or in-memory cache (for demo)
Session Object:
{
"session_id": "sess_abc123",
"user_id": "user_123",
"lesson_number": 3,
"created_at": "2026-04-04T10:30:00Z",
"last_activity": "2026-04-04T11:00:00Z",
"expires_at": "2026-04-04T18:30:00Z", # 8 hours
# Full conversation state (from ARCHITECTURE.md)
"state": {
"vocab_mode": "batch_quiz",
"vocab_batches_completed": [1],
"current_vocab_batch": 2,
# ... full state schema
}
}
Rate Limiting
- 100 requests per minute per session
- 10 concurrent sessions per user
Response Times
Target latencies:
- Vocabulary/Grammar content: < 200ms (from cache)
- Single answer grading: < 500ms (Agent 2 GradingAgent with 7B model, max 50 tokens)
- Exercise generation: < 2s (Agent 3 LLM generation)
- Lesson initialization: < 3s (RAG query + caching)
Agent 2 (Grading Agent) Details
Model: Fine-tuned Qwen2.5-7B (baseline evaluated 2026-04-13)
Grading Modes:
grading_vocab - Vocabulary translation grading
- Input: word (Arabic), student_answer, correct_answer
- Output:
{"correct": true/false} - Flexibility: Accepts synonyms, typos, capitalization variations
grading_grammar (single question) - Grammar quiz question grading
- Input: question, student_answer, correct_answer
- Output:
{"correct": true/false} - Flexibility: Accepts abbreviations (m/f for masculine/feminine), synonyms, typos
- Arabic text: Internal harakaat optional, case endings (final harakaat) required
grading_grammar (multiple questions) - Test grading
- Input: lesson_number, answers (list of question/answer pairs)
- Output:
{"total_score": "X/Y", "results": [{"question_id": "...", "correct": true/false}, ...]}
Edge Case Handling:
- Synonyms: โ "instructor" = "teacher"
- Minor typos: โ "scool" = "school"
- Capitalization: โ "Book" = "book"
- Articles: โ "a pen" = "pen"
- Arabic harakaat: Internal marks optional (ุงููุชุงุจู = ุงูููุชูุงุจู), case endings required (ุงููุชุงุจ โ ุงูููุชูุงุจู)
Baseline Results (7B model, 2026-04-13):
- JSON compliance: 0-6% (adds explanations after JSON)
- Reasoning accuracy: 83% (5/6 correct decisions when ignoring format issues)
- Fine-tuning planned to address format compliance and harakaat flexibility
Next Steps for Implementation:
- Build orchestrator with these exact return formats
- Wrap orchestrator in FastAPI with these endpoints
- Frontend consumes these contracts exactly
Contract is versioned: If we need changes, create /api/v2