Opera8 commited on
Commit
a40111a
·
verified ·
1 Parent(s): 6dfc9b0

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +23 -32
index.html CHANGED
@@ -37,7 +37,7 @@
37
  @keyframes pulse-soft { 0%, 100% { opacity: 1; } 50% { opacity: 0.7; } }
38
  @keyframes bounce { 0%, 20%, 50%, 80%, 100% {transform: translateY(0);} 40% {transform: translateY(-15px);} 60% {transform: translateY(-7px);} }
39
 
40
- /* PODCAST STUDIO VIEW EXACTLY AS ORIGINAL */
41
  .podcast-studio-container { width: 100%; animation: fadeIn 0.5s ease-out; }
42
  .podcast-studio-container .form-group-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 1.2rem; }
43
  .podcast-studio-container #project-speakers-container { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 1.5rem; text-align: center; }
@@ -94,7 +94,6 @@
94
  .podcast-studio-container .loading-state-wrapper .loading-text { font-size: 0.85em; font-weight: 600; color: var(--accent-primary); white-space: nowrap; transition: all 0.3s; }
95
  .podcast-studio-container .turn-retry-btn { font-family: var(--app-font); font-size: 0.85em; font-weight: 600; background: none; border: 1px solid var(--input-border); color: var(--text-secondary); padding: 0.4rem 0.8rem; border-radius: var(--radius-btn); cursor: pointer; transition: var(--transition-smooth); margin-right: auto; display: flex; align-items: center; gap: 6px; }
96
  .podcast-studio-container .turn-retry-btn:hover { border-color: var(--accent-secondary); color: var(--accent-secondary); background: var(--accent-secondary-glow); }
97
- .podcast-studio-container .turn-retry-btn svg { width: 16px; height: 16px; fill: currentColor; }
98
  .podcast-studio-container .replace-success-message, .podcast-studio-container .main-update-message { font-family: var(--app-font); font-size: 0.85em; font-weight: 600; padding: 0.4rem 0.8rem; border-radius: var(--radius-btn); white-space: nowrap; display: none; align-items: center; justify-content: center; margin-right: auto; }
99
  .podcast-studio-container .replace-success-message { background-color: var(--accent-secondary-glow); color: var(--accent-secondary); }
