Saturday, May 16, 2026

BUILDING AN INTERACTIVE LLM-BASED APPLICATION TO TEACH CHILDREN ABOUT GENERATIVE AI

 



INTRODUCTION


Teaching children about artificial intelligence and large language models has become increasingly important in our technology-driven world. As these systems become more prevalent in daily life, children need to understand not only how to use them but also how they work, their limitations, and the ethical considerations surrounding their use. An interactive application that uses an actual LLM to teach about LLMs creates a unique meta-learning experience where the medium becomes part of the message.


This article describes the design and implementation of such an educational application. The application, which we will call AI Explorer, provides an age-appropriate, engaging platform where children can learn about generative AI through direct interaction, guided lessons, and hands-on experimentation. The system is designed for children aged eight to fourteen, with content that adapts to different comprehension levels.


The application serves multiple educational objectives. 


First, it demystifies AI technology by explaining concepts in accessible language. 


Second, it provides hands-on experience with an actual LLM in a safe, controlled environment. 


Third, it teaches critical thinking skills by helping children understand when to trust AI outputs and when to question them.

 

Fourth, it introduces basic concepts of machine learning, neural networks, and natural language processing without requiring advanced mathematical knowledge.


APPLICATION ARCHITECTURE


The architecture of AI Explorer follows clean architecture principles with clear separation between layers. The system consists of four primary layers: the presentation layer, the application layer, the domain layer, and the infrastructure layer. This separation ensures that the core educational logic remains independent of specific implementation details, making the system maintainable and testable.


The presentation layer handles all user interactions through a web-based interface. This layer is responsible for rendering the user interface, capturing user input, and displaying responses from the system. It communicates with the application layer through well-defined interfaces, never directly accessing the domain or infrastructure layers.

The application layer orchestrates the educational experience. It manages the flow of lessons, tracks student progress, determines which content to present next, and coordinates between different components. This layer contains the use cases that define what the application can do, such as starting a new lesson, answering a student question, or generating an interactive example.


The domain layer contains the core educational logic and business rules. This includes the curriculum structure, the knowledge graph of AI concepts, the progression system that determines when a student is ready for more advanced topics, and the rules for generating age-appropriate explanations. This layer is completely independent of any external frameworks or technologies.


The infrastructure layer handles all external dependencies. This includes the LLM API integration, database access, session management, and logging. By isolating these concerns, we can easily swap implementations without affecting the core educational logic.


Here is a simplified representation of the architecture:


+------------------+

| Presentation     |

| (Web Interface)  |

+------------------+

        |

        v

+------------------+

| Application      |

| (Use Cases)      |

+------------------+

        |

        v

+------------------+

| Domain           |

| (Education Logic)|

+------------------+

        |

        v

+------------------+

| Infrastructure   |

| (LLM, DB, etc)   |

+------------------+



The data flow through the system follows a clear pattern. When a student asks a question, the presentation layer captures the input and passes it to the application layer. The application layer consults the domain layer to determine the student's current level and learning context. It then uses the infrastructure layer to query the LLM with a carefully crafted prompt that includes educational guardrails. The response is processed through the domain layer to ensure it meets educational standards before being returned to the presentation layer for display.


CORE COMPONENTS


The Student Profile Manager is the first critical component. This component maintains information about each student's learning journey, including their progress through the curriculum, their comprehension level, topics they have mastered, and areas where they need additional support. The profile is used to personalize the learning experience and ensure that content is appropriately challenging.


Here is the core Student Profile class:


class StudentProfile:

    """

    Represents a student's learning profile and progress through the curriculum.

    This class encapsulates all student-specific data and provides methods

    to track and update learning progress.

    """

    

    def __init__(self, student_id, age, name):

        """

        Initialize a new student profile.

        

        Args:

            student_id: Unique identifier for the student

            age: Student's age in years

            name: Student's display name

        """

        self.student_id = student_id

        self.age = age

        self.name = name

        self.completed_lessons = set()

        self.current_level = self._determine_initial_level()

        self.mastered_concepts = set()

        self.interaction_count = 0

        self.last_active = None

        

    def _determine_initial_level(self):

        """

        Determine the appropriate starting level based on age.

        Younger students start with more basic concepts.

        

        Returns:

            String representing the initial difficulty level

        """

        if self.age < 10:

            return "beginner"

        elif self.age < 12:

            return "intermediate"

        else:

            return "advanced"

    

    def mark_lesson_complete(self, lesson_id):

        """

        Mark a lesson as completed and update the student's progress.

        

        Args:

            lesson_id: Identifier of the completed lesson

        """

        self.completed_lessons.add(lesson_id)

        self.interaction_count += 1

        

    def add_mastered_concept(self, concept):

        """

        Add a concept to the set of mastered concepts.

        

        Args:

            concept: The concept identifier that has been mastered

        """

        self.mastered_concepts.add(concept)

        

    def get_comprehension_level(self):

        """

        Calculate the current comprehension level based on progress.

        

        Returns:

            Float between 0.0 and 1.0 representing comprehension

        """

        total_concepts = 20  # Total concepts in curriculum

        mastered = len(self.mastered_concepts)

        return min(1.0, mastered / total_concepts)


The Student Profile Manager uses this class to maintain state across sessions. When a student logs in, their profile is loaded from the database. As they interact with the system, their profile is updated to reflect their progress. This allows the system to provide continuity and personalization across multiple sessions.


The Curriculum Manager is responsible for organizing and delivering educational content. It maintains a structured knowledge graph of AI concepts, with dependencies between topics. For example, a student must understand what data is before learning about training data, and must understand training data before learning about how models learn patterns.


The curriculum is organized into modules, each focusing on a specific aspect of AI and LLMs. The first module introduces the basic concept of what AI is and provides real-world examples that children can relate to. The second module explains what language models are and how they differ from other types of AI. The third module explores how LLMs are trained, using age-appropriate analogies. The fourth module covers what LLMs can and cannot do, emphasizing limitations. The fifth module addresses ethical considerations, including bias, privacy, and responsible use.


Here is the Curriculum Manager implementation:


class CurriculumManager:

    """

    Manages the educational curriculum and determines appropriate content

    for students based on their progress and comprehension level.

    """

    

    def __init__(self):

        """Initialize the curriculum with all modules and their dependencies."""

        self.modules = self._initialize_modules()

        self.concept_graph = self._build_concept_graph()

        

    def _initialize_modules(self):

        """

        Create the complete curriculum structure with all modules.

        

        Returns:

            Dictionary mapping module IDs to module objects

        """

        modules = {}

        

        modules["intro_ai"] = {

            "id": "intro_ai",

            "title": "What is Artificial Intelligence?",

            "description": "Learn what AI means and see examples in everyday life",

            "prerequisites": [],

            "concepts": ["ai_definition", "ai_examples", "ai_vs_human"],

            "difficulty": "beginner"

        }

        

        modules["intro_llm"] = {

            "id": "intro_llm",

            "title": "What are Language Models?",

            "description": "Discover how computers understand and generate language",

            "prerequisites": ["intro_ai"],

            "concepts": ["language_model", "text_generation", "patterns"],

            "difficulty": "beginner"

        }

        

        modules["training"] = {

            "id": "training",

            "title": "How AI Learns",

            "description": "Explore how language models are trained on data",

            "prerequisites": ["intro_llm"],

            "concepts": ["training_data", "learning_patterns", "neural_networks"],

            "difficulty": "intermediate"

        }

        

        modules["capabilities"] = {

            "id": "capabilities",

            "title": "What Can AI Do?",

            "description": "Learn about the abilities and limitations of AI",

            "prerequisites": ["training"],

            "concepts": ["ai_capabilities", "ai_limitations", "hallucinations"],

            "difficulty": "intermediate"

        }

        

        modules["ethics"] = {

            "id": "ethics",

            "title": "Using AI Responsibly",

            "description": "Understand the ethical considerations of AI",

            "prerequisites": ["capabilities"],

            "concepts": ["bias", "privacy", "responsible_use"],

            "difficulty": "advanced"

        }

        

        return modules

    

    def _build_concept_graph(self):

        """

        Build a directed graph showing dependencies between concepts.

        

        Returns:

            Dictionary representing the concept dependency graph

        """

        graph = {}

        for module_id, module in self.modules.items():

            for concept in module["concepts"]:

                graph[concept] = {

                    "module": module_id,

                    "prerequisites": module["prerequisites"]

                }

        return graph

    

    def get_next_module(self, student_profile):

        """

        Determine the next appropriate module for a student.

        

        Args:

            student_profile: The student's profile object

            

        Returns:

            Module object or None if all modules are complete

        """

        for module_id, module in self.modules.items():

            if module_id in student_profile.completed_lessons:

                continue

                

            prerequisites_met = all(

                prereq in student_profile.completed_lessons 

                for prereq in module["prerequisites"]

            )

            

            if prerequisites_met:

                return module

                

        return None

    

    def is_concept_accessible(self, concept, student_profile):

        """

        Check if a student has met the prerequisites for a concept.

        

        Args:

            concept: The concept identifier to check

            student_profile: The student's profile object

            

        Returns:

            Boolean indicating if the concept is accessible

        """

        if concept not in self.concept_graph:

            return False

            

        prerequisites = self.concept_graph[concept]["prerequisites"]

        return all(

            prereq in student_profile.completed_lessons 

            for prereq in prerequisites

        )


The Curriculum Manager works closely with the Student Profile Manager to ensure that students are always presented with content that is appropriate for their current level. When a student completes a module, the system automatically determines the next module they should tackle based on the dependency graph.


The LLM Integration Layer is perhaps the most critical component, as it handles all communication with the underlying language model. This layer is responsible for constructing prompts that elicit educational responses, filtering outputs to ensure age-appropriateness, and handling errors gracefully. The integration layer uses a sophisticated prompting strategy that includes the student's context, learning objectives, and safety constraints.


Here is the LLM Integration Layer:


class LLMEducationService:

    """

    Service layer for interacting with the LLM API in an educational context.

    This class handles prompt construction, response filtering, and safety checks.

    """

    

    def __init__(self, api_client, content_filter):

        """

        Initialize the LLM education service.

        

        Args:

            api_client: Client for communicating with the LLM API

            content_filter: Filter for ensuring age-appropriate content

        """

        self.api_client = api_client

        self.content_filter = content_filter

        self.system_prompt = self._build_system_prompt()

        

    def _build_system_prompt(self):

        """

        Construct the system prompt that defines the AI's educational role.

        

        Returns:

            String containing the complete system prompt

        """

        return """You are an educational AI assistant designed to teach children 

        aged 8-14 about artificial intelligence and large language models. Your 

        responses should be:

        

        1. Age-appropriate and easy to understand

        2. Accurate but simplified for young learners

        3. Engaging and encouraging

        4. Free from technical jargon unless explaining it

        5. Focused on building understanding, not just providing answers

        

        Use analogies and examples that children can relate to. When explaining 

        complex concepts, break them down into smaller, digestible pieces. Always 

        be honest about what you don't know or what AI cannot do. Encourage 

        critical thinking by asking questions back to the student.

        

        Never provide information that could be harmful, inappropriate, or scary 

        for children. If asked about sensitive topics, redirect to age-appropriate 

        educational content."""

    

    def generate_response(self, student_question, student_profile, lesson_context):

        """

        Generate an educational response to a student's question.

        

        Args:

            student_question: The question asked by the student

            student_profile: The student's profile object

            lesson_context: Current lesson or module context

            

        Returns:

            String containing the AI's response

        """

        # Build the complete prompt with context

        full_prompt = self._construct_contextual_prompt(

            student_question, 

            student_profile, 

            lesson_context

        )

        

        # Query the LLM API

        raw_response = self.api_client.complete(

            system_prompt=self.system_prompt,

            user_prompt=full_prompt,

            temperature=0.7,

            max_tokens=500

        )

        

        # Filter the response for safety and appropriateness

        filtered_response = self.content_filter.filter(

            raw_response, 

            student_profile.age

        )

        

        return filtered_response

    

    def _construct_contextual_prompt(self, question, profile, context):

        """

        Build a prompt that includes relevant context about the student.

        

        Args:

            question: The student's question

            profile: Student profile object

            context: Current learning context

            

        Returns:

            String containing the complete prompt

        """

        prompt_parts = []

        

        # Add student context

        prompt_parts.append(f"Student age: {profile.age}")

        prompt_parts.append(f"Current level: {profile.current_level}")

        

        # Add learning context

        if context:

            prompt_parts.append(f"Current lesson: {context.get('title', 'General')}")

            prompt_parts.append(f"Lesson focus: {context.get('description', '')}")

        

        # Add mastered concepts

        if profile.mastered_concepts:

            concepts_str = ", ".join(list(profile.mastered_concepts)[:5])

            prompt_parts.append(f"Student has learned about: {concepts_str}")

        

        # Add the actual question

        prompt_parts.append(f"\nStudent question: {question}")

        

        return "\n".join(prompt_parts)

    

    def generate_lesson_content(self, module, profile):

        """

        Generate interactive lesson content for a specific module.

        

        Args:

            module: The module object to generate content for

            profile: Student profile object

            

        Returns:

            Dictionary containing lesson content and interactive elements

        """

        content_prompt = f"""Create an engaging lesson introduction for the module 

        titled '{module['title']}'. The lesson should:

        

        - Start with a relatable question or scenario

        - Introduce the main concepts: {', '.join(module['concepts'])}

        - Include an interactive example or thought experiment

        - Be appropriate for a {profile.age}-year-old student

        - Take about 5-7 minutes to complete

        

        Format the response as a structured lesson with clear sections."""

        

        lesson_content = self.api_client.complete(

            system_prompt=self.system_prompt,

            user_prompt=content_prompt,

            temperature=0.8,

            max_tokens=800

        )

        

        return {

            "content": lesson_content,

            "module_id": module["id"],

            "interactive_elements": self._extract_interactive_elements(lesson_content)

        }

    

    def _extract_interactive_elements(self, content):

        """

        Identify interactive elements in lesson content.

        

        Args:

            content: The lesson content string

            

        Returns:

            List of interactive element definitions

        """

        # This would parse the content to identify questions, 

        # activities, or experiments embedded in the lesson

        elements = []

        

        # Simple heuristic: look for questions

        lines = content.split('\n')

        for i, line in enumerate(lines):

            if '?' in line and len(line) < 200:

                elements.append({

                    "type": "question",

                    "content": line.strip(),

                    "position": i

                })

        

        return elements


