From fa1fdc1b37a1863c53d73a834445030fcedd5a89 Mon Sep 17 00:00:00 2001 From: Oikko <100654554+MRIOikko@users.noreply.github.com> Date: Sun, 27 Oct 2024 16:10:57 -0400 Subject: [PATCH] Audio speech and hearing version --- LLM.css | 102 ++++++++++++++++++++++++++++--- LLM.html | 4 ++ LLM.js | 182 +++++++++++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 254 insertions(+), 34 deletions(-) diff --git a/LLM.css b/LLM.css index c3c8eab..80b7e62 100644 --- a/LLM.css +++ b/LLM.css @@ -1,16 +1,13 @@ @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap'); - *{ font-family: 'Arial', sans-serif; } - body{ margin: 0; padding: 0; background-image: linear-gradient(to right, rgb(51, 84, 177), rgb(17, 204, 101)); /*rgb(230, 20, 136)*/ } - .header{ display: flex; font: sans-serif; @@ -20,13 +17,11 @@ body{ border-bottom: 3px solid #ebe4e4; height: 45px; } - .header h1{ color: white; font-size: 22px; font-weight: 800; } - .container{ max-width: 920px; height: 100vh; @@ -36,15 +31,17 @@ body{ margin: 0 auto; } + + + + .info{ - color: rgb(255, 255, 255); display: flex; align-items: center; justify-content: center; flex: 20; } - .info a{ color: #fff; text-decoration: none; @@ -52,11 +49,14 @@ body{ font-weight: bold; transition: all 0.3s ease; } - .info a:hover{ color: #1f263f; } + + + + .input-container{ background-image: linear-gradient( #434764, rgb(57, 59, 95)); border-radius: 15px; @@ -68,6 +68,10 @@ body{ bottom: 0; } + + + + #user-input{ background-color: #182036; color: #ffffff; @@ -85,6 +89,11 @@ body{ font-weight: 400; } + + + + + #send-button{ display: flex; align-items: center; @@ -95,7 +104,7 @@ body{ background-color: #4c77af; color: #fff; cursor: pointer; - margin-left: 15px; + margin-left: 5px; transition: all 0.3s ease; } @@ -103,6 +112,66 @@ body{ background-color: #293b6e; } + + +@keyframes pulse{ + 0%{ + transform: scale(1); + } + 50% { + transform: scale(1.1); + } + 100% { + transform: scale(1); + } + +} + + +.voice-button{ + color: rgb(255, 255, 255); + background-color: #4c77af; + cursor: pointer; + border-radius: 50%; + padding:10px 11px; + margin-left: 5px; + border: none; +} +.voice-button:hover{ + color: white; + background-color:#293b6e ; +} +.voice-button.listening{ + background-color: #46e66e; + animation: pulse 1.5s infinite; +} + + + + + + +.mute-button{ + color: white; + background-color: #4c77af; + cursor: pointer; + border-radius: 50%; + padding:10px 11px; + margin-left: 5px; + border: none; +} +.mute-button:hover{ + color: white; + background-color: #293b6e; +} +.mute-button.muted{ + background-color: #182036; +} + + + + + .chat-container{ flex: 1; } @@ -151,4 +220,19 @@ body{ #chat-log #bot-icon i{ background-color: #00b7ff; padding: 10px 8px 11px; +} + + + +::-webkit-scrollbar { + background: rgb(17, 204, 101); + width: 10px; +} +::-webkit-scrollbar-thumb{ + background: #4c77af; + border-radius: 10px; + +} +::-webkit-scrollbar-thumb.hover{ + background: #293b6e; } \ No newline at end of file diff --git a/LLM.html b/LLM.html index 6df5301..0916435 100644 --- a/LLM.html +++ b/LLM.html @@ -31,9 +31,13 @@

Hi Oikko! Send me a message to get started!

