1"use strict"; 2jQuery(function($) { 3 4 let mediaRecorder; 5 let silenceThreshold = 1; // Adjust this value based on your environment 6 let silenceCheckInterval; 7 let recordingStartTimestamp; 8 let mediaStream; 9 const minRecordingDuration = 4000; 10 const maxRecordingDuration = 30000; 11 let isRecording = false; 12 13 const startRecordingButton = $("#aikit-voice-button"); 14 // const audioPlayer = document.getElementById('audioPlayer'); 15 16 startRecordingButton.click(function (event) { 17 event.preventDefault(); 18 19 if (mediaStream == null) { 20 navigator.mediaDevices.getUserMedia({audio: true}) 21 .then((stream) => { 22 mediaStream = stream; 23 handleRecording(); 24 }) 25 .catch((error) => { 26 // get data-validation-no-mic attribute on .aikit-chat-widget and show the error 27 let message = $(".aikit-chat-widget").data('validation-no-mic'); 28 alert(message); 29 }); 30 } else { 31 stopRecording(); 32 } 33 }); 34 35 const handleRecording = () => { 36 37 isRecording = true; 38 39 const audioContext = new AudioContext(); 40 const mediaStreamSource = audioContext.createMediaStreamSource(mediaStream); 41 const analyser = audioContext.createAnalyser(); 42 mediaStreamSource.connect(analyser); 43 44 // mediaRecorder = new MediaRecorder(mediaStream); 45 mediaRecorder = new RecordRTC(mediaStream, { 46 type: 'audio', 47 mimeType: 'audio/webm', 48 numberOfAudioChannels: 1, 49 recorderType: RecordRTC.StereoAudioRecorder, 50 checkForInactiveTracks: true, 51 desiredSampRate: 16000, 52 }); 53 54 mediaRecorder.startRecording(); 55 56 recordingStartTimestamp = Date.now(); 57 58 // Delay the start of silence checking 59 setTimeout(() => { 60 silenceCheckInterval = setInterval(checkSilence, 180); // Adjust the interval as needed 61 }, minRecordingDuration); 62 63 startRecordingButton.attr('data-recording', '1'); 64 65 const checkSilence = () => { 66 const dataArray = new Uint8Array(analyser.frequencyBinCount); 67 analyser.getByteFrequencyData(dataArray); 68 69 const average = dataArray.reduce((acc, val) => acc + val, 0) / dataArray.length; 70 71 if ( 72 (average <= silenceThreshold && (Date.now() - recordingStartTimestamp) > minRecordingDuration) || 73 ((Date.now() - recordingStartTimestamp) > maxRecordingDuration) 74 ) { 75 stopRecording(); 76 } 77 78 }; 79 }; 80 81 const stopRecording = () => { 82 if (!isRecording) { 83 return; 84 } 85 86 clearInterval(silenceCheckInterval); 87 mediaRecorder.stopRecording(() => { 88 isRecording = false; 89 let audioBlob = mediaRecorder.getBlob(); 90 91 sendAudioToServer(audioBlob); 92 mediaStream.getTracks().forEach(track => track.stop()); 93 94 startRecordingButton.removeAttr('data-recording'); 95 96 mediaStream = null; 97 }); 98 } 99 100 const sendAudioToServer = (audioBlob) => { 101 102 $(".aikit-mic-icon").hide(); 103 $(".aikit-voice-button .aikit-loading").attr('data-visible', '1'); 104 105 let formData = new FormData(); 106 107 let file = new File([audioBlob], "audio.webm", { type: 'audio/webm' }); 108 109 formData.append('audio', file); 110 111 $.ajax({ 112 url: aikitChatbot.siteUrl + '/?rest_route=/aikit/chatbot/v1/speech-to-text', 113 type: 'POST', 114 data: formData, 115 processData: false, 116 contentType: false, 117 success: function(response) { 118 $("#aikit-new-message-textarea").val($("#aikit-new-message-textarea").val() + response.message); 119 $(".aikit-mic-icon").show(); 120 $(".aikit-voice-button .aikit-loading").attr('data-visible', '0'); 121 }, 122 error: function(error) { 123 alert(error); 124 125 $(".aikit-mic-icon").show(); 126 $(".aikit-voice-button .aikit-loading").attr('data-visible', '0'); 127 } 128 }); 129 }; 130 131 132 aikitChatbot.previousMessages = []; 133 let isLivePreview = false;
134 135 // deactivate all inputs inside .aikit-deactivated-form class 136 $(".aikit-deactivated-form *").prop('disabled', true); 137 138 $(".aikit-chatbot-send-button").click(function (event) { 139 event.preventDefault(); 140 141 sendChatbotMessage(); 142 }); 143 144 // on enter key press, send the message 145 $("#aikit-new-message-textarea").keypress(function (event) { 146 // if shift key is pressed, do nothing 147 if (event.shiftKey) { 148 return; 149 } 150 151 if (event.keyCode === 13) { 152 event.preventDefault(); 153 sendChatbotMessage(); 154 } 155 }); 156 157 $(".aikit-open-chat-button").click(function(){ 158 $(".aikit-chat-container").fadeIn(100, function () { 159 $(".aikit-open-chat-button").fadeOut(100); 160 $(".aikit-chatbot-send-button").fadeIn(100); 161 $(".aikit-chat-widget").addClass('aikit-open'); 162 }); 163 164 }); 165 $(".aikit-exit-chat").click(function(){ 166 $(".aikit-chat-container").fadeOut(100, function () { 167 $(".aikit-open-chat-button").fadeIn(100); 168 $(".aikit-chatbot-send-button").fadeOut(100); 169 $(".aikit-chat-widget").removeClass('aikit-open'); 170 }); 171 }); 172 173 if ($('.aikit-chat-widget').data('default-view') === 'collapsed') { 174 $(".aikit-chat-container").hide(); 175 } else { 176 $(".aikit-open-chat-button").hide(); 177 $(".aikit-chat-widget").addClass('aikit-open'); 178 } 179 180 const sendChatbotMessage = () => { 181 let message = $("#aikit-new-message-textarea").val(); 182 183 if (message === '') { 184 return; 185 } 186 187 if ($(".aikit-chatbot-send-button").prop('disabled')) { 188 return; 189 } 190 191 // deactivate the send button 192 $(".aikit-chatbot-send-button").prop('disabled', true); 193 $(".aikit-chatbot-send-button").css('opacity', '0.5'); 194 195 addMessageToChat(message, "reply"); 196 197 let loading = $('<div class="aikit-message aikit-message-bot">\n' + 198 ' <span class="aikit-message-content">\n' + 199 ' <span class="aikit-typing">\n' + 200 ' <span class="aikit-dot"></span>\n' + 201 ' <span class="aikit-dot"></span>\n' + 202 ' <span class="aikit-dot"></span>\n' + 203 ' </span>\n' + 204 ' </span>\n' + 205 ' </div>'); 206 207 $("#aikit-messages").append(loading); 208 loading.hide().fadeIn(300); 209 210 // scroll to bottom of the chat 211 $("#aikit-conversation").animate({ scrollTop: $("#aikit-conversation").prop("scrollHeight")}, 50); 212 213 if (isLivePreview) { 214 // add a test message 215 // wait 1 second 216 setTimeout(function () { 217 loading.remove(); 218 addMessageToChat("This is a test message from the live preview."); 219 // reactivate the send button 220 $(".aikit-chatbot-send-button").prop('disabled', false); 221 222 $(".aikit-chatbot-send-button").css('opacity', '1'); 223 224 }, 2000); 225 226 $("#aikit-new-message-textarea").val(''); 227 return; 228 } 229 230 $.ajax({ 231 type: "POST", 232 url: aikitChatbot.siteUrl + '/?rest_route=/aikit/chatbot/v1/chat', 233 data: JSON.stringify({ 234 message: message, 235 // json previous messages 236 previous_messages: JSON.stringify(aikitChatbot.previousMessages), 237 page_content: aikitChatbot.pageContent, 238 chat_id: $(".aikit-chat-widget").data('chat-id'), 239 }), 240 dataType: "json", 241 encode: true, 242 headers: { 243 'Content-Type': 'application/json', 244 'X-WP-Nonce': aikitChatbot.nonce, 245 }, 246 }).done(function (data) { 247 aikitChatbot.previousMessages.push({ 248 message: message, 249 author: 'user', 250 }); 251 252 aikitChatbot.previousMessages.push({ 253 message: data.message, 254 author: 'assistant', 255 }); 256 257 data.message = data.message.replace(/\n/g, '<br>'); 258 259 data.message = data.message.replace(/(https?:\/\/[^\s]+)/g, '<a href="$1" target="_blank">$1</a>'); 260 261 loading.remove(); 262 addMessageToChat(data.message); 263 264 // reactivate the send button 265 $(".aikit-chatbot-send-button").prop('disabled', false); 266 $(".aikit-chatbot-send-button").css('opacity', '1'); 267 268 }).fail(function (data) { 269 if (data.responseJSON) { 270 data = data.responseJSON; 271 } 272 273 if (data.show_in_alert === true) { 274 alert(data.message); 275 } else { 276 console.log(data); 277 } 278 279 addMessageToChat(data.chat_error, "error"); 280 281 // reactivate the send button 282 $(".aikit-chatbot-send-button").prop('disabled', false); 283 $(".aikit-chatbot-send-button").css('opacity', '1'); 284 loading.remove(); 285 }); 286 287 // clear the input 288 $("#aikit-new-message-textarea").val(''); 289 } 290 291 const addMessageToChat = (message, type = "") => { 292 let className = "aikit-message-bot"; 293 if (type === "reply") { 294 className = "aikit-message-user"; 295 } else if (type === "error") { 296 className = "aikit-message-error"; 297 } 298 299 let bubble = $('<div class="aikit-message ' + className + '"><span className="aikit-message-content">' + message + '</span></div>'); 300 $("#aikit-messages").append(bubble); 301 bubble.hide().fadeIn(100); 302 $("#aikit-conversation").animate({ scrollTop: $("#aikit-conversation").prop("scrollHeight")}, 50); 303 } 304 305 const generateBotStyles = () => { 306 let secondaryColor = hashColorToRgb(aikitChatbot.secondaryColor, 1); 307 let mainColor = hashColorToRgb(aikitChatbot.mainColor, 1); 308 let shadowColor = hashColorToRgb(aikitChatbot.mainColor, .6); 309 let loadingColor = hashColorToRgb(aikitChatbot.mainColor, .7); 310 let dot1 = hashColorToRgb(aikitChatbot.mainColor, .7); 311 let dot2 = hashColorToRgb(aikitChatbot.mainColor, .4); 312 let dot3 = hashColorToRgb(aikitChatbot.mainColor, .2); 313 314 let titleColor = hashColorToRgb(aikitChatbot.titleColor, 0.9); 315 316 // remove the style if it exists 317 $("#aikit-chatbot-style").remove(); 318 319 // output bot style to the head 320 let style = '<style id="aikit-chatbot-style">'; 321 322 style += '.aikit-message-bot {'; 323 style += ' background-color: ' + aikitChatbot.aiMessageBubbleColor + ';'; 324 style += ' color: ' + aikitChatbot.aiMessageTextColor + ';'; 325 style += '}'; 326 327 style += '.aikit-chat-bubble a {'; 328 style += ' text-decoration: underline;'; 329 style += '}'; 330 331 style += '.aikit-message-user {'; 332 style += ' background: linear-gradient(135deg, ' + aikitChatbot.userMessageBubbleColor + ',' + secondaryColor + ');'; 333 style += ' color: ' + aikitChatbot.userMessageTextColor + ';'; 334 style += '}'; 335 336 style += '.aikit-chat-header {'; 337 style += ' background: linear-gradient(135deg, ' + mainColor + ' 0%,' + secondaryColor + ' 100%);'; 338 style += ' color: ' + aikitChatbot.titleColor + ';'; 339 style += '}'; 340 341 style += '.aikit-button-body {'; 342 style += ' background: linear-gradient(135deg, ' + mainColor + ',' + secondaryColor + ');'; 343 style += ' box-shadow: ' + shadowColor + ' 0px 4px 24px;;'; 344 style += '}'; 345 346 style += '.aikit-button i svg, .aikit-down-arrow {'; 347 style += ' color: ' + titleColor + ';'; 348 style += '}'; 349 350 351 style += '.aikit-typing .aikit-dot {'; 352 style += ' background-color: ' + loadingColor + ';'; 353 style += '}'; 354 355 style += ' @keyframes mercuryTypingAnimation {'; 356 style += ' 0% {'; 357 style += ' transform: translateY(0px);'; 358 style += ' background-color: ' + dot1 + ';'; 359 style += ' }'; 360 style += ' 28% {'; 361 style += ' transform: translateY(-7px);'; 362 style += ' background-color: ' + dot2 + ';'; 363 style += ' }'; 364 style += ' 44% {';
365 style += ' transform: translateY(0px);'; 366 style += ' background-color: ' + dot3 + ';'; 367 style += ' }'; 368 style += '}'; 369 370 style += '</style>'; 371 372 $('head').append(style); 373 } 374 375 const activateLivePreview = () => { 376 isLivePreview = true; 377 // activate live editing 378 $("input").on('input', function() { 379 let setting = $(this).attr('data-setting'); 380 if (aikitChatbot[setting] !== undefined) { 381 aikitChatbot[setting] = $(this).val(); 382 } 383 384 updateLivePreview(); 385 }); 386 387 updateLivePreview(); 388 } 389 390 const hashColorToRgb = (color, opacity) => { 391 // turn # color to rgb and add opacity 392 let colorRgb = color.replace('#', ''); 393 colorRgb = colorRgb.match(/.{1,2}/g); 394 colorRgb = 'rgba(' + parseInt(colorRgb[0], 16) + ',' + parseInt(colorRgb[1], 16) + ',' + parseInt(colorRgb[2], 16) + ', ' + opacity + ')'; 395 396 return colorRgb; 397 } 398 399 const updateLivePreview = () => { 400 401 generateBotStyles(); 402 403 // update get value from #aikit-chatbot-appearance-title and set it to the title 404 let title = $("#aikit-chatbot-appearance-title").val(); 405 $(".aikit-chat-welcome span").html(title); 406 407 // same for first message 408 let firstMessage = $("#aikit-chatbot-appearance-start-message").val(); 409 $(".aikit-message:first").html(firstMessage); 410 411 let inputTextPlaceholder = $("#aikit-chatbot-appearance-input-placeholder").val(); 412 $("#aikit-new-message-textarea").attr('placeholder', inputTextPlaceholder); 413 } 414 415 // on load, generate the bot styles 416 generateBotStyles(); 417 418 $('.aikit-chat-widget').removeClass('d-none'); 419 420 if (window.location.href.indexOf('page=aikit_chatbot') > -1) { 421 activateLivePreview(); 422 } 423});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.