/**
* @name chat.js
* @version 0.1.0
* @url https://github.com/lencx/ChatGPT/tree/main/scripts/chat.js
*/
function chatInit() {
const ICONS = {
copy: ``,
cpok: ``,
voice: ``,
speaking: ``,
};
let currentUtterance = null;
let currentIndex = -1;
let chatConf = {};
async function init() {
chatConf = (await invoke('get_app_conf')) || {};
new MutationObserver(observeMutations).observe(document.body, {
childList: true,
subtree: true,
});
document.addEventListener('visibilitychange', focusOnInput);
}
function observeMutations(mutationsList) {
for (const mutation of mutationsList) {
if (mutation.target.closest('form')) {
addChatButtons();
}
}
}
function focusOnInput() {
const textArea = document.getElementsByTagName('textarea')[0];
if (textArea) {
textArea.focus();
}
}
function addChatButtons() {
const list = Array.from(document.querySelectorAll('main >div>div>div>div>div'));
list.forEach((item, idx) => {
if (shouldSkip(item)) {
return;
}
const saybtn = item.querySelector('button.rounded-md').cloneNode(true);
saybtn.classList.add('chat-item-voice');
saybtn.title = 'Say';
saybtn.innerHTML = ICONS.voice;
item.querySelector('.self-end').appendChild(saybtn);
saybtn.onclick = () => handleClick(item, idx, saybtn);
});
}
function shouldSkip(item) {
return (
item.querySelector('.chat-item-voice') ||
!item.querySelector('button.rounded-md') ||
!item.querySelector('.self-end')
);
}
function handleClick(item, idx, saybtn) {
const synth = window.speechSynthesis;
const list = Array.from(document.querySelectorAll('main >div>div>div>div>div'));
if (currentUtterance && currentIndex !== -1) {
synth.cancel();
if (idx === currentIndex) {
saybtn.innerHTML = ICONS.voice;
currentUtterance = null;
currentIndex = -1;
return;
} else if (list[currentIndex].querySelector('.chat-item-voice')) {
list[currentIndex].querySelector('.chat-item-voice').innerHTML = ICONS.voice;
list[idx].querySelector('.chat-item-voice').innerHTML = ICONS.speaking;
}
}
const txt = item?.innerText?.trim() || '';
if (!txt) return;
const utterance = new SpeechSynthesisUtterance(txt);
const voices = speechSynthesis.getVoices();
let voice = voices.find((voice) => voice.voiceURI === chatConf.speech_lang);
if (!voice) {
voice = voices.find((voice) => voice.lang === 'en-US');
}
utterance.voice = voice;
currentIndex = idx;
utterance.lang = voice.lang;
synth.speak(utterance);
saybtn.innerHTML = ICONS.speaking;
currentUtterance = utterance;
currentIndex = idx;
utterance.onend = () => {
saybtn.innerHTML = ICONS.voice;
currentUtterance = null;
currentIndex = -1;
};
}
}
if (document.readyState === 'complete' || document.readyState === 'interactive') {
chatInit();
} else {
document.addEventListener('DOMContentLoaded', chatInit);
}