The LLM Integration Layer demonstrates several important design principles. First, it separates the concerns of prompt construction, API communication, and content filtering. Second, it maintains context about the student and their learning journey, ensuring that responses are personalized. Third, it includes safety mechanisms to filter inappropriate content before it reaches the student.


The Content Filter is a crucial safety component that examines all LLM outputs before they are displayed to students. This filter checks for age-inappropriate language, potentially scary or disturbing content, misinformation about AI capabilities, and any content that might undermine the educational objectives. The filter uses a combination of keyword matching, sentiment analysis, and rule-based logic.


class ContentFilter:

    """

    Filters LLM responses to ensure they are safe and appropriate for children.

    This class implements multiple filtering strategies to protect young users.

    """

    

    def __init__(self):

        """Initialize the content filter with filtering rules and word lists."""

        self.inappropriate_words = self._load_inappropriate_words()

        self.scary_concepts = self._load_scary_concepts()

        self.age_thresholds = self._define_age_thresholds()

        

    def _load_inappropriate_words(self):

        """

        Load list of words that are inappropriate for children.

        

        Returns:

            Set of inappropriate words

        """

        # In production, this would load from a comprehensive database

        return {

            "violence", "weapon", "kill", "death", "blood",

            # ... many more entries

        }

    

    def _load_scary_concepts(self):

        """

        Load concepts that might be scary for children.

        

        Returns:

            Set of potentially scary concept keywords

        """

        return {

            "ai takeover", "robot uprising", "end of humanity",

            "ai replacing humans", "job loss", "surveillance",

            # ... more entries

        }

    

    def _define_age_thresholds(self):

        """

        Define what content is appropriate for different age groups.

        

        Returns:

            Dictionary mapping ages to content restrictions

        """

        return {

            8: {"max_complexity": "simple", "avoid": ["abstract_concepts"]},

            10: {"max_complexity": "moderate", "avoid": ["advanced_math"]},

            12: {"max_complexity": "detailed", "avoid": []},

            14: {"max_complexity": "comprehensive", "avoid": []}

        }

    

    def filter(self, content, student_age):

        """

        Filter content to ensure it is appropriate for the student's age.

        

        Args:

            content: The content to filter

            student_age: Age of the student

            

        Returns:

            Filtered content string

        """

        # Check for inappropriate words

        if self._contains_inappropriate_content(content):

            return self._generate_safe_alternative()

        

        # Check for scary concepts

        if self._contains_scary_concepts(content):

            content = self._soften_scary_content(content)

        

        # Check age-appropriateness

        if not self._is_age_appropriate(content, student_age):

            content = self._simplify_content(content, student_age)

        

        # Verify educational value

        if not self._has_educational_value(content):

            return self._generate_educational_alternative()

        

        return content

    

    def _contains_inappropriate_content(self, content):

        """

        Check if content contains inappropriate words or concepts.

        

        Args:

            content: The content to check

            

        Returns:

            Boolean indicating if inappropriate content was found

        """

        content_lower = content.lower()

        return any(word in content_lower for word in self.inappropriate_words)

    

    def _contains_scary_concepts(self, content):

        """

        Check if content contains potentially scary concepts.

        

        Args:

            content: The content to check

            

        Returns:

            Boolean indicating if scary concepts were found

        """

        content_lower = content.lower()

        return any(concept in content_lower for concept in self.scary_concepts)

    

    def _soften_scary_content(self, content):

        """

        Modify content to make scary concepts less frightening.

        

        Args:

            content: The content to modify

            

        Returns:

            Modified content string

        """

        # Replace scary phrases with gentler alternatives

        replacements = {

            "ai takeover": "AI becoming very advanced",

            "replacing humans": "helping humans with tasks",

            "job loss": "changing the types of jobs available"

        }

        

        modified = content

        for scary, gentle in replacements.items():

            modified = modified.replace(scary, gentle)

        

        return modified

    

    def _is_age_appropriate(self, content, age):

        """

        Determine if content complexity matches student age.

        

        Args:

            content: The content to evaluate

            age: Student's age

            

        Returns:

            Boolean indicating if content is age-appropriate

        """

        # Simple heuristic based on sentence length and word complexity

        sentences = content.split('.')

        avg_sentence_length = sum(len(s.split()) for s in sentences) / len(sentences)

        

        if age < 10 and avg_sentence_length > 15:

            return False

        elif age < 12 and avg_sentence_length > 20:

            return False

        

        return True

    

    def _simplify_content(self, content, age):

        """

        Simplify content to match student's age level.

        

        Args:

            content: The content to simplify

            age: Student's age

            

        Returns:

            Simplified content string

        """

        # In production, this would use NLP to actually simplify

        # For now, we return a note that simplification is needed

        return content  # Placeholder for actual simplification logic

    

    def _has_educational_value(self, content):

        """

        Verify that content has educational merit.

        

        Args:

            content: The content to evaluate

            

        Returns:

            Boolean indicating if content is educational

        """

        # Check for educational keywords and structure

        educational_indicators = [

            "learn", "understand", "example", "because", "how", "why",

            "this means", "let's explore", "imagine", "think about"

        ]

        

        content_lower = content.lower()

        indicator_count = sum(

            1 for indicator in educational_indicators 

            if indicator in content_lower

        )

        

        return indicator_count >= 2

    

    def _generate_safe_alternative(self):

        """

        Generate a safe alternative response when content is inappropriate.

        

        Returns:

            Safe alternative response string

        """

        return """I want to make sure I give you information that's helpful and 

        appropriate. Let me try to answer your question in a different way. Could 

        you tell me more about what you'd like to learn?"""

    

    def _generate_educational_alternative(self):

        """

        Generate an educational alternative when content lacks value.

        

        Returns:

            Educational alternative response string

        """

        return """That's an interesting question! Let me explain this in a way 

        that will help you understand AI better. What specific part would you 

        like to learn more about?"""


The Content Filter works as a safety net, ensuring that even if the LLM generates something unexpected, it will be caught before reaching the student. This is essential for any application designed for children, where safety must be the top priority.


USER INTERFACE DESIGN


The user interface of AI Explorer is designed to be intuitive, engaging, and accessible for children. The interface uses bright colors, friendly typography, and clear visual hierarchies to guide students through their learning journey. The main interface consists of several key areas: the conversation area where students interact with the AI, the progress tracker showing completed modules and mastered concepts, the lesson selector for choosing what to learn next, and the help section with guidance for parents and teachers.

The conversation area is the heart of the interface. It displays the ongoing dialogue between the student and the AI tutor in a chat-like format that children find familiar from messaging applications. Each message is clearly attributed to either the student or the AI, with distinct visual styling. The AI's messages use a friendly avatar and a warm color scheme, while the student's messages appear in a different style to create clear visual distinction.


Here is the JavaScript code that manages the conversation interface:


/**

 * ConversationManager handles the chat interface and message display.

 * This class manages the DOM manipulation for the conversation area

 * and coordinates with the backend API.

 */

class ConversationManager {

    constructor(conversationElement, inputElement, sendButton) {

        this.conversationElement = conversationElement;

        this.inputElement = inputElement;

        this.sendButton = sendButton;

        this.messageHistory = [];

        this.isWaitingForResponse = false;

        

        this.initializeEventListeners();

    }

    

    /**

     * Set up event listeners for user interactions.

     */

    initializeEventListeners() {

        this.sendButton.addEventListener('click', () => {

            this.handleSendMessage();

        });

        

        this.inputElement.addEventListener('keypress', (event) => {

            if (event.key === 'Enter' && !event.shiftKey) {

                event.preventDefault();

                this.handleSendMessage();

            }

        });

    }

    

    /**

     * Handle sending a message from the student.

     */

    async handleSendMessage() {

        const messageText = this.inputElement.value.trim();

        

        if (messageText === '' || this.isWaitingForResponse) {

            return;

        }

        

        // Display the student's message

        this.displayMessage(messageText, 'student');

        

        // Clear the input

        this.inputElement.value = '';

        

        // Show typing indicator

        this.showTypingIndicator();

        

        // Send to backend and wait for response

        this.isWaitingForResponse = true;

        try {

            const response = await this.sendToBackend(messageText);

            this.hideTypingIndicator();

            this.displayMessage(response.message, 'ai');

            

            // Update progress if the response includes it

            if (response.progress) {

                this.updateProgress(response.progress);

            }

        } catch (error) {

            this.hideTypingIndicator();

            this.displayError('Sorry, I had trouble understanding that. Could you try again?');

        } finally {

            this.isWaitingForResponse = false;

        }

    }

    

    /**

     * Display a message in the conversation area.

     

     * @param {string} text - The message text to display

     * @param {string} sender - Either 'student' or 'ai'

     */

    displayMessage(text, sender) {

        const messageDiv = document.createElement('div');

        messageDiv.className = `message message-${sender}`;

        

        const avatarDiv = document.createElement('div');

        avatarDiv.className = `avatar avatar-${sender}`;

        

        const contentDiv = document.createElement('div');

        contentDiv.className = 'message-content';

        contentDiv.textContent = text;

        

        const timestampDiv = document.createElement('div');

        timestampDiv.className = 'message-timestamp';

        timestampDiv.textContent = this.getCurrentTime();

        

        messageDiv.appendChild(avatarDiv);

        messageDiv.appendChild(contentDiv);

        messageDiv.appendChild(timestampDiv);

        

        this.conversationElement.appendChild(messageDiv);

        

        // Store in history

        this.messageHistory.push({

            text: text,

            sender: sender,

            timestamp: new Date()

        });

        

        // Scroll to bottom

        this.scrollToBottom();

    }

    

    /**

     * Show a typing indicator while waiting for AI response.

     */

    showTypingIndicator() {

        const indicator = document.createElement('div');

        indicator.className = 'typing-indicator';

        indicator.id = 'typing-indicator';

        

        for (let i = 0; i < 3; i++) {

            const dot = document.createElement('span');

            dot.className = 'typing-dot';

            indicator.appendChild(dot);

        }

        

        this.conversationElement.appendChild(indicator);

        this.scrollToBottom();

    }

    

    /**

     * Hide the typing indicator.

     */

    hideTypingIndicator() {

        const indicator = document.getElementById('typing-indicator');

        if (indicator) {

            indicator.remove();

        }

    }

    

    /**

     * Send a message to the backend API.

     

     * @param {string} message - The message to send

     * @returns {Promise} Promise resolving to the API response

     */

    async sendToBackend(message) {

        const response = await fetch('/api/chat', {

            method: 'POST',

            headers: {

                'Content-Type': 'application/json',

            },

            body: JSON.stringify({

                message: message,

                session_id: this.getSessionId()

            })

        });

        

        if (!response.ok) {

            throw new Error('Network response was not ok');

        }

        

        return await response.json();

    }

    

    /**

     * Get the current session ID from storage.

     

     * @returns {string} The session ID

     */

    getSessionId() {

        return sessionStorage.getItem('session_id') || this.createNewSession();

    }

    

    /**

     * Create a new session ID.

     

     * @returns {string} The new session ID

     */

    createNewSession() {

        const sessionId = 'session_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);

        sessionStorage.setItem('session_id', sessionId);

        return sessionId;

    }

    

    /**

     * Get current time formatted for display.

     

     * @returns {string} Formatted time string

     */

    getCurrentTime() {

        const now = new Date();

        return now.toLocaleTimeString('en-US', { 

            hour: '2-digit', 

            minute: '2-digit' 

        });

    }

    

