|
<!DOCTYPE html> |
|
<html lang="fa" dir="rtl"> |
|
<head> |
|
<meta charset="UTF-8"> |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
<title>Alpha TTS - نسخه Premium</title> |
|
<style> |
|
@import url('https://fonts.googleapis.com/css2?family=Vazirmatn:wght@300;400;500;700;800&display=swap'); |
|
|
|
:root { |
|
--app-font: 'Vazirmatn', sans-serif; |
|
--bg-color: #0d0f21; |
|
--panel-bg: rgba(26, 30, 56, 0.5); |
|
--panel-border: rgba(255, 255, 255, 0.15); |
|
--text-primary: #f0f4f9; |
|
--text-secondary: #a8b2d1; |
|
--accent-glow: #a77dfd; |
|
--accent-glow-rgb: 167, 125, 253; |
|
--button-bg: linear-gradient(135deg, rgba(167, 125, 253, 0.8) 0%, rgba(89, 97, 240, 0.8) 100%); |
|
--button-hover-bg: linear-gradient(135deg, rgba(167, 125, 253, 1) 0%, rgba(89, 97, 240, 1) 100%); |
|
--radius-card: 24px; |
|
--radius-input: 12px; |
|
} |
|
|
|
|
|
body { |
|
font-family: var(--app-font); |
|
direction: rtl; |
|
background-color: var(--bg-color); |
|
color: var(--text-primary); |
|
font-size: 16px; |
|
line-height: 1.7; |
|
margin: 0; |
|
padding: 40px 0; |
|
min-height: 100vh; |
|
-webkit-font-smoothing: antialiased; |
|
-moz-osx-font-smoothing: grayscale; |
|
overflow: hidden; |
|
position: relative; |
|
} |
|
|
|
body::before { |
|
content: ''; |
|
position: absolute; |
|
top: 0; |
|
left: 0; |
|
width: 100%; |
|
height: 100%; |
|
background: |
|
radial-gradient(circle at 15% 25%, rgba(var(--accent-glow-rgb), 0.2), transparent 40%), |
|
radial-gradient(circle at 85% 75%, rgba(89, 97, 240, 0.2), transparent 40%); |
|
animation: move-glow 20s infinite alternate; |
|
z-index: -1; |
|
} |
|
|
|
@keyframes move-glow { |
|
from { transform: translate(0, 0) scale(1); } |
|
to { transform: translate(50px, -50px) scale(1.2); } |
|
} |
|
|
|
.container { max-width: 800px; width: 95%; margin: 0 auto; z-index: 1; position: relative; } |
|
|
|
|
|
.main-panel { |
|
background: var(--panel-bg); |
|
border: 1px solid var(--panel-border); |
|
border-radius: var(--radius-card); |
|
backdrop-filter: blur(20px); |
|
-webkit-backdrop-filter: blur(20px); |
|
padding: 2rem 2.5rem; |
|
box-shadow: 0 15px 40px rgba(0, 0, 0, 0.3); |
|
} |
|
|
|
.app-header { text-align: center; margin-bottom: 3rem; } |
|
.app-header h1 { font-size: 3em; font-weight: 800; margin:0; text-shadow: 0 0 20px rgba(var(--accent-glow-rgb), 0.5); } |
|
.app-header p { font-size: 1.25em; color: var(--text-secondary); margin-top:0.5rem; } |
|
|
|
.form-group { margin-bottom: 2.5rem; } |
|
label { display: block; font-weight: 700; color: var(--text-primary); font-size: 1.1em; margin-bottom: 1rem; } |
|
textarea, input[type="text"] { |
|
width: 100%; |
|
padding: 1rem; |
|
border-radius: var(--radius-input); |
|
border: 1px solid var(--panel-border); |
|
background-color: rgba(0,0,0,0.2); |
|
box-shadow: none; |
|
font-family: var(--app-font); |
|
font-size: 1rem; |
|
box-sizing: border-box; |
|
color: var(--text-primary); |
|
transition: all 0.25s ease-in-out; |
|
} |
|
textarea:focus, input[type="text"]:focus { |
|
outline: none; |
|
border-color: var(--accent-glow); |
|
box-shadow: 0 0 15px rgba(var(--accent-glow-rgb), 0.3); |
|
background-color: rgba(0,0,0,0.3); |
|
} |
|
|
|
|
|
#selected-speaker-display { text-align: center; } |
|
#selected-speaker-card { display: inline-flex; align-items: center; background: rgba(0,0,0,0.2); border-radius: 99px; padding: 10px; border: 1px solid var(--panel-border); } |
|
#selected-speaker-card img { width: 70px; height: 70px; border-radius: 50%; object-fit: cover; margin-left: 15px; border: 3px solid rgba(255,255,255,0.5); } |
|
#selected-speaker-info h3 { margin: 0; font-size: 1.4em; font-weight: 700; } |
|
#selected-speaker-info p { margin: 5px 0 0; color: var(--text-secondary); font-size: 0.9em; } |
|
#change-speaker-btn { display: block; margin: 1.2rem auto 0; padding: 10px 24px; border-radius: var(--radius-input); background-color: rgba(255,255,255,0.1); border: 1px solid var(--panel-border); cursor: pointer; font-family: var(--app-font); font-weight: 500; color: var(--text-primary); transition: all 0.2s ease; } |
|
#change-speaker-btn:hover { background-color: rgba(255,255,255,0.2); border-color: rgba(255,255,255,0.3); transform: translateY(-2px); } |
|
|
|
|
|
#speaker-modal { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(13, 15, 33, 0.7); backdrop-filter: blur(10px); display: none; align-items: center; justify-content: center; z-index: 1000; opacity: 0; transition: opacity 0.3s ease; } |
|
#speaker-modal.visible { display: flex; opacity: 1; } |
|
.modal-content { background: var(--panel-bg); border: 1px solid var(--panel-border); padding: 2rem; border-radius: var(--radius-card); width: 90%; max-width: 700px; max-height: 85vh; overflow-y: auto; transform: scale(0.95); transition: transform 0.3s ease; } |
|
#speaker-modal.visible .modal-content { transform: scale(1); } |
|
.modal-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 1.5rem; padding-bottom: 1rem; border-bottom: 1px solid var(--panel-border); } |
|
.modal-header h2 { margin: 0; } |
|
.close-modal-btn { background: none; border: none; font-size: 2.2rem; cursor: pointer; color: var(--text-secondary); transition: color 0.2s ease, transform 0.2s ease; line-height: 1; } |
|
.close-modal-btn:hover { color: var(--text-primary); transform: rotate(90deg); } |
|
#speaker-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap: 1.5rem; } |
|
.speaker-card { cursor: pointer; text-align: center; } |
|
.speaker-card .speaker-visual { border: 3px solid transparent; border-radius: var(--radius-input); overflow: hidden; position: relative; background-color: rgba(0,0,0,0.2); transition: all 0.3s ease; } |
|
.speaker-card:hover .speaker-visual { transform: translateY(-5px); box-shadow: 0 8px 25px rgba(0,0,0,0.3); } |
|
.speaker-card input[type="radio"] { display: none; } |
|
.speaker-card img { width: 100%; height: 120px; object-fit: cover; display: block; filter: saturate(0.8); transition: filter 0.3s; } |
|
.speaker-card:hover img { filter: saturate(1); } |
|
.speaker-card .speaker-name { padding: 0.8rem 0.5rem; font-weight: 500; font-size: 0.95em; color: var(--text-secondary); transition: color 0.2s; } |
|
.speaker-card input[type="radio"]:checked + .speaker-visual { border-color: var(--accent-glow); box-shadow: 0 0 20px rgba(var(--accent-glow-rgb), 0.4); } |
|
.speaker-card input[type="radio"]:checked + .speaker-visual .speaker-name { color: var(--accent-glow); font-weight: 700; } |
|
|
|
|
|
.slider-container { display: flex; align-items: center; gap: 1.5rem; } |
|
input[type="range"] { flex-grow: 1; -webkit-appearance: none; appearance: none; width: 100%; height: 6px; background: rgba(0,0,0,0.3); border-radius: 5px; outline: none; } |
|
input[type="range"]::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 22px; height: 22px; background: var(--accent-glow); border-radius: 50%; cursor: pointer; box-shadow: 0 0 10px rgba(var(--accent-glow-rgb), 0.7); } |
|
input[type="range"]::-moz-range-thumb { width: 22px; height: 22px; background: var(--accent-glow); border-radius: 50%; cursor: pointer; box-shadow: 0 0 10px rgba(var(--accent-glow-rgb), 0.7); } |
|
#temperature-value { font-weight: 700; background-color: rgba(0,0,0,0.3); padding: 0.4rem 1rem; border-radius: 8px; border: 1px solid var(--panel-border); min-width: 45px; text-align: center; } |
|
#generate-btn { width: 100%; padding: 1rem 1.5rem; font-size: 1.25em; font-weight: 700; font-family: var(--app-font); background: var(--button-bg); color: white; border: none; border-radius: var(--radius-input); cursor: pointer; transition: all 0.3s ease; box-shadow: 0 5px 20px rgba(var(--accent-glow-rgb), 0.2); } |
|
#generate-btn:hover:not(:disabled) { background: var(--button-hover-bg); transform: translateY(-3px); box-shadow: 0 8px 25px rgba(var(--accent-glow-rgb), 0.4); } |
|
#generate-btn:disabled { background: rgba(107, 114, 128, 0.5); cursor: not-allowed; box-shadow: none; transform: none; } |
|
#output-section { margin-top: 2.5rem; padding: 2rem; min-height: 180px; display: flex; align-items: center; justify-content: center; flex-direction: column; gap: 1rem; border-radius: var(--radius-input); background: rgba(0,0,0,0.2); border: 1px solid var(--panel-border); } |
|
#status-message { font-weight: 500; color: var(--text-secondary); text-align: center; } |
|
#audio-player { width: 100%; margin-top: 1rem; display: none; } |
|
audio::-webkit-media-controls-panel { background-color: rgba(40, 45, 80, 0.8); } |
|
audio::-webkit-media-controls-play-button { color: var(--accent-glow); } |
|
audio::-webkit-media-controls-current-time-display, audio::-webkit-media-controls-time-remaining-display { color: var(--text-primary); } |
|
|
|
|
|
#premium-loader { display: none; flex-direction: column; align-items: center; justify-content: center; gap: 2rem; } |
|
.loader-container { position: relative; width: 150px; height: 150px; } |
|
.loader-orb { |
|
position: absolute; |
|
top: 50%; left: 50%; |
|
width: 80px; height: 80px; |
|
background: radial-gradient(circle, var(--accent-glow) 0%, transparent 70%); |
|
border-radius: 50%; |
|
transform: translate(-50%, -50%); |
|
animation: orb-pulse 2.5s infinite ease-in-out; |
|
} |
|
.loader-particle { |
|
position: absolute; |
|
top: 50%; left: 50%; |
|
width: 5px; height: 5px; |
|
background: var(--accent-glow); |
|
border-radius: 50%; |
|
box-shadow: 0 0 10px var(--accent-glow), 0 0 20px var(--accent-glow); |
|
animation: orbit 4s infinite linear; |
|
} |
|
.loader-particle:nth-child(2) { animation-delay: -0.5s; width: 4px; height: 4px; } |
|
.loader-particle:nth-child(3) { animation-delay: -1s; width: 6px; height: 6px; } |
|
.loader-particle:nth-child(4) { animation-delay: -1.5s; } |
|
.loader-particle:nth-child(5) { animation-delay: -2s; width: 3px; height: 3px; } |
|
.loader-particle:nth-child(6) { animation-delay: -2.5s; } |
|
.loader-particle:nth-child(7) { animation-delay: -3s; width: 4px; height: 4px; } |
|
.loader-particle:nth-child(8) { animation-delay: -3.5s; } |
|
#loading-text { font-size: 1.1em; font-weight: 500; color: var(--text-primary); text-shadow: 0 0 10px rgba(var(--accent-glow-rgb), 0.3); } |
|
|
|
@keyframes orb-pulse { |
|
0%, 100% { transform: translate(-50%, -50%) scale(1); opacity: 0.8; } |
|
50% { transform: translate(-50%, -50%) scale(1.2); opacity: 1; } |
|
} |
|
@keyframes orbit { |
|
from { transform: rotate(0deg) translateX(70px) rotate(0deg); } |
|
to { transform: rotate(360deg) translateX(70px) rotate(-360deg); } |
|
} |
|
|
|
</style> |
|
</head> |
|
<body> |
|
<div class="container"> |
|
<div class="main-panel"> |
|
<header class="app-header"> |
|
<h1>آلفا TTS</h1> |
|
<p>صدای آینده، خلق شده توسط هوش مصنوعی</p> |
|
</header> |
|
|
|
<main> |
|
<form id="tts-form"> |
|
<div class="form-group"> |
|
<label for="text-input">📝 متن برای تبدیل</label> |
|
<textarea id="text-input" rows="5" placeholder="اینجا متن خود را به فارسی وارد کنید...">این یک آزمایش برای بررسی کیفیت صدای تولید شده توسط هوش مصنوعی آلفا است.</textarea> |
|
</div> |
|
<div class="form-group"> |
|
<label for="prompt-input">🗣️ سبک و لحن گفتار (اختیاری)</label> |
|
<input type="text" id="prompt-input" value="با صدایی طبیعی و روان." placeholder="مثال: با لحنی شاد و پرانرژی"> |
|
</div> |
|
<div class="form-group"> |
|
<label>🎤 گوینده منتخب</label> |
|
<div id="selected-speaker-display"> |
|
<div id="selected-speaker-card"> |
|
<img id="selected-speaker-img" src="" alt="عکس گوینده"> |
|
<div id="selected-speaker-info"> |
|
<h3 id="selected-speaker-name"></h3> |
|
<p>برای تغییر کلیک کنید</p> |
|
</div> |
|
</div> |
|
<button type="button" id="change-speaker-btn">تغییر گوینده</button> |
|
</div> |
|
</div> |
|
<div class="form-group"> |
|
<label for="temperature-slider">🌡️ میزان خلاقیت صدا (0.1 تا 1.5)</label> |
|
<div class="slider-container"> |
|
<input type="range" id="temperature-slider" min="0.1" max="1.5" step="0.05" value="0.9"> |
|
<span id="temperature-value">0.9</span> |
|
</div> |
|
</div> |
|
<button type="submit" id="generate-btn">🚀 تولید و پخش صدا</button> |
|
</form> |
|
|
|
<div id="output-section"> |
|
<div id="status-message">خروجی صدا در اینجا نمایش داده میشود</div> |
|
|
|
<div id="premium-loader"> |
|
<div class="loader-container"> |
|
<div class="loader-orb"></div> |
|
<span class="loader-particle"></span><span class="loader-particle"></span><span class="loader-particle"></span> |
|
<span class="loader-particle"></span><span class="loader-particle"></span><span class="loader-particle"></span> |
|
<span class="loader-particle"></span><span class="loader-particle"></span> |
|
</div> |
|
<p id="loading-text">در حال تبدیل متن به صدا با هوش مصنوعی آلفا...</p> |
|
</div> |
|
<audio id="audio-player" controls></audio> |
|
</div> |
|
</main> |
|
</div> |
|
</div> |
|
|
|
<div id="speaker-modal"> |
|
<div class="modal-content"> |
|
<div class="modal-header"> |
|
<h2>انتخاب گوینده</h2> |
|
<button type="button" class="close-modal-btn">×</button> |
|
</div> |
|
<div id="speaker-grid"></div> |
|
</div> |
|
</div> |
|
|
|
<input type="hidden" id="selected_speaker_id_storage" value="Charon"> |
|
|
|
<script> |
|
document.addEventListener('DOMContentLoaded', () => { |
|
const HF_SPACE_URL = "https://hamed744-ttspro.hf.space"; |
|
const JOIN_QUEUE_URL = `${HF_SPACE_URL}/gradio_api/queue/join`; |
|
const GET_DATA_URL_BASE = `${HF_SPACE_URL}/gradio_api/queue/data`; |
|
const FILE_URL_BASE = `${HF_SPACE_URL}/gradio_api/file=`; |
|
const FN_INDEX = 1; |
|
|
|
const speakers = [ |
|
{ 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: "لیدا (زن)" } |
|
]; |
|
|
|
const form = document.getElementById('tts-form'); |
|
const textInput = document.getElementById('text-input'); |
|
const promptInput = document.getElementById('prompt-input'); |
|
const tempSlider = document.getElementById('temperature-slider'); |
|
const tempValueSpan = document.getElementById('temperature-value'); |
|
const generateBtn = document.getElementById('generate-btn'); |
|
|
|
const statusMessage = document.getElementById('status-message'); |
|
const audioPlayer = document.getElementById('audio-player'); |
|
const premiumLoader = document.getElementById('premium-loader'); |
|
|
|
const selectedSpeakerIdStorage = document.getElementById('selected_speaker_id_storage'); |
|
const speakerModal = document.getElementById('speaker-modal'); |
|
const changeSpeakerBtn = document.getElementById('change-speaker-btn'); |
|
const closeModalBtn = document.querySelector('.close-modal-btn'); |
|
const speakerGridInModal = document.getElementById('speaker-grid'); |
|
const selectedSpeakerImgDisplay = document.getElementById('selected-speaker-img'); |
|
const selectedSpeakerNameDisplay = document.getElementById('selected-speaker-name'); |
|
|
|
function getSpeakerById(id) { return speakers.find(s => s.id === id); } |
|
|
|
function getImageUrl(speaker, index) { |
|
const gender = speaker.name.includes('(مرد)') ? 'men' : (speaker.name.includes('(زن)') ? 'women' : 'lego'); |
|
const imageIndex = (index * 11 + 7) % 100; |
|
return `https://randomuser.me/api/portraits/${gender}/${imageIndex}.jpg`; |
|
} |
|
|
|
function updateSelectedSpeakerDisplay(speakerId) { |
|
const speaker = getSpeakerById(speakerId); |
|
if (speaker) { |
|
const speakerIndex = speakers.findIndex(s => s.id === speakerId); |
|
selectedSpeakerImgDisplay.src = getImageUrl(speaker, speakerIndex); |
|
selectedSpeakerNameDisplay.textContent = speaker.name; |
|
selectedSpeakerIdStorage.value = speaker.id; |
|
} |
|
} |
|
|
|
function createSpeakerCardsInModal() { |
|
speakerGridInModal.innerHTML = ''; |
|
speakers.forEach((speaker, index) => { |
|
const card = document.createElement('label'); |
|
card.className = 'speaker-card'; |
|
card.setAttribute('for', `modal-speaker-${speaker.id}`); |
|
const isChecked = speaker.id === selectedSpeakerIdStorage.value ? 'checked' : ''; |
|
|
|
card.innerHTML = ` |
|
<input type="radio" name="modal_speaker_selection" value="${speaker.id}" id="modal-speaker-${speaker.id}" ${isChecked}> |
|
<div class="speaker-visual"> |
|
<img src="${getImageUrl(speaker, index)}" alt="عکس گوینده ${speaker.name}" loading="lazy"> |
|
<div class="speaker-name">${speaker.name}</div> |
|
</div> |
|
`; |
|
|
|
card.addEventListener('click', () => { |
|
updateSelectedSpeakerDisplay(speaker.id); |
|
setTimeout(() => speakerModal.classList.remove('visible'), 200); |
|
}); |
|
|
|
speakerGridInModal.appendChild(card); |
|
}); |
|
} |
|
|
|
changeSpeakerBtn.addEventListener('click', () => { |
|
createSpeakerCardsInModal(); |
|
speakerModal.classList.add('visible'); |
|
}); |
|
closeModalBtn.addEventListener('click', () => speakerModal.classList.remove('visible')); |
|
speakerModal.addEventListener('click', (e) => { |
|
if (e.target === speakerModal) speakerModal.classList.remove('visible'); |
|
}); |
|
|
|
tempSlider.addEventListener('input', () => { tempValueSpan.textContent = tempSlider.value; }); |
|
|
|
function showLoadingState() { |
|
statusMessage.style.display = 'none'; |
|
audioPlayer.style.display = 'none'; |
|
audioPlayer.src = ''; |
|
premiumLoader.style.display = 'flex'; |
|
generateBtn.disabled = true; |
|
generateBtn.textContent = 'در حال خلق صدا...'; |
|
} |
|
|
|
function showResultState(isSuccess, message = '') { |
|
premiumLoader.style.display = 'none'; |
|
if (isSuccess) { |
|
statusMessage.style.display = 'none'; |
|
audioPlayer.style.display = 'block'; |
|
audioPlayer.play(); |
|
} else { |
|
statusMessage.textContent = message || 'یک خطای ناشناخته رخ داد.'; |
|
statusMessage.style.display = 'block'; |
|
audioPlayer.style.display = 'none'; |
|
} |
|
generateBtn.disabled = false; |
|
generateBtn.textContent = '🚀 تولید و پخش صدا'; |
|
} |
|
|
|
async function generateAudio(event) { |
|
event.preventDefault(); |
|
showLoadingState(); |
|
|
|
const text = textInput.value; |
|
if (!text.trim()) { |
|
showResultState(false, 'خطا: متن ورودی نمیتواند خالی باشد.'); |
|
return; |
|
} |
|
|
|
const prompt = promptInput.value; |
|
const temperature = parseFloat(tempSlider.value); |
|
const selectedSpeaker = selectedSpeakerIdStorage.value; |
|
const sessionHash = Math.random().toString(36).substring(2); |
|
const payload = { fn_index: FN_INDEX, data: [false, null, text, prompt, selectedSpeaker, temperature], event_data: null, session_hash: sessionHash }; |
|
|
|
try { |
|
const joinQueueResponse = await fetch(JOIN_QUEUE_URL, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload) }); |
|
if (!joinQueueResponse.ok) { throw new Error(`خطا در اتصال به صف (${joinQueueResponse.status})`); } |
|
|
|
const dataResponse = await fetch(`${GET_DATA_URL_BASE}?session_hash=${sessionHash}`); |
|
const reader = dataResponse.body.getReader(); |
|
const decoder = new TextDecoder(); |
|
let finalFilePath = null; |
|
let buffer = ''; |
|
|
|
while (true) { |
|
const { value, done } = await reader.read(); |
|
if (done) break; |
|
buffer += decoder.decode(value, { stream: true }); |
|
const lines = buffer.split('\n'); |
|
buffer = lines.pop(); |
|
for (const line of lines) { |
|
if (!line.startsWith('data:')) continue; |
|
try { |
|
const data = JSON.parse(line.substring(5)); |
|
if (data.msg === 'process_completed') { |
|
if (data.success && data.output.data && data.output.data[0] && (data.output.data[0].name || data.output.data[0].path)) { |
|
finalFilePath = data.output.data[0].name || data.output.data[0].path; |
|
} |
|
break; |
|
} |
|
} catch (e) { } |
|
} |
|
if (finalFilePath) break; |
|
} |
|
|
|
if (finalFilePath) { |
|
const audioUrl = `${FILE_URL_BASE}${finalFilePath}`; |
|
audioPlayer.src = audioUrl; |
|
showResultState(true); |
|
} else { |
|
throw new Error('فایل صوتی از سرور دریافت نشد.'); |
|
} |
|
} catch (error) { |
|
console.error('یک خطا در فرآیند رخ داد:', error); |
|
showResultState(false, `یک خطا رخ داد: ${error.message}`); |
|
} |
|
} |
|
|
|
updateSelectedSpeakerDisplay(selectedSpeakerIdStorage.value); |
|
form.addEventListener('submit', generateAudio); |
|
}); |
|
</script> |
|
</body> |
|
</html> |