cryogenic22 commited on
Commit
77249ba
·
verified ·
1 Parent(s): 1e4eb9a

Update learning_platform.py

Browse files
Files changed (1) hide show
  1. learning_platform.py +92 -145
learning_platform.py CHANGED
@@ -1,26 +1,85 @@
1
-
2
- import logging
3
  from typing import List, Dict, Any
4
  from dataclasses import dataclass, field
5
  from datetime import datetime
6
  import json
 
7
  from langchain.chat_models import ChatOpenAI
8
  from langchain.embeddings import OpenAIEmbeddings
9
  from langchain_community.vectorstores import FAISS
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
 
11
- logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S')
 
12
 
13
  class CourseBuilder:
14
- def __init__(self, api_key: str, agent_logs: list):
15
  self.api_key = api_key
16
- self.agent_logs = agent_logs
17
  self.llm = ChatOpenAI(
18
  temperature=0.7,
19
  model="gpt-4",
20
- openai_api_key=api_key,
21
- max_retries=3,
22
- retry_on_timeout=True,
23
- timeout=60
24
  )
25
  self.embeddings = OpenAIEmbeddings(openai_api_key=api_key)
26
  self.vector_store = FAISS.from_texts(
@@ -30,44 +89,25 @@ class CourseBuilder:
30
  self.prompts = CoursePrompts()
31
 
32
  async def plan_course(self, topic: str, difficulty: str) -> LearningPath:
33
- logging.info(f"Planning course for topic: {topic}, difficulty: {difficulty}")
34
  prompt = self.prompts.course_planning_prompt().format(topic=topic, difficulty=difficulty)
35
- logging.info(f"Sending prompt: {prompt}")
36
-
37
- try:
38
- response = await self.llm.apredict(prompt)
39
- logging.info(f"Received response: {response}")
40
- except Exception as e:
41
- logging.error(f"Error getting response from API: {str(e)}")
42
- self.agent_logs.append(f"Error getting response from API: {str(e)}")
43
- raise e
44
-
45
  if not response.strip():
46
- logging.error("Empty response from API")
47
- self.agent_logs.append("Empty response from API")
48
  raise ValueError("Empty response from API")
49
  else:
50
- self.agent_logs.append(f"Raw response from API: {response}")
51
-
52
  try:
53
  course_plan = json.loads(response)
54
- logging.info(f"Parsed course plan: {course_plan}")
55
  except json.JSONDecodeError as e:
56
- logging.error(f"Invalid JSON response from API: {str(e)}\nResponse: {response}")
57
- self.agent_logs.append(f"Invalid JSON response from API: {str(e)}\nResponse: {response}")
58
  raise ValueError(f"Invalid JSON response from API: {str(e)}\nResponse: {response}")
59
 
60
- modules = []
61
- for module_data in course_plan.get("modules", []):
62
- if "title" not in module_data:
63
- logging.error(f"Missing 'title' field in module: {module_data}")
64
- self.agent_logs.append(f"Missing 'title' field in module: {module_data}")
65
- raise ValueError("Invalid module data: missing 'title' field")
66
-
67
- module = CourseModule(
68
- title=module_data["title"],
69
- objectives=module_data["objectives"],
70
- prerequisites=module_data.get("prerequisites", []),
71
  sections=[
72
  Section(
73
  title=section["title"],
@@ -75,10 +115,10 @@ class CourseBuilder:
75
  key_points=section.get("key_points", []),
76
  examples=section.get("examples", []),
77
  quiz_questions=section.get("quiz_questions", [])
78
- ) for section in module_data.get("sections", [])
79
  ]
80
- )
81
- modules.append(module)
82
 
83
  learning_path = LearningPath(
84
  topic=topic,
@@ -95,38 +135,23 @@ class CourseBuilder:
95
  metadatas=[{"type": "course_plan", "topic": topic}]
96
  )
97
 
98
- logging.info(f"Created learning path: {learning_path}")
99
  return learning_path
100
 
101
  async def create_module_content(self, module: CourseModule) -> List[Section]:
102
- logging.info(f"Creating content for module: {module.title}")
103
  prompt = self.prompts.module_content_prompt().format(
104
  title=module.title,
105
  objectives=", ".join(module.objectives)
106
  )
107
- logging.info(f"Sending prompt: {prompt}")
108
-
109
- try:
110
- response = await self.llm.apredict(prompt)
111
- logging.info(f"Received response: {response}")
112
- except Exception as e:
113
- logging.error(f"Error getting response from API: {str(e)}")
114
- self.agent_logs.append(f"Error getting response from API: {str(e)}")
115
- raise e
116
 
117
  if not response.strip():
118
- logging.error("Empty response from API")
119
- self.agent_logs.append("Empty response from API")
120
  raise ValueError("Empty response from API")
121
-
122
  try:
123
  content_json = json.loads(response)
124
- logging.info(f"Parsed module content: {content_json}")
125
  except json.JSONDecodeError as e:
126
- logging.error(f"Invalid JSON response from API: {str(e)}\nResponse: {response}")
127
- self.agent_logs.append(f"Invalid JSON response from API: {str(e)}\nResponse: {response}")
128
  raise ValueError(f"Invalid JSON response from API: {str(e)}\nResponse: {response}")
129
-
130
  sections = [Section(**section) for section in content_json.get("sections", [])]
131
 
132
  # Store embeddings for module content
@@ -136,129 +161,51 @@ class CourseBuilder:
136
  metadatas=[{"type": "module_content", "module": module.title}]
137
  )
