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("""
""", unsafe_allow_html=True)
# Initialize the LLM Handler (using Streamlit caching)
@st.cache_resource
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 = '
'
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'
{value}
'
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'
'
if level == 0:
content += f'
{formatted_key}
'
else:
content += f''
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 += '
'
return content
def process_list(lst, level):
content = '
'
for item in lst:
if isinstance(item, dict):
content += process_dict(item, level + 1)
else:
content += f'
{item}
'
content += '
'
return content
html_content += process_dict(data, 0)
html_content += '
'
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")