{"id":386,"date":"2025-12-03T06:21:57","date_gmt":"2025-12-03T06:21:57","guid":{"rendered":"https:\/\/i-cte.org\/robot\/?p=386"},"modified":"2025-12-03T06:21:57","modified_gmt":"2025-12-03T06:21:57","slug":"vacation-vocabulary","status":"publish","type":"post","link":"https:\/\/i-cte.org\/robot\/vacation-vocabulary\/","title":{"rendered":"Vacation &#8211; Vocabulary"},"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>Vocabulary \u2013 Travel Activities<\/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-chat-wrapper {\n            display: flex;\n            flex-direction: column;\n            width: 100%;\n            max-width: 800px;\n            flex: 1;\n        }\n\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: 15px;\n            color: #28a745;\n            text-align: left;\n            max-height: 260px;\n            overflow-y: auto;\n        }\n\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 {\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-selection {\n            margin: 5px 0;\n            width: 100%;\n            max-width: 300px;\n        }\n        .voice-selection label {\n            display: block;\n            margin-bottom: 5px;\n            font-weight: bold;\n            color: #333;\n        }\n        .voice-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 {\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        @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        @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: 220px;\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        @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                font-size: 14px;\n            }\n        }\n\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\/vacation-conversation\/\">Conversation<\/a>\n            <a href=\"https:\/\/i-cte.org\/robot\/vacation-vocabulary\/\">Vocabulary<\/a>\n            <a href=\"https:\/\/i-cte.org\/robot\/vacation-real-life\/\">Real Life<\/a>\n            <a href=\"https:\/\/i-cte.org\/robot\/vacation-describing-pictures\/\">Describing Pictures<\/a>\n            <a href=\"https:\/\/i-cte.org\/robot\/vacation-reading-comprehension\/\">Reading<\/a>\n            <a href=\"https:\/\/i-cte.org\/robot\/vacation-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 helping with travel activities\">\n                <div class=\"sentence-text\">\n                    Practice travel activities. Listen, talk about your trips, and get feedback.\n                <\/div>\n                <div id=\"word-box\" class=\"word-box\">\n                    <!-- Vocabulary list will appear here -->\n                <\/div>\n            <\/div>\n            <div class=\"chat-container\">\n                <div class=\"chat-header\">\n                    <h2>Vocabulary \u2013 Travel Activities<\/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=\"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 Practice\">Start<\/button>\n                    <button id=\"stop-btn\" class=\"stop-button\" aria-label=\"Stop Practice\">Stop<\/button>\n                <\/div>\n            <\/div>\n        <\/div>\n    <\/div>\n\n    <div class=\"menu\">\n            <a href=\"https:\/\/i-cte.org\/robot\/vacation-conversation\/\">Conversation<\/a>\n            <a href=\"https:\/\/i-cte.org\/robot\/vacation-vocabulary\/\">Vocabulary<\/a>\n            <a href=\"https:\/\/i-cte.org\/robot\/vacation-real-life\/\">Real Life<\/a>\n            <a href=\"https:\/\/i-cte.org\/robot\/vacation-describing-pictures\/\">Describing Pictures<\/a>\n            <a href=\"https:\/\/i-cte.org\/robot\/vacation-reading-comprehension\/\">Reading<\/a>\n            <a href=\"https:\/\/i-cte.org\/robot\/vacation-listening\/\">Listening<\/a>\n    <\/div>\n\n<script>\n    \/\/ Travel activities vocabulary\n    const activities = [\n        {\n            id: 1,\n            phrase: \"go to a museum\",\n            keywords: [\"museum\"],\n            example: \"When I visit a new city, I always go to a museum.\"\n        },\n        {\n            id: 2,\n            phrase: \"go sightseeing\",\n            keywords: [\"sightseeing\", \"see the sights\"],\n            example: \"On the first day of my trip, I like to go sightseeing.\"\n        },\n        {\n            id: 3,\n            phrase: \"go scuba diving\",\n            keywords: [\"scuba diving\", \"go diving\"],\n            example: \"When I\u2019m near the ocean, I want to go scuba diving.\"\n        },\n        {\n            id: 4,\n            phrase: \"buy souvenirs\",\n            keywords: [\"souvenirs\", \"buy souvenirs\"],\n            example: \"I usually buy souvenirs for my family when I travel.\"\n        },\n        {\n            id: 5,\n            phrase: \"go hiking\",\n            keywords: [\"hiking\", \"go hiking\"],\n            example: \"In the mountains, we like to go hiking.\"\n        },\n        {\n            id: 6,\n            phrase: \"visit temples\",\n            keywords: [\"visit temples\", \"temples\"],\n            example: \"When I go to Thailand, I want to visit temples.\"\n        },\n        {\n            id: 7,\n            phrase: \"sunbathe on the beach\",\n            keywords: [\"sunbathe\", \"beach\"],\n            example: \"On vacation, I just want to sunbathe on the beach and relax.\"\n        },\n        {\n            id: 8,\n            phrase: \"go whitewater rafting\",\n            keywords: [\"whitewater rafting\", \"rafting\"],\n            example: \"My friends want to go whitewater rafting on our next trip.\"\n        },\n        {\n            id: 9,\n            phrase: \"go on a guided tour\",\n            keywords: [\"guided tour\", \"tour guide\"],\n            example: \"Sometimes I go on a guided tour to learn more about the city.\"\n        }\n    ];\n\n    \/\/ Words that show they talk about trips\/holidays\n    const travelTimeWords = [\n        \"on vacation\", \"on holiday\", \"on my holiday\", \"on my trip\",\n        \"when I travel\", \"when we travel\", \"when I visit a new city\",\n        \"in another country\", \"on our trip\"\n    ];\n\n    const stopKeywords = [\"goodbye\", \"good bye\", \"bye\", \"bye-bye\", \"byebye\", \"stop\"];\n\n    const positiveFeedback = [\n        \"Nice travel sentence!\",\n        \"Great! That sounds natural.\",\n        \"Excellent use of the travel phrase.\",\n        \"Very good \u2013 your sentence is clear.\",\n        \"Well done. That was a good example.\"\n    ];\n\n    const constructiveTemplates = [\n        activity => `Try to use the words \u201c${activity.phrase}\u201d in your sentence. For example: ${activity.example}`,\n        activity => `I didn\u2019t really hear \u201c${activity.phrase}\u201d. Please say one more sentence using that phrase.`,\n        activity => `Remember to include \u201c${activity.phrase}\u201d. For example: ${activity.example}`\n    ];\n\n    const travelHint = \"Next time, you can also say when or where you do it, for example on vacation or on your trip.\";\n\n    let currentActivityIndex = 0;\n    let recognition;\n    let isLessonActive = false;\n    let speechRecognitionActive = false;\n    let inFinalTask = 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 currentVoiceList = [];\n    const allowedLangs = ['en-US', 'en-GB'];\n\n    function initialize() {\n        loadVocabularyToBox();\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            inFinalTask = false;\n            currentActivityIndex = 0;\n            clearChat();\n            appendMessage(\"Let\u2019s practice the travel activities from one to nine.\", \"bot\");\n            startActivity();\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 loadVocabularyToBox() {\n        const box = document.getElementById('word-box');\n        box.innerHTML = \"\";\n\n        const title1 = document.createElement('div');\n        title1.style.fontWeight = \"bold\";\n        title1.textContent = \"Travel activities:\";\n        box.appendChild(title1);\n\n        activities.forEach((act, index) => {\n            const line = document.createElement('div');\n            line.textContent = (index + 1) + \". \" + act.phrase;\n            box.appendChild(line);\n        });\n\n        const spacer = document.createElement('div');\n        spacer.textContent = \"\";\n        box.appendChild(spacer);\n\n        const exTitle = document.createElement('div');\n        exTitle.style.fontWeight = \"bold\";\n        exTitle.textContent = \"Example sentences:\";\n        box.appendChild(exTitle);\n\n        activities.forEach((act, index) => {\n            const exLine = document.createElement('div');\n            const highlighted = act.example.replace(\n                act.phrase,\n                \"<strong>\" + act.phrase + \"<\/strong>\"\n            );\n            exLine.innerHTML = (index + 1) + \". \" + highlighted;\n            box.appendChild(exLine);\n        });\n\n        box.scrollTop = box.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        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        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            }\n        };\n    }\n\n    function greetUser() {\n        const greeting =\n            \"Hello! We\u2019re going to practice travel activities like go to a museum, buy souvenirs, \" +\n            \"and sunbathe on the beach. Click Start, then listen and say your own sentence for each activity.\";\n        appendMessage(greeting, 'bot');\n        showSynthesisLoader(true);\n        sayText(greeting, \"en-US\").then(() => {\n            showSynthesisLoader(false);\n        });\n    }\n\n    function startActivity() {\n        if (!isLessonActive) return;\n\n        if (currentActivityIndex >= activities.length) {\n            startFinalTask();\n            return;\n        }\n\n        const act = activities[currentActivityIndex];\n        const number = currentActivityIndex + 1;\n        const prompt =\n            `Item ${number}. Say a full sentence using the activity \u201c${act.phrase}\u201d. ` +\n            `You can talk about what you do when you travel or go on vacation.`;\n\n        appendMessage(prompt, 'bot');\n        showSynthesisLoader(true);\n        sayText(prompt, \"en-US\").then(() => {\n            showSynthesisLoader(false);\n            listenForActivity(act);\n        });\n    }\n\n    function listenForActivity(act) {\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        recognition.start();\n\n        recognition.onresult = function (event) {\n            if (!speechRecognitionActive) return;\n\n            const userInput = event.results[0][0].transcript.trim();\n            const formatted = formatSentence(normalizeAndFormatUserInput(userInput));\n            appendMessage(formatted, 'user');\n\n            showRecognitionLoader(false);\n            speechRecognitionActive = false;\n\n            const lower = formatted.toLowerCase();\n\n            if (checkStopKeywords(lower)) {\n                endLesson(true);\n                return;\n            }\n\n            const feedback = createActivityFeedback(lower, act);\n            appendMessage(feedback, 'bot');\n            showSynthesisLoader(true);\n            sayText(feedback, \"en-US\").then(() => {\n                showSynthesisLoader(false);\n                currentActivityIndex++;\n                setTimeout(startActivity, 800);\n            });\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 msg = \"There was a microphone problem: \" + event.error + \".\";\n            if (event.error === \"not-allowed\") {\n                msg = \"Microphone access was not allowed. Please allow microphone access in your browser settings.\";\n            }\n            appendMessage(msg, \"bot\");\n            showSynthesisLoader(true);\n            sayText(msg, \"en-US\").then(() => {\n                showSynthesisLoader(false);\n                if (event.error !== \"not-allowed\") {\n                    setTimeout(() => listenForActivity(act), 2000);\n                }\n            });\n        };\n    }\n\n    function createActivityFeedback(lower, act) {\n        const hasKeyword = act.keywords.some(k => lower.includes(k.toLowerCase()));\n        const mentionsTravel = travelTimeWords.some(w => lower.includes(w));\n\n        if (!hasKeyword) {\n            const template =\n                constructiveTemplates[Math.floor(Math.random() * constructiveTemplates.length)];\n            return template(act);\n        }\n\n        if (hasKeyword && !mentionsTravel) {\n            return positiveFeedback[Math.floor(Math.random() * positiveFeedback.length)] +\n                \" \" + travelHint;\n        }\n\n        return positiveFeedback[Math.floor(Math.random() * positiveFeedback.length)];\n    }\n\n    function startFinalTask() {\n        inFinalTask = true;\n        const prompt =\n            \"Great work! For the last task, tell me about a real trip or vacation. \" +\n            \"Use at least two of these activities in one long answer. \" +\n            \"For example: On vacation I go sightseeing and buy souvenirs, and sometimes I go to a museum.\";\n        appendMessage(prompt, 'bot');\n        showSynthesisLoader(true);\n        sayText(prompt, \"en-US\").then(() => {\n            showSynthesisLoader(false);\n            listenForFinalTask();\n        });\n    }\n\n    function listenForFinalTask() {\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        recognition.start();\n\n        recognition.onresult = function (event) {\n            if (!speechRecognitionActive) return;\n\n            const userInput = event.results[0][0].transcript.trim();\n            const formatted = formatSentence(normalizeAndFormatUserInput(userInput));\n            appendMessage(formatted, 'user');\n\n            showRecognitionLoader(false);\n            speechRecognitionActive = false;\n\n            const lower = formatted.toLowerCase();\n\n            if (checkStopKeywords(lower)) {\n                endLesson(true);\n                return;\n            }\n\n            const usedCount = activities.filter(act =>\n                act.keywords.some(k => lower.includes(k.toLowerCase()))\n            ).length;\n\n            let feedback;\n            if (usedCount >= 4) {\n                feedback = \"Excellent! You used many travel activities in your description.\";\n            } else if (usedCount >= 2) {\n                feedback = \"Good job! You used at least two activities. Very clear.\";\n            } else if (usedCount === 1) {\n                feedback = \"Nice answer. Next time, try to add one or two more activities from the list.\";\n            } else {\n                feedback = \"Thank you for your answer. Try again later and include words like museum, souvenirs, hiking, or guided tour.\";\n            }\n\n            appendMessage(feedback, 'bot');\n            showSynthesisLoader(true);\n            sayText(feedback, \"en-US\").then(() => {\n                showSynthesisLoader(false);\n                endLesson(false);\n            });\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 msg = \"There was a microphone problem: \" + event.error + \".\";\n            if (event.error === \"not-allowed\") {\n                msg = \"Microphone access was not allowed. Please allow microphone access in your browser settings.\";\n            }\n            appendMessage(msg, 'bot');\n            showSynthesisLoader(true);\n            sayText(msg, \"en-US\").then(() => {\n                showSynthesisLoader(false);\n                if (event.error !== \"not-allowed\") {\n                    setTimeout(() => listenForFinalTask(), 2000);\n                }\n            });\n        };\n    }\n\n    function checkStopKeywords(lower) {\n        const pattern = new RegExp(\"\\\\b(\" + stopKeywords.join(\"|\") + \")\\\\b\", \"i\");\n        return pattern.test(lower);\n    }\n\n    function normalizeAndFormatUserInput(text) {\n        let normalized = text.replace(\/\\bi\\b\/g, \"I\");\n        return 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 = [\n            \"who\", \"what\", \"where\", \"when\", \"why\", \"how\",\n            \"is\", \"are\", \"do\", \"does\", \"can\", \"should\", \"will\", \"would\"\n        ];\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        if (recognition && speechRecognitionActive) {\n            recognition.stop();\n            speechRecognitionActive = false;\n        }\n        if (!isLessonActive) return;\n\n        isLessonActive = false;\n        inFinalTask = 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 travel activity practice. Come back anytime to review.\";\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 () {\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":195,"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-386","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\/386","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=386"}],"version-history":[{"count":1,"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/posts\/386\/revisions"}],"predecessor-version":[{"id":387,"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/posts\/386\/revisions\/387"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/media\/195"}],"wp:attachment":[{"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/media?parent=386"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/categories?post=386"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/i-cte.org\/robot\/wp-json\/wp\/v2\/tags?post=386"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}