Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import openai | |
| import json | |
| import random | |
| from datetime import datetime | |
| import os | |
| # Configure OpenRouter API | |
| openai.api_base = "https://openrouter.ai/api/v1" | |
| openai.api_key = os.environ.get("OPENROUTER_API_KEY", "").strip() | |
| class ScienceTalkGame: | |
| def __init__(self): | |
| self.scenarios = self.load_all_scenarios() | |
| self.reset_session() | |
| def reset_session(self): | |
| self.session = { | |
| "engagement_scores": {}, | |
| "teaching_points": 0, | |
| "choices_made": [], | |
| "current_scenario": "grade2_plants", | |
| "turn_count": 0 | |
| } | |
| self.update_engagement_for_scenario() | |
| def load_all_scenarios(self): | |
| return { | |
| "grade2_plants": { | |
| "title": "π± Grade 2: Plant Investigation", | |
| "ngss_standard": "2-LS2-1: Environmental Plant Needs", | |
| "setup": "Your 2nd grade students are examining classroom plants. Some are healthy and green, others are yellow and droopy.", | |
| "phenomenon": "Why do some plants in our classroom look different from others?", | |
| "learning_goals": "Students observe plant differences, share ideas about plant needs, and connect to cultural knowledge about plants.", | |
| "students": { | |
| "Maya": { | |
| "background": "Mexican-American, bilingual, family has vegetable garden", | |
| "cultural_assets": "Grandmother's traditional gardening knowledge, Spanish plant names", | |
| "communication_style": "Sometimes shy in English, mixes languages naturally", | |
| "science_thinking": "Connects plants to family cooking and traditional remedies", | |
| "base_engagement": 3 | |
| }, | |
| "Jamal": { | |
| "background": "African-American, urban environment, curious observer", | |
| "cultural_assets": "Community garden experience, street tree observations", | |
| "communication_style": "Energetic, asks lots of 'what if' questions", | |
| "science_thinking": "Makes connections to neighborhood observations", | |
| "base_engagement": 4 | |
| }, | |
| "Aisha": { | |
| "background": "Somali-American, family farming background from Somalia", | |
| "cultural_assets": "Traditional ecological knowledge, seasonal farming wisdom", | |
| "communication_style": "Thoughtful, needs processing time before sharing", | |
| "science_thinking": "Compares to farming practices from home country", | |
| "base_engagement": 2 | |
| }, | |
| "Emma": { | |
| "background": "White suburban, science-enthusiastic family", | |
| "cultural_assets": "Access to science books and nature documentaries", | |
| "communication_style": "Eager to share, uses formal science vocabulary", | |
| "science_thinking": "References books and shows, sometimes dominates", | |
| "base_engagement": 4 | |
| } | |
| } | |
| }, | |
| "grade4_energy": { | |
| "title": "β‘ Grade 4: Energy Transfer Investigation", | |
| "ngss_standard": "4-PS3-2: Energy Transfer", | |
| "setup": "Students tested different spoon materials in hot cocoa and noticed some got hot while others stayed cool.", | |
| "phenomenon": "Why do metal spoons get hot in hot cocoa but wooden spoons don't?", | |
| "learning_goals": "Students explore energy transfer, connect to family cooking knowledge, and investigate material properties.", | |
| "students": { | |
| "Diego": { | |
| "background": "Mexican-American, father works in auto mechanics", | |
| "cultural_assets": "Family knowledge about tools, metal work, cooking traditions", | |
| "communication_style": "Enthusiastic, mixes Spanish and English", | |
| "science_thinking": "Connects to mechanical work and traditional cooking methods", | |
| "base_engagement": 4 | |
| }, | |
| "Keisha": { | |
| "background": "African-American, practical problem-solver, urban environment", | |
| "cultural_assets": "Family cooking traditions, observational skills from city life", | |
| "communication_style": "Direct, logical, asks practical questions", | |
| "science_thinking": "Focuses on real-world applications and problem-solving", | |
| "base_engagement": 4 | |
| }, | |
| "Ryan": { | |
| "background": "White rural, family farm and workshop experience", | |
| "cultural_assets": "Traditional craftsmanship, agricultural knowledge, tool use", | |
| "communication_style": "Methodical, references family work experiences", | |
| "science_thinking": "Connects to farming and workshop applications", | |
| "base_engagement": 3 | |
| }, | |
| "Zara": { | |
| "background": "Somali-American, moved from Somalia, multilingual", | |
| "cultural_assets": "International perspective, traditional cooking methods", | |
| "communication_style": "Careful with English, thoughtful responses", | |
| "science_thinking": "Compares to practices from different countries", | |
| "base_engagement": 2 | |
| } | |
| } | |
| }, | |
| "kindergarten_weather": { | |
| "title": "βοΈ Kindergarten: Weather Watchers", | |
| "ngss_standard": "K-ESS2-1: Weather Patterns", | |
| "setup": "Students noticed that puddles from yesterday's rain have disappeared, and they're curious about where the water went.", | |
| "phenomenon": "Why do puddles disappear on sunny days?", | |
| "learning_goals": "Students observe weather changes, share family weather knowledge, and explore water in the environment.", | |
| "students": { | |
| "Aaliyah": { | |
| "background": "African-American, urban, walks to school daily", | |
| "cultural_assets": "Daily weather observations, neighborhood knowledge", | |
| "communication_style": "Animated storyteller, uses gestures", | |
| "science_thinking": "Makes connections between daily observations", | |
| "base_engagement": 4 | |
| }, | |
| "JosΓ©": { | |
| "background": "Mexican-American, recent immigrant, bilingual family", | |
| "cultural_assets": "Traditional weather prediction methods from Mexico", | |
| "communication_style": "Thoughtful, mixes Spanish and English", | |
| "science_thinking": "Connects to traditional weather wisdom", | |
| "base_engagement": 3 | |
| }, | |
| "Emma": { | |
| "background": "White suburban, science-enthusiastic family", | |
| "cultural_assets": "Science books and weather apps at home", | |
| "communication_style": "Eager, uses weather vocabulary from books", | |
| "science_thinking": "References weather facts from media", | |
| "base_engagement": 4 | |
| }, | |
| "Kai": { | |
| "background": "Mixed Asian/Pacific Islander, military family, moved frequently", | |
| "cultural_assets": "Experience with different climates and weather patterns", | |
| "communication_style": "Observant but hesitant to share", | |
| "science_thinking": "Compares weather across different locations", | |
| "base_engagement": 2 | |
| } | |
| } | |
| }, | |
| "grade5_ecosystems": { | |
| "title": "π Grade 5: Community Ecosystem Scientists", | |
| "ngss_standard": "5-LS2-1: Environmental Matter Cycling", | |
| "setup": "Students visited the community garden and noticed different areas have different plants, insects, and soil conditions.", | |
| "phenomenon": "Why do different areas of the community garden have different living things?", | |
| "learning_goals": "Students explore ecosystem interactions, connect to community knowledge, and investigate matter cycling.", | |
| "students": { | |
| "Amara": { | |
| "background": "Somali-American, family farming background", | |
| "cultural_assets": "Traditional ecological knowledge, crop rotation understanding", | |
| "communication_style": "Thoughtful, connects to family farming wisdom", | |
| "science_thinking": "Sees connections between traditional and scientific knowledge", | |
| "base_engagement": 3 | |
| }, | |
| "Carlos": { | |
| "background": "Mexican-American, grandmother has large garden", | |
| "cultural_assets": "Traditional companion planting, medicinal plants knowledge", | |
| "communication_style": "Enthusiastic about sharing family knowledge", | |
| "science_thinking": "Integrates traditional ecological practices with science", | |
| "base_engagement": 4 | |
| }, | |
| "Destiny": { | |
| "background": "African-American, urban nature observer", | |
| "cultural_assets": "City ecosystem observations, community garden participation", | |
| "communication_style": "Curious, asks detailed questions", | |
| "science_thinking": "Notices patterns in urban environments", | |
| "base_engagement": 4 | |
| }, | |
| "Tyler": { | |
| "background": "White rural, hunting and outdoor experience", | |
| "cultural_assets": "Wildlife observation, forest ecology knowledge", | |
| "communication_style": "Practical, references outdoor experiences", | |
| "science_thinking": "Understands predator-prey relationships and cycles", | |
| "base_engagement": 3 | |
| }, | |
| "Mei": { | |
| "background": "Chinese-American, recently arrived, family gardening", | |
| "cultural_assets": "Traditional Chinese gardening, vermiculture knowledge", | |
| "communication_style": "Hesitant with English, rich knowledge to share", | |
| "science_thinking": "Brings international gardening perspectives", | |
| "base_engagement": 2 | |
| } | |
| } | |
| } | |
| } | |
| def update_engagement_for_scenario(self): | |
| """Set engagement scores based on current scenario""" | |
| scenario = self.scenarios[self.session["current_scenario"]] | |
| self.session["engagement_scores"] = {} | |
| for student_name, student_data in scenario["students"].items(): | |
| self.session["engagement_scores"][student_name] = student_data["base_engagement"] | |
| def get_current_scenario(self): | |
| return self.scenarios[self.session["current_scenario"]] | |
| def change_scenario(self, scenario_key): | |
| """Switch to a different scenario""" | |
| if scenario_key in self.scenarios: | |
| self.session["current_scenario"] = scenario_key | |
| self.session["teaching_points"] = 0 | |
| self.session["choices_made"] = [] | |
| self.session["turn_count"] = 0 | |
| self.update_engagement_for_scenario() | |
| return True | |
| return False | |
| def generate_student_responses(self, teacher_input): | |
| scenario = self.get_current_scenario() | |
| # Create detailed context for each student | |
| student_contexts = [] | |
| for student_name, student_data in scenario["students"].items(): | |
| engagement_level = self.session["engagement_scores"][student_name] | |
| if engagement_level >= 4: | |
| engagement_desc = "highly engaged and eager to participate" | |
| elif engagement_level >= 3: | |
| engagement_desc = "moderately engaged and willing to share" | |
| elif engagement_level >= 2: | |
| engagement_desc = "somewhat hesitant but paying attention" | |
| else: | |
| engagement_desc = "disengaged and unlikely to participate" | |
| context = f"""**{student_name}**: {student_data['background']}. {student_data['cultural_assets']}. {student_data['communication_style']}. Currently {engagement_desc}.""" | |
| student_contexts.append(context) | |
| prompt = f"""You are role-playing elementary students in a science discussion. The scenario is: {scenario['title']} - {scenario['setup']} | |
| The scientific phenomenon being explored: {scenario['phenomenon']} | |
| Students in this discussion: | |
| {chr(10).join(student_contexts)} | |
| The teacher just said: "{teacher_input}" | |
| Respond as each student would, showing their authentic thinking, cultural backgrounds, and current engagement levels. Make responses feel natural for their grade level. Format your response as: | |
| **[Student Name]:** [their response] | |
| For each student response, show their personality, cultural knowledge, communication style, and current engagement level. Some students might not respond if they're disengaged.""" | |
| try: | |
| response = openai.ChatCompletion.create( | |
| model="openai/gpt-3.5-turbo", | |
| messages=[{"role": "user", "content": prompt}], | |
| temperature=0.8, | |
| max_tokens=500 | |
| ) | |
| return response.choices[0].message.content | |
| except Exception as e: | |
| return f"**Error generating student responses:** {str(e)}\n\nPlease check your OpenRouter API key configuration." | |
| def generate_teaching_choices(self, scenario_context=""): | |
| """Generate contextual teaching choices based on current scenario""" | |
| scenario = self.get_current_scenario() | |
| # Base equity-focused choices | |
| base_choices = [ | |
| "π Build on cultural knowledge: Ask students about family/community knowledge related to this topic", | |
| "π€ Create inclusive space: Make sure quieter students get a chance to share their thinking", | |
| "π¬ Promote scientific investigation: Guide students to plan how they could test their ideas", | |
| "βοΈ Manage participation: Redirect conversation to include less dominant voices" | |
| ] | |
| # Scenario-specific choices | |
| scenario_specific = { | |
| "grade2_plants": [ | |
| "π± Connect to home gardens: Ask about plants students have at home", | |
| "π Support language learners: Encourage students to share plant names in their home languages", | |
| "π£οΈ Facilitate peer discussion: Have students share observations with a partner first", | |
| "π Document thinking: Help students draw or record what they notice" | |
| ], | |
| "grade4_energy": [ | |
| "π§ Connect to family work: Ask about tools and materials families use", | |
| "π³ Explore cooking connections: Discuss heat transfer in family cooking traditions", | |
| "π§ͺ Design investigations: Help students plan controlled tests of materials", | |
| "π‘οΈ Make predictions: Ask students to predict what will happen with different materials" | |
| ], | |
| "kindergarten_weather": [ | |
| "π€οΈ Share weather observations: Ask about weather patterns students notice", | |
| "π Connect to daily life: Discuss how weather affects what families do", | |
| "ποΈ Use senses: Encourage students to describe what they see, feel, smell", | |
| "π Track patterns: Help students think about when they've seen this before" | |
| ], | |
| "grade5_ecosystems": [ | |
| "πΏ Explore traditional knowledge: Ask about family farming or gardening practices", | |
| "π Investigate cycles: Help students trace matter through the ecosystem", | |
| "π€ Community connections: Discuss how people are part of the ecosystem", | |
| "π Systematic observation: Guide students to organize their observations" | |
| ] | |
| } | |
| # Combine base and scenario-specific choices | |
| current_specific = scenario_specific.get(self.session["current_scenario"], []) | |
| all_choices = base_choices + current_specific | |
| # Return 4 random choices to keep it fresh | |
| return random.sample(all_choices, min(4, len(all_choices))) | |
| def assess_teaching_choice(self, choice_text): | |
| """Enhanced assessment based on scenario context""" | |
| feedback = "" | |
| points = 0 | |
| engagement_impact = {} | |
| choice_lower = choice_text.lower() | |
| scenario = self.get_current_scenario() | |
| # Assess different types of teaching moves | |
| if any(keyword in choice_lower for keyword in ["cultural", "family", "community", "home"]): | |
| feedback = "π Excellent! You're building on students' cultural assets. This validates their family knowledge and shows that diverse perspectives are valued in science." | |
| points = 3 | |
| # Boost engagement for students with strong cultural assets | |
| for student_name, student_data in scenario["students"].items(): | |
| if "traditional" in student_data["cultural_assets"].lower() or "family" in student_data["cultural_assets"].lower(): | |
| engagement_impact[student_name] = engagement_impact.get(student_name, 0) + 2 | |
| elif any(keyword in choice_lower for keyword in ["inclusive", "quieter", "all students", "everyone"]): | |
| feedback = "β Great equity move! Creating space for all voices helps build a classroom community where everyone's thinking is valued." | |
| points = 2 | |
| # Boost engagement for lower-engaged students | |
| for student_name, engagement in self.session["engagement_scores"].items(): | |
| if engagement <= 3: | |
| engagement_impact[student_name] = engagement_impact.get(student_name, 0) + 2 | |
| elif any(keyword in choice_lower for keyword in ["investigate", "test", "plan", "scientific"]): | |
| feedback = "π¬ Good scientific thinking! You're helping students engage in authentic science practices and develop investigative skills." | |
| points = 2 | |
| # Boost engagement for science-oriented students | |
| for student_name, student_data in scenario["students"].items(): | |
| if "science" in student_data["science_thinking"].lower(): | |
| engagement_impact[student_name] = engagement_impact.get(student_name, 0) + 1 | |
| elif any(keyword in choice_lower for keyword in ["manage", "redirect", "less dominant"]): | |
| feedback = "βοΈ Important facilitation move! Managing participation ensures equitable discourse and gives space for all students to contribute." | |
| points = 2 | |
| # Reduce dominance, increase participation for others | |
| for student_name, engagement in self.session["engagement_scores"].items(): | |
| if engagement >= 4: | |
| engagement_impact[student_name] = engagement_impact.get(student_name, 0) - 1 | |
| else: | |
| engagement_impact[student_name] = engagement_impact.get(student_name, 0) + 1 | |
| elif any(keyword in choice_lower for keyword in ["language", "home languages", "spanish", "multilingual"]): | |
| feedback = "π£οΈ Wonderful! Supporting multilingual learners by honoring their home languages strengthens both their science learning and cultural identity." | |
| points = 3 | |
| # Major boost for multilingual students | |
| for student_name, student_data in scenario["students"].items(): | |
| if "bilingual" in student_data["background"].lower() or "language" in student_data["communication_style"].lower(): | |
| engagement_impact[student_name] = engagement_impact.get(student_name, 0) + 3 | |
| else: | |
| feedback = "Consider how this choice supports equitable participation and builds on student thinking." | |
| points = 1 | |
| return feedback, points, engagement_impact | |
| def update_engagement(self, impact_dict): | |
| """Update student engagement based on teaching choices""" | |
| for student, change in impact_dict.items(): | |
| if student in self.session["engagement_scores"]: | |
| current = self.session["engagement_scores"][student] | |
| new_score = max(1, min(5, current + change)) | |
| self.session["engagement_scores"][student] = new_score | |
| def get_engagement_display(self): | |
| """Create visual representation of student engagement""" | |
| scenario = self.get_current_scenario() | |
| display = "## π Student Engagement Levels\n\n" | |
| for student_name, score in self.session["engagement_scores"].items(): | |
| student_info = scenario["students"][student_name] | |
| stars = "β" * score + "β" * (5-score) | |
| display += f"**{student_name}** ({student_info['background'].split(',')[0]}): {stars} ({score}/5)\n\n" | |
| return display | |
| def get_scenario_info(self): | |
| scenario = self.get_current_scenario() | |
| info = f"""## {scenario['title']} | |
| **NGSS Standard:** {scenario['ngss_standard']} | |
| **Situation:** {scenario['setup']} | |
| **Phenomenon:** {scenario['phenomenon']} | |
| **Learning Goals:** {scenario['learning_goals']} | |
| **Your Students:**""" | |
| for student_name, student_data in scenario["students"].items(): | |
| info += f"\n- **{student_name}:** {student_data['background']} - {student_data['cultural_assets']}" | |
| return info | |
| def get_available_scenarios(self): | |
| """Return list of available scenarios for selection""" | |
| return [(key, data["title"]) for key, data in self.scenarios.items()] | |
| # Initialize game | |
| game = ScienceTalkGame() | |
| def change_scenario(scenario_choice): | |
| """Handle scenario change""" | |
| # Extract scenario key from the choice (format: "key: title") | |
| scenario_key = scenario_choice.split(":")[0].strip() | |
| if game.change_scenario(scenario_key): | |
| scenario_info = game.get_scenario_info() | |
| engagement_display = game.get_engagement_display() | |
| points_display = f"**Teaching Points:** {game.session['teaching_points']}" | |
| welcome_msg = f"""## Welcome to {game.get_current_scenario()['title']}! π | |
| **Instructions:** Type what you would say to start this science discussion, then click 'Send Response' to see how your students react.""" | |
| return scenario_info, engagement_display, welcome_msg, points_display, "", "" | |
| else: | |
| return "Error changing scenario", "", "", "", "", "" | |
| def start_new_session(): | |
| """Reset the current scenario""" | |
| game.reset_session() | |
| scenario_info = game.get_scenario_info() | |
| engagement_display = game.get_engagement_display() | |
| welcome_msg = f"""## Welcome to {game.get_current_scenario()['title']}! π | |
| You're about to practice facilitating an equitable science discussion. Your goals: | |
| 1. **Include all student voices** - especially those who might be hesitant | |
| 2. **Build on cultural assets** - honor knowledge students bring from home | |
| 3. **Promote scientific thinking** - help students observe, question, investigate | |
| 4. **Manage participation** - ensure discussions are equitable | |
| **To begin:** Type what you would say to start the science talk.""" | |
| return scenario_info, engagement_display, welcome_msg, f"**Teaching Points:** {game.session['teaching_points']}", "" | |
| def process_teacher_input(teacher_input): | |
| """Process teacher's response and generate student reactions""" | |
| if not teacher_input or not teacher_input.strip(): | |
| return "Please enter what you would say to your students.", "", "" | |
| # Generate student responses | |
| student_response = game.generate_student_responses(teacher_input) | |
| # Generate teaching choice options | |
| choices = game.generate_teaching_choices() | |
| choice_display = "## π― How do you respond? Choose your next move:\n\n" | |
| for i, choice in enumerate(choices, 1): | |
| choice_display += f"**Option {i}:** {choice}\n\n" | |
| game.session["turn_count"] += 1 | |
| return student_response, choice_display, "" | |
| def handle_teaching_choice(choice_num): | |
| """Process the selected teaching choice""" | |
| if choice_num < 1 or choice_num > 4: | |
| return "Please select a valid choice.", "", "" | |
| choices = game.generate_teaching_choices() | |
| if choice_num <= len(choices): | |
| selected_choice = choices[choice_num - 1] | |
| feedback, points, engagement_impact = game.assess_teaching_choice(selected_choice) | |
| game.session["teaching_points"] += points | |
| game.update_engagement(engagement_impact) | |
| game.session["choices_made"].append({ | |
| "choice": selected_choice, | |
| "points": points, | |
| "turn": game.session["turn_count"] | |
| }) | |
| updated_engagement = game.get_engagement_display() | |
| points_display = f"**Teaching Points:** {game.session['teaching_points']}" | |
| return feedback, updated_engagement, points_display | |
| return "Choice not found.", "", "" | |
| # Create Gradio interface | |
| def create_interface(): | |
| with gr.Blocks(title="Science Talk Adventure", theme=gr.themes.Soft()) as interface: | |
| gr.Markdown("# π± Science Talk Adventure: Multi-Scenario Practice") | |
| gr.Markdown("*Practice equitable science discussions across multiple grade levels and topics*") | |
| with gr.Row(): | |
| with gr.Column(scale=2): | |
| # Scenario selection | |
| scenario_choices = [f"{key}: {data['title']}" for key, data in game.scenarios.items()] | |
| scenario_selector = gr.Dropdown( | |
| choices=scenario_choices, | |
| value=f"{game.session['current_scenario']}: {game.get_current_scenario()['title']}", | |
| label="π Choose Your Scenario", | |
| interactive=True | |
| ) | |
| scenario_info = gr.Markdown(game.get_scenario_info()) | |
| conversation_area = gr.Markdown("*Students will respond here after you speak...*") | |
| teacher_input = gr.Textbox( | |
| label="π¬ What do you say to your students?", | |
| placeholder="Type your response here...", | |
| lines=3 | |
| ) | |
| send_btn = gr.Button("Send Response", variant="primary", size="lg") | |
| choices_display = gr.Markdown("") | |
| with gr.Row(): | |
| choice1_btn = gr.Button("Choice 1", variant="secondary") | |
| choice2_btn = gr.Button("Choice 2", variant="secondary") | |
| choice3_btn = gr.Button("Choice 3", variant="secondary") | |
| choice4_btn = gr.Button("Choice 4", variant="secondary") | |
| feedback_display = gr.Markdown("") | |
| with gr.Column(scale=1): | |
| engagement_display = gr.Markdown(game.get_engagement_display()) | |
| points_display = gr.Markdown(f"**Teaching Points:** {game.session['teaching_points']}") | |
| gr.Markdown("---") | |
| restart_btn = gr.Button("π Restart Current Scenario", variant="outline") | |
| gr.Markdown(""" | |
| ### π‘ Tips for Success: | |
| - **Listen for cultural knowledge** students share | |
| - **Create wait time** for all students to think | |
| - **Build on student ideas** rather than correcting immediately | |
| - **Notice participation patterns** and include all voices | |
| - **Connect to students' lived experiences** | |
| ### π― Available Scenarios: | |
| - **Kindergarten:** Weather patterns and observations | |
| - **Grade 2:** Plant growth and needs | |
| - **Grade 4:** Energy transfer in everyday materials | |
| - **Grade 5:** Community ecosystem interactions | |
| """) | |
| # Event handlers | |
| scenario_selector.change( | |
| change_scenario, | |
| inputs=[scenario_selector], | |
| outputs=[scenario_info, engagement_display, conversation_area, points_display, feedback_display, choices_display] | |
| ) | |
| restart_btn.click( | |
| start_new_session, | |
| outputs=[scenario_info, engagement_display, conversation_area, points_display, feedback_display] | |
| ) | |
| send_btn.click( | |
| process_teacher_input, | |
| inputs=[teacher_input], | |
| outputs=[conversation_area, choices_display, feedback_display] | |
| ) | |
| choice1_btn.click(lambda: handle_teaching_choice(1), outputs=[feedback_display, engagement_display, points_display]) | |
| choice2_btn.click(lambda: handle_teaching_choice(2), outputs=[feedback_display, engagement_display, points_display]) | |
| choice3_btn.click(lambda: handle_teaching_choice(3), outputs=[feedback_display, engagement_display, points_display]) | |
| choice4_btn.click(lambda: handle_teaching_choice(4), outputs=[feedback_display, engagement_display, points_display]) | |
| return interface | |
| # Launch the app | |
| if __name__ == "__main__": | |
| demo = create_interface() | |
| demo.launch() |