from fastapi import FastAPI, HTTPException from pydantic import BaseModel from fastapi.middleware.cors import CORSMiddleware import os import google.generativeai as genai from typing import List, Optional from uuid import uuid4 # Konfigurasi Gemini API genai.configure(api_key=os.environ["GEMINI_API_KEY"]) model = genai.GenerativeModel("gemini-1.5-flash") # Init FastAPI app = FastAPI() # CORS biar frontend bebas akses app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # === MODEL UNTUK REQUEST === class PromptRequest(BaseModel): prompt: str max_new_tokens: int = 300 temperature: float = 0.7 history: Optional[List[str]] = [] class GenerateSoalRequest(BaseModel): topic: str level: Optional[int] = 1 tipe_pertanyaan: Optional[str] = None # "pilihan_ganda", "isian_kosong", "benar_salah" # === HELPER FUNCTION === def format_prompt_soal(topic, tipe=None, level=1): tipe_instruksi = f"Tipe soal yang diminta adalah '{tipe}'." if tipe else "Tipe soal boleh bebas." return f""" Buatkan satu soal latihan grammar Bahasa Inggris untuk topik: "{topic}". {tipe_instruksi} Level kesulitan: {level}/5. Format keluaran harus dalam JSON seperti berikut: {{ "text_pertanyaan": "Tulis pertanyaan di sini...", "tipe_pertanyaan": "pilihan_ganda | isian_kosong | benar_salah", "opsi": {{ "a": "Pilihan A", "b": "Pilihan B", "c": "Pilihan C", "d": "Pilihan D" }}, "jawaban_benar": "b", "penjelasan": "Berikan penjelasan edukatif tentang jawaban yang benar." }} Catatan: - Jika tipe soal bukan "pilihan_ganda", sesuaikan struktur 'opsi' (bisa null atau objek true/false). - Jangan tambahkan teks selain JSON. - Jangan tambahkan penjelasan tambahan di luar JSON. Mulai sekarang, buat 1 soal untuk topik di atas dan jawab dalam format JSON! """ # === ENDPOINT UNTUK PERBAIKAN KELUARAN MODEL (EXISTING) === @app.post("/generate") async def generate_text(req: PromptRequest): try: system_prompt = f""" Kamu adalah asisten edukatif untuk sistem pembelajaran Bahasa Inggris. Berikut ini adalah hasil dari model LLaMA: --- MULAI --- {req.prompt} --- SELESAI --- Tugas kamu adalah: 1. Periksa dan perbaiki kesalahan tata bahasa dan struktur kalimat jika perlu. 2. Ubah seluruh jawaban ke dalam Bahasa Indonesia dengan gaya edukatif dan mudah dipahami oleh pelajar. 3. Pertahankan contoh kalimat dalam Bahasa Inggris sebagaimana aslinya. Jangan diterjemahkan. 4. Pertahankan istilah grammar atau kata yang diapit tanda petik seperti "present continuous", "am", "is", "are", dll. 5. Jangan menambahkan penjelasan yang tidak berkaitan dengan topik grammar dalam jawaban. 6. Fokus pada konteks pembelajaran Bahasa Inggris. Jangan membahas topik lain di luar itu. 7. Jika isi jawaban terlalu panjang, buatlah ringkasan yang jelas dan tetap lengkap. Langsung tampilkan hasil akhir dalam Bahasa Indonesia tanpa menjelaskan proses atau langkah-langkah pengerjaan. """ messages = [{"role": "user", "parts": [{"text": system_prompt.strip()}]}] for msg in req.history or []: role = "user" if msg.startswith("User:") else "model" text = msg.replace("User: ", "").replace("Bot: ", "") messages.append({"role": role, "parts": [{"text": text}]}) result = model.generate_content( messages, generation_config={ "temperature": req.temperature, "max_output_tokens": req.max_new_tokens, } ) return {"generated_text": result.text} except Exception as e: raise HTTPException(status_code=500, detail=str(e)) # === ENDPOINT BARU UNTUK GENERATE SOAL DARI AI === @app.post("/generate-soal") async def generate_soal(req: GenerateSoalRequest): try: prompt = format_prompt_soal(req.topic, req.tipe_pertanyaan, req.level) result = model.generate_content( prompt, generation_config={"temperature": 0.8, "max_output_tokens": 512} ) # Bersihkan & parsing response (anggap Gemini kasih string JSON langsung) import json json_text = result.text.strip().split("```")[-1].strip() # Bersihin kalau ada blok kode soal_data = json.loads(json_text) soal_data["id"] = str(uuid4()) soal_data["topic_id"] = req.topic soal_data["level"] = req.level or 1 soal_data["is_ai_generated"] = True soal_data["created_at"] = str(os.getenv("TZ") or "2025-07-12T00:00:00Z") return {"soal": soal_data} except Exception as e: raise HTTPException(status_code=500, detail=f"Gagal generate soal: {e}") # === ROOT TEST === @app.get("/") async def root(): return {"message": "Gemini endpoint aktif bro! 🚀"}