Spaces:
Sleeping
Sleeping
| import streamlit as st | |
| import json | |
| import os | |
| from dotenv import load_dotenv | |
| from typing import Dict, Any | |
| # Import the LLM Handler directly | |
| from llms_handler import LLMHandler | |
| # Load environment variables for OpenAI API key | |
| load_dotenv() | |
| # Page configuration | |
| st.set_page_config( | |
| page_title="WizLab Lesson Plan Generator", | |
| page_icon="📚", | |
| layout="wide" | |
| ) | |
| # Custom CSS with improved styling | |
| st.markdown(""" | |
| <style> | |
| .main-container { | |
| background-color: white; | |
| border-radius: 8px; | |
| padding: 25px; | |
| margin: 20px 0; | |
| box-shadow: 0 2px 8px rgba(0,0,0,0.1); | |
| } | |
| .section { | |
| margin: 15px 0; | |
| padding: 10px 0; | |
| } | |
| .section-level-0 { | |
| border-bottom: 2px solid #e8eaf6; | |
| margin-bottom: 20px; | |
| } | |
| .section-level-1 { | |
| margin-left: 20px; | |
| border-left: 2px solid #e8eaf6; | |
| padding-left: 15px; | |
| } | |
| .section-level-2 { | |
| margin-left: 15px; | |
| padding-left: 10px; | |
| } | |
| .section-header-main { | |
| color: #1a237e; | |
| font-size: 20px; | |
| font-weight: 600; | |
| margin-bottom: 15px; | |
| padding-bottom: 5px; | |
| border-bottom: 1px solid #e8eaf6; | |
| } | |
| .section-header-sub { | |
| color: #283593; | |
| font-size: 16px; | |
| font-weight: 500; | |
| margin: 10px 0; | |
| } | |
| .section-content { | |
| color: #333; | |
| margin: 10px 0 10px 20px; | |
| line-height: 1.5; | |
| } | |
| .list-item { | |
| margin: 8px 0; | |
| color: #333; | |
| padding-left: 20px; | |
| position: relative; | |
| } | |
| .list-item:before { | |
| content: "•"; | |
| position: absolute; | |
| left: 0; | |
| color: #3949ab; | |
| } | |
| .nested-content { | |
| margin-left: 20px; | |
| padding-left: 15px; | |
| border-left: 2px solid #e8eaf6; | |
| } | |
| .timing-label { | |
| color: #1565c0; | |
| font-weight: 500; | |
| font-style: italic; | |
| } | |
| </style> | |
| """, unsafe_allow_html=True) | |
| # Initialize the LLM Handler (using Streamlit caching) | |
| def get_llm_handler(): | |
| """Create and cache the LLM Handler.""" | |
| return LLMHandler() | |
| llm_handler = get_llm_handler() | |
| # Header | |
| st.title("WizLab Lesson Plan Generator") | |
| st.markdown("We help you generate lesson plans tailored to your needs.") | |
| # Input section | |
| st.header("Input Your Requirements") | |
| # Create two columns for input fields | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| topic = st.text_input("Topic", | |
| placeholder="e.g., Lesson Plan to teach Spanish numbers as third language to English Speaking students ") | |
| age_group_options = ["Elementary (6-11)", "Middle School (12-14)", | |
| "High School (15-18)", "Adult Learners", "Other"] | |
| age_group_selection = st.selectbox("Target Age Group", age_group_options) | |
| if age_group_selection == "Other": | |
| age_group = st.text_input("Specify Age Group") | |
| else: | |
| age_group = age_group_selection | |
| language_options = [ | |
| "English", "中文 (Mandarin Chinese)" | |
| ] | |
| language_selection = st.selectbox("Select Output Language", language_options) | |
| LANGUAGE_MAPPING = { | |
| "中文 (Mandarin Chinese)": "Mandarin Chinese" | |
| } | |
| # Then in your language selection code: | |
| # if language_selection == "Other": | |
| # language = st.text_input("Specify Language") | |
| #else: | |
| # Use mapping if available, otherwise use the base language name | |
| language = LANGUAGE_MAPPING.get(language_selection, language_selection) | |
| skills_section = ["Reading", "Writing", "Listening", "Speaking", "Other"] | |
| skill_focus = st.multiselect("Skills to focus", skills_section) | |
| if "Other" in skill_focus: | |
| other_skills = st.text_input("Specify Skills to focus") | |
| skill_focus.remove("Other") # Remove 'Other' placeholder from the list | |
| if other_skills: | |
| skill_focus.append(other_skills) # Add user-specified skills | |
| with col2: | |
| duration = st.text_input("Duration [in minutes]", placeholder="e.g., 25 minutes") | |
| proficiency_options = ["Beginner [A1]", "Elementary [A2]", "Intermediate[B1]", "Upper-Intermediate [B2]", | |
| "Advanced[C1]", "Proficient [C2]", "Other"] | |
| proficiency_selection = st.selectbox("Proficiency Level [CEFR]", proficiency_options) | |
| if proficiency_selection == "Other": | |
| proficiency = st.text_input("Specify Proficiency Level") | |
| else: | |
| proficiency = proficiency_selection | |
| tech_options = ["Interactive Whiteboard", "Computers/Laptops", | |
| "Mobile Devices", "Internet Access", "None", "Other"] | |
| tech_selection = st.multiselect("Accessible Tech Resources", tech_options) | |
| num_students = st.text_input("Number of students", placeholder="e.g., 30 students") | |
| if "Other" in tech_selection: | |
| other_tech = st.text_input("Specify Other Technology Requirements") | |
| tech_usage = [tech for tech in tech_selection if tech != "Other"] + [other_tech] | |
| else: | |
| tech_usage = tech_selection | |
| def format_content(data): | |
| html_content = '<div class="main-container">' | |
| def format_key(key): | |
| """Format key string to be more readable""" | |
| # Handle camelCase | |
| key = ''.join(' ' + char if char.isupper() else char for char in key).strip() | |
| # Replace underscores and normalize spaces | |
| key = key.replace('_', ' ').title() | |
| return key | |
| def process_value(value, level=0): | |
| if isinstance(value, dict): | |
| return process_dict(value, level) | |
| elif isinstance(value, list): | |
| return process_list(value, level) | |
| else: | |
| return f'<div class="section-content">{value}</div>' | |
| def process_dict(d, level): | |
| content = "" | |
| for key, value in d.items(): | |
| formatted_key = format_key(key) | |
| section_class = "section-level-" + str(level) | |
| content += f'<div class="section {section_class}">' | |
| if level == 0: | |
| content += f'<div class="section-header-main">{formatted_key}</div>' | |
| else: | |
| content += f'<div class="section-header-sub">{formatted_key}</div>' | |
| if isinstance(value, dict) and any(isinstance(v, (dict, list)) for v in value.values()): | |
| content += process_value(value, level + 1) | |
| elif isinstance(value, list) and any(isinstance(item, dict) for item in value): | |
| content += process_value(value, level + 1) | |
| else: | |
| content += process_value(value, level + 1) | |
| content += '</div>' | |
| return content | |
| def process_list(lst, level): | |
| content = '<div class="section-content">' | |
| for item in lst: | |
| if isinstance(item, dict): | |
| content += process_dict(item, level + 1) | |
| else: | |
| content += f'<div class="list-item">{item}</div>' | |
| content += '</div>' | |
| return content | |
| html_content += process_dict(data, 0) | |
| html_content += '</div>' | |
| return html_content | |
| # Generate button | |
| if st.button("Generate Lesson Plan", type="primary"): | |
| if not topic: | |
| st.error("Please enter a topic for the lesson plan.") | |
| else: | |
| with st.spinner("Generating your lesson plan... This may take a minute or two."): | |
| # Set default values if not provided | |
| if not duration: | |
| duration = "30 minutes" | |
| if not proficiency: | |
| proficiency = "Intermediate [B1, B2]" | |
| if not age_group: | |
| age_group = "Elementary (6-11)" | |
| if not tech_usage: | |
| tech_usage = ["White Board", "Internet Access"] | |
| if not language: | |
| language = "English" | |
| detailed_prompt = f""" | |
| Create a lesson plan for teaching '{topic}' to {age_group} students, for a | |
| Duration: {duration}, | |
| Number of students in the class: {num_students}, | |
| Skills to focus in generating lesson plan: {', '.join(skill_focus) if skill_focus else 'All language skills'}, | |
| Proficiency Level [CEFR]: {proficiency}, | |
| Technology Requirements: {', '.join(tech_usage) if tech_usage else 'None'}, | |
| Generate response in {language} Language. | |
| """ | |
| # Add debug output to see what's happening | |
| progress_placeholder = st.empty() | |
| try: | |
| # Direct integration with LLM Handler | |
| # Step 1: Extract and validate input parameters | |
| progress_placeholder.text("Step 1/4: Extracting and validating inputs...") | |
| input_data = llm_handler.input_extraction_validation(detailed_prompt) | |
| progress_placeholder.text("Step 1/4: Input extraction completed") | |
| # Step 2: Determine lesson plan structure | |
| progress_placeholder.text("Step 2/4: Determining lesson structure...") | |
| structure_info = llm_handler.lesson_plan_structure(input_data) | |
| progress_placeholder.text("Step 2/4: Structure determination completed") | |
| # Step 3: Select activity templates | |
| progress_placeholder.text("Step 3/4: Selecting activity templates...") | |
| activity_info = llm_handler.activity_template_selection(input_data, structure_info) | |
| progress_placeholder.text("Step 3/4: Activity template selection completed") | |
| # Step 4: Generate lesson plan | |
| progress_placeholder.text("Step 4/4: Generating final lesson plan...") | |
| lesson_plan = llm_handler.lesson_plan_generation(input_data, structure_info, activity_info) | |
| progress_placeholder.text("Step 4/4: Lesson plan generation completed") | |
| # Clear the progress placeholder | |
| progress_placeholder.empty() | |
| # Notify success | |
| st.success("Lesson plan generated successfully!") | |
| # Create tabs for different views | |
| tab1, tab2 = st.tabs(["Formatted View", "Raw JSON"]) | |
| with tab1: | |
| st.markdown(format_content(lesson_plan), unsafe_allow_html=True) | |
| with tab2: | |
| st.json(lesson_plan) | |
| # Download button | |
| st.download_button( | |
| label="Download Lesson Plan", | |
| data=json.dumps(lesson_plan, indent=2, ensure_ascii=False), | |
| # ensure_ascii=False for proper Unicode handling | |
| file_name=f"lesson_plan_{language}.json", | |
| mime="application/json" | |
| ) | |
| except Exception as e: | |
| st.error(f"An error occurred: {str(e)}") | |
| st.error("Please check if your OpenAI API key is valid and has sufficient credits.") | |
| # Footer | |
| st.markdown("---") | |
| st.markdown("© WizLab Lesson Plan Generator | powered by AI") | |