cryogenic22 commited on
Commit
43f4955
·
verified ·
1 Parent(s): 1a1deca

Update learning_platform.py

Browse files
Files changed (1) hide show
  1. learning_platform.py +132 -106
learning_platform.py CHANGED
@@ -18,6 +18,7 @@ from langchain.agents.streaming import StreamingResponse
18
  # Data Models
19
  @dataclass
20
  class Section:
 
21
  title: str
22
  content: str = ""
23
  key_points: List[str] = field(default_factory=list)
@@ -26,6 +27,7 @@ class Section:
26
 
27
  @dataclass
28
  class CourseModule:
 
29
  title: str
30
  sections: List[Section] = field(default_factory=list)
31
  content: str = ""
@@ -35,6 +37,7 @@ class CourseModule:
35
 
36
  @dataclass
37
  class LearningPath:
 
38
  topic: str
39
  description: str
40
  modules: List[CourseModule]
@@ -44,6 +47,7 @@ class LearningPath:
44
 
45
  class Agents:
46
  def __init__(self, api_key: str):
 
47
  self.content_creator = ChatOpenAI(
48
  temperature=0.7,
49
  model="gpt-4",
@@ -57,6 +61,7 @@ class Agents:
57
 
58
  class ContentGenerator:
59
  def __init__(self, api_key: str):
 
60
  self.embeddings = OpenAIEmbeddings(openai_api_key=api_key)
61
  self.vector_store = FAISS.from_texts(
62
  ["Initial empty store"],
@@ -64,9 +69,11 @@ class ContentGenerator:
64
  )
65
 
66
  def add_to_knowledge_base(self, content: str, metadata: Dict = None):
 
67
  self.vector_store.add_texts([content], metadatas=[metadata or {}])
68
 
69
  class CourseState(TypedDict):
 
70
  messages: Annotated[Sequence[BaseMessage], add_messages]
71
  current_topic: str
72
  difficulty: str
@@ -76,6 +83,7 @@ class CourseState(TypedDict):
76
  class CoursePrompts:
77
  @staticmethod
78
  def planner_prompt() -> str:
 
79
  return """Create a course outline for {topic} at {difficulty} level.
80
  Return a strict JSON object:
81
  {{
@@ -90,6 +98,7 @@ class CoursePrompts:
90
 
91
  @staticmethod
92
  def section_prompt() -> str:
 
93
  return """Create a detailed section for {module_title} covering {topic}.
94
  Include:
95
  - Clear explanations
@@ -114,6 +123,7 @@ class CoursePrompts:
114
 
115
  @staticmethod
116
  def editor_prompt() -> str:
 
117
  return """Review and enhance the section:
118
  - Ensure clarity
119
  - Add examples
@@ -125,113 +135,128 @@ class CoursePrompts:
125
  Return in the same JSON format."""
126
 
127
  class CourseBuilder:
128
- def __init__(self, api_key: str = None):
129
- self.api_key = api_key or os.getenv("OPENAI_API_KEY")
130
- self.setup_agents()
131
- self.setup_graph()
132
-
133
- def setup_agents(self):
134
- self.llm = ChatOpenAI(
135
- temperature=0.7,
136
- model="gpt-4",
137
- openai_api_key=self.api_key
138
- )
139
-
140
- def course_planner(self, state: CourseState) -> CourseState:
141
- """Course planning agent node"""
142
- print("---COURSE PLANNER---")
143
- prompt = PromptTemplate(
144
- template=CoursePrompts.planner_prompt(),
145
- input_variables=["topic", "difficulty"]
146
- )
147
-
148
- response = self.llm.predict(
149
- prompt.format(
150
- topic=state["current_topic"],
151
- difficulty=state["difficulty"]
152
- )
153
- )
154
- return {
155
- "messages": [AIMessage(content=response)],
156
- "status": "planning",
157
- "current_topic": state["current_topic"],
158
- "difficulty": state["difficulty"],
159
- "modules": []
160
- }
161
-
162
- async def generate_module_content(self, module: CourseModule) -> List[Section]:
163
- try:
164
- section = Section(
165
- title=f"Introduction to {module.title}",
166
- content=f"Basic concepts of {module.title}",
167
- key_points=["Key concept 1", "Key concept 2"],
168
- quiz_questions=[{
169
- "question": f"What is {module.title}?",
170
- "options": ["A", "B", "C", "D"],
171
- "correct_answer": "A",
172
- "explanation": "Basic explanation"
173
- }]
174
- )
175
- return [section]
176
- except Exception as e:
177
- print(f"Error generating content: {e}")
178
- return []
179
-
180
- def check_quality(self, state: CourseState) -> Literal["edit", "complete"]:
181
- messages = state["messages"]
182
- last_message = messages[-1]
183
-
184
- if len(last_message.content) > 1000 and "code example" in last_message.content.lower():
185
- return "complete"
186
- return "edit"
187
-
188
- def setup_graph(self):
189
- workflow = StateGraph(CourseState)
190
-
191
- workflow.add_node("planner", self.course_planner)
192
- workflow.add_edge(START, "planner")
193
- workflow.add_edge("planner", END)
194
-
195
- self.graph = workflow.compile()
196
-
 
 
 
 
 
 
 
 
 
 
 
197
  class LearningPlatform:
198
- def __init__(self, api_key: str = None):
199
- self.api_key = api_key or os.getenv("OPENAI_API_KEY")
200
- self.course_builder = CourseBuilder(self.api_key)
201
- self.agents = Agents(self.api_key)
202
- self.content_generator = ContentGenerator(self.api_key)
203
-
204
- async def create_course(self, topic: str, difficulty: str) -> LearningPath:
205
- try:
206
- initial_state = {
207
- "messages": [HumanMessage(content=f"Create a course on {topic} at {difficulty} level")],
208
- "current_topic": topic,
209
- "difficulty": difficulty,
210
- "modules": [],
211
- "status": "planning"
212
- }
213
-
214
- # Create initial module directly
215
- module = CourseModule(
216
- title=topic,
217
- objectives=["Introduction to " + topic],
218
- prerequisites=[]
219
- )
220
- module.sections = await self.course_builder.generate_module_content(module)
221
- module.is_complete = True
222
-
223
- return LearningPath(
224
- topic=topic,
225
- description=f"A {difficulty} level course on {topic}",
226
- modules=[module],
227
- created_at=datetime.now(),
228
- difficulty_level=difficulty,
229
- is_generating=False
230
- )
231
-
232
- except Exception as e:
233
- raise Exception(f"Course creation error: {str(e)}")
234
-
 
 
 
 
235
  async def generate_next_module(self, path: LearningPath, module_index: int):
236
  """Generate content for the next module asynchronously"""
237
  if module_index < len(path.modules):
@@ -244,3 +269,4 @@ class LearningPlatform:
244
  section.content,
245
  {"module": module.title, "section": section.title}
246
  )
 
 
