• דף הבית
    • אינדקס קישורים
    • פוסטים אחרונים
    • משתמשים
    • חיפוש בהגדרות המתקדמות
    • חיפוש גוגל בפורום
    • ניהול המערכת
    • ניהול המערכת - שרת private
    • הרשמה
    • התחברות

    אתר "קולות" – יצירת קרינות ותמלול AI בקלות

    מתוזמן נעוץ נעול הועבר עזרה הדדית למשתמשים מתקדמים
    108 פוסטים 16 כותבים 2.5k צפיות 6 עוקבים
    טוען פוסטים נוספים
    • מהישן לחדש
    • מהחדש לישן
    • הכי הרבה הצבעות
    תגובה
    • תגובה כנושא
    התחברו כדי לפרסם תגובה
    נושא זה נמחק. רק משתמשים עם הרשאות מתאימות יוכלו לצפות בו.
    • ה מנותק
      המתכנת הראשי @שולי
      נערך לאחרונה על ידי

      @שולי תיקנתי את הקישור למעלה הקישור החדש הוא https://ais-pre-hwh53agkcctwmzdhgq5ecq-703503104887.europe-west2.run.app/simple-tts.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>יצירת שמע פשוטה ועקבית (Gemini TTS)</title>
        <style>
          :root {
            --primary: #f59e0b;
            --primary-hover: #d97706;
            --bg: #0f172a;
            --card-bg: #1e293b;
            --border: #334155;
            --text: #f8fafc;
            --text-muted: #94a3b8;
          }
          * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
            font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
          }
          body {
            background-color: var(--bg);
            color: var(--text);
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
            padding: 20px;
          }
          .container {
            background-color: var(--card-bg);
            border: 1px solid var(--border);
            border-radius: 16px;
            width: 100%;
            max-width: 600px;
            padding: 28px;
            box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.5);
          }
          h1 {
            font-size: 20px;
            margin-bottom: 6px;
            color: var(--primary);
            display: flex;
            align-items: center;
            gap: 8px;
          }
          p.subtitle {
            font-size: 13px;
            color: var(--text-muted);
            margin-bottom: 22px;
          }
          .form-group {
            margin-bottom: 16px;
          }
          label {
            display: block;
            font-size: 13px;
            font-weight: 600;
            margin-bottom: 6px;
            color: #e2e8f0;
          }
          input[type="text"], input[type="password"], textarea, select {
            width: 100%;
            padding: 10px 14px;
            background-color: #0f172a;
            border: 1px solid var(--border);
            border-radius: 10px;
            color: #fff;
            font-size: 14px;
            outline: none;
            transition: border-color 0.2s;
          }
          input:focus, textarea:focus, select:focus {
            border-color: var(--primary);
          }
          textarea {
            resize: vertical;
            min-height: 110px;
          }
          .grid {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 12px;
          }
          .lock-box {
            background: rgba(245, 158, 11, 0.1);
            border: 1px solid rgba(245, 158, 11, 0.3);
            padding: 12px 14px;
            border-radius: 10px;
            display: flex;
            align-items: center;
            gap: 10px;
            cursor: pointer;
            margin-bottom: 18px;
          }
          .lock-box input[type="checkbox"] {
            width: 18px;
            height: 18px;
            accent-color: var(--primary);
            cursor: pointer;
          }
          .lock-text {
            font-size: 13px;
            line-height: 1.3;
          }
          .lock-text strong {
            color: var(--primary);
            display: block;
          }
          .lock-text small {
            color: var(--text-muted);
            font-size: 11px;
          }
          button.btn-primary {
            width: 100%;
            background: var(--primary);
            color: #0f172a;
            font-weight: 700;
            font-size: 15px;
            padding: 12px;
            border: none;
            border-radius: 10px;
            cursor: pointer;
            transition: background 0.2s, transform 0.1s;
          }
          button.btn-primary:hover {
            background: var(--primary-hover);
          }
          button.btn-primary:active {
            transform: scale(0.99);
          }
          button.btn-primary:disabled {
            opacity: 0.5;
            cursor: not-allowed;
          }
          .player-area {
            margin-top: 22px;
            padding-top: 18px;
            border-top: 1px solid var(--border);
            display: none;
          }
          audio {
            width: 100%;
            margin-bottom: 12px;
          }
          .download-btn {
            display: inline-block;
            text-align: center;
            width: 100%;
            background: #334155;
            color: #fff;
            padding: 10px;
            border-radius: 8px;
            text-decoration: none;
            font-size: 13px;
            font-weight: 600;
            transition: background 0.2s;
          }
          .download-btn:hover {
            background: #475569;
          }
          .status {
            font-size: 12px;
            margin-top: 10px;
            text-align: center;
            color: var(--text-muted);
          }
        </style>
      </head>
      <body>
      
      <div class="container">
        <h1>🔊 יצירת שמע פשוטה ועקבית (Gemini TTS)</h1>
        <p class="subtitle">קובץ HTML עצמאי וקל ליצירת קרינות נקייה עם נעילת טון וקצב קבוע</p>
      
        <div class="form-group">
          <label for="apiKey">מפתח Gemini API:</label>
          <input type="password" id="apiKey" placeholder="הדבק כאן מפתח מגוגל AI Studio (AIzaSy...)">
        </div>
      
        <div class="form-group">
          <label for="textInput">טקסט להקראה בעברית:</label>
          <textarea id="textInput" placeholder="הקלד כאן את הטקסט שברצונך להקריא..."></textarea>
        </div>
      
        <div class="grid">
          <div class="form-group">
            <label for="voiceSelect">קול קריין:</label>
            <select id="voiceSelect">
              <option value="Puck">איתן (Puck) - גברי צעיר/קצבי</option>
              <option value="Charon">אלון (Charon) - גברי עמוק/בטוח</option>
              <option value="Kore" selected>רות (Kore) - נשי חם/טבעי</option>
              <option value="Fenrir">יהונתן (Fenrir) - גברי סמכותי</option>
              <option value="Aoede">מאיה (Aoede) - נשי צלול</option>
              <option value="Zephyr">דן (Zephyr) - גברי רגוע</option>
            </select>
          </div>
      
          <div class="form-group">
            <label for="speedSelect">מהירות:</label>
            <select id="speedSelect">
              <option value="0.8">0.8x (איטי ומדוד)</option>
              <option value="1.0" selected>1.0x (מהירות רגילה)</option>
              <option value="1.2">1.2x (קצבי ומהיר)</option>
            </select>
          </div>
        </div>
      
        <!-- מנגנון נעילת טון וקצב עקבי -->
        <label class="lock-box">
          <input type="checkbox" id="lockTone" checked>
          <div class="lock-text">
            <strong>🔒 קיבוע טון וסגנון קבוע (Consistent Tone - Zero Jitter)</strong>
            <small>משתמש ב-Seed קבוע וטמפרטורה יציבה כדי שכל הפקה תישמע בדיוק באותו טון</small>
          </div>
        </label>
      
        <button class="btn-primary" id="generateBtn" onclick="generateSpeech()">הפק שמע עכשיו</button>
        <div class="status" id="statusText"></div>
      
        <div class="player-area" id="playerArea">
          <audio id="audioElement" controls></audio>
          <a href="#" class="download-btn" id="downloadBtn" download="speech.wav">הורד קובץ שמע WAV</a>
        </div>
      </div>
      
      <script>
        // שמירת מפתח בזיכרון הדפדפן לנוחות
        const savedKey = localStorage.getItem('gemini_simple_tts_key');
        if (savedKey) document.getElementById('apiKey').value = savedKey;
      
        function pcmToWav(pcmData, sampleRate = 24000, numChannels = 1, bitsPerSample = 16) {
          if (pcmData.length >= 4 && String.fromCharCode(...pcmData.slice(0, 4)) === 'RIFF') {
            return pcmData;
          }
          const byteRate = (sampleRate * numChannels * bitsPerSample) / 8;
          const blockAlign = (numChannels * bitsPerSample) / 8;
          const dataSize = pcmData.length;
          const buffer = new ArrayBuffer(44 + dataSize);
          const view = new DataView(buffer);
      
          function writeString(offset, string) {
            for (let i = 0; i < string.length; i++) {
              view.setUint8(offset + i, string.charCodeAt(i));
            }
          }
      
          writeString(0, 'RIFF');
          view.setUint32(4, 36 + dataSize, true);
          writeString(8, 'WAVE');
          writeString(12, 'fmt ');
          view.setUint32(16, 16, true);
          view.setUint16(20, 1, true); // PCM
          view.setUint16(22, numChannels, true);
          view.setUint32(24, sampleRate, true);
          view.setUint32(28, byteRate, true);
          view.setUint16(32, blockAlign, true);
          view.setUint16(34, bitsPerSample, true);
          writeString(36, 'data');
          view.setUint32(40, dataSize, true);
      
          new Uint8Array(buffer, 44).set(pcmData);
          return new Uint8Array(buffer);
        }
      
        async function generateSpeech() {
          const apiKey = document.getElementById('apiKey').value.trim();
          const text = document.getElementById('textInput').value.trim();
          const voice = document.getElementById('voiceSelect').value;
          const speed = document.getElementById('speedSelect').value;
          const lockTone = document.getElementById('lockTone').checked;
          const statusText = document.getElementById('statusText');
          const generateBtn = document.getElementById('generateBtn');
          const playerArea = document.getElementById('playerArea');
          const audioElement = document.getElementById('audioElement');
          const downloadBtn = document.getElementById('downloadBtn');
      
          if (!apiKey) {
            alert('נא להזין מפתח Gemini API');
            return;
          }
          if (!text) {
            alert('נא להזין טקסט להקראה');
            return;
          }
      
          localStorage.setItem('gemini_simple_tts_key', apiKey);
          generateBtn.disabled = true;
          statusText.innerText = 'מפיק קרינות מול שרתי Google Gemini... אנא המתן';
          playerArea.style.display = 'none';
      
          try {
            // Deterministic seed for consistency
            const seed = Math.abs(voice.split('').reduce((acc, c) => acc * 31 + c.charCodeAt(0), 0) + Math.round(Number(speed) * 100)) % 2147483647;
      
            const requestBody = {
              contents: [{ parts: [{ text }] }],
              generationConfig: {
                responseModalities: ["AUDIO"],
                temperature: lockTone ? 0.55 : 0.7,
                ...(lockTone ? { seed: seed } : {}),
                speechConfig: {
                  voiceConfig: {
                    prebuiltVoiceConfig: { voiceName: voice }
                  }
                }
              }
            };
      
            // מודל TTS יציב וייעודי של גוגל
            const models = ['gemini-3.8-flash-lite-tts', 'gemini-3.8-flash-tts', 'gemini-2.5-flash-preview-tts'];
            let base64Audio = null;
            let lastError = null;
      
            for (const model of models) {
              try {
                const res = await fetch(`https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent?key=${apiKey}`, {
                  method: 'POST',
                  headers: { 'Content-Type': 'application/json' },
                  body: JSON.stringify(requestBody)
                });
                const data = await res.json();
                if (data?.candidates?.[0]?.content?.parts?.[0]?.inlineData?.data) {
                  base64Audio = data.candidates[0].content.parts[0].inlineData.data;
                  break;
                }
                if (data.error) {
                  lastError = data.error.message;
                }
              } catch (e) {
                lastError = e.message;
              }
            }
      
            if (!base64Audio) {
              throw new Error(lastError || 'לא התקבלו נתוני שמע מגוגל. בדוק את תקינות המפתח.');
            }
      
            // פיענוח לקובץ WAV
            const binaryString = window.atob(base64Audio);
            const len = binaryString.length;
            const bytes = new Uint8Array(len);
            for (let i = 0; i < len; i++) {
              bytes[i] = binaryString.charCodeAt(i);
            }
      
            const wavBytes = pcmToWav(bytes, 24000, 1, 16);
            const blob = new Blob([wavBytes], { type: 'audio/wav' });
            const blobUrl = URL.createObjectURL(blob);
      
            audioElement.src = blobUrl;
            downloadBtn.href = blobUrl;
            playerArea.style.display = 'block';
            statusText.innerText = 'הקרינות הופקה בהצלחה!';
            audioElement.play().catch(() => {});
      
          } catch (err) {
            statusText.innerText = 'שגיאה: ' + err.message;
          } finally {
            generateBtn.disabled = false;
          }
        }
      </script>
      </body>
      </html>
      
      י תגובה 1 תגובה אחרונה תגובה ציטוט 0
      • י מנותק
        יענקי פולק @המתכנת הראשי
        נערך לאחרונה על ידי

        @המתכנת-הראשי

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

          @יענקי-פולק
          אפשר לנעול את הקול לקול אחיד
          תראה כאן

          י תגובה 1 תגובה אחרונה תגובה ציטוט 1
          • י מנותק
            יענקי פולק @מסובך מאוד
            נערך לאחרונה על ידי

            @מסובך-מאוד

            1. תודה על המענה אבל קודם כל אני צריך שהוא יעשה לי קבצים שלמים
            2. יכול להיות שזה קשור בגלל שלא הכנסתי מפתח API
            3. האם יש לך פיתרון להוציא בנטפרי מפתחות API
            תגובה 1 תגובה אחרונה תגובה ציטוט 0
            • ה מנותק
              המתכנת הראשי @יענקי פולק
              נערך לאחרונה על ידי

              @יענקי-פולק בנוגע לקבצים של ה2 שניות זה בגלל שאין לך מפתח API וזה קשור למפתחות של גוגל שיש עליהם מגבלה, הפיתרון היחיד לזה זה הוצאת מפתח API.
              בנוגע לשינוי בקול צריך ללחוץ על "נעל טון זה"

              י תגובה 1 תגובה אחרונה תגובה ציטוט 1
              • י מנותק
                יענקי פולק @המתכנת הראשי
                נערך לאחרונה על ידי

                @המתכנת-הראשי

                יענקי-פולק כתב:

                האם יש לך פיתרון להוציא בנטפרי מפתחות API

                ש תגובה 1 תגובה אחרונה תגובה ציטוט 0
                • ש מנותק
                  שלוחה-404 @יענקי פולק
                  נערך לאחרונה על ידי

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

                  י תגובה 1 תגובה אחרונה תגובה ציטוט 1
                  • י מנותק
                    יענקי פולק @שלוחה-404
                    נערך לאחרונה על ידי

                    @שלוחה-404
                    תכל'ס אני יושב בחדר מחשבים במסלול הכי שמור של נטפרי ואין לי גישה למחשב אחר, האם יש לך פיתרון להוציא מפתחות API

                    ש תגובה 1 תגובה אחרונה תגובה ציטוט 0
                    • ש מחובר
                      שולי @יענקי פולק
                      נערך לאחרונה על ידי

                      הגירסה המקוצרת זמינה בכתובת: https://tts.link.tz

                      י תגובה 1 תגובה אחרונה תגובה ציטוט 0
                      • י מנותק
                        יענקי פולק @שולי
                        נערך לאחרונה על ידי

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

                        ש ש 2 תגובות תגובה אחרונה תגובה ציטוט 0
                        • ש מחובר
                          שולי @יענקי פולק
                          נערך לאחרונה על ידי

                          @יענקי-פולק אין לי נטפרי

                          תגובה 1 תגובה אחרונה תגובה ציטוט 0
                          • ש מנותק
                            שלוחה-404 @יענקי פולק
                            נערך לאחרונה על ידי

                            @יענקי-פולק שלחתי לבדיקה

                            תגובה 1 תגובה אחרונה תגובה ציטוט 0

                            שלום! נראה שהשיחה הזו מעניינת אותך, אבל עדיין אין לך חשבון.

                            נמאס לכם לגלול בין אותם הפוסטים בכל ביקור? כשנרשמים לחשבון, תמיד תחזרו בדיוק למקום שבו הייתם קודם, ותוכלו לבחור לקבל התראות על תגובות חדשות (בין אם במייל, ובין אם בהתראת פוש). תוכלו גם לשמור סימניות ולפרגן ב-upvote לפוסטים כדי להביע הערכה לחברי קהילה אחרים.

                            בעזרת התרומה שלך, הפוסט הזה יכול להיות אפילו טוב יותר 💗

                            הרשמה התחברות
                            • פוסט ראשון
                              פוסט אחרון