add country authority
Browse files- lesson_graph.py +43 -63
lesson_graph.py
CHANGED
@@ -17,6 +17,8 @@ class NodeType(Enum):
|
|
17 |
ASSESSMENT = "Assessment"
|
18 |
RESOURCE = "Resource"
|
19 |
SCHOOL_BOARD = "School Board"
|
|
|
|
|
20 |
|
21 |
class ResetState(NamedTuple):
|
22 |
teacher_name: str
|
@@ -27,6 +29,7 @@ class ResetState(NamedTuple):
|
|
27 |
assessment: str
|
28 |
resource: str
|
29 |
school_board: str
|
|
|
30 |
message: str
|
31 |
|
32 |
class LessonGraph:
|
@@ -38,7 +41,8 @@ class LessonGraph:
|
|
38 |
"activity": "",
|
39 |
"assessment": "",
|
40 |
"resource": "",
|
41 |
-
"school_board": ""
|
|
|
42 |
}
|
43 |
|
44 |
REQUIRED_FIELDS = ["teacher_name", "subject", "grade_level"]
|
@@ -51,7 +55,8 @@ class LessonGraph:
|
|
51 |
NodeType.ACTIVITY: "#FF99FF",
|
52 |
NodeType.ASSESSMENT: "#FFFF99",
|
53 |
NodeType.RESOURCE: "#99FFFF",
|
54 |
-
NodeType.SCHOOL_BOARD: "#CCCCCC"
|
|
|
55 |
}
|
56 |
|
57 |
def __init__(self):
|
@@ -72,20 +77,25 @@ class LessonGraph:
|
|
72 |
Add nodes and edges to the lesson plan graph for the given inputs.
|
73 |
Returns a search string and the graph image.
|
74 |
"""
|
75 |
-
self.graph.clear()
|
76 |
self.inputs.update(kwargs)
|
77 |
-
|
78 |
-
# Validate only required fields
|
79 |
self.validate_required_fields()
|
80 |
-
|
81 |
-
# Define
|
82 |
nodes = {
|
83 |
self.inputs["teacher_name"]: {"type": NodeType.USER, "role": "Teacher"},
|
84 |
self.inputs["subject"]: {"type": NodeType.SUBJECT, "description": "Core subject area"},
|
85 |
self.inputs["grade_level"]: {"type": NodeType.GRADE_LEVEL, "description": "Target grade for the lesson"},
|
86 |
}
|
87 |
-
|
88 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
89 |
optional_nodes = {
|
90 |
"learning_objective": NodeType.LEARNING_OBJECTIVE,
|
91 |
"activity": NodeType.ACTIVITY,
|
@@ -93,88 +103,58 @@ class LessonGraph:
|
|
93 |
"resource": NodeType.RESOURCE,
|
94 |
"school_board": NodeType.SCHOOL_BOARD
|
95 |
}
|
96 |
-
|
97 |
for field, node_type in optional_nodes.items():
|
98 |
if self.inputs.get(field):
|
99 |
nodes[self.inputs[field]] = {"type": node_type, "description": f"{node_type.value}"}
|
100 |
-
|
101 |
# Add nodes to the graph
|
102 |
for node, attributes in nodes.items():
|
103 |
self.graph.add_node(node, **attributes)
|
104 |
-
|
105 |
-
# Define
|
106 |
edges = [
|
107 |
(self.inputs["teacher_name"], self.inputs["subject"], {"relationship": "TEACHES"}),
|
108 |
(self.inputs["subject"], self.inputs["grade_level"], {"relationship": "HAS_GRADE"})
|
109 |
]
|
110 |
-
|
111 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
112 |
if self.inputs.get("learning_objective"):
|
113 |
-
edges.
|
114 |
-
|
115 |
-
(self.inputs["learning_objective"], self.inputs["school_board"], {"relationship": "ALIGNS_WITH"})
|
116 |
-
|
117 |
-
|
118 |
if self.inputs.get("activity") and self.inputs.get("learning_objective"):
|
119 |
edges.append((self.inputs["activity"], self.inputs["learning_objective"], {"relationship": "ACHIEVES"}))
|
120 |
-
|
121 |
if self.inputs.get("activity") and self.inputs.get("resource"):
|
122 |
edges.append((self.inputs["activity"], self.inputs["resource"], {"relationship": "REQUIRES"}))
|
123 |
-
|
124 |
if self.inputs.get("learning_objective") and self.inputs.get("assessment"):
|
125 |
edges.append((self.inputs["learning_objective"], self.inputs["assessment"], {"relationship": "EVALUATED_BY"}))
|
126 |
-
|
127 |
if self.inputs.get("school_board"):
|
128 |
edges.append((self.inputs["teacher_name"], self.inputs["school_board"], {"relationship": "BELONGS_TO"}))
|
129 |
-
|
130 |
# Remove None entries from edges list
|
131 |
edges = [edge for edge in edges if edge is not None]
|
132 |
self.graph.add_edges_from(edges)
|
133 |
-
|
134 |
# Generate the search string for content discovery
|
135 |
search_string = f"{self.inputs['subject']} {self.inputs['grade_level']} {self.inputs.get('learning_objective', '')} {self.inputs.get('activity', '')} {self.inputs.get('resource', '')}".strip()
|
136 |
-
|
137 |
# Get the graph image
|
138 |
image = self.draw_graph()
|
139 |
-
|
140 |
-
# Return the search string and the graph image
|
141 |
return search_string, image
|
142 |
|
143 |
-
def draw_graph(self) -> Image.Image:
|
144 |
-
"""
|
145 |
-
Visualize the graph using Matplotlib, handling layout, labels, and interactivity.
|
146 |
-
"""
|
147 |
-
fig, ax = plt.subplots(figsize=(14, 10))
|
148 |
-
pos = nx.spring_layout(self.graph, k=0.9, iterations=50)
|
149 |
-
|
150 |
-
self._draw_nodes(ax, pos)
|
151 |
-
self._draw_edges(ax, pos)
|
152 |
-
self._add_legend(ax)
|
153 |
-
|
154 |
-
plt.title("Your Educational Landscape", fontsize=16)
|
155 |
-
plt.axis('off')
|
156 |
-
plt.tight_layout()
|
157 |
-
|
158 |
-
self._add_interactivity()
|
159 |
-
|
160 |
-
# Save the plot to a BytesIO object
|
161 |
-
buf = BytesIO()
|
162 |
-
plt.savefig(buf, format="png", dpi=300, bbox_inches="tight")
|
163 |
-
buf.seek(0)
|
164 |
-
plt.close(fig)
|
165 |
-
|
166 |
-
return Image.open(buf)
|
167 |
-
|
168 |
-
def _draw_nodes(self, ax, pos):
|
169 |
-
node_colors = [self.COLOR_MAP[self.graph.nodes[node]['type']] for node in self.graph.nodes()]
|
170 |
-
nx.draw_networkx_nodes(self.graph, pos, node_color=node_colors, node_size=3000, alpha=0.8, ax=ax)
|
171 |
-
nx.draw_networkx_labels(self.graph, pos, font_size=10, font_weight="bold", ax=ax)
|
172 |
-
|
173 |
-
def _draw_edges(self, ax, pos):
|
174 |
-
nx.draw_networkx_edges(self.graph, pos, edge_color='gray', arrows=True, arrowsize=20, ax=ax)
|
175 |
-
edge_labels = nx.get_edge_attributes(self.graph, 'relationship')
|
176 |
-
nx.draw_networkx_edge_labels(self.graph, pos, edge_labels=edge_labels, font_size=8, ax=ax)
|
177 |
-
|
178 |
def _add_legend(self, ax):
|
179 |
legend_elements = [mpatches.Patch(color=color, label=node_type.value) for node_type, color in self.COLOR_MAP.items()]
|
180 |
ax.legend(handles=legend_elements, loc='upper left', bbox_to_anchor=(1, 1), title="Node Types")
|
|
|
17 |
ASSESSMENT = "Assessment"
|
18 |
RESOURCE = "Resource"
|
19 |
SCHOOL_BOARD = "School Board"
|
20 |
+
COUNTRY_AUTHORITY = "Country Authority" # New NodeType
|
21 |
+
|
22 |
|
23 |
class ResetState(NamedTuple):
|
24 |
teacher_name: str
|
|
|
29 |
assessment: str
|
30 |
resource: str
|
31 |
school_board: str
|
32 |
+
country_authority: str # New field
|
33 |
message: str
|
34 |
|
35 |
class LessonGraph:
|
|
|
41 |
"activity": "",
|
42 |
"assessment": "",
|
43 |
"resource": "",
|
44 |
+
"school_board": "",
|
45 |
+
"country_authority": "" # New field
|
46 |
}
|
47 |
|
48 |
REQUIRED_FIELDS = ["teacher_name", "subject", "grade_level"]
|
|
|
55 |
NodeType.ACTIVITY: "#FF99FF",
|
56 |
NodeType.ASSESSMENT: "#FFFF99",
|
57 |
NodeType.RESOURCE: "#99FFFF",
|
58 |
+
NodeType.SCHOOL_BOARD: "#CCCCCC",
|
59 |
+
NodeType.COUNTRY_AUTHORITY: "#FFA07A" # New color for Country Authority
|
60 |
}
|
61 |
|
62 |
def __init__(self):
|
|
|
77 |
Add nodes and edges to the lesson plan graph for the given inputs.
|
78 |
Returns a search string and the graph image.
|
79 |
"""
|
80 |
+
self.graph.clear()
|
81 |
self.inputs.update(kwargs)
|
|
|
|
|
82 |
self.validate_required_fields()
|
83 |
+
|
84 |
+
# Define required nodes
|
85 |
nodes = {
|
86 |
self.inputs["teacher_name"]: {"type": NodeType.USER, "role": "Teacher"},
|
87 |
self.inputs["subject"]: {"type": NodeType.SUBJECT, "description": "Core subject area"},
|
88 |
self.inputs["grade_level"]: {"type": NodeType.GRADE_LEVEL, "description": "Target grade for the lesson"},
|
89 |
}
|
90 |
+
|
91 |
+
# Include country authority if provided
|
92 |
+
if self.inputs.get("country_authority"):
|
93 |
+
nodes[self.inputs["country_authority"]] = {
|
94 |
+
"type": NodeType.COUNTRY_AUTHORITY,
|
95 |
+
"description": "Sets national curriculum standards"
|
96 |
+
}
|
97 |
+
|
98 |
+
# Optional nodes
|
99 |
optional_nodes = {
|
100 |
"learning_objective": NodeType.LEARNING_OBJECTIVE,
|
101 |
"activity": NodeType.ACTIVITY,
|
|
|
103 |
"resource": NodeType.RESOURCE,
|
104 |
"school_board": NodeType.SCHOOL_BOARD
|
105 |
}
|
106 |
+
|
107 |
for field, node_type in optional_nodes.items():
|
108 |
if self.inputs.get(field):
|
109 |
nodes[self.inputs[field]] = {"type": node_type, "description": f"{node_type.value}"}
|
110 |
+
|
111 |
# Add nodes to the graph
|
112 |
for node, attributes in nodes.items():
|
113 |
self.graph.add_node(node, **attributes)
|
114 |
+
|
115 |
+
# Define relationships between nodes
|
116 |
edges = [
|
117 |
(self.inputs["teacher_name"], self.inputs["subject"], {"relationship": "TEACHES"}),
|
118 |
(self.inputs["subject"], self.inputs["grade_level"], {"relationship": "HAS_GRADE"})
|
119 |
]
|
120 |
+
|
121 |
+
# Relationships involving country authority
|
122 |
+
if self.inputs.get("country_authority"):
|
123 |
+
if self.inputs.get("learning_objective"):
|
124 |
+
edges.append((self.inputs["country_authority"], self.inputs["learning_objective"], {"relationship": "DEFINES"}))
|
125 |
+
if self.inputs.get("school_board"):
|
126 |
+
edges.append((self.inputs["country_authority"], self.inputs["school_board"], {"relationship": "OVERSEES"}))
|
127 |
+
|
128 |
+
# Existing optional edges
|
129 |
if self.inputs.get("learning_objective"):
|
130 |
+
edges.append((self.inputs["subject"], self.inputs["learning_objective"], {"relationship": "COVERS"}))
|
131 |
+
if self.inputs.get("school_board"):
|
132 |
+
edges.append((self.inputs["learning_objective"], self.inputs["school_board"], {"relationship": "ALIGNS_WITH"}))
|
133 |
+
|
|
|
134 |
if self.inputs.get("activity") and self.inputs.get("learning_objective"):
|
135 |
edges.append((self.inputs["activity"], self.inputs["learning_objective"], {"relationship": "ACHIEVES"}))
|
136 |
+
|
137 |
if self.inputs.get("activity") and self.inputs.get("resource"):
|
138 |
edges.append((self.inputs["activity"], self.inputs["resource"], {"relationship": "REQUIRES"}))
|
139 |
+
|
140 |
if self.inputs.get("learning_objective") and self.inputs.get("assessment"):
|
141 |
edges.append((self.inputs["learning_objective"], self.inputs["assessment"], {"relationship": "EVALUATED_BY"}))
|
142 |
+
|
143 |
if self.inputs.get("school_board"):
|
144 |
edges.append((self.inputs["teacher_name"], self.inputs["school_board"], {"relationship": "BELONGS_TO"}))
|
145 |
+
|
146 |
# Remove None entries from edges list
|
147 |
edges = [edge for edge in edges if edge is not None]
|
148 |
self.graph.add_edges_from(edges)
|
149 |
+
|
150 |
# Generate the search string for content discovery
|
151 |
search_string = f"{self.inputs['subject']} {self.inputs['grade_level']} {self.inputs.get('learning_objective', '')} {self.inputs.get('activity', '')} {self.inputs.get('resource', '')}".strip()
|
152 |
+
|
153 |
# Get the graph image
|
154 |
image = self.draw_graph()
|
155 |
+
|
|
|
156 |
return search_string, image
|
157 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
158 |
def _add_legend(self, ax):
|
159 |
legend_elements = [mpatches.Patch(color=color, label=node_type.value) for node_type, color in self.COLOR_MAP.items()]
|
160 |
ax.legend(handles=legend_elements, loc='upper left', bbox_to_anchor=(1, 1), title="Node Types")
|