18
  # Data Models
19
  @dataclass
20
  class Section:
21
+ # Represents a section of a course module
22
  title: str
23
  content: str = ""
24
  key_points: List[str] = field(default_factory=list)
 
27
 
28
  @dataclass
29
  class CourseModule:
30
+ # Represents a module in a course, which contains multiple sections
31
  title: str
32
  sections: List[Section] = field(default_factory=list)
33
  content: str = ""
 
37
 
38
  @dataclass
39
  class LearningPath:
40
+ # Represents the entire learning path consisting of multiple modules
41
  topic: str
42
  description: str
43
  modules: List[CourseModule]
 
47
 
48
  class Agents:
49
  def __init__(self, api_key: str):
50
+ # Initializes the agents responsible for content creation and editing
51
  self.content_creator = ChatOpenAI(
52
  temperature=0.7,
53
  model="gpt-4",
 
61
 
62
  class ContentGenerator:
63
  def __init__(self, api_key: str):
64
+ # Initializes the content generator with OpenAI embeddings and FAISS vector store
65
  self.embeddings = OpenAIEmbeddings(openai_api_key=api_key)
66
  self.vector_store = FAISS.from_texts(
67
  ["Initial empty store"],
 
69
  )
70
 
71
  def add_to_knowledge_base(self, content: str, metadata: Dict = None):
72
+ # Adds content to the knowledge base for future reference
73
  self.vector_store.add_texts([content], metadatas=[metadata or {}])
74
 
75
  class CourseState(TypedDict):
76
+ # Represents the current state of the course being generated
77
  messages: Annotated[Sequence[BaseMessage], add_messages]
78
  current_topic: str
79
  difficulty: str
 
83
  class CoursePrompts:
84
  @staticmethod
85
  def planner_prompt() -> str:
86
+ # Prompt to create a course outline
87
  return """Create a course outline for {topic} at {difficulty} level.
88
  Return a strict JSON object:
89
  {{
 
98
 
99
  @staticmethod
100
  def section_prompt() -> str:
101
+ # Prompt to create a detailed section for a module
102
  return """Create a detailed section for {module_title} covering {topic}.
103
  Include:
104
  - Clear explanations
 
123
 
124
  @staticmethod
125
  def editor_prompt() -> str:
126
+ # Prompt to review and enhance a section of content
127
  return """Review and enhance the section:
128
  - Ensure clarity
129
  - Add examples
 
135
  Return in the same JSON format."""
136
 
137
  class CourseBuilder:
138
+ def __init__(self, api_key: str = None):
139
+ # Initializes the course builder with an API key and sets up the agents and graph
140
+ self.api_key = api_key or os.getenv("OPENAI_API_KEY")
141
+ self.setup_agents()
142
+ self.setup_graph()
143
+
144
+ def setup_agents(self):
145
+ # Sets up the language model agent for generating content
146
+ self.llm = ChatOpenAI(
147
+ temperature=0.7,
148
+ model="gpt-4",
149
+ openai_api_key=self.api_key
150
+ )
151
+
152
+ def course_planner(self, state: CourseState) -> CourseState:
153
+ """Course planning agent node"""
154
+ print("---COURSE PLANNER---")
155
+ # Create a prompt to generate the course outline
156
+ prompt = PromptTemplate(
157
+ template=CoursePrompts.planner_prompt(),
158
+ input_variables=["topic", "difficulty"]
159
+ )
160
+
161
+ # Use the language model to generate a response based on the prompt
162
+ response = self.llm.predict(
163
+ prompt.format(
164
+ topic=state["current_topic"],
165
+ difficulty=state["difficulty"]
166
+ )
167
+ )
168
+ # Return the updated state with the generated course plan
169
+ return {
170
+ "messages": [AIMessage(content=response)],
171
+ "status": "planning",
172
+ "current_topic": state["current_topic"],
173
+ "difficulty": state["difficulty"],
174
+ "modules": []
175
+ }
176
+
177
+ async def generate_module_content(self, module: CourseModule) -> List[Section]:
178
+ # Generates content for a module asynchronously
179
+ try:
180
+ section = Section(
181
+ title=f"Introduction to {module.title}",
182
+ content=f"Basic concepts of {module.title}",
183
+ key_points=["Key concept 1", "Key concept 2"],
184
+ quiz_questions=[{
185
+ "question": f"What is {module.title}?",
186
+ "options": ["A", "B", "C", "D"],
187
+ "correct_answer": "A",
188
+ "explanation": "Basic explanation"
189
+ }]
190
+ )
191
+ return [section]
192
+ except Exception as e:
193
+ # Log any errors that occur during content generation
194
+ print(f"Error generating content: {e}")
195
+ return []
196
+
197
+ def check_quality(self, state: CourseState) -> Literal["edit", "complete"]:
198
+ # Checks the quality of the generated content to determine if it needs editing or is complete
199
+ messages = state["messages"]
200
+ last_message = messages[-1]
201
+
202
+ if len(last_message.content) > 1000 and "code example" in last_message.content.lower():
203
+ return "complete"
204
+ return "edit"
205
+
206
+ def setup_graph(self):
207
+ # Sets up the workflow graph for generating the course
208
+ workflow = StateGraph(CourseState)
209
+
210
+ # Adds nodes and edges to the graph to define the workflow
211
+ workflow.add_node("planner", self.course_planner)
212
+ workflow.add_edge(START, "planner")
213
+ workflow.add_edge("planner", END)
214
+
215
+ # Compiles the graph to create a runnable workflow
216
+ self.graph = workflow.compile()
217
+
218
  class LearningPlatform:
219
+ def __init__(self, api_key: str = None):
220
+ # Initializes the learning platform with API key and sets up course builder, agents, and content generator
221
+ self.api_key = api_key or os.getenv("OPENAI_API_KEY")
222
+ self.course_builder = CourseBuilder(self.api_key)
223
+ self.agents = Agents(self.api_key)
224
+ self.content_generator = ContentGenerator(self.api_key)
225
+
226
+ async def create_course(self, topic: str, difficulty: str) -> LearningPath:
227
+ try:
228
+ # Initial state for creating the course
229
+ initial_state = {
230
+ "messages": [HumanMessage(content=f"Create a course on {topic} at {difficulty} level")],
231
+ "current_topic": topic,
232
+ "difficulty": difficulty,
233
+ "modules": [],
234
+ "status": "planning"
235
+ }
236
+
237
+ # Create initial module directly
238
+ module = CourseModule(
239
+ title=topic,
240
+ objectives=["Introduction to " + topic],
241
+ prerequisites=[]
242
+ )
243
+ # Generate content for the module asynchronously
244
+ module.sections = await self.course_builder.generate_module_content(module)
245
+ module.is_complete = True
246
+
247
+ # Return the learning path with the generated module
248
+ return LearningPath(
249
+ topic=topic,
250
+ description=f"A {difficulty} level course on {topic}",
251
+ modules=[module],
252
+ created_at=datetime.now(),
253
+ difficulty_level=difficulty,
254
+ is_generating=False
255
+ )
256
+
257
+ except Exception as e:
258
+ raise Exception(f"Course creation error: {str(e)}")
259
+
260
  async def generate_next_module(self, path: LearningPath, module_index: int):
261
  """Generate content for the next module asynchronously"""
262
  if module_index < len(path.modules):
 
269
  section.content,
270
  {"module": module.title, "section": section.title}
271
  )
272
+