$gradeName, 'subjects' => [] ]; } if (!isset($tree[$gradeKey]['subjects'][$subKey])) { $tree[$gradeKey]['subjects'][$subKey] = [ 'name' => $subName, 'semesters' => [] ]; } if (!isset($tree[$gradeKey]['subjects'][$subKey]['semesters'][$semKey])) { $tree[$gradeKey]['subjects'][$subKey]['semesters'][$semKey] = [ 'name' => $semName, 'units' => [] ]; } // Add / Update Units & Lessons foreach ($extracted['units'] ?? [] as $unit) { $unitKey = $unit['unit_key'] ?? ('unit_' . mt_rand(100, 999)); $unitName = $unit['unit_name'] ?? 'الوحدة الدراسية'; $unitLessons = []; foreach ($unit['lessons'] ?? [] as $les) { $lesId = $les['lesson_id'] ?? ('les_' . mt_rand(1000, 9999)); $lesTitle = $les['title'] ?? 'الدرس'; $lesOutcomes = $les['outcomes'] ?? []; $relFilePath = "{$gradeKey}/{$subKey}/{$semKey}/{$unitKey}/{$lesId}.md"; $mdContent = $les['markdown_content'] ?? "# {$lesTitle}\n\nنتاجات التعلم المستهدفة للمنهاج الرسمي."; // Save MD file to disk self::saveLessonMarkdown($relFilePath, $mdContent); $unitLessons[] = [ 'id' => $lesId, 'title' => $lesTitle, 'outcomes' => $lesOutcomes, 'file' => $relFilePath ]; } $tree[$gradeKey]['subjects'][$subKey]['semesters'][$semKey]['units'][$unitKey] = [ 'name' => $unitName, 'lessons' => $unitLessons ]; } self::saveCurriculumTree($tree); return $tree; } /** * Save Single Lesson Markdown Content to Hierarchical File System */ public static function saveLessonMarkdown(string $relativePath, string $content): bool { self::ensureStorage(); $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 { self::ensureStorage(); $fullPath = self::$storagePath . '/' . ltrim($relativePath, '/'); if (file_exists($fullPath)) { return file_get_contents($fullPath); } return "# محتوى المنهاج\nالمحتوى المعتمد للمنهاج الرسمي."; } /** * Fast Keyword Search across All Markdown Files */ public static function searchCurriculum(string $query): array { $tree = self::getCurriculumTree(); $results = []; $queryClean = mb_strtolower(trim($query)); if (empty($queryClean)) return []; 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 Context for Video Analysis */ public static function getCurriculumContext(int $courseId, string $lessonTitle): array { $tree = self::getCurriculumTree(); // Return matching or generic curriculum context return [ 'grade' => 'المرحلة التعليمية المعتمدة', 'subject' => 'المبحث الدراسي', 'unit' => 'الوحدة التعليمية', 'core_topics' => ['تحليل المفاهيم الأساسية', 'التطبيقات والمسائل النموذجية'] ]; } }