File size: 7,695 Bytes
64f0ed1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
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()