Change ChatGPT Image And Text To Speech Function

ChatGPT

  1. // ==UserScript==
  2. // @name Change ChatGPT Image And Text To Speech Function
  3. // @namespace Change ChatGPT Image And Text To Speach Function
  4. // @version 0.2
  5. // @description ChatGPT
  6. // @author kaes-u-paya for text to speech and mei for the image change
  7. // @match https://chat.openai.com/chat
  8. // @grant none
  9. // @license MIT
  10. // ==/UserScript==
  11.  
  12. //var link = "https://s3.bmp.ovh/imgs/2022/12/18/f2294e4eb27e9161.jpg";
  13. var link = "https://cdn4.iconfinder.com/data/icons/artificial-intelligence-35/64/artificial-intelligence-ai-avatar-robot-512.png";
  14. var circle = false;
  15. var shadow = false;
  16.  
  17. var VoiceSettingsTags = `
  18. <div class="properties">
  19. <label for="voice">Voice:</label>
  20. <select id="voice"></select>
  21. <div></div>
  22.  
  23. <label for="pitch">Pitch:</label>
  24. <input id="pitch" type="range" min="0.1" max="2" step="0.1" value="1">
  25. <output for="pitch">1</output>
  26.  
  27. <label for="rate">Rate:</label>
  28. <input id="rate" type="range" min="0.1" max="2" step="0.1" value="1">
  29. <output for="rate">1</output>
  30.  
  31. <label for="volume">Volume:</label>
  32. <input id="volume" type="range" min="0" max="1" step="0.1" value="1">
  33. <output for="volume">1</output>
  34. </div>`;
  35.  
  36. document.head.appendChild(Object.assign(document.createElement("style"), {textContent: `
  37. .properties {
  38. position:absolute;
  39. z-index:10000;
  40. width: 430px;
  41. top:5px;
  42. right:5px;
  43. display: grid;
  44. grid-template-columns: max-content minmax(0, auto) 40px;
  45. gap: 10px;
  46. padding: 10px;
  47. background-color: #0003;
  48. }
  49.  
  50. #voice {
  51. padding-top:0px;
  52. height: 30px;
  53. font-size: 14px;
  54. background: rgba(0, 0, 0, 0.5);
  55. color: #fff;
  56. text-shadow: 0 1px 0 rgba(0, 0, 0, 0.4);
  57. }
  58. `
  59. }));
  60.  
  61. let VoiceSettings = document.createElement('div');
  62. VoiceSettings.innerHTML = VoiceSettingsTags;
  63. document.body.appendChild(VoiceSettings);
  64.  
  65. //var textinput = "Hi how are you?";
  66.  
  67. document.addEventListener("DOMNodeInserted", function(event) {
  68.  
  69.  
  70. /*
  71. * alert('inserted ' + event.target.childNodes[0].childNodes[0].childNodes[0].childNodes[0].getElementsByTagName('img')[1].alt);// new node -- extract your name from google account avatar logo alt text
  72. */
  73.  
  74. /*
  75. try {
  76. let AiLogo = event.target.childNodes[0].childNodes[0].childNodes[0].getElementsByTagName('svg')[0].getAttribute("class"); // find the event when the AI logo will be inserted - class -> 'h-6 w-6'
  77. } catch (event) {
  78. if (event.name === 'TypeError') { //element doesnt exist yet (undefined) - wait for the element to be created
  79. } else {
  80. throw event; // re-throw the error
  81. }
  82. }
  83. */
  84. let AiLogo = event.target.childNodes[0].childNodes[0].childNodes[0].getElementsByTagName('svg')[0].getAttribute("class"); // find the event when the AI logo will be inserted - class -> 'h-6 w-6'
  85. if (AiLogo === 'h-6 w-6'){ //now swap the logo with the custom logo
  86.  
  87. let elementsSVG = document.querySelectorAll('.flex.flex-col.relative.items-end svg');
  88. elementsSVG.forEach(function(elementSVG) {
  89. var imgElement = document.createElement("img");
  90. imgElement.src = link;
  91. if(circle){imgElement.style.borderRadius = "14px";}
  92. if(shadow){imgElement.style.boxShadow = "0 2px 4px rgba(0,0,0,6)";}
  93.  
  94. elementSVG.parentNode.replaceChild(imgElement, elementSVG);
  95. });
  96.  
  97. let elementsRound = document.querySelectorAll('.relative.p-1.rounded-sm.text-white.flex.items-center.justify-center');
  98. elementsRound.forEach(function(elementRound) {
  99. elementRound.style.padding = '0';
  100. if(circle){elementRound.style.borderRadius = "14px";}
  101. });
  102.  
  103. }
  104.  
  105. /*
  106. try {
  107. let AiAnswer = event.target.childNodes[0].childNodes[1].childNodes[0].getElementsByTagName('div')[0].getAttribute("class"); //find the event when the AI gives an answer
  108. } catch (event) {
  109. if (event.name === 'TypeError') { //element doesnt exist yet (undefined) - wait for the element to be created
  110. } else {
  111. throw event; // re-throw the error
  112. }
  113. }
  114. */
  115.  
  116. let AiAnswer = event.target.childNodes[0].childNodes[1].childNodes[0].getElementsByTagName('div')[0].getAttribute("class"); //find the event when the AI gives an answer
  117. if (AiAnswer === 'min-h-[20px] flex flex-col items-start gap-4 whitespace-pre-wrap'){
  118.  
  119. //alert (event.relatedNode.innerHTML);
  120.  
  121. let collectionA = document.getElementsByClassName('w-full border-b border-black/10 dark:border-gray-900/50 text-gray-800 dark:text-gray-100 group bg-gray-50 dark:bg-[#444654]'); //maybe that tag is different if you don't unse the dark theme!
  122. var cLL = collectionA.length;
  123.  
  124.  
  125. if (cLL > 0){
  126.  
  127. var readcounter = 0;
  128. var countnochange = 0;
  129. var delay = 6000; //Delay for one loop = 6 seconds
  130. var cutstart = 0;
  131. var cutend = 0;
  132. var cut1 = 0;
  133. var cut2 = 0;
  134. var speakstring = '';
  135. var oldlenght = 0;
  136.  
  137.  
  138. var myLoop = setInterval(function() {
  139.  
  140. var currentLL = collectionA[cLL-1].childNodes[0].childNodes[1].childNodes[0].childNodes[0].childNodes[0].innerHTML;
  141. currentLL = currentLL.substr(3,currentLL.length-2);
  142.  
  143. if (currentLL.length > oldlenght){
  144. oldlenght = currentLL.length;
  145. countnochange = 0;
  146. }
  147.  
  148.  
  149. readcounter++;
  150.  
  151.  
  152. var posd = currentLL.lastIndexOf('.')+1;
  153. var posp = currentLL.lastIndexOf(':')+1;
  154. var pose = currentLL.lastIndexOf('!')+1;
  155. var posq = currentLL.lastIndexOf('?')+1;
  156. var posb = currentLL.lastIndexOf(',')+1;
  157. var posX = currentLL.lastIndexOf(' ')+1;
  158.  
  159. console.log ('posd: '+posd+' posp: '+posp+' pose: '+pose+' posq: '+posq+' posb: '+posb+' posX: '+posX);
  160.  
  161. if (posd > cut1) {cut1 = posd;}
  162. if (posp > cut1) {cut1 = posp;}
  163. if (pose > cut1) {cut1 = pose;}
  164. if (posq > cut1) {cut1 = posq;}
  165.  
  166. if (posb > cut2) {cut2 = posb;}
  167. if (posX > cut2) {cut2 = posX;}
  168.  
  169. if (posX-posb<20){cut2 = posb;}else{cut2 = posX;} //prefer cutting at ',' instead of the ' ' if the the ',' is less than 20 chars away.. for fluent speaking
  170. if (cut2>cut1){cutend = cut2;}else{cutend = cut1;} //prefer .:!?
  171.  
  172. console.log ('----------------------------------------------------------');
  173. console.log ('start: '+cutstart);
  174. console.log ('stop: '+cutend);
  175.  
  176. var diff = oldlenght - cutend;
  177. console.log ('lenght: '+oldlenght);
  178. console.log ('diff: '+diff);
  179.  
  180. if (readcounter === 1){
  181. speakstring = currentLL.substr(cutstart, cutend);
  182. speakstring = speakstring.replaceAll(/(<([^>]+)>)/ig,' '); //replace all tags with ' '
  183. }else{
  184. var fixend = cutend - diff;
  185. console.log ('fixing end to: '+fixend);
  186. speakstring = currentLL.substr(cutstart, fixend); //WTF!!!!
  187. speakstring = speakstring.substr(0, (speakstring.length - diff));
  188. speakstring = speakstring.replaceAll(/(<([^>]+)>)/ig,' ');
  189. }
  190.  
  191. console.log ('readcounter:'+readcounter);
  192. console.log ('speakstring:'+speakstring);
  193. console.log ('----------------------------------------------------------');
  194. const synth = window.speechSynthesis;
  195. //const voices = window.speechSynthesis.getVoices();
  196. //console.log ('voices:'+voices.length);
  197. //const lastVoice = voices[2];
  198. //console.log ('voice:'+lastVoice.name);
  199. //const lastVoice = voices[voices.length - 1];
  200. const utterThis2 = new SpeechSynthesisUtterance(speakstring);
  201. //utterThis2.voice = lastVoice;
  202.  
  203. utterThis2.voice = window.speechSynthesis.getVoices().find(voice => voice.voiceURI === voiceInEl.value);
  204. utterThis2.pitch = pitchInEl.value;
  205. utterThis2.rate = rateInEl.value;
  206. utterThis2.volume = volumeInEl.value;
  207.  
  208. synth.speak(utterThis2);
  209. cutstart = cutend; //for next loop cycle
  210.  
  211.  
  212. if (currentLL.length === oldlenght){ // no change in text AI finisched writeing
  213. countnochange++;
  214. console.log ('count answer no change: '+countnochange);
  215. if (countnochange > 7){ //aftere 7 loops stop checking for changed answer
  216. clearInterval(myLoop);
  217. console.log ('count answer no change: '+countnochange);
  218. console.log ('stoped checking for answerchange');
  219. countnochange = 0;
  220. }
  221. }
  222.  
  223. }, delay);
  224.  
  225. }
  226.  
  227. } //end answer
  228.  
  229. });
  230.  
  231.  
  232. //Code from: https://codersblock.com/blog/javascript-text-to-speech-and-its-many-quirks/
  233.  
  234. // grab the UI elements to work with
  235. //const textEl = document.getElementById('text');
  236. const voiceInEl = document.getElementById('voice');
  237. const pitchInEl = document.getElementById('pitch');
  238. const rateInEl = document.getElementById('rate');
  239. const volumeInEl = document.getElementById('volume');
  240. const pitchOutEl = document.querySelector('output[for="pitch"]');
  241. const rateOutEl = document.querySelector('output[for="rate"]');
  242. const volumeOutEl = document.querySelector('output[for="volume"]');
  243. //const speakEl = document.getElementById('speak');
  244.  
  245. // add UI event handlers
  246. pitchInEl.addEventListener('change', updateOutputs);
  247. rateInEl.addEventListener('change', updateOutputs);
  248. volumeInEl.addEventListener('change', updateOutputs);
  249. //speakEl.addEventListener('click', speakText);
  250.  
  251. // update voices immediately and whenever they are loaded
  252. updateVoices();
  253. window.speechSynthesis.onvoiceschanged = updateVoices;
  254.  
  255. function updateOutputs() {
  256. // display current values of all range inputs
  257. pitchOutEl.textContent = pitchInEl.value;
  258. rateOutEl.textContent = rateInEl.value;
  259. volumeOutEl.textContent = volumeInEl.value;
  260. }
  261.  
  262. function updateVoices() {
  263. // add an option for each available voice that isn't already added
  264. window.speechSynthesis.getVoices().forEach(voice => {
  265. const isAlreadyAdded = [...voiceInEl.options].some(option => option.value === voice.voiceURI);
  266. if (!isAlreadyAdded) {
  267. const option = new Option(voice.name, voice.voiceURI, voice.default, voice.default);
  268. voiceInEl.add(option);
  269. }
  270. });
  271. }
  272.  
  273. /*
  274.  
  275. let textelements = document.querySelectorAll('.flex.flex-col.w-full.py-2');
  276. let element = textelements[0];
  277. let textarea = element.querySelector('textarea');
  278. textarea.value = textinput;
  279.  
  280. */
  281.  
  282.  
  283. /*
  284. document.addEventListener('DOMContentLoaded', function() {
  285.  
  286. });
  287. */
  288.  
  289.  

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址