File size: 7,178 Bytes
fbe1c8a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fe421f4
fbe1c8a
 
fe421f4
 
 
 
 
 
 
 
6a91b07
 
 
 
 
 
 
 
 
 
fbe1c8a
fe421f4
 
 
fbe1c8a
 
6a91b07
 
 
 
 
 
 
 
 
 
 
 
 
fbe1c8a
 
 
6a91b07
fbe1c8a
 
 
 
 
 
 
 
 
 
 
 
 
fe421f4
6a91b07
 
fbe1c8a
 
 
fe421f4
6a91b07
fbe1c8a
 
6a91b07
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fbe1c8a
 
 
 
 
 
fe421f4
6a91b07
fbe1c8a
 
 
 
 
 
 
 
 
 
 
 
6a91b07
fbe1c8a
 
 
 
 
 
fe421f4
6a91b07
fbe1c8a
 
 
 
 
 
 
 
 
 
 
 
 
 
6a91b07
fbe1c8a
 
 
 
 
fe421f4
6a91b07
fbe1c8a
 
 
 
 
 
 
 
 
 
 
 
 
 
fe421f4
6a91b07
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
# api/teacher_agent.py
"""
教师端 AI Agent:基于与 Clare 相同的 Weaviate(GenAICourses)与 OpenAI,为教师提供:
- 课程描述生成
- 课程文档内容建议
- 作业和题库生成建议
- 学生学习评估分析
"""
from typing import Optional

from .config import client, DEFAULT_MODEL, USE_WEAVIATE
from .weaviate_retrieve import retrieve_from_weaviate

TEACHER_SYSTEM = """你是一位面向高校教师的 AI 助教,擅长课程设计、教学材料建议与学习评估分析。
你与 Clare 共用同一套 GENAI 课程知识库(Weaviate)。回答时请优先依据提供的「课程知识库摘录」,
并结合通用教学经验,给出简洁、可操作的建议。若未提供知识库摘录,则基于通用教育学与学科知识回答。"""


def _lang_instruction(reply_language: Optional[str]) -> str:
    if reply_language == "en" or reply_language == "english":
        return "You must reply in English only."
    if reply_language == "zh" or reply_language == "中文" or not reply_language:
        return "请务必仅用中文回答。"
    return ""


def _call_llm(
    user_content: str,
    system_extra: str = "",
    reply_language: Optional[str] = None,
    max_tokens: int = 1500,
    history: Optional[list] = None,
) -> str:
    """
    history: List of tuples [(user_msg, assistant_msg), ...] for conversation context
    """
    system = TEACHER_SYSTEM
    lang = _lang_instruction(reply_language)
    if lang:
        system = system + "\n\n" + lang
    if system_extra:
        system = system + "\n\n" + system_extra
    
    messages = [{"role": "system", "content": system}]
    
    # Add conversation history if provided
    if history:
        for user_msg, assistant_msg in history[-10:]:  # Keep last 10 turns
            if user_msg:
                messages.append({"role": "user", "content": user_msg})
            if assistant_msg:
                messages.append({"role": "assistant", "content": assistant_msg})
    
    messages.append({"role": "user", "content": user_content})
    
    try:
        resp = client.chat.completions.create(
            model=DEFAULT_MODEL,
            messages=messages,
            temperature=0.6,
            max_tokens=max_tokens,
            timeout=60,
        )
        return (resp.choices[0].message.content or "").strip()
    except Exception as e:
        print(f"[teacher_agent] LLM error: {repr(e)}")
        return f"生成时出错:{repr(e)}。请稍后重试。"


