tast / index.html
Opera8's picture
Update index.html
ed3717e verified
<!DOCTYPE html>
<html lang="fa" dir="rtl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>شبیه‌ساز اختصاصی صدا - OmniVoice Clone API</title>
<!-- استفاده از Tailwind CSS برای طراحی محیط کاربری ساده و مدرن -->
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://fonts.googleapis.com/css2?family=Vazirmatn:wght@300;400;700;900&display=swap" rel="stylesheet">
<style>
body {
font-family: 'Vazirmatn', sans-serif;
}
</style>
</head>
<body class="bg-slate-900 text-slate-100 min-h-screen py-10 px-4">
<div class="max-w-2xl mx-auto bg-slate-800 rounded-2xl shadow-2xl border border-slate-700 overflow-hidden">
<!-- هدر -->
<div class="bg-gradient-to-r from-teal-600 to-emerald-600 p-6 text-white text-center">
<h1 class="text-2xl font-black">پنل شبیه‌سازی صدا (OmniVoice Clone)</h1>
<p class="text-xs opacity-90 mt-1">تولید گفتار با کپی‌برداری دقیق از فایل صوتی مرجع شما</p>
</div>
<div class="p-6 space-y-6">
<!-- متن ورودی -->
<div>
<label class="block text-sm font-bold text-slate-300 mb-2">متن مورد نظر برای تبدیل به گفتار:</label>
<textarea id="inputText" rows="4" class="w-full bg-slate-900 border border-slate-700 rounded-lg p-3 text-white placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-teal-500" placeholder="متنی را که می‌خواهید با صدای شبیه‌سازی‌شده خوانده شود، بنویسید..."></textarea>
</div>
<!-- فایل صوتی مرجع -->
<div class="bg-slate-900/40 p-4 rounded-xl border border-slate-700 space-y-4">
<div>
<label class="block text-sm font-bold text-slate-300 mb-2">فایل صوتی مرجع (۳ تا ۱۰ ثانیه):</label>
<input type="file" id="refAudio" accept="audio/*" class="w-full text-sm text-slate-400 file:mr-4 file:py-2 file:px-4 file:rounded-full file:border-0 file:text-xs file:font-semibold file:bg-teal-600 file:text-white hover:file:bg-teal-500 cursor-pointer">
<p class="text-[10px] text-slate-500 mt-1">یک فایل صوتی کوتاه و باکیفیت از گوینده مورد نظر آپلود کنید (فرمت mp3، wav و غیره).</p>
</div>
<div>
<label class="block text-xs font-bold text-slate-400 mb-1">متن فایل صوتی مرجع (اختیاری):</label>
<input type="text" id="refText" class="w-full bg-slate-900 border border-slate-700 rounded-lg p-2 text-sm text-white focus:outline-none focus:ring-1 focus:ring-teal-500" placeholder="جمله‌ای که گوینده در فایل مرجع بالا می‌گوید...">
</div>
</div>
<!-- انتخاب زبان -->
<div>
<label class="block text-sm font-bold text-slate-300 mb-2">زبان خروجی:</label>
<select id="language" class="w-full bg-slate-900 border border-slate-700 rounded-lg p-2.5 text-white text-sm focus:ring-teal-500 focus:border-teal-500">
<option value="Auto">تشخیص خودکار (Auto)</option>
<option value="English">انگلیسی (English)</option>
<option value="Persian">فارسی (Persian)</option>
<option value="Spanish">اسپانیایی (Spanish)</option>
<option value="French">فرانسوی (French)</option>
<option value="Chinese">چینی (Chinese)</option>
</select>
</div>
<!-- توکن هگینگ فیس -->
<div class="bg-slate-950/20 p-3 rounded-lg border border-slate-700/50">
<label class="block text-xs font-bold text-slate-400 mb-1">توکن Hugging Face (اختیاری):</label>
<input type="password" id="hfToken" class="w-full bg-slate-900 border border-slate-700 rounded-lg p-2 text-xs text-white focus:outline-none focus:ring-1 focus:ring-teal-500" placeholder="Bearer hf_...">
<p class="text-[10px] text-slate-500 mt-1">در صورت شلوغ بودن صف عمومی یا مسدود شدن درخواست‌ها، از توکن شخصی خود استفاده کنید.</p>
</div>
<!-- دکمه پردازش -->
<button id="btnGenerate" onclick="generateClone()" class="w-full bg-gradient-to-r from-teal-500 to-emerald-500 hover:from-teal-600 hover:to-emerald-600 text-white font-bold py-3.5 px-6 rounded-xl transition duration-300 shadow-lg flex items-center justify-center">
<span id="btnText">تولید صدای شبیه‌سازی‌شده (Synthesize)</span>
</button>
<!-- وضعیت زنده -->
<div id="statusBox" class="hidden bg-slate-950/50 p-4 rounded-xl border border-slate-800 text-xs">
<div class="flex items-center space-x-3 space-x-reverse">
<!-- انیمیشن لودینگ سنتی -->
<div class="w-4 h-4 border-2 border-teal-500 border-t-transparent rounded-full animate-spin"></div>
<span id="statusMessage" class="text-slate-300">در حال بررسی ارتباط...</span>
</div>
</div>
<!-- خروجی نهایی -->
<div id="resultContainer" class="hidden bg-slate-900/90 p-5 rounded-xl border border-teal-500/40 space-y-4">
<h3 class="text-sm font-bold text-teal-400">فایل صوتی شبیه‌سازی‌شده با موفقیت آماده شد:</h3>
<audio id="audioPlayer" controls class="w-full"></audio>
<a id="btnDownload" download="cloned_speech.wav" class="block text-center bg-teal-600 hover:bg-teal-500 text-white text-xs font-bold py-2.5 px-4 rounded-lg transition shadow">
دانلود فایل صوتی خروجی (WAV)
</a>
</div>
</div>
</div>
<!-- بارگذاری کتابخانه رسمی جاوااسکریپت گرادیو -->
<script type="module">
import { Client, handle_file } from "https://cdn.jsdelivr.net/npm/@gradio/client/dist/index.min.js";
window.generateClone = async function() {
const btn = document.getElementById("btnGenerate");
const btnText = document.getElementById("btnText");
const statusBox = document.getElementById("statusBox");
const statusMessage = document.getElementById("statusMessage");
const resultContainer = document.getElementById("resultContainer");
const audioPlayer = document.getElementById("audioPlayer");
const btnDownload = document.getElementById("btnDownload");
const text = document.getElementById("inputText").value.trim();
const refAudioFile = document.getElementById("refAudio").files[0];
const refTextVal = document.getElementById("refText").value.trim() || null;
const language = document.getElementById("language").value;
const hfToken = document.getElementById("hfToken").value.trim();
// بررسی الزامات
if (!text) {
alert("لطفاً ابتدا متنی را برای خوانده شدن وارد کنید.");
return;
}
if (!refAudioFile) {
alert("لطفاً فایل صوتی مرجع را آپلود کنید تا صدا شبیه‌سازی شود.");
return;
}
// آماده‌سازی ظاهر
btn.disabled = true;
btnText.innerText = "منتظر بمانید...";
statusBox.classList.remove("hidden");
resultContainer.classList.add("hidden");
statusMessage.innerText = "در حال ایجاد اتصال به موتور هوش مصنوعی OmniVoice...";
try {
// ۱. اتصال به کلاینت گرادیو
const app = await Client.connect("k2-fsa/OmniVoice", {
token: hfToken ? `Bearer ${hfToken}` : undefined
});
statusMessage.innerText = "اتصال برقرار شد. در حال آپلود فایل صوتی مرجع...";
// ۲. پیدا کردن خودکار اندپوینت شبیه‌سازی (دارای ۱۲ پارامتر ورودی)
const cloneDep = app.config.dependencies.find(dep => dep.inputs && dep.inputs.length === 12);
if (!cloneDep) {
throw new Error("تنظیمات مربوط به مدل شبیه‌سازی روی سرور یافت نشد.");
}
const endpoint = cloneDep.api_name ? `/${cloneDep.api_name}` : cloneDep.id;
// ۳. آپلود و ساختاردهی فایل صوتی با کلاینت رسمی
const refAudioPayload = handle_file(refAudioFile);
statusMessage.innerText = "درخواست شما با موفقیت در صف سرور قرار گرفت. پردازش روی کارت گرافیک (ZeroGPU) در حال انجام است. لطفاً پنجره را نبندید...";
// ۴. ارسال نهایی درخواست به کمک متد predict (که به طور خودکار صف و SSE را در پس‌زمینه مدیریت می‌کند)
const result = await app.predict(endpoint, [
text, // 1. Text to synthesize
language, // 2. Language
refAudioPayload, // 3. Reference Audio
refTextVal, // 4. Reference Text
"", // 5. Instruct (در حالت کلون خالی رها می‌شود)
32, // 6. Steps (تعداد مراحل تولید پیش‌فرض)
2.0, // 7. Guidance scale (مقیاس هدایت پیش‌فرض)
true, // 8. Denoise (کاهش نویز پیش‌فرض)
1.0, // 9. Speed (سرعت طبیعی)
0, // 10. Duration (مدت زمان خودکار)
true, // 11. Preprocess prompt (پیش‌پردازش پیش‌فرض)
true // 12. Postprocess output (پس‌پردازش خروجی)
]);
// ۵. نمایش نتایج
if (result && result.data && result.data[0]) {
const audioUrl = result.data[0].url;
audioPlayer.src = audioUrl;
btnDownload.href = audioUrl;
statusMessage.innerText = "پردازش نهایی شد و فایل صدا تولید گردید.";
resultContainer.classList.remove("hidden");
} else {
throw new Error("خروجی معتبری از هوش مصنوعی دریافت نشد.");
}
} catch (error) {
console.error(error);
statusMessage.innerText = `خطا در فرآیند: ${error.message || error}`;
} finally {
btn.disabled = false;
btnText.innerText = "تولید صدای شبیه‌سازی‌شده (Synthesize)";
}
}
</script>
</body>
</html>