Hamed744 commited on
Commit
e10b50e
·
verified ·
1 Parent(s): 3270dcb

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +79 -267
index.html CHANGED
@@ -3,215 +3,47 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>ساخت صدای اختصاصی</title>
7
  <link href="https://fonts.googleapis.com/css2?family=Vazirmatn:wght@400;700&display=swap" rel="stylesheet">
8
  <style>
9
- /* --- General & Background Styles --- */
10
- :root {
11
- --primary-color: #3d5afe;
12
- --secondary-color: #00b0ff;
13
- --text-color: #e0e0e0;
14
- --bg-color-start: #1a2940;
15
- --bg-color-end: #2b3b58;
16
- --glass-bg: rgba(255, 255, 255, 0.05);
17
- --glass-border: rgba(255, 255, 255, 0.2);
18
- }
19
-
20
- @keyframes fadeIn {
21
- from { opacity: 0; transform: translateY(20px); }
22
- to { opacity: 1; transform: translateY(0); }
23
- }
24
-
25
- @keyframes spin {
26
- to { transform: rotate(360deg); }
27
- }
28
-
29
- body {
30
- font-family: 'Vazirmatn', sans-serif;
31
- background: linear-gradient(135deg, var(--bg-color-start), var(--bg-color-end));
32
- color: var(--text-color);
33
- margin: 0;
34
- display: flex;
35
- justify-content: center;
36
- align-items: center;
37
- min-height: 100vh;
38
- overflow-x: hidden;
39
- }
40
-
41
- /* --- Delta Code Gate Styles (Glassmorphism) --- */
42
- #delta-gate-container {
43
- background: var(--glass-bg);
44
- backdrop-filter: blur(15px);
45
- -webkit-backdrop-filter: blur(15px);
46
- border: 1px solid var(--glass-border);
47
- padding: 40px;
48
- border-radius: 20px;
49
- box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.3);
50
- text-align: center;
51
- max-width: 450px;
52
- width: 90%;
53
- transition: opacity 0.5s, transform 0.5s;
54
- animation: fadeIn 0.8s ease-out;
55
- }
56
-
57
- #delta-gate-container.hidden {
58
- opacity: 0;
59
- transform: scale(0.9);
60
- pointer-events: none;
61
- }
62
-
63
- .gate-icon {
64
- width: 60px;
65
- height: 60px;
66
- margin-bottom: 20px;
67
- opacity: 0.8;
68
- }
69
-
70
- #delta-gate-container h1 {
71
- color: #fff;
72
- margin-bottom: 15px;
73
- font-size: 26px;
74
- }
75
-
76
- #delta-gate-container p {
77
- color: var(--text-color);
78
- margin-bottom: 30px;
79
- font-size: 16px;
80
- line-height: 1.6;
81
- }
82
-
83
- #delta-code-input {
84
- width: 100%;
85
- padding: 15px;
86
- background: rgba(0, 0, 0, 0.2);
87
- border: 1px solid var(--glass-border);
88
- border-radius: 12px;
89
- font-size: 16px;
90
- text-align: center;
91
- color: #fff;
92
- box-sizing: border-box;
93
- direction: ltr;
94
- margin-bottom: 25px;
95
- transition: all 0.3s ease;
96
- }
97
-
98
- #delta-code-input::placeholder {
99
- color: rgba(255, 255, 255, 0.5);
100
- }
101
-
102
- #delta-code-input:focus {
103
- outline: none;
104
- border-color: var(--primary-color);
105
- box-shadow: 0 0 0 4px rgba(61, 90, 254, 0.3);
106
- }
107
-
108
- #verify-button {
109
- width: 100%;
110
- padding: 15px;
111
- background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
112
- color: white;
113
- border: none;
114
- border-radius: 12px;
115
- cursor: pointer;
116
- font-size: 18px;
117
- font-weight: bold;
118
- transition: all 0.3s ease;
119
- position: relative;
120
- overflow: hidden;
121
- }
122
-
123
- #verify-button:hover:not(:disabled) {
124
- transform: translateY(-2px);
125
- box-shadow: 0 6px 20px rgba(61, 90, 254, 0.4);
126
- }
127
-
128
- #verify-button:disabled {
129
- background: #555;
130
- cursor: not-allowed;
131
- }
132
-
133
- .loader {
134
- width: 20px;
135
- height: 20px;
136
- border: 3px solid rgba(255, 255, 255, 0.3);
137
- border-top-color: #fff;
138
- border-radius: 50%;
139
- animation: spin 1s linear infinite;
140
- display: inline-block;
141
- }
142
-
143
- #error-message {
144
- color: #ff8a80;
145
- margin-top: 20px;
146
- font-weight: bold;
147
- min-height: 20px;
148
- }
149
-
150
- /* --- Main Content (Vevo API) Styles --- */
151
- #main-content-container {
152
- display: none;
153
- width: 100%;
154
- max-width: 650px;
155
- }
156
-
157
- #huggingface-vevo-api-container {
158
- font-family: 'Vazirmatn', sans-serif;
159
- margin: 20px auto;
160
- background-color: #f7fafc;
161
- color: #2d3748;
162
- direction: rtl;
163
- padding: 10px;
164
- border-radius: 16px;
165
- max-width: 600px;
166
- box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
167
- animation: fadeIn 0.8s ease-out;
168
- }
169
- #huggingface-vevo-api-container .container {
170
- padding: 20px;
171
- background-color: white;
172
- border-radius: 12px;
173
- }
174
- #huggingface-vevo-api-container h1 {
175
- text-align: center; color: #2c5282; font-size: 24px;
176
- }
177
- #huggingface-vevo-api-container .file-input {
178
- margin-bottom: 20px;
179
- }
180
- #huggingface-vevo-api-container label {
181
- display: block; margin-bottom: 8px; font-weight: bold;
182
- }
183
- #huggingface-vevo-api-container .description {
184
- font-size: 14px; color: #718096; margin-top: -5px; margin-bottom: 10px; font-weight: normal;
185
- }
186
- #huggingface-vevo-api-container input[type="file"] {
187
- display: block; width: 100%; padding: 10px; border: 1px solid #cbd5e0; border-radius: 8px; box-sizing: border-box; background-color: #edf2f7; cursor: pointer;
188
- }
189
- #huggingface-vevo-api-container button {
190
- display: block; width: 100%; padding: 14px; background: linear-gradient(135deg, var(--primary-color), var(--secondary-color)); color: white; border: none; border-radius: 8px; cursor: pointer; font-size: 16px; font-weight: bold; transition: all 0.3s;
191
- }
192
- #huggingface-vevo-api-container button:hover:not(:disabled) {
193
- transform: translateY(-2px); box-shadow: 0 4px 15px rgba(61, 90, 254, 0.3);
194
- }
195
- #huggingface-vevo-api-container button:disabled {
196
- background: #a0aec0; cursor: not-allowed;
197
- }
198
- #huggingface-vevo-api-container #status {
199
- margin-top: 20px; padding: 12px; background-color: #e2e8f0; border-radius: 8px; text-align: center;
200
- }
201
- #huggingface-vevo-api-container #result {
202
- margin-top: 20px; text-align: center;
203
- }
204
- #huggingface-vevo-api-container #result audio {
205
- width: 100%; margin-top: 10px; border-radius: 8px;
206
- }
207
- #huggingface-vevo-api-container #result a {
208
- color: var(--primary-color); text-decoration: none; display: inline-block; margin-top: 15px; font-weight: bold;
209
- }
210
  </style>