def generate_course_description(
    topic: str,
    outline_hint: Optional[str] = None,
    reply_language: Optional[str] = None,
    history: Optional[list] = None,
    user_message: Optional[str] = None,
) -> str:
    """
    课程描述生成:根据课程主题(及可选大纲要点)生成一段可用于课程介绍/选课页的描述。
    reply_language: "en" | "zh" | None(默认中文)
    user_message: 持续对话时的用户消息(可选)
    """
    rag = retrieve_from_weaviate(topic, top_k=6) if USE_WEAVIATE else ""
    
    if user_message:
        # 持续对话模式:直接使用用户消息
        user = user_message
        if rag:
            user = f"**参考知识库摘录:**\n{rag[:4000]}\n\n---\n\n{user}"
    else:
        # 初始提交模式:使用表单字段
        user = f"请根据以下信息,生成一段简洁的**课程描述**(约 150–250 字),适合放在课程介绍或选课页面。\n\n"
        user += f"**课程主题/名称:** {topic}\n\n"
        if outline_hint:
            user += f"**大纲或要点(可选):**\n{outline_hint}\n\n"
        if rag:
            user += "**参考知识库摘录(请据此保持与现有课程内容一致):**\n" + rag[:4000] + "\n\n"
        user += "请直接输出课程描述正文,无需重复题目。"
    
    return _call_llm(user, reply_language=reply_language, max_tokens=800, history=history)


def suggest_course_doc_content(
    topic: str,
    current_doc_excerpt: Optional[str] = None,
    doc_type: str = "讲义/课件",
    reply_language: Optional[str] = None,
    history: Optional[list] = None,
) -> str:
    """
    课程文档内容建议:针对某一主题或现有文档片段,给出可写入讲义/课件的内容建议。
    """
    rag = retrieve_from_weaviate(topic, top_k=8) if USE_WEAVIATE else ""
    user = f"请针对以下**课程文档**(类型:{doc_type})给出**内容建议**:结构要点、关键概念、可选的例子或习题方向。\n\n"
    user += f"**主题或章节:** {topic}\n\n"
    if current_doc_excerpt:
        user += f"**当前已有内容(片段):**\n{current_doc_excerpt[:2000]}\n\n"
    if rag:
        user += "**参考知识库摘录:**\n" + rag[:5000] + "\n\n"
    user += "请用分点或短段落给出建议,便于教师直接采纳或改写。"
    return _call_llm(user, reply_language=reply_language, max_tokens=1200, history=history)


def suggest_assignments_questions(
    topic: str,
    week_or_module: Optional[str] = None,
    question_type: str = "混合",
    reply_language: Optional[str] = None,
    history: Optional[list] = None,
) -> str:
    """
    作业和题库生成建议:根据主题(及可选周次/模块)给出作业题、练习题或考试题建议。
    question_type 可为:选择题、简答题、开放题、混合 等。
    """
    rag = retrieve_from_weaviate(topic, top_k=8) if USE_WEAVIATE else ""
    user = f"请根据以下课程信息,给出**作业与题库**的生成建议:包含题目类型、难度分布、2–3 道示例题(含参考答案要点)。\n\n"
    user += f"**主题:** {topic}\n\n"
    if week_or_module:
        user += f"**周次/模块:** {week_or_module}\n\n"
    user += f"**题型偏好:** {question_type}\n\n"
    if rag:
        user += "**参考知识库摘录:**\n" + rag[:5000] + "\n\n"
    user += "请直接给出建议与示例题,便于教师录入题库或布置作业。"
    return _call_llm(user, reply_language=reply_language, max_tokens=1500, history=history)


def analyze_student_assessment(
    assessment_summary: str,
    course_topic_hint: Optional[str] = None,
    reply_language: Optional[str] = None,
    history: Optional[list] = None,
) -> str:
    """
    学生学习评估分析:根据教师提供的学生表现摘要(如作业/测验得分、常见错误、参与度等),
    给出简要分析结论与教学改进建议。
    """
    rag = ""
    if course_topic_hint and USE_WEAVIATE:
        rag = retrieve_from_weaviate(course_topic_hint, top_k=4)
    user = "请根据以下**学生学习评估信息**,给出简要的**分析结论**与**教学改进建议**(分点、可操作)。\n\n"
    user += f"**评估摘要:**\n{assessment_summary}\n\n"
    if course_topic_hint:
        user += f"**相关课程主题:** {course_topic_hint}\n\n"
    if rag:
        user += "**参考知识库摘录(可选,用于对齐课程目标):**\n" + rag[:3000] + "\n\n"
    user += "控制在 300–500 字。"
    return _call_llm(user, reply_language=reply_language, max_tokens=800, history=history)