100
  .podcast-studio-container .main-update-message { background: linear-gradient(90deg, #e6fffa, #b2f5ea); color: #2c7a7b; border: 1px solid #81e6d9; box-shadow: 0 2px 5px rgba(0,0,0,0.05); }
@@ -272,7 +271,7 @@
272
  <div class="form-group">
273
  <label for="text-input-standard">📝 متن اصلی</label>
274
  <textarea id="text-input-standard" rows="5" placeholder="متن خود را برای تبدیل به گفتار اینجا وارد کنید..."></textarea>
275
- <div class="char-counter-wrapper"><span id="char-count">0</span> نویسه</div>
276
  </div>
277
  <div class="form-group">
278
  <label for="prompt-input-standard">🗣️ توصیف لحن و احساس (اختیاری)</label>
@@ -416,7 +415,7 @@
416
  </div>
417
  </section>
418
 
419
- <footer class="site-footer"><p>&copy; 1404 - تمام حقوق برای Ai Sada محفوظ است.</p></footer>
420
  </div>
421
 
422
  <!-- ======================================================================= -->
@@ -443,7 +442,7 @@ document.addEventListener('DOMContentLoaded', () => {
443
  let isMainSelectorAction = false;
444
  let currentPodcastMode = null;
445
 
446
- // لیست کامل و اصلی گویندگان به همراه 4 فایل صوتی و متن
447
  const allSpeakers =[
448
  { id: "Charon", name: "شهاب (مرد)", gender: "male", desc: "صدایی قدرمند و رسا", imgUrl: "https://uploadkon.ir/uploads/a18705_25IMG-۲۰۲۵۰۷۰۵-۱۱۰۵۴۹.jpg", samples:["https://uploadkon.ir/uploads/c17c06_26شهاب-یک-2-.mp3", "https://uploadkon.ir/uploads/af0d06_26شهاب-دو-2-.mp3", "https://uploadkon.ir/uploads/9e2806_26شهاب-سه-2-.mp3", "https://uploadkon.ir/uploads/35bd06_26شهاب-چهار-2-.mp3"], sampleTexts:["", "", "هاهاها ﺗﺒﺪﯾﻞ متن (خنده زیاد) شما ﺑﻪ ﺻﺪﺍﯾﯽ ﮐﻪ ﻫﻤﺪﻟﯽ ﻭ ﺩﺭﮎ ﺭﺍ ﺑﺮﻣﯽ‌ﺍﻧﮕﯿﺰﺩ.(خنده)", "ﺗﺒﺪﯾﻞ ﻣﺘﻦ ﺷﻤﺎﺑﻪ ﺻﺪﺍﯾﯽ ﮐﻪ ﻫﻤﺪﻟﯽ ﻭ ﺩﺭﮎ ﺭﺍ ﺑﺮﻣﯽ‌ﺍﻧﮕﯿﺰﺩ.(متن با صدای ترس و لرز بخون)"] },
449
  { id: "Zephyr", name: "آوا (زن)", gender: "female", desc: "لطیف و دلنشین", imgUrl: "https://uploadkon.ir/uploads/029605_25IMG-۲۰۲۵۰۷۰۵-۱۱۱۲۵۲.jpg", samples:["https://uploadkon.ir/uploads/920e06_26آوا-یک-2-.mp3", "https://uploadkon.ir/uploads/f50c06_26آوا-دو-2-.mp3", "https://uploadkon.ir/uploads/bc8e06_26آوا-سه-2-.mp3", "https://uploadkon.ir/uploads/1b2e06_26آوا-چهار-2-.mp3"], sampleTexts:["", "", "هاهاها ﺗﺒﺪﯾﻞ ﻣﺘﻦ ﺷﻤﺎ(خنده زیاد) ﺑﻪ ﺻﺪﺍﯾﯽ ﮐﻪ ﻫﻤﺪﻟﯽ ﻭ ﺩﺭﮎ ﺭﺍ ﺑﺮﻣﯽ‌ﺍﻧﮕﯿﺰﺩ.(خنده)", "وای ﺗﺒﺪﯾﻞ ﻣﺘﻦ ﺷﻤﺎﺑﻪ ﺻﺪﺍﯾﯽ ﮐﻪ ﻫﻤﺪﻟﯽ ﻭ ﺩﺭﮎ ﺭﺍ ﺑﺮﻣﯽ‌ﺍﻧﮕﯿﺰﺩ.(با تعجب و هیجان زیاد)"] },
@@ -763,7 +762,7 @@ document.addEventListener('DOMContentLoaded', () => {
763
  </div>
764
  <button type="button" id="clear-history-btn-podcast">
765
  <svg viewBox="0 0 24 24"><path d="M19,4H15.5L14.5,3H9.5L8.5,4H5V6H19M6,19A2,2 0 0,0 8,21H16A2,2 0 0,0 18,19V7H6V19Z"></path></svg>
766
- حذف کامل پروژه و شروع مجدد
767
  </button>
768
  `;
769
  container.appendChild(studioContainer);
@@ -821,36 +820,20 @@ document.addEventListener('DOMContentLoaded', () => {
821
  const turnDiv = document.createElement('div');
822
  turnDiv.className = 'script-turn';
823
  const turnIndex = container.children.length;
824
-
825
  turnDiv.innerHTML = `
826
- <div class="turn-speaker-selector">
827
- <div class="custom-select-container" data-selected-id="${speakerId}">
828
- <div class="custom-select-trigger"></div>
829
- <div class="custom-select-options"></div>
830
- </div>
831
- </div>
832
  <div class="turn-content">
833
  <textarea>${text || ''}</textarea>
834
  <div class="turn-player-container">
835
- <button type="button" class="turn-play-btn">
836
- <svg viewBox="0 0 24 24" class="play-icon"><path d="M8 5v14l11-7z"></path></svg>
837
- <svg viewBox="0 0 24 24" class="pause-icon"><path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"></path></svg>
838
- </button>
839
  <audio class="turn-audio" style="display:none;"></audio>
840
- <div class="loading-state-wrapper" style="display:none;">
841
- <div class="spinner"></div>
842
- <span class="loading-text">در حال جایگزینی...</span>
843
- </div>
844
- <button type="button" class="turn-retry-btn">
845
- <svg viewBox="0 0 24 24"><path d="M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"></path></svg>
846
- جایگزین قطعه
847
- </button>
848
- <span class="replace-success-message">فایل جدید جایگزین شد</span>
849
  <span class="main-update-message">فایل اصلی بروز شد</span>
850
  </div>
851
  </div>
852
  <button type="button" class="remove-turn-btn" title="حذف نوبت">×</button>`;
853
-
854
  container.appendChild(turnDiv);
855
 
856
  turnDiv.querySelector('textarea').addEventListener('input', triggerSave);
@@ -890,7 +873,7 @@ document.addEventListener('DOMContentLoaded', () => {
890
  async function initiateAiPodcastGeneration(userText) {
891
  hideModal(longTextModal);
892
  await clearProjectState();
893
- activePodcastSpeakers = [];
894
  podcastMasterAudioBlobs =[];
895
 
896
  showLoadingState(mainOutputSection, "در حال اتصال به هوش مصنوعی...");
@@ -1303,9 +1286,16 @@ document.addEventListener('DOMContentLoaded', () => {
1303
 
1304
  (function() {
1305
  const form = document.getElementById('standard-tts-form'); if (!form) return;
1306
- const textInput = form.querySelector('#text-input-standard'), promptInput = form.querySelector('#prompt-input-standard'), generateBtn = form.querySelector('#generate-btn-standard'), btnText = generateBtn.querySelector('.btn-text'), btnSpinner = generateBtn.querySelector('.spinner'), outputSection = document.getElementById('output-section-standard'), statusMessage = outputSection.querySelector('#status-message-standard'), loadingAnimation = outputSection.querySelector('#loading-animation-wrapper-standard'), playerContent = outputSection.querySelector('#audio-player-content-standard'), charCount = form.querySelector('#char-count');
1307
 
1308
- textInput.addEventListener('input', () => { charCount.textContent = textInput.value.length.toLocaleString('fa-IR'); });
 
 
 
 
 
 
 
1309
 
1310
  const showResultState = (isSuccess, msg = '') => {
1311
  loadingAnimation.style.display = 'none';
@@ -1355,7 +1345,8 @@ document.addEventListener('DOMContentLoaded', () => {
1355
  })();
1356
 
1357
  // Events
1358
- function setupEventListeners() {[changeSpeakerBtn, selectedSpeakerCard].forEach(el => el && el.addEventListener('click', () => { isMainSelectorAction = true; createSpeakerCardsInModal(); showModal(speakerModal); }));
 
1359
  document.querySelectorAll('.modal-overlay').forEach(o => o.addEventListener('click', (e) => (e.target === o) && hideModal(o)));
1360
  document.querySelectorAll('.close-modal-btn').forEach(b => b.addEventListener('click', () => hideModal(b.closest('.modal-overlay'))));
1361
 
@@ -1410,4 +1401,4 @@ document.addEventListener('DOMContentLoaded', () => {
1410
  });
1411
  </script>
1412
  </body>
1413
- </html>
 
37
  @keyframes pulse-soft { 0%, 100% { opacity: 1; } 50% { opacity: 0.7; } }
38
  @keyframes bounce { 0%, 20%, 50%, 80%, 100% {transform: translateY(0);} 40% {transform: translateY(-15px);} 60% {transform: translateY(-7px);} }
39
 
40
+ /* PODCAST STUDIO VIEW */
41
  .podcast-studio-container { width: 100%; animation: fadeIn 0.5s ease-out; }
42
  .podcast-studio-container .form-group-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 1.2rem; }
43
  .podcast-studio-container #project-speakers-container { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 1.5rem; text-align: center; }
 
94
  .podcast-studio-container .loading-state-wrapper .loading-text { font-size: 0.85em; font-weight: 600; color: var(--accent-primary); white-space: nowrap; transition: all 0.3s; }
95
  .podcast-studio-container .turn-retry-btn { font-family: var(--app-font); font-size: 0.85em; font-weight: 600; background: none; border: 1px solid var(--input-border); color: var(--text-secondary); padding: 0.4rem 0.8rem; border-radius: var(--radius-btn); cursor: pointer; transition: var(--transition-smooth); margin-right: auto; display: flex; align-items: center; gap: 6px; }
96
  .podcast-studio-container .turn-retry-btn:hover { border-color: var(--accent-secondary); color: var(--accent-secondary); background: var(--accent-secondary-glow); }
 
97
  .podcast-studio-container .replace-success-message, .podcast-studio-container .main-update-message { font-family: var(--app-font); font-size: 0.85em; font-weight: 600; padding: 0.4rem 0.8rem; border-radius: var(--radius-btn); white-space: nowrap; display: none; align-items: center; justify-content: center; margin-right: auto; }
98
  .podcast-studio-container .replace-success-message { background-color: var(--accent-secondary-glow); color: var(--accent-secondary); }
99
  .podcast-studio-container .main-update-message { background: linear-gradient(90deg, #e6fffa, #b2f5ea); color: #2c7a7b; border: 1px solid #81e6d9; box-shadow: 0 2px 5px rgba(0,0,0,0.05); }
 
271
  <div class="form-group">
272
  <label for="text-input-standard">📝 متن اصلی</label>
273
  <textarea id="text-input-standard" rows="5" placeholder="متن خود را برای تبدیل به گفتار اینجا وارد کنید..."></textarea>
274
+ <div class="char-counter-wrapper"><span id="char-count">0</span> / <span id="char-max">80000</span> نویسه</div>
275
  </div>
276
  <div class="form-group">
277
  <label for="prompt-input-standard">🗣️ توصیف لحن و احساس (اختیاری)</label>
 
415
  </div>
416
  </section>
417
 
418
+ <footer class="site-footer"><p>&copy; 1404 - تمام حقوق برای <a href="#">Ai Sada</a> محفوظ است.</p></footer>
419
  </div>
420
 
421
  <!-- ======================================================================= -->
 
442
  let isMainSelectorAction = false;
443
  let currentPodcastMode = null;
444
 
445
+ // دریافت کامل آرایه اسپیکرها با ۴ فایل و ۴ متن از کد اصلی
446
  const allSpeakers =[
447
  { id: "Charon", name: "شهاب (مرد)", gender: "male", desc: "صدایی قدرمند و رسا", imgUrl: "https://uploadkon.ir/uploads/a18705_25IMG-۲۰۲۵۰۷۰۵-۱۱۰۵۴۹.jpg", samples:["https://uploadkon.ir/uploads/c17c06_26شهاب-یک-2-.mp3", "https://uploadkon.ir/uploads/af0d06_26شهاب-دو-2-.mp3", "https://uploadkon.ir/uploads/9e2806_26شهاب-سه-2-.mp3", "https://uploadkon.ir/uploads/35bd06_26شهاب-چهار-2-.mp3"], sampleTexts:["", "", "هاهاها ﺗﺒﺪﯾﻞ متن (خنده زیاد) شما ﺑﻪ ﺻﺪﺍﯾﯽ ﮐﻪ ﻫﻤﺪﻟﯽ ﻭ ﺩﺭﮎ ﺭﺍ ﺑﺮﻣﯽ‌ﺍﻧﮕﯿﺰﺩ.(خنده)", "ﺗﺒﺪﯾﻞ ﻣﺘﻦ ﺷﻤﺎﺑﻪ ﺻﺪﺍﯾﯽ ﮐﻪ ﻫﻤﺪﻟﯽ ﻭ ﺩﺭﮎ ﺭﺍ ﺑﺮﻣﯽ‌ﺍﻧﮕﯿﺰﺩ.(متن با صدای ترس و لرز بخون)"] },
448
  { id: "Zephyr", name: "آوا (زن)", gender: "female", desc: "لطیف و دلنشین", imgUrl: "https://uploadkon.ir/uploads/029605_25IMG-۲۰۲۵۰۷۰۵-۱۱۱۲۵۲.jpg", samples:["https://uploadkon.ir/uploads/920e06_26آوا-یک-2-.mp3", "https://uploadkon.ir/uploads/f50c06_26آوا-دو-2-.mp3", "https://uploadkon.ir/uploads/bc8e06_26آوا-سه-2-.mp3", "https://uploadkon.ir/uploads/1b2e06_26آوا-چهار-2-.mp3"], sampleTexts:["", "", "هاهاها ﺗﺒﺪﯾﻞ ﻣﺘﻦ ﺷﻤﺎ(خنده زیاد) ﺑﻪ ﺻﺪﺍﯾﯽ ﮐﻪ ﻫﻤﺪﻟﯽ ﻭ ﺩﺭﮎ ﺭﺍ ﺑﺮﻣﯽ‌ﺍﻧﮕﯿﺰﺩ.(خنده)", "وای ﺗﺒﺪﯾﻞ ﻣﺘﻦ ﺷﻤﺎﺑﻪ ﺻﺪﺍﯾﯽ ﮐﻪ ﻫﻤﺪﻟﯽ ﻭ ﺩﺭﮎ ﺭﺍ ﺑﺮﻣﯽ‌ﺍﻧﮕﯿﺰﺩ.(با تعجب و هیجان زیاد)"] },
 
762
  </div>
763
  <button type="button" id="clear-history-btn-podcast">
764
  <svg viewBox="0 0 24 24"><path d="M19,4H15.5L14.5,3H9.5L8.5,4H5V6H19M6,19A2,2 0 0,0 8,21H16A2,2 0 0,0 18,19V7H6V19Z"></path></svg>
765
+ حذف کامل پروژه و بازگشت
766
  </button>
767
  `;
768
  container.appendChild(studioContainer);
 
820
  const turnDiv = document.createElement('div');
821
  turnDiv.className = 'script-turn';
822
  const turnIndex = container.children.length;
 
823
  turnDiv.innerHTML = `
824
+ <div class="turn-speaker-selector"><div class="custom-select-container" data-selected-id="${speakerId}"><div class="custom-select-trigger"></div><div class="custom-select-options"></div></div></div>
 
 
 
 
 
825
  <div class="turn-content">
826
  <textarea>${text || ''}</textarea>
827
  <div class="turn-player-container">
828
+ <button type="button" class="turn-play-btn"><svg viewBox="0 0 24 24" class="play-icon"><path d="M8 5v14l11-7z"></path></svg><svg viewBox="0 0 24 24" class="pause-icon"><path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"></path></svg></button>
 
 
 
829
  <audio class="turn-audio" style="display:none;"></audio>
830
+ <div class="loading-state-wrapper" style="display:none;"><div class="spinner"></div><span class="loading-text">در حال جایگزینی...</span></div>
831
+ <button type="button" class="turn-retry-btn"><svg viewBox="0 0 24 24"><path d="M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"></path></svg> جایگزین قطعه</button>
832
+ <span class="replace-success-message">جایگزین شد</span>
 
 
 
 
 
 
833
  <span class="main-update-message">فایل اصلی بروز شد</span>
834
  </div>
835
  </div>
836
  <button type="button" class="remove-turn-btn" title="حذف نوبت">×</button>`;
 
837
  container.appendChild(turnDiv);
838
 
839
  turnDiv.querySelector('textarea').addEventListener('input', triggerSave);
 
873
  async function initiateAiPodcastGeneration(userText) {
874
  hideModal(longTextModal);
875
  await clearProjectState();
876
+ activePodcastSpeakers =[];
877
  podcastMasterAudioBlobs =[];
878
 
879
  showLoadingState(mainOutputSection, "در حال اتصال به هوش مصنوعی...");
 
1286
 
1287
  (function() {
1288
  const form = document.getElementById('standard-tts-form'); if (!form) return;
1289
+ const textInput = form.querySelector('#text-input-standard'), promptInput = form.querySelector('#prompt-input-standard'), generateBtn = form.querySelector('#generate-btn-standard'), btnText = generateBtn.querySelector('.btn-text'), btnSpinner = generateBtn.querySelector('.spinner'), outputSection = document.getElementById('output-section-standard'), statusMessage = outputSection.querySelector('#status-message-standard'), loadingAnimation = outputSection.querySelector('#loading-animation-wrapper-standard'), playerContent = outputSection.querySelector('#audio-player-content-standard'), charCount = form.querySelector('#char-count'), charMax = form.querySelector('#char-max');
1290
 
1291
+ const MAX_CHARS = 80000;
1292
+ if(charMax) charMax.textContent = MAX_CHARS.toLocaleString('fa-IR');
1293
+
1294
+ textInput.addEventListener('input', () => {
1295
+ const len = textInput.value.length;
1296
+ charCount.textContent = len.toLocaleString('fa-IR');
1297
+ charCount.style.color = len > MAX_CHARS ? 'red' : 'var(--accent-primary)';
1298
+ });
1299
 
1300
  const showResultState = (isSuccess, msg = '') => {
1301
  loadingAnimation.style.display = 'none';
 
1345
  })();
1346
 
1347
  // Events
1348
+ function setupEventListeners() {
1349
+ [changeSpeakerBtn, selectedSpeakerCard].forEach(el => el && el.addEventListener('click', () => { isMainSelectorAction = true; createSpeakerCardsInModal(); showModal(speakerModal); }));
1350
  document.querySelectorAll('.modal-overlay').forEach(o => o.addEventListener('click', (e) => (e.target === o) && hideModal(o)));
1351
  document.querySelectorAll('.close-modal-btn').forEach(b => b.addEventListener('click', () => hideModal(b.closest('.modal-overlay'))));
1352
 
 
1401
  });
1402
  </script>
1403
  </body>
1404
+ </html>