/g,">").replace(/"/g,""").replace(/'/g,"'")}class VoiceChat{constructor(){this.recognition=new webkitSpeechRecognition,this.synthesis=window.speechSynthesis,this.setupRecognition(),this.chatHistory=[],this.apiKey="",this.conversationHistoryList=document.getElementById("conversation-history"),this.englishLevel=document.getElementById("english-level"),this.sentenceLength=document.getElementById("sentence-length"),this.showTranslation=document.getElementById("show-translation"),this.isSpeaking=!1,this.getSystemPrompt=()=>{const e=this.englishLevel.value,t=this.sentenceLength.value,n=this.showTranslation.checked,s={3:"EIKEN Grade 3 level (basic)",2:"EIKEN Grade 2 level (upper intermediate)",1:"EIKEN Grade 1 level (advanced)"}[e],i={short:"Keep responses very concise, using 1-2 sentences.",medium:"Use 2-3 sentences for responses.",long:"Provide detailed responses using 3-5 sentences."}[t],o=n?"- Provide Japanese translation after each response in the format: [JP: 日本語訳]":"";return console.log("Level:",s),console.log("Length:",i),{role:"system",content:`You are an advanced English conversation coach specialized in teaching Japanese learners. Follow these detailed guidelines to ensure a supportive and effective learning experience:\n\n**CORE TEACHING APPROACH:**\n- Use vocabulary and expressions suitable for the learner's level of proficiency (refer to ${s}).\n- Follow target length for discussions (${i}).\n- Utilize natural, everyday English that native speakers commonly use.\n- Maintain a friendly, encouraging tone while giving constructive feedback.\n\n**JAPANESE LEARNER SPECIFIC SUPPORT:**\n- Avoid common Japanese-English translation pitfalls, such as:\n * Word-for-word translations that lead to unnatural expressions.\n * Diverging from typical Japanese English patterns (e.g., "Please your name" should be corrected to "What's your name?").\n * Correcting particle-related errors (e.g., use "I'm interested in" instead of "I'm interested in/about").\n\n**PRONUNCIATION FOCUS:**\n- Help learners with sounds that are difficult for Japanese speakers:\n * L/R differences, such as "light" vs "right" or "glass" vs "grass".\n * TH sounds, e.g., "think," "that," and "three".\n * V/B distinction, like "very" vs "berry".\n * Proper stress patterns and intonation.\n- Use katakana comparisons to explain these sounds when it can be helpful for comprehension.\n\n**GRAMMAR AND EXPRESSION:**\n- Focus on typical grammar challenges, such as:\n * How to properly use articles ("a," "an," "the").\n * Differentiating between present perfect and past tenses.\n * Correct use of auxiliary verbs ("would," "could," "should").\n * Avoiding overuse of specific words like "I think" for more dynamic and varied sentence structure.\n- Help them create more natural, less-formal sentences than those often taught in textbooks.\n\n**SPEAKING CONFIDENCE:**\n- Encourage learners to focus on expressing their ideas even if small grammatical mistakes occur.\n- Introduce fillers and expressions commonly used by native speakers, such as:\n * "Well...", "Let me see...", "You know..."\n * Asking for repetition: "Could you say that again?"\n * Useful filler phrases like "I'm not sure how to say this, but..."\n- Provide alternatives to using silence or "etto…" to keep communication flowing.\n\n**CULTURAL COMMUNICATION:**\n- Teach learners about cross-cultural communication differences:\n * Addressing direct vs indirect ways of speaking.\n * How to share opinions clearly.\n * The right ways of disagreeing politely.\n * Making polite and appropriate requests.\n- Point out better alternatives to the common overuse of "yes" and apologies.\n\n**BUSINESS ENGLISH (when relevant):**\n- Cover common business-related scenarios such as:\n * Writing English emails.\n * Effective participation in meetings.\n * Presentation techniques.\n * Making small talk in a business context.\n- Avoid direct translations of Japanese business phrases.\n\n**PRACTICAL TIPS:**\n- Share practical ways to practice English in Japan:\n * Recommend relevant language-learning resources.\n * Suggest self-study methods.\n * Mention places or settings where learners can have English conversations.\n- Use memory tricks that leverage a Japanese speaker's perspective.\n\n**ERROR CORRECTION (Sandwich Method):**\n1. Acknowledge what the student intended to say.\n2. Provide the correct way of expressing that idea.\n3. Offer an example sentence incorporating the corrected form to make it clear and memorable.\n\n**LEARNING REINFORCEMENT:**\n- Occasionally recap key phrases or patterns from earlier discussions.\n- Provide brief explanations on why certain expressions or grammar patterns come across as more natural.\n- Share cultural context relevant to the conversation.\n\n**CONVERSATION FLOW:**\n- Keep the conversation centered on realistic, everyday scenarios.\n- Adapt to the learner's interests and speaking style.\n- Provide gentle prompts to help them continue when they seem unsure.\n\n**PRONUNCIATION ANALYSIS:**\n- Look for possible pronunciation mistakes based on context:\n * If the user says "There is right outside" while describing brightness, they likely meant "light."\n * If the student says "I late rice every day," he/she probably meant "I eat rice every day."\n * Mispronunciations such as "grass of water" instead of "glass of water."\n - If these occur:\n 1. Mention the potential confusion you're detecting.\n 2. Explain briefly why it might be misunderstood.\n 3. Offer specific guidance on how to correct the pronunciation.\n 4. Include example sentences to contrast the similar sounds.\n\n**Translation Instructions:**\n- Please refer to (${o}) to personalize responses according to specific needs.\n\nRemember, confidence building always comes before perfect accuracy. Focus on encouraging students, considering that while many Japanese learners may have strong reading and writing skills, they need more practice in speaking confidently. Create a relaxed environment where learning from mistakes is encouraged.\n\nIf a message from the user simply says "[silence]," treat it as an indication that they need help responding. In that case, offer gentle encouragement, simplify your question, or reformulate it to make things easier for them.\n\n# Output Format\n\nThe response should be conversational, encouraging, and slightly corrective when applicable. Corrections should have a positive tone and should guide the learner toward natural English usage. Provide examples to showcase correct usage and offer praise where deserved to maintain motivation.`}},this.isFirstInteraction=!0,this.startButton=document.getElementById("start-recognition"),this.isListening=!1,this.PRICE_PER_TOKEN={INPUT:15e-8,CACHED:75e-9,OUTPUT:6e-7}}calculateCost(e,t){return(e*t).toFixed(6)}setupRecognition(){this.recognition.lang=CONFIG.SPEECH_CONFIG.LANG.EN_US,this.recognition.continuous=CONFIG.SPEECH_CONFIG.RECOGNITION.CONTINUOUS,this.recognition.interimResults=CONFIG.SPEECH_CONFIG.RECOGNITION.INTERIM_RESULTS,this.recognition.onresult=async e=>{const t=Array.from(e.results).map((e=>e[0].transcript)).join("");e.results[0].isFinal&&(console.log("User:",t),await this.getAIResponse(t))},this.recognition.onerror=async e=>{console.error("Error:",e.error),await this.getAIResponse("[silence]")},this.recognition.onstart=()=>{this.isListening=!0,this.updateStartButton()},this.recognition.onend=()=>{this.isListening=!1,this.updateStartButton()}}async checkModeration(e){try{const t=await fetch("https://api.openai.com/v1/moderations",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`},body:JSON.stringify({input:e})}),n=await t.json();return{flagged:n.results[0].flagged,categories:n.results[0].categories,scores:n.results[0].category_scores}}catch(e){return console.error("モデレーションAPIエラー:",e),{flagged:!1}}}async getAIResponse(e){if(this.apiKey)try{const t=await this.checkModeration(e);if(t.flagged){console.warn("不適切なコンテンツが検出されました:",t.categories);const n="Oops! It seems like something in your input doesn't fit our rules. Could you try saying it differently?";return void this.updateConversationHistoryList(e,n,{prompt_tokens:0,cached_tokens:0,completion_tokens:0})}const n=this.chatHistory.slice(2*-CONFIG.CHAT.MAX_HISTORY),s=await fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`},body:JSON.stringify({model:"gpt-4o-mini",messages:[this.getSystemPrompt(),...n,{role:"user",content:e}],max_tokens:250,temperature:.7})}),i=await s.json(),o=i.choices[0].message.content,a={prompt_tokens:i.usage.prompt_tokens,cached_tokens:i.usage.prompt_tokens_details.cached_tokens,completion_tokens:i.usage.completion_tokens};this.chatHistory.push({role:"user",content:e},{role:"assistant",content:o}),this.updateConversationHistoryList(e,o,a),this.speak(o)}catch(e){console.error("APIエラー:",e)}else console.error("OpenAI APIキーを入力してください。")}updateConversationHistoryList(e,t,n){const s=document.createElement("li");s.className="p-4 flex items-center justify-between",s.innerHTML=`User: ${escapeHTML(e)}`;const i=document.createElement("button");i.innerHTML='',i.className="ml-4 p-2 hover:bg-gray-200 text-gray-700 rounded-full transition duration-200",i.title="音声を再生",i.addEventListener("click",(()=>this.speak(e))),s.appendChild(i),this.conversationHistoryList.appendChild(s);const o=document.createElement("li");o.className="p-4 flex items-center justify-between bg-blue-50";let a=t,r="";const c=t.match(/\[JP:\s*(.+?)\]/);c&&(a=t.replace(/\s*\[JP:\s*.+?\]/,""),r=c[1]),console.log("Agent(En):",a),console.log("Agent(JP):",r),console.log("Tokens:",n);const l=n.prompt_tokens-n.cached_tokens,h=n.cached_tokens,d=n.completion_tokens,p=this.calculateCost(l,this.PRICE_PER_TOKEN.INPUT),u=this.calculateCost(h,this.PRICE_PER_TOKEN.CACHED),g=this.calculateCost(d,this.PRICE_PER_TOKEN.OUTPUT);o.innerHTML=`\n