File size: 9,192 Bytes
ef89a6f
 
 
 
 
 
 
 
 
 
5169bfd
ef89a6f
5169bfd
 
 
 
 
 
 
ef89a6f
 
 
 
 
 
 
5169bfd
 
ef89a6f
 
 
 
 
 
 
 
 
5169bfd
ef89a6f
5169bfd
 
 
 
 
 
 
 
 
 
ef89a6f
 
 
 
 
 
 
 
 
 
 
5169bfd
ef89a6f
 
 
 
 
 
 
 
 
 
 
5169bfd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ef89a6f
 
 
 
5169bfd
ef89a6f
5169bfd
 
 
 
 
ef89a6f
 
 
 
 
 
5169bfd
ef89a6f
 
 
 
5169bfd
ef89a6f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5169bfd
ef89a6f
 
 
 
 
 
 
 
 
5169bfd
ef89a6f
 
 
 
 
 
 
 
 
 
 
 
5169bfd
ef89a6f
 
 
 
 
 
 
 
c34d857
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
<!DOCTYPE html>
<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>