Spaces:
Running
Running
github-actions[bot] commited on
Commit ยท
f524bd9
1
Parent(s): 1959397
๐ Auto-deploy backend from GitHub (af4a835)
Browse files
main.py
CHANGED
|
@@ -86,6 +86,7 @@ from rag.curriculum_rag import (
|
|
| 86 |
build_analysis_curriculum_context,
|
| 87 |
build_lesson_prompt,
|
| 88 |
build_lesson_query,
|
|
|
|
| 89 |
retrieve_curriculum_context,
|
| 90 |
summarize_retrieval_confidence,
|
| 91 |
)
|
|
@@ -366,6 +367,7 @@ ROLE_POLICIES: Dict[str, Set[str]] = {
|
|
| 366 |
"/api/admin/model-config/override": ADMIN_ONLY,
|
| 367 |
"/api/admin/model-config/reset": ADMIN_ONLY,
|
| 368 |
"/api/lessons/videos/search": ALL_APP_ROLES,
|
|
|
|
| 369 |
"/api/quiz-battle/generate": ALL_APP_ROLES,
|
| 370 |
"/api/quiz-battle/ingest-pdf": TEACHER_OR_ADMIN,
|
| 371 |
"/api/quiz-battle/bank-status": TEACHER_OR_ADMIN,
|
|
@@ -13160,6 +13162,124 @@ async def generate_learning_path(request: DiagnosticLearningPathRequest):
|
|
| 13160 |
raise HTTPException(status_code=500, detail=f"Learning path error: {str(e)}")
|
| 13161 |
|
| 13162 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 13163 |
# โโโ Main โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 13164 |
|
| 13165 |
if __name__ == "__main__":
|
|
|
|
| 86 |
build_analysis_curriculum_context,
|
| 87 |
build_lesson_prompt,
|
| 88 |
build_lesson_query,
|
| 89 |
+
format_retrieved_chunks,
|
| 90 |
retrieve_curriculum_context,
|
| 91 |
summarize_retrieval_confidence,
|
| 92 |
)
|
|
|
|
| 367 |
"/api/admin/model-config/override": ADMIN_ONLY,
|
| 368 |
"/api/admin/model-config/reset": ADMIN_ONLY,
|
| 369 |
"/api/lessons/videos/search": ALL_APP_ROLES,
|
| 370 |
+
"/api/lesson/personalized": ALL_APP_ROLES,
|
| 371 |
"/api/quiz-battle/generate": ALL_APP_ROLES,
|
| 372 |
"/api/quiz-battle/ingest-pdf": TEACHER_OR_ADMIN,
|
| 373 |
"/api/quiz-battle/bank-status": TEACHER_OR_ADMIN,
|
|
|
|
| 13162 |
raise HTTPException(status_code=500, detail=f"Learning path error: {str(e)}")
|
| 13163 |
|
| 13164 |
|
| 13165 |
+
# โโโ Personalized Lesson Endpoint โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 13166 |
+
|
| 13167 |
+
class PersonalizedLessonRequest(BaseModel):
|
| 13168 |
+
topic: str = Field(..., description="Lesson topic")
|
| 13169 |
+
student_uid: str = Field(..., description="Student UID for profile lookup")
|
| 13170 |
+
assessment_context: Optional[Dict[str, Any]] = Field(None, description="Optional assessment context")
|
| 13171 |
+
subject: Optional[str] = Field(None, description="Subject area")
|
| 13172 |
+
quarter: Optional[int] = Field(None, description="Quarter (1-4)")
|
| 13173 |
+
|
| 13174 |
+
|
| 13175 |
+
class PersonalizedLessonResponse(BaseModel):
|
| 13176 |
+
topic: str
|
| 13177 |
+
content: str
|
| 13178 |
+
personalization_notes: str
|
| 13179 |
+
sections: List[Dict[str, str]]
|
| 13180 |
+
suggested_exercises: List[str]
|
| 13181 |
+
difficulty_adjustment: str
|
| 13182 |
+
|
| 13183 |
+
|
| 13184 |
+
@app.post("/api/lesson/personalized", response_model=PersonalizedLessonResponse)
|
| 13185 |
+
async def generate_personalized_lesson(request: PersonalizedLessonRequest):
|
| 13186 |
+
"""
|
| 13187 |
+
Generate a personalized lesson based on student's assessment profile.
|
| 13188 |
+
Adapts content to address weaknesses and reinforce strengths.
|
| 13189 |
+
"""
|
| 13190 |
+
try:
|
| 13191 |
+
# Load student's competency profile if available
|
| 13192 |
+
weaknesses = []
|
| 13193 |
+
strengths = []
|
| 13194 |
+
if firebase_firestore and request.student_uid:
|
| 13195 |
+
try:
|
| 13196 |
+
db = firebase_firestore.client()
|
| 13197 |
+
profile_doc = db.collection("competencyProfiles").document(request.student_uid).get()
|
| 13198 |
+
if profile_doc.exists:
|
| 13199 |
+
profile_data = profile_doc.to_dict()
|
| 13200 |
+
if profile_data and "competencies" in profile_data:
|
| 13201 |
+
for comp_id, comp_data in profile_data["competencies"].items():
|
| 13202 |
+
if comp_data.get("score", 0) < 50:
|
| 13203 |
+
weaknesses.append(comp_id)
|
| 13204 |
+
elif comp_data.get("score", 0) >= 80:
|
| 13205 |
+
strengths.append(comp_id)
|
| 13206 |
+
except Exception as e:
|
| 13207 |
+
logger.warning(f"Could not load competency profile: {e}")
|
| 13208 |
+
|
| 13209 |
+
# Retrieve curriculum context
|
| 13210 |
+
context_chunks = retrieve_curriculum_context(
|
| 13211 |
+
query=build_lesson_query(request.topic, request.subject or "General Mathematics", request.quarter or 1),
|
| 13212 |
+
subject=request.subject,
|
| 13213 |
+
quarter=request.quarter,
|
| 13214 |
+
top_k=5,
|
| 13215 |
+
)
|
| 13216 |
+
context_text = format_retrieved_chunks(context_chunks)
|
| 13217 |
+
|
| 13218 |
+
# Build personalized prompt
|
| 13219 |
+
prompt = f"""Generate a DepEd-aligned SHS mathematics lesson on: {request.topic}
|
| 13220 |
+
|
| 13221 |
+
Student Assessment Profile:
|
| 13222 |
+
- Weaknesses to address: {', '.join(weaknesses) if weaknesses else 'None identified'}
|
| 13223 |
+
- Strengths to reinforce: {', '.join(strengths) if strengths else 'None identified'}
|
| 13224 |
+
|
| 13225 |
+
Curriculum Context:
|
| 13226 |
+
{context_text}
|
| 13227 |
+
|
| 13228 |
+
Instructions:
|
| 13229 |
+
1. Structure the lesson with: Introduction, Key Concepts, Examples, Practice Problems, Summary
|
| 13230 |
+
2. Include extra practice on these weak areas: {', '.join(weaknesses) if weaknesses else 'general topic areas'}
|
| 13231 |
+
3. Provide advanced challenges on these strong areas: {', '.join(strengths) if strengths else 'related advanced topics'}
|
| 13232 |
+
4. Use Filipino Senior High School appropriate language and context
|
| 13233 |
+
5. Reference specific DepEd MELC competencies where applicable
|
| 13234 |
+
|
| 13235 |
+
Return as JSON with fields: topic, sections (array of title/content), suggested_exercises, personalization_notes"""
|
| 13236 |
+
|
| 13237 |
+
req = InferenceRequest(
|
| 13238 |
+
messages=[
|
| 13239 |
+
{"role": "system", "content": "You are a precise DepEd-aligned curriculum assistant."},
|
| 13240 |
+
{"role": "user", "content": prompt},
|
| 13241 |
+
],
|
| 13242 |
+
task_type="rag_lesson",
|
| 13243 |
+
max_new_tokens=1800,
|
| 13244 |
+
temperature=0.2,
|
| 13245 |
+
top_p=0.9,
|
| 13246 |
+
enable_thinking=True,
|
| 13247 |
+
)
|
| 13248 |
+
response_text = get_inference_client().generate_from_messages(req)
|
| 13249 |
+
|
| 13250 |
+
# Parse JSON response
|
| 13251 |
+
try:
|
| 13252 |
+
# Extract JSON from response
|
| 13253 |
+
json_match = re.search(r'\{.*\}', response_text, re.DOTALL)
|
| 13254 |
+
if json_match:
|
| 13255 |
+
lesson_data = json.loads(json_match.group())
|
| 13256 |
+
else:
|
| 13257 |
+
lesson_data = json.loads(response_text)
|
| 13258 |
+
|
| 13259 |
+
return PersonalizedLessonResponse(
|
| 13260 |
+
topic=request.topic,
|
| 13261 |
+
content=lesson_data.get("content", response_text),
|
| 13262 |
+
personalization_notes=f"Personalized for weaknesses: {', '.join(weaknesses)}" if weaknesses else "General lesson",
|
| 13263 |
+
sections=lesson_data.get("sections", []),
|
| 13264 |
+
suggested_exercises=lesson_data.get("suggested_exercises", []),
|
| 13265 |
+
difficulty_adjustment="supportive" if weaknesses else "standard",
|
| 13266 |
+
)
|
| 13267 |
+
except json.JSONDecodeError:
|
| 13268 |
+
# Return raw text if JSON parsing fails
|
| 13269 |
+
return PersonalizedLessonResponse(
|
| 13270 |
+
topic=request.topic,
|
| 13271 |
+
content=response_text,
|
| 13272 |
+
personalization_notes="Raw response (JSON parsing failed)",
|
| 13273 |
+
sections=[{"title": "Content", "content": response_text}],
|
| 13274 |
+
suggested_exercises=[],
|
| 13275 |
+
difficulty_adjustment="standard",
|
| 13276 |
+
)
|
| 13277 |
+
|
| 13278 |
+
except Exception as e:
|
| 13279 |
+
logger.error(f"Personalized lesson generation error: {e}")
|
| 13280 |
+
raise HTTPException(status_code=500, detail=f"Lesson generation error: {str(e)}")
|
| 13281 |
+
|
| 13282 |
+
|
| 13283 |
# โโโ Main โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 13284 |
|
| 13285 |
if __name__ == "__main__":
|