Hamed744 commited on
Commit
4b5c167
·
verified ·
1 Parent(s): f6d3a83

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +270 -70
index.html CHANGED
@@ -3,47 +3,215 @@
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 are identical to the previous version. No changes needed here. */
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 is identical -->
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,30 +220,20 @@
52
  <button id="verify-button">تأیید و ورود</button>
53
  <div id="error-message"></div>
54
  </div>
55
- <div id="main-content-container"></div>
56
-
57
- <script>
58
- // JavaScript part is identical to the previous version. No changes needed.
59
- document.addEventListener('DOMContentLoaded', () => {
60
- const gateContainer = document.getElementById('delta-gate-container');
61
- const mainContentContainer = document.getElementById('main-content-container');
62
- const verifyButton = document.getElementById('verify-button');
63
- const codeInput = document.getElementById('delta-code-input');
64
- const errorMessage = document.getElementById('error-message');
65
- const buttonOriginalText = verifyButton.innerHTML;
66
 
67
- const mainAppHTML = `
 
68
  <div id="huggingface-vevo-api-container">
69
  <div class="container">
70
  <h1>رابط کاربری API برای Vevo</h1>
71
  <div class="file-input">
72
  <label for="sourceAudio">فایل صوتی اصلی (Source Audio):</label>
73
- <p class="description">این فایل صوتی حاوی کلامی است که می‌خواهید با صدای جدید خوانده شود.</p>
74
  <input type="file" id="sourceAudio" accept="audio/*" />
75
  </div>
76
  <div class="file-input">
77
  <label for="timbreRef">فایل صوتی مرجع (Timbre Reference):</label>
78
- <p class="description">این فایل صوتی، صدای مدلی است که می‌خواهید به آن تبدیل شود.</p>
79
  <input type="file" id="timbreRef" accept="audio/*" />
80
  </div>
81
  <button id="generateBtn">تبدیل صدا</button>
@@ -83,15 +241,24 @@
83
  <div id="result"></div>
84
  </div>
85
  </div>
86
- `;
 
 
 
 
 
 
 
 
 
 
 
87
 
88
  const showMainContent = () => {
89
  gateContainer.classList.add('hidden');
90
  setTimeout(() => {
91
  gateContainer.style.display = 'none';
92
  mainContentContainer.style.display = 'block';
93
- mainContentContainer.innerHTML = mainAppHTML;
94
- initializeVevoAPI();
95
  }, 500);
96
  };
97
 
@@ -102,51 +269,55 @@
102
  verifyButton.addEventListener('click', async () => {
103
  const code = codeInput.value.trim();
104
  errorMessage.textContent = '';
 
105
  if (code.length < 38 || code.length > 44) {
106
  errorMessage.textContent = 'کد دلتا نامعتبر است. طول کد باید بین ۳۸ تا ۴۴ کاراکتر باشد.';
107
  return;
108
  }
 
109
  verifyButton.disabled = true;
110
  verifyButton.innerHTML = '<div class="loader"></div>';
111
 
112
  try {
113
- const response = await fetch(window.location.href, {
 
 
114
  method: 'POST',
115
  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
116
  body: `delta_code=${encodeURIComponent(code)}`
117
  });
118
 
119
- if (!response.ok) {
120
- // This will be triggered for server errors like 500
121
- throw new Error('خطای سرور');
122
- }
123
-
124
- const result = await response.json();
125
 
126
- if (result.status === 'success') {
127
  localStorage.setItem('isDeltaCodeValidated', 'true');
128
  showMainContent();
129
  } else {
130
- throw new Error(result.message || 'خطای ناشناخته از سمت سرور.');
 
 
131
  }
132
 
133
  } catch (error) {
134
- errorMessage.textContent = error.message.includes('خطا') ? error.message : 'خطای شبکه. از اتصال خود مطمئن شوید.';
135
  verifyButton.disabled = false;
136
  verifyButton.innerHTML = buttonOriginalText;
137
  }
138
  });
139
 
140
- function initializeVevoAPI() {
141
- const container = document.getElementById('huggingface-vevo-api-container');
142
- if (!container) return;
143
  const generateBtn = container.querySelector('#generateBtn');
144
  const sourceAudioInput = container.querySelector('#sourceAudio');
145
  const timbreRefInput = container.querySelector('#timbreRef');
146
  const statusDiv = container.querySelector('#status');
147
  const resultDiv = container.querySelector('#result');
 
148
  const API_URL = "https://amphion-vevo.hf.space/gradio_api/";
 
149
  const generateSessionHash = () => Math.random().toString(36).substring(2, 15);
 
150
  async function uploadFile(file) {
151
  const formData = new FormData();
152
  formData.append("files", file);
@@ -155,30 +326,56 @@
155
  if (result && result.length > 0) return result[0];
156
  throw new Error("آپلود فایل با خطا مواجه شد.");
157
  }
 
158
  async function startGeneration() {
159
  const sourceFile = sourceAudioInput.files[0];
160
  const timbreFile = timbreRefInput.files[0];
161
- if (!sourceFile || !timbreFile) { alert("لطفاً هر دو فایل صوتی را انتخاب کنید."); return; }
 
 
 
 
 
162
  generateBtn.disabled = true;
163
  statusDiv.textContent = 'در حال آپلود فایل اصلی...';
164
  resultDiv.innerHTML = '';
 
165
  const sessionHash = generateSessionHash();
 
166
  try {
167
  const sourcePath = await uploadFile(sourceFile);
168
  statusDiv.textContent = 'در حال آپلود فایل مرجع...';
169
  const timbrePath = await uploadFile(timbreFile);
 
170
  statusDiv.textContent = 'ارسال درخواست برای پردازش...';
171
- 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 };
172
- await fetch(`${API_URL}queue/join?`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(joinPayload) });
 
 
 
 
 
 
 
 
 
 
 
 
 
173
  statusDiv.textContent = 'در صف پردازش. منتظر نتیجه بمانید...';
174
  const eventSource = new EventSource(`${API_URL}queue/data?session_hash=${sessionHash}`);
 
175
  eventSource.onmessage = (event) => {
176
  const data = JSON.parse(event.data);
177
- if (data.msg === 'process_starts') { statusDiv.textContent = 'پردازش شروع شد...'; }
178
- else if (data.msg === 'process_completed') {
 
 
179
  statusDiv.textContent = 'پردازش با موفقیت انجام شد!';
180
  const resultPath = data.output.data[0].path;
181
  const resultUrl = `${API_URL}file=${resultPath}`;
 
182
  resultDiv.innerHTML = `<h3>نتیجه:</h3><audio controls src="${resultUrl}"></audio><br><a href="${resultUrl}" download="output_voice.wav">دانلود فایل</a>`;
183
  eventSource.close();
184
  generateBtn.disabled = false;
@@ -188,16 +385,19 @@
188
  generateBtn.disabled = false;
189
  }
190
  };
 
191
  eventSource.onerror = () => {
192
  statusDiv.textContent = 'خطا در ارتباط با سرور.';
193
  eventSource.close();
194
  generateBtn.disabled = false;
195
  };
 
196
  } catch (error) {
197
  statusDiv.textContent = `خطا: ${error.message}`;
198
  generateBtn.disabled = false;
199
  }
200
  }
 
201
  generateBtn.addEventListener('click', startGeneration);
202
  }