138
 
139
- logging.info(f"Created {len(sections)} sections for module: {module.title}")
140
  return sections
141
 
142
  async def answer_user_question(self, topic: str, module_title: str, question: str) -> str:
143
- logging.info(f"Answering user question for topic: {topic}, module: {module_title}, question: {question}")
144
  prompt = self.prompts.user_question_prompt().format(
145
  topic=topic,
146
  module_title=module_title,
147
  question=question
148
  )
149
- logging.info(f"Sending prompt: {prompt}")
150
-
151
- try:
152
- response = await self.llm.apredict(prompt)
153
- logging.info(f"Received response: {response}")
154
- except Exception as e:
155
- logging.error(f"Error getting response from API: {str(e)}")
156
- self.agent_logs.append(f"Error getting response from API: {str(e)}")
157
- raise e
158
 
159
  if not response.strip():
160
- logging.error("Empty response from API")
161
- self.agent_logs.append("Empty response from API")
162
  raise ValueError("Empty response from API")
163
 
164
  return response
165
 
166
- class CoursePrompts:
167
- @staticmethod
168
- def course_planning_prompt() -> str:
169
- return """As a course planning expert, design a structured learning path for {topic} at {difficulty} level.
170
-
171
- Requirements:
172
- 1. 5-7 progressive modules
173
- 2. Clear prerequisites and objectives
174
- 3. Practical applications
175
- 4. Real-world examples
176
- 5. A compelling description that excites the learner about the journey ahead
177
- 6. Each module should contain content, quiz questions, and be designed to progressively enhance understanding.
178
- Return a structured JSON with detailed content for each module.
179
- """
180
-
181
- @staticmethod
182
- def module_content_prompt() -> str:
183
- return """Create engaging module content for the module titled '{title}' with the following objectives:
184
-
185
- Objectives: {objectives}
186
-
187
- Include:
188
- 1. Clear explanations with practical examples to deepen understanding
189
- 2. Real-world applications relevant to the topic
190
- 3. Key points that summarize each section concisely
191
- 4. A set of 3-5 quiz questions for each section, with answers and explanations
192
- 5. Encourage learners to think critically and ask questions related to '{title}'
193
- Return a structured JSON with detailed content for each section.
194
- """
195
-
196
- @staticmethod
197
- def user_question_prompt() -> str:
198
- return """As an AI assistant, provide a clear and informative answer to the user's question based on the course topic '{topic}', the module '{module_title}', and the related content.
199
-
200
- User Question: {question}
201
-
202
- Ensure your response is helpful, easy to understand, and relevant to the course content.
203
- """
204
-
205
- @dataclass
206
- class Section:
207
- title: str
208
- content: str = ""
209
- key_points: List[str] = field(default_factory=list)
210
- examples: List[str] = field(default_factory=list)
211
- quiz_questions: List[Dict[str, Any]] = field(default_factory=list)
212
- is_complete: bool = False
213
-
214
- @dataclass
215
- class CourseModule:
216
- title: str
217
- objectives: List[str]
218
- prerequisites: List[str] = field(default_factory=list)
219
- sections: List[Section] = field(default_factory=list)
220
- is_complete: bool = False
221
-
222
- @dataclass
223
- class LearningPath:
224
- topic: str
225
- description: str
226
- modules: List[CourseModule]
227
- difficulty_level: str
228
- created_at: datetime
229
- is_generating: bool = True
230
-
231
  class LearningPlatform:
232
  def __init__(self, api_key: str = None):
233
  self.api_key = api_key or os.getenv("OPENAI_API_KEY")
234
- self.agent_logs = []
235
- self.course_builder = CourseBuilder(self.api_key, self.agent_logs)
236
 
