Hamed744 commited on
Commit
e60f4e8
·
verified ·
1 Parent(s): 5cdc6dd

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +31 -34
index.html CHANGED
@@ -3,7 +3,7 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Alpha TTS - رابط کاربری هوشمند</title>
7
  <style>
8
  @import url('https://fonts.googleapis.com/css2?family=Vazirmatn:wght@300;400;500;700;800&display=swap');
9
 
@@ -50,16 +50,16 @@
50
  textarea, input[type="text"] { width: 100%; padding: 1rem; border-radius: var(--radius-input); border: 2px solid var(--app-border-color); background-color: var(--app-input-bg); box-shadow: none; font-family: var(--app-font); font-size: 1rem; box-sizing: border-box; transition: all 0.2s ease-in-out; }
51
  textarea:focus, input[type="text"]:focus { outline: none; border-color: var(--app-button-bg); box-shadow: 0 0 0 3px rgba(95, 39, 205, 0.2); background-color: #fff; }
52
 
53
- /* --- **بخش جدید: نمایش گوینده منتخب** --- */
54
  #selected-speaker-display { text-align: center; }
55
  #selected-speaker-card { display: inline-flex; align-items: center; background: #fff; border-radius: 99px; padding: 10px; box-shadow: 0 5px 20px rgba(0,0,0,0.1); border: 2px solid var(--app-border-color); }
56
- #selected-speaker-card img { width: 80px; height: 80px; border-radius: 50%; object-fit: cover; margin-left: 15px; }
57
  #selected-speaker-info h3 { margin: 0; font-size: 1.4em; }
58
  #selected-speaker-info p { margin: 5px 0 0; color: var(--app-text-secondary); font-size: 0.9em; }
59
  #change-speaker-btn { display: block; margin: 1rem auto 0; padding: 8px 20px; border-radius: 8px; background-color: var(--app-input-bg); border: 1px solid var(--app-border-color); cursor: pointer; font-family: var(--app-font); font-weight: 500; transition: all 0.2s ease; }
60
  #change-speaker-btn:hover { background-color: #e9ecef; border-color: #ced4da; }
61
 
62
- /* --- **بخش جدید: مودال گالری گویندگان** --- */
63
  #speaker-modal { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,0.5); backdrop-filter: blur(5px); display: none; align-items: center; justify-content: center; z-index: 1000; opacity: 0; transition: opacity 0.3s ease; }
64
  #speaker-modal.visible { display: flex; opacity: 1; }
65
  .modal-content { background: #fff; padding: 2rem; border-radius: var(--radius-card); width: 90%; max-width: 700px; max-height: 80vh; overflow-y: auto; transform: scale(0.95); transition: transform 0.3s ease; }
@@ -75,7 +75,7 @@
75
  .speaker-card .speaker-visual { border: 3px solid transparent; border-radius: var(--radius-card); overflow: hidden; text-align: center; box-shadow: 0 4px 10px rgba(0,0,0,0.05); position: relative; background-color: #fff; }
76
  .speaker-card:hover .speaker-visual { transform: translateY(-3px); box-shadow: 0 6px 15px rgba(0,0,0,0.1); }
77
  .speaker-card input[type="radio"] { display: none; }
78
- .speaker-card img { width: 100%; height: 120px; object-fit: cover; display: block; }
79
  .speaker-card .speaker-name { padding: 0.7rem 0.5rem; font-weight: 500; font-size: 0.9em; }
80
  .speaker-card input[type="radio"]:checked + .speaker-visual { border-color: var(--app-button-bg); box-shadow: var(--speaker-selected-glow); }
81
 
@@ -141,7 +141,6 @@
141
  </main>
142
  </div>
143
 
144
- <!-- Modal برای انتخاب گوینده -->
145
  <div id="speaker-modal">
146
  <div class="modal-content">
147
  <div class="modal-header">
@@ -152,12 +151,10 @@
152
  </div>
153
  </div>
154
 
155
- <!-- این فیلد مخفی برای نگهداری مقدار انتخاب شده است -->
156
- <input type="hidden" id="selected_speaker_id" value="Charon">
157
 
158
  <script>
159
  document.addEventListener('DOMContentLoaded', () => {
160
- // --- پیکربندی و متغیرها ---
161
  const HF_SPACE_URL = "https://hamed744-ttspro.hf.space";
162
  const JOIN_QUEUE_URL = `${HF_SPACE_URL}/gradio_api/queue/join`;
163
  const GET_DATA_URL_BASE = `${HF_SPACE_URL}/gradio_api/queue/data`;
@@ -167,8 +164,7 @@
167
  const speakers = [
168
  { id: "Charon", name: "شهاب (مرد)" }, { id: "Zephyr", name: "آوا (زن)" }, { id: "Achird", name: "نوید (مرد)" }, { id: "Zubenelgenubi", name: "رویا (زن)" }, { id: "Vindemiatrix", name: "کیان (مرد)" }, { id: "Sadachbia", name: "پریسا (زن)" }, { id: "Sadaltager", name: "آرش (مرد)" }, { id: "Sulafat", name: "شبنم (زن)" }, { id: "Laomedeia", name: "سهیل (م��د)" }, { id: "Achernar", name: "مریم (زن)" }, { id: "Alnilam", name: "بهرام (مرد)" }, { id: "Schedar", name: "نگار (زن)" }, { id: "Gacrux", name: "فرید (مرد)" }, { id: "Pulcherrima", name: "سارا (زن)" }, { id: "Umbriel", name: "مانی (مرد)" }, { id: "Algieba", name: "آناهیتا (زن)" }, { id: "Despina", name: "دلنواز (زن)" }, { id: "Erinome", name: "رسا (مرد)" }, { id: "Algenib", name: "امید (مرد)" }, { id: "Rasalthgeti", name: "الهه (زن)" }, { id: "Orus", name: "بردیا (مرد)" }, { id: "Aoede", name: "ترانه (زن)" }, { id: "Callirrhoe", name: "نیما (مرد)" }, { id: "Autonoe", name: "هستی (زن)" }, { id: "Enceladus", name: "کامیار (مرد)" }, { id: "Iapetus", name: "ستاره (زن)" }, { id: "Puck", name: "پویا (مرد)" }, { id: "Kore", name: "مهتاب (زن)" }, { id: "Fenrir", name: "سام (مرد)" }, { id: "Leda", name: "لیدا (زن)" }
169
  ];
170
-
171
- // --- عناصر DOM ---
172
  const form = document.getElementById('tts-form');
173
  const textInput = document.getElementById('text-input');
174
  const promptInput = document.getElementById('prompt-input');
@@ -177,41 +173,48 @@
177
  const generateBtn = document.getElementById('generate-btn');
178
  const statusMessage = document.getElementById('status-message');
179
  const audioPlayer = document.getElementById('audio-player');
180
- const selectedSpeakerIdInput = document.getElementById('selected_speaker_id');
 
181
  const speakerModal = document.getElementById('speaker-modal');
182
  const changeSpeakerBtn = document.getElementById('change-speaker-btn');
183
  const closeModalBtn = document.querySelector('.close-modal-btn');
184
- const speakerGrid = document.getElementById('speaker-grid');
185
- const selectedSpeakerImg = document.getElementById('selected-speaker-img');
186
- const selectedSpeakerName = document.getElementById('selected-speaker-name');
187
 
188
- // --- توابع ---
189
  function getSpeakerById(id) {
190
  return speakers.find(s => s.id === id);
191
  }
192
 
193
  function getImageUrl(speaker, index) {
194
- const gender = speaker.name.includes('(مرد)') ? 'men' : 'women';
195
- return `https://randomuser.me/api/portraits/thumb/${gender}/${index % 100}.jpg`;
 
 
 
196
  }
197
 
198
  function updateSelectedSpeakerDisplay(speakerId) {
199
  const speaker = getSpeakerById(speakerId);
200
  if (speaker) {
201
- selectedSpeakerImg.src = getImageUrl(speaker, speakers.findIndex(s => s.id === speakerId));
202
- selectedSpeakerName.textContent = speaker.name;
203
- selectedSpeakerIdInput.value = speaker.id;
 
204
  }
205
  }
206
 
207
- function createSpeakerCards() {
 
208
  speakers.forEach((speaker, index) => {
209
  const card = document.createElement('label');
210
  card.className = 'speaker-card';
211
- card.setAttribute('for', `speaker-${speaker.id}`);
 
 
212
 
213
  card.innerHTML = `
214
- <input type="radio" name="speaker" value="${speaker.id}" id="speaker-${speaker.id}">
215
  <div class="speaker-visual">
216
  <img src="${getImageUrl(speaker, index)}" alt="عکس گوینده ${speaker.name}" loading="lazy">
217
  <div class="speaker-name">${speaker.name}</div>
@@ -220,19 +223,15 @@
220
 
221
  card.addEventListener('click', () => {
222
  updateSelectedSpeakerDisplay(speaker.id);
223
- // برای بستن خودکار مودال بعد از انتخاب
224
  setTimeout(() => speakerModal.classList.remove('visible'), 100);
225
  });
226
 
227
- speakerGrid.appendChild(card);
228
  });
229
  }
230
 
231
- // --- رویدادهای مودال ---
232
  changeSpeakerBtn.addEventListener('click', () => {
233
- // به‌روزرسانی انتخاب فعلی در مودال
234
- const currentSelected = document.querySelector(`input[name="speaker"][value="${selectedSpeakerIdInput.value}"]`);
235
- if(currentSelected) currentSelected.checked = true;
236
  speakerModal.classList.add('visible');
237
  });
238
  closeModalBtn.addEventListener('click', () => speakerModal.classList.remove('visible'));
@@ -255,7 +254,7 @@
255
  const text = textInput.value;
256
  const prompt = promptInput.value;
257
  const temperature = parseFloat(tempSlider.value);
258
- const selectedSpeaker = selectedSpeakerIdInput.value; // از فیلد مخفی می‌خوانیم
259
  const sessionHash = Math.random().toString(36).substring(2);
260
 
261
  if (!text.trim()) {
@@ -340,9 +339,7 @@
340
  }
341
  }
342
 
343
- // --- راه‌اندازی اولیه ---
344
- createSpeakerCards();
345
- updateSelectedSpeakerDisplay(selectedSpeakerIdInput.value); // نمایش گوینده پیش‌فرض
346
  form.addEventListener('submit', generateAudio);
347
  });
348
  </script>
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Alpha TTS - رابط کاربری هوشمند با عکس</title>
7
  <style>
8
  @import url('https://fonts.googleapis.com/css2?family=Vazirmatn:wght@300;400;500;700;800&display=swap');
9
 
 
50
  textarea, input[type="text"] { width: 100%; padding: 1rem; border-radius: var(--radius-input); border: 2px solid var(--app-border-color); background-color: var(--app-input-bg); box-shadow: none; font-family: var(--app-font); font-size: 1rem; box-sizing: border-box; transition: all 0.2s ease-in-out; }
51
  textarea:focus, input[type="text"]:focus { outline: none; border-color: var(--app-button-bg); box-shadow: 0 0 0 3px rgba(95, 39, 205, 0.2); background-color: #fff; }
52
 
53
+ /* --- نمایش گوینده منتخب --- */
54
  #selected-speaker-display { text-align: center; }
55
  #selected-speaker-card { display: inline-flex; align-items: center; background: #fff; border-radius: 99px; padding: 10px; box-shadow: 0 5px 20px rgba(0,0,0,0.1); border: 2px solid var(--app-border-color); }
56
+ #selected-speaker-card img { width: 80px; height: 80px; border-radius: 50%; object-fit: cover; margin-left: 15px; background-color: #eee; }
57
  #selected-speaker-info h3 { margin: 0; font-size: 1.4em; }
58
  #selected-speaker-info p { margin: 5px 0 0; color: var(--app-text-secondary); font-size: 0.9em; }
59
  #change-speaker-btn { display: block; margin: 1rem auto 0; padding: 8px 20px; border-radius: 8px; background-color: var(--app-input-bg); border: 1px solid var(--app-border-color); cursor: pointer; font-family: var(--app-font); font-weight: 500; transition: all 0.2s ease; }
60
  #change-speaker-btn:hover { background-color: #e9ecef; border-color: #ced4da; }
61
 
62
+ /* --- مودال گالری گویندگان --- */
63
  #speaker-modal { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,0.5); backdrop-filter: blur(5px); display: none; align-items: center; justify-content: center; z-index: 1000; opacity: 0; transition: opacity 0.3s ease; }
64
  #speaker-modal.visible { display: flex; opacity: 1; }
65
  .modal-content { background: #fff; padding: 2rem; border-radius: var(--radius-card); width: 90%; max-width: 700px; max-height: 80vh; overflow-y: auto; transform: scale(0.95); transition: transform 0.3s ease; }
 
75
  .speaker-card .speaker-visual { border: 3px solid transparent; border-radius: var(--radius-card); overflow: hidden; text-align: center; box-shadow: 0 4px 10px rgba(0,0,0,0.05); position: relative; background-color: #fff; }
76
  .speaker-card:hover .speaker-visual { transform: translateY(-3px); box-shadow: 0 6px 15px rgba(0,0,0,0.1); }
77
  .speaker-card input[type="radio"] { display: none; }
78
+ .speaker-card img { width: 100%; height: 120px; object-fit: cover; display: block; background-color: #eee; /* Placeholder color */ }
79
  .speaker-card .speaker-name { padding: 0.7rem 0.5rem; font-weight: 500; font-size: 0.9em; }
80
  .speaker-card input[type="radio"]:checked + .speaker-visual { border-color: var(--app-button-bg); box-shadow: var(--speaker-selected-glow); }
81
 
 
141
  </main>
142
  </div>
143
 
 
144
  <div id="speaker-modal">
145
  <div class="modal-content">
146
  <div class="modal-header">
 
151
  </div>
152
  </div>
153
 
154
+ <input type="hidden" id="selected_speaker_id_storage" value="Charon">
 
155
 
156
  <script>
157
  document.addEventListener('DOMContentLoaded', () => {
 
158
  const HF_SPACE_URL = "https://hamed744-ttspro.hf.space";
159
  const JOIN_QUEUE_URL = `${HF_SPACE_URL}/gradio_api/queue/join`;
160
  const GET_DATA_URL_BASE = `${HF_SPACE_URL}/gradio_api/queue/data`;
 
164
  const speakers = [
165
  { id: "Charon", name: "شهاب (مرد)" }, { id: "Zephyr", name: "آوا (زن)" }, { id: "Achird", name: "نوید (مرد)" }, { id: "Zubenelgenubi", name: "رویا (زن)" }, { id: "Vindemiatrix", name: "کیان (مرد)" }, { id: "Sadachbia", name: "پریسا (زن)" }, { id: "Sadaltager", name: "آرش (مرد)" }, { id: "Sulafat", name: "شبنم (زن)" }, { id: "Laomedeia", name: "سهیل (م��د)" }, { id: "Achernar", name: "مریم (زن)" }, { id: "Alnilam", name: "بهرام (مرد)" }, { id: "Schedar", name: "نگار (زن)" }, { id: "Gacrux", name: "فرید (مرد)" }, { id: "Pulcherrima", name: "سارا (زن)" }, { id: "Umbriel", name: "مانی (مرد)" }, { id: "Algieba", name: "آناهیتا (زن)" }, { id: "Despina", name: "دلنواز (زن)" }, { id: "Erinome", name: "رسا (مرد)" }, { id: "Algenib", name: "امید (مرد)" }, { id: "Rasalthgeti", name: "الهه (زن)" }, { id: "Orus", name: "بردیا (مرد)" }, { id: "Aoede", name: "ترانه (زن)" }, { id: "Callirrhoe", name: "نیما (مرد)" }, { id: "Autonoe", name: "هستی (زن)" }, { id: "Enceladus", name: "کامیار (مرد)" }, { id: "Iapetus", name: "ستاره (زن)" }, { id: "Puck", name: "پویا (مرد)" }, { id: "Kore", name: "مهتاب (زن)" }, { id: "Fenrir", name: "سام (مرد)" }, { id: "Leda", name: "لیدا (زن)" }
166
  ];
167
+
 
168
  const form = document.getElementById('tts-form');
169
  const textInput = document.getElementById('text-input');
170
  const promptInput = document.getElementById('prompt-input');
 
173
  const generateBtn = document.getElementById('generate-btn');
174
  const statusMessage = document.getElementById('status-message');
175
  const audioPlayer = document.getElementById('audio-player');
176
+
177
+ const selectedSpeakerIdStorage = document.getElementById('selected_speaker_id_storage'); // برای نگهداری مقدار
178
  const speakerModal = document.getElementById('speaker-modal');
179
  const changeSpeakerBtn = document.getElementById('change-speaker-btn');
180
  const closeModalBtn = document.querySelector('.close-modal-btn');
181
+ const speakerGridInModal = document.getElementById('speaker-grid'); // گرید داخل مودال
182
+ const selectedSpeakerImgDisplay = document.getElementById('selected-speaker-img'); // نمایش عکس اصلی
183
+ const selectedSpeakerNameDisplay = document.getElementById('selected-speaker-name'); // نمایش نام اصلی
184
 
 
185
  function getSpeakerById(id) {
186
  return speakers.find(s => s.id === id);
187
  }
188
 
189
  function getImageUrl(speaker, index) {
190
+ // از یک سرویس عکس پرتره رندوم استفاده می کنیم
191
+ // برای تنوع بیشتر، از یک اندیس متفاوت برای هر گوینده استفاده می کنیم
192
+ const gender = speaker.name.includes('(مرد)') ? 'men' : (speaker.name.includes('(زن)') ? 'women' : 'lego'); // اگر جنسیت مشخص نیست، از لگو استفاده می کنیم
193
+ const imageIndex = (index * 7 + 13) % 100; // یک فرمول ساده برای ایجاد تنوع در اندیس عکس
194
+ return `https://randomuser.me/api/portraits/${gender}/${imageIndex}.jpg`;
195
  }
196
 
197
  function updateSelectedSpeakerDisplay(speakerId) {
198
  const speaker = getSpeakerById(speakerId);
199
  if (speaker) {
200
+ const speakerIndex = speakers.findIndex(s => s.id === speakerId);
201
+ selectedSpeakerImgDisplay.src = getImageUrl(speaker, speakerIndex);
202
+ selectedSpeakerNameDisplay.textContent = speaker.name;
203
+ selectedSpeakerIdStorage.value = speaker.id; // ذخیره ID انتخاب شده
204
  }
205
  }
206
 
207
+ function createSpeakerCardsInModal() {
208
+ speakerGridInModal.innerHTML = ''; // پاک کردن گرید قبلی
209
  speakers.forEach((speaker, index) => {
210
  const card = document.createElement('label');
211
  card.className = 'speaker-card';
212
+ card.setAttribute('for', `modal-speaker-${speaker.id}`);
213
+
214
+ const isChecked = speaker.id === selectedSpeakerIdStorage.value ? 'checked' : '';
215
 
216
  card.innerHTML = `
217
+ <input type="radio" name="modal_speaker_selection" value="${speaker.id}" id="modal-speaker-${speaker.id}" ${isChecked}>
218
  <div class="speaker-visual">
219
  <img src="${getImageUrl(speaker, index)}" alt="عکس گوینده ${speaker.name}" loading="lazy">
220
  <div class="speaker-name">${speaker.name}</div>
 
223
 
224
  card.addEventListener('click', () => {
225
  updateSelectedSpeakerDisplay(speaker.id);
 
226
  setTimeout(() => speakerModal.classList.remove('visible'), 100);
227
  });
228
 
229
+ speakerGridInModal.appendChild(card);
230
  });
231
  }
232
 
 
233
  changeSpeakerBtn.addEventListener('click', () => {
234
+ createSpeakerCardsInModal(); // هر بار مودال باز می شود، کارت ها را با انتخاب فعلی می سازیم
 
 
235
  speakerModal.classList.add('visible');
236
  });
237
  closeModalBtn.addEventListener('click', () => speakerModal.classList.remove('visible'));
 
254
  const text = textInput.value;
255
  const prompt = promptInput.value;
256
  const temperature = parseFloat(tempSlider.value);
257
+ const selectedSpeaker = selectedSpeakerIdStorage.value; // از فیلد مخفی می‌خوانیم
258
  const sessionHash = Math.random().toString(36).substring(2);
259
 
260
  if (!text.trim()) {
 
339
  }
340
  }
341
 
342
+ updateSelectedSpeakerDisplay(selectedSpeakerIdStorage.value); // نمایش گوینده پیش‌فرض
 
 
343
  form.addEventListener('submit', generateAudio);
344
  });
345
  </script>