Spaces:
Sleeping
Sleeping
| import os | |
| import json | |
| from openai import OpenAI | |
| from typing import Dict, List, Any, Optional | |
| from dotenv import load_dotenv | |
| class LLMHandler: | |
| def __init__(self): | |
| """Initialize the LLM handler with OpenAI client.""" | |
| load_dotenv() | |
| self.client = OpenAI(api_key=os.getenv('OPENAI_API_KEY')) | |
| self.model = "gpt-4o-mini" | |
| def input_extraction_validation(self, user_prompt: str) -> Dict[str, Any]: | |
| """ | |
| Extract and validate key information from user prompt. | |
| Returns a dictionary with extracted information and duration adequacy assessment. | |
| """ | |
| system_prompt = """ | |
| You are an expert in language education, specializing in extracting key information from lesson requests. | |
| Your task is to identify and validate crucial parameters for language lesson planning. | |
| """ | |
| user_message = f""" | |
| Extract key information from the following request for a lesson plan: | |
| User Request: {user_prompt} | |
| Extract the following information: | |
| - topic: The main subject of the lesson | |
| - age_group: Target age group (e.g., Elementary (6-11), High School (14-18), Adult) | |
| - proficiency_level: Language proficiency according to CEFR (e.g., A1, A2, B1, B2, C1, C2) | |
| - lesson_duration: Length of the lesson in minutes | |
| - tech_requirements: Any technology needed for the lesson | |
| - output_language: Language in which materials should be produced | |
| - number_of_students: Number of students in the class | |
| - skills_to_focus: Skills to emphasize (e.g., reading, writing, listening, speaking) | |
| Then, evaluate whether the provided duration is sufficient for a structured lesson plan (PPP, ESA, TTT, TBL, or UbD) based on: | |
| - The complexity of the topic | |
| - The proficiency level of the learners | |
| If duration is insufficient: set "duration_adequacy" to "Not sufficient for structured lesson plan" | |
| If duration is sufficient: set "duration_adequacy" to "Sufficient for structured lesson plan" | |
| Return ONLY a JSON object with these fields. No explanations or other text. | |
| """ | |
| try: | |
| response = self.client.chat.completions.create( | |
| model=self.model, | |
| messages=[ | |
| {"role": "system", "content": system_prompt}, | |
| {"role": "user", "content": user_message} | |
| ], | |
| response_format={"type": "json_object"} | |
| ) | |
| # Try to parse the response as JSON | |
| extracted_info = json.loads(response.choices[0].message.content) | |
| # Validate essential fields and set defaults if missing | |
| if not extracted_info.get("topic"): | |
| extracted_info["topic"] = "No context provided" | |
| if not extracted_info.get("lesson_duration"): | |
| extracted_info["lesson_duration"] = "30 minutes" | |
| if not extracted_info.get("proficiency_level"): | |
| extracted_info["proficiency_level"] = "Intermediate [B1, B2]" | |
| if not extracted_info.get("age_group"): | |
| extracted_info["age_group"] = "Elementary (6-11)" | |
| if not extracted_info.get("tech_requirements"): | |
| extracted_info["tech_requirements"] = ["White Board", "Internet Access"] | |
| if not extracted_info.get("output_language"): | |
| extracted_info["output_language"] = "English" | |
| if not extracted_info.get("number_of_students"): | |
| extracted_info["number_of_students"] = "No context provided" | |
| if not extracted_info.get("skills_to_focus"): | |
| extracted_info["skills_to_focus"] = "No context provided" | |
| if not extracted_info.get("duration_adequacy"): | |
| # Fallback if model doesn't assess duration | |
| extracted_info["duration_adequacy"] = "Sufficient for structured lesson plan" | |
| return extracted_info | |
| except Exception as e: | |
| print(f"Error in input_extraction_validation: {str(e)}") | |
| # Return default values | |
| return { | |
| "topic": "General language practice", | |
| "age_group": "Elementary (6-11)", | |
| "proficiency_level": "Intermediate [B1, B2]", | |
| "lesson_duration": "30 minutes", | |
| "tech_requirements": ["White Board", "Internet Access"], | |
| "output_language": "English", | |
| "number_of_students": "No context provided", | |
| "skills_to_focus": "No context provided", | |
| "duration_adequacy": "Sufficient for structured lesson plan" | |
| } | |
| def lesson_plan_structure(self, input_data: Dict[str, Any]) -> Dict[str, str]: | |
| """ | |
| Determine the appropriate lesson plan structure based on the extracted information. | |
| Returns a dictionary with the selected structure and description. | |
| """ | |
| system_prompt = """ | |
| You are an expert educator specializing in language lesson planning frameworks. | |
| Your task is to select the most appropriate lesson structure based on given parameters. | |
| """ | |
| user_message = f""" | |
| Based on the following information about a language lesson, determine the most appropriate lesson plan structure: | |
| Topic: {input_data.get('topic', 'No context provided')} | |
| Age Group: {input_data.get('age_group', 'No context provided')} | |
| Proficiency Level: {input_data.get('proficiency_level', 'No context provided')} | |
| Lesson Duration: {input_data.get('lesson_duration', 'No context provided')} | |
| Duration Adequacy: {input_data.get('duration_adequacy', 'No context provided')} | |
| Skills to Focus: {input_data.get('skills_to_focus', 'No context provided')} | |
| If Duration Adequacy is "Not sufficient for structured lesson plan": | |
| - Set output_structure to "Generic" | |
| - Set description to "The given duration is not sufficient to create a fully structured lesson plan. Instead, a simplified activity plan has been provided." | |
| Otherwise, select the most appropriate structure from: | |
| - PPP (Presentation, Practice, Production) - For young learners, basic comprehension, structured activities | |
| - ESA (Engage, Study, Activate) - For young learners needing flexibility (consider Boomerang ESA or Patchwork ESA variants) | |
| - TBL (Task-Based Learning) - For high school, advanced learners, or adults focusing on real-world applications | |
| - TTT (Test, Teach, Test) - For learners with prior knowledge to assess gaps, instruct, and reassess | |
| - UbD (Understanding by Design) - For long-term, curriculum-based instruction | |
| Return your response as a JSON object with these two fields: | |
| - output_structure: The selected structure (PPP, ESA, TBL, TTT, UbD, or Generic) | |
| - description: A brief explanation of why this framework structure was chosen | |
| """ | |
| try: | |
| response = self.client.chat.completions.create( | |
| model=self.model, | |
| messages=[ | |
| {"role": "system", "content": system_prompt}, | |
| {"role": "user", "content": user_message} | |
| ], | |
| response_format={"type": "json_object"} | |
| ) | |
| structure_info = json.loads(response.choices[0].message.content) | |
| # Validate required fields | |
| if not structure_info.get("output_structure"): | |
| structure_info["output_structure"] = "Generic" | |
| if not structure_info.get("description"): | |
| structure_info[ | |
| "description"] = "A simplified lesson plan structure was selected based on the available information." | |
| return structure_info | |
| except Exception as e: | |
| print(f"Error in lesson_plan_structure: {str(e)}") | |
| # Fallback if the response is not valid JSON | |
| return { | |
| "output_structure": "Generic", | |
| "description": "A simplified lesson plan structure was selected as a fallback." | |
| } | |
| def activity_template_selection(self, input_data: Dict[str, Any], structure_info: Dict[str, str]) -> Dict[ | |
| str, List[str]]: | |
| """ | |
| Select appropriate activity/worksheet templates based on lesson structure, topic, and duration. | |
| Returns a dictionary with a list of selected activity templates. | |
| """ | |
| system_prompt = """ | |
| You are an expert language instructor specializing in selecting appropriate activities for lessons. | |
| Your task is to choose the most suitable activity templates based on lesson parameters. | |
| """ | |
| user_message = f""" | |
| Select the top 5 most suitable worksheet and activity templates for a language lesson with the following characteristics: | |
| Lesson Structure: {structure_info.get('output_structure', 'Generic')} | |
| Topic: {input_data.get('topic', 'No context provided')} | |
| Duration: {input_data.get('lesson_duration', '30 minutes')} | |
| Age Group: {input_data.get('age_group', 'Elementary (6-11)')} | |
| Proficiency Level: {input_data.get('proficiency_level', 'Intermediate [B1, B2]')} | |
| Skills to Focus: {input_data.get('skills_to_focus', 'No context provided')} | |
| Choose ONLY from these activity templates: | |
| 1. Fill in the blank | |
| 2. Picture/Visual | |
| 3. Sentence Formation | |
| 4. Finding | |
| 5. Matching | |
| 6. Short Response | |
| 7. Long Response | |
| 8. Correction | |
| 9. Audio as material [suitable for activities to focus on listening tasks] | |
| Selection Guidelines: | |
| Prioritize activities that match the Skills to Focus, proficiency level, lesson structure, topic. | |
| For beginner learners (A1, A2), emphasize simple activities like Matching, Picture/Visual, and Fill in the Blank. | |
| For intermediate/advanced learners (B1, B2), incorporate Finding, Short Response, and Long Response. | |
| Ensure a balance of engagement and difficulty. | |
| Return your selection as a JSON object with this field: | |
| - activity_templates: An array containing 5 selected activity templates from the list above | |
| """ | |
| try: | |
| response = self.client.chat.completions.create( | |
| model=self.model, | |
| messages=[ | |
| {"role": "system", "content": system_prompt}, | |
| {"role": "user", "content": user_message} | |
| ], | |
| response_format={"type": "json_object"} | |
| ) | |
| templates_info = json.loads(response.choices[0].message.content) | |
| # Validate the response contains activity_templates | |
| if not templates_info.get("activity_templates"): | |
| templates_info["activity_templates"] = [ | |
| "Fill in the blank", | |
| "Picture/Visual", | |
| "Matching", | |
| "Short Response", | |
| "Correction" | |
| ] | |
| # Ensure we have exactly 5 templates | |
| if len(templates_info["activity_templates"]) < 5: | |
| # Add default templates to reach 5 | |
| default_templates = [ | |
| "Fill in the blank", | |
| "Picture/Visual", | |
| "Matching", | |
| "Short Response", | |
| "Correction" | |
| ] | |
| for template in default_templates: | |
| if template not in templates_info["activity_templates"] and len( | |
| templates_info["activity_templates"]) < 5: | |
| templates_info["activity_templates"].append(template) | |
| if len(templates_info["activity_templates"]) > 5: | |
| templates_info["activity_templates"] = templates_info["activity_templates"][:5] | |
| return templates_info | |
| except Exception as e: | |
| print(f"Error in activity_template_selection: {str(e)}") | |
| # Fallback if the response is not valid JSON | |
| return { | |
| "activity_templates": [ | |
| "Fill in the blank", | |
| "Picture/Visual", | |
| "Matching", | |
| "Short Response", | |
| "Correction" | |
| ] | |
| } | |
| def lesson_plan_generation( | |
| self, | |
| input_data: Dict[str, Any], | |
| structure_info: Dict[str, str], | |
| activity_info: Dict[str, List[str]] | |
| ) -> Dict[str, Any]: | |
| """ | |
| Generate a complete lesson plan based on all previous inputs. | |
| Returns a structured JSON lesson plan. | |
| """ | |
| lesson_structure = structure_info.get("output_structure", "Generic") | |
| structure_description = structure_info.get("description", "") | |
| activity_templates = activity_info.get("activity_templates", []) | |
| system_prompt = """ | |
| You are an expert language instructor with extensive experience in creating detailed lesson plans. | |
| Your task is to generate a comprehensive, well-structured lesson plan based on provided parameters. | |
| These are the details about the activity templates we are considering: | |
| Fill in the Blanks: This activity assesses students’ ability to apply knowledge learned during the lesson. | |
| Example: Complete the sentences using the correct verb forms. | |
| Picture/Visual: This activity tests students' ability to interpret basic pictorial information, such as icons of fruits, animals, and everyday objects. | |
| Example: Identify and write the names of the fruits and vegetables shown in the images. | |
| Sentence Formation: This activity helps students practice sentence construction using minimal context. | |
| Example: Given the words "your brother, height," form a question: "How tall is your brother?" | |
| Finding: This activity strengthens vocabulary and comprehension by requiring students to identify words based on definitions or clues. | |
| Example: What is the term for a woman on her wedding day? Answer: Bride | |
| Matching: This activity reinforces the relationship between different concepts by having students pair related elements. | |
| Example: Match the illnesses in one column with their appropriate treatments in another. | |
| Short Response: This activity helps students practice forming concise answers to questions. | |
| Example: "Which do you prefer—tea or coffee?" Answer: I prefer coffee over tea. | |
| Long Response: This activity encourages students to construct detailed responses or dialogues. | |
| Example: Write a conversation between you and a friend who has just passed an exam. | |
| Correction: This activity develops students’ ability to identify and correct grammatical or structural errors in sentences. | |
| Example: Identify and correct the mistakes in the given sentences. | |
| Audio: This activity aids students to develop their listening skills. | |
| Example: Listen to the audio of customer speaking to a tech support agent and answer to the below questions. | |
| """ | |
| if lesson_structure == "Generic": | |
| user_message = f""" | |
| Generate a Basic Activity Plan for a language lesson with the following details: | |
| Topic: {input_data.get('topic', 'No context provided')} | |
| Age Group: {input_data.get('age_group', 'Elementary (6-11)')} | |
| Proficiency Level: {input_data.get('proficiency_level', 'Intermediate [B1, B2]')} | |
| Lesson Duration: {input_data.get('lesson_duration', '30 minutes')} | |
| Tech Requirements: {input_data.get('tech_requirements', ['White Board', 'Internet Access'])} | |
| Output Language: {input_data.get('output_language', 'English')} | |
| Number of Students: {input_data.get('number_of_students', 'No context provided')} | |
| Skills to Focus: {input_data.get('skills_to_focus', 'No context provided')} | |
| The plan should focus on selecting 2 or 3 meaningful activity due to time constraints. Include a note stating: | |
| "The given duration is not sufficient to create a fully structured lesson plan. Instead, a simplified activity plan has been provided." | |
| Include only activities that match these templates: {', '.join(activity_templates)}. | |
| You must include the following sections in your JSON response: | |
| - lesson_plan_title | |
| - structure (which should be "Generic") | |
| - structure_explanation (explanation that this is a simplified plan due to time constraints) | |
| - objectives | |
| - learning_outcomes | |
| - materials_and_resources (*Avoid external platforms like Kahoot, Quizlet*) | |
| - activity_plan (with timing, e.g., "Activity [X min]") and detail description explaining the activity and its objective. | |
| - assessment_strategy | |
| Provide your complete response in JSON format. | |
| """ | |
| else: | |
| user_message = f""" | |
| Generate a structured lesson plan using the {lesson_structure} framework for a language lesson with the following details: | |
| Topic: {input_data.get('topic', 'No context provided')} | |
| Age Group: {input_data.get('age_group', 'Elementary (6-11)')} | |
| Proficiency Level: {input_data.get('proficiency_level', 'Intermediate [B1, B2]')} | |
| Lesson Duration: {input_data.get('lesson_duration', '30 minutes')} | |
| Tech Requirements: {input_data.get('tech_requirements', ['White Board', 'Internet Access'])} | |
| Output Language: {input_data.get('output_language', 'English')} | |
| Number of Students: {input_data.get('number_of_students', 'No context provided')} | |
| Skills to Focus: {input_data.get('skills_to_focus', 'No context provided')} | |
| Framework Structure: {lesson_structure} | |
| Framework Explanation: {structure_description} | |
| Include only activities that match these templates: {', '.join(activity_templates)} | |
| You must include the following sections in your JSON response: | |
| - lesson_plan_title | |
| - structure (which should be "{lesson_structure}") | |
| - structure_explanation (brief explanation of why this framework was chosen) | |
| - objectives | |
| - learning_outcomes | |
| - essential_questions (if using UbD) | |
| - materials_and_resources (avoid external platforms like Kahoot, Quizlet) | |
| - lesson_plan_structure - with all appropriate sections for {lesson_structure} framework, each containing: | |
| * key_parts (with time allocations, e.g., "Engage [20 minutes]") | |
| * objective (purpose of this section) | |
| * activityies (with timing, e.g., "Activity [X min]") and detail description explaining the activity and its objective. | |
| - assessment_strategies | |
| - additional_details | |
| Provide your complete response in JSON format. | |
| For time allocations, use brackets format (e.g., "Reflection [5 min]"). | |
| Ensure all activities have detailed descriptions. | |
| """ | |
| try: | |
| response = self.client.chat.completions.create( | |
| model=self.model, | |
| messages=[ | |
| {"role": "system", "content": system_prompt}, | |
| {"role": "user", "content": user_message} | |
| ], | |
| response_format={"type": "json_object"} | |
| ) | |
| lesson_plan = json.loads(response.choices[0].message.content) | |
| # Basic validation of the lesson plan | |
| required_fields = ["lesson_plan_title", "structure", "objectives", "learning_outcomes"] | |
| for field in required_fields: | |
| if field not in lesson_plan: | |
| if field == "lesson_plan_title": | |
| lesson_plan[field] = f"Language Lesson: {input_data.get('topic', 'General Practice')}" | |
| elif field == "structure": | |
| lesson_plan[field] = lesson_structure | |
| elif field == "objectives": | |
| lesson_plan[field] = ["Improve language skills"] | |
| elif field == "learning_outcomes": | |
| lesson_plan[field] = ["Students will be able to communicate more effectively"] | |
| return lesson_plan | |
| except Exception as e: | |
| print(f"Error in lesson_plan_generation: {str(e)}") | |
| # Create a minimal fallback lesson plan | |
| return { | |
| "lesson_plan_title": f"Language Lesson: {input_data.get('topic', 'General Practice')}", | |
| "structure": lesson_structure, | |
| "structure_explanation": structure_description or "Basic language practice structure", | |
| "objectives": ["Improve language skills"], | |
| "learning_outcomes": ["Students will be able to communicate more effectively"], | |
| "materials_and_resources": ["Whiteboard", "Handouts"], | |
| "lesson_plan_structure": { | |
| "main_activity": { | |
| "key_parts": "Main Activity [30 minutes]", | |
| "objective": "Practice language skills", | |
| "activities": "Complete worksheet activities" | |
| } | |
| }, | |
| "assessment_strategies": ["Informal assessment through observation"], | |
| "note": "This is a fallback lesson plan due to processing limitations." | |
| } | |