<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[VoiceMaster אתר קריינות משוכלל!!!]]></title><description><![CDATA[<p dir="auto">לאחר זמן רב,<br />
שישבתי יומם ולילה לחשוב איך כל אדם שצריך איזשהו קריינות, יוכל ליצור אותה בקלות.<br />
לכן בניתי את האתר <a href="https://a0733641352-bit.github.io/Voice-Maste/" target="_blank" rel="noopener noreferrer nofollow ugc">הזה</a><br />
קודם כל יש להיכנס ל-<a href="https://aistudio.google.com/api-keys" target="_blank" rel="noopener noreferrer nofollow ugc">Google AI Studio</a> וליצור מפתח API חדש ולעלות לאתר למעלה בצד שמאל.<br />
ואחרי זה תיצרו את הקריינות...</p>
<p dir="auto">או שתפתחו פנקס רשימות ואז תשמרו את זה על שם index.html ותפתחו אותו...</p>
<pre><code>&lt;!DOCTYPE html&gt;
&lt;html lang="he" dir="rtl"&gt;
&lt;head&gt;
    &lt;meta charset="UTF-8"&gt;
    &lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&gt;
    &lt;title&gt;VoiceMaster AI Studio ✨&lt;/title&gt;
    &lt;script src="https://cdn.tailwindcss.com"&gt;&lt;/script&gt;
    &lt;style&gt;
        @import url('https://fonts.googleapis.com/css2?family=Assistant:wght@300;400;600;700;800&amp;display=swap');
        body { font-family: 'Assistant', sans-serif; background: #f1f5f9; transition: background-color 0.3s ease, color 0.3s ease; }
        .dark-mode { background: #020617; color: #f8fafc; }
        .card { background: white; border: 1px solid #e2e8f0; transition: all 0.3s ease; }
        .dark-mode .card { background: #1e293b; border-color: #334155; }
        .loading-spinner { border: 2px solid rgba(255,255,255,0.3); border-top: 2px solid currentColor; border-radius: 50%; width: 16px; height: 16px; animation: spin 0.8s linear infinite; }
        @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
        .ai-glow { box-shadow: 0 0 25px rgba(99, 102, 241, 0.15); }
        .feature-badge { background: linear-gradient(90deg, #4f46e5, #9333ea); color: white; padding: 2px 8px; border-radius: 99px; font-size: 10px; font-weight: bold; }
        
        /* התאמת רכיבי שמע למכשירים ניידים */
        audio {
            max-width: 100%;
            height: 36px;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body class="min-h-screen py-4 sm:py-8 px-3 sm:px-6 md:px-8 transition-colors duration-500" id="bodyTag"&gt;
    &lt;div class="max-w-7xl mx-auto"&gt;
        &lt;header class="flex flex-wrap justify-between items-center gap-4 mb-6 sm:mb-8 pb-4 border-b border-slate-200 dark:border-slate-800"&gt;
            &lt;div class="flex items-center gap-3 sm:gap-4"&gt;
                &lt;div class="bg-indigo-600 p-2.5 sm:p-3 rounded-2xl text-white shadow-xl flex-shrink-0"&gt;
                    &lt;svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 sm:h-8 sm:w-8" fill="none" viewBox="0 0 24 24" stroke="currentColor"&gt;
                        &lt;path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11a7 7 0 01-7 7m0 0a7 7 0 01-7-7m7 7v4m0 0H8m4 0h4m-4-8a3 3 0 01-3-3V5a3 3 0 116 0v6a3 3 0 01-3 3z" /&gt;
                    &lt;/svg&gt;
                &lt;/div&gt;
                &lt;div&gt;
                    &lt;h1 class="text-2xl sm:text-3xl font-black text-slate-800 dark:text-white tracking-tight leading-none uppercase"&gt;Voice&lt;span class="text-indigo-600"&gt;Master&lt;/span&gt;&lt;/h1&gt;
                    &lt;p class="text-[10px] sm:text-xs font-bold text-slate-400 uppercase tracking-widest mt-1"&gt;AI Smart Narration Hub&lt;/p&gt;
                &lt;/div&gt;
            &lt;/div&gt;
            
            &lt;div class="flex items-center gap-2"&gt;
                &lt;div class="relative"&gt;
                    &lt;button id="apiKeyBtn" class="p-2.5 sm:p-3 rounded-xl card shadow-sm hover:scale-105 transition-all flex items-center gap-2 text-xs font-bold text-slate-600 dark:text-slate-300"&gt;
                        &lt;svg class="w-4 h-4 sm:w-5 sm:h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"&gt;&lt;path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z"/&gt;&lt;/svg&gt;
                        &lt;span id="apiKeyStatus" class="hidden sm:inline"&gt;הגדר מפתח&lt;/span&gt;
                    &lt;/button&gt;
                    &lt;div id="apiKeyPopover" class="hidden absolute left-0 sm:left-auto right-0 sm:right-0 mt-2 w-72 sm:w-80 p-4 card rounded-2xl shadow-2xl z-50"&gt;
                        &lt;h4 class="font-bold text-sm mb-2 dark:text-white"&gt;Gemini API Key&lt;/h4&gt;
                        &lt;input id="apiKeyInput" type="password" class="w-full p-2.5 text-xs bg-slate-50 dark:bg-slate-800 rounded-lg border border-slate-200 dark:border-slate-700 outline-none focus:ring-2 focus:ring-indigo-500 mb-2 dark:text-white" placeholder="AIzaSy..."&gt;
                        &lt;div class="flex gap-2"&gt;
                            &lt;button id="saveApiKey" class="flex-1 py-2 bg-indigo-600 text-white text-[11px] font-bold rounded-lg hover:bg-indigo-700 active:scale-95 transition-all"&gt;שמור מפתח&lt;/button&gt;
                            &lt;button id="clearApiKey" class="flex-1 py-2 bg-red-50 text-red-600 text-[11px] font-bold rounded-lg hover:bg-red-100 active:scale-95 transition-all"&gt;מחק&lt;/button&gt;
                        &lt;/div&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
 
                &lt;button id="toggleDark" class="p-2.5 sm:p-3 rounded-xl card shadow-sm hover:scale-105 active:scale-95 transition-all"&gt;
                    &lt;svg class="h-5 w-5 sm:h-6 sm:w-6 text-slate-600 dark:text-indigo-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"&gt;
                        &lt;path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z"/&gt;
                    &lt;/svg&gt;
                &lt;/button&gt;
            &lt;/div&gt;
        &lt;/header&gt;
 
        &lt;div class="grid grid-cols-1 lg:grid-cols-12 gap-6 lg:gap-8"&gt;
            &lt;div class="lg:col-span-5 space-y-6"&gt;
                &lt;div class="card p-4 sm:p-6 rounded-2xl sm:rounded-[2rem] shadow-lg ai-glow border-indigo-100 dark:border-indigo-900/30"&gt;
                    &lt;div class="flex items-center justify-between mb-3 sm:mb-4"&gt;
                        &lt;h3 class="font-bold text-sm sm:text-base text-indigo-900 dark:text-indigo-300"&gt;יצירת תוכן חכמה&lt;/h3&gt;
                    &lt;/div&gt;
                    &lt;div class="flex gap-2 mb-3 sm:mb-4"&gt;
                        &lt;input id="promptInput" type="text" class="flex-grow p-3 bg-slate-50 dark:bg-slate-800 rounded-xl text-xs sm:text-sm border-none outline-none focus:ring-2 focus:ring-indigo-500 dark:text-white" placeholder="תאר מה לכתוב (למשל: פרסומת לשירות חדש)..."&gt;
                        &lt;button id="magicWriteBtn" class="p-3 bg-indigo-600 text-white rounded-xl hover:bg-indigo-700 active:scale-95 transition-all flex items-center justify-center min-w-[48px] sm:min-w-[50px]"&gt;
                            &lt;span id="magicIcon"&gt;✨&lt;/span&gt;
                            &lt;div id="magicLoader" class="loading-spinner hidden"&gt;&lt;/div&gt;
                        &lt;/button&gt;
                    &lt;/div&gt;
                    &lt;div class="grid grid-cols-2 sm:grid-cols-3 gap-2"&gt;
                        &lt;button onclick="smartEdit('הפוך את הטקסט ליותר רגוע ונעים')" class="text-[11px] font-bold py-2 px-1 bg-slate-100 dark:bg-slate-800 rounded-lg hover:bg-indigo-50 dark:hover:bg-indigo-950/40 dark:text-slate-200 active:scale-95 transition-all truncate"&gt;✨ ריכוך&lt;/button&gt;
                        &lt;button onclick="smartEdit('הפוך את הטקסט ליותר שיווקי ואנרגטי')" class="text-[11px] font-bold py-2 px-1 bg-slate-100 dark:bg-slate-800 rounded-lg hover:bg-indigo-50 dark:hover:bg-indigo-950/40 dark:text-slate-200 active:scale-95 transition-all truncate"&gt;✨ שיווקי&lt;/button&gt;
                        &lt;button onclick="smartEdit('קצר את הטקסט ב-30% מבלי לאבד משמעות')" class="text-[11px] font-bold py-2 px-1 bg-slate-100 dark:bg-slate-800 rounded-lg hover:bg-indigo-50 dark:hover:bg-indigo-950/40 dark:text-slate-200 active:scale-95 transition-all truncate"&gt;✨ קיצור&lt;/button&gt;
                        &lt;button onclick="translateText()" class="text-[11px] font-bold py-2 px-1 bg-indigo-50 dark:bg-indigo-900/40 text-indigo-700 dark:text-indigo-300 rounded-lg hover:bg-indigo-100 active:scale-95 transition-all truncate"&gt;✨ תרגם לאנגלית&lt;/button&gt;
                        &lt;button onclick="generatePodcastScript()" class="text-[11px] font-bold py-2 px-1 bg-indigo-50 dark:bg-indigo-900/40 text-indigo-700 dark:text-indigo-300 rounded-lg hover:bg-indigo-100 active:scale-95 transition-all truncate"&gt;✨ תסריט פודקאסט&lt;/button&gt;
                        &lt;button onclick="summarizeText()" class="text-[11px] font-bold py-2 px-1 bg-indigo-50 dark:bg-indigo-900/40 text-indigo-700 dark:text-indigo-300 rounded-lg hover:bg-indigo-100 active:scale-95 transition-all truncate"&gt;✨ סיכום נקודות&lt;/button&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
 
                &lt;div class="card p-4 sm:p-7 rounded-2xl sm:rounded-[2.5rem] shadow-xl border-none"&gt;
                    &lt;div class="flex flex-wrap justify-between items-center gap-2 mb-2"&gt;
                        &lt;label class="text-xs sm:text-sm font-bold text-slate-500 dark:text-slate-400"&gt;טקסט לקריינות&lt;/label&gt;
                        &lt;button id="analyzeToneBtn" class="text-[10px] sm:text-[11px] font-bold text-indigo-600 bg-indigo-50 dark:bg-indigo-900/30 px-2.5 py-1 rounded-full hover:bg-indigo-100 active:scale-95 transition-all flex items-center gap-1"&gt;
                            &lt;span&gt;✨ התאם סגנון אוטומטית&lt;/span&gt;
                            &lt;div id="toneLoader" class="loading-spinner hidden !w-3 !h-3"&gt;&lt;/div&gt;
                        &lt;/button&gt;
                    &lt;/div&gt;
                    &lt;textarea id="textInput" rows="5" class="w-full p-3 sm:p-4 bg-slate-50 dark:bg-slate-800/50 rounded-xl sm:rounded-2xl outline-none border-2 border-transparent focus:border-indigo-500 transition-all text-base sm:text-lg dark:text-white resize-y" placeholder="הטקסט יופיע כאן..."&gt;&lt;/textarea&gt;
                    
                    &lt;div class="flex gap-2 mt-3 mb-5"&gt;
                        &lt;button id="vocalizeBtn" class="flex-1 py-2.5 sm:py-3 bg-slate-50 dark:bg-slate-800 text-slate-600 dark:text-slate-300 rounded-xl text-xs font-bold hover:bg-indigo-50 dark:hover:bg-indigo-900/20 active:scale-95 transition-all flex items-center justify-center gap-2 border border-slate-100 dark:border-slate-700"&gt;
                            &lt;span&gt;✨ ניקוד אוטומטי&lt;/span&gt;
                            &lt;div id="vocalizeLoader" class="loading-spinner hidden"&gt;&lt;/div&gt;
                        &lt;/button&gt;
                    &lt;/div&gt;
 
                    &lt;div class="grid grid-cols-1 sm:grid-cols-2 gap-3 sm:gap-4 mb-6"&gt;
                        &lt;div&gt;
                            &lt;label class="text-[10px] font-bold text-slate-400 uppercase mr-1 block mb-1"&gt;קול&lt;/label&gt;
                            &lt;select id="voiceSelect" class="w-full p-3 bg-slate-100 dark:bg-slate-800 dark:text-white rounded-xl text-xs sm:text-sm font-bold border-none outline-none cursor-pointer"&gt;
                                &lt;optgroup label="גברים (Male)"&gt;
                                    &lt;option value="Zephyr"&gt;Zephyr (קליל)&lt;/option&gt;
                                    &lt;option value="Fenrir"&gt;Fenrir (עמוק)&lt;/option&gt;
                                    &lt;option value="Puck"&gt;Puck (שובב)&lt;/option&gt;
                                    &lt;option value="Charon"&gt;Charon (סמכותי)&lt;/option&gt;
                                    &lt;option value="Orus"&gt;Orus (קלאסי)&lt;/option&gt;
                                    &lt;option value="Enceladus"&gt;Enceladus (צעיר)&lt;/option&gt;
                                    &lt;option value="Iapetus"&gt;Iapetus (חם)&lt;/option&gt;
                                    &lt;option value="Algieba"&gt;Algieba (נמרץ)&lt;/option&gt;
                                    &lt;option value="Rasalgethi"&gt;Rasalgethi (בוגר)&lt;/option&gt;
                                    &lt;option value="Achernar"&gt;Achernar (יציב)&lt;/option&gt;
                                    &lt;option value="Alnilam"&gt;Alnilam (בהיר)&lt;/option&gt;
                                    &lt;option value="Schedar"&gt;Schedar (נעים)&lt;/option&gt;
                                    &lt;option value="Achird"&gt;Achird (שידור)&lt;/option&gt;
                                    &lt;option value="Zubenelgenubi"&gt;Zubenelgenubi (עמוק מאוד)&lt;/option&gt;
                                    &lt;option value="Sadachbia"&gt;Sadachbia (רך)&lt;/option&gt;
                                    &lt;option value="Sadaltager"&gt;Sadaltager (טבעי)&lt;/option&gt;
                                    &lt;option value="Sulafat"&gt;Sulafat (עוצמתי)&lt;/option&gt;
                                &lt;/optgroup&gt;
                                &lt;optgroup label="נשים (Female)"&gt;
                                    &lt;option value="Kore" selected&gt;Kore (מקצועי)&lt;/option&gt;
                                    &lt;option value="Leda"&gt;Leda (עדין)&lt;/option&gt;
                                    &lt;option value="Aoede"&gt;Aoede (רך)&lt;/option&gt;
                                    &lt;option value="Callirrhoe"&gt;Callirrhoe (רהוט)&lt;/option&gt;
                                    &lt;option value="Autonoe"&gt;Autonoe (אנרגטי)&lt;/option&gt;
                                    &lt;option value="Umbriel"&gt;Umbriel (מסתורי)&lt;/option&gt;
                                    &lt;option value="Despina"&gt;Despina (מהיר)&lt;/option&gt;
                                    &lt;option value="Erinome"&gt;Erinome (ידידותי)&lt;/option&gt;
                                    &lt;option value="Algenib"&gt;Algenib (חדשותי)&lt;/option&gt;
                                    &lt;option value="Laomedeia"&gt;Laomedeia (מרגיע)&lt;/option&gt;
                                    &lt;option value="Gacrux"&gt;Gacrux (אלגנטי)&lt;/option&gt;
                                    &lt;option value="Pulcherrima"&gt;Pulcherrima (עשיר)&lt;/option&gt;
                                    &lt;option value="Vindemiatrix"&gt;Vindemiatrix (סבלני)&lt;/option&gt;
                                &lt;/optgroup&gt;
                            &lt;/select&gt;
                        &lt;/div&gt;
                        &lt;div&gt;
                            &lt;label class="text-[10px] font-bold text-slate-400 uppercase mr-1 block mb-1"&gt;סגנון והגשה&lt;/label&gt;
                            &lt;select id="styleSelect" class="w-full p-3 bg-slate-100 dark:bg-slate-800 dark:text-white rounded-xl text-xs sm:text-sm font-bold border-none outline-none cursor-pointer"&gt;
                                &lt;option value="natural"&gt;טבעי (Natural)&lt;/option&gt;
                                &lt;option value="cheerful"&gt;שמח (Cheerful)&lt;/option&gt;
                                &lt;option value="serious"&gt;רציני (Serious)&lt;/option&gt;
                                &lt;option value="whisper"&gt;לחישה (Whisper)&lt;/option&gt;
                                &lt;option value="excited"&gt;נרגש (Excited)&lt;/option&gt;
                                &lt;option value="calm"&gt;רגוע (Calm)&lt;/option&gt;
                                &lt;option value="authoritative"&gt;סמכותי (Authoritative)&lt;/option&gt;
                                &lt;option value="friendly"&gt;ידידותי (Friendly)&lt;/option&gt;
                                &lt;option value="professional"&gt;מקצועי (Professional)&lt;/option&gt;
                                &lt;option value="storytelling"&gt;מספר סיפורים (Storytelling)&lt;/option&gt;
                                &lt;option value="shouting"&gt;צעקה (Shouting)&lt;/option&gt;
                                &lt;option value="terrified"&gt;מבועת (Terrified)&lt;/option&gt;
                                &lt;option value="sad"&gt;עצוב (Sad)&lt;/option&gt;
                                &lt;option value="angry"&gt;כועס (Angry)&lt;/option&gt;
                                &lt;option value="hopeful"&gt;מלא תקווה (Hopeful)&lt;/option&gt;
                            &lt;/select&gt;
                        &lt;/div&gt;
                    &lt;/div&gt;
 
                    &lt;button id="generateBtn" class="w-full bg-indigo-600 hover:bg-indigo-700 active:scale-[0.98] text-white font-bold py-3.5 sm:py-4 rounded-xl sm:rounded-2xl shadow-lg transition-all flex items-center justify-center gap-3"&gt;
                        &lt;span id="btnText" class="text-sm sm:text-base"&gt;הפק קריינות עכשיו&lt;/span&gt;
                        &lt;div id="btnLoader" class="loading-spinner hidden !border-t-white"&gt;&lt;/div&gt;
                    &lt;/button&gt;
                &lt;/div&gt;
            &lt;/div&gt;
 
            &lt;div class="lg:col-span-7"&gt;
                &lt;div class="flex justify-between items-center mb-4"&gt;
                    &lt;h2 class="text-lg sm:text-xl font-bold dark:text-white"&gt;הקלטות אחרונות&lt;/h2&gt;
                    &lt;button id="clearTracks" class="text-xs text-slate-400 hover:text-red-500 font-bold transition-colors"&gt;נקה הכל&lt;/button&gt;
                &lt;/div&gt;
                &lt;div id="tracksContainer" class="space-y-3 sm:space-y-4"&gt;
                    &lt;div id="noTracks" class="text-center py-16 sm:py-24 border-2 border-dashed border-slate-300 dark:border-slate-800 rounded-2xl sm:rounded-[2.5rem] text-slate-400 font-bold text-sm sm:text-base"&gt;
                        היסטוריית הקריינות שלך תישמר כאן
                    &lt;/div&gt;
                &lt;/div&gt;
            &lt;/div&gt;
        &lt;/div&gt;
    &lt;/div&gt;
 
    &lt;div id="toast" class="fixed bottom-4 sm:bottom-8 left-4 sm:left-8 right-4 sm:right-auto px-4 sm:px-6 py-3 rounded-xl shadow-2xl opacity-0 transition-all pointer-events-none z-50 transform translate-y-4 flex items-center justify-center sm:justify-start gap-2 max-w-md"&gt;
        &lt;span id="toastIcon"&gt;&lt;/span&gt;
        &lt;span id="toastMessage" class="text-xs sm:text-sm font-semibold"&gt;&lt;/span&gt;
    &lt;/div&gt;
 
    &lt;script&gt;
        // Global State &amp; Config
        let currentApiKey = localStorage.getItem('gemini_api_key') || "";
        const modelText = "gemini-3.5-flash";
        const modelAudio = "gemini-2.5-flash-preview-tts";
 
        const els = {
            textInput: document.getElementById('textInput'),
            promptInput: document.getElementById('promptInput'),
            generateBtn: document.getElementById('generateBtn'),
            magicWriteBtn: document.getElementById('magicWriteBtn'),
            analyzeToneBtn: document.getElementById('analyzeToneBtn'),
            voiceSelect: document.getElementById('voiceSelect'),
            styleSelect: document.getElementById('styleSelect'),
            tracksContainer: document.getElementById('tracksContainer'),
            noTracks: document.getElementById('noTracks'),
            body: document.getElementById('bodyTag'),
            toast: document.getElementById('toast'),
            toastMessage: document.getElementById('toastMessage'),
            // API Key elements
            apiKeyBtn: document.getElementById('apiKeyBtn'),
            apiKeyPopover: document.getElementById('apiKeyPopover'),
            apiKeyInput: document.getElementById('apiKeyInput'),
            saveApiKey: document.getElementById('saveApiKey'),
            clearApiKey: document.getElementById('clearApiKey'),
            apiKeyStatus: document.getElementById('apiKeyStatus')
        };
 
        // Initialize UI
        function updateApiStatus() {
            if (currentApiKey) {
                els.apiKeyStatus.innerText = "מפתח מוגדר ✅";
                els.apiKeyStatus.classList.add('text-green-600');
                els.apiKeyInput.value = currentApiKey;
            } else {
                els.apiKeyStatus.innerText = "הגדר מפתח ⚠️";
                els.apiKeyStatus.classList.remove('text-green-600');
                els.apiKeyInput.value = "";
            }
        }
        updateApiStatus();
 
        // API Key Popover Toggle
        els.apiKeyBtn.onclick = (e) =&gt; {
            e.stopPropagation();
            els.apiKeyPopover.classList.toggle('hidden');
        };
 
        els.saveApiKey.onclick = () =&gt; {
            const key = els.apiKeyInput.value.trim();
            if (key) {
                currentApiKey = key;
                localStorage.setItem('gemini_api_key', key);
                updateApiStatus();
                els.apiKeyPopover.classList.add('hidden');
                showToast("מפתח ה-API נשמר בהצלחה", "success");
            }
        };
 
        els.clearApiKey.onclick = () =&gt; {
            currentApiKey = "";
            localStorage.removeItem('gemini_api_key');
            updateApiStatus();
            showToast("מפתח ה-API נמחק");
        };
 
        document.addEventListener('click', () =&gt; els.apiKeyPopover.classList.add('hidden'));
        els.apiKeyPopover.onclick = (e) =&gt; e.stopPropagation();
 
        // Utility: API Caller with retry logic
        async function apiCall(model, payload, retries = 5) {
            if (!currentApiKey) {
                showToast("אנא הגדר מפתח API בתפריט למעלה");
                els.apiKeyPopover.classList.remove('hidden');
                throw new Error("Missing API Key");
            }
 
            const url = `https://generativelanguage.googleapis.com/v1beta/models/${model}:${model.includes('tts') ? 'generateContent' : 'generateContent'}?key=${currentApiKey}`;
            
            for (let i = 0; i &lt; retries; i++) {
                try {
                    const response = await fetch(url, {
                        method: 'POST',
                        headers: { 'Content-Type': 'application/json' },
                        body: JSON.stringify(payload)
                    });
                    const data = await response.json();
                    if (response.ok) return data;
                    if (response.status === 429) {
                        await new Promise(r =&gt; setTimeout(r, Math.pow(2, i) * 1000));
                    } else if (response.status === 403 || response.status === 401) {
                        showToast("מפתח ה-API אינו תקין");
                        throw new Error("Invalid API Key");
                    } else {
                        throw new Error(data.error?.message || "Communication Error");
                    }
                } catch (e) {
                    if (i === retries - 1) throw e;
                }
            }
        }
 
        function showToast(msg, type = 'error') {
            els.toastMessage.innerText = msg;
            els.toast.className = `fixed bottom-4 sm:bottom-8 left-4 sm:left-8 right-4 sm:right-auto px-4 sm:px-6 py-3 rounded-xl shadow-2xl transition-all z-50 transform translate-y-0 opacity-100 ${type === 'error' ? 'bg-red-600' : 'bg-indigo-600'} text-white max-w-md flex items-center justify-center sm:justify-start gap-2`;
            setTimeout(() =&gt; { els.toast.classList.add('opacity-0', 'translate-y-4'); }, 4000);
        }
 
        // --- LLM Features ---
 
        // ✨ Magic Write
        els.magicWriteBtn.onclick = async () =&gt; {
            const prompt = els.promptInput.value.trim();
            if (!prompt) return showToast("תאר מה לכתוב בתיבה");
            
            toggleLoader('magic', true);
            try {
                const data = await apiCall(modelText, {
                    contents: [{ parts: [{ text: `כתוב סקריפט קצר ומקצועי לקריינות בעברית עבור הנושא הבא: "${prompt}". החזר רק את הטקסט של הסקריפט ללא הסברים או כותרות.` }] }]
                });
                const result = data.candidates?.[0]?.content?.parts?.[0]?.text;
                if (result) els.textInput.value = result.trim();
            } catch (e) { if(e.message !== "Missing API Key") showToast(e.message); }
            toggleLoader('magic', false);
        };
 
        // ✨ Smart Edit
        async function smartEdit(instruction) {
            const text = els.textInput.value.trim();
            if (!text) return showToast("הכנס קודם טקסט לתיבה");
            
            showToast("מעבד טקסט...", "success");
            try {
                const data = await apiCall(modelText, {
                    contents: [{ parts: [{ text: `${instruction} על הטקסט הבא: "${text}". החזר רק את הטקסט המעובד.` }] }]
                });
                const result = data.candidates?.[0]?.content?.parts?.[0]?.text;
                if (result) els.textInput.value = result.trim();
            } catch (e) { if(e.message !== "Missing API Key") showToast(e.message); }
        }
 
        // ✨ Translate
        async function translateText() {
            const text = els.textInput.value.trim();
            if (!text) return showToast("אין טקסט לתרגום");
            showToast("מתרגם לאנגלית...", "success");
            try {
                const data = await apiCall(modelText, {
                    contents: [{ parts: [{ text: `Translate the following text to fluent English suitable for narration: "${text}". Return only the translation.` }] }]
                });
                const result = data.candidates?.[0]?.content?.parts?.[0]?.text;
                if (result) els.textInput.value = result.trim();
            } catch (e) { if(e.message !== "Missing API Key") showToast(e.message); }
        }
 
        // ✨ Podcast Script
        async function generatePodcastScript() {
            const topic = els.promptInput.value.trim() || "Technology";
            showToast("יוצר תסריט פודקאסט...", "success");
            try {
                const data = await apiCall(modelText, {
                    contents: [{ parts: [{ text: `Create a short podcast script dialogue between two people about: "${topic}". Return only the dialogue in Hebrew.` }] }]
                });
                const result = data.candidates?.[0]?.content?.parts?.[0]?.text;
                if (result) els.textInput.value = result.trim();
            } catch (e) { if(e.message !== "Missing API Key") showToast(e.message); }
        }
 
        // ✨ Summarize
        async function summarizeText() {
            const text = els.textInput.value.trim();
            if (!text) return showToast("אין טקסט לסיכום");
            showToast("מסכם לנקודות...", "success");
            try {
                const data = await apiCall(modelText, {
                    contents: [{ parts: [{ text: `Summarize the following text into 3 clear key points for narration in Hebrew: "${text}".` }] }]
                });
                const result = data.candidates?.[0]?.content?.parts?.[0]?.text;
                if (result) els.textInput.value = result.trim();
            } catch (e) { if(e.message !== "Missing API Key") showToast(e.message); }
        }
 
        // ✨ Tone Analysis
        els.analyzeToneBtn.onclick = async () =&gt; {
            const text = els.textInput.value.trim();
            if (!text) return showToast("אין טקסט לניתוח");
            
            toggleLoader('tone', true);
            try {
                const data = await apiCall(modelText, {
                    contents: [{ parts: [{ text: `Analyze the sentiment of the following text and pick the best speaking style from this list: (natural, cheerful, serious, whisper, excited, calm, authoritative, friendly, professional, storytelling, shouting, terrified, sad, angry, hopeful). Return ONLY the English word. Text: "${text}"` }] }]
                });
                const choice = data.candidates?.[0]?.content?.parts?.[0]?.text?.trim().toLowerCase();
                if (choice) {
                    const cleanChoice = choice.replace(/[^a-z]/g, '');
                    const option = Array.from(els.styleSelect.options).find(o =&gt; o.value === cleanChoice);
                    if (option) {
                        els.styleSelect.value = cleanChoice;
                        showToast(`הסגנון הותאם ל: ${option.text}`, "success");
                    }
                }
            } catch (e) { if(e.message !== "Missing API Key") showToast(e.message); }
            toggleLoader('tone', false);
        };
 
        // ✨ Vocalization (Nikud)
        document.getElementById('vocalizeBtn').onclick = async () =&gt; {
            const text = els.textInput.value.trim();
            if (!text) return showToast("אין טקסט לניקוד");
            toggleLoader('vocalize', true);
            try {
                const data = await apiCall(modelText, {
                    contents: [{ parts: [{ text: `הוסף ניקוד דקדוקי מלא ומדויק לטקסט הבא בעברית: "${text}". החזר רק את הטקסט המנוקד.` }] }]
                });
                const result = data.candidates?.[0]?.content?.parts?.[0]?.text;
                if (result) els.textInput.value = result.trim();
            } catch (e) { if(e.message !== "Missing API Key") showToast(e.message); }
            toggleLoader('vocalize', false);
        };
 
        // --- TTS Core ---
        els.generateBtn.onclick = async () =&gt; {
            const text = els.textInput.value.trim();
            if (!text) return showToast("הכנס טקסט לקריינות");
            
            toggleLoader('btn', true);
            try {
                const result = await apiCall(modelAudio, {
                    contents: [{ parts: [{ text: `Say in a ${els.styleSelect.value} style: ${text}` }] }],
                    generationConfig: {
                        responseModalities: ["AUDIO"],
                        speechConfig: { 
                            voiceConfig: { 
                                prebuiltVoiceConfig: { 
                                    voiceName: els.voiceSelect.value 
                                } 
                            } 
                        }
                    }
                });
 
                const pcmData = result.candidates?.[0]?.content?.parts?.[0]?.inlineData?.data;
                const mimeType = result.candidates?.[0]?.content?.parts?.[0]?.inlineData?.mimeType || "";
                const sampleRate = parseInt(mimeType.split('rate=')[1]) || 24000;
 
                if (pcmData) {
                    const blob = pcmToWav(pcmData, sampleRate);
                    addTrack(blob, text.substring(0, 30));
                    showToast("קריינות הופקה בהצלחה!", "success");
                }
            } catch (e) { if(e.message !== "Missing API Key") showToast(e.message); }
            toggleLoader('btn', false);
        };
 
        // --- Helpers ---
        function toggleLoader(key, show) {
            const l = document.getElementById(key + 'Loader');
            const i = document.getElementById(key + 'Icon');
            const t = document.getElementById(key + 'Text');
            if (l) l.classList.toggle('hidden', !show);
            if (i) i.classList.toggle('hidden', show);
            if (t) t.innerText = show ? "מעבד..." : "הפק קריינות עכשיו";
            if (key === 'btn') els.generateBtn.disabled = show;
        }
 
        function pcmToWav(base64, rate) {
            const binary = atob(base64);
            const bytes = new Uint8Array(binary.length);
            for (let i = 0; i &lt; binary.length; i++) bytes[i] = binary.charCodeAt(i);
            const header = new ArrayBuffer(44);
            const v = new DataView(header);
            const s = (off, str) =&gt; { for (let i = 0; i &lt; str.length; i++) v.setUint8(off + i, str.charCodeAt(i)); };
            s(0, 'RIFF'); v.setUint32(4, 36 + bytes.length, true); s(8, 'WAVE'); s(12, 'fmt '); v.setUint32(16, 16, true);
            v.setUint16(20, 1, true); v.setUint16(22, 1, true); v.setUint32(24, rate, true); v.setUint32(28, rate * 2, true);
            v.setUint16(32, 2, true); v.setUint16(34, 16, true); s(36, 'data'); v.setUint32(40, bytes.length, true);
            return new Blob([header, bytes], { type: 'audio/wav' });
        }
 
        function addTrack(blob, title) {
            els.noTracks.classList.add('hidden');
            const url = URL.createObjectURL(blob);
            const div = document.createElement('div');
            div.className = "card p-3 sm:p-4 rounded-xl sm:rounded-2xl flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3 shadow-sm border-slate-100 dark:border-slate-800";
            div.innerHTML = `
                &lt;div class="flex-grow w-full sm:w-auto"&gt;
                    &lt;div class="font-bold text-xs sm:text-sm truncate dark:text-white"&gt;${title}...&lt;/div&gt;
                    &lt;div class="text-[10px] text-slate-400 mt-0.5"&gt;${els.voiceSelect.value} | ${els.styleSelect.value}&lt;/div&gt;
                &lt;/div&gt;
                &lt;div class="flex items-center justify-between sm:justify-end w-full sm:w-auto gap-2 border-t sm:border-t-0 pt-2 sm:pt-0 border-slate-100 dark:border-slate-800"&gt;
                    &lt;audio src="${url}" controls class="w-full sm:w-48"&gt;&lt;/audio&gt;
                    &lt;a href="${url}" download="voice_${Date.now()}.wav" class="p-2 hover:bg-indigo-50 dark:hover:bg-slate-700 rounded-lg text-indigo-600 flex-shrink-0"&gt;
                        &lt;svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"&gt;&lt;path d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"/&gt;&lt;/svg&gt;
                    &lt;/a&gt;
                &lt;/div&gt;
            `;
            els.tracksContainer.prepend(div);
        }
 
        document.getElementById('toggleDark').onclick = () =&gt; els.body.classList.toggle('dark-mode');
        document.getElementById('clearTracks').onclick = () =&gt; {
            els.tracksContainer.querySelectorAll('.card').forEach(c =&gt; c.remove());
            els.noTracks.classList.remove('hidden');
        };
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre>
<p dir="auto">בהצלחה!!!</p>
]]></description><link>https://bina.top/topic/154/voicemaster-אתר-קריינות-משוכלל</link><generator>RSS for Node</generator><lastBuildDate>Sun, 16 Aug 2026 23:14:03 GMT</lastBuildDate><atom:link href="https://bina.top/topic/154.rss" rel="self" type="application/rss+xml"/><pubDate>Thu, 13 Aug 2026 09:48:59 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to VoiceMaster אתר קריינות משוכלל!!! on Thu, 13 Aug 2026 10:28:00 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/bugs-bunny" aria-label="Profile: Bugs-Bunny">@<bdi>Bugs-Bunny</bdi></a> בשמחה....</p>
]]></description><link>https://bina.top/post/1982</link><guid isPermaLink="true">https://bina.top/post/1982</guid><dc:creator><![CDATA[אריה AI]]></dc:creator><pubDate>Thu, 13 Aug 2026 10:28:00 GMT</pubDate></item><item><title><![CDATA[Reply to VoiceMaster אתר קריינות משוכלל!!! on Thu, 13 Aug 2026 10:27:24 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/%D7%90%D7%A8%D7%99%D7%94-ai" aria-label="Profile: אריה-ai">@<bdi>אריה-ai</bdi></a> ממש נחמד תמשיכו להגדיל את המקום הנהדר הזה</p>
]]></description><link>https://bina.top/post/1981</link><guid isPermaLink="true">https://bina.top/post/1981</guid><dc:creator><![CDATA[Bugs Bunny]]></dc:creator><pubDate>Thu, 13 Aug 2026 10:27:24 GMT</pubDate></item></channel></rss>