Opera8 commited on
Commit
0c270ba
·
verified ·
1 Parent(s): 052c219

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +603 -276
index.html CHANGED
@@ -2,398 +2,725 @@
2
  <html lang="fa" dir="rtl">
3
  <head>
4
  <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
6
- <title>استودیو هوشمند آلفا</title>
7
- <link href="https://fonts.googleapis.com/css2?family=Vazirmatn:wght@300;400;500;700;800&display=swap" rel="stylesheet">
 
 
 
 
 
 
 
 
 
8
  <style>
9
  :root {
10
- --bg-color: #F8F9FC;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  --card-bg: #FFFFFF;
12
- --primary: #4A6CFA;
13
- --primary-dark: #3754db;
14
- --text-main: #1A202C;
15
- --text-muted: #718096;
16
- --border: #E2E8F0;
17
- --input-bg: #F7FAFC;
18
- --success: #38A169;
19
  --radius: 16px;
20
- --shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
21
  }
22
 
23
- * { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
24
 
25
  body {
26
- font-family: 'Vazirmatn', sans-serif;
27
  background-color: var(--bg-color);
28
- color: var(--text-main);
29
  margin: 0;
30
- padding: 20px 15px;
31
- display: flex;
32
- flex-direction: column;
33
- align-items: center;
34
  min-height: 100vh;
 
 
 
35
  }
36
 
37
- .container {
38
- width: 100%;
39
- max-width: 600px;
40
- position: relative;
41
- z-index: 10;
42
- }
43
 
44
- /* هدر */
45
- header {
46
- text-align: center;
47
- margin-bottom: 30px;
48
- animation: fadeIn 0.8s ease;
 
 
49
  }
50
-
51
- .logo-container {
52
- width: 70px; height: 70px;
53
- background: #fff;
54
- border-radius: 20px;
55
- margin: 0 auto 15px;
56
- display: flex; align-items: center; justify-content: center;
57
- box-shadow: 0 10px 20px rgba(74, 108, 250, 0.15);
58
- color: var(--primary);
59
- }
60
-
61
- h1 {
62
- font-size: 1.8rem; font-weight: 800; margin: 0;
63
- color: #2D3748; letter-spacing: -0.5px;
64
- }
65
- .subtitle {
66
- font-size: 0.95rem; color: var(--text-muted); margin-top: 5px;
67
- }
68
 
69
- /* کارت اصلی */
 
 
70
  .card {
71
  background: var(--card-bg);
72
- border-radius: var(--radius);
73
- box-shadow: var(--shadow);
74
- border: 1px solid var(--border);
 
75
  padding: 25px;
76
- transition: all 0.3s ease;
77
- }
78
-
79
- .label {
80
- font-weight: 700; margin-bottom: 10px; display: block;
81
- color: #4A5568; font-size: 0.95rem; display: flex; align-items: center; gap: 8px;
82
  }
83
- .label svg { color: var(--primary); }
84
 
85
- textarea {
86
- width: 100%;
87
- background: var(--input-bg);
 
88
  border: 2px solid var(--border);
89
- border-radius: 12px;
90
- padding: 15px;
91
- font-family: inherit; font-size: 1rem;
92
- min-height: 100px; resize: vertical; outline: none;
93
- transition: border-color 0.2s;
94
- color: #2D3748;
 
 
 
 
 
 
 
 
 
 
 
95
  }
96
- textarea:focus { border-color: var(--primary); background: #fff; }
97
-
98
- /* بخش تنظیمات (زیر متن) */
99
- .settings-grid {
100
- display: grid;
101
- grid-template-columns: 1fr 1fr;
102
- gap: 15px;
103
- margin-top: 20px;
104
- padding-top: 20px;
105
- border-top: 1px dashed var(--border);
106
  }
 
 
 
107
 
108
- .setting-item label {
109
- font-size: 0.8rem; color: var(--text-muted); margin-bottom: 5px; display: block;
 
 
 
 
 
 
 
 
 
 
 
 
110
  }
111
 
112
- .setting-input {
113
- width: 100%;
114
- background: var(--input-bg);
115
- border: 1px solid var(--border);
116
- border-radius: 10px;
117
- padding: 10px;
118
- font-family: inherit;
119
- font-size: 0.9rem;
120
- outline: none;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
121
  }
122
- .setting-input:focus { border-color: var(--primary); }
123
-
124
- /* دکمه اصلی */
125
- .btn-primary {
126
- width: 100%;
127
- padding: 16px;
128
- background: linear-gradient(135deg, var(--primary), var(--primary-dark));
129
- color: #fff;
130
- border: none;
131
- border-radius: 14px;
132
- font-size: 1.1rem;
133
- font-weight: 700;
134
- cursor: pointer;
135
- margin-top: 25px;
136
- box-shadow: 0 4px 12px rgba(74, 108, 250, 0.3);
137
- transition: transform 0.2s;
138
- display: flex; align-items: center; justify-content: center; gap: 10px;
139
  }
140
- .btn-primary:active { transform: scale(0.98); }
141
- .btn-primary:disabled { opacity: 0.7; cursor: wait; filter: grayscale(1); }
142
 
143
- /* بخش نتیجه */
144
- #resultSection { display: none; margin-top: 25px; animation: slideUp 0.6s ease; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
145
 
146
- .result-header {
147
- display: flex; justify-content: space-between; align-items: center;
148
- margin-bottom: 15px; padding-bottom: 15px; border-bottom: 1px solid var(--border);
 
149
  }
150
 
151
- .lyrics-box {
152
- background: #F7FAFC;
153
- border-radius: 12px;
154
- padding: 20px;
155
- max-height: 400px;
156
- overflow-y: auto;
157
- white-space: pre-wrap;
158
- line-height: 2.2;
159
- font-size: 1rem;
160
- color: #4A5568;
161
  text-align: center;
162
- border: 1px solid var(--border);
163
- margin-top: 20px;
164
  }
165
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
166
  .lyrics-tag {
167
- color: var(--primary);
168
- font-weight: 800;
169
- display: block;
170
- margin-top: 15px;
171
- font-size: 0.9em;
172
  }
173
 
174
- /* لودر */
175
- #loader { display: none; text-align: center; margin-top: 20px; }
176
- .spinner {
177
- width: 40px; height: 40px; border: 4px solid rgba(74, 108, 250, 0.1);
178
- border-left-color: var(--primary); border-radius: 50%;
179
- margin: 0 auto 10px; animation: spin 1s linear infinite;
180
  }
181
- @keyframes spin { 100% { transform: rotate(360deg); } }
182
- @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
183
- @keyframes slideUp { from { transform: translateY(20px); opacity: 0; } to { transform: translateY(0); opacity: 1; } }
184
 
185
- /* پلیر */
186
- audio { width: 100%; border-radius: 30px; height: 45px; }
 
 
 
 
 
 
187
  </style>
188
  </head>
189
  <body>
190
  <div class="container">
191
- <header>
192
- <div class="logo-container">
193
- <svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2a10 10 0 1 0 10 10 4 4 0 0 1-5-5 4 4 0 0 1-5-5"></path><path d="M8.5 8.5v.01"></path><path d="M16 16v.01"></path><path d="M12 12v.01"></path></svg>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
194
  </div>
195
- <h1>استودیو هوشمند آلفا</h1>
196
- <p class="subtitle">ایده بده، آهنگ کامل تحویل بگیر</p>
197
- </header>
198
-
199
- <div class="card" id="inputCard">
200
- <label class="label">
201
- <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 19l7-7 3 3-7 7-3-3z"></path><path d="M18 13l-1.5-7.5L2 2l3.5 14.5L13 18l5-5z"></path><path d="M2 2l7.586 7.586"></path><circle cx="11" cy="11" r="2"></circle></svg>
202
- موضوع آهنگ چیه؟
203
- </label>
204
- <textarea id="ideaInput" placeholder="مثال: یه آهنگ رپ اجتماعی سنگین یا یه موزیک پاپ شاد برای تولد..."></textarea>
205
-
206
- <!-- تنظیمات -->
207
- <div class="settings-grid">
208
- <div class="setting-item">
209
- <label>مدل هوش مصنوعی</label>
210
- <select id="modelSelect" class="setting-input">
211
- <option value="acestep-v15-turbo">Alpha Turbo (سریع)</option>
212
- <option value="acestep-v15-turbo-shift3">Alpha Pro (کیفیت بالا)</option>
213
- </select>
214
- </div>
215
- <div class="setting-item">
216
- <label>زمان انیه)</label>
217
- <input type="number" id="duration" value="30" class="setting-input">
218
- </div>
219
- <div class="setting-item">
220
- <label>تعداد گام (Steps)</label>
221
- <input type="number" id="steps" value="8" class="setting-input">
222
- </div>
223
- <div class="setting-item">
224
- <label>تعداد خروجی</label>
225
- <select id="batchSize" class="setting-input">
226
- <option value="1">۱ آهنگ</option>
227
- <option value="2" آهنگ</option>
228
- </select>
 
 
 
 
 
 
 
229
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
230
  </div>
231
-
232
- <button id="generateBtn" class="btn-primary">
233
- <span>ساخت آهنگ</span>
234
- <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M5 12h14"></path><path d="M12 5l7 7-7 7"></path></svg>
235
  </button>
236
  </div>
237
 
238
- <div id="loader">
239
- <div class="spinner"></div>
240
- <p id="loaderText" style="color:var(--text-muted); font-size:0.9rem;">در حال پردازش...</p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
241
  </div>
242
 
243
- <div id="resultSection" class="card">
244
- <div class="result-header">
245
- <div style="font-weight:700; color:#2D3748;">🎵 پخش آهنگ</div>
246
- <a id="downloadLink" href="#" style="color:var(--primary); text-decoration:none; font-size:0.9rem; font-weight:600;">دانلود فایل</a>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
247
  </div>
248
-
249
- <div id="playerContainer"></div>
 
 
 
 
 
 
 
 
 
 
 
250
 
251
- <div class="label" style="justify-content:center; margin-top:20px; color:var(--text-muted);">متن آهنگ</div>
252
- <div id="lyricsDisplay" class="lyrics-box"></div>
 
 
 
 
 
 
 
253
 
254
- <button onclick="window.location.reload()" class="btn-primary" style="background:transparent; border:2px solid var(--border); color:var(--text-muted); margin-top:15px; box-shadow:none;">
 
 
 
255
  ساخت یک آهنگ دیگر
256
  </button>
257
  </div>
 
 
258
  </div>
259
 
260
  <script>
261
- const ACE_SPACE_URL = "https://ace-step-ace-step-v1-5.hf.space/";
 
 
 
262
 
 
 
 
 
 
263
  const generateBtn = document.getElementById('generateBtn');
264
- const ideaInput = document.getElementById('ideaInput');
265
- const loader = document.getElementById('loader');
 
 
 
 
266
  const loaderText = document.getElementById('loaderText');
267
- const resultSection = document.getElementById('resultSection');
268
- const inputCard = document.getElementById('inputCard');
269
- const lyricsDisplay = document.getElementById('lyricsDisplay');
270
- const playerContainer = document.getElementById('playerContainer');
271
- const downloadLink = document.getElementById('downloadLink');
272
-
273
- // Settings Inputs
274
- const modelSelect = document.getElementById('modelSelect');
275
- const durationInput = document.getElementById('duration');
 
 
 
 
276
  const stepsInput = document.getElementById('steps');
277
- const batchSizeInput = document.getElementById('batchSize');
 
 
 
278
 
279
  generateBtn.addEventListener('click', async () => {
280
- const idea = ideaInput.value.trim();
281
- if (!idea) { alert("لطفا موضوع آهنگ را بنویسید."); return; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
282
 
283
- // UI Loading State
284
- generateBtn.disabled = true;
285
- inputCard.style.opacity = "0.7";
286
- inputCard.style.pointerEvents = "none";
287
- loader.style.display = "block";
288
-
289
  try {
290
- // Step 1: Generate Lyrics & Prompt (Gemini)
291
- loaderText.innerText = "آلفا در حال نوشتن متن آهنگ...";
292
-
293
- const refineResponse = await fetch('/api/refine', {
294
- method: 'POST',
 
 
 
 
295
  headers: {'Content-Type': 'application/json'},
296
- body: JSON.stringify({ idea: idea })
 
 
 
297
  });
298
-
299
- const data = await refineResponse.json();
300
- if (data.error) throw new Error(data.error);
301
 
302
- const generatedLyrics = data.lyrics;
303
- const generatedPrompt = data.music_prompt;
 
 
304
 
305
- // Step 2: Generate Audio (ACE-Step)
306
- loaderText.innerText = "آلفا در حال آهنگسازی و خوانندگی...";
 
 
 
 
307
 
308
- // Prepare ACE-Step Payload
 
 
309
  const payload = [
310
  modelSelect.value, // Model
311
- "custom", null, "unknown",
312
- generatedPrompt, // Music Prompt
313
- generatedLyrics, // Lyrics
 
 
 
 
314
  0, "", "", "unknown",
315
- parseInt(stepsInput.value), // Steps
316
- 7, true, -1, null, -1,
317
- parseInt(batchSizeInput.value), // Batch Size
318
- null, null, 0, -1,
 
 
 
 
 
 
319
  "Fill the audio semantic mask based on the given conditions:",
320
  1, "text2music", false, 0, 1, 3, "ode", "", "mp3", 0.85,
321
- true, 2, 0, 0.9, "NO USER INPUT", true, true, true, null, false, true, false, false, 0.5, 8, null, [], false, null, null, null, null
 
 
 
 
 
 
322
  ];
323
 
324
  const session_hash = Math.random().toString(36).substring(2);
325
 
326
- const joinResp = await fetch(`${ACE_SPACE_URL}gradio_api/queue/join`, {
 
 
 
 
 
327
  method: 'POST',
328
  headers: { 'Content-Type': 'application/json' },
329
  body: JSON.stringify({ data: payload, fn_index: 77, session_hash })
330
  });
331
 
332
- if (!joinResp.ok) throw new Error('خطا در اتصال به سرور آهنگسازی');
 
 
 
 
 
 
333
 
334
- const eventSource = new EventSource(`${ACE_SPACE_URL}gradio_api/queue/data?session_hash=${session_hash}`);
 
 
 
 
335
 
336
  eventSource.onmessage = (event) => {
337
- const msg = JSON.parse(event.data);
 
 
338
 
339
  if (msg.msg === 'process_starts') {
340
- loaderText.innerText = "در حال ضبط نهایی...";
341
- } else if (msg.msg === 'process_completed') {
 
 
 
 
 
 
 
342
  eventSource.close();
343
- loader.style.display = "none";
344
-
345
- // Show Result
346
- displayResult(msg.output, generatedLyrics);
347
  }
348
  };
349
 
350
  eventSource.onerror = () => {
351
- throw new Error('قطع ارتباط با سرور.');
 
 
352
  };
353
 
354
  } catch (error) {
355
- alert("خطا: " + error.message);
356
- loader.style.display = "none";
357
- generateBtn.disabled = false;
358
- inputCard.style.opacity = "1";
359
- inputCard.style.pointerEvents = "auto";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
360
  }
361
  });
362
 
363
- function displayResult(outputData, lyrics) {
 
 
 
364
  let audioUrl = null;
365
-
366
- // Find mp3 url
367
  function traverse(obj) {
368
- if (typeof obj === 'string' && obj.includes('/file=') && obj.endsWith('.mp3')) {
 
 
 
 
 
369
  audioUrl = obj;
370
  } else if (obj && typeof obj === 'object') {
371
- if (obj.url && obj.url.endsWith('.mp3')) audioUrl = obj.url;
 
 
372
  Object.values(obj).forEach(traverse);
373
  }
374
  }
375
- traverse(outputData);
376
 
377
- if (audioUrl) {
378
- const fullUrl = audioUrl.startsWith('http') ? audioUrl : ACE_SPACE_URL.replace(/\/$/, '') + audioUrl;
379
-
380
- // Set Player
381
- playerContainer.innerHTML = `<audio controls autoplay src="${fullUrl}"></audio>`;
382
- downloadLink.href = fullUrl;
383
 
384
  // Format Lyrics
385
- const formattedLyrics = lyrics.replace(/\[(.*?)\]/g, '<span class="lyrics-tag">[$1]</span>');
386
- lyricsDisplay.innerHTML = formattedLyrics;
387
-
388
- // Show Section
389
- inputCard.style.display = "none";
390
- resultSection.style.display = "block";
391
  } else {
392
- alert("فایل صوتی یافت نشد. لطفا دوباره تلاش کنید.");
393
- generateBtn.disabled = false;
394
- inputCard.style.opacity = "1";
395
- inputCard.style.pointerEvents = "auto";
396
- }
397
  }
398
  </script>
399
  </body>
 
2
  <html lang="fa" dir="rtl">
3
  <head>
4
  <meta charset="UTF-8">
5
+ <meta name="viewportست این کد را جایگزین `index.html` قبلی کنید.
6
+
7
+ ```html
8
+ <!DOCTYPE html> " content="width=device-width, initial-scale=1.0, maximum-scale=1.0
9
+ <html lang="fa" dir="rtl">
10
+ <head>
11
+ <meta charset="UTF-8">
12
+ <meta name="viewport" content="width=device-width, initial-scale=, user-scalable=no">
13
+ <title>استودیو موزیک آلفا</title>
14
+ <link href="https://fonts.googleapis.com/css2?family=Vazirmatn1.0">
15
+ <title>استودیو آلفا</title>
16
+ <link:wght@300;400;500;700;800&display href="https://fonts.googleapis.com/css2?family=Vazirmatn:wght@400;500;600;700;800&display=swap" rel="stylesheet">
17
  <style>
18
  :root {
19
+ --app-font: 'Vazirmatn', sans-serif;
20
+ --app-bg: #F8F9FC;
21
+ --panel-bg: #FFFFFF;
22
+ --panel-border: #EAEFF7;
23
+ --input-bg: #F6F8FB;
24
+ --input-border: #=swap" rel="stylesheet">
25
+ <style>
26
+ :root {
27
+ --appE1E7EF;
28
+ --text-primary: #1A202C;
29
+ --text-secondary: #626F86;
30
+ --accent-primary: #4A6CFA;
31
+ --accent-glow: rgba(74, 108, 250, 0.25);
32
+ --accent-secondary: #0FD4A8;
33
+ --radius-card: 24px;
34
+ --radius-btn: 14px;
35
+ --radius-input: 12px;
36
+ --transition-smooth: all 0.35s cubic-bezier(0.4, 0, 0.2, 1);
37
+ }
38
+
39
+ @keyframes fadeIn { from { opacity: 0; transform: translateY(15px); } to { opacity: 1; transform: translateY(0); } }
40
+ @keyframes fill-progress { from { width: 0%; } to { width: 100%; } }
41
+ @keyframes pulse-loader { 0% { box-shadow: 0 0 40px rgba(56, 189, 248, 0.3); } 50%-font: 'Vazirmatn', sans-serif;
42
+ --bg-color: #F3F4F6;
43
  --card-bg: #FFFFFF;
44
+ --primary: #3B82F6;
45
+ --primary-dark: #2563EB;
46
+ --accent: #8B5CF6;
47
+ --text-dark: #1F2937;
48
+ --text-gray: #6B7280;
49
+ --border: #E5E7EB;
 
50
  --radius: 16px;
 
51
  }
52
 
53
+ * { box-sizing: border-box; -webkit-tap-highlight-color: transparent; outline: none; } { box-shadow: 0 0 60px rgba(56, 189,
54
 
55
  body {
56
+ font-family: var(--app-font);
57
  background-color: var(--bg-color);
58
+ color: var(--text-dark);
59
  margin: 0;
60
+ padding: 20px;
 
 
 
61
  min-height: 100vh;
62
+ display: flex;
63
+ justify-content: center;
64
+ align-items: flex-start;
65
  }
66
 
67
+ .container { max-width: 600px; width: 100%; position: relative; z-index: 2; }
 
 
 
 
 
68
 
69
+ /* Header */
70
+ header { text-align: center; margin-bottom: 2rem; }
71
+ .logo {
72
+ font-size: 2.5rem; font-weight: 900;
73
+ background: linear-gradient(135deg, var(--primary), var(--accent));
74
+ -webkit-background-clip: text; -webkit-text-fill-color: transparent;
75
+ letter-spacing: -1px; margin-bottom: 5px; display248, 0.7); } 100% { box-shadow: 0 0: inline-block;
76
  }
77
+ .tagline { color: var(--text-gray); font- 40px rgba(56, 189, 248, 0.3);size: 0.9rem; font-weight: 500; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
 
79
+ /* Main Card */ } }
80
+
81
+ body { font-family: var(--app-font); background-color: var
82
  .card {
83
  background: var(--card-bg);
84
+ border-radius: var(--app-bg); color: var(--text-primary); margin: 0; padding: 2.5(--radius);
85
+ box-shadow: 0 10px 25px -5px rgbarem 1rem; display: flex; justify-content: center; align-items: flex-start; min(0, 0, 0, 0.05);
86
+ border: 1px solid-height: 100vh; }
87
+ .container { max-width: 820 var(--border);
88
  padding: 25px;
89
+ transition: all 0.3s ease;px; width: 100%; }
90
+ header { position: relative; text-align: center
 
 
 
 
91
  }
 
92
 
93
+ .input-area { position: relative; margin-bottom: 15px; }
94
+
95
+ ; margin-bottom: 2.5rem; padding: 2rem 0; animation: fadeIn 0 textarea {
96
+ width: 100%; background: #F9FAFB;
97
  border: 2px solid var(--border);
98
+ border-radius: 12px; padding: 15px;
99
+ font-family: inherit; font-size: 1rem; color: var(--.8s 0.1s ease-out backwards; overflow: hidden; }
100
+ #neural-canvas { position: absolute; top: 0; left: 0; width: 100%; height:text-dark);
101
+ min-height: 120px; resize: none; transition: 0.3s 100%; z-index: 1; opacity: 0.6; }
102
+ .header-content { position: relative; z-index: 2; }
103
+
104
+ .logo-container;
105
+ }
106
+ textarea:focus { border-color: var(--primary); background: #fff; box { width: 80px; height: 80px; margin: 0 auto 1.5-shadow: 0 0 0 4px rgba(59, 130, 246,rem; display: flex; align-items: center; justify-content: center; background: radial-gradient(circle, rgba 0.1); }
107
+
108
+ /* Settings Accordion */
109
+ details {
110
+ background: #F8(255, 255, 255, 0.8), rgba(255, 255, 255, 0)); border-radius: 50%; boxFAFC; border: 1px solid var(--border);
111
+ border-radius: 12px;-shadow: 0 0 30px var(--accent-primary-glow); }
112
+ .logo margin-top: -10px; margin-bottom: 20px;
113
+ overflow: hidden;-icon { width: 40px; height: 40px; color: var(--accent-primary); }
114
+ transition: 0.3s;
115
  }
116
+ summary {
117
+ padding: 12px
118
+ h1 { font-size: 2.8rem; font-weight: 80015px; cursor: pointer; font-size: 0.9rem;
119
+ font-weight: ; margin: 0; background: linear-gradient(90deg, var(--accent-primary), var(--600; color: var(--text-gray); list-style: none;
120
+ display: flex;accent-secondary)); -webkit-background-clip: text; -webkit-text-fill-color: transparent; align-items: center; justify-content: space-between;
 
 
 
 
 
121
  }
122
+ summary::after { content: '+'; letter-spacing: -1px; }
123
+ .subtitle { font-size: 1.1rem font-size: 1.2em; font-weight: bold; }
124
+ details[open] summary::; color: var(--text-secondary); margin-top: 0.5rem; }
125
 
126
+ mainafter { content: '-'; }
127
+ details[open] { border-color: var(--primary); }
128
+
129
+ { padding: 3rem; background-color: var(--panel-bg); border-radius: var(--radius.settings-grid {
130
+ padding: 15px; border-top: 1px solid var(---card); box-shadow: 0 20px 25px -5px rgba(26border);
131
+ display: grid; grid-template-columns: 1fr 1fr; gap: , 32, 44, 0.07); border: 1px solid var(--panel15px;
132
+ }
133
+ .setting-item label { display: block; font-size: -border); animation: fadeIn 0.8s 0.3s ease-out backwards; }
134
+ 0.8rem; color: var(--text-gray); margin-bottom: 5px; }
135
+
136
+ .form-group { margin-bottom: 1.5rem; }
137
+ .form-label { display: flex; align-items: center; gap: 0.75rem; font-.setting-item input, .setting-item select {
138
+ width: 100%; padding: 8px; border: 1px solid var(--border);
139
+ border-radius: 8px; background:weight: 700; color: var(--text-primary); font-size: 1.2em #fff; font-family: inherit;
140
  }
141
 
142
+ /* Generate Button */
143
+ .btn-alpha; margin-bottom: 1rem; }
144
+
145
+ textarea {
146
+ width: 100 {
147
+ width: 100%; padding: 18px;
148
+ background: linear%; background-color: var(--input-bg); border: 2px solid var(--input-border);
149
+ border-gradient(90deg, var(--primary), var(--accent));
150
+ color: #fff; border-radius: var(--radius-input); padding: 1.5rem;
151
+ font-family:: none; border-radius: 14px;
152
+ font-size: 1.1rem var(--app-font); font-size: 1.1rem; color: var(--text-primary);; font-weight: 800; cursor: pointer;
153
+ box-shadow: 0 4
154
+ outline: none; resize: vertical; min-height: 150px; transition: var(--transitionpx 15px rgba(59, 130, 246, 0.3-smooth);
155
+ }
156
+ textarea:focus { border-color: var(--accent-primary); background-);
157
+ display: flex; justify-content: center; align-items: center; gap: 10color: #fff; box-shadow: 0 0 15px var(--accent-primary-glowpx;
158
+ transition: transform 0.2s, box-shadow 0.2s;
159
+ }
160
+ ); }
161
+
162
+ /* Settings Accordion */
163
+ .settings-toggle {
164
+ cursor: pointer; display: flex.btn-alpha:active { transform: scale(0.98); }
165
+ .btn-alpha:; align-items: center; justify-content: space-between;
166
+ padding: 1rem; backgrounddisabled { opacity: 0.7; filter: grayscale(1); cursor: not-allowed; }
167
+
168
+ : var(--input-bg); border-radius: var(--radius-input);
169
+ font-weight: 600; color: var(--text-secondary); border: 1px solid var(--input-border);/* --- COOL LOADER ANIMATION --- */
170
+ #loader-container {
171
+ display: none; flex-direction: column
172
+ transition: var(--transition-smooth);
173
+ }
174
+ .settings-toggle:hover { background:; align-items: center; justify-content: center;
175
+ padding: 40px 20px; text #fff; border-color: var(--accent-primary); }
176
+ .settings-content {
177
+ max-align: center;
178
+ }
179
+
180
+ .neural-loader {
181
+ position: relative; width: 8-height: 0; overflow: hidden; transition: max-height 0.5s ease-out;
182
+ padding0px; height: 80px; margin-bottom: 20px;
183
+ }
184
+ : 0 1rem; background: #fff;
185
+ }
186
+ .settings-content.open { max.neural-circle {
187
+ position: absolute; width: 100%; height: 100-height: 500px; padding: 1rem; border: 1px solid var(--input-%; border-radius: 50%;
188
+ border: 3px solid transparent; border-top-color: var(--border); border-top: none; border-radius: 0 0 var(--radius-input) var(--primary);
189
+ animation: spin 1.5s linear infinite;
190
+ }
191
+ .neural-circle::before {
192
+ content: ""; position: absolute; top: 5px; left: 5px;radius-input); margin-top: -5px; }
193
+
194
+ .grid-3 { display: grid; right: 5px; bottom: 5px;
195
+ border-radius: 50%; border: grid-template-columns: 1fr 1fr 1fr; gap: 1rem; margin-top: 3px solid transparent; border-top-color: var(--accent);
196
+ animation: spin 3s linear infinite;10px; }
197
+ .input-mini { width: 100%; padding: 10px
198
+ }
199
+ .neural-circle::after {
200
+ content: ""; position: absolute; top: ; border-radius: 8px; border: 1px solid var(--input-border); background: var(--input15px; left: 15px; right: 15px; bottom: 15px-bg); font-family: inherit; }
201
+ .label-mini { font-size: 0.;
202
+ border-radius: 50%; border: 3px solid transparent; border-top-color85rem; color: var(--text-secondary); margin-bottom: 5px; display: block;: #10B981;
203
+ animation: spin 1.5s linear infinite reverse;
204
  }
205
+ }
206
+
207
+ /* Main Button */
208
+ #generateButton {
209
+ display: flex; align-items: center .neural-core {
210
+ position: absolute; top: 50%; left: 50%; transform: translate; justify-content: center; gap: 0.75rem;
211
+ width: 100(-50%, -50%);
212
+ width: 20px; height: 20px;%; padding: 1.2rem; font-size: 1.2rem; font-weight: background: var(--primary); border-radius: 50%;
213
+ box-shadow: 0 0700;
214
+ background: linear-gradient(95deg, var(--accent-secondary) 20px var(--primary); animation: pulse 1s infinite alternate;
 
 
 
 
 
 
 
215
  }
 
 
216
 
217
+ @keyframes0%, var(--accent-primary) 100%);
218
+ color: #fff; border: none spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(; border-radius: var(--radius-btn); cursor: pointer;
219
+ transition: all 0.360deg); } }
220
+ @keyframes pulse { 0% { transform: translate(-50%, -53s ease; box-shadow: 0 6px 20px -5px var(--accent-primary-glow0%) scale(0.8); opacity: 0.6; } 100% { transform: translate(-50%, -50%) scale(1.2); opacity: 1; } }
221
+
222
+ .status); margin-top: 2rem;
223
+ }
224
+ #generateButton:hover { transform: translateY(--text {
225
+ font-weight: 600; background: linear-gradient(90deg, var3px) scale(1.01); box-shadow: 0 10px 25px -5px var(--accent-primary-glow); }
226
+ #generateButton:disabled { opacity: 0.5(--primary), var(--accent));
227
+ -webkit-background-clip: text; -webkit-text-fill; cursor: not-allowed; transform: none; }
228
+
229
+ /* --- COOL LOADER --- */
230
+ #-color: transparent;
231
+ font-size: 1.1rem;
232
+ }
233
+
234
+ /* --- RESULT SECTIONaiLoader { display: none; margin-top: 3rem; flex-direction: column; align-items: center --- */
235
+ #result-section { display: none; animation: slideUp 0.6s cubic-bezier(0; }
236
+ .generator-container {
237
+ position: relative; width: 100%; height: 2.2, 1, 0.3, 1); }
238
 
239
+ .result-card {
240
+ background00px; background: #0f172a; border-radius: 20px;
241
+ : #fff; border-radius: 20px; overflow: hidden;
242
+ box-shadow: 0 overflow: hidden; border: 1px solid #334155; box-shadow: 20px 40px -10px rgba(0,0,0,0.1); border: 0 0 50px rgba(74, 108, 250, 0.21px solid var(--border);
243
  }
244
 
245
+ .player-top {
246
+ background: linear-gradient);
247
+ display: flex; flex-direction: column; align-items: center; justify-content: center;
248
+ (135deg, #F8FAFC, #EFF6FF);
249
+ padding: 20px; }
250
+ .scan-line {
251
+ position: absolute; top: 0; left: 0; width border-bottom: 1px solid var(--border);
 
 
 
252
  text-align: center;
 
 
253
  }
254
 
255
+ : 100%; height: 4px;
256
+ background: var(--accent-secondary);
257
+ box-shadow audio { width: 100%; height: 45px; border-radius: 25px;: 0 0 15px var(--accent-secondary);
258
+ animation: scan 2s linear margin-top: 10px; }
259
+
260
+ .lyrics-box {
261
+ padding: 25 infinite; z-index: 5;
262
+ }
263
+ .data-stream {
264
+ position: absolute; widthpx; max-height: 400px; overflow-y: auto;
265
+ text-align:: 100%; height: 100%; top:0; left:0;
266
+ background center; line-height: 2.4; font-size: 1.05rem;
267
+ color:: repeating-linear-gradient(0deg, transparent 0, transparent 20px, rgba(74, #374151; white-space: pre-wrap; background: #fff;
268
+ }
269
+ 108, 250, 0.1) 21px);
270
+ opacity:
271
  .lyrics-tag {
272
+ color: var(--primary); font-weight: 800; display0.3;
273
+ }
274
+ .loader-text {
275
+ font-size: 1.2rem;: block; margin-top: 15px;
276
+ font-size: 0.85em font-weight: 700; color: #fff; z-index: 10; margin-; letter-spacing: 1px; text-transform: uppercase;
277
  }
278
 
279
+ .btn-downloadbottom: 10px; text-shadow: 0 0 10px rgba(255,2 {
280
+ display: inline-flex; align-items: center; gap: 5px;
281
+ color55,255,0.5);
282
+ }
283
+ .progress-bar-container {: var(--primary); text-decoration: none; font-weight: 700; font-size: width: 80%; height: 6px; background: #334155; border-0.9rem;
 
284
  }
 
 
 
285
 
286
+ @keyframes slideUp { from { opacity: 0; transform: translateYradius: 3px; z-index: 10; overflow: hidden; }
287
+ .progress-bar { width(40px); } to { opacity: 1; transform: translateY(0); } }
288
+
289
+ /*: 0%; height: 100%; background: linear-gradient(90deg, var(--accent Hide Scrollbar */
290
+ .lyrics-box::-webkit-scrollbar { width: 6px; }
291
+ .lyrics--secondary), var(--accent-primary)); transition: width 0.3s; animation: fill-progress 20box::-webkit-scrollbar-thumb { background: #E5E7EB; border-radius: 3px;s linear forwards; }
292
+
293
+ @keyframes scan { 0% { top: 0%; opacity: 0; }
294
  </style>
295
  </head>
296
  <body>
297
  <div class="container">
298
+
299
+ <!-- } 10% { opacity: 1; } 90% { opacity: 1; } 10 HEADER -->
300
+ <header id="mainHeader">
301
+ <div class="logo">Alpha Music</div>
302
+ 0% { top: 100%; opacity: 0; } }
303
+
304
+ /* Result */
305
+ #result-container { display: none; margin-top: 2rem; animation: fadeIn 0.8s; <div class="tagline">استودیو هوشمند ساخت موسیقی آلفا</div>
306
+ </header> }
307
+ .audio-player-wrapper {
308
+ background: #fff; border: 2px solid var(--input
309
+
310
+ <!-- INPUT SECTION -->
311
+ <div id="inputSection" class="card">
312
+ <div class="input-area">
313
+ <textarea id="ideaInput" placeholder="توضیحات آهنگ خود را-border); border-radius: var(--radius-card); padding: 1.5rem;
314
+ box-shadow: 0 10px 30px rgba(0,0,0,0.05); اینجا بنویسید...&#10;مثال: آهنگ پاپ عاشقانه درباره باران، صدای زن، احساس text-align: center;
315
+ }
316
+ audio { width: 100%; border-radius:ی..."></textarea>
317
  </div>
318
+
319
+ <details>
320
+ <summary>
321
+ <span>تنظیمات پیش 30px; margin-top: 10px; }
322
+ .lyrics-box {
323
+ رفته (اختیاری)</span>
324
+ </summary>
325
+ <div class="settings-grid">
326
+ margin-top: 1.5rem; padding: 1.5rem; background: var(--input-bg); border<div class="setting-item">
327
+ <label>مدل هوش مصنوعی</label>
328
+ <-radius: var(--radius-input);
329
+ max-height: 400px; overflow-yselect id="modelSelect">
330
+ <option value="acestep-v15-turbo">Alpha Turbo (: auto; white-space: pre-wrap; line-height: 1.8; text-align:سریع)</option>
331
+ <option value="acestep-v15-turbo-shift3">Alpha Pro center;
332
+ color: var(--text-primary); border: 1px dashed var(--input-border);
333
+ (دقیق)</option>
334
+ </select>
335
+ </div>
336
+ <div class="setting-item">
337
+ }
338
+
339
+ @media (max-width: 768px) { .grid-3 { grid-<label>تعداد گام (Steps)</label>
340
+ <input type="number" id="steps"template-columns: 1fr; } }
341
+ </style>
342
+ </head>
343
+ <body>
344
+ value="8" min="4" max="20">
345
+ </div>
346
+ <div class="setting-item">
347
+ <div class="container">
348
+ <header>
349
+ <canvas id="neural-canvas"></ <label>شانس (Seed)</label>
350
+ <input type="text" id="seed" value="-canvas>
351
+ <div class="header-content">
352
+ <div class="logo-container">
353
+ <svg class="logo-icon" viewBox="0 0 24 24" fill="1" placeholder="-1 برای تصادفی">
354
+ </div>
355
+ <div class="setting-item">
356
+ <labelnone" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon>تعداد خروجی</label>
357
+ <input type="number" value="1" disabled style="background: points="12 2 2 7 12 12 22 7 12 2"></ #f3f4f6; color: #9ca3af;">
358
+ </div>
359
  </div>
360
+ </details>polygon><polyline points="2 17 12 22 22 17"></polyline><
361
+
362
+ <button id="generateBtn" class="btn-alpha">
363
+ <span>ساخت آهنگ جادویی</span>
364
+ polyline points="2 12 12 17 22 12"></polyline></svg>
365
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="</div>
366
+ <h1>استودیو آلفا</h1>
367
+ <p class="subtitle">هوش مصنوعی،none" xmlns="http://www.w3.org/2000/svg"><path d="M12 آهنگساز شخصی شما</p>
368
+ </div>
369
+ </header>
370
+ <main>
371
+ <!--22C17.5228 22 22 17.5228 22 Main Input -->
372
+ <div class="form-group">
373
+ <div class="form-label"> 12C22 6.47715 17.5228 2
374
+ <svg width="24" height="24" viewBox="0 0 24 24 12 2C6.47715 2 2 6.4771" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 1a5 2 12C2 17.5228 6.477153 3 0 0 0-3 3v8a3 3 0 0 22 12 22Z" stroke="currentColor" stroke-width="2" stroke-linecap0 6 0V4a3 3 0 0 0-3-3z"></path="round" stroke-linejoin="round"/><path d="M2 12H22" stroke="currentColor"><path d="M19 10v2a7 7 0 0 1-1 stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><path d="M124 0v-2"></path></svg>
375
+ توصیف آهنگ (موضوع، سبک، خوان 2C14.5013 4.73835 15.92نده)
376
+ </div>
377
+ <textarea id="ideaInput" placeholder="مثال: یه آهنگ پاپ عاشق28 8.29203 16 12C15.9228 15انه غمگین، صدای زن، در مورد جاده شمال و بارون..."></textarea>
378
+ </div>
379
+
380
+ .708 14.5013 19.2616 12 <!-- Advanced Settings (Collapsible) -->
381
+ <div class="form-group">
382
+ <div class="22C9.49872 19.2616 8.077settings-toggle" onclick="toggleSettings()">
383
+ <span>تنظیمات پیشرفته (اختیاری)</span>
384
+ 25 15.708 8 12C8.07725 8.2 <svg width="20" height="20" viewBox="0 0 24 249203 9.49872 4.73835 12 " fill="none" stroke="currentColor" stroke-width="2"><polyline points="6 9 122Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round 15 18 9"></polyline></svg>
385
  </div>
386
+ <div class="settings-"/></svg>
 
 
 
387
  </button>
388
  </div>
389
 
390
+ <!-- COOL LOADER -->
391
+ <div id="content" id="settingsContent">
392
+ <div class="grid-3">
393
+ <div>
394
+ <labelloader-container">
395
+ <div class="neural-loader">
396
+ <div class="neural-circle"></div>
397
+ <div class="neural-core"></div>
398
+ </div>
399
+ <div class="status-text class="label-mini">مدل هوش مصنوعی</label>
400
+ <select id="modelSelect" class="input" id="loaderText">در حال پردازش...</div>
401
+ <p style="color: #9CA3AF;-mini">
402
+ <option value="acestep-v15-turbo">Alpha Turbo (سریع)</option> font-size: 0.85rem; margin-top: 10px;">لطفاً صفحه را نب
403
+ <option value="acestep-v15-turbo-shift3">Alpha Pro (دقیق)</option>
404
+ </select>
405
+ </div>
406
+ <div>
407
+ <label class="label-mini">تعداد مراحلندید، این فرآیند حدود ۱ دقیقه طول می‌کشد.</p>
408
  </div>
409
 
410
+ <!-- RESULT SECTION -->
411
+ <div id="result-section">
412
+ <div class="result-card">
413
+ <div (Steps)</label>
414
+ <select id="stepsSelect" class="input-mini">
415
+ <option value class="player-top">
416
+ <div style="display: flex; justify-content: space-between;="8">۸ مرحله (نرمال)</option>
417
+ <option value="12">۱۲ مرحله (کی align-items: center; margin-bottom: 10px;">
418
+ <span style="font-weight: 7فیت بالا)</option>
419
+ <option value="4">۴ مرحله (خیلی سریع)</option>
420
+ 00; color: var(--text-dark);">خروجی نهایی آلفا</span>
421
+ <a id="download </select>
422
+ </div>
423
+ <div>
424
+ <label class="label-mini">تنوع (Seed)</labelLink" href="#" class="btn-download" download>
425
+ <svg width="18" height="1>
426
+ <input type="text" id="seedInput" class="input-mini" value="-1" placeholder="-8" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-1 تصادفی">
427
+ </div>
428
+ </div>
429
  </div>
430
+ </div>
431
+
432
+ <button id="generateButton">width="2"><path d="M21 15v4a2 2 0 0
433
+ <svg width="24" height="24" viewBox="0 0 24 1-2 2H5a2 2 0 0 1-2-2v-424" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke"/><polyline points="7 10 12 15 17 10"/><line x1="-linejoin="round"><polygon points="5 3 19 12 5 21 5 312" y1="15" x2="12" y2="3"/></svg>
434
+ "></polygon></svg>
435
+ <span>ساخت آهنگ با هوش مصنوعی</span>
436
+ </button>
437
+
438
+ دانلود
439
+ </a>
440
+ </div>
441
+ <div id="player-wrapper"></div>
442
+ </div>
443
 
444
+ < <!-- Cool Loader -->
445
+ <div id="aiLoader">
446
+ <div class="generator-container">
447
+ div class="lyrics-box" id="lyrics-content">
448
+ <!-- متن آهنگ اینجا قرار میگیرد -->
449
+ </div><div class="scan-line"></div>
450
+ <div class="data-stream"></div>
451
+ <div
452
+ </div>
453
 
454
+ <button onclick="location.reload()" class="btn-alpha" style="margin class="loader-text" id="loaderText">در حال پردازش هسته آلفا...</div>
455
+ -top: 20px; background: #fff; color: var(--text-dark); border: 2px<div class="progress-bar-container">
456
+ <div class="progress-bar"></div>
457
+ </div> solid var(--border); box-shadow: none;">
458
  ساخت یک آهنگ دیگر
459
  </button>
460
  </div>
461
+ <div style="margin-top: 10px; color: #94a3b8; font-
462
+
463
  </div>
464
 
465
  <script>
466
+ // Configuration
467
+ const ACE_SPACE_URL = "https://size: 0.8rem;">لطفاً صفحه را نبندید</div>
468
+ </div>
469
+ </div> ace-step-ace-step-v1-5.hf.space/";
470
 
471
+ // DOM Elements
472
+
473
+ <!-- Final Result -->
474
+ <div id="result-container">
475
+ <div class="audio-
476
  const generateBtn = document.getElementById('generateBtn');
477
+ const ideaInput = document.getElementById('ideaplayer-wrapper">
478
+ <h3 style="margin: 0 0 10px 0; color:Input');
479
+ const inputSection = document.getElementById('inputSection');
480
+ const loaderContainer = document.getElementById var(--success-color);">✨ آهنگ شما آماده شد</h3>
481
+ <div id="audioWrapper"></div>
482
+ ('loader-container');
483
  const loaderText = document.getElementById('loaderText');
484
+ const resultSection =<a id="downloadBtn" href="#" style="display: inline-block; margin-top: 15px; document.getElementById('result-section');
485
+ const lyricsContent = document.getElementById('lyrics-content');
486
+ const playerWrapper = document.getElementById('player-wrapper');
487
+ const downloadLink = document.getElementById('downloadLink color: var(--accent-primary); text-decoration: none; font-weight: bold;">دانلود فایل MP3</a>
488
+ ');
489
+ const mainHeader = document.getElementById('mainHeader');
490
+
491
+ // Inputs
492
+ const modelSelect =</div>
493
+ <div class="lyrics-box" id="lyricsOutput"></div>
494
+ </div>
495
+ </main>
496
+ document.getElementById('modelSelect');
497
  const stepsInput = document.getElementById('steps');
498
+ const seedInput </div>
499
+
500
+ <script>
501
+ const ACE_SPACE_URL = "https://ace-step = document.getElementById('seed');
502
 
503
  generateBtn.addEventListener('click', async () => {
504
+ const idea = idea-ace-step-v1-5.hf.space/";
505
+
506
+ // UI Elements
507
+ constInput.value.trim();
508
+ if (!idea) {
509
+ ideaInput.focus();
510
+ alert("لطف ideaInput = document.getElementById('ideaInput');
511
+ const generateButton = document.getElementById('generateButton');
512
+ const loaderاً توضیحات آهنگ را وارد کنید.");
513
+ return;
514
+ }
515
+
516
+ // 1. Switch UI to Loader
517
+ = document.getElementById('aiLoader');
518
+ const loaderText = document.getElementById('loaderText');
519
+ const inputSection.style.display = 'none';
520
+ mainHeader.style.display = 'none'; // Hide header resultContainer = document.getElementById('result-container');
521
+ const lyricsOutput = document.getElementById('lyricsOutput');
522
+ const audioWrapper = document.getElementById('audioWrapper');
523
+ const downloadBtn = document.getElementById('downloadBtn');
524
+
525
+ for cleaner look during load
526
+ loaderContainer.style.display = 'flex';
527
+ loaderText.textContent = "آلف // Settings Logic
528
+ function toggleSettings() {
529
+ const content = document.getElementById('settingsContent');
530
+ ا در حال نوشتن ترانه و ملودی...";
531
 
 
 
 
 
 
 
532
  try {
533
+ // 2. Call Gemini ( content.classList.toggle('open');
534
+ }
535
+
536
+ // Main Logic
537
+ generateButton.addEventListener('click', asyncLyrics & Prompt)
538
+ const geminiResp = await fetch('/api/refine', {
539
+ method: () => {
540
+ const idea = ideaInput.value.trim();
541
+ if (!idea) { alert('لط 'POST',
542
  headers: {'Content-Type': 'application/json'},
543
+ body: JSON.stringifyفا ایده آهنگ را بنویسید.'); return; }
544
+
545
+ // 1. UI Transition
546
+ generateButton({ idea: idea })
547
  });
 
 
 
548
 
549
+ const geminiData = await geminiResp.json();
550
+ if (gem.style.display = 'none';
551
+ resultContainer.style.display = 'none';
552
+ loader.style.displayiniData.error) throw new Error("Gemini Error: " + geminiData.error);
553
 
554
+ // 3 = 'flex';
555
+ loaderText.innerText = "هوش مصنوعی آلفا در حال نوشتن شعر...";
556
+ . Update Loader & Call ACE-Step
557
+ loaderText.textContent = "آلفا در حال تنظیم و ساخت
558
+ // Scroll to loader
559
+ loader.scrollIntoView({ behavior: 'smooth' });
560
 
561
+ try {
562
+ آهنگ...";
563
+
564
  const payload = [
565
  modelSelect.value, // Model
566
+ "custom",// 2. Call Gemini for Text & Prompt
567
+ const refineResponse = await fetch('/api/refine', {
568
+ null, "unknown",
569
+ geminiData.music_prompt, // Prompt from Gemini
570
+ geminiData.lyrics method: 'POST',
571
+ headers: {'Content-Type': 'application/json'},
572
+ body:, // Lyrics from Gemini
573
  0, "", "", "unknown",
574
+ parseInt(stepsInput.value) JSON.stringify({ idea: idea })
575
+ });
576
+
577
+ const refinedData = await refineResponse.json(); || 8, // Steps
578
+ 7, true,
579
+ parseInt(seedInput.value) || -
580
+ if (refinedData.error) throw new Error(refinedData.error);
581
+
582
+ const lyrics = refinedData1, // Seed
583
+ null, -1, 1, null, null, 0, -1,
584
  "Fill the audio semantic mask based on the given conditions:",
585
  1, "text2music", false, 0, 1, 3, "ode", "", "mp3", 0.85,
586
+ true, 2, 0, 0.9, "NO USER INPUT", true,.lyrics;
587
+ const prompt = refinedData.music_prompt;
588
+
589
+ // Update Loader
590
+ loaderText.innerText = "استودیو آلفا در حال ضبط آهنگ...";
591
+
592
+ // 3. Call ACE-Step for true, true, null, false, true, false, false, 0.5, 8, null, [], false, null, null, null, null
593
  ];
594
 
595
  const session_hash = Math.random().toString(36).substring(2);
596
 
597
+ const aceResp = await fetch(`${ACE_SPACE_URL}grad Audio
598
+ const model = document.getElementById('modelSelect').value;
599
+ const steps = Number(document.getElementById('stepsSelect').value);
600
+ const seed = document.getElementById('seedInput').value;
601
+
602
+ const payloadio_api/queue/join`, {
603
  method: 'POST',
604
  headers: { 'Content-Type': 'application/json' },
605
  body: JSON.stringify({ data: payload, fn_index: 77, session_hash })
606
  });
607
 
608
+ if (!aceResp.ok) throw new Error(' = [
609
+ model, "custom", null, "unknown",
610
+ prompt, lyrics,
611
+ 0, "", "", "unknown", steps, 7, true, seed, null, -1, 1, null, null, 0, -1,
612
+ "Fill the audio semantic mask based on the given conditions:",
613
+ 1, "text2music", false, 0, 1, 3, "ode", "", "mp3", 0.85,
614
+ true, 2, 0, 0.9, "NO USERخطا در اتصال به سرور موزیک');
615
 
616
+ // 4. Handle SSE
617
+ const eventSource = new EventSource INPUT", true, true, true, null, false, true, false, false, 0.5, 8, null, [], false, null, null, null, null
618
+ ];
619
+
620
+ const session_hash =(`${ACE_SPACE_URL}gradio_api/queue/data?session_hash=${session_hash}`);
621
 
622
  eventSource.onmessage = (event) => {
623
+ const msg = JSON.parse(event. Math.random().toString(36).substring(2);
624
+
625
+ const joinResp = await fetch(`${ACE_data);
626
 
627
  if (msg.msg === 'process_starts') {
628
+ loaderText.textContentSPACE_URL}gradio_api/queue/join`, {
629
+ method: 'POST',
630
+ headers = "آهنگ در حال ضبط استودیویی...";
631
+ }
632
+ else if (msg.msg: { 'Content-Type': 'application/json' },
633
+ body: JSON.stringify({ data: payload, fn_index: 77, session_hash })
634
+ });
635
+
636
+ if (!joinResp.ok === 'process_completed') {
637
  eventSource.close();
638
+ showResult(msg.output, geminiData.lyrics);
 
 
 
639
  }
640
  };
641
 
642
  eventSource.onerror = () => {
643
+ ) throw new Error('خطا در اتصال به سرور موزیک');
644
+
645
+ const eventSource = new EventSource(`${ACE_ throw new Error('ارتباط با سرور قطع شد.');
646
  };
647
 
648
  } catch (error) {
649
+ SPACE_URL}gradio_api/queue/data?session_hash=${session_hash}`);
650
+
651
+ eventalert("خطا: " + error.message);
652
+ location.reload(); // Reset on error
653
+ }Source.onmessage = (event) => {
654
+ const msg = JSON.parse(event.data);
655
+
656
+ if (msg.msg === 'process_starts') {
657
+ loaderText.innerText = "در
658
+ });
659
+
660
+ function showResult(outputData, lyricsText) {
661
+ loaderContainer.style.display = 'none حال رندر نهایی صدا...";
662
+ } else if (msg.msg === 'process_completed') {
663
+ event';
664
+ mainHeader.style.display = 'block';
665
+ resultSection.style.display = 'blockSource.close();
666
+ showResult(msg.output, lyrics);
667
+ }
668
+ };
669
+
670
+ eventSource.onerror';
671
+
672
+ // Find Audio URL
673
+ let audioUrl = null;
674
+ function findAudio(obj) {
675
+ if (typeof obj === 'string' && obj.includes('/file=') && obj.endsWith('.mp3')) { = () => { throw new Error('ارتباط با سرور قطع شد.'); };
676
+
677
+ } catch (e)
678
+ audioUrl = obj;
679
+ } else if (obj && typeof obj === 'object') {
680
+ {
681
+ alert("خطا: " + e.message);
682
+ loader.style.display = 'noneif (obj.url && obj.url.endsWith('.mp3')) audioUrl = obj.url;
683
+ ';
684
+ generateButton.style.display = 'flex';
685
  }
686
  });
687
 
688
+ function showResultObject.values(obj).forEach(findAudio);
689
+ }
690
+ }
691
+ findAudio(outputData(data, lyrics) {
692
  let audioUrl = null;
 
 
693
  function traverse(obj) {
694
+ if);
695
+
696
+ if (audioUrl) {
697
+ const fullUrl = audioUrl.startsWith('http') ? audio (typeof obj === 'string' && obj.includes('/file=') && obj.endsWith('.mp3')) {Url : ACE_SPACE_URL.replace(/\/$/, '') + audioUrl;
698
+
699
+ // Create Player
700
  audioUrl = obj;
701
  } else if (obj && typeof obj === 'object') {
702
+
703
+ playerWrapper.innerHTML = `<audio controls autoplay src="${fullUrl}"></audio>`;
704
+ downloadLink.href = fullif (obj.url && obj.url.endsWith('.mp3')) audioUrl = obj.url;
705
  Object.values(obj).forEach(traverse);
706
  }
707
  }
708
+ traverse(data);
709
 
710
+ Url;
 
 
 
 
 
711
 
712
  // Format Lyrics
713
+ const formattedLyrics = lyricsText.replace(/\[(.*?)\]/g, '<span class="lyrics-tag">[$1]</span>');
714
+ lyricsContent.innerHTML = formattedLyrics;if (audioUrl) {
715
+ const fullUrl = audioUrl.startsWith('http') ? audioUrl : ACE_SPACE_URL.replace(/\/$/, '') + audioUrl;
716
+
717
+ audioWrapper.innerHTML = `<
 
718
  } else {
719
+ alert("فایل صوتی یافت نشد!");
720
+ location.reload();
721
+ audio controls autoplay src="${fullUrl}"></audio>`;
722
+ downloadBtn.href = fullUrl;
723
+ lyrics}
724
  }
725
  </script>
726
  </body>