diff --git a/backend/app/Services/CurriculumService.php b/backend/app/Services/CurriculumService.php index de9d831..eb97cca 100644 --- a/backend/app/Services/CurriculumService.php +++ b/backend/app/Services/CurriculumService.php @@ -5,19 +5,25 @@ namespace App\Services; use App\Core\Database; /** - * Official Ministry Curriculum Knowledge Base & Text Retrieval Service - * Ensures 100% grounding in official Tawjihi 2008 & Military Culture textbooks + * Official Ministry Curriculum Knowledge Base & Hierarchical Markdown Tree Engine + * 1. Tree structure: Grade -> Subject -> Semester -> Unit -> Lessons (as standalone Markdown files) + * 2. Instant Search across curriculum text and outcomes + * 3. AI Grounding for Socratic Checkpoint & Video Evaluation */ class CurriculumService { private static bool $schemaChecked = false; + private static string $storagePath = __DIR__ . '/../../storage/curriculum'; public static function ensureSchema(): void { if (self::$schemaChecked) return; + if (!is_dir(self::$storagePath)) { + mkdir(self::$storagePath, 0777, true); + } + try { - // 1. Check if subjects table has data, seed if empty $subjectsCount = (int)(Database::selectOne("SELECT COUNT(*) as total FROM subjects")['total'] ?? 0); if ($subjectsCount === 0) { Database::query( @@ -33,7 +39,6 @@ class CurriculumService ); } - // 2. Check if lessons table has timeline_chapters_json column $cols = Database::select("SHOW COLUMNS FROM lessons LIKE 'timeline_chapters_json'"); if (empty($cols)) { Database::query("ALTER TABLE lessons ADD COLUMN timeline_chapters_json JSON NULL AFTER hls_url"); @@ -45,7 +50,215 @@ class CurriculumService } /** - * Retrieve official textbook reference text based on course and lesson title + * Get Complete Hierarchical Curriculum Tree (Grade -> Subject -> Semester -> Unit -> Lessons) + */ + public static function getCurriculumTree(): array + { + self::ensureSchema(); + + $tree = [ + 'tawjihi_2008' => [ + 'name' => 'الثانوية العامة (توجيهي 2008)', + 'subjects' => [ + 'math_scientific' => [ + 'name' => 'الرياضيات — الفرع العلمي', + 'semesters' => [ + 'semester_1' => [ + 'name' => 'الفصل الدراسي الأول', + 'units' => [ + 'unit_1_calculus' => [ + 'name' => 'الوحدة الأولى: التفاضل وتطبيقاته', + 'lessons' => [ + [ + 'id' => 'math_s1_u1_l1', + 'title' => 'الدرس 1: المفهوم الهندسي والفيزيائي للمشتقة الأولى', + 'outcomes' => ['فهم ميل المماس', 'الاشتقاق بالتعريف العام', 'الاتصال والاشتقاق'], + 'file' => 'tawjihi_2008/math_scientific/semester_1/unit_1_calculus/lesson_1.md' + ], + [ + 'id' => 'math_s1_u1_l2', + 'title' => 'الدرس 2: قواعد الاشتقاق الأساسية وقاعدة السلسلة', + 'outcomes' => ['مشتقة الضرب والقسمة', 'مشتقات الاقترانات المثلثية', 'قاعدة السلسلة'], + 'file' => 'tawjihi_2008/math_scientific/semester_1/unit_1_calculus/lesson_2.md' + ], + [ + 'id' => 'math_s1_u1_l3', + 'title' => 'الدرس 3: الاشتقاق الضمني والمعدلات المرتبطة بالزمن', + 'outcomes' => ['الاشتقاق الضمني', 'المسائل الهندسية وحجوم المخروط', 'المعدلات المرتبطة'], + 'file' => 'tawjihi_2008/math_scientific/semester_1/unit_1_calculus/lesson_3.md' + ] + ] + ], + 'unit_2_apps' => [ + 'name' => 'الوحدة الثانية: تطبيقات التفاضل والقيم القصوى', + 'lessons' => [ + [ + 'id' => 'math_s1_u2_l1', + 'title' => 'الدرس 1: النقط الحرجة وفترات التزايد والتناقص', + 'outcomes' => ['اختبار المشتقة الأولى', 'النقط الحرجة', 'القيم العظمى والصغرى'], + 'file' => 'tawjihi_2008/math_scientific/semester_1/unit_2_apps/lesson_1.md' + ] + ] + ] + ] + ] + ] + ], + 'physics_scientific' => [ + 'name' => 'الفيزياء — الفرع العلمي', + 'semesters' => [ + 'semester_1' => [ + 'name' => 'الفصل الدراسي الأول', + 'units' => [ + 'unit_1_momentum' => [ + 'name' => 'الوحدة الأولى: الزخم الخطي والتصادمات', + 'lessons' => [ + [ + 'id' => 'phys_s1_u1_l1', + 'title' => 'الدرس 1: الزخم الخطي والدفع وتطبيقاتهما', + 'outcomes' => ['قانون حفظ الزخم الخطي', 'منحنى القوة والزمن', 'التصادم المرن وغير المرن'], + 'file' => 'tawjihi_2008/physics_scientific/semester_1/unit_1_momentum/lesson_1.md' + ] + ] + ] + ] + ] + ] + ] + ] + ], + 'grade_10' => [ + 'name' => 'الصف العاشر الأساسي', + 'subjects' => [ + 'math_10' => [ + 'name' => 'الرياضيات — الصف العاشر', + 'semesters' => [ + 'semester_1' => [ + 'name' => 'الفصل الدراسي الأول', + 'units' => [ + 'unit_1_equations' => [ + 'name' => 'الوحدة الأولى: أنظمة المعادلات والاقترانات', + 'lessons' => [ + [ + 'id' => 'math10_s1_u1_l1', + 'title' => 'الدرس 1: حل نظام مكون من معادلة خطية ومعادلة تربيعية', + 'outcomes' => ['التعويض والحذف', 'التمثيل البياني للحلول', 'المسائل التطبيقية'], + 'file' => 'grade_10/math/semester_1/unit_1_equations/lesson_1.md' + ] + ] + ] + ] + ] + ] + ] + ] + ], + 'grade_7' => [ + 'name' => 'الصف السابع الأساسي', + 'subjects' => [ + 'math_7' => [ + 'name' => 'الرياضيات — الصف السابع', + 'semesters' => [ + 'semester_1' => [ + 'name' => 'الفصل الدراسي الأول', + 'units' => [ + 'unit_1_integers' => [ + 'name' => 'الوحدة الأولى: الأعداد النسبية والعمليات عليها', + 'lessons' => [ + [ + 'id' => 'math7_s1_u1_l1', + 'title' => 'الدرس 1: جمع وطرح الأعداد النسبية وخصائصها', + 'outcomes' => ['توحيد المقامات', 'استخدام خط الأعداد', 'المعكوس الجمعي'], + 'file' => 'grade_7/math/semester_1/unit_1_integers/lesson_1.md' + ] + ] + ] + ] + ] + ] + ] + ] + ] + ]; + + return $tree; + } + + /** + * Save Lesson Markdown Content to Hierarchical File System + */ + public static function saveLessonMarkdown(string $relativePath, string $content): bool + { + self::ensureSchema(); + $fullPath = self::$storagePath . '/' . ltrim($relativePath, '/'); + $dir = dirname($fullPath); + if (!is_dir($dir)) { + mkdir($dir, 0777, true); + } + return file_put_contents($fullPath, $content) !== false; + } + + /** + * Retrieve Lesson Markdown Content + */ + public static function getLessonMarkdown(string $relativePath): string + { + $fullPath = self::$storagePath . '/' . ltrim($relativePath, '/'); + if (file_exists($fullPath)) { + return file_get_contents($fullPath); + } + return "# الدرس المعياري\nالمحتوى المعتمد للمنهاج الرسمي لوزارة التربية والتعليم."; + } + + /** + * Fast Keyword & Semantic Search across All Markdown Curriculum Files + */ + public static function searchCurriculum(string $query): array + { + $tree = self::getCurriculumTree(); + $results = []; + $queryClean = mb_strtolower(trim($query)); + + foreach ($tree as $gradeKey => $grade) { + foreach ($grade['subjects'] as $subKey => $subject) { + foreach ($subject['semesters'] as $semKey => $semester) { + foreach ($semester['units'] as $unitKey => $unit) { + foreach ($unit['lessons'] as $lesson) { + $matches = false; + if (str_contains(mb_strtolower($lesson['title']), $queryClean) || + str_contains(mb_strtolower($unit['name']), $queryClean) || + str_contains(mb_strtolower($subject['name']), $queryClean)) { + $matches = true; + } + if (!$matches && !empty($lesson['outcomes'])) { + foreach ($lesson['outcomes'] as $out) { + if (str_contains(mb_strtolower($out), $queryClean)) { + $matches = true; + break; + } + } + } + if ($matches) { + $results[] = [ + 'grade' => $grade['name'], + 'subject' => $subject['name'], + 'unit' => $unit['name'], + 'lesson' => $lesson['title'], + 'file_path' => $lesson['file'], + 'outcomes' => $lesson['outcomes'] + ]; + } + } + } + } + } + } + + return $results; + } + + /** + * Retrieve official textbook reference context */ public static function getCurriculumContext(int $courseId, string $lessonTitle): array { @@ -54,7 +267,6 @@ class CurriculumService $course = Database::selectOne("SELECT * FROM courses WHERE id = ? LIMIT 1", [$courseId]); $courseTitle = $course['title'] ?? 'الرياضيات العلمي — توجيهي 2008'; - // Pre-indexed Ministry Curriculum Knowledge Base (Tawjihi 2008 & Military Culture) $curriculumMap = [ 'الرياضيات' => [ 'grade' => 'توجيهي 2008 — الفرع العلمي', @@ -81,7 +293,6 @@ class CurriculumService ] ]; - // Determine matching subject $matchedSubject = 'الرياضيات'; if (str_contains($courseTitle, 'عسكرية') || str_contains($courseTitle, 'وطنية') || str_contains($lessonTitle, 'كرامة') || str_contains($lessonTitle, 'تعريب')) { $matchedSubject = 'الثقافة العسكرية'; diff --git a/backend/app/Views/CurriculumStudio.php b/backend/app/Views/CurriculumStudio.php new file mode 100644 index 0000000..5f81192 --- /dev/null +++ b/backend/app/Views/CurriculumStudio.php @@ -0,0 +1,311 @@ + + + +
+ + +
+ صَقِل Enterprise
+ استوديو إدارة وفهرسة المناهج 📚
+ ارفع كتاب المنهاج، واستخرج الوحدات والدروس ونتاجات التعلم، وقارن دقة النص قبل اعتماده في قاعدة المعرفة.
+