您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Read selected text using OpenAI TTS API
当前为
- // ==UserScript==
- // @name Text-to-Speech Reader
- // @namespace http://tampermonkey.net/
- // @version 1.0
- // @description Read selected text using OpenAI TTS API
- // @author https://linux.do/u/snaily
- // @match *://*/*
- // @grant GM_xmlhttpRequest
- // @grant GM_registerMenuCommand
- // @grant GM_addStyle
- // @grant GM_setValue
- // @grant GM_getValue
- // @license MIT
- // ==/UserScript==
- (function() {
- 'use strict';
- // Add a button to the page for reading selected text
- const button = document.createElement('button');
- button.innerText = 'Read Aloud';
- button.style.position = 'absolute';
- button.style.zIndex = '1000';
- button.style.display = 'none'; // Initially hidden
- button.style.backgroundColor = '#007BFF'; // Blue background
- button.style.color = '#FFFFFF'; // White text
- button.style.border = 'none';
- button.style.borderRadius = '5px';
- button.style.padding = '10px 20px';
- button.style.boxShadow = '0 2px 5px rgba(0, 0, 0, 0.2)';
- button.style.cursor = 'pointer';
- button.style.fontSize = '14px';
- button.style.fontFamily = 'Arial, sans-serif';
- document.body.appendChild(button);
- // Function to get selected text
- function getSelectedText() {
- let text = '';
- if (window.getSelection) {
- text = window.getSelection().toString();
- } else if (document.selection && document.selection.type != 'Control') {
- text = document.selection.createRange().text;
- }
- console.log('Selected Text:', text); // Debugging line
- return text;
- }
- // Function to call OpenAI TTS API
- function callOpenAITTS(text, baseUrl, apiKey, voice) {
- const cachedAudioUrl = getCachedAudio(text);
- if (cachedAudioUrl) {
- console.log('Using cached audio');
- playAudio(cachedAudioUrl);
- resetButton();
- return;
- }
- const url = `${baseUrl}/v1/audio/speech`;
- console.log('Calling OpenAI TTS API with text:', text);
- GM_xmlhttpRequest({
- method: 'POST',
- url: url,
- headers: {
- 'Content-Type': 'application/json',
- 'Authorization': `Bearer ${apiKey}`
- },
- data: JSON.stringify({
- model: 'tts-1',
- input: text,
- voice: voice
- }),
- responseType: 'arraybuffer',
- onload: function(response) {
- if (response.status === 200) {
- console.log('API call successful'); // Debugging line
- const audioBlob = new Blob([response.response], { type: 'audio/mpeg' });
- const audioUrl = URL.createObjectURL(audioBlob);
- playAudio(audioUrl);
- cacheAudio(text, audioUrl);
- } else {
- console.error('Error:', response.statusText);
- }
- // Reset button after request is complete
- resetButton();
- },
- onerror: function(error) {
- console.error('Request failed', error);
- // Reset button after request is complete
- resetButton();
- }
- });
- }
- // Function to play audio
- function playAudio(url) {
- const audio = new Audio(url);
- audio.play();
- }
- // Function to use browser's built-in TTS
- function speakText(text) {
- const utterance = new SpeechSynthesisUtterance(text);
- speechSynthesis.speak(utterance);
- }
- // Function to set button to loading state
- function setLoadingState() {
- button.disabled = true;
- button.innerText = 'Loading...';
- button.style.backgroundColor = '#6c757d'; // Grey background
- button.style.cursor = 'not-allowed';
- }
- // Function to reset button to original state
- function resetButton() {
- button.disabled = false;
- button.innerText = 'Read Aloud';
- button.style.backgroundColor = '#007BFF'; // Blue background
- button.style.cursor = 'pointer';
- }
- // Helper function to get cached audio URL
- function getCachedAudio(text) {
- const cache = GM_getValue('cache', {});
- const item = cache[text];
- if (item) {
- const now = new Date().getTime();
- const weekInMillis = 7 * 24 * 60 * 60 * 1000; // One day in milliseconds
- if (now - item.timestamp < weekInMillis) {
- return item.audioUrl;
- } else {
- delete cache[text]; // Remove expired cache item
- GM_setValue('cache', cache);
- }
- }
- return null;
- }
- // Helper function to cache audio URL
- function cacheAudio(text, audioUrl) {
- const cache = GM_getValue('cache', {});
- cache[text] = {
- audioUrl: audioUrl,
- timestamp: new Date().getTime()
- };
- GM_setValue('cache', cache);
- }
- // Function to clear cache
- function clearCache() {
- GM_setValue('cache', {});
- alert('Cache cleared successfully.');
- }
- // Event listener for button click
- button.addEventListener('click', () => {
- const selectedText = getSelectedText();
- if (selectedText) {
- let apiKey = GM_getValue('apiKey', null);
- let baseUrl = GM_getValue('baseUrl', null);
- let voice = GM_getValue('voice', 'onyx'); // Default to 'onyx'
- if (!baseUrl) {
- alert('Please set the base URL for the TTS API in the Tampermonkey menu.');
- return;
- }
- if (!apiKey) {
- alert('Please set the API key for the TTS API in the Tampermonkey menu.');
- return;
- }
- setLoadingState(); // Set button to loading state
- if (window.location.hostname === 'github.com') {
- speakText(selectedText);
- resetButton(); // Reset button immediately for built-in TTS
- }else {
- callOpenAITTS(selectedText, baseUrl, apiKey, voice);
- }
- } else {
- alert('Please select some text to read aloud.');
- }
- });
- // Show the button near the selected text
- document.addEventListener('mouseup', (event) => {
- // Check if the mouseup event is triggered by the button itself
- if (event.target === button) {
- return;
- }
- const selectedText = getSelectedText();
- if (selectedText) {
- const mouseX = event.pageX;
- const mouseY = event.pageY;
- button.style.left = `${mouseX + 10}px`;
- button.style.top = `${mouseY + 10}px`;
- button.style.display = 'block';
- } else {
- button.style.display = 'none';
- }
- });
- // Register menu command to set base URL
- GM_registerMenuCommand('Set Base URL for TTS API', () => {
- const currentBaseUrl = GM_getValue('baseUrl', 'https://api.openai.com'); // Default to 'https://api.openai.com'
- const newBaseUrl = prompt('Enter the base URL for the TTS API:', currentBaseUrl);
- if (newBaseUrl) {
- GM_setValue('baseUrl', newBaseUrl);
- alert('Base URL set to: ' + newBaseUrl);
- }
- });
- // Register menu command to set API key
- GM_registerMenuCommand('Set API Key for TTS API', () => {
- const currentApiKey = GM_getValue('apiKey', '');
- const newApiKey = prompt('Enter the API key for the TTS API:', currentApiKey);
- if (newApiKey) {
- GM_setValue('apiKey', newApiKey);
- alert('API key set to: ' + newApiKey);
- }
- });
- // Register menu command to set voice
- GM_registerMenuCommand('Set Voice for TTS', () => {
- const currentVoice = GM_getValue('voice', 'onyx'); // Default to 'onyx'
- const newVoice = prompt('Enter the voice for the TTS API (alloy, echo, fable, onyx, nova, shimmer):', currentVoice);
- const validVoices = ['alloy', 'echo', 'fable', 'onyx', 'nova', 'shimmer'];
- if (newVoice && validVoices.includes(newVoice.toLowerCase())) {
- GM_setValue('voice', newVoice.toLowerCase());
- alert('Voice set to: ' + newVoice);
- } else {
- alert('Invalid voice. Please enter one of the following: alloy, echo, fable, onyx, nova, shimmer.');
- }
- });
- // Register menu command to clear cache
- GM_registerMenuCommand('Clear TTS Cache', clearCache);
- })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址