fjarsra commited on
Commit
efa350e
·
verified ·
1 Parent(s): b725bb4

Update app/services/llm_engine.py

Browse files
Files changed (1) hide show
  1. app/services/llm_engine.py +116 -0
app/services/llm_engine.py CHANGED
@@ -2,6 +2,7 @@ import os
2
  import json
3
  from groq import AsyncGroq
4
  from dotenv import load_dotenv
 
5
 
6
  load_dotenv()
7
 
@@ -316,5 +317,120 @@ class LLMEngine:
316
  print(f"ERROR Analyze Progress: {e}")
317
  return f"Error generate progress: {str(e)}"
318
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
319
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
320
  llm_engine = LLMEngine()
 
2
  import json
3
  from groq import AsyncGroq
4
  from dotenv import load_dotenv
5
+ from app.services.skill_manager import skill_manager
6
 
7
  load_dotenv()
8
 
 
317
  print(f"ERROR Analyze Progress: {e}")
318
  return f"Error generate progress: {str(e)}"
319
 
320
+ async def generate_curriculum_stateless(self, user_data: dict):
321
+ """
322
+ Menggabungkan Data JSON Asli + Kecerdasan LLM.
323
+ """
324
+ name = user_data.get('name', 'Learner')
325
+ role_name = user_data.get('active_path', 'General Tech')
326
+ missing_skills = user_data.get('missing_skills', [])
327
+
328
+ if not missing_skills:
329
+ return []
330
+
331
+ # --- STEP 1: AMBIL DATA DARI SKILL MANAGER ---
332
+ # Disini kita menggunakan object 'skill_manager' yang sudah di-import
333
+ role_json_data = skill_manager.get_role_data(role_name)
334
+
335
+ verified_context_list = []
336
+
337
+ for gap in missing_skills:
338
+ s_name = gap['skill_name']
339
+ t_level = gap['target_level'].lower()
340
+
341
+ # Cari skill di JSON
342
+ found_skill = None
343
+ if role_json_data:
344
+ for s in role_json_data.get('sub_skills', []):
345
+ # Simple matching nama skill
346
+ if s['name'].lower() in s_name.lower() or s_name.lower() in s['name'].lower():
347
+ found_skill = s
348
+ break
349
 
350
+ # Ambil detail course jika ketemu
351
+ if found_skill:
352
+ level_data = found_skill.get('levels', {}).get(t_level, {})
353
+ rec_data = level_data.get('recommendation', {})
354
+
355
+ real_course = rec_data.get('course_name', 'NOT_FOUND')
356
+ real_chapters = rec_data.get('specific_chapters', [])
357
+
358
+ verified_context_list.append({
359
+ "requested_skill": s_name,
360
+ "target_level": t_level,
361
+ "OFFICIAL_COURSE": real_course,
362
+ "OFFICIAL_CHAPTERS": real_chapters
363
+ })
364
+ else:
365
+ verified_context_list.append({
366
+ "requested_skill": s_name,
367
+ "target_level": t_level,
368
+ "OFFICIAL_COURSE": "NOT_FOUND",
369
+ "OFFICIAL_CHAPTERS": []
370
+ })
371
+
372
+ context_str = json.dumps(verified_context_list, indent=2)
373
+
374
+ # --- STEP 2: PROMPT ---
375
+ system_prompt = f"""
376
+ ROLE: Expert Curriculum Developer.
377
+ TUGAS: Susun rekomendasi kursus berdasarkan DATA RESMI DATABASE.
378
+
379
+ DATA USER:
380
+ - Nama: {name}
381
+ - Target Role: {role_name}
382
+
383
+ DATA RESMI (CONTEXT):
384
+ {context_str}
385
+
386
+ INSTRUKSI UTAMA:
387
+ 1. Iterasi setiap skill dalam DATA RESMI.
388
+ 2. Jika 'OFFICIAL_COURSE' tersedia (Bukan NOT_FOUND):
389
+ - WAJIB GUNAKAN Judul & Chapters tersebut. JANGAN MENGARANG.
390
+ 3. Jika 'OFFICIAL_COURSE' adalah "NOT_FOUND":
391
+ - Generate judul & bab yang relevan.
392
+
393
+ LOGIKA BADGE (PRIORITY):
394
+ - "🔴 High Priority": Jika level target = materi kursus (Setara).
395
+ - "🟡 Medium Priority": Jika level target < materi kursus (Upskill/Lebih sulit).
396
+ - "🟢 Low Priority": Jika level target > materi kursus (Review/Lebih mudah).
397
+
398
+ OUTPUT JSON:
399
+ {{
400
+ "items": [
401
+ {{
402
+ "skill": "Nama Skill",
403
+ "current_level": "Level Target",
404
+ "course_to_take": "Judul Kursus",
405
+ "chapters": ["Bab 1", "Bab 2"],
406
+ "match_score": 95.5,
407
+ "badge": "🔴 High Priority"
408
+ }}
409
+ ]
410
+ }}
411
+ """
412
+
413
+ try:
414
+ response_content = await self._execute_with_retry(
415
+ messages=[{"role": "system", "content": system_prompt}],
416
+ model="llama-3.3-70b-versatile",
417
+ temperature=0.3, # Rendah agar patuh data
418
+ response_format={"type": "json_object"}
419
+ )
420
+
421
+ data = json.loads(response_content)
422
+
423
+ if "items" in data and isinstance(data["items"], list):
424
+ return data["items"]
425
+
426
+ for val in data.values():
427
+ if isinstance(val, list):
428
+ return val
429
+
430
+ return []
431
+
432
+ except Exception as e:
433
+ print(f"Error Gen Curriculum: {e}")
434
+ return []
435
+
436
  llm_engine = LLMEngine()