From f7992f94623235fdce6430c0a3a83a271621ed97 Mon Sep 17 00:00:00 2001 From: abiyasa05 Date: Fri, 6 Jun 2025 15:00:31 +0700 Subject: [PATCH] create: add controller for generate question --- .../LiteracyGenerateQuestionsController.php | 407 ++++++++++++++++-- 1 file changed, 371 insertions(+), 36 deletions(-) diff --git a/Penilaian Literasi/iClOP-V2/app/Http/Controllers/Literacy/LiteracyGenerateQuestionsController.php b/Penilaian Literasi/iClOP-V2/app/Http/Controllers/Literacy/LiteracyGenerateQuestionsController.php index 3710c56..fb47ce6 100644 --- a/Penilaian Literasi/iClOP-V2/app/Http/Controllers/Literacy/LiteracyGenerateQuestionsController.php +++ b/Penilaian Literasi/iClOP-V2/app/Http/Controllers/Literacy/LiteracyGenerateQuestionsController.php @@ -11,6 +11,11 @@ use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Storage; +use Illuminate\Support\Facades\Log; +use Smalot\PdfParser\Parser; +use PhpOffice\PhpWord\IOFactory; +use PhpOffice\PhpWord\Element\Text; +use PhpOffice\PhpWord\Element\TextRun; class LiteracyGenerateQuestionsController extends Controller { @@ -45,19 +50,39 @@ public function generate_questions() ]); } - // function generate_from_ai(Request $request) + // Fungsi untuk menyimpan dan meng-generate pertanyaan + // public function generate_from_ai(Request $request) // { // try { - // $fastApiUrl = 'http://127.0.0.1:8001/generate/'; // Pastikan ini benar + // $fastApiUrl = 'http://127.0.0.1:8001/generate/'; + // // Mengirim request ke FastAPI // $response = Http::timeout(300)->post($fastApiUrl, [ // 'content' => $request->input('content'), // ]); + // // Jika response dari API berhasil // if ($response->successful()) { + // // Cek apakah data sudah ada + // $existingText = LiteracyGeneratedText::where('user_id', auth()->id()) + // ->where('generate_text', $response->json()['generated_questions']) + // ->first(); + + // if (!$existingText) { + // // Menyimpan hasil generate ke database hanya jika belum ada + // $generatedText = new LiteracyGeneratedText(); + // $generatedText->user_id = auth()->id(); + // $generatedText->generate_text = $response->json()['generated_questions'] ?? "No questions generated."; + // $generatedText->save(); + // } + + // // Ambil hasil generate terbaru dari database + // $latestGeneratedText = LiteracyGeneratedText::where('user_id', auth()->id())->latest()->first()->generate_text; + + // // Mengembalikan response sukses dengan pertanyaan yang dihasilkan // return response()->json([ // 'status' => 'success', - // 'generated_questions' => $response->json()['generated_questions'] ?? "No questions generated." + // 'generated_questions' => $latestGeneratedText // Ambil generate_text terbaru // ]); // } else { // return response()->json([ @@ -75,51 +100,361 @@ public function generate_questions() // } // Fungsi untuk menyimpan dan meng-generate pertanyaan - public function generate_from_ai(Request $request) + public function generate_from_ai_last(Request $request) { + $request->validate([ + 'material_id' => 'required|exists:literacy_materials,id', + 'question_type' => 'required|in:multiple_choice,essay', + 'question_count' => 'required|integer|min:1|max:20', + ]); + try { - $fastApiUrl = 'http://127.0.0.1:8001/generate/'; + ini_set('max_execution_time', 300); - // Mengirim request ke FastAPI - $response = Http::timeout(300)->post($fastApiUrl, [ - 'content' => $request->input('content'), - ]); + $material = LiteracyMaterial::findOrFail($request->material_id); + $filePath = 'public/' . $material->file_path; - // Jika response dari API berhasil - if ($response->successful()) { - // Cek apakah data sudah ada - $existingText = LiteracyGeneratedText::where('user_id', auth()->id()) - ->where('generate_text', $response->json()['generated_questions']) - ->first(); - - if (!$existingText) { - // Menyimpan hasil generate ke database hanya jika belum ada - $generatedText = new LiteracyGeneratedText(); - $generatedText->user_id = auth()->id(); - $generatedText->generate_text = $response->json()['generated_questions'] ?? "No questions generated."; - $generatedText->save(); - } - - // Ambil hasil generate terbaru dari database - $latestGeneratedText = LiteracyGeneratedText::where('user_id', auth()->id())->latest()->first()->generate_text; - - // Mengembalikan response sukses dengan pertanyaan yang dihasilkan + if (!Storage::exists($filePath)) { return response()->json([ - 'status' => 'success', - 'generated_questions' => $latestGeneratedText // Ambil generate_text terbaru - ]); + 'status' => 'error', + 'message' => 'File materi tidak ditemukan: ' . $filePath + ], 400); + } + + $fullPath = storage_path('app/' . $filePath); + $extension = strtolower(pathinfo($fullPath, PATHINFO_EXTENSION)); + $text = ''; + + if ($extension === 'pdf') { + $parser = new Parser(); + $pdf = $parser->parseFile($fullPath); + $text = $pdf->getText(); + } elseif ($extension === 'docx') { + $phpWord = IOFactory::load($fullPath); + foreach ($phpWord->getSections() as $section) { + if (method_exists($section, 'getElements')) { + foreach ($section->getElements() as $element) { + if ($element instanceof Text) { + $text .= $element->getText() . " "; + } elseif ($element instanceof TextRun && method_exists($element, 'getElements')) { + foreach ($element->getElements() as $subElement) { + if ($subElement instanceof Text) { + $text .= $subElement->getText() . " "; + } + } + } + } + } + } + } elseif ($extension === 'txt') { + $text = file_get_contents($fullPath); } else { return response()->json([ 'status' => 'error', - 'message' => 'Failed to fetch questions from AI.', - 'fastapi_response' => $response->body() - ], $response->status()); + 'message' => 'Format file tidak didukung.' + ], 400); } - } catch (\Exception $e) { + + if (empty(trim($text))) { + return response()->json([ + 'status' => 'error', + 'message' => 'Isi file tidak dapat dibaca sebagai teks.' + ], 400); + } + + $text = mb_convert_encoding($text, 'UTF-8', 'UTF-8'); + $text = strip_tags($text); + $text = substr($text, 0, length: 3000); + + $response = Http::timeout(300)->asJson()->post('http://127.0.0.1:8001/generate-from-material/', [ + 'content' => $text, + 'question_type' => $request->question_type, + 'question_count' => (int) $request->question_count, + ]); + + if ($response->successful()) { + $generatedText = LiteracyGeneratedText::create([ + 'user_id' => Auth::id(), + 'material_id' => $request->material_id, + 'question_type' => $request->question_type, + 'generate_text' => $response->json()['generated_questions'], + 'question_count' => $request->question_count, + ]); + + return response()->json([ + 'status' => 'success', + 'generated_questions' => $generatedText->generate_text + ]); + } + + Log::error('FastAPI Error Response:', [ + 'status' => $response->status(), + 'body' => $response->body() + ]); + return response()->json([ 'status' => 'error', - 'message' => 'Internal Server Error: ' . $e->getMessage() + 'message' => 'Gagal menghasilkan soal dari model', + 'response' => $response->json() + ], $response->status()); + + } catch (\Exception $e) { + Log::error('Generate Error:', ['error' => $e->getMessage()]); + return response()->json([ + 'status' => 'error', + 'message' => 'Terjadi kesalahan internal: ' . $e->getMessage() ], 500); } } + + public function generate_from_ai(Request $request) + { + $request->validate([ + 'material_id' => 'required|exists:literacy_materials,id', + 'question_type' => 'required|in:multiple_choice,essay', + 'question_count' => 'required|integer|min:1|max:20', + 'start_page' => 'nullable|integer|min:1', + 'end_page' => 'nullable|integer|min:1', + ]); + + try { + ini_set('max_execution_time', 300); + + $material = LiteracyMaterial::findOrFail($request->material_id); + $filePath = 'public/' . $material->file_path; + + if (!Storage::exists($filePath)) { + return response()->json([ + 'status' => 'error', + 'message' => 'File materi tidak ditemukan: ' . $filePath + ], 400); + } + + $fullPath = storage_path('app/' . $filePath); + $extension = strtolower(pathinfo($fullPath, PATHINFO_EXTENSION)); + $text = ''; + + if ($extension === 'pdf') { + $parser = new Parser(); + $pdf = $parser->parseFile($fullPath); + $pages = $pdf->getPages(); + + $start = $request->input('start_page', 10); + $end = $request->input('end_page', count($pages)); + + // Validasi batas halaman + if ($start < 1 || $start > count($pages) || $end < $start) { + return response()->json([ + 'status' => 'error', + 'message' => 'Halaman tidak valid atau melebihi jumlah halaman PDF.' + ], 400); + } + + for ($i = $start - 1; $i < $end && $i < count($pages); $i++) { + $text .= $pages[$i]->getText(); + } + } elseif ($extension === 'docx') { + $phpWord = IOFactory::load($fullPath); + foreach ($phpWord->getSections() as $section) { + if (method_exists($section, 'getElements')) { + foreach ($section->getElements() as $element) { + if ($element instanceof Text) { + $text .= $element->getText() . " "; + } elseif ($element instanceof TextRun && method_exists($element, 'getElements')) { + foreach ($element->getElements() as $subElement) { + if ($subElement instanceof Text) { + $text .= $subElement->getText() . " "; + } + } + } + } + } + } + } elseif ($extension === 'txt') { + $text = file_get_contents($fullPath); + } else { + return response()->json([ + 'status' => 'error', + 'message' => 'Format file tidak didukung.' + ], 400); + } + + if (empty(trim($text))) { + return response()->json([ + 'status' => 'error', + 'message' => 'Isi file tidak dapat dibaca sebagai teks.' + ], 400); + } + + // Sanitasi dan potong agar tidak melebihi token limit + $text = mb_convert_encoding($text, 'UTF-8', 'UTF-8'); + $text = strip_tags($text); + $text = substr($text, 0, 3000); // max 3000 karakter (bisa diatur) + + $response = Http::timeout(300)->asJson()->post('http://127.0.0.1:8001/generate-from-material/', [ + 'content' => $text, + 'question_type' => $request->question_type, + 'question_count' => (int) $request->question_count, + ]); + + if ($response->successful()) { + $generatedText = LiteracyGeneratedText::create([ + 'user_id' => Auth::id(), + 'material_id' => $request->material_id, + 'question_type' => $request->question_type, + 'generate_text' => $response->json()['generated_questions'], + 'question_count' => $request->question_count, + ]); + + return response()->json([ + 'status' => 'success', + 'generated_questions' => $generatedText->generate_text + ]); + } + + Log::error('FastAPI Error Response:', [ + 'status' => $response->status(), + 'body' => $response->body() + ]); + + return response()->json([ + 'status' => 'error', + 'message' => 'Gagal menghasilkan soal dari model', + 'response' => $response->json() + ], $response->status()); + + } catch (\Exception $e) { + Log::error('Generate Error:', ['error' => $e->getMessage()]); + return response()->json([ + 'status' => 'error', + 'message' => 'Terjadi kesalahan internal: ' . $e->getMessage() + ], 500); + } + } + + // public function generate_from_ai(Request $request) + // { + // $request->validate([ + // 'material_id' => 'required|exists:literacy_materials,id', + // 'question_type' => 'required|in:multiple_choice,essay', + // 'question_count' => 'required|integer|min:1|max:20', + // ]); + + // try { + // $material = LiteracyMaterial::findOrFail($request->material_id); + + // // Ambil path file PDF + // $filePath = 'public/' . $material->file_path; + // if (!Storage::exists($filePath)) { + // return response()->json([ + // 'status' => 'error', + // 'message' => 'File materi tidak ditemukan: ' . $filePath + // ], 400); + // } + + // // Parse isi PDF halaman 15-17 (index 14 sampai 16) + // $parser = new Parser(); + // $pdf = $parser->parseFile(storage_path('app/' . $filePath)); + // $pages = $pdf->getPages(); + + // $startPage = 14; // halaman 15 (index mulai 0) + // $endPage = 16; // halaman 17 + // $totalPages = count($pages); + + // if ($totalPages < $startPage + 1) { + // return response()->json([ + // 'status' => 'error', + // 'message' => 'PDF tidak cukup halaman untuk mengambil halaman 15-17' + // ], 400); + // } + + // $text = ''; + // for ($i = $startPage; $i <= $endPage && $i < $totalPages; $i++) { + // $text .= $pages[$i]->getText() . "\n"; + // } + + // // Bersihkan dan batasi panjang konten + // $text = mb_convert_encoding($text, 'UTF-8', 'UTF-8'); + // $text = strip_tags($text); + // $text = substr($text, 0, 5000); // potong supaya tidak terlalu panjang + + // // Kirim ke FastAPI + // $response = Http::timeout(300) + // ->asJson() + // ->post('http://127.0.0.1:8001/generate-from-material/', [ + // 'content' => $text, + // 'question_type' => $request->question_type, + // 'question_count' => (int) $request->question_count, + // ]); + + // if ($response->successful()) { + // $generatedText = LiteracyGeneratedText::create([ + // 'user_id' => auth()->id(), + // 'material_id' => $request->material_id, + // 'question_type' => $request->question_type, + // 'generate_text' => $response->json()['generated_questions'], + // 'question_count' => $request->question_count, + // ]); + + // return response()->json([ + // 'status' => 'success', + // 'generated_questions' => $generatedText->generate_text + // ]); + // } + + // Log::error('FastAPI Error Response:', [ + // 'status' => $response->status(), + // 'body' => $response->body() + // ]); + + // return response()->json([ + // 'status' => 'error', + // 'message' => 'Gagal menghasilkan soal dari model', + // 'response' => $response->json() + // ], $response->status()); + + // } catch (\Exception $e) { + // Log::error('Generate Error:', ['error' => $e->getMessage()]); + // return response()->json([ + // 'status' => 'error', + // 'message' => 'Terjadi kesalahan internal: ' . $e->getMessage() + // ], 500); + // } + // } + + public function history_generated_texts() + { + $history_generated_texts = LiteracyGeneratedText::where('user_id', Auth::id()) + ->orderBy('created_at', 'desc') + ->get(); + + $materials = LiteracyMaterial::all(); + + return view('literacy.teacher.history_generated.index', [ + 'history_generated_texts' => $history_generated_texts, + 'materials' => $materials, + ]); + } + + public function show_history_generated_texts($id) + { + $history_generated_texts = LiteracyGeneratedText::all(); + return view('literacy.teacher.history_generated.index', compact('history_generated_texts')); + } + + public function history_index() + { + $history_generated_texts = LiteracyGeneratedText::orderBy('created_at', 'desc')->get(); + + return view('literacy.teacher.history_generated.index', compact('history_generated_texts')); + } + + public function destroy_history($id) + { + $deleted = LiteracyGeneratedText::findOrFail($id); + $deleted->delete(); + + return redirect()->route('literacy_teacher_generate_questions_history') + ->with('success', 'History deleted successfully.'); + } } \ No newline at end of file