237
  async def create_course(self, topic: str, difficulty: str) -> LearningPath:
238
  try:
239
  learning_path = await self.course_builder.plan_course(topic, difficulty)
240
  # Log successful course creation
241
- self.agent_logs.append(f"Successfully created course: {learning_path.topic}")
242
  return learning_path
243
  except Exception as e:
244
- self.agent_logs.append(f"Course creation error: {str(e)}")
245
  raise Exception(f"Course creation error: {str(e)}")
246
 
247
  async def generate_next_module(self, path: LearningPath, module_index: int):
248
  if module_index < len(path.modules):
249
  module = path.modules[module_index]
250
  if not module.is_complete:
251
- self.agent_logs.append(f"Generating content for module: {module.title}")
252
  sections = await self.course_builder.create_module_content(module)
253
  module.sections = sections
254
  module.is_complete = True
255
- self.agent_logs.append(f"Module '{module.title}' is now complete.")
256
 
257
  async def handle_user_question(self, path: LearningPath, module_index: int, question: str) -> str:
258
  if module_index < len(path.modules):
259
  module = path.modules[module_index]
260
- self.agent_logs.append(f"Answering user question for module: {module.title}")
261
  answer = await self.course_builder.answer_user_question(path.topic, module.title, question)
262
  return answer
263
  else:
264
- raise ValueError("Invalid module index")
 
 
 
1
  from typing import List, Dict, Any
2
  from dataclasses import dataclass, field
3
  from datetime import datetime
4
  import json
5
+ import os
6
  from langchain.chat_models import ChatOpenAI
7
  from langchain.embeddings import OpenAIEmbeddings
8
  from langchain_community.vectorstores import FAISS
9
+ import streamlit as st
10
+
11
+ @dataclass
12
+ class Section:
13
+ title: str
14
+ content: str = ""
15
+ key_points: List[str] = field(default_factory=list)
16
+ examples: List[str] = field(default_factory=list)
17
+ quiz_questions: List[Dict[str, Any]] = field(default_factory=list)
18
+ is_complete: bool = False
19
+
20
+ @dataclass
21
+ class CourseModule:
22
+ title: str
23
+ objectives: List[str]
24
+ prerequisites: List[str] = field(default_factory=list)
25
+ sections: List[Section] = field(default_factory=list)
26
+ is_complete: bool = False
27
+
28
+ @dataclass
29
+ class LearningPath:
30
+ topic: str
31
+ description: str
32
+ modules: List[CourseModule]
33
+ difficulty_level: str
34
+ created_at: datetime
35
+ is_generating: bool = True
36
+
37
+ class CoursePrompts:
38
+ @staticmethod
39
+ def course_planning_prompt() -> str:
40
+ return """As a course planning expert, design a structured learning path for {topic} at {difficulty} level.
41
+
42
+ Requirements:
43
+ 1. 5-7 progressive modules
44
+ 2. Clear prerequisites and objectives
45
+ 3. Practical applications
46
+ 4. Real-world examples
47
+ 5. A compelling description that excites the learner about the journey ahead
48
+ 6. Each module should contain content, quiz questions, and be designed to progressively enhance understanding.
49
+ Return a structured JSON with detailed content for each module.
50
+ """
51
+
52
+ @staticmethod
53
+ def module_content_prompt() -> str:
54
+ return """Create engaging module content for the module titled '{title}' with the following objectives:
55
+
56
+ Objectives: {objectives}
57
+
58
+ Include:
59
+ 1. Clear explanations with practical examples to deepen understanding
60
+ 2. Real-world applications relevant to the topic
61
+ 3. Key points that summarize each section concisely
62
+ 4. A set of 3-5 quiz questions for each section, with answers and explanations
63
+ 5. Encourage learners to think critically and ask questions related to '{title}'
64
+ Return a structured JSON with detailed content for each section.
65
+ """
66
+
67
+ @staticmethod
68
+ def user_question_prompt() -> str:
69
+ return """As an AI assistant, provide a clear and informative answer to the user's question based on the course topic '{topic}', the module '{module_title}', and the related content.
70
+
71
+ User Question: {question}
72
 
73
+ Ensure your response is helpful, easy to understand, and relevant to the course content.
74
+ """
75
 
76
  class CourseBuilder:
77
+ def __init__(self, api_key: str):
78
  self.api_key = api_key
 
79
  self.llm = ChatOpenAI(
80
  temperature=0.7,
81
  model="gpt-4",
82
+ openai_api_key=api_key
 
 
 
83
  )
84
  self.embeddings = OpenAIEmbeddings(openai_api_key=api_key)
