Spaces:
Sleeping
Sleeping
final-version
Browse files- agents/analysis_phase/objectives.py +1 -3
- agents/final_outliners/__init__.py +2 -0
- agents/final_outliners/axis_generator.py +198 -0
- agents/final_outliners/unit_generator.py +127 -0
- app.py +10 -160
- modules/__init__.py +0 -2
- modules/firebase_config.py +0 -44
- modules/firebase_credentials.json +0 -13
- requirements.txt +1 -1
- routers/objective_route.py +49 -0
- routers/outcome_route.py +49 -0
- routers/outliner_route.py +55 -0
- routers/training_route.py +48 -0
- schemas/__init__.py +8 -1
- schemas/outliner_schema.py +218 -0
agents/analysis_phase/objectives.py
CHANGED
|
@@ -127,8 +127,6 @@ objectives_task = Task(
|
|
| 127 |
"}\n"
|
| 128 |
"The output must be valid JSON, without markdown formatting or code blocks."
|
| 129 |
),
|
| 130 |
-
|
| 131 |
agent=objectives_generator,
|
| 132 |
-
# context=[outline_task],
|
| 133 |
-
human_input=False,
|
| 134 |
)
|
|
|
|
| 127 |
"}\n"
|
| 128 |
"The output must be valid JSON, without markdown formatting or code blocks."
|
| 129 |
),
|
| 130 |
+
output_json=LearningObjectivesOutput,
|
| 131 |
agent=objectives_generator,
|
|
|
|
|
|
|
| 132 |
)
|
agents/final_outliners/__init__.py
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from .unit_generator import unit_generation_task, unit_generator_agent
|
| 2 |
+
from .axis_generator import axis_generator_agent, axis_generation_task
|
agents/final_outliners/axis_generator.py
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from crewai import Agent, Task, Crew, Process, LLM
|
| 2 |
+
import os
|
| 3 |
+
import json
|
| 4 |
+
from modules import output_dir, llm
|
| 5 |
+
from schemas import FullCurriculumStructure
|
| 6 |
+
|
| 7 |
+
axis_generator_agent = Agent(
|
| 8 |
+
|
| 9 |
+
role="Arabic Educational Subtopic Generator (Subtopic Developer)",
|
| 10 |
+
|
| 11 |
+
goal=(
|
| 12 |
+
"Analyze the provided metadata ({topic}, {domain}, {audience}, {content_type}, {material_type}) "
|
| 13 |
+
"along with the CurriculumStructure (main concept, related concepts, and units). "
|
| 14 |
+
# "Receive the output of the unit generator (which includes units titles and focuses). "
|
| 15 |
+
"For each unit — based on its title and focus — generate 5 coherent and progressive Arabic subtopics (axes). "
|
| 16 |
+
"These subtopics should represent a logical and educational flow from foundational understanding "
|
| 17 |
+
"to advanced application and creativity. "
|
| 18 |
+
|
| 19 |
+
# "Each axis should represent a specific stage of learning progression — starting from basic knowledge acquisition "
|
| 20 |
+
# "and moving toward critical thinking and creative application. "
|
| 21 |
+
"Each axis should correspond to a cognitive stage: remembering, understanding, applying, analyzing, evaluating, and creating. "
|
| 22 |
+
|
| 23 |
+
"Ensure that the axes are written as Arabic educational subheadings that align with the unit’s focus, "
|
| 24 |
+
"support conceptual growth, and maintain thematic coherence across the curriculum."
|
| 25 |
+
"Ensure all axes are contextually relevant to the unit's focus and contribute to the learner's comprehensive understanding."
|
| 26 |
+
|
| 27 |
+
"Additionally, before finalizing each axis, verify that it can be supported by available educational content such as articles, research papers, open educational resources, or online books. "
|
| 28 |
+
"Ensure that each axis represents a concept or topic that has sufficient publicly available Arabic or English educational materials that could be used for further learning content generation."
|
| 29 |
+
|
| 30 |
+
),
|
| 31 |
+
|
| 32 |
+
backstory=(
|
| 33 |
+
"You are a senior Arabic curriculum designer and learning progression specialist. "
|
| 34 |
+
"You possess deep expertise in Arabic pedagogy and cognitive development frameworks such as Bloom’s Taxonomy. "
|
| 35 |
+
"You skillfully expand each educational unit into coherent Arabic subtopics (axes) that reflect a logical learning progression — "
|
| 36 |
+
"starting from basic understanding and moving toward higher-order thinking and creative application. "
|
| 37 |
+
"Each axis builds upon the previous one to form a cohesive and culturally relevant learning journey. "
|
| 38 |
+
"Your designs prioritize conceptual clarity, educational depth, and alignment with Arabic academic standards."
|
| 39 |
+
"You also ensure that each generated subtopic (axis) is research-backed and can be supported by credible educational materials available online, enabling later integration with content retrieval systems."
|
| 40 |
+
|
| 41 |
+
),
|
| 42 |
+
|
| 43 |
+
output_format = (
|
| 44 |
+
"Return valid JSON strictly following this structure:\n"
|
| 45 |
+
"{\n"
|
| 46 |
+
" 'main_concept': '...',\n"
|
| 47 |
+
" 'related_concepts': ['...', '...'],\n"
|
| 48 |
+
" 'units': [\n"
|
| 49 |
+
" {\n"
|
| 50 |
+
" 'unit_number': 1,\n"
|
| 51 |
+
" 'title': 'الوحدة الأولى: ...',\n"
|
| 52 |
+
" 'focus': '...',\n"
|
| 53 |
+
" 'axes': [\n"
|
| 54 |
+
" {'axis_number': 1, 'title': '...', 'purpose': '...'},\n"
|
| 55 |
+
" {'axis_number': 2, 'title': '...', 'purpose': '...'},\n"
|
| 56 |
+
" {'axis_number': 3, 'title': '...', 'purpose': '...'},\n"
|
| 57 |
+
" {'axis_number': 4, 'title': '...', 'purpose': '...'},\n"
|
| 58 |
+
" {'axis_number': 5, 'title': '...', 'purpose': '...'}\n"
|
| 59 |
+
" ]\n"
|
| 60 |
+
" }, ...\n"
|
| 61 |
+
" ]\n"
|
| 62 |
+
"}"
|
| 63 |
+
),
|
| 64 |
+
|
| 65 |
+
examples = [
|
| 66 |
+
{
|
| 67 |
+
"input": {
|
| 68 |
+
"main_concept": "التفكير التصميمي",
|
| 69 |
+
"related_concepts": ["حل المشكلات", "اتخاذ القرار", "الإبداع", "تحسين العمليات"],
|
| 70 |
+
"units": [
|
| 71 |
+
{
|
| 72 |
+
"unit_number": 1,
|
| 73 |
+
"title": "الوحدة الأولى: مدخل إلى التفكير التصميمي",
|
| 74 |
+
"focus": "فهم المفهوم الجوهري وأبعاده الفكرية والنظرية"
|
| 75 |
+
},
|
| 76 |
+
{
|
| 77 |
+
"unit_number": 2,
|
| 78 |
+
"title": "الوحدة الثانية: الأدوات والمجالات العملية لتطبيق التفكير التصميمي",
|
| 79 |
+
"focus": "تطبيق أدوات التفكير التصميمي في بيئات واقعية ومجالات مختلفة"
|
| 80 |
+
},
|
| 81 |
+
{
|
| 82 |
+
"unit_number": 3,
|
| 83 |
+
"title": "الوحدة الثالثة: التفكير التصميمي وحل المشكلات",
|
| 84 |
+
"focus": "توظيف التفكير التصميمي كمنهج فعال في معالجة التحديات وإيجاد حلول مبت��رة"
|
| 85 |
+
},
|
| 86 |
+
{
|
| 87 |
+
"unit_number": 4,
|
| 88 |
+
"title": "الوحدة الرابعة: التفكير التصميمي مدخل لتطوير مهارات اتخاذ القرار",
|
| 89 |
+
"focus": "استخدام التفكير التصميمي كأداة لتحسين جودة القرارات وتطوير مهارات المفكر التصميمي"
|
| 90 |
+
}
|
| 91 |
+
]
|
| 92 |
+
},
|
| 93 |
+
"output": {
|
| 94 |
+
"units": [
|
| 95 |
+
{
|
| 96 |
+
"unit_number": 1,
|
| 97 |
+
"title": "الوحدة الأولى: مدخل إلى التفكير التصميمي",
|
| 98 |
+
"focus": "فهم المفهوم الجوهري وأبعاده الفكرية والنظرية",
|
| 99 |
+
"axes": [
|
| 100 |
+
{"axis_number": 1, "title": "ما هو التفكير التصميمي؟", "purpose": "تعريف المفهوم وشرح جوهره الفلسفي والعملي"},
|
| 101 |
+
{"axis_number": 2, "title": "أهمية التفكير التصميمي", "purpose": "إبراز الدور الحيوي للتفكير التصميمي في الإبداع والابتكار"},
|
| 102 |
+
{"axis_number": 3, "title": "المبادئ الأساسية للتفكير التصميمي", "purpose": "توضيح الأسس التي يقوم عليها النهج التصميمي"},
|
| 103 |
+
{"axis_number": 4, "title": "المراحل الخمس للتفكير التصميمي", "purpose": "شرح خطوات العملية التصميمية من التعاطف إلى الاختبار"},
|
| 104 |
+
{"axis_number": 5, "title": "نماذج تطبيقية ناجحة للتفكير التصميمي", "purpose": "عرض أمثلة عملية من مؤسسات استخدمت التفكير التصميمي بفعالية"}
|
| 105 |
+
]
|
| 106 |
+
},
|
| 107 |
+
{
|
| 108 |
+
"unit_number": 2,
|
| 109 |
+
"title": "الوحدة الثانية: الأدوات والمجالات العملية لتطبيق التفكير التصميمي",
|
| 110 |
+
"focus": "تطبيق أدوات التفكير التصميمي في بيئات واقعية ومجالات مختلفة",
|
| 111 |
+
"axes": [
|
| 112 |
+
{"axis_number": 1, "title": "استخدامات التفكير التصميمي", "purpose": "توضيح المجالات التي يمكن تطبيق التفكير التصميمي فيها"},
|
| 113 |
+
{"axis_number": 2, "title": "ستة مجالات عملية يظهر فيها أثر التفكير التصميمي", "purpose": "عرض تطبيقات التفكير التصميمي في مجالات متنوعة"},
|
| 114 |
+
{"axis_number": 3, "title": "أدوات التفكير التصميمي", "purpose": "تعريف المتعلم بأهم الأدوات والوسائل المستخدمة في العملية التصميمية"},
|
| 115 |
+
{"axis_number": 4, "title": "عوامل يجب مراعاتها عند تنفيذ عملية التفكير التصميمي", "purpose": "توضيح الاعتبارات التي تضمن نجاح التطبيق"},
|
| 116 |
+
{"axis_number": 5, "title": "التحديات الشائعة في التفكير التصميمي", "purpose": "تحليل العقبات التي تواجه الفرق عند تطبيق هذا النهج"}
|
| 117 |
+
]
|
| 118 |
+
},
|
| 119 |
+
{
|
| 120 |
+
"unit_number": 3,
|
| 121 |
+
"title": "الوحدة الثالثة: التفكير التصميمي وحل المشكلات",
|
| 122 |
+
"focus": "توظيف التفكير التصميمي كمنهج فعال في معالجة التحديات وإيجاد حلول مبتكرة",
|
| 123 |
+
"axes": [
|
| 124 |
+
{"axis_number": 1, "title": "ماذا يعني حل المشكلة؟", "purpose": "توضيح المفهوم النظري والعملي لحل المشكلات"},
|
| 125 |
+
{"axis_number": 2, "title": "أربع خطوات لحل المشكلة", "purpose": "شرح المراحل الأساسية في عملية حل المشكلات"},
|
| 126 |
+
{"axis_number": 3, "title": "الفرق بين التفكير التحليلي والتصميمي في حل المشكلات", "purpose": "المقارنة بين نهجين مختلفين في معالجة القضايا"},
|
| 127 |
+
{"axis_number": 4, "title": "نهج التفكير التصميمي لحل المشكلات", "purpose": "شرح كيفية استخدام التفكير التصميمي لإيجاد حلول مبتكرة"},
|
| 128 |
+
{"axis_number": 5, "title": "نماذج تطبيقية ناجحة في حل المشكلات بالتفك��ر التصميمي", "purpose": "تقديم دراسات حالة توضح نجاح النهج التصميمي في معالجة قضايا واقعية"}
|
| 129 |
+
]
|
| 130 |
+
},
|
| 131 |
+
{
|
| 132 |
+
"unit_number": 4,
|
| 133 |
+
"title": "الوحدة الرابعة: التفكير التصميمي مدخل لتطوير مهارات اتخاذ القرار",
|
| 134 |
+
"focus": "استخدام التفكير التصميمي كأداة لتحسين جودة القرارات وتطوير مهارات المفكر التصميمي",
|
| 135 |
+
"axes": [
|
| 136 |
+
{"axis_number": 1, "title": "ما هو اتخاذ القرار؟", "purpose": "تعريف عملية اتخاذ القرار وعناصرها الأساسية"},
|
| 137 |
+
{"axis_number": 2, "title": "خصائص المفكر التصميمي ودوره في تحسين القرارات", "purpose": "توضيح السمات الشخصية والعقلية للمفكر التصميمي"},
|
| 138 |
+
{"axis_number": 3, "title": "العلاقة بين التفكير التصميمي واتخاذ القرار", "purpose": "شرح كيفية مساهمة النهج التصميمي في اتخاذ قرارات فعالة"},
|
| 139 |
+
{"axis_number": 4, "title": "سبع خطوات لعملية اتخاذ القرار باستخدام التفكير التصميمي", "purpose": "عرض مراحل متكاملة لاتخاذ القرار بأسلوب تصميمي"},
|
| 140 |
+
{"axis_number": 5, "title": "كيف انعكس التفكير التصميمي في قرارات ناجحة؟", "purpose": "عرض أمثلة واقعية لنجاحات عملية في قرارات اتخذت عبر التفكير التصميمي"}
|
| 141 |
+
]
|
| 142 |
+
}
|
| 143 |
+
]
|
| 144 |
+
}
|
| 145 |
+
}
|
| 146 |
+
],
|
| 147 |
+
|
| 148 |
+
llm=llm,
|
| 149 |
+
# llm=llm_5m,
|
| 150 |
+
allow_delegation=False,
|
| 151 |
+
verbose=True,
|
| 152 |
+
reasoning=True,
|
| 153 |
+
max_iter=100
|
| 154 |
+
)
|
| 155 |
+
|
| 156 |
+
# ============================================================
|
| 157 |
+
# 🧩 3. Axis Generation Task
|
| 158 |
+
# ============================================================
|
| 159 |
+
|
| 160 |
+
axis_generation_task = Task(
|
| 161 |
+
|
| 162 |
+
description=(
|
| 163 |
+
"## GOAL\n"
|
| 164 |
+
"Expand each educational unit from the Unit Generator output into 5 structured Arabic subtopics (axes). "
|
| 165 |
+
|
| 166 |
+
# "Each axis should develop the learner’s understanding progressively — starting with remembering, "
|
| 167 |
+
# "then understanding, applying, analyzing, and finally creating.\n"
|
| 168 |
+
"Each axis should represent a cognitive development stage — moving from foundational understanding to applied mastery.\n\n"
|
| 169 |
+
|
| 170 |
+
"## CONTEXT\n"
|
| 171 |
+
# "You are provided with a units_agent_conceptual JSON (containing the main concept, related concepts, and list of units). "
|
| 172 |
+
"You are provided with a CurriculumStructure JSON (containing the main concept, related concepts, and list of units). "
|
| 173 |
+
"Each unit includes a title and conceptual focus.\n\n"
|
| 174 |
+
"## STEPS\n"
|
| 175 |
+
"1. Read the CurriculumStructure carefully to understand the hierarchy and conceptual logic.\n"
|
| 176 |
+
"2. For each unit:\n"
|
| 177 |
+
" - Identify its conceptual focus.\n"
|
| 178 |
+
" - Generate 5 progressive subtopics (axes) that unfold logically.\n"
|
| 179 |
+
" - Each axis must include:\n"
|
| 180 |
+
" • 'axis_number': numerical order from 1 to 5.\n"
|
| 181 |
+
" • 'title': Arabic title that feels like a subheading in a textbook.\n"
|
| 182 |
+
" • 'purpose': one-sentence explanation of the educational goal behind that subtopic.\n\n"
|
| 183 |
+
|
| 184 |
+
"3. For each generated axis, verify conceptually that it can be expanded using available online educational content (articles, academic papers, or open textbooks).\n"
|
| 185 |
+
" - Prefer subtopics that are well-established in educational or academic literature.\n"
|
| 186 |
+
" - Avoid overly niche or abstract titles that would lack sufficient learning resources.\n\n"
|
| 187 |
+
|
| 188 |
+
"## NOTES\n"
|
| 189 |
+
# "- Make sure the subtopics flow naturally, covering introduction, comprehension, practice, and innovation.\n"
|
| 190 |
+
"- The 5 axes should reflect a natural flow following Bloom’s taxonomy: Remember → Understand → Apply → Analyze → Create.\n"
|
| 191 |
+
"- Ensure the titles sound academic, culturally appropriate, and pedagogically progressive.\n"
|
| 192 |
+
"- Return the result as a valid FullCurriculumStructure JSON containing all units with their axes."
|
| 193 |
+
),
|
| 194 |
+
|
| 195 |
+
expected_output="A FullCurriculumStructure JSON object containing all units and their respective 5 axes each.",
|
| 196 |
+
agent=axis_generator_agent,
|
| 197 |
+
output_json=FullCurriculumStructure,
|
| 198 |
+
)
|
agents/final_outliners/unit_generator.py
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from crewai import Agent, Task, Crew, Process, LLM
|
| 2 |
+
import os
|
| 3 |
+
import json
|
| 4 |
+
from modules import llm
|
| 5 |
+
from schemas import CurriculumStructure
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
unit_generator_agent = Agent(
|
| 9 |
+
role="Arabic Educational Unit Generator (Conceptual Curriculum Designer)",
|
| 10 |
+
goal=(
|
| 11 |
+
"Analyze the provided metadata ({topic}, {domain}, {audience}, {content_type}, {material_type}). "
|
| 12 |
+
"Understand the main concept and its related sub-concepts within the topic title. "
|
| 13 |
+
# "Generate 4 educational units that fully cover all the key aspects of the topic, "
|
| 14 |
+
"Design 4 coherent Arabic educational units that collectively cover the full conceptual scope of the topic. "
|
| 15 |
+
# "differentiate between the main and related concepts, and build meaningful learning flow. "
|
| 16 |
+
"Ensure that each unit builds upon the previous one — moving from conceptual understanding "
|
| 17 |
+
"to deeper analysis, differentiation, and application."
|
| 18 |
+
"Additionally, verify that each generated unit represents a concept or learning area that can be supported "
|
| 19 |
+
"by available educational materials such as online articles, academic papers, open courses, or textbooks. "
|
| 20 |
+
"Each unit should correspond to a topic that has sufficient real-world educational content, "
|
| 21 |
+
"so it can later be expanded into detailed axes and linked with web-based learning resources."
|
| 22 |
+
),
|
| 23 |
+
backstory=(
|
| 24 |
+
# "You are an expert Arabic curriculum designer who understands how to transform conceptual topics "
|
| 25 |
+
# "into coherent learning structures. You design units that reflect deep comprehension of the main topic "
|
| 26 |
+
# "and its related ideas, ensuring logical flow from foundational understanding to practical application. "
|
| 27 |
+
# "You write unit titles in Arabic that sound like chapters of a book, ready to be expanded later into subtopics."
|
| 28 |
+
"You are an expert Arabic curriculum designer specializing in conceptual and competency-based education. "
|
| 29 |
+
"You transform topics into structured learning journeys that reflect progressive understanding — "
|
| 30 |
+
"starting from foundational ideas and moving toward advanced, practical, or reflective application. "
|
| 31 |
+
"Your writing style for unit titles follows the elegance of Arabic academic chapters, "
|
| 32 |
+
"while maintaining clarity and purpose. Each unit’s focus must capture the essential learning outcomes "
|
| 33 |
+
"and intellectual goals of that section."
|
| 34 |
+
"You also ensure that each generated unit can be reinforced by real and accessible educational materials — "
|
| 35 |
+
"such as books, articles, or open educational resources — enabling future integration with automated content retrieval and enrichment systems."
|
| 36 |
+
),
|
| 37 |
+
output_format=(
|
| 38 |
+
"Return **valid JSON** matching the following structure:\n"
|
| 39 |
+
"{\n"
|
| 40 |
+
" 'main_concept': '...',\n"
|
| 41 |
+
" 'related_concepts': ['...', '...'],\n"
|
| 42 |
+
" 'units': [\n"
|
| 43 |
+
" {'unit_number': 1, 'title': 'الوحدة الأولى: ...', 'focus': '...'},\n"
|
| 44 |
+
" {'unit_number': 2, 'title': 'الوحدة الثانية: ...', 'focus': '...'},\n"
|
| 45 |
+
" {'unit_number': 3, 'title': 'الوحدة الثالثة: ...', 'focus': '...'},\n"
|
| 46 |
+
" {'unit_number': 4, 'title': 'الوحدة الرابعة: ...', 'focus': '...'}\n"
|
| 47 |
+
" ]\n"
|
| 48 |
+
"}"
|
| 49 |
+
),
|
| 50 |
+
examples=[
|
| 51 |
+
{
|
| 52 |
+
"input": {
|
| 53 |
+
"topic": "تقنيات التفكير التصميمي (Design Thinking) لحل المشكلات واتخاذ القرارات",
|
| 54 |
+
"domain": "الإدارة والتفكير الإبداعي",
|
| 55 |
+
"content_type": "تدريبي",
|
| 56 |
+
"audience": "القادة والمدربون والموظفون الإداريون",
|
| 57 |
+
"material_type": ["مفاهمية", "هيكلية", "إجرائية", "واقعية", "إبداعية"],
|
| 58 |
+
},
|
| 59 |
+
"output": {
|
| 60 |
+
"main_concept": "التفكير التصميمي",
|
| 61 |
+
"related_concepts": [
|
| 62 |
+
"حل المشكلات",
|
| 63 |
+
"اتخاذ القرار",
|
| 64 |
+
"الإبداع",
|
| 65 |
+
"تحسين العمليات",
|
| 66 |
+
],
|
| 67 |
+
"units": [
|
| 68 |
+
{
|
| 69 |
+
"unit_number": 1,
|
| 70 |
+
"title": "الوحدة الأولى: مدخل إلى التفكير التصميمي وفلسفته",
|
| 71 |
+
"focus": "فهم الأسس الفكرية والنظرية للتفكير التصميمي وموقعه ضمن أنماط التفكير الإبداعي.",
|
| 72 |
+
},
|
| 73 |
+
{
|
| 74 |
+
"unit_number": 2,
|
| 75 |
+
"title": "الوحدة الثانية: مراحل وأدوات تطبيق التفكير التصميمي",
|
| 76 |
+
"focus": "تعلّم الخطوات العملية وأهم الأدوات المنهجية لتطبيق التفكير التصميمي في المواقف الواقعية.",
|
| 77 |
+
},
|
| 78 |
+
{
|
| 79 |
+
"unit_number": 3,
|
| 80 |
+
"title": "الوحدة الثالثة: التفكير التصميمي كأداة لحل المشكلات المعقدة",
|
| 81 |
+
"focus": "تحليل العلاقة بين التفكير التصميمي والتفكير التحليلي عند التعامل مع القضايا التنظيمية والمهنية.",
|
| 82 |
+
},
|
| 83 |
+
{
|
| 84 |
+
"unit_number": 4,
|
| 85 |
+
"title": "الوحدة الرابعة: التفكير التصميمي كمدخل لاتخاذ القرارات الإبداعية",
|
| 86 |
+
"focus": "تطبيق التفكير التصميمي في اتخاذ قرارات استراتيجية مبتكرة وتحسين العمليات المؤسسية.",
|
| 87 |
+
},
|
| 88 |
+
],
|
| 89 |
+
},
|
| 90 |
+
}
|
| 91 |
+
],
|
| 92 |
+
llm=llm,
|
| 93 |
+
# llm=llm_5m,
|
| 94 |
+
allow_delegation=False,
|
| 95 |
+
reasoning=True,
|
| 96 |
+
max_iter=100,
|
| 97 |
+
verbose=True,
|
| 98 |
+
)
|
| 99 |
+
|
| 100 |
+
|
| 101 |
+
# ============================================================
|
| 102 |
+
# 🧠 4. Task Definition
|
| 103 |
+
# ============================================================
|
| 104 |
+
|
| 105 |
+
unit_generation_task = Task(
|
| 106 |
+
description=(
|
| 107 |
+
"## GOAL\n"
|
| 108 |
+
"Generate **4 comprehensive and logically structured Arabic educational units** that summarize all key aspects of the topic: {topic}.\n\n"
|
| 109 |
+
"## STEPS\n"
|
| 110 |
+
"1. Extract the **main concept** and its **related sub-concepts** from the topic title.\n"
|
| 111 |
+
"2. Divide the topic into **4 major units** that together form a complete conceptual narrative.\n"
|
| 112 |
+
"3. Ensure the units are **progressive** — starting from foundational understanding and moving toward practical or reflective application.\n"
|
| 113 |
+
"4. Phrase each unit title like an **Arabic book chapter**, clear, formal, and pedagogically meaningful.\n"
|
| 114 |
+
"5. Write each unit’s focus as a **short, outcome-oriented summary** describing the main skills, ideas, or insights learners will gain.\n\n"
|
| 115 |
+
"6. Ensure that each proposed unit corresponds to a topic that can be supported by available educational content on the web, "
|
| 116 |
+
"including Arabic or English articles, research papers, or learning materials. "
|
| 117 |
+
"Prefer units that align with well-documented or widely discussed educational themes.\n\n"
|
| 118 |
+
"## NOTE\n"
|
| 119 |
+
"- Each unit should represent a major conceptual pillar essential for fully understanding the topic.\n"
|
| 120 |
+
"- Titles should be phrased like Arabic book chapters, preparing readers for deeper exploration through future subtopics.\n"
|
| 121 |
+
"- Avoid overlap or repetition between units; instead, show logical and conceptual progression.\n"
|
| 122 |
+
"- Maintain an academic yet clear tone — precise, structured, and free from unnecessary jargon.\n"
|
| 123 |
+
),
|
| 124 |
+
expected_output="A `CurriculumStructure` JSON object containing: `main_concept`, `related_concepts`, and `units`.",
|
| 125 |
+
agent=unit_generator_agent,
|
| 126 |
+
output_json=CurriculumStructure,
|
| 127 |
+
)
|
app.py
CHANGED
|
@@ -1,4 +1,8 @@
|
|
| 1 |
import os
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
|
| 3 |
# Force HOME to /tmp so CrewAI doesn't try writing to /.local
|
| 4 |
os.environ["HOME"] = "/tmp"
|
|
@@ -11,47 +15,12 @@ os.makedirs("/tmp/.local/share", exist_ok=True)
|
|
| 11 |
os.makedirs("/tmp/crewai_data", exist_ok=True)
|
| 12 |
os.makedirs("/tmp/crewai_home", exist_ok=True)
|
| 13 |
|
| 14 |
-
from crewai import Crew, Process
|
| 15 |
-
|
| 16 |
-
import json
|
| 17 |
-
from fastapi import FastAPI
|
| 18 |
-
from agents.outliner_phase import (
|
| 19 |
-
research_agent,
|
| 20 |
-
research_task,
|
| 21 |
-
structure_agent,
|
| 22 |
-
structure_task,
|
| 23 |
-
design_task,
|
| 24 |
-
designer_agent,
|
| 25 |
-
review_agent,
|
| 26 |
-
review_task,
|
| 27 |
-
)
|
| 28 |
-
from agents.analysis_phase import (
|
| 29 |
-
outline_agent,
|
| 30 |
-
outline_task,
|
| 31 |
-
objectives_generator,
|
| 32 |
-
objectives_task,
|
| 33 |
-
outcomes_generator,
|
| 34 |
-
outcomes_task,
|
| 35 |
-
)
|
| 36 |
-
from modules import (
|
| 37 |
-
llm,
|
| 38 |
-
inputs,
|
| 39 |
-
# outlines,
|
| 40 |
-
# objectives,
|
| 41 |
-
init_firebase,
|
| 42 |
-
get_realtime_db,
|
| 43 |
-
get_firestore_db,
|
| 44 |
-
)
|
| 45 |
-
|
| 46 |
-
from schemas import OutlineInput, DNAMetadata, LearningObjectivesOutput, CurriculumOutline
|
| 47 |
-
|
| 48 |
|
| 49 |
app = FastAPI(title="AI Agent Project", version="1.0.0")
|
| 50 |
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
firestore_db = get_firestore_db()
|
| 55 |
|
| 56 |
|
| 57 |
# Example root endpoint
|
|
@@ -60,130 +29,11 @@ def read_root():
|
|
| 60 |
return {"message": "Welcome to AI Agent Project API 🚀"}
|
| 61 |
|
| 62 |
|
| 63 |
-
# -----------------------------------------------
|
| 64 |
-
# === Agent 1: Deep Semantic Topics Generator ===
|
| 65 |
-
# === Agent 2: Expander to 20 Topics ===
|
| 66 |
-
# === Agent 3: Module Organizer ===
|
| 67 |
-
# === Agent 4: Final Reviewer (اختياري) ===
|
| 68 |
-
# -----------------------------------------------
|
| 69 |
-
@app.post("/run_outliner_agents")
|
| 70 |
-
def run_outliner_agents(data: OutlineInput):
|
| 71 |
-
outline_crew = Crew(
|
| 72 |
-
agents=[research_agent, structure_agent, designer_agent, review_agent],
|
| 73 |
-
tasks=[research_task, structure_task, design_task, review_task],
|
| 74 |
-
process=Process.sequential,
|
| 75 |
-
)
|
| 76 |
-
|
| 77 |
-
inputs=data.dict()
|
| 78 |
-
user_inputs = DNAMetadata(
|
| 79 |
-
topic=inputs["topic"],
|
| 80 |
-
domain=inputs["domain"],
|
| 81 |
-
content_type=inputs["content_type"],
|
| 82 |
-
audience=inputs["audience"],
|
| 83 |
-
material_type=inputs["material_type"],
|
| 84 |
-
).dict()
|
| 85 |
-
|
| 86 |
-
result = outline_crew.kickoff(inputs=user_inputs)
|
| 87 |
-
|
| 88 |
-
print(result.json_dict)
|
| 89 |
-
return {"message": "Deep Semantic Topics Generator works well 🚀","result":result}
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
# ------------------------------------
|
| 93 |
-
# === Agent 5:Objectives Generator ===
|
| 94 |
-
# ------------------------------------
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
@app.post("/objectives")
|
| 98 |
-
def run_objectives(data: OutlineInput, outlines: CurriculumOutline):
|
| 99 |
-
objectives_crew = Crew(
|
| 100 |
-
agents=[objectives_generator],
|
| 101 |
-
tasks=[objectives_task],
|
| 102 |
-
process=Process.sequential,
|
| 103 |
-
)
|
| 104 |
-
inputs = data.dict()
|
| 105 |
-
user_inputs = DNAMetadata(
|
| 106 |
-
topic=inputs["topic"],
|
| 107 |
-
domain=inputs["domain"],
|
| 108 |
-
content_type=inputs["content_type"],
|
| 109 |
-
audience=inputs["audience"],
|
| 110 |
-
material_type=inputs["material_type"],
|
| 111 |
-
).dict()
|
| 112 |
-
merged_inputs = {**user_inputs, "outlines": outlines.dict()}
|
| 113 |
-
|
| 114 |
-
result = objectives_crew.kickoff(inputs=merged_inputs)
|
| 115 |
-
|
| 116 |
-
print(result.json_dict)
|
| 117 |
-
|
| 118 |
-
return {"message": "Objectives Generated Well 🚀","result":result}
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
# ------------------------------------
|
| 122 |
-
# === Agent 6:Outcomes Generator ===
|
| 123 |
-
# ------------------------------------
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
@app.post("/outcomes")
|
| 127 |
-
def run_outcomes(
|
| 128 |
-
data: OutlineInput, objectives: LearningObjectivesOutput):
|
| 129 |
-
outcomes_crew = Crew(
|
| 130 |
-
agents=[outcomes_generator],
|
| 131 |
-
tasks=[outcomes_task],
|
| 132 |
-
process=Process.sequential,
|
| 133 |
-
)
|
| 134 |
-
|
| 135 |
-
inputs = data.dict()
|
| 136 |
-
user_inputs = DNAMetadata(
|
| 137 |
-
topic=inputs["topic"],
|
| 138 |
-
domain=inputs["domain"],
|
| 139 |
-
content_type=inputs["content_type"],
|
| 140 |
-
audience=inputs["audience"],
|
| 141 |
-
material_type=inputs["material_type"],
|
| 142 |
-
).dict()
|
| 143 |
-
merged_inputs = {**user_inputs, "objectives": objectives.dict()}
|
| 144 |
-
|
| 145 |
-
result = outcomes_crew.kickoff(inputs=merged_inputs)
|
| 146 |
-
print(result.json_dict)
|
| 147 |
-
|
| 148 |
-
return {"message": "Outcomes Generated Well 🚀", "result": result}
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
###########################################################
|
| 152 |
-
|
| 153 |
-
# ------------------------------------
|
| 154 |
-
# === Agent 7:Outcomes Generator ===
|
| 155 |
-
# ------------------------------------
|
| 156 |
-
|
| 157 |
-
|
| 158 |
-
@app.get("/training")
|
| 159 |
-
def run_training(data: OutlineInput, objectives: LearningObjectivesOutput):
|
| 160 |
-
training_crew = Crew(
|
| 161 |
-
agents=[outcomes_generator],
|
| 162 |
-
tasks=[outcomes_task],
|
| 163 |
-
process=Process.sequential,
|
| 164 |
-
)
|
| 165 |
-
|
| 166 |
-
inputs = data.dict()
|
| 167 |
-
user_inputs = DNAMetadata(
|
| 168 |
-
topic=inputs["topic"],
|
| 169 |
-
domain=inputs["domain"],
|
| 170 |
-
content_type=inputs["content_type"],
|
| 171 |
-
audience=inputs["audience"],
|
| 172 |
-
material_type=inputs["material_type"],
|
| 173 |
-
).dict()
|
| 174 |
-
|
| 175 |
-
merged_inputs = {**user_inputs, "objectives": objectives.dict()}
|
| 176 |
-
result = training_crew.kickoff(inputs=merged_inputs)
|
| 177 |
-
print(result.json_dict)
|
| 178 |
-
|
| 179 |
-
return {"message": "Outcomes Generated Well 🚀", "result": result}
|
| 180 |
-
|
| 181 |
-
|
| 182 |
# ------------------------
|
| 183 |
# ✅ نقطة تشغيل السيرفر
|
| 184 |
# ------------------------
|
| 185 |
|
| 186 |
-
if __name__ == "__main__":
|
| 187 |
-
|
| 188 |
|
| 189 |
-
|
|
|
|
| 1 |
import os
|
| 2 |
+
from crewai import Crew, Process
|
| 3 |
+
import json
|
| 4 |
+
from fastapi import FastAPI
|
| 5 |
+
from routers import objective_route, outliner_route, outcome_route
|
| 6 |
|
| 7 |
# Force HOME to /tmp so CrewAI doesn't try writing to /.local
|
| 8 |
os.environ["HOME"] = "/tmp"
|
|
|
|
| 15 |
os.makedirs("/tmp/crewai_data", exist_ok=True)
|
| 16 |
os.makedirs("/tmp/crewai_home", exist_ok=True)
|
| 17 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
|
| 19 |
app = FastAPI(title="AI Agent Project", version="1.0.0")
|
| 20 |
|
| 21 |
+
app.include_router(outliner_route.router)
|
| 22 |
+
app.include_router(objective_route.router)
|
| 23 |
+
app.include_router(outcome_route.router)
|
|
|
|
| 24 |
|
| 25 |
|
| 26 |
# Example root endpoint
|
|
|
|
| 29 |
return {"message": "Welcome to AI Agent Project API 🚀"}
|
| 30 |
|
| 31 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 32 |
# ------------------------
|
| 33 |
# ✅ نقطة تشغيل السيرفر
|
| 34 |
# ------------------------
|
| 35 |
|
| 36 |
+
# if __name__ == "__main__":
|
| 37 |
+
# import uvicorn
|
| 38 |
|
| 39 |
+
# uvicorn.run("main:app", host="127.0.0.1", port=8000, reload=True)
|
modules/__init__.py
CHANGED
|
@@ -15,5 +15,3 @@ from .directory import (
|
|
| 15 |
scraper_dir,
|
| 16 |
urls_dir
|
| 17 |
)
|
| 18 |
-
|
| 19 |
-
from .firebase_config import init_firebase, get_realtime_db, get_firestore_db
|
|
|
|
| 15 |
scraper_dir,
|
| 16 |
urls_dir
|
| 17 |
)
|
|
|
|
|
|
modules/firebase_config.py
DELETED
|
@@ -1,44 +0,0 @@
|
|
| 1 |
-
import os
|
| 2 |
-
import json
|
| 3 |
-
import firebase_admin
|
| 4 |
-
from firebase_admin import credentials, db, firestore
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
def init_firebase():
|
| 8 |
-
"""
|
| 9 |
-
Initializes Firebase with credentials and database URL.
|
| 10 |
-
Works both locally (with firebase_credentials.json) and on Hugging Face Spaces (with FIREBASE_CREDENTIALS env variable).
|
| 11 |
-
"""
|
| 12 |
-
try:
|
| 13 |
-
if not firebase_admin._apps:
|
| 14 |
-
# لو شغال على Hugging Face Space – اقرأ من المتغير السري
|
| 15 |
-
firebase_json_str = os.getenv("FIREBASE_CREDENTIALS")
|
| 16 |
-
|
| 17 |
-
if firebase_json_str:
|
| 18 |
-
firebase_credentials = json.loads(firebase_json_str)
|
| 19 |
-
cred = credentials.Certificate(firebase_credentials)
|
| 20 |
-
else:
|
| 21 |
-
# لو شغال محليًا – اقرأ من الملف
|
| 22 |
-
cred = credentials.Certificate("modules/firebase_credentials.json")
|
| 23 |
-
|
| 24 |
-
firebase_admin.initialize_app(
|
| 25 |
-
cred,
|
| 26 |
-
{"databaseURL": "https://contiai-cfbff-default-rtdb.firebaseio.com/"},
|
| 27 |
-
)
|
| 28 |
-
print("✅ Firebase initialized successfully.")
|
| 29 |
-
except Exception as e:
|
| 30 |
-
print(f"❌ Error initializing Firebase: {e}")
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
def get_realtime_db():
|
| 34 |
-
"""
|
| 35 |
-
Returns a reference to the Firebase Realtime Database.
|
| 36 |
-
"""
|
| 37 |
-
return db.reference("/")
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
def get_firestore_db():
|
| 41 |
-
"""
|
| 42 |
-
Returns a reference to the Firestore client.
|
| 43 |
-
"""
|
| 44 |
-
return firestore.client()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
modules/firebase_credentials.json
DELETED
|
@@ -1,13 +0,0 @@
|
|
| 1 |
-
{
|
| 2 |
-
"type": "service_account",
|
| 3 |
-
"project_id": "contiai-cfbff",
|
| 4 |
-
"private_key_id": "586ff713c2ed3a1d61228378d01cc0bd6f4519ee",
|
| 5 |
-
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC1zGqYIBTS5qM+\nAge3H5FRNwbCVPDCVdDvm44GuIdaQ5SrTQuk/D9PV5L6W0FkMXVhrL/ihU6DxfFw\nx+q8pYGvesdqbbn3wCsgSz0C4aUeMroAKeNYUQgYo6mohAstSswYMk8szfP/NHey\n4RcBASbU4b5+yEFBhWEihBi41wLoXkgS04OVIfGKVJD+tcdE/iKxQtsbA3M/LfHX\nCmpm/2/20l/ONhysXOdXDjR3jKxNTTbVuSE1vL5nYhlPejEFr8ROheo0HpdmDxR7\n2Qiblc4x7sll3KvRfbWnObBsUQU3TL5c//oYdJyeSQWWMNPVA2chPkJbEa8IxkLS\nbCvjd4ylAgMBAAECggEAC3eTLawWxCrKFzCXl5eewFAUb0ORhobuzX5MjUrGA6dW\narh9+70kqfa5jZ/qvJm/o3z7AxwqrkMl2vN+CfVcL1szCUwi7WhD3OvOzS5TqCQs\nLIB35Guc2bkEPyqwOpe7zrbo3MgGeo17rPia5w3q8VIzHg1RmGlqWnv/xAD3IC/F\nV00RMKWr8n/6rVt1G/dnsHAQUYcxPxta6AlcqaKt4FPNVp3Jy4tEysYCNROckiQm\nkzWs19/e+c5DUZwTq4L3mHrOt1HA+0TNUqALn7MYXkq4+QZ7BsLzPuz7MgcO2PHg\njSXk7L9km+iSGE7MrQ67hpSvvxrb4wWsytpLyxEiLQKBgQDpO7xSvQ7XCwp3pByk\n91WE0+/LDbKdOyCke7EpJYCn2LxV0Mtg64uT9DbhvpB+G5MtTT+S7VNCCxYkD/wG\ng5SjoLkqG35GZRtfzM8s5oxmP9flUPSTpGxTPTFQ4v2+hGJbcHW0enzCHi4Affxe\nYOKXZ2uDy3S+2czKoInDLICJbwKBgQDHi2BVyJOH+eZocMXK7uN7gQRK2PEx+Tbh\nUSBPy/u77fmlnXUDSOhkUJJ449nOpDmXIP08vRDc7VSx0Nba5/OGIJPv+9zAnB77\nYS8ZV4FFR2V/vGhSA8Arw4ez+0hlmd0tZDU6K4qzd3+tol+5Gcx6blG6IJ/cm+vk\n1ZSpQkV5KwKBgAqhUV0IBuQgObLoRPHz3+705eoATtLBviQhCxsP/YQo6bSTlqFt\nOuhcah/x2o4U3alj6vDcZj4NWU39eIQnfR/UFHxp0mCM/SlpoUuvmliSslleTjdo\neBN3J4dDQUNsrzrxrjuylXsXewtEsrrueYVjDlBsdn64WJAnrv+5SIZ7AoGABhoI\n9BaSDFJj7UWlhrMPWbN0QiWoGnMYboNgjZAbPn/kZmAON+9+y7J7CB9PhbYX3Lsx\ngy302gyXzmgoacE1/R/55hi5g1pCyEUMf6XhWhD41ZMZTYi3057DA4nniNPPo5ew\n2PqD30EEMncInkxfqE6/SQW+XayW5gRx60sPfMkCgYANJV3w6Torl/6gGhcTdK81\nm7UNSQ5TOWGoyknGJlV2dnPXQH+l9doPdqGu/TZdtp7uhNJRxRyOZxq6iI+vvyPP\nt+ZWbB4x1qR2lsUI/3vCDtNpdsanoYFglIJpNSkSgs+dILy4CulUhsCPnT/y7QTp\nGDRfPtyjdtOQSZLlwljUEQ==\n-----END PRIVATE KEY-----\n",
|
| 6 |
-
"client_email": "firebase-adminsdk-fbsvc@contiai-cfbff.iam.gserviceaccount.com",
|
| 7 |
-
"client_id": "105916337677880596734",
|
| 8 |
-
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
|
| 9 |
-
"token_uri": "https://oauth2.googleapis.com/token",
|
| 10 |
-
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
|
| 11 |
-
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-fbsvc%40contiai-cfbff.iam.gserviceaccount.com",
|
| 12 |
-
"universe_domain": "googleapis.com"
|
| 13 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
requirements.txt
CHANGED
|
@@ -8,4 +8,4 @@ langchain_openai
|
|
| 8 |
litellm
|
| 9 |
openai
|
| 10 |
fastapi
|
| 11 |
-
|
|
|
|
| 8 |
litellm
|
| 9 |
openai
|
| 10 |
fastapi
|
| 11 |
+
crewai[anthropic]
|
routers/objective_route.py
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
from crewai import Crew, Process
|
| 3 |
+
import json
|
| 4 |
+
from fastapi import APIRouter, HTTPException, Depends
|
| 5 |
+
from agents.analysis_phase import (
|
| 6 |
+
objectives_generator,
|
| 7 |
+
objectives_task,
|
| 8 |
+
)
|
| 9 |
+
from modules import (
|
| 10 |
+
llm,
|
| 11 |
+
inputs,
|
| 12 |
+
)
|
| 13 |
+
from schemas import (
|
| 14 |
+
CurriculumStructure,
|
| 15 |
+
DNAMetadata,
|
| 16 |
+
OutlineInput,
|
| 17 |
+
)
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
router = APIRouter(prefix="/analysis", tags=["Objectives"])
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
# ------------------------------------
|
| 24 |
+
# === Agent 5:Objectives Generator ===
|
| 25 |
+
# ------------------------------------
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
@router.post("/objectives")
|
| 29 |
+
def run_objectives(data: OutlineInput, outlines: CurriculumStructure):
|
| 30 |
+
objectives_crew = Crew(
|
| 31 |
+
agents=[objectives_generator],
|
| 32 |
+
tasks=[objectives_task],
|
| 33 |
+
process=Process.sequential,
|
| 34 |
+
)
|
| 35 |
+
inputs = data.dict()
|
| 36 |
+
user_inputs = DNAMetadata(
|
| 37 |
+
topic=inputs["topic"],
|
| 38 |
+
domain=inputs["domain"],
|
| 39 |
+
content_type=inputs["content_type"],
|
| 40 |
+
audience=inputs["audience"],
|
| 41 |
+
material_type=inputs["material_type"],
|
| 42 |
+
).dict()
|
| 43 |
+
merged_inputs = {**user_inputs, "outlines": outlines.dict()}
|
| 44 |
+
|
| 45 |
+
result = objectives_crew.kickoff(inputs=merged_inputs)
|
| 46 |
+
|
| 47 |
+
print(result.json_dict)
|
| 48 |
+
|
| 49 |
+
return {"message": "Objectives Generated Well 🚀", "result": result}
|
routers/outcome_route.py
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
from crewai import Crew, Process
|
| 3 |
+
import json
|
| 4 |
+
from fastapi import APIRouter, HTTPException, Depends
|
| 5 |
+
from agents.analysis_phase import (
|
| 6 |
+
outcomes_generator,
|
| 7 |
+
outcomes_task,
|
| 8 |
+
)
|
| 9 |
+
from modules import (
|
| 10 |
+
llm,
|
| 11 |
+
inputs,
|
| 12 |
+
)
|
| 13 |
+
from schemas import (
|
| 14 |
+
LearningObjectivesOutput,
|
| 15 |
+
DNAMetadata,
|
| 16 |
+
OutlineInput,
|
| 17 |
+
)
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
router = APIRouter(prefix="/analysis", tags=["outcomes"])
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
# ------------------------------------
|
| 24 |
+
# === Agent 6:Outcomes Generator ===
|
| 25 |
+
# ------------------------------------
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
@router.post("/outcomes")
|
| 29 |
+
def run_outcomes(data: OutlineInput, objectives: LearningObjectivesOutput):
|
| 30 |
+
outcomes_crew = Crew(
|
| 31 |
+
agents=[outcomes_generator],
|
| 32 |
+
tasks=[outcomes_task],
|
| 33 |
+
process=Process.sequential,
|
| 34 |
+
)
|
| 35 |
+
|
| 36 |
+
inputs = data.dict()
|
| 37 |
+
user_inputs = DNAMetadata(
|
| 38 |
+
topic=inputs["topic"],
|
| 39 |
+
domain=inputs["domain"],
|
| 40 |
+
content_type=inputs["content_type"],
|
| 41 |
+
audience=inputs["audience"],
|
| 42 |
+
material_type=inputs["material_type"],
|
| 43 |
+
).dict()
|
| 44 |
+
merged_inputs = {**user_inputs, "objectives": objectives.dict()}
|
| 45 |
+
|
| 46 |
+
result = outcomes_crew.kickoff(inputs=merged_inputs)
|
| 47 |
+
print(result.json_dict)
|
| 48 |
+
|
| 49 |
+
return {"message": "Outcomes Generated Well 🚀", "result": result}
|
routers/outliner_route.py
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
from crewai import Crew, Process
|
| 3 |
+
import json
|
| 4 |
+
from fastapi import APIRouter, HTTPException, Depends
|
| 5 |
+
from agents.final_outliners import (
|
| 6 |
+
unit_generator_agent,
|
| 7 |
+
unit_generation_task,
|
| 8 |
+
axis_generator_agent,
|
| 9 |
+
axis_generation_task,
|
| 10 |
+
)
|
| 11 |
+
from modules import (
|
| 12 |
+
llm,
|
| 13 |
+
inputs,
|
| 14 |
+
)
|
| 15 |
+
from schemas import (
|
| 16 |
+
CurriculumStructure,
|
| 17 |
+
DNAMetadata,
|
| 18 |
+
OutlineInput,
|
| 19 |
+
)
|
| 20 |
+
|
| 21 |
+
router = APIRouter(prefix="/outliner", tags=["Authentication"])
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
# === Agent 1: Deep Semantic Topics Generator ===
|
| 25 |
+
# === Agent 2: Expander to 20 Topics ===
|
| 26 |
+
# === Agent 3: Module Organizer ===
|
| 27 |
+
# === Agent 4: Final Reviewer (اختياري) ===
|
| 28 |
+
# -----------------------------------------------
|
| 29 |
+
@router.post("/run_outliner_agents")
|
| 30 |
+
def run_outliner_agents(data: OutlineInput):
|
| 31 |
+
outline_crew = Crew(
|
| 32 |
+
agents=[
|
| 33 |
+
unit_generator_agent,
|
| 34 |
+
axis_generator_agent,
|
| 35 |
+
],
|
| 36 |
+
tasks=[
|
| 37 |
+
unit_generation_task,
|
| 38 |
+
axis_generation_task,
|
| 39 |
+
],
|
| 40 |
+
process=Process.sequential,
|
| 41 |
+
)
|
| 42 |
+
|
| 43 |
+
inputs = data.dict()
|
| 44 |
+
user_inputs = DNAMetadata(
|
| 45 |
+
topic=inputs["topic"],
|
| 46 |
+
domain=inputs["domain"],
|
| 47 |
+
content_type=inputs["content_type"],
|
| 48 |
+
audience=inputs["audience"],
|
| 49 |
+
material_type=inputs["material_type"],
|
| 50 |
+
).dict()
|
| 51 |
+
|
| 52 |
+
result = outline_crew.kickoff(inputs=user_inputs)
|
| 53 |
+
|
| 54 |
+
print(result.json_dict)
|
| 55 |
+
return {"message": "Deep Semantic Topics Generator works well 🚀", "result": result}
|
routers/training_route.py
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
from crewai import Crew, Process
|
| 3 |
+
import json
|
| 4 |
+
from fastapi import APIRouter, HTTPException, Depends
|
| 5 |
+
from agents.analysis_phase import (
|
| 6 |
+
training_agent,
|
| 7 |
+
training_task,
|
| 8 |
+
)
|
| 9 |
+
from modules import (
|
| 10 |
+
llm,
|
| 11 |
+
inputs,
|
| 12 |
+
)
|
| 13 |
+
from schemas import (
|
| 14 |
+
LearningObjectivesOutput,
|
| 15 |
+
DNAMetadata,
|
| 16 |
+
OutlineInput,
|
| 17 |
+
)
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
router = APIRouter(prefix="/analysis", tags=["training"])
|
| 21 |
+
|
| 22 |
+
# ------------------------------------
|
| 23 |
+
# === Agent 7:Training Generator ===
|
| 24 |
+
# ------------------------------------
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
@app.get("/training")
|
| 28 |
+
def run_training(data: OutlineInput, objectives: LearningObjectivesOutput):
|
| 29 |
+
training_crew = Crew(
|
| 30 |
+
agents=[training_agent],
|
| 31 |
+
tasks=[training_task],
|
| 32 |
+
process=Process.sequential,
|
| 33 |
+
)
|
| 34 |
+
|
| 35 |
+
inputs = data.dict()
|
| 36 |
+
user_inputs = DNAMetadata(
|
| 37 |
+
topic=inputs["topic"],
|
| 38 |
+
domain=inputs["domain"],
|
| 39 |
+
content_type=inputs["content_type"],
|
| 40 |
+
audience=inputs["audience"],
|
| 41 |
+
material_type=inputs["material_type"],
|
| 42 |
+
).dict()
|
| 43 |
+
|
| 44 |
+
merged_inputs = {**user_inputs, "objectives": objectives.dict()}
|
| 45 |
+
result = training_crew.kickoff(inputs=merged_inputs)
|
| 46 |
+
print(result.json_dict)
|
| 47 |
+
|
| 48 |
+
return {"message": "Outcomes Generated Well 🚀", "result": result}
|
schemas/__init__.py
CHANGED
|
@@ -4,7 +4,14 @@ from .extractor_schema import AllPartsOfContent, SinglePartOfContent, Section
|
|
| 4 |
from .keywoard_schema import SuggestedSearchQueries
|
| 5 |
from .objectives_schema import LearningObjectivesOutput
|
| 6 |
from .outcomes_schema import BloomOutcomesOutput
|
| 7 |
-
from .outliner_schema import
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
from .source_schema import AllResults, SingleResult
|
| 9 |
from .training_schema import TrainingProgramOutput
|
| 10 |
from .inputs_schema import OutlineInput
|
|
|
|
| 4 |
from .keywoard_schema import SuggestedSearchQueries
|
| 5 |
from .objectives_schema import LearningObjectivesOutput
|
| 6 |
from .outcomes_schema import BloomOutcomesOutput
|
| 7 |
+
from .outliner_schema import (
|
| 8 |
+
CurriculumOutline,
|
| 9 |
+
Unit,
|
| 10 |
+
DeepSemanticTopicsOutput,
|
| 11 |
+
ExpandedTopicsList,
|
| 12 |
+
CurriculumStructure,
|
| 13 |
+
FullCurriculumStructure,
|
| 14 |
+
)
|
| 15 |
from .source_schema import AllResults, SingleResult
|
| 16 |
from .training_schema import TrainingProgramOutput
|
| 17 |
from .inputs_schema import OutlineInput
|
schemas/outliner_schema.py
CHANGED
|
@@ -1,7 +1,225 @@
|
|
| 1 |
from pydantic import BaseModel, Field
|
| 2 |
from typing import List, Dict, Literal, Optional
|
|
|
|
| 3 |
|
|
|
|
| 4 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
# ========= 2. Schema for Units =========
|
| 6 |
class Unit(BaseModel):
|
| 7 |
module_title: str = Field(
|
|
|
|
| 1 |
from pydantic import BaseModel, Field
|
| 2 |
from typing import List, Dict, Literal, Optional
|
| 3 |
+
from .dna_schema import DNAMetadata
|
| 4 |
|
| 5 |
+
################==NEW==################
|
| 6 |
|
| 7 |
+
# Unit Generator Schema #
|
| 8 |
+
class Unit(BaseModel):
|
| 9 |
+
"""
|
| 10 |
+
Represents a single instructional unit within a curriculum.
|
| 11 |
+
|
| 12 |
+
Each unit is a focused section of the overall curriculum,
|
| 13 |
+
designed to teach a specific set of concepts or skills.
|
| 14 |
+
"""
|
| 15 |
+
|
| 16 |
+
unit_number: int = Field(
|
| 17 |
+
...,
|
| 18 |
+
title="The sequential number of this unit within the overall curriculum (e.g., 1, 2, 3).",
|
| 19 |
+
)
|
| 20 |
+
title: str = Field(
|
| 21 |
+
...,
|
| 22 |
+
title="Unit Title",
|
| 23 |
+
description="The Arabic title or name of the educational unit, clearly representing its theme or purpose.",
|
| 24 |
+
)
|
| 25 |
+
|
| 26 |
+
# focus: str = Field(..., title="Unit Focus", description="Brief note on what this unit emphasizes conceptually")
|
| 27 |
+
focus: str = Field(
|
| 28 |
+
...,
|
| 29 |
+
title="Unit Focus",
|
| 30 |
+
description=(
|
| 31 |
+
"A concise overview highlighting the main concepts, skills, and learning outcomes "
|
| 32 |
+
"covered in this unit. It describes what learners should understand or achieve after completing it."
|
| 33 |
+
"It sets the intellectual direction for the included axes."
|
| 34 |
+
),
|
| 35 |
+
)
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
class CurriculumStructure(BaseModel):
|
| 39 |
+
"""
|
| 40 |
+
Represents the full structure of a curriculum for a specific topic or program.
|
| 41 |
+
|
| 42 |
+
This model combines both conceptual metadata (via DNAMetadata) and pedagogical structure (via Unit).
|
| 43 |
+
It provides all the necessary contextual and educational information the AI agent or system
|
| 44 |
+
needs to generate, evaluate, or organize learning content effectively.
|
| 45 |
+
"""
|
| 46 |
+
|
| 47 |
+
# topic: str
|
| 48 |
+
# domain: str
|
| 49 |
+
# audience: str
|
| 50 |
+
# content_type: str
|
| 51 |
+
# material_type: List[str]
|
| 52 |
+
|
| 53 |
+
Metadata: List["DNAMetadata"] = Field(
|
| 54 |
+
...,
|
| 55 |
+
title="List of DNA Metadata Objects",
|
| 56 |
+
description=(
|
| 57 |
+
"A list of DNAMetadata items, where each item represents a distinct topic or concept "
|
| 58 |
+
"along with its domain, audience, content type, and material nature.\n"
|
| 59 |
+
"This allows the agent to process multiple curriculum components or educational segments "
|
| 60 |
+
"within a single structured input."
|
| 61 |
+
),
|
| 62 |
+
)
|
| 63 |
+
|
| 64 |
+
main_concept: str = Field(
|
| 65 |
+
...,
|
| 66 |
+
title="Main Concept",
|
| 67 |
+
description=(
|
| 68 |
+
"The central or core idea around which the curriculum is built. "
|
| 69 |
+
"It defines the overarching theme that connects all units and topics together."
|
| 70 |
+
),
|
| 71 |
+
)
|
| 72 |
+
|
| 73 |
+
related_concepts: List[str] = Field(
|
| 74 |
+
...,
|
| 75 |
+
title="Related Concepts",
|
| 76 |
+
description=(
|
| 77 |
+
"A set of secondary or supporting ideas that complement or expand upon the main concept. "
|
| 78 |
+
"These help the agent establish conceptual links and subtopics within the curriculum."
|
| 79 |
+
),
|
| 80 |
+
)
|
| 81 |
+
|
| 82 |
+
units: List[Unit] = Field(
|
| 83 |
+
...,
|
| 84 |
+
title="Curriculum Units",
|
| 85 |
+
description=(
|
| 86 |
+
"A detailed list of instructional units included in this curriculum. "
|
| 87 |
+
"Each unit includes its number, title, and conceptual focus to define its role "
|
| 88 |
+
"within the overall learning journey."
|
| 89 |
+
),
|
| 90 |
+
)
|
| 91 |
+
|
| 92 |
+
|
| 93 |
+
# Axis Generator Schema #
|
| 94 |
+
class Axis(BaseModel):
|
| 95 |
+
"""
|
| 96 |
+
Represents a single 'axis' or subtopic within an educational unit.
|
| 97 |
+
|
| 98 |
+
Each axis embodies a progressive learning step that moves from
|
| 99 |
+
basic understanding toward higher-order thinking such as
|
| 100 |
+
application, analysis, or creative synthesis.
|
| 101 |
+
"""
|
| 102 |
+
|
| 103 |
+
axis_number: int = Field(
|
| 104 |
+
...,
|
| 105 |
+
title="Axis Number",
|
| 106 |
+
description="The sequential order of this axis within the unit (1 to 5).",
|
| 107 |
+
)
|
| 108 |
+
|
| 109 |
+
title: str = Field(
|
| 110 |
+
...,
|
| 111 |
+
title="Axis Title",
|
| 112 |
+
description=(
|
| 113 |
+
"The Arabic title of the subtopic or 'axis' inside the unit. "
|
| 114 |
+
"Each axis defines a distinct conceptual or cognitive step "
|
| 115 |
+
"that contributes to the overall unit progression."
|
| 116 |
+
),
|
| 117 |
+
)
|
| 118 |
+
|
| 119 |
+
purpose: str = Field(
|
| 120 |
+
...,
|
| 121 |
+
title="Axis Purpose",
|
| 122 |
+
description=(
|
| 123 |
+
"A concise statement describing the educational intent of this axis — "
|
| 124 |
+
"what learners should achieve cognitively (e.g., understanding, applying, analyzing, creating)."
|
| 125 |
+
),
|
| 126 |
+
)
|
| 127 |
+
|
| 128 |
+
|
| 129 |
+
############################################################################################################
|
| 130 |
+
class UnitWithAxes(BaseModel):
|
| 131 |
+
"""
|
| 132 |
+
Represents a curriculum unit that contains multiple learning axes.
|
| 133 |
+
|
| 134 |
+
Each unit defines a coherent topic focus and consists of five axes,
|
| 135 |
+
each representing a structured subtopic or cognitive level that guides
|
| 136 |
+
the learner progressively from comprehension to advanced application.
|
| 137 |
+
"""
|
| 138 |
+
|
| 139 |
+
unit_number: int = Field(
|
| 140 |
+
...,
|
| 141 |
+
title="The sequential number of this unit within the overall curriculum (e.g., 1, 2, 3).",
|
| 142 |
+
)
|
| 143 |
+
|
| 144 |
+
title: str = Field(
|
| 145 |
+
...,
|
| 146 |
+
title="Unit Title",
|
| 147 |
+
description="The Arabic title or name of the educational unit, clearly representing its theme or purpose.",
|
| 148 |
+
)
|
| 149 |
+
|
| 150 |
+
# focus: str = Field(..., title="Unit Focus", description="Brief note on what this unit emphasizes conceptually")
|
| 151 |
+
focus: str = Field(
|
| 152 |
+
...,
|
| 153 |
+
title="Unit Focus",
|
| 154 |
+
description=(
|
| 155 |
+
"A concise overview highlighting the main concepts, skills, and learning outcomes "
|
| 156 |
+
"covered in this unit. It describes what learners should understand or achieve after completing it."
|
| 157 |
+
"It sets the intellectual direction for the included axes."
|
| 158 |
+
),
|
| 159 |
+
)
|
| 160 |
+
|
| 161 |
+
axes: List[Axis] = Field(
|
| 162 |
+
...,
|
| 163 |
+
title="Unit Axes",
|
| 164 |
+
description=(
|
| 165 |
+
"A list of five(5) coherent Arabic subtopics (axes) that make up the unit. "
|
| 166 |
+
"Each axis represents a progressive cognitive step — from foundational understanding "
|
| 167 |
+
"to creative synthesis — ensuring a balanced learning journey."
|
| 168 |
+
),
|
| 169 |
+
)
|
| 170 |
+
|
| 171 |
+
|
| 172 |
+
############################################################################################################
|
| 173 |
+
class FullCurriculumStructure(BaseModel):
|
| 174 |
+
"""
|
| 175 |
+
Represents the complete process of axis generation for an educational curriculum.
|
| 176 |
+
|
| 177 |
+
This model integrates educational metadata (via DNAMetadata), the conceptual hierarchy
|
| 178 |
+
(main and related concepts), and the pedagogical structure (units and axes).
|
| 179 |
+
It serves as the core structure for AI-driven generation, evaluation, and organization
|
| 180 |
+
of educational axes aligned with learner needs and content goals.
|
| 181 |
+
"""
|
| 182 |
+
|
| 183 |
+
Metadata: List["DNAMetadata"] = Field(
|
| 184 |
+
...,
|
| 185 |
+
title="List of DNA Metadata Objects",
|
| 186 |
+
description=(
|
| 187 |
+
"A list of DNAMetadata items, where each item represents a distinct topic or concept "
|
| 188 |
+
"along with its domain, audience, content type, and material nature.\n"
|
| 189 |
+
"This allows the agent to process multiple curriculum components or educational segments "
|
| 190 |
+
"within a single structured input."
|
| 191 |
+
),
|
| 192 |
+
)
|
| 193 |
+
|
| 194 |
+
main_concept: str = Field(
|
| 195 |
+
...,
|
| 196 |
+
title="Main Concept",
|
| 197 |
+
description=(
|
| 198 |
+
"The central or core idea around which the curriculum is built. "
|
| 199 |
+
"It defines the overarching theme that connects all units and topics together."
|
| 200 |
+
),
|
| 201 |
+
)
|
| 202 |
+
|
| 203 |
+
related_concepts: List[str] = Field(
|
| 204 |
+
...,
|
| 205 |
+
title="Related Concepts",
|
| 206 |
+
description=(
|
| 207 |
+
"A set of secondary or supporting ideas that complement or expand upon the main concept. "
|
| 208 |
+
"These help the agent establish conceptual links and subtopics within the curriculum."
|
| 209 |
+
),
|
| 210 |
+
)
|
| 211 |
+
|
| 212 |
+
units: List[UnitWithAxes] = Field(
|
| 213 |
+
...,
|
| 214 |
+
title="Units with Axes",
|
| 215 |
+
description=(
|
| 216 |
+
"A structured list of educational units. Each unit includes its title, "
|
| 217 |
+
"conceptual focus, and five (5) well-defined axes that progressively develop the learner’s understanding."
|
| 218 |
+
),
|
| 219 |
+
)
|
| 220 |
+
|
| 221 |
+
|
| 222 |
+
##############################--OLD--#####################################################
|
| 223 |
# ========= 2. Schema for Units =========
|
| 224 |
class Unit(BaseModel):
|
| 225 |
module_title: str = Field(
|