Opera8 commited on
Commit
b6f03f7
·
verified ·
1 Parent(s): 1ae5bd5

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +192 -86
index.html CHANGED
@@ -15,8 +15,8 @@
15
  --input-border: #E1E7EF;
16
  --text-primary: #1A202C;
17
  --text-secondary: #626F86;
18
- --accent-primary: #D53F8C; /* رنگ جدید برای برند آلفا (صورتی/بنفش جذاب) */
19
- --accent-glow: rgba(213, 63, 140, 0.2);
20
  --success-color: #38A169;
21
  --radius-card: 20px;
22
  --radius-btn: 14px;
@@ -57,7 +57,7 @@
57
 
58
  h1 {
59
  font-size: 1.8rem; font-weight: 800; margin: 0;
60
- background: linear-gradient(90deg, #2d3748, var(--accent-primary));
61
  -webkit-background-clip: text; -webkit-text-fill-color: transparent;
62
  }
63
  .subtitle { font-size: 0.9rem; color: var(--text-secondary); margin-top: 5px; }
@@ -89,10 +89,10 @@
89
  textarea { min-height: 120px; resize: vertical; }
90
  textarea:focus, input:focus, select:focus { border-color: var(--accent-primary); background: #fff; }
91
 
92
- /* استایل دکمه‌ها */
93
  .btn-main {
94
  width: 100%; padding: 16px;
95
- background: linear-gradient(135deg, var(--accent-primary), #9F7AEA);
96
  color: #fff; border: none; border-radius: var(--radius-btn);
97
  font-size: 1.1rem; font-weight: 700; cursor: pointer;
98
  display: flex; justify-content: center; align-items: center; gap: 10px;
@@ -108,7 +108,7 @@
108
  }
109
  .btn-outline:hover { border-color: var(--accent-primary); color: var(--accent-primary); }
110
 
111
- /* استایل آکاردئون تنظیمات */
112
  .accordion {
113
  background-color: var(--input-bg);
114
  color: var(--text-primary);
@@ -152,18 +152,14 @@
152
  .checkbox-wrapper { display: flex; align-items: center; gap: 10px; margin-top: 5px; padding-bottom: 15px; border-top: 1px solid #e2e8f0; padding-top: 15px; }
153
  .checkbox-wrapper input { width: 20px; height: 20px; cursor: pointer; }
154
 
155
- /* بخش نتیجه */
156
- #finalResult { display: none; animation: slideUp 0.6s cubic-bezier(0.16, 1, 0.3, 1); }
157
-
158
  .player-header {
159
  display: flex; align-items: center; justify-content: space-between;
160
  margin-bottom: 15px; padding-bottom: 15px;
161
  border-bottom: 1px solid var(--panel-border);
162
  }
163
-
164
- /* دکمه دانلود */
165
  #mainDownloadLink {
166
- background-color: rgba(213, 63, 140, 0.1);
167
  color: var(--accent-primary);
168
  text-decoration: none;
169
  font-size: 0.9rem;
@@ -173,11 +169,9 @@
173
  transition: 0.2s;
174
  display: none;
175
  }
176
- #mainDownloadLink:hover { background-color: rgba(213, 63, 140, 0.2); }
177
-
178
  .audio-item { margin-bottom: 10px; }
179
  audio { width: 100%; height: 45px; border-radius: 20px; margin-top: 5px; }
180
-
181
  .lyrics-container {
182
  background: var(--input-bg);
183
  border-radius: 16px;
@@ -192,17 +186,7 @@
192
  border: 1px solid var(--input-border);
193
  margin-top: 15px;
194
  }
195
-
196
- .lyrics-tag {
197
- color: var(--accent-primary);
198
- font-weight: 800;
199
- display: block;
200
- margin-top: 20px;
201
- margin-bottom: 5px;
202
- font-size: 0.9em;
203
- letter-spacing: 1px;
204
- text-transform: uppercase;
205
- }
206
 
207
  /* لودر */
208
  #loader { display: none; text-align: center; padding: 20px; }
@@ -213,6 +197,54 @@
213
  .bar:nth-child(4) { animation-delay: 0.3s; height: 50%; }
214
  @keyframes jump { 0%, 100% { height: 20%; } 50% { height: 100%; } }
215
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
216
  .hidden { display: none; }
217
  @keyframes slideUp { from { opacity: 0; transform: translateY(30px); } to { opacity: 1; transform: translateY(0); } }
218
  </style>
@@ -223,14 +255,13 @@
223
  <div class="container">
224
  <header>
225
  <div class="logo-box">
226
- <!-- آیکون جدید موسیقی -->
227
  <svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18V5l12-2v13"></path><circle cx="6" cy="18" r="3"></circle><circle cx="18" cy="16" r="3"></circle></svg>
228
  </div>
229
  <h1>استودیو موزیک آلفا</h1>
230
  <p class="subtitle">ساخت آهنگ حرفه‌ای با هوش مصنوعی</p>
231
  </header>
232
 
233
- <!-- مرحله اصلی: ورودی + تنظیمات + دکمه نهایی -->
234
  <div id="step1" class="card">
235
  <div class="form-label">
236
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z"></path><path d="M19 10v2a7 7 0 0 1-14 0v-2"></path></svg>
@@ -238,14 +269,13 @@
238
  </div>
239
  <textarea id="ideaInput" placeholder="مثال: آهنگ تولد برای سمیرا، سبک پاپ شاد..."></textarea>
240
 
241
- <!-- تنظیمات پیشرفته -->
242
- <button class="accordion">تنظیمات پیشرفته (مدل، تعداد، کیفیت)</button>
243
  <div class="panel">
244
  <div class="settings-grid">
245
  <div class="settings-group">
246
  <label>مدل هوش مصنوعی:</label>
247
  <select id="model_select">
248
- <option value="acestep-v15-turbo-shift3" selected>Turbo-Shift3 (دقیق‌ترین - پیشنهادی)</option>
249
  <option value="acestep-v15-turbo">Turbo (سریع‌ترین)</option>
250
  </select>
251
  </div>
@@ -288,36 +318,55 @@
288
  <p style="color: #718096; font-size: 0.9rem; margin-top: 10px;" id="loaderText">در حال پردازش...</p>
289
  </div>
290
 
291
- <!-- مرحله نهایی: نمایش نتیجه -->
292
- <div id="finalResult" class="card">
293
  <div class="player-header">
294
  <div style="font-weight: 700; color: var(--success-color); display: flex; align-items: center; gap: 5px;">
295
  <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path><polyline points="22 4 12 14.01 9 11.01"></polyline></svg>
296
- آهنگ آماده شد
297
  </div>
298
- <a id="mainDownloadLink" href="#" target="_blank" download>
299
- دانلود آهنگ 📥
300
- </a>
301
  </div>
302
-
303
  <div id="playerWrapper"></div>
304
-
305
  <div class="form-label" style="margin-top: 20px; justify-content: center; color: #718096;">متن آهنگ</div>
306
  <div class="lyrics-container" id="finalLyricsBox"></div>
307
-
308
  <button onclick="location.reload()" class="btn-main btn-outline">ساخت آهنگ جدید</button>
309
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
310
  </div>
311
 
312
  <script>
313
  const ACE_SPACE_URL = "https://ace-step-ace-step-v1-5.hf.space/";
314
 
315
- // --- توابع کمکی ---
316
  const getVal = (id) => document.getElementById(id).value;
317
  const getNum = (id) => Number(document.getElementById(id).value);
318
  const getChk = (id) => document.getElementById(id).checked;
319
 
320
- // المان‌ها
321
  const ideaInput = document.getElementById('ideaInput');
322
  const processBtn = document.getElementById('processBtn');
323
  const step1 = document.getElementById('step1');
@@ -327,32 +376,101 @@
327
  const playerWrapper = document.getElementById('playerWrapper');
328
  const finalLyricsBox = document.getElementById('finalLyricsBox');
329
  const mainDownloadLink = document.getElementById('mainDownloadLink');
 
330
 
331
- // فعال‌سازی آکاردئون
332
  const acc = document.getElementsByClassName("accordion");
333
  for (let i = 0; i < acc.length; i++) {
334
  acc[i].addEventListener("click", function() {
335
  this.classList.toggle("active");
336
  const panel = this.nextElementSibling;
337
- if (panel.style.maxHeight) {
338
- panel.style.maxHeight = null;
339
- } else {
340
- panel.style.maxHeight = panel.scrollHeight + "px";
341
- }
342
  });
343
  }
344
 
345
- // --- فرآیند اصلی: ساخت یک‌مرحله‌ای ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
346
  processBtn.addEventListener('click', async () => {
347
  if (!ideaInput.value.trim()) return alert("لطفا موضوع آهنگ را بنویسید");
348
 
349
- // مخفی کردن فرم و نمایش لودر
350
  processBtn.disabled = true;
351
  step1.style.display = 'none';
352
  loader.style.display = 'block';
353
 
354
  try {
355
- // 1. دریافت متن و پرامپت از Gemini
356
  loaderText.innerText = "آلفا در حال نوشتن شعر و ملودی...";
357
 
358
  const response = await fetch('/api/refine', {
@@ -367,34 +485,25 @@
367
  const lyrics = data.lyrics;
368
  const musicPrompt = data.music_prompt;
369
 
370
- // 2. ارسال مستقیم برای ساخت آهنگ دون توقف)
371
- loaderText.innerText = "در حال ضبط آهنگ در استودیو آلفا (لطفاً صبر کنید)...";
372
 
373
- // آماده‌سازی محیط پخش
374
  formatLyricsForDisplay(lyrics);
375
  playerWrapper.innerHTML = '';
376
 
377
  const payload = [
378
- getVal('model_select'),
379
- "custom", null, "unknown",
380
- musicPrompt,
381
- lyrics,
382
  0, "", "", "unknown",
383
- getNum('steps_input'),
384
- getNum('cfg_input'),
385
- true,
386
- getNum('seed_input'),
387
- null, -1,
388
- getNum('batch_size'),
389
- null, null, 0, -1,
390
  "Fill the audio semantic mask based on the given conditions:",
391
  1, "text2music", false, 0, 1, 3, "ode", "", "mp3", 0.85,
392
- getChk('think_checkbox'),
393
- 2, 0, 0.9, "NO USER INPUT", true, true, true, null, false, true, false, false, 0.5, 8, null, [], false, null, null, null, null
394
  ];
395
 
396
  const session_hash = Math.random().toString(36).substring(2);
397
-
398
  const joinResp = await fetch(`${ACE_SPACE_URL}gradio_api/queue/join`, {
399
  method: 'POST',
400
  headers: { 'Content-Type': 'application/json' },
@@ -412,37 +521,35 @@
412
  } else if (msg.msg === 'process_completed') {
413
  eventSource.close();
414
  loader.style.display = 'none';
415
- handleAudioOutput(msg.output);
416
  }
417
  };
418
-
419
- eventSource.onerror = () => {
420
- throw new Error('ارتباط با سرور قطع شد.');
421
- };
422
 
423
  } catch (e) {
424
  alert("خطا: " + e.message);
425
  loader.style.display = 'none';
426
- step1.style.display = 'block'; // بازگشت به مرحله اول در صورت خطا
427
  processBtn.disabled = false;
428
  }
429
  });
430
 
431
- function handleAudioOutput(data) {
432
  const processedUrls = new Set();
433
  let hasResult = false;
434
 
435
  function addAudio(url) {
436
  const fullUrl = url.startsWith('http') ? url : ACE_SPACE_URL.replace(/\/$/, '') + url;
437
-
438
  if (processedUrls.has(fullUrl)) return;
439
  processedUrls.add(fullUrl);
440
-
441
  hasResult = true;
442
 
 
443
  if (processedUrls.size === 1) {
444
  mainDownloadLink.href = fullUrl;
445
  mainDownloadLink.style.display = 'inline-block';
 
 
446
  }
447
 
448
  const div = document.createElement('div');
@@ -470,26 +577,25 @@
470
  }
471
  }
472
 
 
 
 
 
473
  function formatLyricsForDisplay(text) {
474
- let formatted = text.replace(/\[(.*?)\]/g, '<span class="lyrics-tag">[$1]</span>');
475
- finalLyricsBox.innerHTML = formatted;
476
  }
477
 
 
478
  const canvas = document.getElementById('music-canvas');
479
  const ctx = canvas.getContext('2d');
480
  let t = 0;
481
-
482
- function resize() {
483
- canvas.width = window.innerWidth;
484
- canvas.height = 400;
485
- }
486
  window.addEventListener('resize', resize);
487
  resize();
488
-
489
  function anim() {
490
  ctx.clearRect(0, 0, canvas.width, canvas.height);
491
  ctx.beginPath();
492
- ctx.strokeStyle = "rgba(213, 63, 140, 0.1)"; // رنگ متناسب با تم آلفا
493
  ctx.lineWidth = 2;
494
  for(let i=0; i<canvas.width; i+=20) {
495
  ctx.moveTo(i, 0);
 
15
  --input-border: #E1E7EF;
16
  --text-primary: #1A202C;
17
  --text-secondary: #626F86;
18
+ --accent-primary: #4A6CFA;
19
+ --accent-glow: rgba(74, 108, 250, 0.2);
20
  --success-color: #38A169;
21
  --radius-card: 20px;
22
  --radius-btn: 14px;
 
57
 
58
  h1 {
59
  font-size: 1.8rem; font-weight: 800; margin: 0;
60
+ background: linear-gradient(90deg, #2d3748, #4A6CFA);
61
  -webkit-background-clip: text; -webkit-text-fill-color: transparent;
62
  }
63
  .subtitle { font-size: 0.9rem; color: var(--text-secondary); margin-top: 5px; }
 
89
  textarea { min-height: 120px; resize: vertical; }
90
  textarea:focus, input:focus, select:focus { border-color: var(--accent-primary); background: #fff; }
91
 
92
+ /* دکمه‌ها */
93
  .btn-main {
94
  width: 100%; padding: 16px;
95
+ background: linear-gradient(135deg, var(--accent-primary), #3b5bdb);
96
  color: #fff; border: none; border-radius: var(--radius-btn);
97
  font-size: 1.1rem; font-weight: 700; cursor: pointer;
98
  display: flex; justify-content: center; align-items: center; gap: 10px;
 
108
  }
109
  .btn-outline:hover { border-color: var(--accent-primary); color: var(--accent-primary); }
110
 
111
+ /* تنظیمات پیشرفته */
112
  .accordion {
113
  background-color: var(--input-bg);
114
  color: var(--text-primary);
 
152
  .checkbox-wrapper { display: flex; align-items: center; gap: 10px; margin-top: 5px; padding-bottom: 15px; border-top: 1px solid #e2e8f0; padding-top: 15px; }
153
  .checkbox-wrapper input { width: 20px; height: 20px; cursor: pointer; }
154
 
155
+ /* پلیر و متن */
 
 
156
  .player-header {
157
  display: flex; align-items: center; justify-content: space-between;
158
  margin-bottom: 15px; padding-bottom: 15px;
159
  border-bottom: 1px solid var(--panel-border);
160
  }
 
 
161
  #mainDownloadLink {
162
+ background-color: rgba(74, 108, 250, 0.1);
163
  color: var(--accent-primary);
164
  text-decoration: none;
165
  font-size: 0.9rem;
 
169
  transition: 0.2s;
170
  display: none;
171
  }
172
+ #mainDownloadLink:hover { background-color: rgba(74, 108, 250, 0.2); }
 
173
  .audio-item { margin-bottom: 10px; }
174
  audio { width: 100%; height: 45px; border-radius: 20px; margin-top: 5px; }
 
175
  .lyrics-container {
176
  background: var(--input-bg);
177
  border-radius: 16px;
 
186
  border: 1px solid var(--input-border);
187
  margin-top: 15px;
188
  }
189
+ .lyrics-tag { color: var(--accent-primary); font-weight: 800; display: block; margin-top: 20px; margin-bottom: 5px; font-size: 0.9em; letter-spacing: 1px; text-transform: uppercase; }
 
 
 
 
 
 
 
 
 
 
190
 
191
  /* لودر */
192
  #loader { display: none; text-align: center; padding: 20px; }
 
197
  .bar:nth-child(4) { animation-delay: 0.3s; height: 50%; }
198
  @keyframes jump { 0%, 100% { height: 20%; } 50% { height: 100%; } }
199
 
200
+ /* استایل بخش تاریخچه (History) */
201
+ .history-section {
202
+ margin-top: 30px;
203
+ width: 100%;
204
+ }
205
+ .history-title {
206
+ font-size: 1.2rem; font-weight: 800; color: var(--text-primary); margin-bottom: 15px; display: flex; align-items: center; gap: 10px;
207
+ }
208
+ .history-list {
209
+ display: grid; grid-template-columns: repeat(auto-fill, minmax(100%, 1fr)); gap: 12px;
210
+ }
211
+ .history-card {
212
+ background: white; border-radius: 16px; padding: 15px;
213
+ display: flex; align-items: center; justify-content: space-between;
214
+ border: 1px solid var(--panel-border);
215
+ transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
216
+ cursor: pointer;
217
+ position: relative; overflow: hidden;
218
+ }
219
+ .history-card:hover { transform: translateY(-3px); box-shadow: 0 8px 20px rgba(74, 108, 250, 0.15); border-color: var(--accent-primary); }
220
+ .h-info { display: flex; align-items: center; gap: 15px; }
221
+ .h-icon { width: 45px; height: 45px; background: var(--input-bg); border-radius: 12px; display: flex; align-items: center; justify-content: center; color: var(--accent-primary); font-size: 1.2rem; }
222
+ .h-details h4 { margin: 0; font-size: 1rem; color: var(--text-primary); font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 200px; }
223
+ .h-details span { font-size: 0.8rem; color: var(--text-secondary); }
224
+ .h-play { color: var(--accent-primary); opacity: 0; transition: 0.3s; transform: scale(0.8); }
225
+ .history-card:hover .h-play { opacity: 1; transform: scale(1); }
226
+
227
+ /* مودال (Modal) */
228
+ .modal-overlay {
229
+ position: fixed; top: 0; left: 0; width: 100%; height: 100%;
230
+ background: rgba(0,0,0,0.6); backdrop-filter: blur(5px);
231
+ z-index: 1000; display: none; align-items: center; justify-content: center;
232
+ opacity: 0; transition: opacity 0.3s;
233
+ }
234
+ .modal-content {
235
+ width: 90%; max-width: 600px; max-height: 90vh; overflow-y: auto;
236
+ background: white; border-radius: 20px; padding: 25px;
237
+ transform: scale(0.9); transition: transform 0.3s;
238
+ position: relative;
239
+ }
240
+ .modal-close {
241
+ position: absolute; top: 15px; left: 15px; background: #eee; border: none;
242
+ width: 30px; height: 30px; border-radius: 50%; cursor: pointer; font-size: 1.2rem;
243
+ display: flex; align-items: center; justify-content: center; color: #555;
244
+ }
245
+ .modal-overlay.open { display: flex; opacity: 1; }
246
+ .modal-overlay.open .modal-content { transform: scale(1); }
247
+
248
  .hidden { display: none; }
249
  @keyframes slideUp { from { opacity: 0; transform: translateY(30px); } to { opacity: 1; transform: translateY(0); } }
250
  </style>
 
255
  <div class="container">
256
  <header>
257
  <div class="logo-box">
 
258
  <svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18V5l12-2v13"></path><circle cx="6" cy="18" r="3"></circle><circle cx="18" cy="16" r="3"></circle></svg>
259
  </div>
260
  <h1>استودیو موزیک آلفا</h1>
261
  <p class="subtitle">ساخت آهنگ حرفه‌ای با هوش مصنوعی</p>
262
  </header>
263
 
264
+ <!-- مرحله اصلی -->
265
  <div id="step1" class="card">
266
  <div class="form-label">
267
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z"></path><path d="M19 10v2a7 7 0 0 1-14 0v-2"></path></svg>
 
269
  </div>
270
  <textarea id="ideaInput" placeholder="مثال: آهنگ تولد برای سمیرا، سبک پاپ شاد..."></textarea>
271
 
272
+ <button class="accordion">تنظیمات پیشرفته</button>
 
273
  <div class="panel">
274
  <div class="settings-grid">
275
  <div class="settings-group">
276
  <label>مدل هوش مصنوعی:</label>
277
  <select id="model_select">
278
+ <option value="acestep-v15-turbo-shift3" selected>Turbo-Shift3 (دقیق‌ترین)</option>
279
  <option value="acestep-v15-turbo">Turbo (سریع‌ترین)</option>
280
  </select>
281
  </div>
 
318
  <p style="color: #718096; font-size: 0.9rem; margin-top: 10px;" id="loaderText">در حال پردازش...</p>
319
  </div>
320
 
321
+ <!-- نتیجه نهایی مچنین برای مودال استفاده می‌شود) -->
322
+ <div id="finalResult" class="card" style="display:none;">
323
  <div class="player-header">
324
  <div style="font-weight: 700; color: var(--success-color); display: flex; align-items: center; gap: 5px;">
325
  <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path><polyline points="22 4 12 14.01 9 11.01"></polyline></svg>
326
+ آهنگ جدید آماده شد
327
  </div>
328
+ <a id="mainDownloadLink" href="#" target="_blank" download>دانلود آهنگ 📥</a>
 
 
329
  </div>
 
330
  <div id="playerWrapper"></div>
 
331
  <div class="form-label" style="margin-top: 20px; justify-content: center; color: #718096;">متن آهنگ</div>
332
  <div class="lyrics-container" id="finalLyricsBox"></div>
 
333
  <button onclick="location.reload()" class="btn-main btn-outline">ساخت آهنگ جدید</button>
334
  </div>
335
+
336
+ <!-- بخش سوابق (History) -->
337
+ <div class="history-section">
338
+ <div class="history-title">
339
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"></circle><polyline points="12 6 12 12 16 14"></polyline></svg>
340
+ آخرین آهنگ‌های ساخته شده
341
+ </div>
342
+ <div class="history-list" id="historyList">
343
+ <!-- آیتم‌ها اینجا اضافه می‌شوند -->
344
+ </div>
345
+ </div>
346
+ </div>
347
+
348
+ <!-- مودال نمایش سابقه -->
349
+ <div class="modal-overlay" id="historyModal">
350
+ <div class="modal-content">
351
+ <button class="modal-close" onclick="closeModal()">×</button>
352
+ <div class="player-header">
353
+ <div style="font-weight: 700; color: var(--accent-primary);">پخش آهنگ آرشیو شده</div>
354
+ <a id="modalDownloadLink" href="#" target="_blank" style="color:var(--accent-primary); font-weight:700; text-decoration:none;">دانلود 📥</a>
355
+ </div>
356
+ <div id="modalAudioWrapper" style="margin-bottom:15px;"></div>
357
+ <div class="form-label">متن آهنگ</div>
358
+ <div class="lyrics-container" id="modalLyricsBox"></div>
359
+ </div>
360
  </div>
361
 
362
  <script>
363
  const ACE_SPACE_URL = "https://ace-step-ace-step-v1-5.hf.space/";
364
 
365
+ // المان‌ها
366
  const getVal = (id) => document.getElementById(id).value;
367
  const getNum = (id) => Number(document.getElementById(id).value);
368
  const getChk = (id) => document.getElementById(id).checked;
369
 
 
370
  const ideaInput = document.getElementById('ideaInput');
371
  const processBtn = document.getElementById('processBtn');
372
  const step1 = document.getElementById('step1');
 
376
  const playerWrapper = document.getElementById('playerWrapper');
377
  const finalLyricsBox = document.getElementById('finalLyricsBox');
378
  const mainDownloadLink = document.getElementById('mainDownloadLink');
379
+ const historyList = document.getElementById('historyList');
380
 
381
+ // آکاردئون
382
  const acc = document.getElementsByClassName("accordion");
383
  for (let i = 0; i < acc.length; i++) {
384
  acc[i].addEventListener("click", function() {
385
  this.classList.toggle("active");
386
  const panel = this.nextElementSibling;
387
+ panel.style.maxHeight = panel.style.maxHeight ? null : panel.scrollHeight + "px";
 
 
 
 
388
  });
389
  }
390
 
391
+ // --- مدیریت سوابق (History Manager) ---
392
+ function loadHistory() {
393
+ const history = JSON.parse(localStorage.getItem('alphaHistory')) || [];
394
+ historyList.innerHTML = '';
395
+
396
+ if (history.length === 0) {
397
+ historyList.innerHTML = '<div style="text-align:center; color:#999; padding:20px;">هنوز آهنگی نساخته‌اید</div>';
398
+ return;
399
+ }
400
+
401
+ history.forEach((item, index) => {
402
+ const div = document.createElement('div');
403
+ div.className = 'history-card';
404
+ div.innerHTML = `
405
+ <div class="h-info">
406
+ <div class="h-icon">🎵</div>
407
+ <div class="h-details">
408
+ <h4>${item.idea.substring(0, 30)}${item.idea.length > 30 ? '...' : ''}</h4>
409
+ <span>${item.date}</span>
410
+ </div>
411
+ </div>
412
+ <div class="h-play">▶ نمایش</div>
413
+ `;
414
+ div.onclick = () => openHistoryItem(item);
415
+ historyList.appendChild(div);
416
+ });
417
+ }
418
+
419
+ function saveToHistory(idea, lyrics, audioUrl) {
420
+ let history = JSON.parse(localStorage.getItem('alphaHistory')) || [];
421
+
422
+ const newItem = {
423
+ id: Date.now(),
424
+ idea: idea,
425
+ lyrics: lyrics,
426
+ audioUrl: audioUrl,
427
+ date: new Date().toLocaleDateString('fa-IR', { hour: '2-digit', minute: '2-digit' })
428
+ };
429
+
430
+ // اضافه کردن به اول لیست
431
+ history.unshift(newItem);
432
+
433
+ // اگر بیشتر از 10 تا شد، آخری را حذف کن
434
+ if (history.length > 10) {
435
+ history.pop();
436
+ }
437
+
438
+ localStorage.setItem('alphaHistory', JSON.stringify(history));
439
+ loadHistory();
440
+ }
441
+
442
+ function openHistoryItem(item) {
443
+ const modal = document.getElementById('historyModal');
444
+ document.getElementById('modalLyricsBox').innerHTML = formatLyrics(item.lyrics);
445
+ document.getElementById('modalAudioWrapper').innerHTML = `<audio controls autoplay src="${item.audioUrl}"></audio>`;
446
+ document.getElementById('modalDownloadLink').href = item.audioUrl;
447
+
448
+ modal.classList.add('open');
449
+ }
450
+
451
+ function closeModal() {
452
+ const modal = document.getElementById('historyModal');
453
+ modal.classList.remove('open');
454
+ document.getElementById('modalAudioWrapper').innerHTML = ''; // توقف موزیک
455
+ }
456
+
457
+ // بستن مودال با کلیک بیرون
458
+ document.getElementById('historyModal').addEventListener('click', (e) => {
459
+ if (e.target === document.getElementById('historyModal')) closeModal();
460
+ });
461
+
462
+ // لود کردن سوابق هنگام شروع
463
+ loadHistory();
464
+
465
+ // --- فرآیند اصلی ---
466
  processBtn.addEventListener('click', async () => {
467
  if (!ideaInput.value.trim()) return alert("لطفا موضوع آهنگ را بنویسید");
468
 
 
469
  processBtn.disabled = true;
470
  step1.style.display = 'none';
471
  loader.style.display = 'block';
472
 
473
  try {
 
474
  loaderText.innerText = "آلفا در حال نوشتن شعر و ملودی...";
475
 
476
  const response = await fetch('/api/refine', {
 
485
  const lyrics = data.lyrics;
486
  const musicPrompt = data.music_prompt;
487
 
488
+ loaderText.innerText = "در حال ضبط آهنگ در استودیو آلفا...";
 
489
 
490
+ // آماده‌سازی نمایش نتیجه جاری
491
  formatLyricsForDisplay(lyrics);
492
  playerWrapper.innerHTML = '';
493
 
494
  const payload = [
495
+ getVal('model_select'), "custom", null, "unknown",
496
+ musicPrompt, lyrics,
 
 
497
  0, "", "", "unknown",
498
+ getNum('steps_input'), getNum('cfg_input'),
499
+ true, getNum('seed_input'), null, -1,
500
+ getNum('batch_size'), null, null, 0, -1,
 
 
 
 
501
  "Fill the audio semantic mask based on the given conditions:",
502
  1, "text2music", false, 0, 1, 3, "ode", "", "mp3", 0.85,
503
+ getChk('think_checkbox'), 2, 0, 0.9, "NO USER INPUT", true, true, true, null, false, true, false, false, 0.5, 8, null, [], false, null, null, null, null
 
504
  ];
505
 
506
  const session_hash = Math.random().toString(36).substring(2);
 
507
  const joinResp = await fetch(`${ACE_SPACE_URL}gradio_api/queue/join`, {
508
  method: 'POST',
509
  headers: { 'Content-Type': 'application/json' },
 
521
  } else if (msg.msg === 'process_completed') {
522
  eventSource.close();
523
  loader.style.display = 'none';
524
+ handleAudioOutput(msg.output, lyrics, ideaInput.value);
525
  }
526
  };
527
+ eventSource.onerror = () => { throw new Error('ارتباط با سرور قطع شد.'); };
 
 
 
528
 
529
  } catch (e) {
530
  alert("خطا: " + e.message);
531
  loader.style.display = 'none';
532
+ step1.style.display = 'block';
533
  processBtn.disabled = false;
534
  }
535
  });
536
 
537
+ function handleAudioOutput(data, lyrics, idea) {
538
  const processedUrls = new Set();
539
  let hasResult = false;
540
 
541
  function addAudio(url) {
542
  const fullUrl = url.startsWith('http') ? url : ACE_SPACE_URL.replace(/\/$/, '') + url;
 
543
  if (processedUrls.has(fullUrl)) return;
544
  processedUrls.add(fullUrl);
 
545
  hasResult = true;
546
 
547
+ // نمایش در نتیجه اصلی
548
  if (processedUrls.size === 1) {
549
  mainDownloadLink.href = fullUrl;
550
  mainDownloadLink.style.display = 'inline-block';
551
+ // ذخیره در سوابق
552
+ saveToHistory(idea, lyrics, fullUrl);
553
  }
554
 
555
  const div = document.createElement('div');
 
577
  }
578
  }
579
 
580
+ function formatLyrics(text) {
581
+ return text.replace(/\[(.*?)\]/g, '<span class="lyrics-tag">[$1]</span>');
582
+ }
583
+
584
  function formatLyricsForDisplay(text) {
585
+ finalLyricsBox.innerHTML = formatLyrics(text);
 
586
  }
587
 
588
+ // انیمیشن پس‌زمینه
589
  const canvas = document.getElementById('music-canvas');
590
  const ctx = canvas.getContext('2d');
591
  let t = 0;
592
+ function resize() { canvas.width = window.innerWidth; canvas.height = 400; }
 
 
 
 
593
  window.addEventListener('resize', resize);
594
  resize();
 
595
  function anim() {
596
  ctx.clearRect(0, 0, canvas.width, canvas.height);
597
  ctx.beginPath();
598
+ ctx.strokeStyle = "rgba(74, 108, 250, 0.1)";
599
  ctx.lineWidth = 2;
600
  for(let i=0; i<canvas.width; i+=20) {
601
  ctx.moveTo(i, 0);