File size: 11,920 Bytes
4741934
 
 
 
 
ed3717e
 
39152f8
 
4741934
 
39152f8
4741934
 
 
39152f8
4741934
ed3717e
 
 
 
 
4741934
 
ed3717e
 
 
 
 
 
4741934
ed3717e
 
39152f8
ed3717e
 
 
39152f8
 
ed3717e
 
39152f8
4741934
3a0ef3e
ed3717e
 
 
 
 
 
 
 
 
 
 
 
4741934
ed3717e
 
 
 
 
 
4741934
ed3717e
 
 
 
 
 
 
 
 
 
 
39152f8
 
ed3717e
 
 
 
 
 
 
 
 
39152f8
 
4741934
ed3717e
39152f8
 
4741934
ed3717e
39152f8
 
 
 
 
 
 
4741934
39152f8
ed3717e
 
39152f8
 
4741934
ed3717e
39152f8
ed3717e
 
 
 
 
39152f8
 
4741934
ed3717e
39152f8
d811ffc
39152f8
 
ed3717e
4741934
39152f8
ed3717e
39152f8
 
 
4741934
ed3717e
d811ffc
ed3717e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d811ffc
ed3717e
 
d811ffc
ed3717e
39152f8
4741934
39152f8
ed3717e
 
 
39152f8
ed3717e
4741934
 
39152f8
4741934
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
<!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>