Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>11Labs Safe TTS Tool</title> | |
| <style> | |
| body { font-family: Arial, sans-serif; max-width: 600px; margin: 40px auto; padding: 20px; background-color: #f4f4f9; } | |
| .container { background: white; padding: 20px; border-radius: 10px; box-shadow: 0 4px 8px rgba(0,0,0,0.1); } | |
| h2 { text-align: center; color: #333; } | |
| label { font-weight: bold; display: block; margin-top: 15px; } | |
| input, textarea, select { width: 100%; padding: 10px; margin-top: 5px; border: 1px solid #ccc; border-radius: 5px; box-sizing: border-box; } | |
| .btn { width: 100%; color: white; padding: 12px; border: none; border-radius: 5px; margin-top: 15px; cursor: pointer; font-size: 16px; font-weight: bold; transition: 0.3s; } | |
| .btn-blue { background-color: #007bff; } | |
| .btn-blue:hover { background-color: #0056b3; } | |
| .btn-green { background-color: #28a745; } | |
| .btn-green:hover:not(:disabled) { background-color: #218838; } | |
| .btn:disabled { background-color: #6c757d; cursor: not-allowed; } | |
| #audioContainer { margin-top: 20px; text-align: center; display: none; padding: 15px; background: #e9ecef; border-radius: 8px; } | |
| .status-box { text-align: center; margin-top: 15px; padding: 10px; border-radius: 5px; font-weight: bold; display: none; transition: 0.3s; } | |
| .status-loading { background-color: #fff3cd; color: #856404; display: block; } | |
| .status-success { background-color: #d4edda; color: #155724; display: block; } | |
| .status-error { background-color: #f8d7da; color: #721c24; display: block; } | |
| #customVoiceDiv { display: none; margin-top: 10px; padding: 10px; background: #fff8e1; border-left: 4px solid #ffc107; border-radius: 4px; } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <h2>11Labs Safe TTS (No IP Block)</h2> | |
| <label for="apiKey">ElevenLabs API Key:</label> | |
| <input type="password" id="apiKey" placeholder="Apni API key yahan daalein..." required> | |
| <button class="btn btn-blue" onclick="connectAPI()" id="connectBtn">Connect API & Load Voices</button> | |
| <label for="voiceDropdown">Select Voice:</label> | |
| <select id="voiceDropdown" onchange="toggleCustomVoice()"> | |
| <option value="">-- Pehle API Connect Karein --</option> | |
| <option value="custom">✏️ Enter Custom Voice ID</option> | |
| </select> | |
| <div id="customVoiceDiv"> | |
| <label for="customVoiceId">Custom Voice ID:</label> | |
| <input type="text" id="customVoiceId" placeholder="Voice ID paste karein (e.g., EXAVITQu4vr4xnSDxMaL)"> | |
| </div> | |
| <label for="modelSelect">Select Model:</label> | |
| <select id="modelSelect"> | |
| <option value="eleven_multilingual_v2">Multilingual v2 (Best for most)</option> | |
| <option value="eleven_multilingual_v1">Multilingual v1</option> | |
| <option value="eleven_monolingual_v1">Monolingual v1 (English only)</option> | |
| </select> | |
| <label for="text">Text to Speech:</label> | |
| <textarea id="text" rows="5" placeholder="Jo bulwana hai yahan type karein..." required></textarea> | |
| <button class="btn btn-green" onclick="generateAudio()" id="generateBtn">Generate Audio</button> | |
| <div id="statusBox" class="status-box"></div> | |
| <div id="audioContainer"> | |
| <audio id="audioPlayer" controls style="width: 100%;"></audio> | |
| <br><br> | |
| <a id="downloadLink" download="generated_audio.mp3" style="text-decoration: none; background: #007bff; color: white; padding: 10px 20px; border-radius: 5px; display: inline-block;">Download MP3</a> | |
| </div> | |
| </div> | |
| <script> | |
| // API Connect karke Voices load karna | |
| async function connectAPI() { | |
| const apiKey = document.getElementById('apiKey').value.trim(); | |
| const connectBtn = document.getElementById('connectBtn'); | |
| const voiceDropdown = document.getElementById('voiceDropdown'); | |
| if (!apiKey) { | |
| showStatus('कृपया पहले API Key डालें!', 'error'); | |
| return; | |
| } | |
| showStatus('Voices लोड हो रही हैं... ⏳', 'loading'); | |
| connectBtn.disabled = true; | |
| try { | |
| const response = await fetch('https://api.elevenlabs.io/v1/voices', { | |
| method: 'GET', | |
| headers: { 'xi-api-key': apiKey } | |
| }); | |
| if (!response.ok) { | |
| throw new Error("API Key गलत है या नेटवर्क समस्या है!"); | |
| } | |
| const data = await response.json(); | |
| // Dropdown clear karke naye options daalna | |
| voiceDropdown.innerHTML = '<option value="custom">✏️ Enter Custom Voice ID</option>'; | |
| data.voices.forEach(voice => { | |
| const option = document.createElement('option'); | |
| option.value = voice.voice_id; | |
| option.textContent = voice.name; | |
| voiceDropdown.appendChild(option); | |
| }); | |
| // Default pehli voice select karna agar available ho | |
| if (data.voices.length > 0) { | |
| voiceDropdown.value = data.voices[0].voice_id; | |
| } | |
| toggleCustomVoice(); // Custom box ko hide karne ke liye | |
| showStatus('API Connected! ' + data.voices.length + ' Voices लोड हो गईं ✅', 'success'); | |
| } catch (error) { | |
| showStatus('Error: ' + error.message, 'error'); | |
| } finally { | |
| connectBtn.disabled = false; | |
| } | |
| } | |
| // Custom Voice ID box ko dikhana ya chhupana | |
| function toggleCustomVoice() { | |
| const dropdown = document.getElementById('voiceDropdown'); | |
| const customDiv = document.getElementById('customVoiceDiv'); | |
| if (dropdown.value === 'custom') { | |
| customDiv.style.display = 'block'; | |
| } else { | |
| customDiv.style.display = 'none'; | |
| } | |
| } | |
| // Audio Generate karna | |
| async function generateAudio() { | |
| const apiKey = document.getElementById('apiKey').value.trim(); | |
| const modelId = document.getElementById('modelSelect').value; | |
| const text = document.getElementById('text').value.trim(); | |
| const dropdown = document.getElementById('voiceDropdown'); | |
| let voiceId = dropdown.value; | |
| if (voiceId === 'custom') { | |
| voiceId = document.getElementById('customVoiceId').value.trim(); | |
| } | |
| const audioContainer = document.getElementById('audioContainer'); | |
| const audioPlayer = document.getElementById('audioPlayer'); | |
| const downloadLink = document.getElementById('downloadLink'); | |
| const generateBtn = document.getElementById('generateBtn'); | |
| if (!apiKey || !text || !voiceId) { | |
| showStatus('कृपया API Key, Voice ID और Text भरें!', 'error'); | |
| return; | |
| } | |
| audioContainer.style.display = "none"; | |
| showStatus('Audio जनरेट हो रहा है, कृपया प्रतीक्षा करें... ⏳', 'loading'); | |
| generateBtn.disabled = true; | |
| generateBtn.innerText = "Processing..."; | |
| try { | |
| const response = await fetch(`https://api.elevenlabs.io/v1/text-to-speech/${voiceId}`, { | |
| method: 'POST', | |
| headers: { | |
| 'Accept': 'audio/mpeg', | |
| 'xi-api-key': apiKey, | |
| 'Content-Type': 'application/json' | |
| }, | |
| body: JSON.stringify({ | |
| text: text, | |
| model_id: modelId, | |
| voice_settings: { | |
| stability: 0.5, | |
| similarity_boost: 0.5 | |
| } | |
| }) | |
| }); | |
| if (!response.ok) { | |
| const errData = await response.json(); | |
| throw new Error(errData.detail.message || "API request फेल हो गई!"); | |
| } | |
| const blob = await response.blob(); | |
| const audioUrl = URL.createObjectURL(blob); | |
| audioPlayer.src = audioUrl; | |
| downloadLink.href = audioUrl; | |
| audioContainer.style.display = "block"; | |
| showStatus('Audio तैयार है! 🎉', 'success'); | |
| } catch (error) { | |
| showStatus('Error: ' + error.message, 'error'); | |
| } finally { | |
| generateBtn.disabled = false; | |
| generateBtn.innerText = "Generate Audio"; | |
| } | |
| } | |
| function showStatus(message, type) { | |
| const statusBox = document.getElementById('statusBox'); | |
| statusBox.innerText = message; | |
| statusBox.className = 'status-box'; | |
| if(type === 'loading') statusBox.classList.add('status-loading'); | |
| if(type === 'success') statusBox.classList.add('status-success'); | |
| if(type === 'error') statusBox.classList.add('status-error'); | |
| } | |
| </script> | |
| </body> | |
| </html> | |