{"id":409,"date":"2025-12-03T06:58:17","date_gmt":"2025-12-03T06:58:17","guid":{"rendered":"https:\/\/i-cte.org\/robot\/?p=409"},"modified":"2025-12-03T06:58:17","modified_gmt":"2025-12-03T06:58:17","slug":"life-stories-conversation","status":"publish","type":"post","link":"https:\/\/i-cte.org\/robot\/life-stories-conversation\/","title":{"rendered":"Life Stories &#8211; Conversation"},"content":{"rendered":"\n<p>This Robot is used for practicing English at level A2. In order to interact with this Robot smoothly, please use a laptop, desktop, or iPad. Do not use Smartphones, though they are sometimes fine. It depends on the updated browsers and Internet connection.<\/p>\n\n\n\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Life Stories &#8211; Conversation<\/title>\n    <style>\n        \/* Reset and Base Styles *\/\n        * {\n            box-sizing: border-box;\n        }\n\n        body {\n            font-family: Arial, sans-serif;\n            background-color: #f4f6f8;\n            margin: 0;\n            padding: 0;\n            display: flex;\n            flex-direction: column;\n            min-height: 100vh;\n        }\n\n        \/* Menu Styles *\/\n        .menu {\n            width: 100%;\n            background-color: #28a745;\n            padding: 10px;\n            text-align: center;\n            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);\n            margin-bottom: 10px;\n            overflow-x: auto;\n            white-space: nowrap;\n        }\n        .menu a {\n            color: #fff;\n            text-decoration: none;\n            margin: 0 10px;\n            font-weight: bold;\n            font-size: 14px;\n            display: inline-block;\n        }\n        .menu a:hover,\n        .menu a:focus {\n            text-decoration: underline;\n            outline: 2px dashed #fff;\n            outline-offset: 4px;\n        }\n\n        \/* Container Styles *\/\n        .container {\n            display: flex;\n            flex-direction: column;\n            align-items: center;\n            padding: 10px;\n            box-sizing: border-box;\n            flex: 1 0 auto;\n            width: 100%;\n        }\n\n        \/* Image and Chat Containers *\/\n        .image-chat-wrapper {\n            display: flex;\n            flex-direction: column;\n            width: 100%;\n            max-width: 800px;\n            flex: 1;\n        }\n\n        \/* Image Container Styles *\/\n        .image-container {\n            flex: 1;\n            text-align: center;\n            margin-bottom: 15px;\n        }\n        .image-container img {\n            width: 100%;\n            height: auto;\n            max-height: 300px;\n            object-fit: cover;\n            border-radius: 15px;\n            box-shadow: 0 0 8px rgba(0, 0, 0, 0.1);\n        }\n        .sentence-text {\n            margin: 10px 0;\n            font-weight: bold;\n            color: #333;\n            font-size: 16px;\n        }\n        .word-box {\n            margin-top: 10px;\n            padding: 10px;\n            background-color: #fff;\n            border: 2px solid #28a745;\n            border-radius: 8px;\n            box-shadow: 0 0 8px rgba(0, 0, 0, 0.1);\n            font-size: 16px;\n            color: #28a745;\n            text-align: left;\n            max-height: 250px;\n            overflow-y: auto;\n        }\n\n        \/* Chat Container Styles *\/\n        .chat-container {\n            background-color: #28a745;\n            border-radius: 15px;\n            box-shadow: 0 0 8px rgba(0, 0, 0, 0.1);\n            border: 3px solid #007bff;\n            overflow: hidden;\n            display: flex;\n            flex-direction: column;\n            height: auto;\n            max-height: 500px;\n            flex: 1;\n        }\n        .chat-header {\n            background-color: #1e7e34;\n            color: #fff;\n            padding: 12px;\n            text-align: center;\n            border-bottom: 1px solid #155724;\n            position: relative;\n        }\n        .chat-header h2 {\n            margin: 0;\n            font-size: 18px;\n        }\n        .chat-header .loader {\n            position: absolute;\n            right: 20px;\n            top: 50%;\n            transform: translateY(-50%);\n            display: none;\n        }\n        .chat-messages {\n            padding: 12px;\n            overflow-y: auto;\n            flex: 1;\n            background-color: #fff;\n            max-height: 300px;\n        }\n        .message {\n            margin-bottom: 10px;\n            padding: 10px;\n            border-radius: 6px;\n            font-size: 14px;\n            line-height: 1.5;\n        }\n        .user-message {\n            background-color: #ffc107;\n            color: #fff;\n            text-align: right;\n        }\n        .bot-message {\n            background-color: #17a2b8;\n            color: #fff;\n            text-align: left;\n        }\n\n        \/* Chat Input Styles *\/\n        .chat-input {\n            display: flex;\n            align-items: center;\n            background-color: #c3e6cb;\n            padding: 10px;\n            justify-content: space-between;\n            flex-wrap: wrap;\n            gap: 8px;\n        }\n        .send-button, .stop-button {\n            background-color: #17a2b8;\n            color: #fff;\n            font-weight: bold;\n            border: none;\n            border-radius: 5px;\n            padding: 12px 16px;\n            cursor: pointer;\n            transition: background-color 0.3s;\n            flex: 1;\n            max-width: 150px;\n            font-size: 16px;\n        }\n        .stop-button {\n            background-color: #dc3545;\n        }\n        .send-button:hover,\n        .stop-button:hover,\n        .send-button:focus,\n        .stop-button:focus {\n            background-color: #218838;\n            outline: none;\n        }\n\n        \/* Voice & Role Selection Styles *\/\n        .voice-selection,\n        .role-selection {\n            margin: 5px 0;\n            width: 100%;\n            max-width: 300px;\n        }\n        .voice-selection label,\n        .role-selection label {\n            display: block;\n            margin-bottom: 5px;\n            font-weight: bold;\n            color: #333;\n        }\n        .voice-selection select,\n        .role-selection select {\n            width: 100%;\n            padding: 8px;\n            border-radius: 5px;\n            border: 1px solid #ccc;\n            font-size: 14px;\n        }\n\n        \/* Loader Styles *\/\n        .loader {\n            border: 4px solid #f3f3f3;\n            border-top: 4px solid #17a2b8;\n            border-radius: 50%;\n            width: 20px;\n            height: 20px;\n            animation: spin 2s linear infinite;\n            display: inline-block;\n            margin-left: 10px;\n        }\n\n        @keyframes spin {\n            0% { transform: rotate(0deg); }\n            100% { transform: rotate(360deg); }\n        }\n\n        \/* Portrait Mode *\/\n        @media (orientation: portrait) {\n            .image-chat-wrapper {\n                flex-direction: column;\n            }\n            .image-container, .chat-container {\n                width: 100%;\n                max-width: 100%;\n            }\n        }\n\n        \/* Landscape Mode *\/\n        @media (orientation: landscape) and (min-width: 600px) {\n            .image-chat-wrapper {\n                flex-direction: row;\n                justify-content: space-between;\n            }\n            .image-container, .chat-container {\n                width: 48%;\n                max-width: 48%;\n            }\n            .word-box {\n                max-height: 200px;\n            }\n            .chat-header h2 {\n                font-size: 20px;\n            }\n            .message {\n                font-size: 15px;\n            }\n            .send-button, .stop-button {\n                font-size: 18px;\n                padding: 14px 20px;\n            }\n        }\n\n        \/* General Mobile Responsiveness *\/\n        @media (max-width: 768px) {\n            .chat-header h2 {\n                font-size: 16px;\n            }\n            .message {\n                font-size: 14px;\n            }\n            .send-button, .stop-button {\n                font-size: 16px;\n                padding: 12px 16px;\n            }\n            .word-box {\n                font-size: 15px;\n            }\n            .voice-selection select,\n            .role-selection select {\n                font-size: 14px;\n            }\n        }\n\n        \/* Samsung Android Specific Adjustments *\/\n        @media only screen and (max-device-width: 480px) and (-webkit-min-device-pixel-ratio: 2) {\n            .chat-header h2 {\n                font-size: 18px;\n            }\n            .send-button, .stop-button {\n                padding: 14px 18px;\n                font-size: 16px;\n            }\n            .message {\n                font-size: 14px;\n            }\n            .word-box {\n                font-size: 16px;\n            }\n            .chat-input input {\n                font-size: 16px;\n            }\n        }\n    <\/style>\n<\/head>\n<body>\n    <div class=\"menu\">\n<a href=\"https:\/\/i-cte.org\/robot\/life-stories-conversation\/\">Conversation<\/a>\n<a href=\"https:\/\/i-cte.org\/robot\/life-stories-vocabulary\/\">Vocabulary<\/a>\n<a href=\"https:\/\/i-cte.org\/robot\/life-stories-real-life\/\">Real Life<\/a>\n<a href=\"https:\/\/i-cte.org\/robot\/life-stories-describing-pictures\/\">Describing Pictures<\/a>\n<a href=\"https:\/\/i-cte.org\/robot\/life-stories-reading-comprehension\/\">Reading<\/a>\n<a href=\"https:\/\/i-cte.org\/robot\/life-stories-listening\/\">Listening<\/a>\n    <\/div>\n\n    <div class=\"container\">\n        <div class=\"image-chat-wrapper\">\n            <div class=\"image-container\">\n                <img decoding=\"async\" src=\"https:\/\/i-cte.org\/robot\/wp-content\/uploads\/2025\/05\/DALL\u00b7E-2025-05-13-18.46.33-A-single-small-academic-themed-robot-instructor-designed-to-teach-in-a-classroom.-The-robot-is-knee-high-sleek-and-professional-looking-wearing-dig-1.webp\" alt=\"Robot teacher in a classroom\">\n                <div class=\"sentence-text\">\n                    Practice the conversation. Choose your role, listen, and answer like a real conversation.\n                <\/div>\n                <div id=\"word-box\" class=\"word-box\">\n                    <!-- Script will be displayed here -->\n                <\/div>\n            <\/div>\n            <div class=\"chat-container\">\n                <div class=\"chat-header\">\n                    <h2>Life Stories &#8211; Conversation<\/h2>\n                    <div class=\"loader\" id=\"synthesis-loader\"><\/div>\n                <\/div>\n                <div class=\"chat-messages\" id=\"chat-messages\">\n                    <!-- Messages will appear here -->\n                <\/div>\n                <div class=\"chat-input\">\n                    <div class=\"role-selection\">\n                        <label for=\"role-select\">Choose Roles:<\/label>\n                        <select id=\"role-select\" aria-label=\"Select Role\">\n                            <option value=\"student-todd\">Student = Todd, Bot = Megan<\/option>\n                            <option value=\"student-megan\">Student = Megan, Bot = Todd<\/option>\n                        <\/select>\n                    <\/div>\n                    <div class=\"voice-selection\">\n                        <label for=\"voice-select\">Choose Voice (US \/ UK):<\/label>\n                        <select id=\"voice-select\" aria-label=\"Select Voice\">\n                            <option value=\"\">Loading voices&#8230;<\/option>\n                        <\/select>\n                    <\/div>\n                    <button id=\"start-btn\" class=\"send-button\" aria-label=\"Start Lesson\">Start<\/button>\n                    <button id=\"stop-btn\" class=\"stop-button\" aria-label=\"Stop Lesson\">Stop<\/button>\n                <\/div>\n            <\/div>\n        <\/div>\n    <\/div>\n\n    <div class=\"menu\">\n<a href=\"https:\/\/i-cte.org\/robot\/life-stories-conversation\/\">Conversation<\/a>\n<a href=\"https:\/\/i-cte.org\/robot\/life-stories-vocabulary\/\">Vocabulary<\/a>\n<a href=\"https:\/\/i-cte.org\/robot\/life-stories-real-life\/\">Real Life<\/a>\n<a href=\"https:\/\/i-cte.org\/robot\/life-stories-describing-pictures\/\">Describing Pictures<\/a>\n<a href=\"https:\/\/i-cte.org\/robot\/life-stories-reading-comprehension\/\">Reading<\/a>\n<a href=\"https:\/\/i-cte.org\/robot\/life-stories-listening\/\">Listening<\/a>\n    <\/div>\n\n<script>\n    \/\/ Conversation in pairs: Todd line then Megan line\n    const conversationPairs = [\n        {\n            todd: \"Hey, that jewelry is really interesting. Where did you get it?\",\n            megan: \"Yes, it\u2019s beautiful, isn\u2019t it? It\u2019s Mayan. You know, from Mexico.\"\n        },\n        {\n            todd: \"Oh, right. Did you go there on vacation?\",\n            megan: \"No, actually I lived there with my family for five years.\"\n        },\n        {\n            todd: \"Really? You lived in Mexico? You didn\u2019t tell me that. When did you move there?\",\n            megan: \"When I was around nine, I guess. My father got a job there, so ...\"\n        },\n        {\n            todd: \"Tell me about Mexico. Did you like it?\",\n            megan: \"Yeah, it was great. We stayed in Yucat\u00e1n, in the south. The people are really friendly, and the food was amazing!\"\n        },\n        {\n            todd: \"When did you move back to the States?\",\n            megan: \"We came to San Francisco when I was, er ... fourteen.\"\n        },\n        {\n            todd: \"So, which do you prefer, there or here?\",\n            megan: \"I think I prefer it here.\"\n        },\n        {\n            todd: \"Oh really? Why\u2019s that?\",\n            megan: \"Because I met you here!\"\n        }\n    ];\n\n    \/\/ Stop keywords\n    const stopKeywords = [\"goodbye\", \"good bye\", \"bye\", \"bye-bye\", \"byebye\"];\n\n    let currentPairIndex = 0;\n    let recognition;\n    let isLessonActive = false;\n    let speechRecognitionActive = false;\n\n    const speechSynthesisSupported = 'speechSynthesis' in window;\n    const SpeechRecognitionClass = window.SpeechRecognition || window.webkitSpeechRecognition;\n    const speechRecognitionSupported = !!SpeechRecognitionClass;\n\n    let voices = [];\n    let selectedVoice = null;\n    let currentRoleMode = \"student-todd\"; \/\/ default\n    let currentVoiceList = [];\n\n    \/\/ Only US & UK English\n    const allowedLangs = ['en-US', 'en-GB'];\n\n    function initialize() {\n        loadScriptToWordBox();\n\n        const roleSelect = document.getElementById('role-select');\n        roleSelect.onchange = () => {\n            currentRoleMode = roleSelect.value;\n        };\n\n        loadVoices();\n\n        if (speechSynthesisSupported) {\n            setTimeout(() => greetUser(), 500);\n        } else {\n            appendMessage(\"Sorry, your browser does not support speech synthesis.\", \"bot\");\n        }\n\n        if (!speechRecognitionSupported) {\n            appendMessage(\"Sorry, your browser does not support speech recognition.\", \"bot\");\n        }\n\n        document.getElementById('start-btn').onclick = function () {\n            if (isLessonActive) return;\n\n            if (!speechSynthesisSupported) {\n                appendMessage(\"Speech synthesis is not supported in your browser.\", \"bot\");\n                return;\n            }\n            if (!speechRecognitionSupported) {\n                appendMessage(\"Speech recognition is not supported in your browser.\", \"bot\");\n                return;\n            }\n\n            isLessonActive = true;\n            currentPairIndex = 0;\n            clearChat();\n            appendMessage(\"Let\u2019s start the conversation.\", \"bot\");\n            startConversationTurn();\n        };\n\n        document.getElementById('stop-btn').onclick = function () {\n            if (recognition && speechRecognitionActive) {\n                recognition.stop();\n                speechRecognitionActive = false;\n            }\n            endLesson(true);\n        };\n    }\n\n    function loadScriptToWordBox() {\n        const wordBox = document.getElementById('word-box');\n        wordBox.innerHTML = \"\";\n        conversationPairs.forEach(pair => {\n            if (pair.todd) {\n                const line1 = document.createElement('div');\n                line1.textContent = \"Todd: \" + pair.todd;\n                wordBox.appendChild(line1);\n            }\n            if (pair.megan) {\n                const line2 = document.createElement('div');\n                line2.textContent = \"Megan: \" + pair.megan;\n                wordBox.appendChild(line2);\n            }\n            const br = document.createElement('div');\n            br.textContent = \"\";\n            wordBox.appendChild(br);\n        });\n        wordBox.scrollTop = wordBox.scrollHeight;\n    }\n\n    function loadVoices() {\n        if (!speechSynthesisSupported) return;\n\n        function attemptPopulate() {\n            voices = window.speechSynthesis.getVoices();\n            if (voices && voices.length > 0) {\n                populateVoiceList();\n            }\n        }\n\n        attemptPopulate();\n        window.speechSynthesis.onvoiceschanged = attemptPopulate;\n    }\n\n    function populateVoiceList() {\n        const voiceSelect = document.getElementById('voice-select');\n        if (!voiceSelect) return;\n\n        voiceSelect.innerHTML = '';\n        currentVoiceList = [];\n\n        const enVoices = voices.filter(v => allowedLangs.includes(v.lang));\n\n        \/\/ Try to pick up to four labelled voices: US\/UK, male\/female\n        const configs = [\n            {\n                label: \"US English \u2013 Female\",\n                match: v =>\n                    v.lang === 'en-US' &&\n                    \/female|zira|jessa|samantha|aria|google us english\/i.test(v.name)\n            },\n            {\n                label: \"US English \u2013 Male\",\n                match: v =>\n                    v.lang === 'en-US' &&\n                    \/male|david|mark|guy|benjamin\/i.test(v.name)\n            },\n            {\n                label: \"UK English \u2013 Female\",\n                match: v =>\n                    v.lang === 'en-GB' &&\n                    \/female|hazel|susan|google uk english female\/i.test(v.name)\n            },\n            {\n                label: \"UK English \u2013 Male\",\n                match: v =>\n                    v.lang === 'en-GB' &&\n                    \/male|george|ryan|google uk english male\/i.test(v.name)\n            }\n        ];\n\n        const labeledVoices = [];\n        const used = new Set();\n\n        configs.forEach(cfg => {\n            const found = enVoices.find(v => cfg.match(v) && !used.has(v.name + v.lang));\n            if (found) {\n                labeledVoices.push({ label: cfg.label, voice: found });\n                used.add(found.name + found.lang);\n            }\n        });\n\n        \/\/ If none matched patterns, just take first up to 4 en-US\/en-GB voices\n        let finalList;\n        if (labeledVoices.length > 0) {\n            finalList = labeledVoices;\n        } else if (enVoices.length > 0) {\n            finalList = enVoices.slice(0, 4).map(v => ({\n                label: `${v.lang === 'en-US' ? 'US' : 'UK'} English \u2013 ${v.name}`,\n                voice: v\n            }));\n        } else {\n            finalList = [];\n        }\n\n        if (finalList.length === 0) {\n            const option = document.createElement('option');\n            option.value = \"\";\n            option.textContent = \"No US\/UK voices available\";\n            voiceSelect.appendChild(option);\n            voiceSelect.disabled = true;\n            selectedVoice = null;\n            return;\n        }\n\n        voiceSelect.disabled = false;\n        finalList.forEach((item, index) => {\n            const option = document.createElement('option');\n            option.value = String(index);\n            option.textContent = item.label;\n            voiceSelect.appendChild(option);\n            currentVoiceList[index] = item.voice;\n        });\n\n        voiceSelect.selectedIndex = 0;\n        selectedVoice = currentVoiceList[0];\n\n        voiceSelect.onchange = () => {\n            const selectedIndex = parseInt(voiceSelect.value, 10);\n            if (!isNaN(selectedIndex) && currentVoiceList[selectedIndex]) {\n                selectedVoice = currentVoiceList[selectedIndex];\n                console.log(`Selected voice: ${selectedVoice.name} (${selectedVoice.lang})`);\n            }\n        };\n    }\n\n    function greetUser() {\n        const greeting =\n            \"Hello! We\u2019re going to practice the conversation between Todd and Megan. \" +\n            \"Choose your role, then click Start. Listen to your partner\u2019s line and then answer.\";\n        appendMessage(greeting, 'bot');\n        showSynthesisLoader(true);\n        sayText(greeting, \"en-US\").then(() => {\n            showSynthesisLoader(false);\n        });\n    }\n\n    \/\/ Start one turn (bot speaks its role, then waits for student)\n    function startConversationTurn() {\n        if (!isLessonActive) return;\n\n        if (currentPairIndex >= conversationPairs.length) {\n            endLesson(false);\n            return;\n        }\n\n        const pair = conversationPairs[currentPairIndex];\n\n        let botSpeaker, botText, studentSpeaker, expectedStudentText;\n\n        if (currentRoleMode === \"student-todd\") {\n            botSpeaker = \"Megan\";\n            botText = pair.megan;\n            studentSpeaker = \"Todd\";\n            expectedStudentText = pair.todd;\n        } else {\n            botSpeaker = \"Todd\";\n            botText = pair.todd;\n            studentSpeaker = \"Megan\";\n            expectedStudentText = pair.megan;\n        }\n\n        \/\/ If there's no bot text, finish\n        if (!botText) {\n            endLesson(false);\n            return;\n        }\n\n        \/\/ Bot speaks its line\n        const botDisplay = botSpeaker + \": \" + botText;\n        appendMessage(botDisplay, \"bot\");\n        showSynthesisLoader(true);\n        sayText(botText, \"en-US\").then(() => {\n            showSynthesisLoader(false);\n\n            \/\/ If there is no student response for this pair, move straight on\n            if (!expectedStudentText) {\n                currentPairIndex++;\n                setTimeout(startConversationTurn, 800);\n            } else {\n                \/\/ Just listen (no extra prompts)\n                listenForStudent(studentSpeaker, expectedStudentText);\n            }\n        });\n    }\n\n    function listenForStudent(studentSpeaker, expectedText) {\n        if (!speechRecognitionSupported) return;\n\n        recognition = new SpeechRecognitionClass();\n        recognition.lang = 'en-US';\n        recognition.interimResults = false;\n        recognition.maxAlternatives = 1;\n\n        showRecognitionLoader(true);\n        appendMessage(\"Listening...\", \"bot\");\n        speechRecognitionActive = true;\n\n        recognition.start();\n\n        recognition.onresult = function (event) {\n            if (!speechRecognitionActive) return;\n\n            const userInput = event.results[0][0].transcript.trim();\n            const formattedInput = normalizeAndFormatUserInput(userInput);\n            appendMessage(formattedInput, 'user');\n\n            showRecognitionLoader(false);\n            speechRecognitionActive = false;\n\n            if (checkStopKeywords(formattedInput.toLowerCase())) {\n                endLesson(true);\n                return;\n            }\n\n            \/\/ No extra feedback sentence; move on to the next turn\n            currentPairIndex++;\n            setTimeout(startConversationTurn, 800);\n        };\n\n        recognition.onspeechend = function () {\n            if (speechRecognitionActive) {\n                recognition.stop();\n                speechRecognitionActive = false;\n                showRecognitionLoader(false);\n            }\n        };\n\n        recognition.onerror = function (event) {\n            showRecognitionLoader(false);\n            speechRecognitionActive = false;\n            let errorMessage = 'There was a microphone problem: ' + event.error + \".\";\n            if (event.error === 'not-allowed') {\n                errorMessage =\n                    \"Microphone access was not allowed. Please allow microphone access in your browser settings.\";\n            }\n\n            appendMessage(errorMessage, 'bot');\n            showSynthesisLoader(true);\n            sayText(errorMessage, \"en-US\").then(() => {\n                showSynthesisLoader(false);\n                if (event.error !== 'not-allowed') {\n                    setTimeout(() => {\n                        listenForStudent(studentSpeaker, expectedText);\n                    }, 2000);\n                }\n            });\n        };\n    }\n\n    function checkStopKeywords(userInput) {\n        const pattern = new RegExp('\\\\b(' + stopKeywords.join('|') + ')\\\\b', 'i');\n        return pattern.test(userInput);\n    }\n\n    function normalizeAndFormatUserInput(text) {\n        let normalized = text.replace(\/\\bi\\b\/g, \"I\");\n        return formatSentence(normalized);\n    }\n\n    function formatSentence(text) {\n        if (!text) return text;\n        text = text.charAt(0).toUpperCase() + text.slice(1);\n\n        const questionWords = ['who', 'what', 'where', 'when', 'why', 'how', 'is', 'are', 'do', 'does', 'can', 'should', 'will', 'would'];\n        const firstWord = text.split(\" \")[0].toLowerCase();\n\n        if (questionWords.includes(firstWord) && !text.endsWith('?')) {\n            text += '?';\n        } else if (!text.endsWith('.') && !text.endsWith('?')) {\n            text += '.';\n        }\n\n        return text;\n    }\n\n    function clearChat() {\n        const messageContainer = document.getElementById('chat-messages');\n        if (messageContainer) {\n            messageContainer.innerHTML = \"\";\n        }\n    }\n\n    function endLesson(userStopped = false) {\n        if (speechSynthesisSupported) {\n            window.speechSynthesis.cancel();\n        }\n\n        if (recognition && speechRecognitionActive) {\n            recognition.stop();\n            speechRecognitionActive = false;\n        }\n\n        if (!isLessonActive) return;\n        isLessonActive = false;\n\n        let message;\n        if (userStopped) {\n            message = \"Thank you for practicing! Goodbye!\";\n        } else {\n            message = \"Well done! You\u2019ve finished the conversation. Try again with the other role when you are ready.\";\n        }\n        appendMessage(message, \"bot\");\n        showSynthesisLoader(true);\n        sayText(message, \"en-US\").then(() => {\n            showSynthesisLoader(false);\n        });\n    }\n\n    function sayText(text, lang) {\n        return new Promise((resolve) => {\n            if (!speechSynthesisSupported) {\n                resolve();\n                return;\n            }\n            const utterance = new SpeechSynthesisUtterance(text);\n            utterance.lang = lang;\n            utterance.rate = 1.0;\n            utterance.pitch = 1.0;\n\n            if (selectedVoice) {\n                utterance.voice = selectedVoice;\n            }\n\n            utterance.onend = function () {\n                resolve();\n            };\n\n            utterance.onerror = function (event) {\n                console.error('Speech synthesis error:', event.error);\n                resolve();\n            };\n\n            window.speechSynthesis.speak(utterance);\n        });\n    }\n\n    function appendMessage(text, sender) {\n        const messageContainer = document.getElementById('chat-messages');\n        if (!messageContainer) return;\n        const messageElement = document.createElement('div');\n        messageElement.classList.add('message');\n        messageElement.classList.add(sender === 'bot' ? 'bot-message' : 'user-message');\n        messageElement.innerText = text;\n        messageContainer.appendChild(messageElement);\n        messageContainer.scrollTop = messageContainer.scrollHeight;\n    }\n\n    function showSynthesisLoader(show) {\n        const loader = document.getElementById('synthesis-loader');\n        if (!loader) return;\n        loader.style.display = show ? 'inline-block' : 'none';\n        if (show) {\n            loader.style.borderTop = '4px solid #17a2b8';\n        }\n    }\n\n    function showRecognitionLoader(show) {\n        const loader = document.getElementById('synthesis-loader');\n        if (!loader) return;\n        if (show) {\n            loader.style.display = 'inline-block';\n            loader.style.borderTop = '4px solid #ffc107';\n        } else {\n            loader.style.display = 'none';\n        }\n    }\n\n    window.onload = initialize;\n<\/script>\n<\/body>\n<\/html>\n\n","protected":false},"excerpt":{"rendered":"<p>This Robot is used for practicing English at level A2. In order to interact with this Robot smoothly, please use<\/p>\n","protected":false},"author":1,"featured_media":204,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"colormag_page_layout":"default_layout","footnotes":""},"categories":[18,5],"tags":[],"class_list":["post-409","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-a2","category-chatbot"],"_links":{"self":[{"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/posts\/409","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/comments?post=409"}],"version-history":[{"count":1,"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/posts\/409\/revisions"}],"predecessor-version":[{"id":410,"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/posts\/409\/revisions\/410"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/media\/204"}],"wp:attachment":[{"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/media?parent=409"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/categories?post=409"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/tags?post=409"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}