Update Saqel Platform: 2026-09-09 00:12:31

This commit is contained in:
Hamza-Ayed
2026-09-09 00:12:31 +03:00
parent 3d9fb16767
commit 956bb4a674
4 changed files with 28 additions and 8 deletions
@@ -42,6 +42,12 @@ class TeacherLessonAuditModel {
final readiness = (json['pedagogical_readiness_score'] as num?)?.toInt(); final readiness = (json['pedagogical_readiness_score'] as num?)?.toInt();
final visual = (json['visual_clarity_score'] as num?)?.toInt(); final visual = (json['visual_clarity_score'] as num?)?.toInt();
final decisionValue = json['decision']?.toString() ?? 'pending'; final decisionValue = json['decision']?.toString() ?? 'pending';
final ai = json['ai_analysis'] is Map ? Map<String, dynamic>.from(json['ai_analysis'] as Map) : null;
final qa = ai != null && ai['quality_assessment'] is Map ? Map<String, dynamic>.from(ai['quality_assessment'] as Map) : null;
final cpCount = (ai?['checkpoints_count'] as num?)?.toInt() ?? (json['socratic_stops_count'] as num?)?.toInt() ?? 0;
final alignScore = (qa?['alignment_score'] as num?)?.toInt();
return TeacherLessonAuditModel( return TeacherLessonAuditModel(
lessonTitle: json['lesson_title'] ?? '', lessonTitle: json['lesson_title'] ?? '',
subject: json['subject'] ?? '', subject: json['subject'] ?? '',
@@ -50,15 +56,16 @@ class TeacherLessonAuditModel {
durationGatePassed: json['duration_gate_passed'] ?? durationGatePassed: json['duration_gate_passed'] ??
(durationSeconds > 0 && durationSeconds <= 1500), (durationSeconds > 0 && durationSeconds <= 1500),
durationWarning: json['duration_warning'], durationWarning: json['duration_warning'],
qualityScore: (json['quality_score'] as num?)?.toInt() ?? readiness ?? 0, qualityScore: (qa?['clarity_score'] as num?)?.toInt() ?? (json['quality_score'] as num?)?.toInt() ?? readiness ?? 0,
approvalStatus: json['approval_status'] ?? decisionValue, approvalStatus: qa?['status']?.toString() ?? json['approval_status'] ?? decisionValue,
curriculumAlignment: curriculumAlignment: alignScore != null
json['curriculum_alignment'] ?? 'بانتظار تحليل الملف الفعلي', ? 'تطابق معتمد بنسبة $alignScore% مع المنهاج الرسمي'
: (json['curriculum_alignment'] ?? 'بانتظار تحليل الملف الفعلي'),
audioClarity: json['audio_clarity'] ?? audioClarity: json['audio_clarity'] ??
(visual == null (visual == null
? 'تم التحقق من وجود مسار صوت فعلي' ? 'تم التحقق من وجود مسار صوت فعلي'
: 'وضوح الصورة $visual%، وتم التحقق من وجود الصوت'), : 'وضوح الصورة $visual%، وتم التحقق من وجود الصوت'),
socraticStopsCount: (json['socratic_stops_count'] as num?)?.toInt() ?? 0, socraticStopsCount: cpCount,
decision: json['report'] ?? json['reason'] ?? decisionValue, decision: json['report'] ?? json['reason'] ?? decisionValue,
); );
} }
@@ -321,8 +321,12 @@ class TeacherStudioCubit extends Cubit<TeacherStudioState> {
final report = data['preflight_report'] is Map final report = data['preflight_report'] is Map
? Map<String, dynamic>.from(data['preflight_report'] as Map) ? Map<String, dynamic>.from(data['preflight_report'] as Map)
: <String, dynamic>{}; : <String, dynamic>{};
final aiAnalysis = data['ai_analysis'] is Map
? Map<String, dynamic>.from(data['ai_analysis'] as Map)
: <String, dynamic>{};
final result = TeacherLessonAuditModel.fromJson({ final result = TeacherLessonAuditModel.fromJson({
...report, ...report,
'ai_analysis': aiAnalysis,
'lesson_title': state.lessonTitle, 'lesson_title': state.lessonTitle,
'subject': selectedSubjectName 'subject': selectedSubjectName
}); });
@@ -551,7 +551,9 @@ class _TeacherStudioUploadTabState extends State<TeacherStudioUploadTab> {
const SizedBox(width: 8), const SizedBox(width: 8),
Text( Text(
isApproved isApproved
? 'جاهزة لرفع الملف والتحليل' ? (state.isUploaded
? 'تم اعتماد ونشر الحصة بنجاح 🎖️'
: 'جاهزة لرفع الملف والتحليل')
: 'بيانات الحصة بحاجة للمراجعة', : 'بيانات الحصة بحاجة للمراجعة',
style: TextStyle( style: TextStyle(
fontSize: 15, fontSize: 15,
+9 -2
View File
@@ -267,8 +267,15 @@ class VideoService
@shell_exec($thumbCmd); @shell_exec($thumbCmd);
// 2. Generate HLS Segments & Playlist (6-second chunks for fast start) // 2. Generate HLS Segments & Playlist (6-second chunks for fast start)
$hlsCmd = "{$ffmpeg} -i " . escapeshellarg($sourceMp4Path) . " -codec:v libx264 -crf 23 -preset veryfast -codec:a aac -b:a 128k -hls_time 6 -hls_list_size 0 -hls_segment_filename " . escapeshellarg($segmentPattern) . " " . escapeshellarg($playlistPath) . " -y 2>/dev/null"; // Try ultra-fast stream copy first (takes 2-4s instead of 4 minutes of CPU encoding)
@shell_exec($hlsCmd); $hlsFastCmd = "{$ffmpeg} -i " . escapeshellarg($sourceMp4Path) . " -c copy -hls_time 6 -hls_list_size 0 -hls_segment_filename " . escapeshellarg($segmentPattern) . " " . escapeshellarg($playlistPath) . " -y 2>/dev/null";
@shell_exec($hlsFastCmd);
// Fallback to transcoding only if stream copy failed to produce playlist
if (!file_exists($playlistPath)) {
$hlsCmd = "{$ffmpeg} -i " . escapeshellarg($sourceMp4Path) . " -codec:v libx264 -crf 23 -preset veryfast -codec:a aac -b:a 128k -hls_time 6 -hls_list_size 0 -hls_segment_filename " . escapeshellarg($segmentPattern) . " " . escapeshellarg($playlistPath) . " -y 2>/dev/null";
@shell_exec($hlsCmd);
}
$hlsUrl = '/api/videos/hls/' . $videoUuid . '/index.m3u8'; $hlsUrl = '/api/videos/hls/' . $videoUuid . '/index.m3u8';
$thumbUrl = '/api/videos/hls/' . $videoUuid . '/thumbnail.jpg'; $thumbUrl = '/api/videos/hls/' . $videoUuid . '/thumbnail.jpg';