Offex commited on
Commit
bf42e9f
·
verified ·
1 Parent(s): 1cc84d6

Create app.html

Browse files
Files changed (1) hide show
  1. app.html +245 -0
app.html ADDED
@@ -0,0 +1,245 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ```html
2
+ <!DOCTYPE html>
3
+ <html lang="hi">
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <title>Cartesia AI TTS Tool</title>
8
+ <script src="https://cdn.tailwindcss.com"></script>
9
+ <style>
10
+ @import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@300;400;600;700&display=swap');
11
+ body {
12
+ font-family: 'Plus Jakarta Sans', sans-serif;
13
+ background-color: #050505;
14
+ color: #ffffff;
15
+ }
16
+ .cartesia-card {
17
+ background: rgba(20, 20, 20, 0.8);
18
+ border: 1px solid #333;
19
+ backdrop-filter: blur(10px);
20
+ }
21
+ .status-pill {
22
+ padding: 2px 8px;
23
+ border-radius: 99px;
24
+ font-size: 0.7rem;
25
+ font-weight: bold;
26
+ text-transform: uppercase;
27
+ }
28
+ .pulse-red { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.7); animation: pulse-red 2s infinite; }
29
+ @keyframes pulse-red { 0% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.4); } 70% { box-shadow: 0 0 0 10px rgba(239, 68, 68, 0); } 100% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0); } }
30
+ </style>
31
+ </head>
32
+ <body class="p-4 md:p-10 min-h-screen">
33
+ <div class="max-w-5xl mx-auto">
34
+ <!-- Header Section -->
35
+ <div class="flex flex-col md:flex-row justify-between items-center mb-10 gap-4">
36
+ <div>
37
+ <h1 class="text-4xl font-extrabold tracking-tight text-white">Cartesia <span class="text-blue-500">AI</span></h1>
38
+ <p class="text-gray-400">High-performance text-to-speech engine</p>
39
+ </div>
40
+ <div class="flex items-center gap-3 cartesia-card p-2 px-4 rounded-full">
41
+ <span id="statusDot" class="h-3 w-3 rounded-full bg-red-500 pulse-red"></span>
42
+ <span id="statusText" class="text-sm font-medium text-gray-300 uppercase tracking-widest">Disconnected</span>
43
+ </div>
44
+ </div>
45
+
46
+ <div class="grid grid-cols-1 lg:grid-cols-12 gap-8">
47
+ <!-- Left Column: Settings -->
48
+ <div class="lg:col-span-4 space-y-6">
49
+ <div class="cartesia-card p-6 rounded-3xl">
50
+ <h2 class="text-lg font-bold mb-4 flex items-center gap-2">
51
+ <span>🔑</span> API Settings
52
+ </h2>
53
+ <div class="space-y-4">
54
+ <div>
55
+ <label class="block text-xs font-bold text-gray-500 mb-1">API KEY</label>
56
+ <input type="password" id="apiKey" placeholder="sk_car_..."
57
+ class="w-full bg-black border border-gray-800 rounded-xl p-3 text-sm focus:border-blue-500 outline-none transition-all">
58
+ </div>
59
+ <button id="connectBtn" class="w-full bg-white text-black font-bold py-3 rounded-xl hover:bg-gray-200 transition-colors">
60
+ Connect Account
61
+ </button>
62
+ </div>
63
+ </div>
64
+
65
+ <div class="cartesia-card p-6 rounded-3xl">
66
+ <h2 class="text-lg font-bold mb-4 flex items-center gap-2">
67
+ <span>🎙️</span> Voice Engine
68
+ </h2>
69
+ <div class="space-y-4">
70
+ <div>
71
+ <label class="block text-xs font-bold text-gray-500 mb-1">CHOOSE VOICE</label>
72
+ <select id="voiceSelect" class="w-full bg-black border border-gray-800 rounded-xl p-3 text-sm outline-none focus:border-blue-500">
73
+ <option value="">Select a voice...</option>
74
+ </select>
75
+ </div>
76
+ <div>
77
+ <label class="block text-xs font-bold text-gray-500 mb-1">CUSTOM VOICE ID</label>
78
+ <input type="text" id="customVoiceId" placeholder="Paste Voice ID here..."
79
+ class="w-full bg-black border border-gray-800 rounded-xl p-3 text-sm outline-none focus:border-blue-500">
80
+ </div>
81
+ </div>
82
+ </div>
83
+ </div>
84
+
85
+ <!-- Right Column: Workspace -->
86
+ <div class="lg:col-span-8 space-y-6">
87
+ <!-- Message Output Box -->
88
+ <div id="logBox" class="hidden cartesia-card p-4 rounded-2xl text-sm border-l-4">
89
+ <p id="logMessage"></p>
90
+ </div>
91
+
92
+ <div class="cartesia-card p-8 rounded-3xl">
93
+ <label class="block text-xs font-bold text-gray-500 mb-2 uppercase tracking-widest text-center">Your Script</label>
94
+ <textarea id="textInput" rows="6" placeholder="Yahan apna text likhen..."
95
+ class="w-full bg-transparent border-b border-gray-800 text-2xl text-center focus:border-blue-500 outline-none transition-all resize-none mb-8"></textarea>
96
+
97
+ <div class="flex flex-col items-center gap-6">
98
+ <button id="generateBtn" class="bg-blue-600 hover:bg-blue-500 text-white px-10 py-4 rounded-full font-bold text-lg shadow-lg shadow-blue-900/40 disabled:opacity-50 transition-all flex items-center gap-2">
99
+ <span id="btnIcon">⚡</span> <span id="btnText">Convert to Speech</span>
100
+ </button>
101
+
102
+ <div id="audioArea" class="w-full hidden text-center animate-fade-in">
103
+ <audio id="audioPlayer" controls class="w-full mx-auto"></audio>
104
+ <p class="text-xs text-gray-500 mt-2">Niche audio play karen</p>
105
+ </div>
106
+ </div>
107
+ </div>
108
+ </div>
109
+ </div>
110
+ </div>
111
+
112
+ <script>
113
+ const apiKeyInput = document.getElementById('apiKey');
114
+ const connectBtn = document.getElementById('connectBtn');
115
+ const voiceSelect = document.getElementById('voiceSelect');
116
+ const customVoiceId = document.getElementById('customVoiceId');
117
+ const textInput = document.getElementById('textInput');
118
+ const generateBtn = document.getElementById('generateBtn');
119
+ const logBox = document.getElementById('logBox');
120
+ const logMessage = document.getElementById('logMessage');
121
+ const statusDot = document.getElementById('statusDot');
122
+ const statusText = document.getElementById('statusText');
123
+ const audioArea = document.getElementById('audioArea');
124
+ const audioPlayer = document.getElementById('audioPlayer');
125
+
126
+ // Cartesia API Base URL
127
+ const CARTESIA_API_URL = "https://api.cartesia.ai";
128
+
129
+ function updateLog(msg, type = 'info') {
130
+ logBox.classList.remove('hidden');
131
+ logMessage.textContent = msg;
132
+ if (type === 'error') {
133
+ logBox.className = "cartesia-card p-4 rounded-2xl text-sm border-l-4 border-red-500 text-red-400";
134
+ } else if (type === 'success') {
135
+ logBox.className = "cartesia-card p-4 rounded-2xl text-sm border-l-4 border-green-500 text-green-400";
136
+ } else {
137
+ logBox.className = "cartesia-card p-4 rounded-2xl text-sm border-l-4 border-blue-500 text-blue-400";
138
+ }
139
+ }
140
+
141
+ async function fetchVoices() {
142
+ const key = apiKeyInput.value.trim();
143
+ if (!key) return updateLog("Pehle API Key daalen", "error");
144
+
145
+ connectBtn.disabled = true;
146
+ connectBtn.textContent = "Connecting...";
147
+
148
+ try {
149
+ const response = await fetch(`${CARTESIA_API_URL}/voices`, {
150
+ headers: {
151
+ "X-API-Key": key,
152
+ "Cartesia-Version": "2024-06-10"
153
+ }
154
+ });
155
+
156
+ if (!response.ok) throw new Error("API Key galat hai ya expiry ho gayi hai.");
157
+
158
+ const voices = await response.json();
159
+
160
+ voiceSelect.innerHTML = '<option value="">Select a voice...</option>';
161
+ voices.forEach(voice => {
162
+ const option = document.createElement('option');
163
+ option.value = voice.id;
164
+ option.textContent = `${voice.name} (${voice.language})`;
165
+ voiceSelect.appendChild(option);
166
+ });
167
+
168
+ statusDot.className = "h-3 w-3 rounded-full bg-green-500 shadow-lg shadow-green-900";
169
+ statusText.textContent = "CONNECTED";
170
+ updateLog("Account successfully connected! Voices load ho chuki hain.", "success");
171
+
172
+ } catch (err) {
173
+ updateLog(err.message, "error");
174
+ statusDot.className = "h-3 w-3 rounded-full bg-red-500 pulse-red";
175
+ statusText.textContent = "ERROR";
176
+ } finally {
177
+ connectBtn.disabled = false;
178
+ connectBtn.textContent = "Connect Account";
179
+ }
180
+ }
181
+
182
+ connectBtn.addEventListener('click', fetchVoices);
183
+
184
+ generateBtn.addEventListener('click', async () => {
185
+ const key = apiKeyInput.value.trim();
186
+ const voiceId = customVoiceId.value.trim() || voiceSelect.value;
187
+ const text = textInput.value.trim();
188
+
189
+ if (!key) return updateLog("API Key missing!", "error");
190
+ if (!voiceId) return updateLog("Koi voice select karen ya custom ID daalen", "error");
191
+ if (!text) return updateLog("Kuch text to likhen!", "error");
192
+
193
+ generateBtn.disabled = true;
194
+ document.getElementById('btnText').textContent = "Processing...";
195
+ document.getElementById('btnIcon').textContent = "⌛";
196
+ audioArea.classList.add('hidden');
197
+
198
+ try {
199
+ const response = await fetch(`${CARTESIA_API_URL}/tts/bytes`, {
200
+ method: 'POST',
201
+ headers: {
202
+ "X-API-Key": key,
203
+ "Cartesia-Version": "2024-06-10",
204
+ "Content-Type": "application/json"
205
+ },
206
+ body: JSON.stringify({
207
+ model_id: "sonic-english", // Cartesia basic model
208
+ transcript: text,
209
+ voice: {
210
+ mode: "id",
211
+ id: voiceId
212
+ },
213
+ output_format: {
214
+ container: "wav",
215
+ encoding: "pcm_f32le",
216
+ sample_rate: 44100
217
+ }
218
+ })
219
+ });
220
+
221
+ if (!response.ok) {
222
+ const errorData = await response.json();
223
+ throw new Error(errorData.message || "TTS generation failed");
224
+ }
225
+
226
+ const blob = await response.blob();
227
+ const url = URL.createObjectURL(blob);
228
+ audioPlayer.src = url;
229
+ audioArea.classList.remove('hidden');
230
+ updateLog("Audio generate ho gaya!", "success");
231
+ audioPlayer.play();
232
+
233
+ } catch (err) {
234
+ updateLog(err.message, "error");
235
+ } finally {
236
+ generateBtn.disabled = false;
237
+ document.getElementById('btnText').textContent = "Convert to Speech";
238
+ document.getElementById('btnIcon').textContent = "⚡";
239
+ }
240
+ });
241
+ </script>
242
+ </body>
243
+ </html>
244
+
245
+ ```