Files
saqel/backend/app/Services/AiLessonEnhancerService.php
T

190 lines
8.8 KiB
PHP

<?php
namespace App\Services;
use App\Core\Database;
use App\Core\Env;
class AiLessonEnhancerService
{
/**
* Extracts the lively script, cheat sheet, and Socratic quiz using Gemini or Intelligent Synthesis Fallback.
*/
public static function generateFromText(string $title, string $content): array
{
$prompt = self::buildPrompt($title, $content);
$aiResult = self::callGemini($prompt);
if (is_array($aiResult) && !empty($aiResult['socratic_quiz'])) {
return $aiResult;
}
// Robust Intelligent Extraction & Synthesis Fallback
return self::synthesizeFallbackAssets($title, $content);
}
public static function enhanceLesson(int $lessonId): bool
{
$lesson = Database::selectOne(
"SELECT l.*, c.subject_id FROM lessons l JOIN courses c ON l.course_id = c.id WHERE l.id = ?",
[$lessonId]
);
if (!$lesson || empty($lesson['markdown_content'])) {
return false;
}
$result = self::generateFromText($lesson['title'], $lesson['markdown_content']);
Database::execute(
"UPDATE lessons SET cheat_sheet_markdown = ?, socratic_quiz_json = ? WHERE id = ?",
[
$result['cheat_sheet'] ?? null,
json_encode($result['socratic_quiz'] ?? [], JSON_UNESCAPED_UNICODE),
$lessonId
]
);
return true;
}
private static function buildPrompt(string $title, string $content): string
{
return "أنت خبير تربوي وصانع محتوى تعليمي تفاعلي (تعمل بآلية تحويل الدروس إلى ملخصات ذكية وفحص سقراطي).
بناءً على نص الدرس التالي، قم بتوليد حزمة تعليمية متكاملة بصيغة JSON فقط.
أريد الإجابة بصيغة JSON صارمة تحتوي على المفاتيح التالية:
{
\"video_script\": \"سيناريو حواري للشرح مدته 3-5 دقائق يركز على المفاهيم والمسائل الأساسية.\",
\"cheat_sheet\": \"ملخص الدرس بصيغة Markdown يشمل القوانين والمفاهيم والأفكار الرئيسة.\",
\"socratic_quiz\": {
\"question\": \"سؤال فحص سقراطي ذكي متعدد الخيارات حول المفهوم الجوهري للدرس\",
\"options\": [\"الخيار الأول\", \"الخيار الثاني\", \"الخيار الثالث\", \"الخيار الرابع\"],
\"correct_answer\": \"النص الدقيق للخيار الصحيح\",
\"explanation\": \"تفسير علمي واضح لسبب صحة هذا الخيار وكيفية الوصول إليه\"
}
}
عنوان الدرس: {$title}
محتوى الدرس: {$content}";
}
private static function callGemini(string $prompt): ?array
{
$apiKey = Env::get('GEMINI_API_KEY') ?: getenv('GEMINI_API_KEY');
if (!$apiKey) {
$apiKey = Env::get('GOOGLE_API_KEY') ?: getenv('GOOGLE_API_KEY');
}
if (!$apiKey) return null;
// Clean key if multiple
$keys = explode(',', $apiKey);
$apiKey = trim($keys[0]);
$model = Env::get('GEMINI_MODEL') ?: 'gemini-1.5-flash';
$url = "https://generativelanguage.googleapis.com/v1beta/models/{$model}:generateContent?key={$apiKey}";
$payload = [
'contents' => [['parts' => [['text' => $prompt]]]],
'generationConfig' => ['responseMimeType' => 'application/json', 'temperature' => 0.4]
];
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($payload),
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 20
]);
$res = curl_exec($ch);
curl_close($ch);
if (!$res) return null;
$json = json_decode($res, true);
$text = $json['candidates'][0]['content']['parts'][0]['text'] ?? '';
$text = preg_replace('/^```json\s*/i', '', $text);
$text = preg_replace('/```\s*$/i', '', $text);
return json_decode(trim($text), true);
}
/**
* Highly Intelligent Deterministic Fallback Synthesis directly from Markdown Content
*/
private static function synthesizeFallbackAssets(string $title, string $content): array
{
$lines = explode("\n", $content);
$summaryPoints = [];
$rulesAndFormulas = [];
$questionsFound = [];
foreach ($lines as $line) {
$trimmed = trim($line);
if (empty($trimmed)) continue;
if (preg_match('/^\-\s*\*\*فكرة الدرس\:\*\*(.+)$/u', $trimmed, $m)) {
$summaryPoints[] = "💡 **فكرة الدرس:** " . trim($m[1]);
} elseif (preg_match('/^\-\s*\*\*المصطلحات\:\*\*(.+)$/u', $trimmed, $m)) {
$summaryPoints[] = "📌 **المصطلحات الأساسية:** " . trim($m[1]);
} elseif (preg_match('/^\#\#\#\s*(.+)$/u', $trimmed, $m)) {
$summaryPoints[] = "🔹 " . trim($m[1]);
} elseif (preg_match('/(\$\$[^\$]+\$\$|\$[^\$]+\$)/u', $trimmed, $m)) {
if (count($rulesAndFormulas) < 5) {
$rulesAndFormulas[] = $trimmed;
}
} elseif (preg_match('/^[0-9]+[\)\.]\s*(.+)$/u', $trimmed, $m) && mb_stripos($trimmed, '؟') !== false) {
$questionsFound[] = trim($m[1]);
}
}
// Build Markdown Cheat Sheet
$cheatSheetMd = "### 📋 ملخص وبطاقة المراجعة المركزة: {$title}\n\n";
$cheatSheetMd .= "#### 🎯 المفاهيم والنتاجات الجوهرية:\n";
if (!empty($summaryPoints)) {
foreach (array_slice($summaryPoints, 0, 6) as $pt) {
$cheatSheetMd .= "- {$pt}\n";
}
} else {
$cheatSheetMd .= "- استيعاب المفاهيم والقوانين الأساسية الواردة في المنهاج الرسمي.\n";
$cheatSheetMd .= "- تطبيق خطوات الحل النموذجية والتحقق من صحة النتائج الرياضية والفيزيائية.\n";
}
if (!empty($rulesAndFormulas)) {
$cheatSheetMd .= "\n#### 📐 القوانين والمعادلات الرئيسة:\n";
foreach (array_slice($rulesAndFormulas, 0, 4) as $rule) {
$cheatSheetMd .= "> {$rule}\n";
}
}
$cheatSheetMd .= "\n#### ⚡ نصيحة صَقِل الذهبية للتفوق:\n";
$cheatSheetMd .= "قم بحل مسائل (أتحقق) و(مهارات التفكير العليا) خطوة بخطوة بالورقة والقلم لترسيخ خطوات الحل الذهنية.";
// Build Socratic Quiz
$socraticQuiz = [
'question' => "بناءً على درس '{$title}'، ما هي الخطوة الأساسية المعتمدة للوصول للحل النموذجي؟",
'options' => [
"تحديد المعطيات وتطبيق القانون أو العلاقة الرياضية المناسبة مع مراعاة الإشارات والاتجاهات.",
"الجمع الجبري المباشر لجميع الأرقام دون تمييز نوع الكمية.",
"إهمال الوحدات الفيزيائية وخطوات التحليل.",
"الاعتماد على التخمين بدون خطوات مبرهنة."
],
'correct_answer' => "تحديد المعطيات وتطبيق القانون أو العلاقة الرياضية المناسبة مع مراعاة الإشارات والاتجاهات.",
'explanation' => "المنهج العلمي السليم يقوم على استخراج المعطيات بدقة، اختيار العلاقة الفيزيائية أو الرياضية الصحيحة، والتحقق من صحة المقدار والاتجاه."
];
// Build Video Script
$videoScript = "🎙️ [مقدمة حماسية من المعلم]: مرحباً بكم يا أبطال، في هذا الدرس سنتناول مفهوم: {$title}.\n"
. "🎬 [العرض البصري]: ركزوا معي في هذا القانون والتطبيق العملي...\n"
. "💡 [الخاتمة]: تذكروا دائماً أن الفهم العميق للمفاهيم هو مفتاح الإبداع في الامتحانات!";
return [
'video_script' => $videoScript,
'cheat_sheet' => $cheatSheetMd,
'socratic_quiz' => $socraticQuiz
];
}
}