+ + + + diff --git a/LLM.js b/LLM.js index d41f151..bcb818f 100644 --- a/LLM.js +++ b/LLM.js @@ -4,6 +4,34 @@ const chatLog = document.getElementById('chat-log'), buttonIcon = document.getElementById('button-icon'), info = document.querySelector('.info'); + +const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition; +const recognition = new SpeechRecognition(); +recognition.continuous = false; +recognition.lang = 'en-US'; + + +const synth = window.speechSynthesis; +let isMuted = false; + + +const voiceButton = document.createElement('button'); +voiceButton.innerHTML = ''; +voiceButton.className = 'voice-button'; +sendButton.parentNode.insertBefore(voiceButton, sendButton); + + +const muteButton = document.createElement('button'); +muteButton.innerHTML = ''; +muteButton.className = 'mute-button'; +sendButton.parentNode.insertBefore(muteButton, sendButton); + + +let isListening = false; + + +voiceButton.addEventListener('click', toggleVoiceInput); +muteButton.addEventListener('click', toggleMute); sendButton.addEventListener('click', sendMessage); userInput.addEventListener('keydown', (event) => { if (event.key === 'Enter') { @@ -11,52 +39,157 @@ userInput.addEventListener('keydown', (event) => { } }); -function sendMessage() { + +function toggleMute() { + isMuted = !isMuted; + if (isMuted) { + muteButton.innerHTML = ''; + muteButton.setAttribute('title', 'Unmute AI voice'); + synth.cancel(); + } else { + muteButton.innerHTML = ''; + muteButton.setAttribute('title', 'Mute AI voice'); + } + muteButton.classList.toggle('muted'); +} + + +function toggleVoiceInput() { + if (!isListening) { + recognition.start(); + voiceButton.innerHTML = ''; + voiceButton.classList.add('listening'); + isListening = true; + } else { + recognition.stop(); + voiceButton.innerHTML = ''; + voiceButton.classList.remove('listening'); + isListening = false; + } +} + + +recognition.onresult = (event) => { + const transcript = event.results[0][0].transcript; + userInput.value = transcript; + sendMessage(); +}; + + +recognition.onend = () => { + voiceButton.innerHTML = ''; + voiceButton.classList.remove('listening'); + isListening = false; +}; + + +function splitIntoSentences(text) { + return text.match(/[^.!?]+[.!?]+/g) || [text]; +} + + +function speakMessage(message) { + if (isMuted) return; + + + synth.cancel(); + + + const sentences = splitIntoSentences(message); + let currentSentence = 0; + + + function speakNextSentence() { + if (currentSentence < sentences.length && !isMuted) { + const utterance = new SpeechSynthesisUtterance(sentences[currentSentence]); + utterance.lang = 'en-GB'; + utterance.rate = 1.01; + utterance.pitch = 1.4; + + + + utterance.onend = () => { + currentSentence++; + speakNextSentence(); + }; + + + + utterance.onerror = (event) => { + console.error('Speech error:', event); + currentSentence = sentences.length; + }; + + + synth.speak(utterance); + } + } + + + speakNextSentence(); +} + + +async function sendMessage() { const message = userInput.value.trim(); if (message === '') { return; } + + appendMessage('user', message); userInput.value = ''; - const options = { - method: 'POST', - headers: { - 'x-rapidapi-key': '96fe58a1edmsh64abdfc6c6d56dap19fd5djsnd234de8c1a26', - 'x-rapidapi-host': 'chat-gpt26.p.rapidapi.com', - 'Content-Type': 'application/json', - }, - body: `{"messages":[{"role":"user","content":"${message}"}]}` - }; - fetch('https://chat-gpt26.p.rapidapi.com/', options).then((response) => response.json()).then((response) => { - appendMessage('bot', response.choices[0].message.content); + try { + const options = { + method: 'POST', + headers: { + 'x-rapidapi-key': '96fe58a1edmsh64abdfc6c6d56dap19fd5djsnd234de8c1a26', + 'x-rapidapi-host': 'cheapest-gpt-4-turbo-gpt-4-vision-chatgpt-openai-ai-api.p.rapidapi.com', + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + messages: [{ role: 'user', content: message }], + model: 'gpt-4o' + }) + }; + + + const response = await fetch('https://cheapest-gpt-4-turbo-gpt-4-vision-chatgpt-openai-ai-api.p.rapidapi.com/v1/chat/completions', options); + const data = await response.json(); + + const botResponse = data.choices[0].message.content; + appendMessage('bot', botResponse); + + speakMessage(botResponse); + buttonIcon.classList.add('fa-solid', 'fa-bolt'); buttonIcon.classList.remove('fas', 'fa-spinner', 'fa-pulse'); - }).catch((err) => { - if (err.name === 'TypeError') { - appendMessage('bot', 'ERROR : Check Your Skibidi API Key! '); - buttonIcon.classList.add('fa-solid', 'fa-bolt'); - buttonIcon.classList.remove('fas', 'fa-spinner', 'fa-pulse'); - } - }); + } catch (err) { + console.error('Error:', err); + appendMessage('bot', 'Sorry, there was an error processing your request.'); + buttonIcon.classList.add('fa-solid', 'fa-bolt'); + buttonIcon.classList.remove('fas', 'fa-spinner', 'fa-pulse'); + } } + function appendMessage(sender, message) { info.style.display = "none"; buttonIcon.classList.remove('fa-solid', 'fa-bolt'); buttonIcon.classList.add('fas', 'fa-spinner', 'fa-pulse'); - + const messageElement = document.createElement('div'); const iconElement = document.createElement('div'); const chatElement = document.createElement('div'); const icon = document.createElement('i'); - + chatElement.classList.add("chat-box"); iconElement.classList.add("icon"); messageElement.classList.add(sender); messageElement.innerText = message; - + if (sender === 'user') { icon.classList.add('fa-solid', 'fa-ghost'); iconElement.setAttribute('id', 'user-icon'); @@ -64,11 +197,10 @@ function appendMessage(sender, message) { icon.classList.add('fa-solid', 'fa-circle-notch'); iconElement.setAttribute('id', 'bot-icon'); } - + iconElement.appendChild(icon); chatElement.appendChild(iconElement); chatElement.appendChild(messageElement); chatLog.appendChild(chatElement); - chatLog.scrollTo = chatLog.scrollHeight; - + chatLog.scrollTop = chatLog.scrollHeight; } \ No newline at end of file