Update Saqel Platform: 2026-09-08 18:19:28

This commit is contained in:
Hamza-Ayed
2026-09-08 18:19:28 +03:00
parent 75451ebc3f
commit e5cbd89323
22 changed files with 1537 additions and 595 deletions
+13 -5
View File
@@ -42,6 +42,7 @@ class VideoController
$courseId = (int)($request->getBody()['course_id'] ?? $_POST['course_id'] ?? 0);
$title = trim((string)($request->getBody()['title'] ?? $_POST['title'] ?? ''));
$seqOrder = (int)($request->getBody()['sequence_order'] ?? $_POST['sequence_order'] ?? 1);
$curriculumKey = trim((string)($request->getBody()['curriculum_key'] ?? $_POST['curriculum_key'] ?? ''));
if (empty($title)) {
$response->status(400)->json([
@@ -64,13 +65,19 @@ class VideoController
return;
}
} else {
$existingCourse = Database::selectOne("SELECT id, teacher_id FROM courses WHERE teacher_id = ? LIMIT 1", [$request->user_id]);
$subjectName = trim((string)($request->getBody()['subject'] ?? $_POST['subject'] ?? ''));
$gradeLevel = trim((string)($request->getBody()['grade_level'] ?? $_POST['grade_level'] ?? ''));
$existingCourse = Database::selectOne(
"SELECT c.id, c.teacher_id FROM courses c
JOIN subjects s ON s.id = c.subject_id
WHERE c.teacher_id = ? AND c.grade_level = ? AND (s.name_ar = ? OR s.name_en = ?)
LIMIT 1",
[$request->user_id, $gradeLevel, $subjectName, $subjectName]
);
if ($existingCourse) {
$courseId = (int)$existingCourse['id'];
$course = $existingCourse;
} else {
$subjectName = trim((string)($request->getBody()['subject'] ?? $_POST['subject'] ?? ''));
$gradeLevel = trim((string)($request->getBody()['grade_level'] ?? $_POST['grade_level'] ?? ''));
$subject = Database::selectOne(
"SELECT id FROM subjects WHERE name_ar = ? OR name_en = ? ORDER BY id LIMIT 1",
[$subjectName, $subjectName]
@@ -121,11 +128,12 @@ class VideoController
// Insert lesson record with HLS references
$lessonId = Database::insert(
"INSERT INTO lessons (course_id, title, sequence_order, storage_type, video_uuid, bunny_video_id, local_path, hls_url, thumbnail_url, duration_seconds, is_free_preview, encoding_status)
VALUES (?, ?, ?, 'api_upload', ?, '', ?, ?, ?, ?, 0, 'ready')",
"INSERT INTO lessons (course_id, title, curriculum_key, sequence_order, storage_type, video_uuid, bunny_video_id, local_path, hls_url, thumbnail_url, duration_seconds, is_free_preview, encoding_status)
VALUES (?, ?, ?, ?, 'api_upload', ?, '', ?, ?, ?, ?, 0, 'ready')",
[
$courseId,
$title,
$curriculumKey !== '' ? $curriculumKey : null,
$seqOrder,
$uploadResult['video_uuid'],
$uploadResult['local_path'],
@@ -78,7 +78,7 @@ class AiVideoAnalyzerService
$report = json_decode($text, true);
if ($code !== 200 || !is_array($report) || !in_array($report['decision'] ?? '', ['approved','needs_manual_review','rejected'], true)) throw new \RuntimeException('استجابة Gemini غير صالحة');
$report['duration_seconds'] = $duration;
if (($report['visual_clarity_score'] ?? 0) < 70 || ($report['pedagogical_readiness_score'] ?? 0) < 70) $report['decision'] = 'needs_manual_review';
if (($report['visual_clarity_score'] ?? 0) < 85 || ($report['pedagogical_readiness_score'] ?? 0) < 85) $report['decision'] = 'needs_manual_review';
return $report;
} catch (\Throwable $e) {
return ['decision' => 'needs_manual_review', 'reason' => 'تعذر إكمال تحليل Gemini؛ لم يتم رفع الفيديو'];
+22 -26
View File
@@ -52,19 +52,19 @@ class TeacherRatingService
Database::query("
CREATE TABLE teacher_performance_metrics (
teacher_id BIGINT UNSIGNED PRIMARY KEY,
avg_response_minutes INT DEFAULT 4,
response_rate_percentage DECIMAL(5, 2) DEFAULT 98.50,
avg_response_minutes INT DEFAULT 0,
response_rate_percentage DECIMAL(5, 2) DEFAULT 0,
active_queue_count INT UNSIGNED DEFAULT 0,
total_students_enrolled INT DEFAULT 0,
total_reviews_count INT DEFAULT 0,
raw_avg_rating DECIMAL(3, 2) DEFAULT 5.00,
weighted_student_rating DECIMAL(3, 2) DEFAULT 5.00,
ai_engagement_score DECIMAL(5, 2) DEFAULT 96.00,
sla_speed_score DECIMAL(5, 2) DEFAULT 98.00,
mastery_impact_score DECIMAL(5, 2) DEFAULT 94.00,
composite_merit_score DECIMAL(5, 2) DEFAULT 96.50,
star_equivalent DECIMAL(3, 2) DEFAULT 4.90,
reputation_tier VARCHAR(100) DEFAULT 'معلم نخبوي معتمد 💎',
raw_avg_rating DECIMAL(3, 2) DEFAULT 0,
weighted_student_rating DECIMAL(3, 2) DEFAULT 0,
ai_engagement_score DECIMAL(5, 2) DEFAULT 0,
sla_speed_score DECIMAL(5, 2) DEFAULT 0,
mastery_impact_score DECIMAL(5, 2) DEFAULT 0,
composite_merit_score DECIMAL(5, 2) DEFAULT 0,
star_equivalent DECIMAL(3, 2) DEFAULT 0,
reputation_tier VARCHAR(100) DEFAULT 'بانتظار بيانات الأداء',
last_calculated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
CONSTRAINT fk_tpm_teacher FOREIGN KEY (teacher_id) REFERENCES teachers(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
@@ -308,10 +308,6 @@ class TeacherRatingService
]
);
if ($studentsCount <= 0) {
$studentsCount = 83;
}
return [
'teacher_id' => $teacherId,
'composite_merit_score' => $compositeScore,
@@ -327,12 +323,12 @@ class TeacherRatingService
'sla_speed_score' => $slaComponent,
'mastery_impact_score' => $masteryComponent,
'ai_engagement_score' => $aiEngagementScore,
'success_rate_percentage' => 98.2,
'curriculum_alignment_pct' => 96.0,
'socratic_interaction_pct' => 89.0,
'audio_clarity_pct' => 94.0,
'cognitive_focus_pct' => 92.0,
'ai_recommendation' => 'توجيه الذكاء الاصطناعي الأسبوعي: نسبة الالتزام الوزاري ممتازة (96%). يُوصى بإضافة وقفة سقراطية استنتاجية في الدقيقة 14 من الدرس القادم لتعزيز تفاعل الطلبة.'
'success_rate_percentage' => 0.0,
'curriculum_alignment_pct' => 0.0,
'socratic_interaction_pct' => 0.0,
'audio_clarity_pct' => 0.0,
'cognitive_focus_pct' => 0.0,
'ai_recommendation' => 'ستظهر التوصية بعد توفر حصص محللة وتفاعل فعلي من الطلبة.'
];
}
@@ -419,7 +415,7 @@ class TeacherRatingService
}
} catch (\Throwable $e) {}
return 94.50;
return 0.0;
}
/**
@@ -431,11 +427,11 @@ class TeacherRatingService
$teachers = Database::select(
"SELECT t.id, t.full_name, t.specialization, t.bio,
COALESCE(m.avg_response_minutes, 3) as avg_response_minutes,
COALESCE(m.response_rate_percentage, 99.0) as response_rate_percentage,
COALESCE(m.composite_merit_score, 96.50) as composite_merit_score,
COALESCE(m.star_equivalent, 4.90) as star_equivalent,
COALESCE(m.reputation_tier, 'معلم نخبوي معتمد 💎') as reputation_tier,
COALESCE(m.avg_response_minutes, 0) as avg_response_minutes,
COALESCE(m.response_rate_percentage, 0) as response_rate_percentage,
COALESCE(m.composite_merit_score, 0) as composite_merit_score,
COALESCE(m.star_equivalent, 0) as star_equivalent,
COALESCE(m.reputation_tier, 'بانتظار بيانات الأداء') as reputation_tier,
(SELECT COUNT(*) FROM lessons WHERE course_id IN (SELECT id FROM courses WHERE teacher_id = t.id)) as lessons_count
FROM teachers t
LEFT JOIN teacher_performance_metrics m ON t.id = m.teacher_id