您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
enjoy Hands-Free Communication with ChatGPT
- // ==UserScript==
- // @name TalkGPT
- // @namespace http://tampermonkey.net/
- // @version 0.2
- // @description enjoy Hands-Free Communication with ChatGPT
- // @author temberature@mail.com
- // @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);
- }
- })();