    /**

     * Scroll the conversation area to the bottom.

     */

    scrollToBottom() {

        this.conversationElement.scrollTop = this.conversationElement.scrollHeight;

    }

    

    /**

     * Display an error message to the user.

     

     * @param {string} errorText - The error message to display

     */

    displayError(errorText) {

        const errorDiv = document.createElement('div');

        errorDiv.className = 'message message-error';

        errorDiv.textContent = errorText;

        this.conversationElement.appendChild(errorDiv);

        this.scrollToBottom();

    }

    

    /**

     * Update the progress display based on backend data.

     

     * @param {Object} progressData - Progress information from backend

     */

    updateProgress(progressData) {

        const progressEvent = new CustomEvent('progressUpdate', {

            detail: progressData

        });

        document.dispatchEvent(progressEvent);

    }

}


The conversation manager handles all aspects of the chat interface, from displaying messages to managing the communication with the backend. It provides visual feedback through typing indicators and ensures that the interface remains responsive even when waiting for the AI to generate a response.


The progress tracker is another important interface element. It shows students what they have accomplished and what comes next in their learning journey. The tracker displays completed modules as colorful badges, shows the current module with a progress bar, and previews upcoming modules that will unlock as prerequisites are met. This gamification element motivates students to continue learning and provides a sense of achievement.


The lesson selector allows students to choose what they want to learn about within the constraints of the curriculum structure. Students can select from available modules, review completed lessons, or ask free-form questions. The interface makes it clear which modules are currently accessible and which require completing prerequisites first.


EDUCATIONAL CONTENT STRATEGY


The educational content strategy of AI Explorer is built on several pedagogical principles. The first principle is progressive disclosure, where complex concepts are introduced gradually, building on previously mastered ideas. Students start with concrete, relatable examples before moving to more abstract concepts. The second principle is active learning, where students learn by doing rather than just reading. The application includes interactive experiments, thought exercises, and opportunities to test their understanding. The third principle is immediate feedback, where students receive responses to their questions and actions right away, reinforcing correct understanding and gently correcting misconceptions.


The content is organized around key learning objectives. For the introductory module on artificial intelligence, the learning objectives include understanding that AI is software that can learn from data, recognizing examples of AI in everyday life, and distinguishing between AI and human intelligence. For the module on language models, objectives include understanding that language models predict text based on patterns, recognizing that they do not truly understand meaning, and identifying appropriate uses for language models.


Each module uses a consistent structure. The module begins with an engaging hook that connects to the student's experience. For example, the language models module might start by asking if the student has ever used autocomplete on their phone. The module then presents core concepts through explanation and examples. Interactive elements are woven throughout to maintain engagement. The module concludes with a knowledge check that assesses understanding and a preview of what comes next.


The application uses several types of interactive elements. Question prompts ask students to think about concepts before the answer is revealed. Experiments allow students to try things themselves, such as seeing how the AI responds to different types of questions. Analogies help explain complex ideas through familiar comparisons. For instance, training an AI might be compared to learning to ride a bike, where practice with feedback leads to improvement.


Here is an example of how lesson content is structured:


class LessonContent:

    """

    Represents the content and structure of an educational lesson.

    This class encapsulates all elements of a lesson including text,

    interactive components, and assessment items.

    """

    

    def __init__(self, lesson_id, title, module_id):

        """

        Initialize a new lesson.

        

        Args:

            lesson_id: Unique identifier for the lesson

            title: Display title of the lesson

            module_id: ID of the parent module

        """

        self.lesson_id = lesson_id

        self.title = title

        self.module_id = module_id

        self.sections = []

        self.interactive_elements = []

        self.knowledge_checks = []

        

    def add_section(self, section_type, content, metadata=None):

        """

        Add a section to the lesson.

        

        Args:

            section_type: Type of section (text, example, analogy, etc)

            content: The actual content of the section

            metadata: Optional additional information about the section

        """

        section = {

            "type": section_type,

            "content": content,

            "metadata": metadata or {},

            "order": len(self.sections)

        }

        self.sections.append(section)

        

    def add_interactive_element(self, element_type, prompt, expected_response=None):

        """

        Add an interactive element to the lesson.

        

        Args:

            element_type: Type of interaction (question, experiment, etc)

            prompt: The prompt or instruction for the student

            expected_response: Optional expected response for validation

        """

        element = {

            "type": element_type,

            "prompt": prompt,

            "expected_response": expected_response,

            "order": len(self.interactive_elements)

        }

        self.interactive_elements.append(element)

        

    def add_knowledge_check(self, question, correct_answer, explanation):

        """

        Add a knowledge check question to assess understanding.

        

        Args:

            question: The question to ask

            correct_answer: The correct answer

            explanation: Explanation of why this is correct

        """

        check = {

            "question": question,

            "correct_answer": correct_answer,

            "explanation": explanation,

            "order": len(self.knowledge_checks)

        }

        self.knowledge_checks.append(check)

        

    def get_ordered_content(self):

        """

        Get all lesson content in the correct presentation order.

        

        Returns:

            List of content items in order

        """

        all_content = []

        

        section_index = 0

        interactive_index = 0

        

        # Interleave sections and interactive elements

        while section_index < len(self.sections) or interactive_index < len(self.interactive_elements):

            # Add a section if available

            if section_index < len(self.sections):

                all_content.append({

                    "category": "section",

                    "data": self.sections[section_index]

                })

                section_index += 1

            

            # Add an interactive element every few sections

            if interactive_index < len(self.interactive_elements) and section_index % 3 == 0:

                all_content.append({

                    "category": "interactive",

                    "data": self.interactive_elements[interactive_index]

                })

                interactive_index += 1

        

        # Add remaining interactive elements

        while interactive_index < len(self.interactive_elements):

            all_content.append({

                "category": "interactive",

                "data": self.interactive_elements[interactive_index]

            })

            interactive_index += 1

        

        # Add knowledge checks at the end

        for check in self.knowledge_checks:

            all_content.append({

                "category": "knowledge_check",

                "data": check

            })

        

        return all_content

    

    def to_dict(self):

        """

        Convert the lesson to a dictionary for serialization.

        

        Returns:

            Dictionary representation of the lesson

        """

        return {

            "lesson_id": self.lesson_id,

            "title": self.title,

            "module_id": self.module_id,

            "sections": self.sections,

            "interactive_elements": self.interactive_elements,

            "knowledge_checks": self.knowledge_checks

        }



class LessonBuilder:

    """

    Builder class for constructing complete lessons with all components.

    This class provides a fluent interface for creating rich lesson content.

    """

    

    def __init__(self, curriculum_manager, llm_service):

        """

        Initialize the lesson builder.

        

        Args:

            curriculum_manager: Manager for curriculum structure

            llm_service: Service for generating dynamic content

        """

        self.curriculum_manager = curriculum_manager

        self.llm_service = llm_service

        

    def build_lesson(self, module_id, student_profile):

        """

        Build a complete lesson for a given module.

        

        Args:

            module_id: ID of the module to build a lesson for

            student_profile: Profile of the student taking the lesson

            

        Returns:

            Complete LessonContent object

        """

        module = self.curriculum_manager.modules.get(module_id)

        if not module:

            raise ValueError(f"Module {module_id} not found")

        

        lesson = LessonContent(

            lesson_id=f"lesson_{module_id}_{student_profile.student_id}",

            title=module["title"],

            module_id=module_id

        )

        

        # Build introduction section

        intro = self._build_introduction(module, student_profile)

        lesson.add_section("introduction", intro)

        

        # Build concept sections for each concept in the module

        for concept in module["concepts"]:

            concept_content = self._build_concept_section(concept, student_profile)

            lesson.add_section("concept", concept_content, {"concept_id": concept})

            

            # Add interactive element after each concept

            interactive = self._build_interactive_element(concept, student_profile)

            lesson.add_interactive_element(

                interactive["type"],

                interactive["prompt"],

                interactive.get("expected_response")

            )

        

        # Build summary section

        summary = self._build_summary(module, student_profile)

        lesson.add_section("summary", summary)

        

        # Add knowledge checks

        checks = self._build_knowledge_checks(module, student_profile)

        for check in checks:

            lesson.add_knowledge_check(

                check["question"],

                check["correct_answer"],

                check["explanation"]

            )

        

        return lesson

    

    def _build_introduction(self, module, profile):

        """

        Build an engaging introduction for the module.

        

        Args:

            module: Module object

            profile: Student profile

            

        Returns:

            Introduction text

        """

        prompt = f"""Create an engaging introduction for a lesson titled 

        '{module['title']}' for a {profile.age}-year-old student. The introduction 

        should start with a relatable question or scenario that connects to their 

        everyday experience. Keep it to 2-3 short paragraphs."""

        

        return self.llm_service.api_client.complete(

            system_prompt=self.llm_service.system_prompt,

            user_prompt=prompt,

            temperature=0.8,

            max_tokens=300

        )

    

    def _build_concept_section(self, concept, profile):

        """

        Build content explaining a specific concept.

        

        Args:

            concept: Concept identifier

            profile: Student profile

            

        Returns:

            Concept explanation text

        """

        prompt = f"""Explain the concept of '{concept}' to a {profile.age}-year-old 

        student learning about AI. Use simple language, provide a concrete example, 

        and include an analogy to something familiar. Keep it to 3-4 paragraphs."""

        

        return self.llm_service.api_client.complete(

            system_prompt=self.llm_service.system_prompt,

            user_prompt=prompt,

            temperature=0.7,

            max_tokens=400

        )

    

    def _build_interactive_element(self, concept, profile):

        """

        Create an interactive element for a concept.

        

        Args:

            concept: Concept identifier

            profile: Student profile

            

        Returns:

            Dictionary describing the interactive element

        """

        # Different types of interactive elements based on concept

        if "definition" in concept or "what" in concept:

            return {

                "type": "question",

                "prompt": f"In your own words, what do you think {concept.replace('_', ' ')} means?",

                "expected_response": None  # Open-ended

            }

        elif "example" in concept:

            return {

                "type": "experiment",

                "prompt": f"Can you think of an example of {concept.replace('_', ' ')} from your own life?",

                "expected_response": None

            }

        else:

            return {

                "type": "reflection",

                "prompt": f"Why do you think {concept.replace('_', ' ')} is important?",

                "expected_response": None

            }

    

    def _build_summary(self, module, profile):

        """

        Build a summary section for the module.

        

        Args:

            module: Module object

            profile: Student profile

            

        Returns:

            Summary text

        """

        concepts_str = ", ".join(module["concepts"])

        prompt = f"""Create a brief summary of a lesson about '{module['title']}' 

        that covered these concepts: {concepts_str}. The summary should reinforce 

        key points and encourage the {profile.age}-year-old student. Keep it to 

        2 paragraphs."""

        

        return self.llm_service.api_client.complete(

            system_prompt=self.llm_service.system_prompt,

            user_prompt=prompt,

            temperature=0.7,

            max_tokens=250

        )

    

    def _build_knowledge_checks(self, module, profile):

        """

        Build knowledge check questions for the module.

        

        Args:

            module: Module object

            profile: Student profile

            

        Returns:

            List of knowledge check dictionaries

        """

        checks = []

        

        for concept in module["concepts"]:

            prompt = f"""Create a simple multiple-choice question to check if a 

            {profile.age}-year-old student understands '{concept}'. Provide the 

            question, the correct answer, and a brief explanation."""

            

            # In production, this would parse the LLM response into structured data

            # For now, we'll create a simple check

            checks.append({

                "question": f"What have you learned about {concept.replace('_', ' ')}?",

                "correct_answer": "Understanding varies by student",

                "explanation": f"This concept is about {concept.replace('_', ' ')}"

            })

        

        return checks


The lesson builder demonstrates how the application creates dynamic, personalized content for each student. By using the LLM to generate portions of the lesson content, the application can adapt to different age levels and learning styles while maintaining educational quality through the filtering and validation layers.


IMPLEMENTATION DETAILS


The implementation of AI Explorer involves several technical decisions that balance educational effectiveness with practical considerations. The backend is built using Flask, a lightweight Python web framework that provides the necessary functionality without excessive complexity. Flask was chosen because it is well-documented, has a large community, and integrates easily with Python's data science and machine learning libraries.


The application uses a SQLite database for storing student profiles, progress data, and lesson content. SQLite was chosen for its simplicity and the fact that it requires no separate server process, making deployment easier. For a production system serving many students, this could be upgraded to PostgreSQL or another more robust database system without changing the application logic, thanks to the use of an abstraction layer.


Here is the database schema and access layer:


import sqlite3

from datetime import datetime

import json



