您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds speech-to-text functionality to t3.chat using OpenAI's Whisper API with configurable API key via UI.
// ==UserScript== // @name T3 Chat STT with Whisper API (Configurable API Key) // @namespace http://tampermonkey.net/ // @version 1.0 // @description Adds speech-to-text functionality to t3.chat using OpenAI's Whisper API with configurable API key via UI. // @author wearifulpoet // @match https://t3.chat/* // @grant none // @license MIT // ==/UserScript== (function() { 'use strict'; // ********** API Key Configuration ********** // Use localStorage to store the API key. // Initially, if no API key is stored, an empty string is returned. const getApiKey = () => localStorage.getItem("whisper_api_key") || ""; const setApiKey = (key) => localStorage.setItem("whisper_api_key", key); // ********************************************* // Create the STT button. const sttButton = document.createElement('button'); sttButton.innerHTML = "🎙️ Start STT"; sttButton.style.position = "fixed"; sttButton.style.bottom = "20px"; sttButton.style.right = "20px"; sttButton.style.zIndex = "9999"; sttButton.style.padding = "10px"; sttButton.style.fontSize = "16px"; document.body.appendChild(sttButton); // Create the API Key configuration button. const apiKeyButton = document.createElement('button'); apiKeyButton.innerHTML = "API Key"; apiKeyButton.style.position = "fixed"; apiKeyButton.style.bottom = "20px"; apiKeyButton.style.right = "140px"; apiKeyButton.style.zIndex = "9999"; apiKeyButton.style.padding = "10px"; apiKeyButton.style.fontSize = "16px"; document.body.appendChild(apiKeyButton); // Event listener to set/update the API key. apiKeyButton.addEventListener("click", () => { const currentKey = getApiKey(); const newKey = prompt("Enter your Whisper API key:", currentKey); if (newKey !== null) { setApiKey(newKey.trim()); alert("API key updated!"); } }); let mediaRecorder = null; let audioChunks = []; let isRecording = false; sttButton.addEventListener("click", async () => { if (!isRecording) { // Check if the API key has been set. const storedKey = getApiKey(); if (!storedKey) { alert("Please set your Whisper API key using the API Key button."); return; } // Start recording sttButton.innerHTML = "Stop Recording"; isRecording = true; try { const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); mediaRecorder = new MediaRecorder(stream); audioChunks = []; mediaRecorder.addEventListener("dataavailable", event => { if (event.data.size > 0) { audioChunks.push(event.data); } }); mediaRecorder.addEventListener("stop", async () => { const audioBlob = new Blob(audioChunks, { type: 'audio/wav' }); // Prepare the file to send to Whisper API. const audioFile = new File([audioBlob], "audio.wav", { type: 'audio/wav' }); const formData = new FormData(); formData.append("file", audioFile); formData.append("model", "whisper-1"); try { const response = await fetch("https://api.openai.com/v1/audio/transcriptions", { method: "POST", headers: { "Authorization": `Bearer ${getApiKey()}` }, body: formData }); if (!response.ok) { const errorText = await response.text(); console.error("Whisper API error:", errorText); alert("Error with Whisper API:\n" + errorText); return; } const result = await response.json(); const transcription = result.text; // Find the chat input textarea and insert the transcription. const chatInput = document.querySelector("textarea"); if (chatInput) { chatInput.value = transcription; // Dispatch an input event if the site relies on it. chatInput.dispatchEvent(new Event('input', { bubbles: true })); } else { alert("Chat input not found!"); } } catch (error) { console.error("Error calling Whisper API:", error); alert("Error calling Whisper API: " + error.message); } }); mediaRecorder.start(); } catch (error) { console.error("Error accessing microphone:", error); alert("Error accessing microphone: " + error.message); sttButton.innerHTML = "🎙️ Start STT"; isRecording = false; } } else { // Stop recording sttButton.innerHTML = "🎙️ Start STT"; isRecording = false; if (mediaRecorder && mediaRecorder.state === "recording") { mediaRecorder.stop(); } } }); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址