דילוג לתוכן
  • חוקי הפורום
  • פופולרי
  • לא נפתר
  • משתמשים
  • חיפוש גוגל בפורום
  • צור קשר
עיצובים
  • בהיר
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • כהה
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • ברירת מחדל (ללא עיצוב (ברירת מחדל))
  • ללא עיצוב (ברירת מחדל)
כיווץ
מתמחים טופ
א

אריה AI

@אריה AI
הפסקת מעקב מעקב
אודות
פוסטים
150
נושאים
4
שיתופים
0
קבוצות
0
עוקבים
15
עוקב אחרי
434

פוסטים

פוסטים אחרונים הגבוה ביותר שנוי במחלוקת

  • שיתוף | חדש!!! VoiceMaster אתר קריינות משוכלל!!!
    א אריה AI

    לאחר זמן רב,
    שישבתי יומם ולילה לחשוב איך כל אדם שצריך איזשהו קריינות, יוכל ליצור אותה בקלות.
    לכן בניתי את האתר הזה
    קודם כל יש להיכנס ל-Google AI Studio וליצור מפתח API חדש ולעלות לאתר למעלה בצד שמאל.
    ואחרי זה תיצרו את הקריינות...

    עדכון ב' תמוז: נכון לעכשיו מי שצריך את האתר יכול להוריד את הקובץ שנמצא כאן...
    אני יסדר את האתר בקרוב...

    עזרה הדדית - בינה מלאכותית

  • שיתוף | האתר קריינות VoiceMaster המשוכלל שודרג!!! 🎙🎙🎙
    א אריה AI

    בהמשך לנושא הזה...
    שהאמת צבר תאוצה...
    לתועלת הכלל, ואחרי בקשות שונות,

    הנה הקובץ html המעודכן של האתר. פתחו פנקס רשימות, העתיקו אותו ושמרו אותו על שם מסוים עם הסיומת .html ...

    <!DOCTYPE html>
    <html lang="he" dir="rtl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>VoiceMaster AI Studio ✨</title>
        <script src="https://cdn.tailwindcss.com"></script>
        <style>
            @import url('https://fonts.googleapis.com/css2?family=Assistant:wght@300;400;600;700;800&display=swap');
            :root {
                --bg-1: #f6f3ff;
                --bg-2: #eef4ff;
                --bg-3: #fffaf0;
                --panel: rgba(255,255,255,0.8);
                --panel-strong: #ffffff;
                --text: #1f2937;
                --muted: #64748b;
                --line: rgba(148, 163, 184, 0.26);
                --brand: #4f46e5;
                --brand-2: #8b5cf6;
                --brand-3: #f59e0b;
                --gold: #eab308;
                --shadow: rgba(79, 70, 229, 0.14);
            }
    
            * { box-sizing: border-box; }
            html { scroll-behavior: smooth; }
            body {
                font-family: 'Assistant', sans-serif;
                width: 100%;
                max-width: 100vw;
                overflow-x: hidden;
                background:
                    radial-gradient(circle at top right, rgba(139, 92, 246, 0.18), transparent 18%),
                    radial-gradient(circle at bottom left, rgba(245, 158, 11, 0.14), transparent 20%),
                    linear-gradient(135deg, var(--bg-1), var(--bg-2), var(--bg-3));
                color: var(--text);
                transition: background 0.35s ease, color 0.35s ease;
            }
            body.dark-mode {
                --bg-1: #101426;
                --bg-2: #172033;
                --bg-3: #241e2d;
                --text: #e5e7eb;
                background:
                    radial-gradient(circle at top right, rgba(129, 140, 248, 0.18), transparent 20%),
                    radial-gradient(circle at bottom left, rgba(245, 158, 11, 0.10), transparent 22%),
                    linear-gradient(135deg, var(--bg-1), var(--bg-2), var(--bg-3));
            }
            body.dark-mode .card,
            body.dark-mode .floating-menu { background: rgba(23, 32, 51, 0.82); border-color: rgba(148, 163, 184, 0.22); }
            body.dark-mode .text-slate-800,
            body.dark-mode .text-slate-900,
            body.dark-mode .text-indigo-900 { color: #f8fafc !important; }
            body.dark-mode input,
            body.dark-mode select,
            body.dark-mode textarea,
            body.dark-mode .bg-slate-50,
            body.dark-mode .bg-slate-100 { background-color: #1e293b !important; color: #f8fafc !important; border-color: #334155; }
            body.dark-mode .bg-white { background-color: #1e293b !important; }
            body.dark-mode .border-slate-200,
            body.dark-mode .border-slate-300 { border-color: #334155 !important; }
    
            .page-shell {
                position: relative;
                width: 100%;
                min-width: 0;
                max-width: 1360px;
                margin: 0 auto;
                padding: clamp(14px, 3vw, 28px) clamp(12px, 3vw, 32px) 48px;
            }
            .page-shell::before,
            .page-shell::after {
                content: "";
                position: absolute;
                width: 280px;
                height: 280px;
                border-radius: 50%;
                filter: blur(90px);
                opacity: 0.42;
                z-index: 0;
                pointer-events: none;
            }
            .page-shell::before { right: -30px; top: 10px; background: rgba(79, 70, 229, 0.18); }
            .page-shell::after { left: -40px; bottom: 30px; background: rgba(245, 158, 11, 0.14); }
    
            .card {
                min-width: 0;
                max-width: 100%;
                background: rgba(255,255,255,0.74);
                backdrop-filter: blur(14px);
                border: 1px solid rgba(255,255,255,0.6);
                box-shadow: 0 18px 40px -22px rgba(31, 41, 55, 0.18);
                transition: all 0.28s ease;
            }
            .card:hover { transform: translateY(-1px); box-shadow: 0 24px 46px -24px rgba(79, 70, 229, 0.28); }
    
            .luxury-chip {
                background: linear-gradient(135deg, rgba(79, 70, 229, 0.12), rgba(245, 158, 11, 0.12));
                border: 1px solid rgba(79, 70, 229, 0.14);
                color: #4c1d95;
                border-radius: 999px;
                padding: 6px 12px;
                font-size: 11px;
                font-weight: 800;
                letter-spacing: 0.4px;
            }
    
            .floating-menu {
                background: rgba(255,255,255,0.65);
                border: 1px solid rgba(148, 163, 184, 0.2);
                backdrop-filter: blur(12px);
                box-shadow: 0 16px 34px -18px rgba(79,70,229,0.24);
            }
    
            .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); } }
    
            .pulse-soft {
                animation: pulseSoft 2.8s ease-in-out infinite;
            }
            @keyframes pulseSoft {
                0%, 100% { transform: scale(1); box-shadow: 0 0 0 rgba(79,70,229,0.12); }
                50% { transform: scale(1.02); box-shadow: 0 0 24px rgba(79,70,229,0.18); }
            }
    
            .feature-badge {
                background: linear-gradient(90deg, #4f46e5, #8b5cf6, #f59e0b);
                color: white;
                padding: 2px 8px;
                border-radius: 999px;
                font-size: 10px;
                font-weight: 800;
                box-shadow: 0 10px 20px -12px rgba(79, 70, 229, 0.7);
            }
    
            .premium-button {
                background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 48%, #f59e0b 100%);
                box-shadow: 0 18px 30px -18px rgba(79, 70, 229, 0.7);
            }
    
            .app-header {
                min-height: 76px;
                width: 100%;
                min-width: 0;
                position: relative;
                z-index: 1000 !important;
            }
            .header-controls {
                position: relative;
                margin-inline-start: auto;
            }
            .api-key-popover {
                position: absolute;
                top: calc(100% + 10px);
                right: 0 !important;
                left: auto !important;
                width: min(360px, calc(100vw - 24px)) !important;
                min-width: min(300px, calc(100vw - 24px));
                overflow-x: hidden;
                padding: 18px;
                z-index: 1000;
                pointer-events: auto;
                isolation: isolate;
            }
            .api-key-backdrop,
            .api-key-backdrop.hidden { display: none !important; }
            .api-key-backdrop:not(.hidden) { pointer-events: auto; }
            .api-key-popover h4 { display: flex; align-items: center; gap: 8px; }
            .api-key-popover .key-manager-note { font-size: 10px; color: #64748b; line-height: 1.5; margin-bottom: 10px; }
            .api-key-popover .key-form { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 8px; }
            .api-key-popover .key-form button { white-space: nowrap; }
            .saved-api-key-row {
                display: flex;
                align-items: center;
                justify-content: space-between;
                gap: 8px;
                width: 100%;
                min-width: 0;
            }
            .saved-api-key-row button {
                white-space: nowrap;
                flex: 0 0 auto;
            }
            .saved-api-key-row .saved-key {
                min-width: 0;
                flex: 1 1 auto;
                overflow: hidden;
                text-overflow: ellipsis;
            }
            .saved-api-key-row .copy-key,
            .saved-api-key-row .remove-key {
                min-width: 42px;
                text-align: center;
            }
            .brand-lockup,
            .header-controls,
            .app-main-grid > div { min-width: 0; }
            .app-main-grid {
                align-items: start;
                width: 100%;
                min-width: 0;
            }
            .studio-card {
                min-width: 0;
            }
            .floating-menu button {
                min-height: 38px;
                white-space: nowrap;
            }
            select, input, textarea {
                min-width: 0;
            }
    
            @media (max-width: 640px) {
                .page-shell { padding-bottom: 30px; }
                .app-header { align-items: flex-start; }
                .brand-lockup { max-width: calc(100vw - 92px); }
                .brand-lockup h1 { font-size: 1.45rem; }
                .header-controls { width: 100%; justify-content: flex-end; }
                .api-key-popover {
                    position: fixed;
                    top: 12px;
                    right: 12px !important;
                    left: 12px !important;
                    width: auto !important;
                    min-width: 0;
                    max-width: none;
                    max-height: calc(100dvh - 24px);
                    overflow-y: auto;
                    overscroll-behavior: contain;
                    border-radius: 24px;
                    pointer-events: auto;
                    touch-action: manipulation;
                }
                .api-key-backdrop {
                    display: block;
                    position: fixed;
                    inset: 0;
                    background: rgba(15, 23, 42, 0.42);
                    z-index: 900;
                }
                .api-key-backdrop:not(.hidden) { display: block !important; }
                .floating-menu {
                    justify-content: flex-start;
                    flex-wrap: nowrap;
                    overflow-x: auto;
                    scrollbar-width: none;
                    margin-inline: -4px;
                    padding-inline: 4px;
                }
                .floating-menu::-webkit-scrollbar { display: none; }
                .floating-menu button { flex: 0 0 auto; }
                .studio-card { border-radius: 1.35rem; }
                #textInput { min-height: 150px; }
                #customStyleInput { min-width: 0; }
                #generateBtn { min-height: 54px; }
                audio { width: 100%; }
            }
    
            audio { max-width: 100%; height: 36px; }
            input, select, textarea, button { font-family: 'Assistant', sans-serif; }
            textarea::-webkit-scrollbar { width: 8px; }
            textarea::-webkit-scrollbar-thumb { background: rgba(99,102,241,0.28); border-radius: 10px; }
        </style>
    </head>
    <body class="min-h-screen" id="bodyTag">
        <div class="page-shell">
            <header class="app-header relative z-10 flex flex-wrap justify-between items-center gap-4 mb-6 sm:mb-8 pb-4 border-b border-slate-200/80">
                <div class="brand-lockup flex items-center gap-3 sm:gap-4">
                    <div class="bg-gradient-to-br from-indigo-600 via-violet-500 to-amber-400 p-2.5 sm:p-3 rounded-2xl text-white shadow-xl flex-shrink-0 ring-8 ring-indigo-500/10 pulse-soft">
                        <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">
                            <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" />
                        </svg>
                    </div>
                    <div>
                        <h1 class="text-2xl sm:text-3xl font-black tracking-tight leading-none uppercase text-slate-800">Voice<span class="text-indigo-600">Master</span></h1>
                        <div class="mt-1 flex flex-wrap items-center gap-2">
                            <p class="text-[10px] sm:text-xs font-bold text-slate-400 uppercase tracking-widest">AI Smart Narration Hub</p>
                        </div>
                    </div>
                </div>
    
                <div class="header-controls flex items-center gap-2 sm:gap-3">
                    <div class="relative">
                        <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">
                            <svg class="w-4 h-4 sm:w-5 sm:h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><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"/></svg>
                            <span id="apiKeyStatus" class="hidden sm:inline">הגדר מפתח</span>
                        </button>
                        <div id="apiKeyPopover" class="api-key-popover hidden card rounded-2xl shadow-2xl">
                            <h4 class="font-bold text-sm mb-1 text-slate-800"><span class="text-indigo-600">●</span> ניהול מפתחות API</h4>
                            <p class="key-manager-note">הוסף כמה מפתחות, בחר מפתח פעיל, העתק או מחק. המפתחות נשמרים מקומית בדפדפן.</p>
                            <div class="key-form">
                                <input id="apiKeyInput" type="password" class="w-full p-2.5 text-xs bg-slate-50 rounded-lg border border-slate-200 outline-none focus:ring-2 focus:ring-indigo-500 text-slate-800" placeholder="הדבק כאן מפתח Gemini">
                                <button id="saveApiKey" type="button" class="px-3 py-2 bg-indigo-600 text-white text-[11px] font-bold rounded-lg hover:bg-indigo-700 active:scale-95 transition-all">הוסף</button>
                            </div>
                            <div class="flex gap-2 mt-2">
                                <button id="newApiKeyBtn" type="button" class="flex-1 py-2 bg-slate-100 text-slate-700 text-[11px] font-bold rounded-lg hover:bg-indigo-50 active:scale-95 transition-all">מפתח חדש</button>
                                <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">מחק פעיל</button>
                            </div>
                            <div class="mt-3 border-t border-slate-200 pt-3">
                                <div class="flex items-center justify-between mb-2">
                                    <span class="text-[10px] font-bold text-slate-500">מפתחות שמורים</span>
                                    <span id="apiKeyCount" class="text-[10px] text-slate-400">0</span>
                                </div>
                                <div id="savedApiKeysList" class="space-y-2"></div>
                            </div>
                        </div>
                    </div>
                    <button id="toggleDark" class="p-2.5 sm:p-3 rounded-xl card shadow-sm hover:scale-105 active:scale-95 transition-all text-slate-600" aria-label="החלף מצב לילה" title="החלף מצב לילה">
                        <svg id="darkModeIcon" class="h-5 w-5 sm:h-6 sm:w-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                            <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"/>
                        </svg>
                    </button>
                </div>
            </header>
    
            <div id="apiKeyBackdrop" class="api-key-backdrop" aria-hidden="true"></div>
    
            <div class="app-main-grid grid grid-cols-1 lg:grid-cols-12 gap-6 lg:gap-8">
                <div class="lg:col-span-5 space-y-6">
                    <div class="studio-card card p-4 sm:p-6 rounded-2xl sm:rounded-[2rem] shadow-lg border-indigo-100 pulse-soft">
                        <div class="flex items-center justify-between mb-3 sm:mb-4">
                            <h3 class="font-black text-sm sm:text-base text-indigo-900">יצירת תוכן חכמה</h3>
                        </div>
                        <div class="flex gap-2 mb-3 sm:mb-4">
                            <input id="promptInput" type="text" class="flex-grow p-3 bg-slate-50/90 rounded-xl text-xs sm:text-sm border border-slate-200 outline-none focus:ring-2 focus:ring-indigo-500 text-slate-800" placeholder="תאר מה לכתוב (למשל: פרסומת לשירות חדש)...">
                            <button id="magicWriteBtn" class="p-3 premium-button text-white rounded-xl hover:brightness-110 active:scale-95 transition-all flex items-center justify-center min-w-[48px] sm:min-w-[50px] shadow-lg shadow-indigo-500/25">
                                <span id="magicIcon">✨</span>
                                <div id="magicLoader" class="loading-spinner hidden"></div>
                            </button>
                        </div>
                        <div class="grid grid-cols-2 sm:grid-cols-3 gap-2">
                            <button onclick="smartEdit('הפוך את הטקסט ליותר רגוע ונעים')" class="text-[11px] font-bold py-2 px-1 bg-slate-100 rounded-lg hover:bg-indigo-50 text-slate-700 active:scale-95 transition-all truncate">✨ ריכוך</button>
                            <button onclick="smartEdit('הפוך את הטקסט ליותר שיווקי ואנרגטי')" class="text-[11px] font-bold py-2 px-1 bg-slate-100 rounded-lg hover:bg-indigo-50 text-slate-700 active:scale-95 transition-all truncate">✨ שיווקי</button>
                            <button onclick="smartEdit('קצר את הטקסט ב-30% מבלי לאבד משמעות')" class="text-[11px] font-bold py-2 px-1 bg-slate-100 rounded-lg hover:bg-indigo-50 text-slate-700 active:scale-95 transition-all truncate">✨ קיצור</button>
                            <button onclick="translateText()" class="text-[11px] font-bold py-2 px-1 bg-indigo-50 text-indigo-700 rounded-lg hover:bg-indigo-100 active:scale-95 transition-all truncate">✨ תרגם</button>
                            <button onclick="generatePodcastScript()" class="text-[11px] font-bold py-2 px-1 bg-indigo-50 text-indigo-700 rounded-lg hover:bg-indigo-100 active:scale-95 transition-all truncate">✨ פודקאסט</button>
                            <button onclick="summarizeText()" class="text-[11px] font-bold py-2 px-1 bg-amber-50 text-amber-700 rounded-lg hover:bg-amber-100 active:scale-95 transition-all truncate">✨ סיכום</button>
                        </div>
                    </div>
     
                    <div class="studio-card card p-4 sm:p-7 rounded-2xl sm:rounded-[2.5rem] shadow-xl border-none">
                        <div class="flex flex-wrap justify-between items-center gap-2 mb-2">
                            <label class="text-xs sm:text-sm font-bold text-slate-500">טקסט לקריינות</label>
                            <button id="analyzeToneBtn" class="text-[10px] sm:text-[11px] font-bold text-indigo-600 bg-indigo-50 px-2.5 py-1 rounded-full hover:bg-indigo-100 active:scale-95 transition-all flex items-center gap-1">
                                <span>✨ התאם סגנון אוטומטית</span>
                                <div id="toneLoader" class="loading-spinner hidden !w-3 !h-3"></div>
                            </button>
                        </div>
                        <textarea id="textInput" rows="5" class="w-full p-3 sm:p-4 bg-slate-50/90 rounded-xl sm:rounded-2xl outline-none border-2 border-transparent focus:border-indigo-500 transition-all text-base sm:text-lg text-slate-800 resize-y shadow-inner shadow-slate-200/50" placeholder="הטקסט יופיע כאן..."></textarea>
    
                        <div class="flex gap-2 mt-3 mb-5">
                            <button id="vocalizeBtn" class="flex-1 py-2.5 sm:py-3 bg-slate-50 text-slate-600 rounded-xl text-xs font-bold hover:bg-indigo-50 active:scale-95 transition-all flex items-center justify-center gap-2 border border-slate-100">
                                <span>✨ ניקוד אוטומטי</span>
                                <div id="vocalizeLoader" class="loading-spinner hidden"></div>
                            </button>
                        </div>
    
                        <div class="grid grid-cols-1 sm:grid-cols-2 gap-3 sm:gap-4 mb-6">
                            <div>
                                <label class="text-[10px] font-bold text-slate-400 uppercase mr-1 block mb-1">קול</label>
                                <select id="voiceSelect" class="w-full p-3 bg-slate-100 rounded-xl text-xs sm:text-sm font-bold border-none outline-none cursor-pointer text-slate-800"></select>
                            </div>
                            <div>
                                <label class="text-[10px] font-bold text-slate-400 uppercase mr-1 block mb-1">סגנון והגשה</label>
                                <select id="styleSelect" class="w-full p-3 bg-slate-100 rounded-xl text-xs sm:text-sm font-bold border-none outline-none cursor-pointer text-slate-800"></select>
                            </div>
                        </div>
    
                        <div class="mb-4">
                            <label class="text-[10px] font-bold text-slate-400 uppercase mr-1 block mb-1">סגנון מותאם אישית</label>
                            <div class="flex gap-2">
                                <input id="customStyleInput" type="text" class="flex-1 p-3 bg-slate-50 rounded-xl border border-slate-200 outline-none focus:ring-2 focus:ring-indigo-500 text-xs text-slate-800" placeholder="לדוגמה: קריין יוקרתי, איטי, חם ומדויק">
                                <button id="saveCustomStyleBtn" class="px-3 py-2 rounded-xl bg-slate-800 text-white text-[11px] font-bold hover:bg-slate-700 active:scale-95 transition-all">שמור</button>
                            </div>
                        </div>
    
                        <button id="generateBtn" class="w-full premium-button hover:brightness-110 active:scale-[0.98] text-white font-bold py-3.5 sm:py-4 rounded-xl sm:rounded-2xl shadow-lg shadow-indigo-500/30 transition-all flex items-center justify-center gap-3">
                            <span id="btnText" class="text-sm sm:text-base">הפק קריינות עכשיו</span>
                            <div id="btnLoader" class="loading-spinner hidden !border-t-white"></div>
                        </button>
                    </div>
                </div>
     
                <div class="lg:col-span-7">
                    <div class="flex justify-between items-center mb-4">
                        <div>
                            <h2 class="text-lg sm:text-xl font-black text-slate-900">הקלטות אחרונות</h2>
                            <p class="text-[11px] text-slate-400">היסטוריית שמירת הקול שלך</p>
                        </div>
                        <button id="clearTracks" class="text-xs text-slate-400 hover:text-red-500 font-bold transition-colors">נקה הכל</button>
                    </div>
                    <div id="tracksContainer" class="space-y-3 sm:space-y-4">
                        <div id="noTracks" class="text-center py-16 sm:py-24 border-2 border-dashed border-slate-300 rounded-2xl sm:rounded-[2.5rem] text-slate-400 font-bold text-sm sm:text-base bg-white/25">
                            היסטוריית הקריינות שלך תישמר כאן
                        </div>
                    </div>
                </div>
            </div>
    
            <footer class="relative z-10 mt-10 sm:mt-14 rounded-2xl sm:rounded-[2rem] border border-white/70 bg-white/55 p-5 sm:p-7 text-center shadow-lg backdrop-blur-md">
                <div class="mx-auto max-w-2xl">
                    <div class="mb-2 flex items-center justify-center gap-2">
                    </div>
                    <p class="text-base sm:text-lg font-black text-slate-800">אתר זה פותח על ידי אריה AI</p>
                    <p class="mt-2 text-xs sm:text-sm text-slate-500">אפשר למצוא את אריה AI גם בפורומים:</p>
                    <div class="mt-4 flex flex-col sm:flex-row items-stretch justify-center gap-2 sm:gap-3">
                        <a href="https://f2.freeivr.co.il/user/%D7%90%D7%A8%D7%99%D7%94-ai" target="_blank" rel="noopener noreferrer" class="rounded-xl border border-indigo-200 bg-indigo-50 px-4 py-3 text-xs sm:text-sm font-bold text-indigo-700 transition-all hover:-translate-y-0.5 hover:bg-indigo-100">אריה AI בפורום ימות המשיח</a>
                        <a href="https://mitmachim.top/user/%D7%90%D7%A8%D7%99%D7%94-ai" target="_blank" rel="noopener noreferrer" class="rounded-xl border border-amber-200 bg-amber-50 px-4 py-3 text-xs sm:text-sm font-bold text-amber-700 transition-all hover:-translate-y-0.5 hover:bg-amber-100">אריה AI בפורום מתמחים טופ</a>
                    </div>
                    <div class="mt-5 border-t border-slate-200/80 pt-4">
                        <p class="text-xs sm:text-sm font-bold text-slate-600">לפניות, הצעות ייעול  :</p>
                        <a href="mailto:a0733641352@gmail.com" class="mt-1 inline-block text-sm sm:text-base font-black text-indigo-600 transition-colors hover:text-amber-600">a0733641352@gmail.com</a>
                    </div>
                </div>
            </footer>
        </div>
     
        <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">
            <span id="toastIcon"></span>
            <span id="toastMessage" class="text-xs sm:text-sm font-semibold"></span>
        </div>
     
        <script>
            // Global State & Config
            function readStoredArray(key) {
                try {
                    const value = JSON.parse(localStorage.getItem(key) || '[]');
                    return Array.isArray(value) ? value : [];
                } catch (error) {
                    return [];
                }
            }
    
            let savedApiKeys = readStoredArray('gemini_api_keys').filter((key) => typeof key === 'string' && key.trim());
            const legacyApiKey = localStorage.getItem('gemini_api_key') || '';
            if (legacyApiKey && !savedApiKeys.includes(legacyApiKey)) savedApiKeys.push(legacyApiKey);
            let currentApiKey = localStorage.getItem('gemini_active_api_key') || savedApiKeys[0] || '';
            let customStyles = readStoredArray('custom_voice_styles');
            const apiKeyCooldowns = new Map();
            const modelText = "gemini-3.5-flash";
            const modelAudio = "gemini-2.5-flash-preview-tts";
    
            const voiceCatalog = {
                male: [
                    ['Zephyr', 'קליל'], ['Fenrir', 'עמוק'], ['Puck', 'שובב'], ['Charon', 'סמכותי'], ['Orus', 'קלאסי'],
                    ['Enceladus', 'צעיר'], ['Iapetus', 'חם'], ['Algieba', 'נמרץ'], ['Rasalgethi', 'בוגר'], ['Achernar', 'יציב'],
                    ['Alnilam', 'בהיר'], ['Schedar', 'נעים'], ['Achird', 'שידורי'], ['Zubenelgenubi', 'עמוק מאוד'],
                    ['Sadachbia', 'רך'], ['Sadaltager', 'טבעי'], ['Sulafat', 'עוצמתי'],
                    ['Zephyr', 'פרסומי'], ['Zephyr', 'רגוע'], ['Zephyr', 'חברי'], ['Zephyr', 'דוקומנטרי'],
                    ['Fenrir', 'קולנועי'], ['Fenrir', 'דרמטי'], ['Fenrir', 'חדשותי'], ['Fenrir', 'מלכותי'],
                    ['Puck', 'צעיר ואנרגטי'], ['Puck', 'קומי'], ['Puck', 'פודקאסט'], ['Puck', 'שיווקי'],
                    ['Charon', 'קריין חד'], ['Charon', 'מנחה'], ['Charon', 'עסקי'], ['Charon', 'רשמי'],
                    ['Orus', 'חם ובוגר'], ['Orus', 'מספר סיפורים'], ['Orus', 'אלגנטי'], ['Orus', 'מוטיבציוני'],
                    ['Iapetus', 'פרימיום'], ['Iapetus', 'עמוק וחם'], ['Algieba', 'ספורטיבי'], ['Algieba', 'מהיר'],
                    ['Rasalgethi', 'בשל ורגוע'], ['Achernar', 'יציב וברור'], ['Alnilam', 'בהיר ודינמי']
                ],
                female: [
                    ['Kore', 'מקצועי'], ['Leda', 'עדין'], ['Aoede', 'רך'], ['Callirrhoe', 'רהוט'], ['Autonoe', 'אנרגטי'],
                    ['Umbriel', 'מסתורי'], ['Despina', 'מהיר'], ['Erinome', 'ידידותי'], ['Algenib', 'חדשותי'],
                    ['Laomedeia', 'מרגיע'], ['Gacrux', 'אלגנטי'], ['Pulcherrima', 'עשיר'], ['Vindemiatrix', 'סבלני']
                ]
            };
    
            const styleCatalog = [
                { value: 'natural', label: 'טבעי (Natural)' },
                { value: 'broadcast', label: 'שידור (Broadcast)' },
                { value: 'cheerful', label: 'שמח (Cheerful)' },
                { value: 'serious', label: 'רציני (Serious)' },
                { value: 'whisper', label: 'לחישה (Whisper)' },
                { value: 'excited', label: 'נרגש (Excited)' },
                { value: 'calm', label: 'רגוע (Calm)' },
                { value: 'authoritative', label: 'סמכותי (Authoritative)' },
                { value: 'friendly', label: 'ידידותי (Friendly)' },
                { value: 'professional', label: 'מקצועי (Professional)' },
                { value: 'storytelling', label: 'מספר סיפורים (Storytelling)' },
                { value: 'documentary', label: 'דוקומנטרי (Documentary)' },
                { value: 'podcast', label: 'פודקאסט (Podcast)' },
                { value: 'commercial', label: 'פרסומת (Commercial)' },
                { value: 'dramatic', label: 'דרמטי (Dramatic)' },
                { value: 'warm', label: 'חם (Warm)' },
                { value: 'confident', label: 'ביטחון (Confident)' },
                { value: 'gentle', label: 'עדין (Gentle)' },
                { value: 'energetic', label: 'אנרגטי (Energetic)' },
                { value: 'luxury', label: 'יוקרתי (Luxury)' },
                { value: 'inspiring', label: 'מעורר השראה (Inspiring)' },
                { value: 'technical', label: 'טכני (Technical)' },
                { value: 'shouting', label: 'צעקה (Shouting)' },
                { value: 'terrified', label: 'מבועת (Terrified)' },
                { value: 'sad', label: 'עצוב (Sad)' },
                { value: 'angry', label: 'כועס (Angry)' },
                { value: 'hopeful', label: 'מלא תקווה (Hopeful)' },
                { value: 'cinematic', label: 'קולנועי (Cinematic)' },
                { value: 'royal', label: 'מלכותי (Royal)' },
                { value: 'motivational', label: 'מוטיבציוני (Motivational)' }
            ];
    
            function saveApiKeyState() {
                savedApiKeys = [...new Set(savedApiKeys.filter((key) => typeof key === 'string' && key.trim()))];
                try {
                    localStorage.setItem('gemini_api_keys', JSON.stringify(savedApiKeys));
                    if (currentApiKey) localStorage.setItem('gemini_active_api_key', currentApiKey);
                    else localStorage.removeItem('gemini_active_api_key');
                    return true;
                } catch (error) {
                    return false;
                }
            }
    
            function renderSavedApiKeys() {
                const list = document.getElementById('savedApiKeysList');
                const count = document.getElementById('apiKeyCount');
                if (!list || !count) return;
                count.textContent = String(savedApiKeys.length);
                list.innerHTML = savedApiKeys.length ? '' : '<div class="text-[10px] text-slate-400">אין מפתחות שמורים</div>';
                savedApiKeys.forEach((key) => {
                    const row = document.createElement('div');
                    const masked = `${key.slice(0, 6)}...${key.slice(-4)}`;
                    row.className = 'saved-api-key-row rounded-lg border border-slate-200 bg-white px-2 py-1.5';
                    row.innerHTML = `<button class="saved-key flex-1 text-right text-[10px] font-bold ${key === currentApiKey ? 'text-indigo-600' : 'text-slate-600'}" data-key="${key}">${key === currentApiKey ? '✓ ' : ''}${masked}</button><button class="copy-key text-[10px] font-bold text-indigo-600" data-key="${key}">העתק</button><button class="remove-key text-[10px] font-bold text-red-500" data-key="${key}">מחק</button>`;
                    list.appendChild(row);
                });
                list.querySelectorAll('.saved-key').forEach((button) => {
                    button.onclick = () => { currentApiKey = button.dataset.key; saveApiKeyState(); updateApiStatus(); renderSavedApiKeys(); };
                });
                list.querySelectorAll('.remove-key').forEach((button) => {
                    button.onclick = () => {
                        savedApiKeys = savedApiKeys.filter((key) => key !== button.dataset.key);
                        if (currentApiKey === button.dataset.key) currentApiKey = savedApiKeys[0] || '';
                        saveApiKeyState(); updateApiStatus(); renderSavedApiKeys();
                    };
                });
                list.querySelectorAll('.copy-key').forEach((button) => {
                    button.onclick = async () => {
                        await copyApiKey(button.dataset.key);
                        showToast('מפתח ה-API הועתק', 'success');
                    };
                });
            }
     
            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'),
                customStyleInput: document.getElementById('customStyleInput'),
                saveCustomStyleBtn: document.getElementById('saveCustomStyleBtn'),
                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'),
                newApiKeyBtn: document.getElementById('newApiKeyBtn'),
                apiKeyBackdrop: document.getElementById('apiKeyBackdrop')
            };
    
            function setApiKeyPopover(open) {
                els.apiKeyPopover.classList.toggle('hidden', !open);
                els.apiKeyBackdrop.classList.toggle('hidden', !open);
                if (open) {
                    requestAnimationFrame(() => els.apiKeyInput.focus());
                }
            }
    
            async function copyApiKey(key) {
                try {
                    await navigator.clipboard.writeText(key);
                } catch (error) {
                    els.apiKeyInput.value = key;
                    els.apiKeyInput.select();
                    document.execCommand('copy');
                }
            }
     
            function populateVoiceSelect() {
                const group = (label, voices) => `<optgroup label="${label}">${voices.map(([id, description]) => `<option value="${id}">${id} (${description})</option>`).join('')}</optgroup>`;
                els.voiceSelect.innerHTML = group('קולות גבריים', voiceCatalog.male) + group('קולות נשיים', voiceCatalog.female);
                els.voiceSelect.value = 'Zephyr';
            }
    
            function populateStyleSelect() {
                const options = [...styleCatalog, ...customStyles].map(item => `<option value="${item.value}">${item.label}</option>`).join('');
                els.styleSelect.innerHTML = options;
                els.styleSelect.value = 'professional';
            }
    
            // Initialize UI
            populateVoiceSelect();
            populateStyleSelect();
            saveApiKeyState();
            renderSavedApiKeys();
    
            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();
    
            els.newApiKeyBtn.onclick = () => {
                els.apiKeyInput.value = '';
                els.apiKeyInput.type = 'password';
                els.apiKeyInput.focus();
                els.saveApiKey.innerText = 'הוסף מפתח';
            };
    
            const savedDarkMode = localStorage.getItem('voice_master_dark_mode') === 'true';
            const toggleDark = document.getElementById('toggleDark');
            const darkModeIcon = document.getElementById('darkModeIcon');
            function updateDarkModeButton() {
                const isDark = els.body.classList.contains('dark-mode');
                toggleDark.setAttribute('aria-label', isDark ? 'עבור למצב יום' : 'עבור למצב לילה');
                toggleDark.title = isDark ? 'עבור למצב יום' : 'עבור למצב לילה';
                darkModeIcon.innerHTML = isDark
                    ? '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364-6.364l-.707.707M6.343 17.657l-.707.707m12.728 0l-.707-.707M6.343 6.343l-.707-.707M16 12a4 4 0 11-8 0 4 4 0 018 0z"/>'
                    : '<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"/>';
            }
            if (savedDarkMode) els.body.classList.add('dark-mode');
            updateDarkModeButton();
            toggleDark.onclick = () => {
                els.body.classList.toggle('dark-mode');
                localStorage.setItem('voice_master_dark_mode', String(els.body.classList.contains('dark-mode')));
                updateDarkModeButton();
            };
    
            document.getElementById('apiKeyInput').insertAdjacentHTML('afterend', '<button id="copyApiKeyBtn" type="button" class="w-full mt-2 py-2 bg-slate-100 text-slate-700 text-[11px] font-bold rounded-lg hover:bg-indigo-50 active:scale-95 transition-all">העתק מפתח נוכחי</button>');
            document.getElementById('copyApiKeyBtn').onclick = async () => {
                const key = els.apiKeyInput.value.trim() || currentApiKey;
                if (!key) return showToast('אין מפתח API להעתקה');
                await copyApiKey(key);
                showToast('מפתח ה-API הועתק', 'success');
            };
     
            // API Key Popover Toggle
            els.apiKeyBtn.onclick = (e) => {
                e.stopPropagation();
                setApiKeyPopover(els.apiKeyPopover.classList.contains('hidden'));
            };
     
            function addApiKey() {
                const key = els.apiKeyInput.value.trim();
                if (!key) {
                    showToast('הדבק מפתח API לפני ההוספה');
                    els.apiKeyInput.focus();
                    return false;
                }
                if (key.length < 20) {
                    showToast('מפתח ה־API קצר מדי או לא הוזן במלואו');
                    els.apiKeyInput.focus();
                    return false;
                }
    
                const wasExisting = savedApiKeys.includes(key);
                if (!wasExisting) savedApiKeys.push(key);
                currentApiKey = key;
                if (!saveApiKeyState()) {
                    if (!wasExisting) savedApiKeys = savedApiKeys.filter((item) => item !== key);
                    showToast('לא ניתן לשמור בדפדפן. אפשר הרשאת אחסון ונסה שוב');
                    return false;
                }
    
                renderSavedApiKeys();
                updateApiStatus();
                els.apiKeyInput.value = '';
                els.saveApiKey.innerText = 'הוסף';
                setApiKeyPopover(false);
                showToast(wasExisting ? 'המפתח כבר היה שמור והוא נבחר כמפתח הפעיל' : 'מפתח ה־API נוסף בהצלחה', 'success');
                return true;
            }
    
            els.saveApiKey.onclick = addApiKey;
            els.apiKeyInput.addEventListener('keydown', (event) => {
                if (event.key === 'Enter') {
                    event.preventDefault();
                    addApiKey();
                }
            });
     
            els.clearApiKey.onclick = () => {
                savedApiKeys = savedApiKeys.filter((key) => key !== currentApiKey);
                currentApiKey = savedApiKeys[0] || "";
                saveApiKeyState();
                renderSavedApiKeys();
                updateApiStatus();
                showToast("מפתח ה-API נמחק");
            };
    
            els.saveCustomStyleBtn.onclick = () => {
                const label = els.customStyleInput.value.trim();
                if (!label) return showToast('כתוב תיאור לסגנון המותאם אישית');
                const value = `custom_${Date.now()}`;
                customStyles.push({ value, label: `מותאם אישית: ${label}`, instruction: label });
                localStorage.setItem('custom_voice_styles', JSON.stringify(customStyles));
                populateStyleSelect();
                els.styleSelect.value = value;
                els.customStyleInput.value = '';
                showToast('הסגנון המותאם נשמר', 'success');
            };
     
            document.addEventListener('click', (event) => {
                if (!els.apiKeyPopover.contains(event.target) && event.target !== els.apiKeyBtn) setApiKeyPopover(false);
            });
            els.apiKeyPopover.onclick = (e) => e.stopPropagation();
            els.apiKeyPopover.addEventListener('pointerdown', (e) => e.stopPropagation());
            els.apiKeyBackdrop.onclick = () => setApiKeyPopover(false);
     
            // Utility: Try each available key once, then stop to avoid wasting quota.
            async function apiCall(model, payload) {
                if (!currentApiKey) {
                    showToast("אנא הוסף מפתח API בתפריט מפתחות ה־API");
                    setApiKeyPopover(true);
                    const error = new Error('Missing API Key');
                    error.userMessage = 'לא הוגדר מפתח API.';
                    throw error;
                }
    
                const availableKeys = savedApiKeys.length ? [...savedApiKeys] : [currentApiKey];
                const orderedKeys = [currentApiKey, ...availableKeys.filter((key) => key !== currentApiKey)];
                let lastError = null;
    
                for (const key of orderedKeys) {
                    const cooldownUntil = apiKeyCooldowns.get(key) || 0;
                    if (cooldownUntil > Date.now()) continue;
                    const url = `https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent?key=${encodeURIComponent(key)}`;
                    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;
    
                        lastError = new Error(data.error?.message || 'API request failed');
                        lastError.status = response.status;
                        lastError.userMessage = getHebrewApiError(response.status, data.error?.message);
                        if (response.status === 429) {
                            apiKeyCooldowns.set(key, Date.now() + 30000);
                        } else if (response.status === 401 || response.status === 403) {
                            apiKeyCooldowns.set(key, Date.now() + 300000);
                        } else {
                            throw lastError;
                        }
                    } catch (error) {
                        lastError = error;
                        if (error.name === 'TypeError') {
                            lastError.userMessage = 'אין חיבור לאינטרנט או שהדפדפן חסם את הבקשה.';
                        }
                        if (error.status && ![401, 403, 429].includes(error.status)) throw error;
                    }
                }
    
                if (lastError) throw lastError;
                const cooldownError = new Error('All API keys are cooling down');
                cooldownError.userMessage = 'כל מפתחות ה־API בהמתנה זמנית. נסה שוב בעוד חצי דקה.';
                throw cooldownError;
            }
    
            function rotateApiKey() {
                const availableKey = savedApiKeys.find((key) => (apiKeyCooldowns.get(key) || 0) <= Date.now());
                if (!availableKey || availableKey === currentApiKey) return false;
                currentApiKey = availableKey;
                saveApiKeyState();
                updateApiStatus();
                renderSavedApiKeys();
                return true;
            }
    
            function cleanGeneratedText(text) {
                return String(text || '')
                    .replace(/^[\s`*_#>-]+/gm, '')
                    .replace(/[\*#`]/g, '')
                    .replace(/^\s*\d+[.)]\s*/gm, '')
                    .replace(/\n{3,}/g, '\n\n')
                    .trim();
            }
    
            function getHebrewApiError(status, serverMessage = '') {
                if (status === 400) return 'הבקשה אינה תקינה. בדוק את הטקסט או את הגדרות הקריינות.';
                if (status === 401 || status === 403) return 'מפתח ה־API אינו תקין או שאין לו הרשאה.';
                if (status === 404) return 'השירות או המודל המבוקש אינם זמינים כרגע.';
                if (status === 429) return 'המפתח הגיע למגבלת השימוש. המערכת תנסה מפתח אחר אם קיים.';
                if (status >= 500) return 'שירות Gemini אינו זמין כרגע. נסה שוב מאוחר יותר.';
                if (!serverMessage) return 'אירעה שגיאה בתקשורת עם Gemini.';
                return 'אירעה שגיאה בתקשורת עם Gemini. בדוק את המפתח ואת החיבור לאינטרנט.';
            }
    
            function showHebrewError(error) {
                const message = error?.userMessage || getHebrewApiError(error?.status, error?.message);
                if (message && message !== 'Missing API Key') showToast(message);
            }
     
            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(() => { els.toast.classList.add('opacity-0', 'translate-y-4'); }, 4000);
            }
     
            // --- LLM Features ---
     
            // ✨ Magic Write
            els.magicWriteBtn.onclick = async () => {
                const prompt = els.promptInput.value.trim();
                if (!prompt) return showToast("תאר מה לכתוב בתיבה");
                
                toggleLoader('magic', true);
                try {
                    const data = await apiCall(modelText, {
                        contents: [{ parts: [{ text: `כתוב טקסט קצר ומקצועי לקריינות בעברית בנושא הבא: "${prompt}". השתמש בעברית בלבד. אל תכתוב כותרות, רשימות, כוכביות, סולמיות, סימוני Markdown, מספרי סעיפים, קוד או תגיות. החזר רק את הטקסט הנקי.` }] }]
                    });
                    const result = data.candidates?.[0]?.content?.parts?.[0]?.text;
                    if (result) els.textInput.value = cleanGeneratedText(result);
                } catch (e) { if(e.message !== "Missing API Key") showHebrewError(e); }
                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}". החזר בעברית בלבד טקסט נקי, בלי כותרות, רשימות, כוכביות, סולמיות, סימוני Markdown, מספרים, קוד או תגיות.` }] }]
                    });
                    const result = data.candidates?.[0]?.content?.parts?.[0]?.text;
                    if (result) els.textInput.value = cleanGeneratedText(result);
                } catch (e) { if(e.message !== "Missing API Key") showHebrewError(e); }
            }
     
            // ✨ 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: `שכתב את הטקסט הבא לעברית טבעית וברורה שמתאימה לקריינות: "${text}". החזר רק טקסט בעברית ללא כותרות, רשימות, כוכביות, סולמיות, Markdown, קוד או תגיות.` }] }]
                    });
                    const result = data.candidates?.[0]?.content?.parts?.[0]?.text;
                    if (result) els.textInput.value = cleanGeneratedText(result);
                } catch (e) { if(e.message !== "Missing API Key") showHebrewError(e); }
            }
     
            // ✨ Podcast Script
            async function generatePodcastScript() {
                const topic = els.promptInput.value.trim() || "Technology";
                showToast("יוצר תסריט פודקאסט...", "success");
                try {
                    const data = await apiCall(modelText, {
                        contents: [{ parts: [{ text: `כתוב בעברית בלבד דו-שיח קצר וטבעי לפודקאסט בין שני דוברים בנושא "${topic}". אל תשתמש בכותרות, רשימות, כוכביות, סולמיות, Markdown, קוד או תגיות. החזר רק את הדו-שיח הנקי.` }] }]
                    });
                    const result = data.candidates?.[0]?.content?.parts?.[0]?.text;
                    if (result) els.textInput.value = cleanGeneratedText(result);
                } catch (e) { if(e.message !== "Missing API Key") showHebrewError(e); }
            }
     
            // ✨ 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: `סכם בעברית את הטקסט הבא לשלושה משפטים קצרים וברורים לקריינות: "${text}". אל תשתמש ברשימות, כוכביות, סולמיות, Markdown, קוד או תגיות.` }] }]
                    });
                    const result = data.candidates?.[0]?.content?.parts?.[0]?.text;
                    if (result) els.textInput.value = cleanGeneratedText(result);
                } catch (e) { if(e.message !== "Missing API Key") showHebrewError(e); }
            }
     
            // ✨ Tone Analysis
            els.analyzeToneBtn.onclick = async () => {
                const text = els.textInput.value.trim();
                if (!text) return showToast("אין טקסט לניתוח");
                
                toggleLoader('tone', true);
                try {
                    const data = await apiCall(modelText, {
                        contents: [{ parts: [{ text: `נתח את הטקסט הבא ובחר סגנון הקראה אחד בלבד מהרשימה: natural, cheerful, serious, whisper, excited, calm, authoritative, friendly, professional, storytelling, shouting, terrified, sad, angry, hopeful. החזר רק את מילת הסגנון באנגלית ללא הסבר. הטקסט: "${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 => o.value === cleanChoice);
                        if (option) {
                            els.styleSelect.value = cleanChoice;
                            showToast(`הסגנון הותאם ל: ${option.text}`, "success");
                        }
                    }
                } catch (e) { if(e.message !== "Missing API Key") showHebrewError(e); }
                toggleLoader('tone', false);
            };
     
            // ✨ Vocalization (Nikud)
            document.getElementById('vocalizeBtn').onclick = async () => {
                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 = cleanGeneratedText(result);
                } catch (e) { if(e.message !== "Missing API Key") showHebrewError(e); }
                toggleLoader('vocalize', false);
            };
     
            // --- TTS Core ---
            els.generateBtn.onclick = async () => {
                const text = els.textInput.value.trim();
                if (!text) return showToast("הכנס טקסט לקריינות");
                
                toggleLoader('btn', true);
                try {
                    const selectedStyle = [...styleCatalog, ...customStyles].find((style) => style.value === els.styleSelect.value);
                    const styleInstruction = selectedStyle?.instruction || selectedStyle?.label || els.styleSelect.value;
                    const result = await apiCall(modelAudio, {
                        contents: [{ parts: [{ text: `בצע קריינות בעברית. סגנון ההקראה: ${styleInstruction}. הקרא בדיוק את הטקסט הבא ללא הוספת מילים: ${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") showHebrewError(e); }
                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 < binary.length; i++) bytes[i] = binary.charCodeAt(i);
                const header = new ArrayBuffer(44);
                const v = new DataView(header);
                const s = (off, str) => { for (let i = 0; i < 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 = `
                    <div class="flex-grow w-full sm:w-auto">
                        <div class="font-bold text-xs sm:text-sm truncate dark:text-white">${title}...</div>
                        <div class="text-[10px] text-slate-400 mt-0.5">${els.voiceSelect.value} | ${els.styleSelect.value}</div>
                    </div>
                    <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">
                        <audio src="${url}" controls class="w-full sm:w-48"></audio>
                        <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">
                            <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"/></svg>
                        </a>
                    </div>
                `;
                els.tracksContainer.prepend(div);
            }
     
            document.getElementById('clearTracks').onclick = () => {
                els.tracksContainer.querySelectorAll('.card').forEach(c => c.remove());
                els.noTracks.classList.remove('hidden');
            };
        </script>
    </body>
    </html>
    

    האתר (הקובץ html) שופר, כמה וכמה דברים שודרגו וסודרו כמה אפשרויות:

    • הוספת סגנון מותאם אישית, וכן נוספו כמה סגנונות חדשים.
    • המצב לילה סודר.
    • ניהול מפתחות api סודר.

    על כל בעיה שאתם נתקלים אשמח שתעדכנו אותי על כך.

    כל מי שרוצה מפתח api של gemini יכול לפתוח באופן עצמאי, קודם כל יש להיכנס ל-Google AI Studio וליצור מפתח API חדש ולעלות לאתר למעלה בצד שמאל.
    או לשלוח לי מייל לכתובת: a0733641352@gmail.com ולכתוב בשורת הנושא: בקשת מפתח api

    תוכלו לראות מה היכולות בספוילר שלפניכם....
    נוסח ע"י AI...

    🎙️ סקירה מפורטת: יכולות, כלים ותכונות במערכת הסטודיו (VoiceMaster AI Studio)


    1. הפקת קריינות והמרת טקסט לדיבור (TTS - Text To Speech)

    • מנוע קריינות מתקדם: יצירת קבצי אודיו באיכות גבוהה מטקסט חופשי.
    • מגוון קולות רחב:
      • קולות גבריים: מגוון דמויות וגווני קול (Zephyr, Fenrir, Puck, Charon, Orus, Iapetus, Algieba ועוד) בסגנונות כמו עמוק, קליל, סמכותי, צעיר, חם, יציב וכו'.
      • קולות נשיים: קולות שונים (Kore, Leda, Aoede, Callirrhoe, Autonoe, Umbriel ועוד) בסגנונות מקצועי, עדין, רך, רהוט, אנרגטי, מרגיע ואלגנטי.
    • סגנונות הגשה והקראה:
      • בחירה מתוך רשימת סגנונות מובנים: טבעי, שידור, שמח, רציני, לחישה, נרגש, רגוע, סמכותי, ידידותי, מקצועי, מספר סיפורים, דוקומנטרי, פודקאסט, פרסומת, דרמטי, חם, ביטחון, עדין, אנרגטי, יוקרתי, מעורר השראה, טכני, קולנועי, מלכותי, מוטיבציוני ועוד.
    • סגנון מותאם אישית: אפשרות להגדיר ולהזין סגנון הקראה מותאם אישית לפי דרישה (כגון: "קריין יוקרתי, איטי, חם ומדויק") ושמירתו במערכת לשימוש חוזר.

    2. יצירת תוכן ועריכת טקסט חכמה

    • כתיבת תוכן אוטומטית (Magic Write): הזנת תיאור קצר (פרומפט) וקבלת טקסט מותאם ומקצועי לקריינות.
    • עריכה ושיוף בלחיצת כפתור:
      • ריכוך: הפיכת הטקסט לרגוע ונעים יותר.
      • שיווקי: שדרוג הטקסט לבעל אופי שיווקי ואנרגטי.
      • קיצור: צמצום אורך הטקסט בכ-30% תוך שמירה על המשמעות.
      • תרגום ושכתוב: תרגום או שכתוב הטקסט לעברית טבעית וברורה המתאימה לקריינות.
      • תסריט פודקאסט: יצירת דו-שיח קצר וטבעי בין שני דוברים לפי נושא נבחר.
      • סיכום: תמצית הטקסט למספר משפטים ממוקדים.

    3. כלי עזר לקריינות ולטקסט

    • ניקוד אוטומטי: הוספת ניקוד דקדוקי מלא ומדויק לטקסט העברי לשיפור נכונות ההקראה.
    • התאמת סגנון אוטומטית (Tone Analysis): ניתוח אוטומטי של הטקסט והתאמת סגנון ההקראה המתאים ביותר עבורו מתוך רשימת הסגנונות.

    4. נגן אודיו וניהול הקלטות

    • נגן אודיו מובנה: האזנה מיידית לקריינות שיוצרה ישירות מתוך הממשק.
    • הורדת קבצים: הורדת הקריינות כקובץ אודיו בפורמט WAV.
    • היסטוריית הקלטות: שמירה של ההקלטות האחרונות כולל פירוט הקול והסגנון שנבחרו.
    • ניהול רשימה: אפשרות לניקוי היסטוריית ההקלטות בכל עת.

    5. ניהול מפתחות API וממשק משתמש

    תכונה תיאור
    ניהול מפתחות API גמיש אפשרות להוסיף, לנהל, להעתיק, למחוק ולעבור בין מספר מפתחות API שמורים.
    מנגנון חלוקת עומסים ומעבר אוטומטי המערכת יודעת לעבור בין מפתחות שמורים במקרה של עומס או מגבלת שימוש.
    עיצוב ומצבי תצוגה ממשק מותאם לניידים ולמחשבים, כולל תמיכה מלאה במצב לילה (Dark Mode) ומצב יום.

    כמו כן אני הולך לשדרג משמעותית בתקופה הקרובה את האתר.

    נכון לעכשיו האתר כאן...

    בהצלחה!!!!

    עזרה הדדית - בינה מלאכותית

  • שיתוף | מה חדש בבינה מלאכותית - מתעדכן
    א אריה AI

    גוגל שינו את העיצוב של ג'מיני לגמרי.

    והוסיפו בו אופציות רבות...


    תמונות:

    7bd40f22-4296-4adf-8b9e-5b7da487befa-image.png

    81c19c39-e1ce-4dc5-aa1e-a79960fe07a6-image.png

    b5da17ad-29bd-477b-8783-517c0bc253e6-image.png

    fcc5c9ae-f381-4320-b6f2-a6ed73c30a4d-image.png

    92c76783-d7b7-4af9-b77c-b76343a40a21-image.png

    קרדיט ל @מייבין-במקצת

    עזרה הדדית - בינה מלאכותית

  • שיתוף | מה חדש בבינה מלאכותית - נספח עדכוני פיצ'רים ודיונים 💬
    א אריה AI

    @shalomke כתב:
    בקשה של פרומפט אחד לפייבל 5
    https://beit-hamikdash.vercel.app/

    הזוי...
    אולי תפתח על זה נושא מורחב...

    עזרה הדדית - בינה מלאכותית

  • שיתוף | שמעתם על: 🚀 משדרגים את ההקלטות הקוליות של המערכת הטלפונית עם Smart Records AI??? -אתם חייבים לשמוע!!!-
    א אריה AI

    🎙️ נמאס לכם להקליט הודעות למערכת שוב ושוב?
    מעוניינים בקול מקצועי? הכירו את הפרויקט החדש והניסיוני שלנו המאפשר יצירת הודעות קוליות דרך שיחת טלפון באמצעות בינה מלאכותית!
    מה במערכת?

    🎤 הקלטה או הקלדה: מקליטים או מקלידים את התוכן בקלות.
    🤖 מנועי AI מתקדמים: שימוש במנועים של ElevenLabs או Gemini לקול אנושי ואיכותי.
    ☁️ סנכרון מלא: ההקלטה המוכנה עולה אוטומטית למערכת הטלפונית.
    ⚠️ שימו לב:
    המערכת פועלת כרגע בגרסת הרצה (Beta) בצורה ניסיונית וחינמית, אך ייתכן ובעתיד המערכת תהיה בתשלום.
    נשמח מאוד לכל דיווח על תקלה או הצעה לשיפור כדי שנוכל להתקדם!

    כנסו לקישור Smart-Records.AI/ivr2tts, הגדירו את הגדרות החובה ותוכלו לחייג למערכת הטלפונית וליצור קבצי קריינות.
    מספר הטלפון של המערכת מוצג מיד לאחר ההתחברות לממשק וסיום השלבים.

    בהצלחה!!
    1008125021.png
    מקור

    מערכות IVR - ימות המשיח

  • שיתוף | האתר קריינות VoiceMaster המשוכלל שודרג!!! 🎙🎙🎙
    א אריה AI

    @fhryurygfgdf כתב:

    [הצעה לשיפור] אולי שיהיה אפשרות להוסיף קול אישי או משהו בסגנון ואז זה יהיה יותר טוב.....

    אולי בעתיד...

    עזרה הדדית - בינה מלאכותית

  • שיתוף | האתר קריינות VoiceMaster המשוכלל שודרג!!! 🎙🎙🎙
    א אריה AI

    @רוטב-שום כתב:

    @אריה-ai לדעתי כדי להוסיף אופציה שיהיה אפשר לבחור באיזה מודל של גמיני להשתמש

    גם רעיון....

    עזרה הדדית - בינה מלאכותית

  • בקשה| פיתוח קו מידע ופעולות מרוכז לבעלי הטלפון הכשר
    א אריה AI

    @המלאך בחינם אני יכול,
    שקל אחד לא אדרוש על זה...

    ומי ששואל מדוע???
    אז התשובה היא שאני רואה בזה זכות!!!

    מערכות IVR - ימות המשיח

  • המלצה | ימות אמשיח וועדת הרבנים עוקבים אחרי הפורום
    א אריה AI

    @SHIMI-0 ימות אמשיח וועדת הרבנים עוקבים אחרי הפורום.
    רק משהו קטן...
    ימות המשיח כותבים עם המשיח, ולא ימות אמשיח...😊
    👮 כמובן אני לא שוטר הכתב...👍
    ובנושא לפוסט: זה כן נכון במובן חלקי.

    מערכות IVR - ימות המשיח

  • שיתוף | חדש!!! VoiceMaster אתר קריינות משוכלל!!!
    א אריה AI

    @היפ-הופ אני ככל הנראה עובד על זה בשבוע הקרוב ולאלו המכירים את האתר פשוט סיפור של @מייבין-במקצת אז יתכן ואני ישלב את שני האתרים ביחד....

    עזרה הדדית - בינה מלאכותית

  • שיתוף | חדש!!! VoiceMaster אתר קריינות משוכלל!!!
    א אריה AI

    לתועלת הציבור הנה קובץ מעודכן כמובן במודל AI!!!!
    הורידו אותו שוב ותהנו.
    cb22d480-6588-404a-a538-1b8c4fb71d3d-קריינות מעודכן.zip

    עזרה הדדית - בינה מלאכותית

  • בקשת מידע | מספר לא מוכר
    א אריה AI

    @SHIMI-0 במייל שלי, אפרסם בהזדמנות...

    עזרה הדדית - מחשבים וטכנולוגיה

  • בירור | כמה עולה לפתח מערכת IVR
    א אריה AI

    @מענין-לשמוע זה כזה קל!!!!!!!!
    בראיון הרוב פה חינמי...
    👍

    שאלות למומחים

  • מדריך | כל הפרטים על וירטואל פלוס
    א אריה AI

    @שלוםפ איך אני יכול לברר מה המספר וירטואל שלי (נמחק לי מהאנשי קשר)


    או בשירות הלקוחות...
    או במייל: cs@yemot.co.il

    בהצלחה!!!

    מערכות IVR - ימות המשיח

  • בירור | כמה עולה לפתח מערכת IVR
    א אריה AI

    @מענין-לשמוע לא, בפעם הראשונה עובר לשלוחה עם סיסמא, ואחרי זה עובר להרשמה לרשימת תפוצה וכו'

    שאלות למומחים

  • שאלה | בעיית הצטרפות למרחב (Space) ב-Google Chat
    א אריה AI

    @fhryurygfgdf קשור ככל הנראה לנטפרי...

    עזרה הדדית - סינוני אינטרנט

  • שיתוף | חדש!!! VoiceMaster אתר קריינות משוכלל!!!
    א אריה AI

    @CUBASE תכלס צודק אני יעביר את זה בקרוב למודל gemin 3.1.

    עזרה הדדית - בינה מלאכותית

  • שיתוף | חדש!!! VoiceMaster אתר קריינות משוכלל!!!
    א אריה AI

    תגידו, האם אתם רוצים שאני אסדר את הממשק בעברית מלאה והסברים...

    עזרה הדדית - בינה מלאכותית

  • שיתוף | חדש!!! VoiceMaster אתר קריינות משוכלל!!!
    א אריה AI

    @דוד-חדאד אגב גם אני בנטפרי ואני אסדר זאת ככל הנראה ביום שני הקרוב...

    עזרה הדדית - בינה מלאכותית

  • שיתוף | חדש!!! VoiceMaster אתר קריינות משוכלל!!!
    א אריה AI

    @היפ-הופ הראיונות בשלבי בניה מתקדמים...

    עזרה הדדית - בינה מלאכותית
  • התחברות

  • אין לך חשבון עדיין? הרשמה

  • התחברו או הירשמו כדי לחפש.
  • פוסט ראשון
    פוסט אחרון
0
  • חוקי הפורום
  • פופולרי
  • לא נפתר
  • משתמשים
  • חיפוש גוגל בפורום
  • צור קשר