203
  });
 
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
  <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
  <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
 
 
269
  verifyButton.addEventListener('click', async () => {
270
  const code = codeInput.value.trim();
271
  errorMessage.textContent = '';
272
+
273
  if (code.length < 38 || code.length > 44) {
274
  errorMessage.textContent = 'کد دلتا نامعتبر است. طول کد باید بین ۳۸ تا ۴۴ کاراکتر باشد.';
275
  return;
276
  }
277
+
278
  verifyButton.disabled = true;
279
  verifyButton.innerHTML = '<div class="loader"></div>';
280
 
281
  try {
282
+ // ** مهم: آدرس PHP API را اینجا وارد کنید **
283
+ // فرض می‌کنیم send_code_api.php در همان مسیر gemin.php است.
284
+ const response = await fetch('https://www.aisada.ir/app/send_code_api.php', {
285
  method: 'POST',
286
  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
287
  body: `delta_code=${encodeURIComponent(code)}`
288
  });
289
 
290
+ const result = await response.json(); // سعی کنید پاسخ JSON را بخوانید
 
 
 
 
 
291
 
292
+ if (response.ok && result.status === 'success') {
293
  localStorage.setItem('isDeltaCodeValidated', 'true');
294
  showMainContent();
295
  } else {
296
+ errorMessage.textContent = result.message || 'خطا در تأیید کد. لطفاً دوباره تلاش کنید.';
297
+ verifyButton.disabled = false;
298
+ verifyButton.innerHTML = buttonOriginalText;
299
  }
300
 
301
  } catch (error) {
302
+ errorMessage.textContent = 'خطای شبکه. از اتصال اینترنت خود مطمئن شوید یا بعداً تلاش کنید.';
303
  verifyButton.disabled = false;
304
  verifyButton.innerHTML = buttonOriginalText;
305
  }
306
  });
