Mercurial Hosting > lang
view src/chat.js @ 31:1e7d855afde3
voices
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Sun, 03 Aug 2025 17:05:38 -0600 |
parents | 505185272dd7 |
children | d34d709a7a8e |
line wrap: on
line source
'use strict'; let chat; function setChat(newChat) { let audioChanged = chat && chat.voice != newChat.voice; chat = newChat; document.querySelector('[content] [name]').textContent = chat.name; if(audioChanged) { let s = `voice=${chat.voice}&`; let audios = document.querySelectorAll('audio[src]'); for( let audio of audios ) { audio.src = audio.src.replace(/voice=[^&]+&/,s); } } } function editChat(name) { let dialog = document.querySelector('dialog[edit]'); dialog.querySelector('input[name=name]').value = chat.name; dialog.querySelector('select[name=voice]').value = chat.voice; dialog.showModal(); } function saveChat(form) { closeModal(form); ajaxForm('save_chat.js',form); } function deleteChat() { let dialog = document.querySelector('dialog[delete]'); dialog.showModal(); } function doDeleteChat(el) { closeModal(el); ajax(`delete_chat.js?chat=${chat.id}`); } function systemPrompt() { let dialog = document.querySelector('dialog[system_prompt]'); dialog.showModal(); } function showWaitingAiIcon() { document.querySelector('[waiting-ai-icon]').style.display = 'block'; } function hideWaitingAiIcon() { document.querySelector('[waiting-ai-icon]').style.display = 'none'; } function playLastMessage() { let audios = document.querySelectorAll('audio'); if( audios.length >= 1 ) { let audio = audios[audios.length-1]; audio.play(); } } function handleChatMarkdown() { handleMarkdown(chat.language_region,chat.voice); } function scrollToEnd() { window.scrollTo(0, document.body.scrollHeight); } function updateAi(html) { hideWaitingAiIcon(); document.querySelector('div[messages]').insertAdjacentHTML('beforeend',html); handleChatMarkdown(); document.querySelector('textarea').focus(); scrollToEnd(); playLastMessage(); } const isMobile = 'ontouchstart' in window || navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0; function textareaKey(event) { if( event.keyCode===13 && !event.shiftKey && !event.ctrlKey && !isMobile ) { event.preventDefault(); askAi(); } } let audio; function fixTextarea(textarea) { textarea.style.height = 'initial'; textarea.style.height = (textarea.scrollHeight+2) + 'px'; textarea.parentNode.scrollIntoViewIfNeeded(false); if( !audio ) audio = document.querySelector('div[buttons] audio'); audio.src = `/tts.mp3?lang=${chat.language_region}&voice=${chat.voice}&text=${encodeURIComponent(textarea.value)}`; } function askAi() { let input = document.querySelector('textarea'); let url = `ai_ask.js?chat=${chat.id}&input=${encodeURIComponent(input.value)}`; ajax(url); input.value = ''; fixTextarea(input); showWaitingAiIcon(); } function setText(text) { let textarea = document.querySelector('textarea'); textarea.value = text; fixTextarea(textarea); } let recorder = null; let chunks; function startRecording() { chunks = []; function record(stream) { recorder = new MediaRecorder( stream, { mimeType: 'audio/webm;codecs=opus' } ); recorder.ondataavailable = function(event) { chunks.push(event.data); }; recorder.onstop = function(event) { recorder = null; let blob = new Blob(chunks, { type: 'audio/webm' }); let formData = new FormData(); formData.append('audio', blob, 'recording.webm'); ajax('stt.js',formData); document.querySelector('button[record]').textContent = 'Record'; }; recorder.start(); } navigator.mediaDevices.getUserMedia({ audio: { channelCount: 1 } }).then(record); document.querySelector('button[record]').textContent = 'Stop Recording'; } function toggleRecording() { if( recorder === null ) { startRecording(); } else { recorder.stop(); } }