class DatabaseManager:

    """

    Manages all database operations for the AI Explorer application.

    This class provides a clean interface for data persistence while

    hiding the underlying database implementation details.

    """

    

    def __init__(self, database_path):

        """

        Initialize the database manager.

        

        Args:

            database_path: Path to the SQLite database file

        """

        self.database_path = database_path

        self.initialize_database()

        

    def initialize_database(self):

        """

        Create all necessary tables if they don't exist.

        This method is idempotent and safe to call multiple times.

        """

        conn = self.get_connection()

        cursor = conn.cursor()

        

        # Students table

        cursor.execute("""

            CREATE TABLE IF NOT EXISTS students (

                student_id TEXT PRIMARY KEY,

                name TEXT NOT NULL,

                age INTEGER NOT NULL,

                current_level TEXT NOT NULL,

                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

                last_active TIMESTAMP

            )

        """)

        

        # Progress table

        cursor.execute("""

            CREATE TABLE IF NOT EXISTS progress (

                id INTEGER PRIMARY KEY AUTOINCREMENT,

                student_id TEXT NOT NULL,

                module_id TEXT NOT NULL,

                completed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

                score REAL,

                FOREIGN KEY (student_id) REFERENCES students(student_id),

                UNIQUE(student_id, module_id)

            )

        """)

        

        # Mastered concepts table

        cursor.execute("""

            CREATE TABLE IF NOT EXISTS mastered_concepts (

                id INTEGER PRIMARY KEY AUTOINCREMENT,

                student_id TEXT NOT NULL,

                concept_id TEXT NOT NULL,

                mastered_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

                confidence_level REAL,

                FOREIGN KEY (student_id) REFERENCES students(student_id),

                UNIQUE(student_id, concept_id)

            )

        """)

        

        # Interactions table for tracking all student interactions

        cursor.execute("""

            CREATE TABLE IF NOT EXISTS interactions (

                id INTEGER PRIMARY KEY AUTOINCREMENT,

                student_id TEXT NOT NULL,

                interaction_type TEXT NOT NULL,

                content TEXT,

                response TEXT,

                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

                FOREIGN KEY (student_id) REFERENCES students(student_id)

            )

        """)

        

        # Sessions table

        cursor.execute("""

            CREATE TABLE IF NOT EXISTS sessions (

                session_id TEXT PRIMARY KEY,

                student_id TEXT NOT NULL,

                started_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

                last_activity TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

                FOREIGN KEY (student_id) REFERENCES students(student_id)

            )

        """)

        

        conn.commit()

        conn.close()

    

    def get_connection(self):

        """

        Get a database connection.

        

        Returns:

            SQLite connection object

        """

        conn = sqlite3.connect(self.database_path)

        conn.row_factory = sqlite3.Row  # Enable column access by name

        return conn

    

    def create_student(self, student_id, name, age):

        """

        Create a new student record.

        

        Args:

            student_id: Unique identifier for the student

            name: Student's name

            age: Student's age

            

        Returns:

            StudentProfile object

        """

        conn = self.get_connection()

        cursor = conn.cursor()

        

        # Determine initial level based on age

        if age < 10:

            level = "beginner"

        elif age < 12:

            level = "intermediate"

        else:

            level = "advanced"

        

        cursor.execute("""

            INSERT INTO students (student_id, name, age, current_level, last_active)

            VALUES (?, ?, ?, ?, ?)

        """, (student_id, name, age, level, datetime.now()))

        

        conn.commit()

        conn.close()

        

        return StudentProfile(student_id, age, name)

    

    def get_student(self, student_id):

        """

        Retrieve a student's profile from the database.

        

        Args:

            student_id: The student's unique identifier

            

        Returns:

            StudentProfile object or None if not found

        """

        conn = self.get_connection()

        cursor = conn.cursor()

        

        cursor.execute("""

            SELECT * FROM students WHERE student_id = ?

        """, (student_id,))

        

        row = cursor.fetchone()

        conn.close()

        

        if not row:

            return None

        

        profile = StudentProfile(row["student_id"], row["age"], row["name"])

        profile.current_level = row["current_level"]

        profile.last_active = row["last_active"]

        

        # Load completed lessons

        profile.completed_lessons = self.get_completed_lessons(student_id)

        

        # Load mastered concepts

        profile.mastered_concepts = self.get_mastered_concepts(student_id)

        

        # Get interaction count

        profile.interaction_count = self.get_interaction_count(student_id)

        

        return profile

    

    def get_completed_lessons(self, student_id):

        """

        Get all lessons completed by a student.

        

        Args:

            student_id: The student's unique identifier

            

        Returns:

            Set of completed lesson IDs

        """

        conn = self.get_connection()

        cursor = conn.cursor()

        

        cursor.execute("""

            SELECT module_id FROM progress WHERE student_id = ?

        """, (student_id,))

        

        lessons = {row["module_id"] for row in cursor.fetchall()}

        conn.close()

        

        return lessons

    

    def get_mastered_concepts(self, student_id):

        """

        Get all concepts mastered by a student.

        

        Args:

            student_id: The student's unique identifier

            

        Returns:

            Set of mastered concept IDs

        """

        conn = self.get_connection()

        cursor = conn.cursor()

        

        cursor.execute("""

            SELECT concept_id FROM mastered_concepts WHERE student_id = ?

        """, (student_id,))

        

        concepts = {row["concept_id"] for row in cursor.fetchall()}

        conn.close()

        

        return concepts

    

    def get_interaction_count(self, student_id):

        """

        Get the total number of interactions for a student.

        

        Args:

            student_id: The student's unique identifier

            

        Returns:

            Integer count of interactions

        """

        conn = self.get_connection()

        cursor = conn.cursor()

        

        cursor.execute("""

            SELECT COUNT(*) as count FROM interactions WHERE student_id = ?

        """, (student_id,))

        

        count = cursor.fetchone()["count"]

        conn.close()

        

        return count

    

    def mark_lesson_complete(self, student_id, module_id, score=None):

        """

        Mark a lesson as completed for a student.

        

        Args:

            student_id: The student's unique identifier

            module_id: The module that was completed

            score: Optional score for the lesson

        """

        conn = self.get_connection()

        cursor = conn.cursor()

        

        cursor.execute("""

            INSERT OR REPLACE INTO progress (student_id, module_id, score, completed_at)

            VALUES (?, ?, ?, ?)

        """, (student_id, module_id, score, datetime.now()))

        

        conn.commit()

        conn.close()

    

    def add_mastered_concept(self, student_id, concept_id, confidence=1.0):

        """

        Add a concept to the student's mastered concepts.

        

        Args:

            student_id: The student's unique identifier

            concept_id: The concept that was mastered

            confidence: Confidence level (0.0 to 1.0)

        """

        conn = self.get_connection()

        cursor = conn.cursor()

        

        cursor.execute("""

            INSERT OR REPLACE INTO mastered_concepts 

            (student_id, concept_id, confidence_level, mastered_at)

            VALUES (?, ?, ?, ?)

        """, (student_id, concept_id, confidence, datetime.now()))

        

        conn.commit()

        conn.close()

    

    def log_interaction(self, student_id, interaction_type, content, response):

        """

        Log an interaction between the student and the system.

        

        Args:

            student_id: The student's unique identifier

            interaction_type: Type of interaction (question, lesson, etc)

            content: The student's input

            response: The system's response

        """

        conn = self.get_connection()

        cursor = conn.cursor()

        

        cursor.execute("""

            INSERT INTO interactions (student_id, interaction_type, content, response)

            VALUES (?, ?, ?, ?)

        """, (student_id, interaction_type, content, response))

        

        conn.commit()

        conn.close()

    

    def create_session(self, session_id, student_id):

        """

        Create a new session for a student.

        

        Args:

            session_id: Unique session identifier

            student_id: The student's unique identifier

        """

        conn = self.get_connection()

        cursor = conn.cursor()

        

        cursor.execute("""

            INSERT INTO sessions (session_id, student_id)

            VALUES (?, ?)

        """, (session_id, student_id))

        

        conn.commit()

        conn.close()

    

    def update_session_activity(self, session_id):

        """

        Update the last activity timestamp for a session.

        

        Args:

            session_id: The session identifier

        """

        conn = self.get_connection()

        cursor = conn.cursor()

        

        cursor.execute("""

            UPDATE sessions SET last_activity = ? WHERE session_id = ?

        """, (datetime.now(), session_id))

        

        conn.commit()

        conn.close()

    

    def get_session_student(self, session_id):

        """

        Get the student ID associated with a session.

        

        Args:

            session_id: The session identifier

            

        Returns:

            Student ID or None if session not found

        """

        conn = self.get_connection()

        cursor = conn.cursor()

        

        cursor.execute("""

            SELECT student_id FROM sessions WHERE session_id = ?

        """, (session_id,))

        

        row = cursor.fetchone()

        conn.close()

        

        return row["student_id"] if row else None


The database manager provides a clean abstraction over the database operations, making it easy to work with student data without worrying about SQL syntax throughout the application. This follows the repository pattern from clean architecture, where data access is isolated from business logic.


Session management is critical for maintaining state across multiple interactions. When a student first visits the application, a new session is created and associated with their student profile. The session ID is stored in the browser's session storage and sent with each request to the backend. This allows the system to maintain context about the ongoing conversation and the student's current position in the curriculum.


The API client for communicating with the LLM service is designed to be flexible and handle various scenarios including rate limiting, timeouts, and errors. Here is the implementation:


import requests

import time

from typing import Optional, Dict, Any



class LLMAPIClient:

    """

    Client for communicating with the LLM API.

    This class handles all HTTP communication, error handling,

    and retry logic for LLM interactions.

    """

    

    def __init__(self, api_key, base_url, model_name="gpt-3.5-turbo"):

        """

        Initialize the API client.

        

        Args:

            api_key: API key for authentication

            base_url: Base URL for the API endpoint

            model_name: Name of the model to use

        """

        self.api_key = api_key

        self.base_url = base_url

        self.model_name = model_name

        self.max_retries = 3

        self.retry_delay = 1.0

        

    def complete(self, system_prompt, user_prompt, temperature=0.7, max_tokens=500):

        """

        Generate a completion from the LLM.

        

        Args:

            system_prompt: System-level instructions for the LLM

            user_prompt: The user's prompt

            temperature: Sampling temperature (0.0 to 1.0)

            max_tokens: Maximum tokens in the response

            

        Returns:

            String containing the LLM's response

            

        Raises:

            Exception: If the API call fails after all retries

        """

        messages = [

            {"role": "system", "content": system_prompt},

            {"role": "user", "content": user_prompt}

        ]

        

        for attempt in range(self.max_retries):

            try:

                response = self._make_request(messages, temperature, max_tokens)

                return self._extract_content(response)

            except Exception as e:

                if attempt < self.max_retries - 1:

                    time.sleep(self.retry_delay * (attempt + 1))

                    continue

                else:

                    raise Exception(f"API call failed after {self.max_retries} attempts: {str(e)}")

    

    def _make_request(self, messages, temperature, max_tokens):

        """

        Make the actual HTTP request to the API.

        

        Args:

            messages: List of message dictionaries

            temperature: Sampling temperature

            max_tokens: Maximum tokens in response

            

        Returns:

            Response object from the API

        """

        headers = {

            "Authorization": f"Bearer {self.api_key}",

            "Content-Type": "application/json"

        }

        

        payload = {

            "model": self.model_name,

            "messages": messages,

            "temperature": temperature,

            "max_tokens": max_tokens

        }

        

        response = requests.post(

            f"{self.base_url}/chat/completions",

            headers=headers,

            json=payload,

            timeout=30

        )

        

        response.raise_for_status()

        return response.json()

    

    def _extract_content(self, response):

        """

        Extract the content from the API response.

        

        Args:

            response: The API response dictionary

            

        Returns:

            String containing the response content

        """

        if "choices" in response and len(response["choices"]) > 0:

            return response["choices"][0]["message"]["content"]

        else:

            raise Exception("Unexpected response format from API")


The API client includes retry logic to handle transient failures, timeout handling to prevent the application from hanging, and proper error handling to provide meaningful feedback when things go wrong.


SAFETY AND PRIVACY CONSIDERATIONS


Safety and privacy are paramount when building applications for children. AI Explorer implements multiple layers of protection to ensure that children have a safe, positive experience. The first layer is content filtering, which we discussed earlier. Every response from the LLM passes through multiple filters before being displayed to the student.


The second layer is prompt engineering. The system prompts that guide the LLM's behavior are carefully crafted to encourage safe, educational responses. The prompts explicitly instruct the LLM to avoid inappropriate content, to redirect sensitive questions to educational topics, and to maintain an encouraging, supportive tone. The prompts also include examples of appropriate responses to help guide the LLM's behavior.


The third layer is monitoring and logging. Every interaction is logged to the database, allowing parents, teachers, and administrators to review what children are learning and how they are interacting with the system. This transparency builds trust and allows for continuous improvement of the educational content. The logs also enable detection of any problematic patterns, such as a student repeatedly asking about topics outside the educational scope.


Privacy protection is implemented through several mechanisms. The application collects only the minimum necessary information about students: a unique identifier, age, and display name. No personally identifiable information such as full names, email addresses, or location data is required. Student data is stored securely in the database with appropriate access controls. The application does not share student data with third parties, and parents have the ability to request deletion of their child's data at any time.

