DeployMora / app /services /llm_engine.py
fjarsra's picture
Upload 11 files
64f0ed1 verified
import os
import json
from groq import Groq
from dotenv import load_dotenv
# Load API Key
load_dotenv()
# Inisialisasi Client Groq
client = Groq(
api_key=os.getenv("GROQ_API_KEY"),
)
# Model yang Anda pilih
MODEL_NAME = "llama-3.3-70b-versatile"
class LLMEngine:
# ... (kode inisialisasi client Groq tetap sama) ...
@staticmethod
async def process_user_intent(user_text: str, available_skills: list[str]):
skills_str = ", ".join(available_skills)
system_prompt = f"""
ROLE: Klasifikator Niat (Intent Classifier).
SKILL TERSEDIA: {skills_str}
TUGAS:
1. Tentukan kategori aksi.
2. Deteksi SEMUA skill yang disebutkan user.
OUTPUT JSON:
{{
"action": "START_EXAM" | "GET_RECOMMENDATION" | "CASUAL_CHAT",
"detected_skills": ["Skill A", "Skill B"] (List of strings, kosongkan jika tidak ada)
}}
"""
user_prompt = f'Input: "{user_text}"'
try:
response = client.chat.completions.create(
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt}
],
model=MODEL_NAME,
temperature=0.1, # Sangat kaku
response_format={"type": "json_object"}
)
return json.loads(response.choices[0].message.content)
except Exception as e:
print(f"Error intent: {e}")
return {"action": "CASUAL_CHAT", "detected_skill": None}
@staticmethod
async def casual_chat(user_text: str):
"""Untuk ngobrol santai jika tidak ada action khusus"""
system_prompt="""
ROLE: Kamu adalah asisten belajar bernama MORA.
TUGAS:
1. Hanya jawab pertanyaan terkait belajar pemrograman, AI, dan web development.
"""
try:
response = client.chat.completions.create(
messages=[
{"role": "system", "content": "Kamu adalah asisten belajar bernama MORA. Jawab ramah dan singkat."},
{"role": "user", "content": user_text}
],
model=MODEL_NAME,
)
return response.choices[0].message.content
except:
return "Maaf saya sedang error."
# ... (Fungsi generate_question dan evaluate_answer biarkan tetap ada) ...
@staticmethod
async def generate_question(topics: list[str], level: str):
topics_str = ", ".join(topics)
# System Prompt: Instruksi Dasar
system_prompt = f"""
ROLE: Kamu adalah Senior AI Engineer & Penguji Ujian Teknis.
TARGET LEVEL: {level}
TOPICS: {topics_str}
TUGAS:
Buatlah SATU soal studi kasus integrasi (gabungan) untuk menguji pemahaman kandidat.
INSTRUKSI KHUSUS:
1. Jangan menanyakan definisi. Buat skenario nyata.
2. Output HARUS dalam format JSON valid.
3. Pertanyaan hanya seputar What, How, Why
"""
# User Prompt: Trigger Generasi
user_prompt = """
Buatkan soal beserta rubrik penilaiannya sekarang.
OUTPUT FORMAT (JSON):
{
"question_text": "Teks pertanyaan untuk user...",
"grading_rubric": {
"key_concept": "Konsep utama...",
"must_have_keywords": ["keyword1", "keyword2"],
"explanation_focus": "Fokus penjelasan..."
}
}
"""
try:
# Panggil API Groq
response = client.chat.completions.create(
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt}
],
model=MODEL_NAME,
temperature=0.7,
# FITUR PENTING: Memaksa output JSON
response_format={"type": "json_object"}
)
# Parse string JSON ke Dictionary Python
return json.loads(response.choices[0].message.content)
except Exception as e:
print(f"Error generating question via Groq: {e}")
return None
@staticmethod
async def evaluate_answer(user_answer: str, question_context: dict):
rubric = question_context.get('grading_rubric')
question = question_context.get('question_text')
system_prompt = f"""
ROLE: Kamu adalah Penilai Ujian (Grader) yang objektif.
KONTEKS SOAL: "{question}"
RUBRIK (KUNCI JAWABAN):
- Konsep: {rubric['key_concept']}
- Keyword Wajib: {rubric['must_have_keywords']}
- Fokus: {rubric['explanation_focus']}
TUGAS:
Nilai jawaban user. Analisis maknanya secara semantik.
Output HARUS JSON.
"""
user_prompt = f"""
JAWABAN USER: "{user_answer}"
Berikan penilaianmu dalam format JSON berikut:
{{
"is_correct": boolean,
"score": integer (0-100),
"feedback": "Penjelasan singkat (maks 2 kalimat) kenapa benar/salah",
"missing_concepts": ["list konsep yang kurang"]
}}
"""
try:
response = client.chat.completions.create(
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt}
],
model=MODEL_NAME,
temperature=0.5, # Lebih rendah agar penilaian konsisten
response_format={"type": "json_object"}
)
return json.loads(response.choices[0].message.content)
except Exception as e:
print(f"Error evaluating answer via Groq: {e}")
# Return nilai default agar tidak crash
return {"is_correct": False, "score": 0, "feedback": "Terjadi kesalahan sistem evaluasi.", "missing_concepts": []}
@staticmethod
async def analyze_psych_answer(user_answer: str, question_data: dict):
"""
Menentukan user condong ke Opsi A atau B berdasarkan ketikan mereka.
"""
prompt = f"""
ROLE: Psikolog Penjurusan Karir IT.
PERTANYAAN: "{question_data['question']}"
OPSI A: "{question_data['options']['A']}"
OPSI B: "{question_data['options']['B']}"
JAWABAN USER: "{user_answer}"
TUGAS:
Analisis jawaban user. Apakah makna kalimatnya lebih dekat ke Opsi A atau Opsi B?
OUTPUT JSON:
{{
"choice": "A" | "B",
"reason": "Alasan singkat kenapa masuk kategori itu"
}}
"""
try:
response = client.chat.completions.create(
messages=[{"role": "user", "content": prompt}],
model=MODEL_NAME,
temperature=0.1, # Harus tegas
response_format={"type": "json_object"}
)
return json.loads(response.choices[0].message.content)
except Exception as e:
return {"choice": "A", "reason": "Error, default ke A"}
# Instance global
llm_engine = LLMEngine()