diff --git a/apps/student_app/pubspec.lock b/apps/student_app/pubspec.lock index bf689f5..173cd02 100644 --- a/apps/student_app/pubspec.lock +++ b/apps/student_app/pubspec.lock @@ -332,10 +332,10 @@ packages: dependency: transitive description: name: matcher - sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861 + sha256: "12956d0ad8390bbcc63ca2e1469c0619946ccb52809807067a7020d57e647aa6" url: "https://pub.dev" source: hosted - version: "0.12.19" + version: "0.12.18" material_color_utilities: dependency: transitive description: @@ -348,10 +348,10 @@ packages: dependency: transitive description: name: meta - sha256: "1741988757a65eb6b36abe716829688cf01910bbf91c34354ff7ec1c3de2b349" + sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.17.0" nested: dependency: transitive description: @@ -577,10 +577,10 @@ packages: dependency: transitive description: name: test_api - sha256: "949a932224383300f01be9221c39180316445ecb8e7547f70a41a35bf421fb9e" + sha256: "93167629bfc610f71560ab9312acdda4959de4df6fac7492c89ff0d3886f6636" url: "https://pub.dev" source: hosted - version: "0.7.11" + version: "0.7.9" typed_data: dependency: transitive description: diff --git a/backend/app/Controllers/VideoController.php b/backend/app/Controllers/VideoController.php index eff3763..bebca8b 100644 --- a/backend/app/Controllers/VideoController.php +++ b/backend/app/Controllers/VideoController.php @@ -423,6 +423,29 @@ class VideoController $lessonId = (int)$lesson['id']; + // Self-Healing Curriculum Guard: Purge any obsolete/mismatched calculus questions + // for non-calculus lessons (e.g. Grade 10 Systems of Equations) + $isCalculusLesson = (str_contains($lesson['title'], 'اشتقاق') || str_contains($lesson['title'], 'تفاضل')); + if (!$isCalculusLesson) { + try { + $mismatched = Database::selectOne( + "SELECT q.id FROM questions q + JOIN exams e ON q.exam_id = e.id + WHERE e.lesson_id = ? AND (q.question_text LIKE '%مشتق%' OR q.question_text LIKE '%f\'(x)%') + LIMIT 1", + [$lessonId] + ); + if ($mismatched) { + $badExams = Database::select("SELECT id FROM exams WHERE lesson_id = ? AND scope = 'in_video_checkpoint'", [$lessonId]); + foreach ($badExams as $be) { + Database::query("DELETE FROM exams WHERE id = ?", [$be['id']]); + } + } + } catch (\Throwable $e) { + error_log("Curriculum self-healing notice: " . $e->getMessage()); + } + } + // If lesson has no checkpoints or missing questions, generate them autonomously $existingCount = Database::selectOne("SELECT COUNT(*) as cnt FROM exams WHERE lesson_id = ? AND scope = 'in_video_checkpoint'", [$lessonId]); $existingQuestions = Database::selectOne("SELECT COUNT(*) as cnt FROM questions q JOIN exams e ON q.exam_id = e.id WHERE e.lesson_id = ?", [$lessonId]); diff --git a/backend/app/Services/AiVideoAnalyzerService.php b/backend/app/Services/AiVideoAnalyzerService.php index c85b249..81959e5 100644 --- a/backend/app/Services/AiVideoAnalyzerService.php +++ b/backend/app/Services/AiVideoAnalyzerService.php @@ -374,8 +374,47 @@ class AiVideoAnalyzerService ]; } - // Safe generic fallback: never inject unrelated advanced topics when - // Gemini is unavailable. + // Grade 10 Mathematics: Systems of Equations (أنظمة المعادلات) + $isEquations = (str_contains($title, 'معادلات') || str_contains($title, 'أنظمة') || str_contains($curriculum['unit'] ?? '', 'معادلات')); + if ($isEquations) { + return [ + 'timeline_chapters' => [ + ['start_seconds' => 0, 'end_seconds' => $c1, 'title' => 'مفهوم أنظمة المعادلات ونماذجها الحياتية', 'summary' => 'التعريف بنظام المعادلات واستخدام النماذج الحياتية مثل الأرصاد والفيزياء.'], + ['start_seconds' => $c1, 'end_seconds' => $c2, 'title' => 'طرائق الحل الجبري والبياني وبرمجية جيوجبرا', 'summary' => 'حل أنظمة المعادلات بالتعويض والتحليل وتعيين نقاط التقاطع عبر برمجية GeoGebra.'], + ['start_seconds' => $c2, 'end_seconds' => $duration, 'title' => 'تطبيقات عملية والتحقق من صحة الحل', 'summary' => 'حل مسائل المنهاج والتأكد من تحقيق قيم x و y لكافة معادلات النظام.'] + ], + 'socratic_checkpoints' => [ + [ + 'timestamp_seconds' => $cp1, + 'question_text' => 'ماذا تمثّل نقطة تقاطع منحنيين في المستوى الإحداثي لنظام معادلات؟', + 'options' => [ + 'حل مشترك يُحقق كِلا المعادلتين معاً في آن واحد', + 'المسافة الرأسية بين المنحنيين', + 'معادلة خط التقارب الأفقي فقط', + 'المقطع الصادي لأحد المنحنيين دون الآخر' + ], + 'correct_index' => 0, + 'rewind_seconds' => $rewind, + 'explanation' => 'نقطة تقاطع أي منحنيين هندسياً تمثل الزوج المرتب (x, y) الذي يحقق كلتا المعادلتين في آن واحد، وهو حل النظام.' + ], + [ + 'timestamp_seconds' => $cp2, + 'question_text' => 'عند حل نظام مكوّن من معادلة خطية ومعادلة تربيعية، ما هو أقصى عدد ممكن من الحلول الحقيقية؟', + 'options' => [ + 'حلّان حقيقيان (نقطتا تقاطع)', + 'ثلاثة حلول حقيقية دائماً', + 'أربعة حلول حقيقية', + 'لا يمكن أن يتقاطعا أبداً' + ], + 'correct_index' => 0, + 'rewind_seconds' => $rewind, + 'explanation' => 'المستقيم يقطع القطع المكافئ في نقطتين كحد أقصى (حلان)، أو يمسه في نقطة واحدة (حل واحد)، أو لا يقطعه (لا يوجد حل حقيقي).' + ] + ] + ]; + } + + // Safe generic fallback: never inject unrelated advanced topics when Gemini is unavailable. $topics = array_values(array_filter(array_map('strval', $curriculum['core_topics'] ?? []))); $topic = $topics[0] ?? $title; $topicTwo = $topics[1] ?? $topic; diff --git a/backend/scripts/purge_mismatched_checkpoints.php b/backend/scripts/purge_mismatched_checkpoints.php new file mode 100644 index 0000000..740be21 --- /dev/null +++ b/backend/scripts/purge_mismatched_checkpoints.php @@ -0,0 +1,50 @@ +getMessage() . "\n"; +}