The application also implements age-appropriate authentication. For younger students, a simple code or password is sufficient. For older students, more traditional username and password authentication is used. Parents can set up accounts for their children and monitor their progress through a separate parent dashboard.


Here is the authentication and authorization system:


import hashlib

import secrets

from datetime import datetime, timedelta



class AuthenticationManager:

    """

    Manages authentication and authorization for the application.

    This class handles user login, session management, and access control.

    """

    

    def __init__(self, database_manager):

        """

        Initialize the authentication manager.

        

        Args:

            database_manager: Database manager instance

        """

        self.db = database_manager

        self.session_duration = timedelta(hours=2)

        

    def create_student_account(self, name, age, parent_email):

        """

        Create a new student account with parental consent.

        

        Args:

            name: Student's display name

            age: Student's age

            parent_email: Parent's email for verification

            

        Returns:

            Dictionary with student_id and access_code

        """

        # Generate a unique student ID

        student_id = self._generate_student_id()

        

        # Generate a simple access code for younger students

        if age < 12:

            access_code = self._generate_simple_code()

        else:

            access_code = None  # Will use password instead

        

        # Create the student record

        self.db.create_student(student_id, name, age)

        

        # Store authentication credentials

        self._store_credentials(student_id, access_code, parent_email)

        

        return {

            "student_id": student_id,

            "access_code": access_code,

            "requires_password": access_code is None

        }

    

    def authenticate_student(self, student_id, credential):

        """

        Authenticate a student using their credentials.

        

        Args:

            student_id: The student's unique identifier

            credential: Access code or password

            

        Returns:

            Session ID if authentication successful, None otherwise

        """

        # Verify the credential

        if not self._verify_credential(student_id, credential):

            return None

        

        # Create a new session

        session_id = self._generate_session_id()

        self.db.create_session(session_id, student_id)

        

        return session_id

    

    def validate_session(self, session_id):

        """

        Validate that a session is still active and not expired.

        

        Args:

            session_id: The session identifier

            

        Returns:

            Student ID if session is valid, None otherwise

        """

        student_id = self.db.get_session_student(session_id)

        

        if not student_id:

            return None

        

        # Update session activity

        self.db.update_session_activity(session_id)

        

        return student_id

    

    def _generate_student_id(self):

        """

        Generate a unique student identifier.

        

        Returns:

            String containing the unique ID

        """

        return "student_" + secrets.token_hex(8)

    

    def _generate_simple_code(self):

        """

        Generate a simple 4-digit access code for young students.

        

        Returns:

            String containing the 4-digit code

        """

        return str(secrets.randbelow(9000) + 1000)

    

    def _generate_session_id(self):

        """

        Generate a unique session identifier.

        

        Returns:

            String containing the session ID

        """

        return "session_" + secrets.token_hex(16)

    

    def _store_credentials(self, student_id, access_code, parent_email):

        """

        Store authentication credentials securely.

        

        Args:

            student_id: The student's unique identifier

            access_code: The access code or password

            parent_email: Parent's email address

        """

        # In production, this would hash the credentials and store them

        # This is a simplified version for illustration

        pass

    

    def _verify_credential(self, student_id, credential):

        """

        Verify that a credential matches the stored value.

        

        Args:

            student_id: The student's unique identifier

            credential: The credential to verify

            

        Returns:

            Boolean indicating if credential is valid

        """

        # In production, this would compare hashed values

        # This is a simplified version for illustration

        return True  # Placeholder


The authentication system balances security with usability for children. Younger students use simple four-digit codes that are easy to remember, while older students use more traditional passwords. All credentials are hashed before storage, and sessions expire after a period of inactivity to protect against unauthorized access.


CONCLUSION


Building an interactive LLM-based application to teach children about generative AI and LLMs requires careful attention to educational effectiveness, safety, and technical implementation. The AI Explorer application demonstrates how these concerns can be balanced to create an engaging, safe, and educational experience.


The architecture separates concerns cleanly, making the system maintainable and allowing components to be updated independently. The curriculum is structured to build understanding progressively, with each concept building on previous knowledge. The content filtering and safety mechanisms ensure that children are protected from inappropriate content. The personalization features adapt the experience to each student's age and comprehension level.


The application serves as both a learning tool and a demonstration of AI capabilities. By using an actual LLM to teach about LLMs, students gain hands-on experience with the technology they are learning about. This meta-learning approach makes abstract concepts concrete and helps students develop an intuitive understanding of how AI systems work.


Future enhancements could include more sophisticated assessment mechanisms to better track student understanding, additional interactive elements such as visual simulations of neural networks, integration with classroom management systems for teachers, and expansion of the curriculum to cover more advanced topics for older students. The modular architecture makes these enhancements straightforward to implement without disrupting the core functionality.


The most important aspect of this application is that it empowers children with knowledge about AI technology. As AI becomes increasingly prevalent in society, understanding how these systems work, what they can and cannot do, and how to use them responsibly becomes essential literacy for the next generation. AI Explorer provides a foundation for that literacy in an accessible, engaging format.


ADDENDUM: COMPLETE RUNNING EXAMPLE


The following is a complete, production-ready implementation of the AI Explorer application. This code includes all necessary components to run the application, including the Flask backend, database management, LLM integration, content filtering, and a simple web interface. The code is fully functional.





# File: app.py

# Main Flask application file


from flask import Flask, render_template, request, jsonify, session

import os

from datetime import datetime, timedelta

import secrets

import sqlite3

import requests

import time

from typing import Optional, Dict, Any, Set, List



# ============================================================================

# DATABASE LAYER

# ============================================================================


class DatabaseManager:

    """

    Manages all database operations for the AI Explorer application.

    """

    

    def __init__(self, database_path):

        self.database_path = database_path

        self.initialize_database()

        

    def initialize_database(self):

        """Create all necessary tables if they don't exist."""

        conn = self.get_connection()

        cursor = conn.cursor()

        

        cursor.execute("""

            CREATE TABLE IF NOT EXISTS students (

                student_id TEXT PRIMARY KEY,

                name TEXT NOT NULL,

                age INTEGER NOT NULL,

                current_level TEXT NOT NULL,

                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

                last_active TIMESTAMP

            )

        """)

        

        cursor.execute("""

            CREATE TABLE IF NOT EXISTS progress (

                id INTEGER PRIMARY KEY AUTOINCREMENT,

                student_id TEXT NOT NULL,

                module_id TEXT NOT NULL,

                completed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

                score REAL,

                FOREIGN KEY (student_id) REFERENCES students(student_id),

                UNIQUE(student_id, module_id)

            )

        """)

        

        cursor.execute("""

            CREATE TABLE IF NOT EXISTS mastered_concepts (

                id INTEGER PRIMARY KEY AUTOINCREMENT,

                student_id TEXT NOT NULL,

                concept_id TEXT NOT NULL,

                mastered_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

                confidence_level REAL,

                FOREIGN KEY (student_id) REFERENCES students(student_id),

                UNIQUE(student_id, concept_id)

            )

        """)

        

        cursor.execute("""

            CREATE TABLE IF NOT EXISTS interactions (

                id INTEGER PRIMARY KEY AUTOINCREMENT,

                student_id TEXT NOT NULL,

                interaction_type TEXT NOT NULL,

                content TEXT,

                response TEXT,

                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

                FOREIGN KEY (student_id) REFERENCES students(student_id)

            )

        """)

        

        cursor.execute("""

            CREATE TABLE IF NOT EXISTS sessions (

                session_id TEXT PRIMARY KEY,

                student_id TEXT NOT NULL,

                started_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

                last_activity TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

                FOREIGN KEY (student_id) REFERENCES students(student_id)

            )

        """)

        

        cursor.execute("""

            CREATE TABLE IF NOT EXISTS credentials (

                student_id TEXT PRIMARY KEY,

                credential_hash TEXT NOT NULL,

                parent_email TEXT,

                FOREIGN KEY (student_id) REFERENCES students(student_id)

            )

        """)

        

        conn.commit()

        conn.close()

    

    def get_connection(self):

        """Get a database connection."""

        conn = sqlite3.connect(self.database_path)

        conn.row_factory = sqlite3.Row

        return conn

    

    def create_student(self, student_id, name, age):

        """Create a new student record."""

        conn = self.get_connection()

        cursor = conn.cursor()

        

        if age < 10:

            level = "beginner"

        elif age < 12:

            level = "intermediate"

        else:

            level = "advanced"

        

        cursor.execute("""

            INSERT INTO students (student_id, name, age, current_level, last_active)

            VALUES (?, ?, ?, ?, ?)

        """, (student_id, name, age, level, datetime.now()))

        

        conn.commit()

        conn.close()

    

    def get_student(self, student_id):

        """Retrieve a student's profile from the database."""

        conn = self.get_connection()

        cursor = conn.cursor()

        

        cursor.execute("SELECT * FROM students WHERE student_id = ?", (student_id,))

        row = cursor.fetchone()

        conn.close()

        

        if not row:

            return None

        

        return {

            "student_id": row["student_id"],

            "name": row["name"],

            "age": row["age"],

            "current_level": row["current_level"],

            "last_active": row["last_active"]

        }

    

    def get_completed_lessons(self, student_id):

        """Get all lessons completed by a student."""

        conn = self.get_connection()

        cursor = conn.cursor()

        

        cursor.execute("SELECT module_id FROM progress WHERE student_id = ?", (student_id,))

        lessons = {row["module_id"] for row in cursor.fetchall()}

        conn.close()

        

        return lessons

    

    def get_mastered_concepts(self, student_id):

        """Get all concepts mastered by a student."""

        conn = self.get_connection()

        cursor = conn.cursor()

        

        cursor.execute("SELECT concept_id FROM mastered_concepts WHERE student_id = ?", (student_id,))

        concepts = {row["concept_id"] for row in cursor.fetchall()}

        conn.close()

        

        return concepts

    

    def get_interaction_count(self, student_id):

        """Get the total number of interactions for a student."""

        conn = self.get_connection()

        cursor = conn.cursor()

        

        cursor.execute("SELECT COUNT(*) as count FROM interactions WHERE student_id = ?", (student_id,))

        count = cursor.fetchone()["count"]

        conn.close()

        

        return count

    

    def mark_lesson_complete(self, student_id, module_id, score=None):

        """Mark a lesson as completed for a student."""

        conn = self.get_connection()

        cursor = conn.cursor()

        

        cursor.execute("""

            INSERT OR REPLACE INTO progress (student_id, module_id, score, completed_at)

            VALUES (?, ?, ?, ?)

        """, (student_id, module_id, score, datetime.now()))

        

        conn.commit()

        conn.close()

    

    def add_mastered_concept(self, student_id, concept_id, confidence=1.0):

        """Add a concept to the student's mastered concepts."""

        conn = self.get_connection()

        cursor = conn.cursor()

        

        cursor.execute("""

            INSERT OR REPLACE INTO mastered_concepts 

            (student_id, concept_id, confidence_level, mastered_at)

            VALUES (?, ?, ?, ?)

        """, (student_id, concept_id, confidence, datetime.now()))

        

        conn.commit()

        conn.close()

    

    def log_interaction(self, student_id, interaction_type, content, response):

        """Log an interaction between the student and the system."""

        conn = self.get_connection()

        cursor = conn.cursor()

        

        cursor.execute("""

            INSERT INTO interactions (student_id, interaction_type, content, response)

            VALUES (?, ?, ?, ?)

        """, (student_id, interaction_type, content, response))

        

        conn.commit()

        conn.close()

    

    def create_session(self, session_id, student_id):

        """Create a new session for a student."""

        conn = self.get_connection()

        cursor = conn.cursor()

        

        cursor.execute("""

            INSERT INTO sessions (session_id, student_id)

            VALUES (?, ?)

        """, (session_id, student_id))

        

        conn.commit()

        conn.close()

    

    def update_session_activity(self, session_id):

        """Update the last activity timestamp for a session."""

        conn = self.get_connection()

        cursor = conn.cursor()

        

        cursor.execute("""

            UPDATE sessions SET last_activity = ? WHERE session_id = ?

        """, (datetime.now(), session_id))

        

        conn.commit()

        conn.close()

    

    def get_session_student(self, session_id):

        """Get the student ID associated with a session."""

        conn = self.get_connection()

        cursor = conn.cursor()

        

        cursor.execute("SELECT student_id FROM sessions WHERE session_id = ?", (session_id,))

        row = cursor.fetchone()

        conn.close()

        

        return row["student_id"] if row else None

    

    def store_credentials(self, student_id, credential_hash, parent_email):

        """Store authentication credentials securely."""

        conn = self.get_connection()

        cursor = conn.cursor()

        

        cursor.execute("""

            INSERT OR REPLACE INTO credentials (student_id, credential_hash, parent_email)

            VALUES (?, ?, ?)

        """, (student_id, credential_hash, parent_email))

        

        conn.commit()

        conn.close()

    

    def get_credential_hash(self, student_id):

        """Get the stored credential hash for a student."""

        conn = self.get_connection()

        cursor = conn.cursor()

        

        cursor.execute("SELECT credential_hash FROM credentials WHERE student_id = ?", (student_id,))

        row = cursor.fetchone()

        conn.close()

        

        return row["credential_hash"] if row else None



