File size: 3,485 Bytes
cc73727
5804d3d
cc73727
61f8c8e
5804d3d
cc73727
 
 
 
 
 
 
 
 
 
 
5804d3d
 
cc73727
257d15f
cc73727
 
 
 
 
257d15f
 
cc73727
 
 
 
 
 
 
 
 
 
 
257d15f
cc73727
b3687e7
cc73727
257d15f
5804d3d
 
cc73727
257d15f
cc73727
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61f8c8e
3bb7108
cc73727
257d15f
cc73727
3bb7108
257d15f
cc73727
 
3bb7108
cc73727
 
3bb7108
cc73727
 
 
 
 
 
 
 
 
 
257d15f
3bb7108
 
 
b2c3ef9
f53cf63
61f8c8e
150e70c
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
# agents.py
import os
import json
import random

# Try to import zhipuai client
ZHIPU_AVAILABLE = False
client = None
ZHIPU_KEY = os.getenv("zhipuai_api_key")
if ZHIPU_KEY:
    try:
        from zhipuai import ZhipuAI
        client = ZhipuAI(api_key=ZHIPU_KEY)
        ZHIPU_AVAILABLE = True
    except Exception:
        ZHIPU_AVAILABLE = False

class AnalyzerAgent:
    """Simple objective analyzer for MCQ answers."""
    def analyze(self, student_answers, correct_answers):
        """
        student_answers: list of strings like 'A', 'B', 'C' or actual choice text
        correct_answers: list of strings (prefer letter 'A'..'D' or exact text)
        Returns (score, analysis_list)
        """
        score = 0
        analysis = []
        for i, (s, c) in enumerate(zip(student_answers, correct_answers), start=1):
            s_norm = (s or "").strip()
            c_norm = (c or "").strip()
            ok = False
            if c_norm == "":
                ok = False
            elif len(c_norm) == 1 and c_norm.upper() in ["A","B","C","D"]:
                ok = (s_norm.upper() == c_norm.upper())
            else:
                ok = (s_norm.lower() == c_norm.lower())
            if ok:
                score += 1
                analysis.append(f"Q{i}: ✅")
            else:
                analysis.append(f"Q{i}: ❌ (Your: {s_norm} | Key: {c_norm})")
        return score, analysis

class CoachAgent:
    """Provides AI feedback using ZhipuAI if available."""
    def __init__(self):
        self.client = client

    def coach(self, context_text):
        """
        context_text: a small JSON/string summarizing student's performance.
        Returns an advice string.
        """
        if not ZHIPU_AVAILABLE or self.client is None:
            # Fallback advice
            return "AI coach not configured. Set environment variable 'zhipuai_api_key' to enable AI analysis.\nGeneral advice: Review the wrong questions, focus on weak topics, and practice time management."
        try:
            prompt = (
                "You are an experienced SPM coach. Given the student's summary, provide concise actionable advice (3-5 bullets).\n\n"
                f"Student summary:\n{context_text}\n\nAdvice:"
            )
            resp = self.client.chat.completions.create(
                model="glm-4",
                messages=[{"role":"user","content":prompt}],
                temperature=0.2,
            )
            out = resp.choices[0].message["content"].strip()
            return out
        except Exception as e:
            return f"AI coach error: {str(e)}"

class PredictiveAgent:
    """(Optional) Use LLM to forecast likely topics/questions."""
    def __init__(self):
        self.client = client

    def predict(self, subject, year_range="2018-2024"):
        if not ZHIPU_AVAILABLE or self.client is None:
            return "Predicted question (LLM not configured)."
        prompt = (
            f"Analyze SPM {subject} past papers between {year_range}. "
            "Identify recurring topics and predict 5 high-probability short objective questions."
        )
        try:
            resp = self.client.chat.completions.create(
                model="glm-4",
                messages=[{"role":"user","content":prompt}],
                temperature=0.3,
            )
            return resp.choices[0].message["content"].strip()
        except Exception as e:
            return f"Prediction error: {str(e)}"