TalkGPT

enjoy Hands-Free Communication with ChatGPT

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey, Greasemonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да инсталирате разширение, като например Tampermonkey .

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Userscripts.

За да инсталирате скрипта, трябва да инсталирате разширение като Tampermonkey.

За да инсталирате този скрипт, трябва да имате инсталиран скриптов мениджър.

(Вече имам скриптов мениджър, искам да го инсталирам!)

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

(Вече имам инсталиран мениджър на стиловете, искам да го инсталирам!)

// ==UserScript==
// @name        TalkGPT
// @namespace   http://tampermonkey.net/
// @version     0.2
// @description enjoy Hands-Free Communication with ChatGPT
// @author      [email protected]
// @include     https://chat.openai.com/chat*
// @grant       none
// @license GNU GPLv3
// ==/UserScript==

(function () {
  addTalkBtn();
  let VoiceList;

  if (typeof speechSynthesis !== 'undefined' && speechSynthesis.onvoiceschanged !== undefined) {
    speechSynthesis.onvoiceschanged = generateVoiceList;
  }
  let voice = "Microsoft Aria Online (Natural) - English (United States)", lang = "en-US";
  const observer = new MutationObserver(mutations => {
    mutations.forEach(mutation => {
      if (mutation.type === 'childList') {
        mutation.addedNodes.forEach(addedNode => {
          if (addedNode.nodeType === Node.ELEMENT_NODE && ((addedNode.classList.contains('overflow-hidden') && addedNode.classList.contains('w-full') && addedNode.classList.contains('h-full') && addedNode.classList.contains('relative')) || addedNode.classList.contains('px-2') &&
          addedNode.classList.contains('py-10') &&
          addedNode.classList.contains('relative') &&
          addedNode.classList.contains('w-full') &&
          addedNode.classList.contains('flex') &&
          addedNode.classList.contains('flex-col') &&
          addedNode.classList.contains('h-full') &&
          addedNode.classList.contains('list')) ) {


            addTalkBtn();
            let stretchElement = document.querySelector('.stretch');
            let justifyCenterDiv = stretchElement.querySelector('.justify-center');
            justifyCenterDiv.appendChild(VoiceList);

          }

          if (addedNode.nodeType === Node.ELEMENT_NODE && addedNode.classList.contains('btn') && addedNode.classList.contains('flex') && addedNode.classList.contains('justify-center') && addedNode.classList.contains('gap-2') && addedNode.classList.contains('btn-neutral') && addedNode.classList.contains('border-0') && addedNode.classList.contains('md:border') && addedNode.textContent.includes('Regenerate response')) {
            const proseElements = document.querySelectorAll('.prose');
            const lastProseElement = proseElements[proseElements.length - 1];

            window.utterances = [];
            const msg = new SpeechSynthesisUtterance(lastProseElement.textContent);
            utterances.push(msg);
            msg.voice = window.speechSynthesis.getVoices().find(v => {
              return v.name === voice;
            });
            msg.onend = () => {
              recognize();
            };
            window.speechSynthesis.speak(msg);
          }
        });
      }
    });
  });

  observer.observe(document.body, { childList: true, subtree: true });


  function recognize() {
    const recognition = new webkitSpeechRecognition();
    recognition.interimResults = true;
    recognition.lang = lang; // Set the language to Mandarin Chinese

    recognition.start();

    let transcript = '';

    recognition.onresult = (event) => {
      for (let i = event.resultIndex; i < event.results.length; i++) {
        if (event.results[i].isFinal) {
          transcript += event.results[i][0].transcript;
        }
      }
    };

    recognition.onend = () => {
      if(!transcript){
        return;
      }
      const textarea = document.querySelector('textarea');
      textarea.value = textarea.value + "" + transcript;

      // Find the sibling button and click it
      const button = textarea.nextElementSibling;
      button.click();
    };
  }
  function generateVoiceList() {
    let stretchElement = document.querySelector('.stretch');
    let justifyCenterDiv = stretchElement.querySelector('.justify-center');

    if(justifyCenterDiv.querySelector('select')) {
      return;
    }
    const select = document.createElement('select');

    select.style = "width: 5rem;border: 0;"
    select.onchange = function(event) {
      const values = event.target.value.split(';');
      voice = values[0];
      lang = values[1];
    }
    if (typeof speechSynthesis === 'undefined') {
      return;
    }

    const voices = speechSynthesis.getVoices();

    for (let i = 0; i < voices.length; i++) {
      const option = document.createElement('option');
      option.textContent = `${voices[i].name};${voices[i].lang}`;

      if (voices[i].default) {
        option.textContent += '; — DEFAULT';
      }

      option.setAttribute('data-lang', voices[i].lang);
      option.setAttribute('data-name', voices[i].name);

      select.appendChild(option);
      select.value = `${voice};${lang}`;
    }


    VoiceList = select;
    justifyCenterDiv.appendChild(select);

  }


  function addTalkBtn() {
    let stretchElement = document.querySelector('.stretch');
    let justifyCenterDiv = stretchElement.querySelector('.justify-center');
    const button = document.createElement('button');
    button.classList.add('btn', 'flex', 'gap-2', 'justify-center', 'btn-neutral');
    button.textContent = 'Talk';
    button.addEventListener('click', function(e) {
      e.preventDefault();
      recognize();
    });
    justifyCenterDiv.appendChild(button);
  }

})();