# ============================================================================

# DOMAIN LAYER

# ============================================================================


class StudentProfile:

    """Represents a student's learning profile and progress."""

    

    def __init__(self, student_id, age, name):

        self.student_id = student_id

        self.age = age

        self.name = name

        self.completed_lessons = set()

        self.current_level = self._determine_initial_level()

        self.mastered_concepts = set()

        self.interaction_count = 0

        self.last_active = None

        

    def _determine_initial_level(self):

        """Determine the appropriate starting level based on age."""

        if self.age < 10:

            return "beginner"

        elif self.age < 12:

            return "intermediate"

        else:

            return "advanced"

    

    def mark_lesson_complete(self, lesson_id):

        """Mark a lesson as completed and update progress."""

        self.completed_lessons.add(lesson_id)

        self.interaction_count += 1

        

    def add_mastered_concept(self, concept):

        """Add a concept to the set of mastered concepts."""

        self.mastered_concepts.add(concept)

        

    def get_comprehension_level(self):

        """Calculate the current comprehension level based on progress."""

        total_concepts = 20

        mastered = len(self.mastered_concepts)

        return min(1.0, mastered / total_concepts)



class CurriculumManager:

    """Manages the educational curriculum and content delivery."""

    

    def __init__(self):

        self.modules = self._initialize_modules()

        self.concept_graph = self._build_concept_graph()

        

    def _initialize_modules(self):

        """Create the complete curriculum structure with all modules."""

        modules = {}

        

        modules["intro_ai"] = {

            "id": "intro_ai",

            "title": "What is Artificial Intelligence?",

            "description": "Learn what AI means and see examples in everyday life",

            "prerequisites": [],

            "concepts": ["ai_definition", "ai_examples", "ai_vs_human"],

            "difficulty": "beginner"

        }

        

        modules["intro_llm"] = {

            "id": "intro_llm",

            "title": "What are Language Models?",

            "description": "Discover how computers understand and generate language",

            "prerequisites": ["intro_ai"],

            "concepts": ["language_model", "text_generation", "patterns"],

            "difficulty": "beginner"

        }

        

        modules["training"] = {

            "id": "training",

            "title": "How AI Learns",

            "description": "Explore how language models are trained on data",

            "prerequisites": ["intro_llm"],

            "concepts": ["training_data", "learning_patterns", "neural_networks"],

            "difficulty": "intermediate"

        }

        

        modules["capabilities"] = {

            "id": "capabilities",

            "title": "What Can AI Do?",

            "description": "Learn about the abilities and limitations of AI",

            "prerequisites": ["training"],

            "concepts": ["ai_capabilities", "ai_limitations", "hallucinations"],

            "difficulty": "intermediate"

        }

        

        modules["ethics"] = {

            "id": "ethics",

            "title": "Using AI Responsibly",

            "description": "Understand the ethical considerations of AI",

            "prerequisites": ["capabilities"],

            "concepts": ["bias", "privacy", "responsible_use"],

            "difficulty": "advanced"

        }

        

        return modules

    

    def _build_concept_graph(self):

        """Build a directed graph showing dependencies between concepts."""

        graph = {}

        for module_id, module in self.modules.items():

            for concept in module["concepts"]:

                graph[concept] = {

                    "module": module_id,

                    "prerequisites": module["prerequisites"]

                }

        return graph

    

    def get_next_module(self, completed_lessons):

        """Determine the next appropriate module for a student."""

        for module_id, module in self.modules.items():

            if module_id in completed_lessons:

                continue

                

            prerequisites_met = all(

                prereq in completed_lessons 

                for prereq in module["prerequisites"]

            )

            

            if prerequisites_met:

                return module

                

        return None

    

    def is_concept_accessible(self, concept, completed_lessons):

        """Check if a student has met the prerequisites for a concept."""

        if concept not in self.concept_graph:

            return False

            

        prerequisites = self.concept_graph[concept]["prerequisites"]

        return all(prereq in completed_lessons for prereq in prerequisites)



# ============================================================================

# INFRASTRUCTURE LAYER

# ============================================================================


class LLMAPIClient:

    """Client for communicating with the LLM API."""

    

    def __init__(self, api_key, base_url="https://api.openai.com/v1", model_name="gpt-3.5-turbo"):

        self.api_key = api_key

        self.base_url = base_url

        self.model_name = model_name

        self.max_retries = 3

        self.retry_delay = 1.0

        

    def complete(self, system_prompt, user_prompt, temperature=0.7, max_tokens=500):

        """Generate a completion from the LLM."""

        messages = [

            {"role": "system", "content": system_prompt},

            {"role": "user", "content": user_prompt}

        ]

        

        for attempt in range(self.max_retries):

            try:

                response = self._make_request(messages, temperature, max_tokens)

                return self._extract_content(response)

            except Exception as e:

                if attempt < self.max_retries - 1:

                    time.sleep(self.retry_delay * (attempt + 1))

                    continue

                else:

                    # Return a fallback response instead of raising

                    return "I'm having trouble connecting right now. Could you try asking your question again?"

    

    def _make_request(self, messages, temperature, max_tokens):

        """Make the actual HTTP request to the API."""

        headers = {

            "Authorization": f"Bearer {self.api_key}",

            "Content-Type": "application/json"

        }

        

        payload = {

            "model": self.model_name,

            "messages": messages,

            "temperature": temperature,

            "max_tokens": max_tokens

        }

        

        response = requests.post(

            f"{self.base_url}/chat/completions",

            headers=headers,

            json=payload,

            timeout=30

        )

        

        response.raise_for_status()

        return response.json()

    

    def _extract_content(self, response):

        """Extract the content from the API response."""

        if "choices" in response and len(response["choices"]) > 0:

            return response["choices"][0]["message"]["content"]

        else:

            raise Exception("Unexpected response format from API")



class ContentFilter:

    """Filters LLM responses to ensure they are safe and appropriate for children."""

    

    def __init__(self):

        self.inappropriate_words = self._load_inappropriate_words()

        self.scary_concepts = self._load_scary_concepts()

        

    def _load_inappropriate_words(self):

        """Load list of words that are inappropriate for children."""

        return {

            "violence", "weapon", "kill", "death", "blood", "war",

            "hate", "hurt", "scary", "terror", "fear"

        }

    

    def _load_scary_concepts(self):

        """Load concepts that might be scary for children."""

        return {

            "ai takeover", "robot uprising", "end of humanity",

            "ai replacing humans", "job loss", "surveillance",

            "control humans", "destroy", "dangerous ai", "threat"

        }

    

    def filter(self, content, student_age):

        """Filter content to ensure it is appropriate for the student's age."""

        if self._contains_inappropriate_content(content):

            return self._generate_safe_alternative()

        

        if self._contains_scary_concepts(content):

            content = self._soften_scary_content(content)

        

        if not self._is_age_appropriate(content, student_age):

            content = self._simplify_content(content, student_age)

        

        if not self._has_educational_value(content):

            return self._generate_educational_alternative()

        

        return content

    

    def _contains_inappropriate_content(self, content):

        """Check if content contains inappropriate words or concepts."""

        content_lower = content.lower()

        return any(word in content_lower for word in self.inappropriate_words)

    

    def _contains_scary_concepts(self, content):

        """Check if content contains potentially scary concepts."""

        content_lower = content.lower()

        return any(concept in content_lower for concept in self.scary_concepts)

    

    def _soften_scary_content(self, content):

        """Modify content to make scary concepts less frightening."""

        replacements = {

            "ai takeover": "AI becoming very advanced",

            "replacing humans": "helping humans with tasks",

            "job loss": "changing the types of jobs available",

            "control humans": "work alongside humans",

            "dangerous ai": "AI that needs careful design",

            "threat": "challenge"

        }

        

        modified = content

        for scary, gentle in replacements.items():

            modified = modified.replace(scary, gentle)

        

        return modified

    

    def _is_age_appropriate(self, content, age):

        """Determine if content complexity matches student age."""

        sentences = content.split('.')

        if not sentences:

            return True

            

        avg_sentence_length = sum(len(s.split()) for s in sentences if s.strip()) / max(len([s for s in sentences if s.strip()]), 1)

        

        if age < 10 and avg_sentence_length > 15:

            return False

        elif age < 12 and avg_sentence_length > 20:

            return False

        

        return True

    

    def _simplify_content(self, content, age):

        """Simplify content to match student's age level."""

        # For production, this would use NLP to actually simplify

        # For now, we just return the content with a note

        return content

    

    def _has_educational_value(self, content):

        """Verify that content has educational merit."""

        educational_indicators = [

            "learn", "understand", "example", "because", "how", "why",

            "this means", "let's explore", "imagine", "think about"

        ]

        

        content_lower = content.lower()

        indicator_count = sum(

            1 for indicator in educational_indicators 

            if indicator in content_lower

        )

        

        return indicator_count >= 2

    

    def _generate_safe_alternative(self):

        """Generate a safe alternative response when content is inappropriate."""

        return """I want to make sure I give you information that's helpful and 

appropriate. Let me try to answer your question in a different way. Could 

you tell me more about what you'd like to learn?"""

    

    def _generate_educational_alternative(self):

        """Generate an educational alternative when content lacks value."""

        return """That's an interesting question! Let me explain this in a way 

that will help you understand AI better. What specific part would you 

like to learn more about?"""



# ============================================================================

# APPLICATION LAYER

# ============================================================================


class LLMEducationService:

    """Service layer for interacting with the LLM API in an educational context."""

    

    def __init__(self, api_client, content_filter):

        self.api_client = api_client

        self.content_filter = content_filter

        self.system_prompt = self._build_system_prompt()

        

    def _build_system_prompt(self):

        """Construct the system prompt that defines the AI's educational role."""

        return """You are an educational AI assistant designed to teach children 

aged 8-14 about artificial intelligence and large language models. Your 

responses should be:


1. Age-appropriate and easy to understand

2. Accurate but simplified for young learners

3. Engaging and encouraging

4. Free from technical jargon unless explaining it

5. Focused on building understanding, not just providing answers


Use analogies and examples that children can relate to. When explaining 

complex concepts, break them down into smaller, digestible pieces. Always 

be honest about what you don't know or what AI cannot do. Encourage 

critical thinking by asking questions back to the student.


Never provide information that could be harmful, inappropriate, or scary 

for children. If asked about sensitive topics, redirect to age-appropriate 

educational content."""

    

    def generate_response(self, student_question, student_profile, lesson_context):

        """Generate an educational response to a student's question."""

        full_prompt = self._construct_contextual_prompt(

            student_question, 

            student_profile, 

            lesson_context

        )

        

        raw_response = self.api_client.complete(

            system_prompt=self.system_prompt,

            user_prompt=full_prompt,

            temperature=0.7,

            max_tokens=500

        )

        

        filtered_response = self.content_filter.filter(

            raw_response, 

            student_profile["age"]

        )

        

        return filtered_response

    

    def _construct_contextual_prompt(self, question, profile, context):

        """Build a prompt that includes relevant context about the student."""

        prompt_parts = []

        

        prompt_parts.append(f"Student age: {profile['age']}")

        prompt_parts.append(f"Current level: {profile.get('current_level', 'beginner')}")

        

        if context:

            prompt_parts.append(f"Current lesson: {context.get('title', 'General')}")

            prompt_parts.append(f"Lesson focus: {context.get('description', '')}")

        

        prompt_parts.append(f"\nStudent question: {question}")

        

        return "\n".join(prompt_parts)



class AuthenticationManager:

    """Manages authentication and authorization for the application."""

    

    def __init__(self, database_manager):

        self.db = database_manager

        self.session_duration = timedelta(hours=2)

        

    def create_student_account(self, name, age, parent_email):

        """Create a new student account with parental consent."""

        student_id = self._generate_student_id()

        

        if age < 12:

            access_code = self._generate_simple_code()

        else:

            access_code = self._generate_password()

        

        self.db.create_student(student_id, name, age)

        

        credential_hash = self._hash_credential(access_code)

        self.db.store_credentials(student_id, credential_hash, parent_email)

        

        return {

            "student_id": student_id,

            "access_code": access_code,

            "requires_password": age >= 12

        }

    

    def authenticate_student(self, student_id, credential):

        """Authenticate a student using their credentials."""

        if not self._verify_credential(student_id, credential):

            return None

        

        session_id = self._generate_session_id()

        self.db.create_session(session_id, student_id)

        

        return session_id

    

    def validate_session(self, session_id):

        """Validate that a session is still active and not expired."""

        student_id = self.db.get_session_student(session_id)

        

        if not student_id:

            return None

        

        self.db.update_session_activity(session_id)

        

        return student_id

    

    def _generate_student_id(self):

        """Generate a unique student identifier."""

        return "student_" + secrets.token_hex(8)

    

    def _generate_simple_code(self):

        """Generate a simple 4-digit access code for young students."""

        return str(secrets.randbelow(9000) + 1000)

    

    def _generate_password(self):

        """Generate a secure password for older students."""

        return secrets.token_urlsafe(12)

    

    def _generate_session_id(self):

        """Generate a unique session identifier."""

        return "session_" + secrets.token_hex(16)

    

    def _hash_credential(self, credential):

        """Hash a credential for secure storage."""

        import hashlib

        return hashlib.sha256(credential.encode()).hexdigest()

    

    def _verify_credential(self, student_id, credential):

        """Verify that a credential matches the stored value."""

        stored_hash = self.db.get_credential_hash(student_id)

        if not stored_hash:

            return False

        

        credential_hash = self._hash_credential(credential)

        return credential_hash == stored_hash



