feat: Add AiLessonEnhancerService to automatically generate NotebookLM-style cheat sheets and quizzes
This commit is contained in:
@@ -0,0 +1,102 @@
|
|||||||
|
<?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.
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
$prompt = self::buildPrompt($lesson['title'], $lesson['markdown_content']);
|
||||||
|
$result = self::callGemini($prompt);
|
||||||
|
|
||||||
|
if (!$result) return false;
|
||||||
|
|
||||||
|
// Save to Database
|
||||||
|
Database::execute(
|
||||||
|
"UPDATE lessons SET cheat_sheet_markdown = ?, socratic_quiz_json = ? WHERE id = ?",
|
||||||
|
[
|
||||||
|
$result['cheat_sheet'] ?? null,
|
||||||
|
json_encode($result['socratic_quiz'] ?? []),
|
||||||
|
$lessonId
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Return true if successful
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function buildPrompt(string $title, string $content): string
|
||||||
|
{
|
||||||
|
return "أنت خبير تعليمي وصانع محتوى محترف (تعمل بآلية مشابهة لـ Google NotebookLM).
|
||||||
|
بناءً على نص الدرس التالي، قم بتوليد حزمة تعليمية متكاملة بصيغة JSON فقط.
|
||||||
|
|
||||||
|
أريد الإجابة بصيغة JSON صارمة تحتوي على المفاتيح التالية:
|
||||||
|
{
|
||||||
|
\"video_script\": \"سيناريو حواري حيوي للمعلم يشرح الدرس بحماس مع التوجيهات البصرية.\",
|
||||||
|
\"cheat_sheet\": \"ملخص الدرس بخطوات سريعة ومبسطة جداً (بصيغة Markdown).\",
|
||||||
|
\"socratic_quiz\": {
|
||||||
|
\"question\": \"سؤال ذكي متعدد الخيارات\",
|
||||||
|
\"options\": [\"خيار A\", \"خيار B\", \"خيار C\", \"خيار D\"],
|
||||||
|
\"correct_answer\": \"النص الدقيق للخيار الصحيح\",
|
||||||
|
\"explanation\": \"تفسير سبب صحة هذا الخيار\"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
عنوان الدرس: {$title}
|
||||||
|
محتوى الدرس: {$content}";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function callGemini(string $prompt): ?array
|
||||||
|
{
|
||||||
|
$apiKey = Env::get('GEMINI_API_KEY');
|
||||||
|
if (!$apiKey) {
|
||||||
|
$keys = explode(',', getenv('GEMINI_API_KEY'));
|
||||||
|
$apiKey = trim($keys[0] ?? '');
|
||||||
|
}
|
||||||
|
if (!$apiKey) return null;
|
||||||
|
|
||||||
|
$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.7]
|
||||||
|
];
|
||||||
|
|
||||||
|
$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 => 60
|
||||||
|
]);
|
||||||
|
$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);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user