307
 
308
+ // --- Section 2: Your Vevo API Logic ---
309
+ const container = document.getElementById('huggingface-vevo-api-container');
310
+ if (container) {
311
  const generateBtn = container.querySelector('#generateBtn');
312
  const sourceAudioInput = container.querySelector('#sourceAudio');
313
  const timbreRefInput = container.querySelector('#timbreRef');
314
  const statusDiv = container.querySelector('#status');
315
  const resultDiv = container.querySelector('#result');
316
+
317
  const API_URL = "https://amphion-vevo.hf.space/gradio_api/";
318
+
319
  const generateSessionHash = () => Math.random().toString(36).substring(2, 15);
320
+
321
  async function uploadFile(file) {
322
  const formData = new FormData();
323
  formData.append("files", file);
 
326
  if (result && result.length > 0) return result[0];
327
  throw new Error("آپلود فایل با خطا مواجه شد.");
328
  }
329
+
330
  async function startGeneration() {
331
  const sourceFile = sourceAudioInput.files[0];
332
  const timbreFile = timbreRefInput.files[0];
333
+
334
+ if (!sourceFile || !timbreFile) {
335
+ alert("لطفاً هر دو فایل صوتی را انتخاب کنید.");
336
+ return;
337
+ }
338
+
339
  generateBtn.disabled = true;
340
  statusDiv.textContent = 'در حال آپلود فایل اصلی...';
341
  resultDiv.innerHTML = '';
342
+
343
  const sessionHash = generateSessionHash();
344
+
345
  try {
346
  const sourcePath = await uploadFile(sourceFile);
347
  statusDiv.textContent = 'در حال آپلود فایل مرجع...';
348
  const timbrePath = await uploadFile(timbreFile);
349
+
350
  statusDiv.textContent = 'ارسال درخواست برای پردازش...';
351
+
352
+ const joinPayload = {
353
+ "data": [
354
+ { "path": sourcePath, "url": `${API_URL}file=${sourcePath}`, "orig_name": sourceFile.name, "meta": { "_type": "gradio.FileData" } },
355
+ { "path": timbrePath, "url": `${API_URL}file=${timbrePath}`, "orig_name": timbreFile.name, "meta": { "_type": "gradio.FileData" } }
356
+ ],
357
+ "fn_index": 0, "session_hash": sessionHash
358
+ };
359
+
360
+ await fetch(`${API_URL}queue/join?`, {
361
+ method: 'POST',
362
+ headers: { 'Content-Type': 'application/json' },
363
+ body: JSON.stringify(joinPayload)
364
+ });
365
+
366
  statusDiv.textContent = 'در صف پردازش. منتظر نتیجه بمانید...';
367
  const eventSource = new EventSource(`${API_URL}queue/data?session_hash=${sessionHash}`);
368
+
369
  eventSource.onmessage = (event) => {
370
  const data = JSON.parse(event.data);
371
+
372
+ if (data.msg === 'process_starts') {
373
+ statusDiv.textContent = 'پردازش شروع شد...';
374
+ } else if (data.msg === 'process_completed') {
375
  statusDiv.textContent = 'پردازش با موفقیت انجام شد!';
376
  const resultPath = data.output.data[0].path;
377
  const resultUrl = `${API_URL}file=${resultPath}`;
378
+
379
  resultDiv.innerHTML = `<h3>نتیجه:</h3><audio controls src="${resultUrl}"></audio><br><a href="${resultUrl}" download="output_voice.wav">دانلود فایل</a>`;
380
  eventSource.close();
381
  generateBtn.disabled = false;
 
385
  generateBtn.disabled = false;
386
  }
387
  };
388
+
389
  eventSource.onerror = () => {
390
  statusDiv.textContent = 'خطا در ارتباط با سرور.';
391
  eventSource.close();
392
  generateBtn.disabled = false;
393
  };
394
+
395
  } catch (error) {
396
  statusDiv.textContent = `خطا: ${error.message}`;
397
  generateBtn.disabled = false;
398
  }
399
  }
400
+
401
  generateBtn.addEventListener('click', startGeneration);
402
  }
403
  });