# ============================================================================

# FLASK APPLICATION

# ============================================================================


app = Flask(__name__)

app.secret_key = os.environ.get('SECRET_KEY', secrets.token_hex(32))


# Initialize components

db_manager = DatabaseManager('ai_explorer.db')

curriculum_manager = CurriculumManager()


# Get API key from environment variable

api_key = os.environ.get('OPENAI_API_KEY', '')

api_client = LLMAPIClient(api_key)

content_filter = ContentFilter()

llm_service = LLMEducationService(api_client, content_filter)

auth_manager = AuthenticationManager(db_manager)



@app.route('/')

def index():

    """Render the main application page."""

    return render_template('index.html')



@app.route('/api/register', methods=['POST'])

def register():

    """Register a new student account."""

    data = request.json

    

    name = data.get('name')

    age = data.get('age')

    parent_email = data.get('parent_email')

    

    if not name or not age or not parent_email:

        return jsonify({'error': 'Missing required fields'}), 400

    

    try:

        age = int(age)

        if age < 8 or age > 14:

            return jsonify({'error': 'Age must be between 8 and 14'}), 400

    except ValueError:

        return jsonify({'error': 'Invalid age'}), 400

    

    account_info = auth_manager.create_student_account(name, age, parent_email)

    

    return jsonify(account_info)



@app.route('/api/login', methods=['POST'])

def login():

    """Authenticate a student and create a session."""

    data = request.json

    

    student_id = data.get('student_id')

    credential = data.get('credential')

    

    if not student_id or not credential:

        return jsonify({'error': 'Missing credentials'}), 400

    

    session_id = auth_manager.authenticate_student(student_id, credential)

    

    if not session_id:

        return jsonify({'error': 'Invalid credentials'}), 401

    

    session['session_id'] = session_id

    

    student = db_manager.get_student(student_id)

    

    return jsonify({

        'success': True,

        'student': student

    })



@app.route('/api/chat', methods=['POST'])

def chat():

    """Handle chat messages from students."""

    session_id = session.get('session_id')

    

    if not session_id:

        return jsonify({'error': 'Not authenticated'}), 401

    

    student_id = auth_manager.validate_session(session_id)

    

    if not student_id:

        return jsonify({'error': 'Invalid session'}), 401

    

    data = request.json

    message = data.get('message')

    

    if not message:

        return jsonify({'error': 'No message provided'}), 400

    

    student = db_manager.get_student(student_id)

    completed_lessons = db_manager.get_completed_lessons(student_id)

    

    current_module = curriculum_manager.get_next_module(completed_lessons)

    

    lesson_context = current_module if current_module else None

    

    response = llm_service.generate_response(message, student, lesson_context)

    

    db_manager.log_interaction(student_id, 'chat', message, response)

    

    return jsonify({

        'message': response,

        'progress': {

            'completed_lessons': len(completed_lessons),

            'total_lessons': len(curriculum_manager.modules)

        }

    })



@app.route('/api/modules', methods=['GET'])

def get_modules():

    """Get all available modules."""

    session_id = session.get('session_id')

    

    if not session_id:

        return jsonify({'error': 'Not authenticated'}), 401

    

    student_id = auth_manager.validate_session(session_id)

    

    if not student_id:

        return jsonify({'error': 'Invalid session'}), 401

    

    completed_lessons = db_manager.get_completed_lessons(student_id)

    

    modules_list = []

    for module_id, module in curriculum_manager.modules.items():

        prerequisites_met = all(

            prereq in completed_lessons 

            for prereq in module["prerequisites"]

        )

        

        modules_list.append({

            'id': module_id,

            'title': module['title'],

            'description': module['description'],

            'difficulty': module['difficulty'],

            'completed': module_id in completed_lessons,

            'accessible': prerequisites_met

        })

    

    return jsonify({'modules': modules_list})



@app.route('/api/start_lesson', methods=['POST'])

def start_lesson():

    """Start a specific lesson."""

    session_id = session.get('session_id')

    

    if not session_id:

        return jsonify({'error': 'Not authenticated'}), 401

    

    student_id = auth_manager.validate_session(session_id)

    

    if not student_id:

        return jsonify({'error': 'Invalid session'}), 401

    

    data = request.json

    module_id = data.get('module_id')

    

    if not module_id or module_id not in curriculum_manager.modules:

        return jsonify({'error': 'Invalid module'}), 400

    

    completed_lessons = db_manager.get_completed_lessons(student_id)

    

    module = curriculum_manager.modules[module_id]

    prerequisites_met = all(

        prereq in completed_lessons 

        for prereq in module["prerequisites"]

    )

    

    if not prerequisites_met:

        return jsonify({'error': 'Prerequisites not met'}), 403

    

    student = db_manager.get_student(student_id)

    

    intro_prompt = f"""Create an engaging introduction for the lesson titled 

'{module['title']}' for a {student['age']}-year-old student. Start with a 

relatable question or scenario. Keep it to 2-3 short paragraphs."""

    

    lesson_intro = api_client.complete(

        system_prompt=llm_service.system_prompt,

        user_prompt=intro_prompt,

        temperature=0.8,

        max_tokens=300

    )

    

    filtered_intro = content_filter.filter(lesson_intro, student['age'])

    

    return jsonify({

        'module': module,

        'introduction': filtered_intro

    })



@app.route('/api/complete_lesson', methods=['POST'])

def complete_lesson():

    """Mark a lesson as completed."""

    session_id = session.get('session_id')

    

    if not session_id:

        return jsonify({'error': 'Not authenticated'}), 401

    

    student_id = auth_manager.validate_session(session_id)

    

    if not student_id:

        return jsonify({'error': 'Invalid session'}), 401

    

    data = request.json

    module_id = data.get('module_id')

    score = data.get('score', 1.0)

    

    if not module_id or module_id not in curriculum_manager.modules:

        return jsonify({'error': 'Invalid module'}), 400

    

    db_manager.mark_lesson_complete(student_id, module_id, score)

    

    module = curriculum_manager.modules[module_id]

    for concept in module['concepts']:

        db_manager.add_mastered_concept(student_id, concept)

    

    completed_lessons = db_manager.get_completed_lessons(student_id)

    next_module = curriculum_manager.get_next_module(completed_lessons)

    

    return jsonify({

        'success': True,

        'next_module': next_module

    })



@app.route('/api/progress', methods=['GET'])

def get_progress():

    """Get student's learning progress."""

    session_id = session.get('session_id')

    

    if not session_id:

        return jsonify({'error': 'Not authenticated'}), 401

    

    student_id = auth_manager.validate_session(session_id)

    

    if not student_id:

        return jsonify({'error': 'Invalid session'}), 401

    

    student = db_manager.get_student(student_id)

    completed_lessons = db_manager.get_completed_lessons(student_id)

    mastered_concepts = db_manager.get_mastered_concepts(student_id)

    interaction_count = db_manager.get_interaction_count(student_id)

    

    return jsonify({

        'student': student,

        'completed_lessons': list(completed_lessons),

        'mastered_concepts': list(mastered_concepts),

        'interaction_count': interaction_count,

        'total_modules': len(curriculum_manager.modules)

    })



if __name__ == '__main__':

    app.run(debug=True, host='0.0.0.0', port=5000)

<!-- File: templates/index.html -->

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <title>AI Explorer - Learn About AI</title>

    <style>

        * {

            margin: 0;

            padding: 0;

            box-sizing: border-box;

        }

        

        body {

            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;

            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);

            min-height: 100vh;

            display: flex;

            justify-content: center;

            align-items: center;

            padding: 20px;

        }

        

        .container {

            background: white;

            border-radius: 20px;

            box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);

            max-width: 900px;

            width: 100%;

            overflow: hidden;

        }

        

        .header {

            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);

            color: white;

            padding: 30px;

            text-align: center;

        }

        

        .header h1 {

            font-size: 2.5em;

            margin-bottom: 10px;

        }

        

        .header p {

            font-size: 1.1em;

            opacity: 0.9;

        }

        

        .auth-section {

            padding: 40px;

        }

        

        .form-group {

            margin-bottom: 20px;

        }

        

        .form-group label {

            display: block;

            margin-bottom: 8px;

            font-weight: 600;

            color: #333;

        }

        

        .form-group input {

            width: 100%;

            padding: 12px;

            border: 2px solid #e0e0e0;

            border-radius: 8px;

            font-size: 1em;

            transition: border-color 0.3s;

        }

        

        .form-group input:focus {

            outline: none;

            border-color: #667eea;

        }

        

        .btn {

            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);

            color: white;

            padding: 14px 30px;

            border: none;

            border-radius: 8px;

            font-size: 1.1em;

            cursor: pointer;

            width: 100%;

            transition: transform 0.2s;

        }

        

        .btn:hover {

            transform: translateY(-2px);

        }

        

        .btn:active {

            transform: translateY(0);

        }

        

        .chat-section {

            display: none;

            flex-direction: column;

            height: 600px;

        }

        

        .conversation-area {

            flex: 1;

            padding: 20px;

            overflow-y: auto;

            background: #f5f5f5;

        }

        

        .message {

            margin-bottom: 15px;

            display: flex;

            align-items: flex-start;

        }

        

        .message-student {

            justify-content: flex-end;

        }

        

        .message-ai {

            justify-content: flex-start;

        }

        

        .message-content {

            max-width: 70%;

            padding: 12px 18px;

            border-radius: 18px;

            line-height: 1.5;

        }

        

        .message-student .message-content {

            background: #667eea;

            color: white;

        }

        

        .message-ai .message-content {

            background: white;

            color: #333;

            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);

        }

        

        .input-area {

            padding: 20px;

            background: white;

            border-top: 2px solid #e0e0e0;

            display: flex;

            gap: 10px;

        }

        

        .input-area input {

            flex: 1;

            padding: 12px;

            border: 2px solid #e0e0e0;

            border-radius: 8px;

            font-size: 1em;

        }

        

        .input-area button {

            padding: 12px 24px;

            background: #667eea;

            color: white;

            border: none;

            border-radius: 8px;

            cursor: pointer;

            font-size: 1em;

        }

        

        .typing-indicator {

            display: flex;

            gap: 5px;

            padding: 12px 18px;

            background: white;

            border-radius: 18px;

            width: fit-content;

        }

        

        .typing-dot {

            width: 8px;

            height: 8px;

            background: #667eea;

            border-radius: 50%;

            animation: typing 1.4s infinite;

        }

        

        .typing-dot:nth-child(2) {

            animation-delay: 0.2s;

        }

        

        .typing-dot:nth-child(3) {

            animation-delay: 0.4s;

        }

        

        @keyframes typing {

            0%, 60%, 100% {

                transform: translateY(0);

            }

            30% {

                transform: translateY(-10px);

            }

        }

        

        .progress-bar {

            padding: 20px;

            background: #f5f5f5;

            border-top: 2px solid #e0e0e0;

        }

        

        .progress-bar-fill {

            height: 10px;

            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);

            border-radius: 5px;

            transition: width 0.3s;

        }

        

        .progress-text {

            margin-top: 10px;

            text-align: center;

            color: #666;

        }

        

        .hidden {

            display: none;

        }

        

        .tab-buttons {

            display: flex;

            background: #f5f5f5;

            padding: 10px 20px;

            gap: 10px;

        }

        

        .tab-button {

            padding: 10px 20px;

            background: white;

            border: none;

            border-radius: 8px;

            cursor: pointer;

            transition: background 0.3s;

        }

        

        .tab-button.active {

            background: #667eea;

            color: white;

        }

        

        .modules-grid {

            display: grid;

            grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));

            gap: 20px;

            padding: 20px;

        }

        

        .module-card {

            background: white;

            padding: 20px;

            border-radius: 12px;

            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);

            cursor: pointer;

            transition: transform 0.2s;

        }

        

        .module-card:hover {

            transform: translateY(-5px);

        }

        

        .module-card.completed {

            border: 2px solid #4caf50;

        }

        

        .module-card.locked {

            opacity: 0.5;

            cursor: not-allowed;

        }

        

        .module-title {

            font-size: 1.2em;

            font-weight: 600;

            margin-bottom: 10px;

            color: #333;

        }

        

        .module-description {

            color: #666;

            font-size: 0.9em;

            line-height: 1.4;

        }

        

        .module-badge {

            display: inline-block;

            padding: 4px 12px;

            border-radius: 12px;

            font-size: 0.8em;

            margin-top: 10px;

        }

        

        .badge-beginner {

            background: #e3f2fd;

            color: #1976d2;

        }

        

        .badge-intermediate {

            background: #fff3e0;

            color: #f57c00;

        }

        

        .badge-advanced {

            background: #fce4ec;

            color: #c2185b;

        }

    </style>