85
  self.vector_store = FAISS.from_texts(
 
89
  self.prompts = CoursePrompts()
90
 
91
  async def plan_course(self, topic: str, difficulty: str) -> LearningPath:
 
92
  prompt = self.prompts.course_planning_prompt().format(topic=topic, difficulty=difficulty)
93
+ response = await self.llm.apredict(prompt)
94
+
95
+ # Debug: Log the raw response for troubleshooting
 
 
 
 
 
 
 
96
  if not response.strip():
 
 
97
  raise ValueError("Empty response from API")
98
  else:
99
+ st.session_state.agent_logs.append(f"Raw response from API: {response}")
100
+
101
  try:
102
  course_plan = json.loads(response)
 
103
  except json.JSONDecodeError as e:
 
 
104
  raise ValueError(f"Invalid JSON response from API: {str(e)}\nResponse: {response}")
105
 
106
+ modules = [
107
+ CourseModule(
108
+ title=module["title"],
109
+ objectives=module["objectives"],
110
+ prerequisites=module.get("prerequisites", []),
 
 
 
 
 
 
111
  sections=[
112
  Section(
113
  title=section["title"],
 
115
  key_points=section.get("key_points", []),
116
  examples=section.get("examples", []),
117
  quiz_questions=section.get("quiz_questions", [])
118
+ ) for section in module.get("sections", [])
119
  ]
120
+ ) for module in course_plan.get("modules", [])
121
+ ]
122
 
123
  learning_path = LearningPath(
124
  topic=topic,
 
135
  metadatas=[{"type": "course_plan", "topic": topic}]
136
  )
137
 
 
138
  return learning_path
139
 
140
  async def create_module_content(self, module: CourseModule) -> List[Section]:
 
141
  prompt = self.prompts.module_content_prompt().format(
142
  title=module.title,
143
  objectives=", ".join(module.objectives)
144
  )
145
+ response = await self.llm.apredict(prompt)
 
 
 
 
 
 
 
 
146
 
147
  if not response.strip():
 
 
148
  raise ValueError("Empty response from API")
149
+
150
  try:
151
  content_json = json.loads(response)
 
152
  except json.JSONDecodeError as e:
 
 
153
  raise ValueError(f"Invalid JSON response from API: {str(e)}\nResponse: {response}")
154
+
155
  sections = [Section(**section) for section in content_json.get("sections", [])]
156
 
157
  # Store embeddings for module content
 
161
  metadatas=[{"type": "module_content", "module": module.title}]
162
  )
163
 
 
164
  return sections
165
 
166
  async def answer_user_question(self, topic: str, module_title: str, question: str) -> str:
 
167
  prompt = self.prompts.user_question_prompt().format(
168
  topic=topic,
169
  module_title=module_title,
170
  question=question
171
  )
172
+ response = await self.llm.apredict(prompt)
 
 
 
 
 
 
 
 
173
 
174
  if not response.strip():
 
 
175
  raise ValueError("Empty response from API")
176
 
177
  return response
178
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
179
  class LearningPlatform:
180
  def __init__(self, api_key: str = None):
181
  self.api_key = api_key or os.getenv("OPENAI_API_KEY")
182
+ self.course_builder = CourseBuilder(self.api_key)
 
183
 
184
  async def create_course(self, topic: str, difficulty: str) -> LearningPath:
185
  try:
186
  learning_path = await self.course_builder.plan_course(topic, difficulty)
187
  # Log successful course creation
188
+ st.session_state.agent_logs.append(f"Successfully created course: {learning_path.topic}")
189
  return learning_path
190
  except Exception as e:
191
+ st.session_state.agent_logs.append(f"Course creation error: {str(e)}")
192
  raise Exception(f"Course creation error: {str(e)}")
193
 
194
  async def generate_next_module(self, path: LearningPath, module_index: int):
195
  if module_index < len(path.modules):
196
  module = path.modules[module_index]
197
  if not module.is_complete:
198
+ st.session_state.agent_logs.append(f"Generating content for module: {module.title}")
199
  sections = await self.course_builder.create_module_content(module)
200
  module.sections = sections
201
  module.is_complete = True
202
+ st.session_state.agent_logs.append(f"Module '{module.title}' is now complete.")
203
 
204
  async def handle_user_question(self, path: LearningPath, module_index: int, question: str) -> str:
205
  if module_index < len(path.modules):
206
  module = path.modules[module_index]
207
+ st.session_state.agent_logs.append(f"Answering user question for module: {module.title}")
208
  answer = await self.course_builder.answer_user_question(path.topic, module.title, question)
209
  return answer
210
  else:
211
+ raise ValueError("Invalid module index")