211
  </head>
212
  <body>
213
 
214
- <!-- Gate Container: Asks for Delta Code -->
215
  <div id="delta-gate-container">
216
  <svg class="gate-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" color="#fff"><path d="M17 3.25H7C4.65279 3.25 2.75 5.15279 2.75 7.5V16.5C2.75 18.8472 4.65279 20.75 7 20.75H17C19.3472 20.75 21.25 18.8472 21.25 16.5V7.5C21.25 5.15279 19.3472 3.25 17 3.25ZM19.75 7.5V16.5C19.75 18.0376 18.5376 19.25 17 19.25H7C5.46243 19.25 4.25 18.0376 4.25 16.5V7.5C4.25 5.96243 5.46243 4.75 7 4.75H17C18.5376 4.75 19.75 5.96243 19.75 7.5ZM12 7.75C12.4142 7.75 12.75 8.08579 12.75 8.5V11H14.25C14.6642 11 15 11.3358 15 11.75V13.25C15 13.6642 14.6642 14 14.25 14H12.75V15.5C12.75 15.9142 12.4142 16.25 12 16.25C11.5858 16.25 11.25 15.9142 11.25 15.5V14H9.75C9.33579 14 9 13.6642 9 13.25V11.75C9 11.3358 9.33579 11 9.75 11H11.25V8.5C11.25 8.08579 11.5858 7.75 12 7.75Z"></path></svg>