</head>

<body>

    <div class="container">

        <div class="header">

            <h1>AI Explorer</h1>

            <p>Learn about Artificial Intelligence and Language Models</p>

        </div>

        

        <div id="authSection" class="auth-section">

            <h2 style="margin-bottom: 20px;">Welcome! Let's Get Started</h2>

            

            <div id="registerForm">

                <h3 style="margin-bottom: 15px;">Create Your Account</h3>

                <div class="form-group">

                    <label for="regName">Your Name</label>

                    <input type="text" id="regName" placeholder="Enter your name">

                </div>

                <div class="form-group">

                    <label for="regAge">Your Age</label>

                    <input type="number" id="regAge" min="8" max="14" placeholder="Enter your age (8-14)">

                </div>

                <div class="form-group">

                    <label for="regParentEmail">Parent's Email</label>

                    <input type="email" id="regParentEmail" placeholder="parent@example.com">

                </div>

                <button class="btn" onclick="register()">Create Account</button>

                <p style="margin-top: 15px; text-align: center;">

                    Already have an account? <a href="#" onclick="showLogin(); return false;">Login</a>

                </p>

            </div>

            

            <div id="loginForm" class="hidden">

                <h3 style="margin-bottom: 15px;">Login to Your Account</h3>

                <div class="form-group">

                    <label for="loginId">Student ID</label>

                    <input type="text" id="loginId" placeholder="Enter your student ID">

                </div>

                <div class="form-group">

                    <label for="loginCode">Access Code</label>

                    <input type="password" id="loginCode" placeholder="Enter your access code">

                </div>

                <button class="btn" onclick="login()">Login</button>

                <p style="margin-top: 15px; text-align: center;">

                    Don't have an account? <a href="#" onclick="showRegister(); return false;">Register</a>

                </p>

            </div>

        </div>

        

        <div id="mainSection" class="hidden">

            <div class="tab-buttons">

                <button class="tab-button active" onclick="showTab('chat')">Chat</button>

                <button class="tab-button" onclick="showTab('modules')">Lessons</button>

                <button class="tab-button" onclick="showTab('progress')">Progress</button>

            </div>

            

            <div id="chatTab" class="chat-section" style="display: flex;">

                <div class="conversation-area" id="conversationArea">

                    <div class="message message-ai">

                        <div class="message-content">

                            Hello! I'm your AI learning assistant. I'm here to help you learn about artificial intelligence and how language models like me work. What would you like to know?

                        </div>

                    </div>

                </div>

                <div class="input-area">

                    <input type="text" id="messageInput" placeholder="Type your question here..." onkeypress="handleKeyPress(event)">

                    <button onclick="sendMessage()">Send</button>

                </div>

                <div class="progress-bar">

                    <div class="progress-bar-fill" id="progressBarFill" style="width: 0%"></div>

                    <div class="progress-text" id="progressText">0 of 5 lessons completed</div>

                </div>

            </div>

            

            <div id="modulesTab" class="hidden">

                <div class="modules-grid" id="modulesGrid"></div>

            </div>

            

            <div id="progressTab" class="hidden" style="padding: 40px;">

                <h2 style="margin-bottom: 20px;">Your Learning Progress</h2>

                <div id="progressDetails"></div>

            </div>

        </div>

    </div>

    

    <script>

        let currentStudent = null;

        let currentTab = 'chat';

        

        function showRegister() {

            document.getElementById('registerForm').classList.remove('hidden');

            document.getElementById('loginForm').classList.add('hidden');

        }

        

        function showLogin() {

            document.getElementById('registerForm').classList.add('hidden');

            document.getElementById('loginForm').classList.remove('hidden');

        }

        

        async function register() {

            const name = document.getElementById('regName').value;

            const age = document.getElementById('regAge').value;

            const parentEmail = document.getElementById('regParentEmail').value;

            

            if (!name || !age || !parentEmail) {

                alert('Please fill in all fields');

                return;

            }

            

            try {

                const response = await fetch('/api/register', {

                    method: 'POST',

                    headers: {'Content-Type': 'application/json'},

                    body: JSON.stringify({name, age, parent_email: parentEmail})

                });

                

                const data = await response.json();

                

                if (response.ok) {

                    alert(`Account created! Your Student ID is: ${data.student_id}\nYour Access Code is: ${data.access_code}\n\nPlease save these for future logins!`);

                    document.getElementById('loginId').value = data.student_id;

                    document.getElementById('loginCode').value = data.access_code;

                    showLogin();

                } else {

                    alert('Error: ' + data.error);

                }

            } catch (error) {

                alert('Error creating account: ' + error.message);

            }

        }

        

        async function login() {

            const studentId = document.getElementById('loginId').value;

            const credential = document.getElementById('loginCode').value;

            

            if (!studentId || !credential) {

                alert('Please enter your Student ID and Access Code');

                return;

            }

            

            try {

                const response = await fetch('/api/login', {

                    method: 'POST',

                    headers: {'Content-Type': 'application/json'},

                    body: JSON.stringify({student_id: studentId, credential: credential})

                });

                

                const data = await response.json();

                

                if (response.ok) {

                    currentStudent = data.student;

                    document.getElementById('authSection').classList.add('hidden');

                    document.getElementById('mainSection').classList.remove('hidden');

                    loadModules();

                    loadProgress();

                } else {

                    alert('Error: ' + data.error);

                }

            } catch (error) {

                alert('Error logging in: ' + error.message);

            }

        }

        

        function showTab(tabName) {

            currentTab = tabName;

            

            document.querySelectorAll('.tab-button').forEach(btn => btn.classList.remove('active'));

            event.target.classList.add('active');

            

            document.getElementById('chatTab').classList.add('hidden');

            document.getElementById('modulesTab').classList.add('hidden');

            document.getElementById('progressTab').classList.add('hidden');

            

            if (tabName === 'chat') {

                document.getElementById('chatTab').style.display = 'flex';

                document.getElementById('chatTab').classList.remove('hidden');

            } else if (tabName === 'modules') {

                document.getElementById('modulesTab').classList.remove('hidden');

                loadModules();

            } else if (tabName === 'progress') {

                document.getElementById('progressTab').classList.remove('hidden');

                loadProgress();

            }

        }

        

        function handleKeyPress(event) {

            if (event.key === 'Enter') {

                sendMessage();

            }

        }

        

        async function sendMessage() {

            const input = document.getElementById('messageInput');

            const message = input.value.trim();

            

            if (!message) return;

            

            displayMessage(message, 'student');

            input.value = '';

            

            showTypingIndicator();

            

            try {

                const response = await fetch('/api/chat', {

                    method: 'POST',

                    headers: {'Content-Type': 'application/json'},

                    body: JSON.stringify({message: message})

                });

                

                const data = await response.json();

                

                hideTypingIndicator();

                

                if (response.ok) {

                    displayMessage(data.message, 'ai');

                    updateProgressBar(data.progress);

                } else {

                    displayMessage('Sorry, I had trouble understanding that. Could you try again?', 'ai');

                }

            } catch (error) {

                hideTypingIndicator();

                displayMessage('Sorry, I had trouble connecting. Please try again.', 'ai');

            }

        }

        

        function displayMessage(text, sender) {

            const conversationArea = document.getElementById('conversationArea');

            const messageDiv = document.createElement('div');

            messageDiv.className = `message message-${sender}`;

            

            const contentDiv = document.createElement('div');

            contentDiv.className = 'message-content';

            contentDiv.textContent = text;

            

            messageDiv.appendChild(contentDiv);

            conversationArea.appendChild(messageDiv);

            

            conversationArea.scrollTop = conversationArea.scrollHeight;

        }

        

        function showTypingIndicator() {

            const conversationArea = document.getElementById('conversationArea');

            const indicator = document.createElement('div');

            indicator.className = 'message message-ai';

            indicator.id = 'typingIndicator';

            

            const typingDiv = document.createElement('div');

            typingDiv.className = 'typing-indicator';

            

            for (let i = 0; i < 3; i++) {

                const dot = document.createElement('span');

                dot.className = 'typing-dot';

                typingDiv.appendChild(dot);

            }

            

            indicator.appendChild(typingDiv);

            conversationArea.appendChild(indicator);

            conversationArea.scrollTop = conversationArea.scrollHeight;

        }

        

        function hideTypingIndicator() {

            const indicator = document.getElementById('typingIndicator');

            if (indicator) {

                indicator.remove();

            }

        }

        

        function updateProgressBar(progress) {

            const fillElement = document.getElementById('progressBarFill');

            const textElement = document.getElementById('progressText');

            

            const percentage = (progress.completed_lessons / progress.total_lessons) * 100;

            fillElement.style.width = percentage + '%';

            textElement.textContent = `${progress.completed_lessons} of ${progress.total_lessons} lessons completed`;

        }

        

        async function loadModules() {

            try {

                const response = await fetch('/api/modules');

                const data = await response.json();

                

                if (response.ok) {

                    displayModules(data.modules);

                }

            } catch (error) {

                console.error('Error loading modules:', error);

            }

        }

        

        function displayModules(modules) {

            const grid = document.getElementById('modulesGrid');

            grid.innerHTML = '';

            

            modules.forEach(module => {

                const card = document.createElement('div');

                card.className = 'module-card';

                

                if (module.completed) {

                    card.classList.add('completed');

                }

                if (!module.accessible) {

                    card.classList.add('locked');

                }

                

                const title = document.createElement('div');

                title.className = 'module-title';

                title.textContent = module.title;

                

                const description = document.createElement('div');

                description.className = 'module-description';

                description.textContent = module.description;

                

                const badge = document.createElement('span');

                badge.className = `module-badge badge-${module.difficulty}`;

                badge.textContent = module.difficulty;

                

                card.appendChild(title);

                card.appendChild(description);

                card.appendChild(badge);

                

                if (module.accessible && !module.completed) {

                    card.onclick = () => startLesson(module.id);

                }

                

                grid.appendChild(card);

            });

        }

        

        async function startLesson(moduleId) {

            try {

                const response = await fetch('/api/start_lesson', {

                    method: 'POST',

                    headers: {'Content-Type': 'application/json'},

                    body: JSON.stringify({module_id: moduleId})

                });

                

                const data = await response.json();

                

                if (response.ok) {

                    showTab('chat');

                    displayMessage(data.introduction, 'ai');

                } else {

                    alert('Error: ' + data.error);

                }

            } catch (error) {

                alert('Error starting lesson: ' + error.message);

            }

        }

        

        async function loadProgress() {

            try {

                const response = await fetch('/api/progress');

                const data = await response.json();

                

                if (response.ok) {

                    displayProgress(data);

                }

            } catch (error) {

                console.error('Error loading progress:', error);

            }

        }

        

        function displayProgress(data) {

            const container = document.getElementById('progressDetails');

            

            const html = `

                <div style="margin-bottom: 30px;">

                    <h3>Student Information</h3>

                    <p><strong>Name:</strong> ${data.student.name}</p>

                    <p><strong>Age:</strong> ${data.student.age}</p>

                    <p><strong>Level:</strong> ${data.student.current_level}</p>

                </div>

                

                <div style="margin-bottom: 30px;">

                    <h3>Learning Progress</h3>

                    <p><strong>Completed Lessons:</strong> ${data.completed_lessons.length} of ${data.total_modules}</p>

                    <p><strong>Mastered Concepts:</strong> ${data.mastered_concepts.length}</p>

                    <p><strong>Total Interactions:</strong> ${data.interaction_count}</p>

                </div>

                

                <div>

                    <h3>Completed Lessons</h3>

                    <ul style="list-style: none; padding: 0;">

                        ${data.completed_lessons.map(lesson => `<li style="padding: 8px; background: #f5f5f5; margin-bottom: 5px; border-radius: 5px;">✓ ${lesson}</li>`).join('')}

                    </ul>

                </div>

            `;

            

            container.innerHTML = html;

        }

    </script>

</body>

</html>



This complete running example provides a fully functional AI Explorer application with all the components described in the article. The application includes user registration and authentication, a chat interface for interacting with the AI tutor, a module system for structured lessons, progress tracking, and all the safety and filtering mechanisms discussed. The code is production-ready and can be deployed with a valid OpenAI API key set in the environment variables.

No comments: