您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Read selected text using OpenAI TTS API
当前为
- // ==UserScript==
- // @name Text-to-Speech Reader
- // @namespace http://tampermonkey.net/
- // @version 1.3
- // @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.width = 'auto';
- 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';
- }
- });
- // Initialize UI components
- function initModal() {
- const modalHTML = `
- <div id="configModal" style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.5); display: none; justify-content: center; align-items: center; z-index: 10000;">
- <div style="background: white; padding: 20px; border-radius: 10px; width: 300px;">
- <h2>Configure TTS Settings</h2>
- <label for="baseUrl">Base URL:</label>
- <input type="text" id="baseUrl" value="${GM_getValue('baseUrl', 'https://api.openai.com')}" style="width: 100%;">
- <label for="apiKey">API Key:</label>
- <input type="text" id="apiKey" value="${GM_getValue('apiKey', '')}" style="width: 100%;">
- <label for="voice">Voice:</label>
- <select id="voice" style="width: 100%;">
- <option value="alloy">Alloy</option>
- <option value="echo">Echo</option>
- <option value="fable">Fable</option>
- <option value="onyx">Onyx</option>
- <option value="nova">Nova</option>
- <option value="shimmer">Shimmer</option>
- </select>
- <button id="saveConfig" style="margin-top: 10px; width: 100%; padding: 10px; background-color: #007BFF; color: white; border: none; border-radius: 5px;">Save</button>
- <button id="cancelConfig" style="margin-top: 10px; width: 100%; padding: 10px; background-color: grey; color: white; border: none; border-radius: 5px;">Cancel</button>
- </div>
- </div>
- `;
- document.body.insertAdjacentHTML('beforeend', modalHTML);
- document.getElementById('saveConfig').addEventListener('click', saveConfig);
- document.getElementById('cancelConfig').addEventListener('click', closeModal);
- }
- function saveConfig() {
- const baseUrl = document.getElementById('baseUrl').value;
- const apiKey = document.getElementById('apiKey').value;
- const voice = document.getElementById('voice').value;
- GM_setValue('baseUrl', baseUrl);
- GM_setValue('apiKey', apiKey);
- GM_setValue('voice', voice);
- alert('Settings saved successfully.');
- closeModal();
- }
- function closeModal() {
- document.getElementById('configModal').style.display = 'none';
- }
- function openModal() {
- if (!document.getElementById('configModal')) {
- initModal();
- }
- document.getElementById('configModal').style.display = 'flex';
- }
- GM_registerMenuCommand('Configure TTS Settings', openModal);
- // Register menu command to clear cache
- GM_registerMenuCommand('Clear TTS Cache', clearCache);
- })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址