217
  <h1>ورود به پنل اختصاصی</h1>
@@ -220,20 +52,32 @@
220
  <button id="verify-button">تأیید و ورود</button>
221
  <div id="error-message"></div>
222
  </div>
223
-
224
- <!-- Main Content: Your Voice Conversion Tool (Initially Hidden) -->
225
  <div id="main-content-container">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
226
  <div id="huggingface-vevo-api-container">
227
  <div class="container">
228
  <h1>رابط کاربری API برای Vevo</h1>
229
  <div class="file-input">
230
  <label for="sourceAudio">فایل صوتی اصلی (Source Audio):</label>
231
- <p class="description">این فایل صوتی حاوی کلامی است که می‌خواهید با صدای جدید خوانده شود (مثلاً صدای خودتان).</p>
232
  <input type="file" id="sourceAudio" accept="audio/*" />
233
  </div>
234
  <div class="file-input">
235
  <label for="timbreRef">فایل صوتی مرجع (Timbre Reference):</label>
236
- <p class="description">این فایل صوتی، ��دای مدلی است که می‌خواهید صدای اصلی به آن تبدیل شود.</p>
237
  <input type="file" id="timbreRef" accept="audio/*" />
238
  </div>
239
  <button id="generateBtn">تبدیل صدا</button>
@@ -241,24 +85,16 @@
241
  <div id="result"></div>
242
  </div>
243
  </div>
