File size: 10,962 Bytes
43a0ec2
 
d0ed37e
 
 
43a0ec2
d0ed37e
 
 
 
 
43a0ec2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d0ed37e
 
 
 
 
43a0ec2
 
d0ed37e
75e0119
43a0ec2
 
 
 
 
 
 
 
 
 
 
d0ed37e
 
43a0ec2
 
 
 
 
 
 
 
 
 
d0ed37e
 
43a0ec2
 
 
 
d0ed37e
 
 
43a0ec2
 
 
d0ed37e
 
 
43a0ec2
d0ed37e
43a0ec2
75e0119
 
 
 
 
 
 
 
 
 
43a0ec2
d0ed37e
 
 
43a0ec2
 
 
 
 
 
75e0119
 
 
 
d0ed37e
43a0ec2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d0ed37e
43a0ec2
 
 
 
 
 
 
 
 
 
 
 
 
d0ed37e
 
 
 
 
 
 
 
 
 
 
43a0ec2
 
d0ed37e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43a0ec2
 
 
d0ed37e
43a0ec2
 
 
d0ed37e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
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)
@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 = '<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")