244
- </div>
245
-
246
- <script>
247
- document.addEventListener('DOMContentLoaded', () => {
248
-
249
- // --- Section 1: Gate Logic ---
250
- const gateContainer = document.getElementById('delta-gate-container');
251
- const mainContentContainer = document.getElementById('main-content-container');
252
- const verifyButton = document.getElementById('verify-button');
253
- const codeInput = document.getElementById('delta-code-input');
254
- const errorMessage = document.getElementById('error-message');
255
- const buttonOriginalText = verifyButton.innerHTML;
256
 
257
  const showMainContent = () => {
258
  gateContainer.classList.add('hidden');
259
  setTimeout(() => {
260
  gateContainer.style.display = 'none';
261
  mainContentContainer.style.display = 'block';
 
 
 
262
  }, 500);
263
  };
264
 
@@ -279,33 +115,38 @@ document.addEventListener('DOMContentLoaded', () => {
279
  verifyButton.innerHTML = '<div class="loader"></div>';
280
 
281
  try {
282
- // ** CRITICAL: This URL points to YOUR live PHP script **
283
- const response = await fetch('https://www.aisada.ir/app/gemin.php', {
284
  method: 'POST',
285
  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
286
  body: `delta_code=${encodeURIComponent(code)}`
287
  });
288
 
289
- // The PHP script itself will return a response, but we only need to know if it was sent.
290
- // A better implementation would check the JSON response, but this works for now.
291
  if (!response.ok) {
292
- throw new Error(`خطای سرور: ${response.statusText}`);
 
 
 
 
 
 
 
 
 
 
293
  }
294
-
295
- // Assume success if the request was sent without network errors
296
- localStorage.setItem('isDeltaCodeValidated', 'true');
297
- showMainContent();
298
 
299
  } catch (error) {
300
- errorMessage.textContent = 'خطای شبکه. از اتصال اینترنت خود مطمئن شوید یا بعداً تلاش کنید.';
301
  verifyButton.disabled = false;
302
  verifyButton.innerHTML = buttonOriginalText;
303
  }
304
  });
305
 
306
- // --- Section 2: Your Vevo API Logic ---
307
- const container = document.getElementById('huggingface-vevo-api-container');
308
- if (container) {
 
 
309
  const generateBtn = container.querySelector('#generateBtn');
310
  const sourceAudioInput = container.querySelector('#sourceAudio');
311
  const timbreRefInput = container.querySelector('#timbreRef');
@@ -314,8 +155,8 @@ document.addEventListener('DOMContentLoaded', () => {
314
 
315
  const API_URL = "https://amphion-vevo.hf.space/gradio_api/";
316
 
 
317
  const generateSessionHash = () => Math.random().toString(36).substring(2, 15);
318
-
319
  async function uploadFile(file) {
320
  const formData = new FormData();
321
  formData.append("files", file);
@@ -324,56 +165,30 @@ document.addEventListener('DOMContentLoaded', () => {
324
  if (result && result.length > 0) return result[0];
325
  throw new Error("آپلود فایل با خطا مواجه شد.");
326
  }
327
-
328
  async function startGeneration() {
329
  const sourceFile = sourceAudioInput.files[0];
330
  const timbreFile = timbreRefInput.files[0];
331
-
332
- if (!sourceFile || !timbreFile) {
333
- alert("لطفاً هر دو فایل صوتی را انتخاب کنید.");
334
- return;
335
- }
336
-
337
  generateBtn.disabled = true;
338
  statusDiv.textContent = 'در حال آپلود فایل اصلی...';
339
  resultDiv.innerHTML = '';
340
-
341
  const sessionHash = generateSessionHash();
342
-
343
  try {
344
  const sourcePath = await uploadFile(sourceFile);
345
  statusDiv.textContent = 'در حال آپلود فایل مرجع...';
346
  const timbrePath = await uploadFile(timbreFile);
347
-
348
  statusDiv.textContent = 'ارسال درخواست برای پردازش...';
349
-
350
- const joinPayload = {
351
- "data": [
352
- { "path": sourcePath, "url": `${API_URL}file=${sourcePath}`, "orig_name": sourceFile.name, "meta": { "_type": "gradio.FileData" } },
353
- { "path": timbrePath, "url": `${API_URL}file=${timbrePath}`, "orig_name": timbreFile.name, "meta": { "_type": "gradio.FileData" } }
354
- ],
355
- "fn_index": 0, "session_hash": sessionHash
356
- };
357
-
358
- await fetch(`${API_URL}queue/join?`, {
359
- method: 'POST',
360
- headers: { 'Content-Type': 'application/json' },
361
- body: JSON.stringify(joinPayload)
362
- });
363
-
364
  statusDiv.textContent = 'در صف پردازش. منتظر نتیجه بمانید...';
365
  const eventSource = new EventSource(`${API_URL}queue/data?session_hash=${sessionHash}`);
366
-
367
  eventSource.onmessage = (event) => {
368
  const data = JSON.parse(event.data);
369
-
370
- if (data.msg === 'process_starts') {
371
- statusDiv.textContent = 'پردازش شروع شد...';
372
- } else if (data.msg === 'process_completed') {
373
  statusDiv.textContent = 'پردازش با موفقیت انجام شد!';
374
  const resultPath = data.output.data[0].path;
375
  const resultUrl = `${API_URL}file=${resultPath}`;
376
-
377
  resultDiv.innerHTML = `<h3>نتیجه:</h3><audio controls src="${resultUrl}"></audio><br><a href="${resultUrl}" download="output_voice.wav">دانلود فایل</a>`;
378
  eventSource.close();
379
  generateBtn.disabled = false;
@@ -383,19 +198,16 @@ document.addEventListener('DOMContentLoaded', () => {
383
  generateBtn.disabled = false;
384
  }
385
  };
386
-
387
  eventSource.onerror = () => {
388
  statusDiv.textContent = 'خطا در ارتباط با سرور.';
389
  eventSource.close();
390
  generateBtn.disabled = false;
391
  };
392
-
393
  } catch (error) {
394
  statusDiv.textContent = `خطا: ${error.message}`;
395
  generateBtn.disabled = false;
396
  }
397
  }
398
-
399
  generateBtn.addEventListener('click', startGeneration);
400
  }
401
  });
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>ورود به پنل اختصاصی</title>
7
  <link href="https://fonts.googleapis.com/css2?family=Vazirmatn:wght@400;700&display=swap" rel="stylesheet">
8
  <style>
9
+ /* CSS styles from the previous response are here... (I've kept them exactly the same) */
10
+ :root { --primary-color: #3d5afe; --secondary-color: #00b0ff; --text-color: #e0e0e0; --bg-color-start: #1a2940; --bg-color-end: #2b3b58; --glass-bg: rgba(255, 255, 255, 0.05); --glass-border: rgba(255, 255, 255, 0.2); }
11
+ @keyframes fadeIn { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } }
12
+ @keyframes spin { to { transform: rotate(360deg); } }
13
+ body { font-family: 'Vazirmatn', sans-serif; background: linear-gradient(135deg, var(--bg-color-start), var(--bg-color-end)); color: var(--text-color); margin: 0; display: flex; justify-content: center; align-items: center; min-height: 100vh; overflow-x: hidden; }
14
+ #delta-gate-container { background: var(--glass-bg); backdrop-filter: blur(15px); -webkit-backdrop-filter: blur(15px); border: 1px solid var(--glass-border); padding: 40px; border-radius: 20px; box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.3); text-align: center; max-width: 450px; width: 90%; transition: opacity 0.5s, transform 0.5s; animation: fadeIn 0.8s ease-out; }
15
+ #delta-gate-container.hidden { opacity: 0; transform: scale(0.9); pointer-events: none; }
16
+ .gate-icon { width: 60px; height: 60px; margin-bottom: 20px; opacity: 0.8; }
17
+ #delta-gate-container h1 { color: #fff; margin-bottom: 15px; font-size: 26px; }
18
+ #delta-gate-container p { color: var(--text-color); margin-bottom: 30px; font-size: 16px; line-height: 1.6; }
19
+ #delta-code-input { width: 100%; padding: 15px; background: rgba(0, 0, 0, 0.2); border: 1px solid var(--glass-border); border-radius: 12px; font-size: 16px; text-align: center; color: #fff; box-sizing: border-box; direction: ltr; margin-bottom: 25px; transition: all 0.3s ease; }
20
+ #delta-code-input::placeholder { color: rgba(255, 255, 255, 0.5); }
21
+ #delta-code-input:focus { outline: none; border-color: var(--primary-color); box-shadow: 0 0 0 4px rgba(61, 90, 254, 0.3); }
22
+ #verify-button { width: 100%; padding: 15px; background: linear-gradient(135deg, var(--primary-color), var(--secondary-color)); color: white; border: none; border-radius: 12px; cursor: pointer; font-size: 18px; font-weight: bold; transition: all 0.3s ease; position: relative; overflow: hidden; }
23
+ #verify-button:hover:not(:disabled) { transform: translateY(-2px); box-shadow: 0 6px 20px rgba(61, 90, 254, 0.4); }
24
+ #verify-button:disabled { background: #555; cursor: not-allowed; }
25
+ .loader { width: 20px; height: 20px; border: 3px solid rgba(255, 255, 255, 0.3); border-top-color: #fff; border-radius: 50%; animation: spin 1s linear infinite; display: inline-block; }
26
+ #error-message { color: #ff8a80; margin-top: 20px; font-weight: bold; min-height: 20px; }
27
+ #main-content-container { display: none; width: 100%; max-width: 650px; }
28
+ #huggingface-vevo-api-container { font-family: 'Vazirmatn', sans-serif; margin: 20px auto; background-color: #f7fafc; color: #2d3748; direction: rtl; padding: 10px; border-radius: 16px; max-width: 600px; box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1); animation: fadeIn 0.8s ease-out; }
29
+ #huggingface-vevo-api-container .container { padding: 20px; background-color: white; border-radius: 12px; }
30
+ #huggingface-vevo-api-container h1 { text-align: center; color: #2c5282; font-size: 24px; }
31
+ #huggingface-vevo-api-container .file-input { margin-bottom: 20px; }
32
+ #huggingface-vevo-api-container label { display: block; margin-bottom: 8px; font-weight: bold; }
33
+ #huggingface-vevo-api-container .description { font-size: 14px; color: #718096; margin-top: -5px; margin-bottom: 10px; font-weight: normal; }
34
+ #huggingface-vevo-api-container input[type="file"] { display: block; width: 100%; padding: 10px; border: 1px solid #cbd5e0; border-radius: 8px; box-sizing: border-box; background-color: #edf2f7; cursor: pointer; }
35
+ #huggingface-vevo-api-container button { display: block; width: 100%; padding: 14px; background: linear-gradient(135deg, var(--primary-color), var(--secondary-color)); color: white; border: none; border-radius: 8px; cursor: pointer; font-size: 16px; font-weight: bold; transition: all 0.3s; }
36
+ #huggingface-vevo-api-container button:hover:not(:disabled) { transform: translateY(-2px); box-shadow: 0 4px 15px rgba(61, 90, 254, 0.3); }
37
+ #huggingface-vevo-api-container button:disabled { background: #a0aec0; cursor: not-allowed; }
38
+ #huggingface-vevo-api-container #status { margin-top: 20px; padding: 12px; background-color: #e2e8f0; border-radius: 8px; text-align: center; }
39
+ #huggingface-vevo-api-container #result { margin-top: 20px; text-align: center; }
40
+ #huggingface-vevo-api-container #result audio { width: 100%; margin-top: 10px; border-radius: 8px; }
41
+ #huggingface-vevo-api-container #result a { color: var(--primary-color); text-decoration: none; display: inline-block; margin-top: 15px; font-weight: bold; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
  </style>
43
  </head>
44
  <body>
45
 
46
+ <!-- HTML part remains the same -->
47
  <div id="delta-gate-container">
48
  <svg class="gate-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" color="#fff"><path d="M17 3.25H7C4.65279 3.25 2.75 5.15279 2.75 7.5V16.5C2.75 18.8472 4.65279 20.75 7 20.75H17C19.3472 20.75 21.25 18.8472 21.25 16.5V7.5C21.25 5.15279 19.3472 3.25 17 3.25ZM19.75 7.5V16.5C19.75 18.0376 18.5376 19.25 17 19.25H7C5.46243 19.25 4.25 18.0376 4.25 16.5V7.5C4.25 5.96243 5.46243 4.75 7 4.75H17C18.5376 4.75 19.75 5.96243 19.75 7.5ZM12 7.75C12.4142 7.75 12.75 8.08579 12.75 8.5V11H14.25C14.6642 11 15 11.3358 15 11.75V13.25C15 13.6642 14.6642 14 14.25 14H12.75V15.5C12.75 15.9142 12.4142 16.25 12 16.25C11.5858 16.25 11.25 15.9142 11.25 15.5V14H9.75C9.33579 14 9 13.6642 9 13.25V11.75C9 11.3358 9.33579 11 9.75 11H11.25V8.5C11.25 8.08579 11.5858 7.75 12 7.75Z"></path></svg>
49
  <h1>ورود به پنل اختصاصی</h1>
 
52
  <button id="verify-button">تأیید و ورود</button>
53
  <div id="error-message"></div>
54
  </div>
 
 
55
  <div id="main-content-container">
56
+ <!-- Main content will be loaded here -->
57
+ </div>
58
+
59
+ <script>
60
+ document.addEventListener('DOMContentLoaded', () => {
61
+ const gateContainer = document.getElementById('delta-gate-container');
62
+ const mainContentContainer = document.getElementById('main-content-container');
63
+ const verifyButton = document.getElementById('verify-button');
64
+ const codeInput = document.getElementById('delta-code-input');
65
+ const errorMessage = document.getElementById('error-message');
66
+ const buttonOriginalText = verifyButton.innerHTML;
67
+
68
+ // The main app's HTML content
69
+ const mainAppHTML = `
70
  <div id="huggingface-vevo-api-container">
71
  <div class="container">
72
  <h1>رابط کاربری API برای Vevo</h1>
73
  <div class="file-input">
74
  <label for="sourceAudio">فایل صوتی اصلی (Source Audio):</label>
75
+ <p class="description">این فایل صوتی حاوی کلامی است که می‌خواهید با صدای جدید خوانده شود.</p>
76
  <input type="file" id="sourceAudio" accept="audio/*" />
77
  </div>
78
  <div class="file-input">
79
  <label for="timbreRef">فایل صوتی مرجع (Timbre Reference):</label>
80
+ <p class="description">این فایل صوتی، صدای مدلی است که می‌خواهید به آن تبدیل شود.</p>
81
  <input type="file" id="timbreRef" accept="audio/*" />
82
  </div>
83
  <button id="generateBtn">تبدیل صدا</button>
 
85
  <div id="result"></div>
86
  </div>
87
  </div>
88
+ `;
 
 
 
 
 
 
 
 
 
 
 
89
 
90
  const showMainContent = () => {
91
  gateContainer.classList.add('hidden');
92
  setTimeout(() => {
93
  gateContainer.style.display = 'none';
94
  mainContentContainer.style.display = 'block';
95
+ mainContentContainer.innerHTML = mainAppHTML;
96
+ // Now, initialize the Vevo API script AFTER the content is on the page
97
+ initializeVevoAPI();
98
  }, 500);
99
  };
100
 
 
115
  verifyButton.innerHTML = '<div class="loader"></div>';
116
 
117
  try {
118
+ const response = await fetch(window.location.href, { // POST to the same page
 
119
  method: 'POST',
120
  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
121
  body: `delta_code=${encodeURIComponent(code)}`
122
  });
123
 
 
 
124
  if (!response.ok) {
125
+ throw new Error('خطای سرور');
126
+ }
127
+
128
+ const result = await response.json(); // Parse the JSON response from PHP
129
+
130
+ if (result.status === 'success') {
131
+ localStorage.setItem('isDeltaCodeValidated', 'true');
132
+ showMainContent();
133
+ } else {
134
+ // Show error message from server (e.g., "Failed to contact Telegram")
135
+ throw new Error(result.message || 'خطای ناشناخته از سمت سرور.');
136
  }
 
 
 
 
137
 
138
  } catch (error) {
139
+ errorMessage.textContent = error.message.includes('خطا') ? error.message : 'خطای شبکه. از اتصال خود مطمئن شوید.';
140
  verifyButton.disabled = false;
141
  verifyButton.innerHTML = buttonOriginalText;
142
  }
143
  });
144
 
145
+ // --- Vevo API Logic is now in its own function ---
146
+ function initializeVevoAPI() {
147
+ const container = document.getElementById('huggingface-vevo-api-container');
148
+ if (!container) return; // Exit if the container isn't ready
149
+
150
  const generateBtn = container.querySelector('#generateBtn');
151
  const sourceAudioInput = container.querySelector('#sourceAudio');
152
  const timbreRefInput = container.querySelector('#timbreRef');
 
155
 
156
  const API_URL = "https://amphion-vevo.hf.space/gradio_api/";
157
 
158
+ // ... (The rest of the Vevo API JavaScript is identical, no changes needed)
159
  const generateSessionHash = () => Math.random().toString(36).substring(2, 15);
 
160
  async function uploadFile(file) {
161
  const formData = new FormData();
162
  formData.append("files", file);
 
165
  if (result && result.length > 0) return result[0];
166
  throw new Error("آپلود فایل با خطا مواجه شد.");
167
  }
 
168
  async function startGeneration() {
169
  const sourceFile = sourceAudioInput.files[0];
170
  const timbreFile = timbreRefInput.files[0];
171
+ if (!sourceFile || !timbreFile) { alert("لطفاً هر دو فایل صوتی را انتخاب کنید."); return; }
 
 
 
 
 
172
  generateBtn.disabled = true;
173
  statusDiv.textContent = 'در حال آپلود فایل اصلی...';
174
  resultDiv.innerHTML = '';
 
175
  const sessionHash = generateSessionHash();
 
176
  try {
177
  const sourcePath = await uploadFile(sourceFile);
178
  statusDiv.textContent = 'در حال آپلود فایل مرجع...';
179
  const timbrePath = await uploadFile(timbreFile);
 
180
  statusDiv.textContent = 'ارسال درخواست برای پردازش...';
181
+ const joinPayload = { "data": [ { "path": sourcePath, "url": `${API_URL}file=${sourcePath}`, "orig_name": sourceFile.name, "meta": { "_type": "gradio.FileData" } }, { "path": timbrePath, "url": `${API_URL}file=${timbrePath}`, "orig_name": timbreFile.name, "meta": { "_type": "gradio.FileData" } } ], "fn_index": 0, "session_hash": sessionHash };
182
+ await fetch(`${API_URL}queue/join?`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(joinPayload) });
 
 
 
 
 
 
 
 
 
 
 
 
 
183
  statusDiv.textContent = 'در صف پردازش. منتظر نتیجه بمانید...';
184
  const eventSource = new EventSource(`${API_URL}queue/data?session_hash=${sessionHash}`);
 
185
  eventSource.onmessage = (event) => {
186
  const data = JSON.parse(event.data);
187
+ if (data.msg === 'process_starts') { statusDiv.textContent = 'پردازش شروع شد...'; }
188
+ else if (data.msg === 'process_completed') {
 
 
189
  statusDiv.textContent = 'پردازش با موفقیت انجام شد!';
190
  const resultPath = data.output.data[0].path;
191
  const resultUrl = `${API_URL}file=${resultPath}`;
 
192
  resultDiv.innerHTML = `<h3>نتیجه:</h3><audio controls src="${resultUrl}"></audio><br><a href="${resultUrl}" download="output_voice.wav">دانلود فایل</a>`;
193
  eventSource.close();
194
  generateBtn.disabled = false;
 
198
  generateBtn.disabled = false;
199
  }
200
  };
 
201
  eventSource.onerror = () => {
202
  statusDiv.textContent = 'خطا در ارتباط با سرور.';
203
  eventSource.close();
204
  generateBtn.disabled = false;
205
  };
 
206
  } catch (error) {
207
  statusDiv.textContent = `خطا: ${error.message}`;
208
  generateBtn.disabled = false;
209
  }
210
  }
 
211
  generateBtn.addEventListener('click', startGeneration);
212
  }
213
  });