דילוג לתוכן
  • חוקי הפורום
  • פופולרי
  • לא נפתר
  • משתמשים
  • חיפוש גוגל בפורום
  • צור קשר
עיצובים
  • בהיר
  • 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

  • ברירת מחדל (ללא עיצוב (ברירת מחדל))
  • ללא עיצוב (ברירת מחדל)
כיווץ
מתמחים טופ
  1. דף הבית
  2. מחשבים וטכנולוגיה
  3. עזרה הדדית - מחשבים וטכנולוגיה
  4. המלצה | 🤖 עוזר AI חדש לפורום - עונה תוך שניות, מכיר את מתמחים טופ מבפנים!

המלצה | 🤖 עוזר AI חדש לפורום - עונה תוך שניות, מכיר את מתמחים טופ מבפנים!

מתוזמן נעוץ נעול הועבר עזרה הדדית - מחשבים וטכנולוגיה
114 פוסטים 25 כותבים 1.8k צפיות 28 עוקבים
  • מהישן לחדש
  • מהחדש לישן
  • הכי הרבה הצבעות
תגובה
  • תגובה כנושא
התחברו כדי לפרסם תגובה
נושא זה נמחק. רק משתמשים עם הרשאות מתאימות יוכלו לצפות בו.
  • מייבין במקצתמ מייבין במקצת

    @יודע-ומייבין

    אתה אמור להתנצל???
    אם זה לא היה אתה בעצמך - הייתי נותן דיס על פוסט כזה 🤦‍♂️

    י מחובר
    י מחובר
    יודע ומייבין
    כתב נערך לאחרונה על ידי
    #84

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

    מייבין במקצתמ תגובה 1 תגובה אחרונה
    0
    • י יודע ומייבין

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

      מייבין במקצתמ מנותק
      מייבין במקצתמ מנותק
      מייבין במקצת
      כתב נערך לאחרונה על ידי מייבין במקצת
      #85

      @יודע-ומייבין

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

      ההבנה הכי גדולה היא להבין שאני לא מבין.

      תגובה 1 תגובה אחרונה
      1
      • מ מחובר
        מ מחובר
        מוטל 2
        כתב נערך לאחרונה על ידי מוטל 2
        #86

        שלום וברכה,

        כיון שזה היה חשוב לי, ישבתי על הקוד שלו שעות, וב"ה הצלחתי לעשות לו שטיפת מוח, כולל כמה וכמה שיפורים {כגון הסטוריית בקשות, וקישורים לחיצים וכן אפשרות לגרור את החלון ממקום למקום, וכן הוספתי אפשרות להוספת קבצים או תמונות לדיוק השאלה או הבקשה}.

        הקוד המתוקן בספויילר:

        // ==UserScript==
        // @name         מתמחים טופ + בינה טופ - עוזר AI מושלם עם תמיכה בקבצים, תמונות והדבקה ישירה
        // @namespace    https://mitmachim.top/
        // @version      23.0.0
        // @description  עוזר AI צף עם תמיכה בצירוף והדבקת קבצים ותמונות, חיפוש משתמשים ואשכולות, היסטוריית שיחות וגרירת חלון
        // @author       you
        // @match        https://mitmachim.top/*
        // @match        https://bina.top/*
        // @icon         https://mitmachim.top/favicon.ico
        // @grant        GM_setValue
        // @grant        GM_getValue
        // @grant        GM_registerMenuCommand
        // @grant        GM_xmlhttpRequest
        // @connect      generativelanguage.googleapis.com
        // @connect      mitmachim.top
        // @connect      bina.top
        // @run-at       document-end
        // ==/UserScript==
        
        (function () {
          'use strict';
        
          function getSiteOrigin() {
            const host = location.hostname.toLowerCase();
            if (host === 'bina.top' || host.endsWith('.bina.top')) {
              return 'https://bina.top';
            }
            return 'https://mitmachim.top';
          }
        
          const SITE_ORIGIN = getSiteOrigin();
          const SITE_HOST = new URL(SITE_ORIGIN).hostname;
        
          const K = {
            apiKey: 'mt_ai_gemini_key',
            context: 'mt_ai_context',
            persona: 'mt_ai_persona',
            sessions: 'mt_ai_sessions_list',
            currentSessionId: 'mt_ai_current_session_id'
          };
        
          const get = (k, d = '') => GM_getValue(k, d);
          const set = (k, v) => GM_setValue(k, v);
        
          function request(details) {
            return new Promise((resolve, reject) => {
              GM_xmlhttpRequest({
                ...details,
                onload: resolve,
                onerror: () => reject(new Error('שגיאת רשת')),
                ontimeout: () => reject(new Error('זמן קצוב עבר'))
              });
            });
          }
        
          async function fetchText(url) {
            const res = await request({ method: 'GET', url, timeout: 25000 });
            if (res.status < 200 || res.status >= 300) throw new Error('שגיאה בטעינת נתונים');
            return res.responseText;
          }
        
          function htmlToText(root) {
            if (!root) return '';
            const clone = root.cloneNode(true);
            clone.querySelectorAll('script,style').forEach(x => x.remove());
            clone.querySelectorAll('a[href]').forEach(a => {
              try {
                const href = new URL(a.getAttribute('href'), SITE_ORIGIN).href;
                const label = (a.textContent || '').trim();
                const replacement = label && label !== href ? `${label} (${href})` : href;
                a.replaceWith(document.createTextNode(' ' + replacement + ' '));
              } catch {}
            });
            clone.querySelectorAll('br').forEach(br => br.replaceWith(document.createTextNode('\n')));
            clone.querySelectorAll('p,div,li,blockquote,tr,h1,h2,h3,h4,h5,h6').forEach(b => {
              b.appendChild(document.createTextNode('\n'));
            });
            return (clone.textContent || '')
              .replace(/[ \t]+/g, ' ')
              .replace(/ *\n */g, '\n')
              .replace(/\n{3,}/g, '\n\n')
              .trim();
          }
        
          function extractSearchHits(data) {
            const arr = data?.posts || data?.matches || data?.results || [];
            if (!Array.isArray(arr)) return [];
            return arr.map(p => {
              const topic = p.topic || p;
              const title = topic?.title || p.title || '(ללא כותרת)';
              const slug = topic?.slug || p.slug;
              const tid = topic?.tid || p.tid;
              let url = '';
              if (slug) url = `${SITE_ORIGIN}/topic/${slug}`;
              else if (tid) url = `${SITE_ORIGIN}/topic/${tid}`;
              return { title, url };
            }).filter(h => h.url);
          }
        
          async function legacySearchScrape(query) {
            try {
              const url = `${SITE_ORIGIN}/search?term=${encodeURIComponent(query)}`;
              const html = await fetchText(url);
              const doc = new DOMParser().parseFromString(html, 'text/html');
              doc.querySelectorAll('script,style,nav,header,footer').forEach(x => x.remove());
              const results = [];
              doc.querySelectorAll('a[href*="/topic/"]').forEach(a => {
                if (results.length >= 6) return;
                const href = a.getAttribute('href');
                const text = (a.textContent || '').trim();
                if (href && text && text.length > 3) {
                  try {
                    const absolute = new URL(href, url).href;
                    if (!results.some(r => r.url === absolute)) {
                      results.push({ title: text, url: absolute });
                    }
                  } catch {}
                }
              });
              return results;
            } catch {
              return [];
            }
          }
        
          async function searchUserProfile(query) {
            query = String(query || '').trim();
            if (!query) return '';
            try {
              const apiUrl = `${SITE_ORIGIN}/api/users?query=${encodeURIComponent(query)}&page=1`;
              const raw = await fetchText(apiUrl);
              const data = JSON.parse(raw);
              const users = data?.users || [];
              if (!users.length) return '';
        
              let block = `משתמשים שנמצאו בפורום עבור "${query}":\n\n`;
              users.slice(0, 5).forEach(u => {
                const username = u.username || 'לא ידוע';
                const fullname = u.fullname ? ` (${u.fullname})` : '';
                const reputation = u.reputation !== undefined ? u.reputation : 'לא ידוע';
                const postCount = u.postcount !== undefined ? u.postcount : 'לא ידוע';
                const profileUrl = `${SITE_ORIGIN}/user/${u.userslug || username}`;
                block += `- משתמש: ${username}${fullname}\n  קישור לפרופיל: ${profileUrl}\n  מוניטין: ${reputation} | הודעות: ${postCount}\n\n`;
              });
              return block;
            } catch {
              return '';
            }
          }
        
          async function quickForumSearch(query) {
            query = String(query || '').trim();
            if (!query) return '';
        
            let userBlock = '';
            if (query.includes('משתמש') || query.includes('פרופיל') || query.includes('מוניטין')) {
              const cleanName = query.replace(/משתמש|פרופיל|מוניטין|של/g, '').trim();
              if (cleanName) {
                userBlock = await searchUserProfile(cleanName);
              }
            }
        
            let hits = [];
            try {
              const apiUrl = `${SITE_ORIGIN}/api/search?term=${encodeURIComponent(query)}`;
              const raw = await fetchText(apiUrl);
              const data = JSON.parse(raw);
              hits = extractSearchHits(data);
            } catch {
              hits = [];
            }
        
            if (!hits.length) {
              hits = await legacySearchScrape(query);
            }
        
            let block = userBlock ? userBlock + '\n' : '';
        
            if (hits.length > 0) {
              const seen = new Set();
              const uniqueHits = hits.filter(h => {
                if (seen.has(h.url)) return false;
                seen.add(h.url);
                return true;
              });
        
              const topResults = uniqueHits.slice(0, 3);
              const enriched = await Promise.all(topResults.map(async r => {
                const snippet = await fetchTopicSnippet(r.url);
                return { ...r, snippet };
              }));
        
              block += `תוצאות חיפוש אשכולות בפורום ${SITE_HOST} עבור "${query}":\n\n`;
              enriched.forEach((r, i) => {
                block += `--- נושא ${i + 1}: ${r.title} ---\nקישור מלא: ${r.url}\n`;
                block += r.snippet ? `תוכן הנושא:\n${r.snippet}\n\n` : '(לא ניתן היה לשלוף את תוכן הנושא)\n\n';
              });
            }
        
            return block;
          }
        
          async function fetchTopicSnippet(url, maxChars = 1400) {
            try {
              const html = await fetchText(url);
              const doc = new DOMParser().parseFromString(html, 'text/html');
              doc.querySelectorAll('script,style,nav,header,footer,aside,form').forEach(x => x.remove());
        
              const postEls = Array.from(doc.querySelectorAll('[component="post"]'));
              let text = '';
        
              if (postEls.length) {
                const parts = postEls.slice(0, 8).map((post, i) => {
                  const contentEl = post.querySelector('[component="post/content"]') || post;
                  const authorEl = post.querySelector('[component="user/username"]') || post.querySelector('a[href*="/user/"]');
                  const author = authorEl ? authorEl.textContent.trim() : '';
                  const postText = htmlToText(contentEl);
                  return postText ? `[פוסט ${i + 1}${author ? ' מאת ' + author : ''}]\n${postText}` : '';
                }).filter(Boolean);
                text = parts.join('\n\n');
              }
        
              if (!text) {
                const container = doc.querySelector('[component="topic"]') || doc.querySelector('main') || doc.body;
                text = htmlToText(container);
              }
        
              if (text.length > maxChars) text = text.slice(0, maxChars) + '\n...[הטקסט קוצץ]';
              return text;
            } catch {
              return '';
            }
          }
        
          function getPageContext() {
            try {
              const main = document.querySelector('[component="topic"]') || document.querySelector('main') || document.body;
              let text = htmlToText(main);
              if (text.length > 1500) {
                text = text.slice(0, 1500) + '\n...[הטקסט קוצץ]';
              }
              return `אתר: ${SITE_HOST}\nכותרת: ${document.title}\nתוכן העמוד:\n${text}`;
            } catch {
              return '';
            }
          }
        
          const MODEL_CANDIDATES = ['gemini-3.6-flash', 'gemini-3.5-flash-lite', 'gemini-2.5-flash-lite'];
        
          function sleep(ms) {
            return new Promise(resolve => setTimeout(resolve, ms));
          }
        
          async function callGeminiWithModel(model, key, body) {
            const url = `https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent?key=${encodeURIComponent(key)}`;
        
            const res = await request({
              method: 'POST',
              url,
              headers: { 'Content-Type': 'application/json' },
              data: JSON.stringify(body),
              timeout: 30000
            });
        
            let data;
            try {
              data = JSON.parse(res.responseText);
            } catch {
              throw new Error('תשובת השרת אינה תקינה.');
            }
        
            if (res.status < 200 || res.status >= 300) {
              const err = new Error(data?.error?.message || `שגיאה (${res.status})`);
              err.status = res.status;
              throw err;
            }
        
            const parts = data?.candidates?.[0]?.content?.parts || [];
            const answer = parts.filter(p => !p.thought).map(p => p.text || '').join('');
        
            const finishReason = data?.candidates?.[0]?.finishReason;
            if (finishReason === 'MAX_TOKENS' && answer.trim()) {
              return answer + '\n\n⚠️ (התשובה נקטעה עקב מגבלת אורך)';
            }
        
            return answer || '(לא התקבלה תשובה)';
          }
        
          async function callGemini(history, searchResults) {
            const key = get(K.apiKey, '').trim();
            if (!key) throw new Error('לא הוגדר מפתח API בהגדרות.');
        
            let systemText = `אתה עוזר AI לפורום ${SITE_HOST}. ענה בעברית ברורה, מדויקת ולעניין. באפשרותך לחפש ולהציג גם פרופילים, מוניטין ונתוני משתמשים בפורום במידת הצורך.`;
            const persona = get(K.persona, '');
            if (persona) systemText += '\n\n' + persona;
        
            if (get(K.context, true)) {
              const context = getPageContext();
              if (context) systemText += '\n\n' + context;
            }
        
            if (searchResults) {
              systemText += '\n\nמידע שנמצא בחיפוש בפורום ובמשתמשים:\n' + searchResults;
            }
        
            const contents = history.map(m => {
              const parts = [];
              if (m.fileData) {
                parts.push({
                  inlineData: {
                    mimeType: m.fileData.mimeType,
                    data: m.fileData.data
                  }
                });
              }
              parts.push({ text: m.text });
              return { role: m.role === 'model' ? 'model' : 'user', parts };
            });
        
            const body = {
              contents,
              generationConfig: { maxOutputTokens: 2500 }
            };
        
            if (systemText) {
              body.systemInstruction = { parts: [{ text: systemText }] };
            }
        
            let lastError;
            for (const model of MODEL_CANDIDATES) {
              for (let attempt = 0; attempt < 2; attempt++) {
                try {
                  return await callGeminiWithModel(model, key, body);
                } catch (e) {
                  lastError = e;
                  const retryable = e.status === 503 || e.status === 429;
                  if (retryable && attempt === 0) {
                    await sleep(1200);
                    continue;
                  }
                  break;
                }
              }
            }
        
            throw lastError || new Error('כל המודלים נכשלו.');
          }
        
          // --- UI Elements & Styling ---
          const style = document.createElement('style');
          style.textContent = `
            #bina-ai-button { position:fixed; bottom:22px; left:22px; width:58px; height:58px; border-radius:50%; border:0; background:linear-gradient(135deg,#4f8cff,#7c5cff); color:white; font-size:27px; cursor:pointer; z-index:999999; box-shadow:0 5px 20px rgba(0,0,0,.3); }
            #bina-ai-panel { position:fixed; left:22px; bottom:92px; width:400px; max-width:92vw; height:560px; max-height:80vh; background:white; border-radius:15px; overflow:hidden; display:none; flex-direction:column; z-index:999999; box-shadow:0 10px 40px rgba(0,0,0,.3); direction:rtl; font-family:Arial,sans-serif; border:1px solid #ddd; }
            #bina-ai-panel.open { display:flex; }
            #bina-ai-panel.fullscreen { inset:0; width:100vw; height:100vh; max-width:none; max-height:none; border-radius:0; }
            #bina-ai-header { padding:11px; background:linear-gradient(135deg,#4f8cff,#7c5cff); color:white; font-weight:bold; display:flex; justify-content:space-between; align-items:center; cursor:move; user-select:none; }
            #bina-ai-header button { border:0; background:transparent; color:white; font-size:15px; cursor:pointer; margin-right:4px; }
            #bina-ai-new-btn { background: #ffffff !important; color: #4f8cff !important; padding: 4px 10px; border-radius: 8px; font-size: 12px !important; font-weight: bold; margin-left: 8px; box-shadow: 0 2px 5px rgba(0,0,0,0.15); transition: all 0.2s; cursor: pointer; }
            #bina-ai-new-btn:hover { background: #f0f4ff !important; transform: translateY(-1px); }
            #bina-ai-info { padding:6px 10px; font-size:11px; background:#fafafa; border-bottom:1px solid #eee; color:#666; display:flex; justify-content:space-between; align-items:center; }
            #bina-ai-messages { flex:1; overflow-y:auto; padding:10px; background:#f5f6fa; display:flex; flex-direction:column; gap:8px; }
            .bina-ai-msg { padding:9px 11px; border-radius:10px; max-width:88%; font-size:13px; line-height:1.5; white-space:pre-wrap; word-break:break-word; }
            .bina-ai-user { align-self:flex-end; background:#4f8cff; color:white; }
            .bina-ai-model { align-self:flex-start; background:white; border:1px solid #ddd; color:#222; }
            .bina-ai-error { align-self:center; color:#a00000; background:#ffe3e3; border:1px solid #f0b0b0; }
            .bina-ai-step { align-self:center; color:#444; background:#eef2ff; font-size:11px; }
            .bina-ai-msg a { color:#2a5fd6; text-decoration:underline; word-break:break-all; }
            .bina-ai-user a { color:#eaf1ff; }
            #bina-ai-inputbar { display:flex; gap:6px; padding:8px; border-top:1px solid #ddd; background: #fff; align-items: center; }
            #bina-ai-input { flex:1; resize:none; height:40px; border:1px solid #ddd; border-radius:8px; padding:8px; font-family:inherit; }
            #bina-ai-send { border:0; border-radius:8px; padding:0 14px; background:#4f8cff; color:white; font-weight:bold; cursor:pointer; height:40px; }
            #bina-ai-file-btn { border:0; border-radius:8px; width:40px; height:40px; background:#f0f2f5; color:#555; font-size:18px; cursor:pointer; display:flex; align-items:center; justify-content:center; }
            #bina-ai-file-btn:hover { background:#e4e6eb; }
            #bina-file-indicator { font-size: 11px; color: #4f8cff; padding: 2px 10px; background: #eef2ff; display: none; align-items: center; justify-content: space-between; border-bottom: 1px solid #ddd; }
            #bina-ai-settings { position:fixed; inset:0; display:none; align-items:center; justify-content:center; background:rgba(0,0,0,.45); z-index:1000000; }
            #bina-ai-settings.open { display:flex; }
            #bina-ai-settings-box { width:460px; max-width:92vw; max-height:88vh; overflow:auto; background:white; border-radius:15px; padding:18px; direction:rtl; font-family:Arial,sans-serif; }
            .bina-provider { border:1px solid #ddd; border-radius:10px; padding:10px; margin-bottom:9px; }
            .bina-provider-title { font-weight:bold; margin-bottom:8px; }
            .bina-provider input[type=password] { width:100%; box-sizing:border-box; padding:6px; margin-top:5px; border:1px solid #ddd; border-radius:6px; }
            .bina-field { margin-top:10px; }
            .bina-field label { display:block; font-weight:bold; font-size:12px; margin-bottom:5px; }
            .bina-field textarea { width:100%; box-sizing:border-box; padding:8px; border:1px solid #ddd; border-radius:8px; }
            .bina-buttons { display:flex; justify-content:flex-end; gap:8px; margin-top:15px; }
            .bina-buttons button { padding:8px 16px; border:0; border-radius:8px; cursor:pointer; }
            #bina-ai-save { background:#4f8cff; color:white; }
            .session-item { display: flex; justify-content: space-between; align-items: center; padding: 8px 10px; border-bottom: 1px solid #eee; font-size: 13px; }
            .session-item:hover { background: #f8f9fa; }
            .session-title { cursor: pointer; color: #2a5fd6; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; margin-left: 10px; font-weight: 500; }
            .session-title:hover { text-decoration: underline; }
            .session-actions button { background: #ff4d4d; color: white; border: none; border-radius: 4px; padding: 4px 8px; cursor: pointer; font-size: 11px; margin-right: 4px; }
            .session-actions button.load-btn { background: #4f8cff; }
          `;
          document.head.appendChild(style);
        
          const button = document.createElement('button');
          button.id = 'bina-ai-button';
          button.textContent = '🤖';
          button.title = `עוזר AI — ${SITE_HOST}`;
          document.body.appendChild(button);
        
          const panel = document.createElement('div');
          panel.id = 'bina-ai-panel';
          panel.innerHTML = `
            <div id="bina-ai-header">
              <div style="display:flex; align-items:center;">
                <span>🤖 עוזר AI</span>
                <button id="bina-ai-new-btn" title="התחל שיחה חדשה">💬 שיחה חדשה</button>
              </div>
              <div>
                <button id="bina-ai-settings-btn" title="הגדרות והיסטוריית שיחות">⚙️</button>
                <button id="bina-ai-fullscreen" title="מסך מלא">⛶</button>
                <button id="bina-ai-close" title="סגור">✕</button>
              </div>
            </div>
            <div id="bina-ai-info">
              <div>🌐 מחובר ל-${SITE_HOST}</div>
              <div>
                <label><input type="checkbox" id="bina-ai-context"> הקשר עמוד</label>
              </div>
            </div>
            <div id="bina-file-indicator">
              <span id="bina-file-name">📎 קובץ צורף</span>
              <button id="bina-remove-file" style="background:none; border:none; color:#a00000; cursor:pointer; font-weight:bold;">הסר ✕</button>
            </div>
            <div id="bina-ai-messages"></div>
            <div id="bina-ai-inputbar">
              <input type="file" id="bina-ai-file-input" style="display:none;" />
              <button id="bina-ai-file-btn" type="button" title="צירוף קובץ או תמונה">📎</button>
              <textarea id="bina-ai-input" placeholder="שאל שאלה, חפש אשכול, בדוק משתמש או הדבק תמונה/קובץ (Ctrl+V)..."></textarea>
              <button id="bina-ai-send" type="button">שלח</button>
            </div>
          `;
          document.body.appendChild(panel);
        
          // --- Dragging Logic ---
          const header = document.querySelector('#bina-ai-header');
          let isDragging = false, startX, startY, initialX, initialY;
        
          header.addEventListener('mousedown', e => {
            if (e.target.tagName === 'BUTTON') return;
            isDragging = true;
            startX = e.clientX;
            startY = e.clientY;
            const rect = panel.getBoundingClientRect();
            initialX = rect.left;
            initialY = rect.top;
            panel.style.bottom = 'auto';
            panel.style.left = initialX + 'px';
            panel.style.top = initialY + 'px';
            document.addEventListener('mousemove', onMouseMove);
            document.addEventListener('mouseup', onMouseUp);
          });
        
          function onMouseMove(e) {
            if (!isDragging) return;
            const dx = e.clientX - startX;
            const dy = e.clientY - startY;
            panel.style.left = (initialX + dx) + 'px';
            panel.style.top = (initialY + dy) + 'px';
          }
        
          function onMouseUp() {
            isDragging = false;
            document.removeEventListener('mousemove', onMouseMove);
            document.removeEventListener('mouseup', onMouseUp);
          }
        
          // --- File Attachment & Paste Logic ---
          let attachedFile = null;
          const fileInput = document.querySelector('#bina-ai-file-input');
          const fileBtn = document.querySelector('#bina-ai-file-btn');
          const fileIndicator = document.querySelector('#bina-file-indicator');
          const fileNameSpan = document.querySelector('#bina-file-name');
          const removeFileBtn = document.querySelector('#bina-remove-file');
          const input = document.querySelector('#bina-ai-input');
        
          fileBtn.onclick = () => fileInput.click();
        
          function processFile(file) {
            if (!file) return;
            const reader = new FileReader();
            reader.onload = function (uploadEvent) {
              const base64Data = uploadEvent.target.result.split(',')[1];
              attachedFile = {
                mimeType: file.type || 'application/octet-stream',
                data: base64Data,
                name: file.name || 'קובץ מודבק'
              };
              fileNameSpan.textContent = `📎 ${attachedFile.name} צורף בהצלחה`;
              fileIndicator.style.display = 'flex';
            };
            reader.readAsDataURL(file);
          }
        
          fileInput.onchange = (e) => {
            processFile(e.target.files[0]);
          };
        
          // תמיכה בהדבקת קובץ/תמונה ישירות לתיבת הטקסט (Ctrl + V)
          input.addEventListener('paste', (e) => {
            const items = (e.clipboardData || e.originalEvent.clipboardData).items;
            for (let index in items) {
              const item = items[index];
              if (item.kind === 'file') {
                const blob = item.getAsFile();
                if (blob) {
                  e.preventDefault();
                  processFile(blob);
                  break;
                }
              }
            }
          });
        
          removeFileBtn.onclick = () => {
            attachedFile = null;
            fileInput.value = '';
            fileIndicator.style.display = 'none';
          };
        
          // --- Sessions Management Logic ---
          let sessions = [];
          try {
            sessions = JSON.parse(get(K.sessions, '[]'));
            if (!Array.isArray(sessions)) sessions = [];
          } catch (e) {
            sessions = [];
          }
          let currentSessionId = get(K.currentSessionId, '');
          let history = [];
        
          function saveSessionsToStorage() {
            set(K.sessions, JSON.stringify(sessions));
            set(K.currentSessionId, currentSessionId);
          }
        
          function startNewSession() {
            const newId = 'session_' + Date.now();
            const newSession = { id: newId, title: 'שיחה חדשה', history: [] };
            sessions.unshift(newSession);
            if (sessions.length > 20) sessions.pop();
            currentSessionId = newId;
            history = [];
            saveSessionsToStorage();
            renderMessages();
            welcome();
            renderSessionsList();
          }
        
          function loadSession(id) {
            const found = sessions.find(s => s.id === id);
            if (found) {
              currentSessionId = found.id;
              history = [...found.history];
              saveSessionsToStorage();
              renderMessages();
              if (history.length === 0) welcome();
              renderSessionsList();
            }
          }
        
          function deleteSession(id) {
            sessions = sessions.filter(s => s.id !== id);
            if (currentSessionId === id) {
              if (sessions.length > 0) {
                loadSession(sessions[0].id);
              } else {
                startNewSession();
              }
            } else {
              saveSessionsToStorage();
              renderSessionsList();
            }
          }
        
          // --- Settings & History Modal ---
          const settings = document.createElement('div');
          settings.id = 'bina-ai-settings';
          settings.innerHTML = `
            <div id="bina-ai-settings-box">
              <h3>⚙️ הגדרות והיסטוריית שיחות</h3>
              <div style="font-size:11px;color:#777;margin-bottom:12px">האתר הנוכחי: <b>${SITE_HOST}</b></div>
        
              <div class="bina-provider">
                <div class="bina-provider-title">🔵 Gemini API Key</div>
                <div style="font-size:11px;margin-bottom:3px;color:#555;">מפתח API:</div>
                <input type="password" id="gemini-key" placeholder="הכנס כאן את המפתח">
              </div>
        
              <div class="bina-field"><label>הנחיות אישיות</label><textarea id="bina-persona" placeholder="לדוגמה: ענה בקצרה..."></textarea></div>
        
              <div class="bina-field" style="margin-top:15px;">
                <label>📜 היסטוריית שיחות שמורות</label>
                <div id="bina-sessions-container" style="max-height:180px; overflow-y:auto; border:1px solid #ddd; border-radius:6px; margin-top:5px; background:#fafafa;"></div>
              </div>
        
              <div class="bina-buttons"><button id="bina-cancel">סגור</button><button id="bina-ai-save">שמור הגדרות</button></div>
            </div>
          `;
          document.body.appendChild(settings);
        
          function renderSessionsList() {
            const container = document.querySelector('#bina-sessions-container');
            if (!container) return;
            if (sessions.length === 0) {
              container.innerHTML = '<div style="padding:10px; font-size:12px; color:#777; text-align:center;">אין שיחות שמורות</div>';
              return;
            }
            container.innerHTML = '';
            sessions.forEach(s => {
              const item = document.createElement('div');
              item.className = 'session-item';
              if (s.id === currentSessionId) {
                item.style.background = '#eef2ff';
                item.style.fontWeight = 'bold';
              }
        
              const titleSpan = document.createElement('span');
              titleSpan.className = 'session-title';
              titleSpan.textContent = s.title || 'שיחה ללא כותרת';
              titleSpan.title = s.title;
              titleSpan.onclick = () => {
                loadSession(s.id);
                settings.classList.remove('open');
              };
        
              const actionsDiv = document.createElement('div');
              actionsDiv.className = 'session-actions';
        
              const loadBtn = document.createElement('button');
              loadBtn.className = 'load-btn';
              loadBtn.textContent = 'המשך';
              loadBtn.onclick = () => {
                loadSession(s.id);
                settings.classList.remove('open');
              };
        
              const delBtn = document.createElement('button');
              delBtn.textContent = 'מחק';
              delBtn.onclick = () => {
                deleteSession(s.id);
              };
        
              actionsDiv.appendChild(loadBtn);
              actionsDiv.appendChild(delBtn);
        
              item.appendChild(titleSpan);
              item.appendChild(actionsDiv);
              container.appendChild(item);
            });
          }
        
          function loadSettings() {
            document.querySelector('#gemini-key').value = get(K.apiKey, '');
            document.querySelector('#bina-persona').value = get(K.persona, '');
            document.querySelector('#bina-ai-context').checked = get(K.context, true);
            renderSessionsList();
          }
        
          function saveSettings() {
            set(K.apiKey, document.querySelector('#gemini-key').value.trim());
            set(K.persona, document.querySelector('#bina-persona').value.trim());
            set(K.context, document.querySelector('#bina-ai-context').checked);
            settings.classList.remove('open');
          }
        
          document.querySelector('#bina-ai-settings-btn').onclick = () => { loadSettings(); settings.classList.add('open'); };
          document.querySelector('#bina-cancel').onclick = () => settings.classList.remove('open');
          document.querySelector('#bina-ai-save').onclick = saveSettings;
        
          document.querySelector('#bina-ai-new-btn').onclick = () => {
            startNewSession();
          };
        
          const messagesContainer = document.querySelector('#bina-ai-messages');
          const sendButton = document.querySelector('#bina-ai-send');
        
          function escapeHtml(str) {
            return String(str)
              .replace(/&/g, '&amp;')
              .replace(/</g, '&lt;')
              .replace(/>/g, '&gt;');
          }
        
          function linkify(escapedText) {
            const urlRegex = /(https?:\/\/[^\s<>"')]+)/g;
            return escapedText.replace(urlRegex, raw => {
              const trimmed = raw.replace(/[).,;:!?]+$/, '');
              const trailing = raw.slice(trimmed.length);
              return `<a href="${trimmed}" target="_blank" rel="noopener noreferrer">${trimmed}</a>${trailing}`;
            });
          }
        
          function renderMessages() {
            messagesContainer.innerHTML = '';
            history.forEach(m => {
              const type = m.role === 'user' ? 'bina-ai-user' : 'bina-ai-model';
              const div = document.createElement('div');
              div.className = 'bina-ai-msg ' + type;
              let contentHtml = linkify(escapeHtml(m.text)).replace(/\n/g, '<br>');
              if (m.fileData && m.fileData.name) {
                contentHtml = `📎 <b>[קובץ: ${m.fileData.name}]</b><br>` + contentHtml;
              }
              div.innerHTML = contentHtml;
              messagesContainer.appendChild(div);
            });
            messagesContainer.scrollTop = messagesContainer.scrollHeight;
          }
        
          function addMessage(text, type, fileInfo = null) {
            const div = document.createElement('div');
            div.className = 'bina-ai-msg ' + type;
            let contentHtml = linkify(escapeHtml(text)).replace(/\n/g, '<br>');
            if (fileInfo && fileInfo.name) {
              contentHtml = `📎 <b>[קובץ: ${fileInfo.name}]</b><br>` + contentHtml;
            }
            div.innerHTML = contentHtml;
            messagesContainer.appendChild(div);
            messagesContainer.scrollTop = messagesContainer.scrollHeight;
            return div;
          }
        
          function welcome() {
            addMessage(`שלום! 🤖\nאני עוזר ה-AI של ${SITE_HOST}.\n\nשאל אותי כל שאלה, חפש אשכולות, בדוק פרופילים או צרף/הדבק קובץ ותמונה!`, 'bina-ai-model');
            if (!get(K.apiKey)) {
              addMessage('⚠️ עדיין לא הוגדר מפתח API. פתח ⚙️ והוסף.', 'bina-ai-error');
            }
          }
        
          button.onclick = () => panel.classList.toggle('open');
          document.querySelector('#bina-ai-close').onclick = () => panel.classList.remove('open');
          document.querySelector('#bina-ai-fullscreen').onclick = () => panel.classList.toggle('fullscreen');
        
          async function send() {
            const text = input.value.trim();
            const currentFile = attachedFile;
        
            if (!text && !currentFile) return;
            if (!get(K.apiKey)) {
              addMessage('⚠️ אין מפתח API פעיל. פתח ⚙️ והגדר.', 'bina-ai-error');
              return;
            }
        
            if (!currentSessionId || sessions.length === 0) {
              startNewSession();
            }
        
            const messageText = text || 'צורף קובץ לעיון';
            addMessage(messageText, 'bina-ai-user', currentFile);
        
            history.push({
              role: 'user',
              text: messageText,
              fileData: currentFile ? { mimeType: currentFile.mimeType, data: currentFile.data, name: currentFile.name } : null
            });
        
            input.value = '';
            attachedFile = null;
            fileInput.value = '';
            fileIndicator.style.display = 'none';
            sendButton.disabled = true;
        
            const currentSession = sessions.find(s => s.id === currentSessionId);
            if (currentSession && currentSession.title === 'שיחה חדשה') {
              currentSession.title = messageText.slice(0, 25) + (messageText.length > 25 ? '...' : '');
            }
        
            const stepMsg = addMessage('🔎 מחפש בנתוני הפורום והמשתמשים...', 'bina-ai-step');
        
            try {
              const searchResults = await quickForumSearch(messageText);
              stepMsg.remove();
        
              const pending = addMessage('🤖 מנתח תשובה...', 'bina-ai-model');
              const answer = await callGemini(history, searchResults);
              pending.remove();
        
              addMessage(answer, 'bina-ai-model');
              history.push({ role: 'model', text: answer, fileData: null });
        
              if (currentSession) {
                currentSession.history = [...history];
                saveSessionsToStorage();
              }
            } catch (e) {
              stepMsg.remove();
              addMessage('⚠️ ' + (e?.message || String(e)), 'bina-ai-error');
            } finally {
              sendButton.disabled = false;
              input.focus();
            }
          }
        
          sendButton.onclick = send;
          input.addEventListener('keydown', e => {
            if (e.key === 'Enter' && !e.shiftKey) {
              e.preventDefault();
              send();
            }
          });
        
          GM_registerMenuCommand('⚙️ הגדרות עוזר AI', () => { loadSettings(); settings.classList.add('open'); });
        
          if (sessions.length > 0) {
            if (!currentSessionId || !sessions.some(s => s.id === currentSessionId)) {
              currentSessionId = sessions[0].id;
            }
            loadSession(currentSessionId);
          } else {
            startNewSession();
          }
        })();
        

        כמה תמונות מהעוזר גרסת "חפרן" שעשיתי:

        bbf4fc34-c7cd-4443-985d-3025c914a766-image.jpeg
        2c0532ee-5f87-4bf7-bd9d-ce1bf8f559b8-image.jpeg
        6ca78945-c7f0-4da5-93ff-17bb9ac20bae-image.jpeg

        י י 2 תגובות תגובה אחרונה
        0
        • מ מוטל 2

          שלום וברכה,

          כיון שזה היה חשוב לי, ישבתי על הקוד שלו שעות, וב"ה הצלחתי לעשות לו שטיפת מוח, כולל כמה וכמה שיפורים {כגון הסטוריית בקשות, וקישורים לחיצים וכן אפשרות לגרור את החלון ממקום למקום, וכן הוספתי אפשרות להוספת קבצים או תמונות לדיוק השאלה או הבקשה}.

          הקוד המתוקן בספויילר:

          // ==UserScript==
          // @name         מתמחים טופ + בינה טופ - עוזר AI מושלם עם תמיכה בקבצים, תמונות והדבקה ישירה
          // @namespace    https://mitmachim.top/
          // @version      23.0.0
          // @description  עוזר AI צף עם תמיכה בצירוף והדבקת קבצים ותמונות, חיפוש משתמשים ואשכולות, היסטוריית שיחות וגרירת חלון
          // @author       you
          // @match        https://mitmachim.top/*
          // @match        https://bina.top/*
          // @icon         https://mitmachim.top/favicon.ico
          // @grant        GM_setValue
          // @grant        GM_getValue
          // @grant        GM_registerMenuCommand
          // @grant        GM_xmlhttpRequest
          // @connect      generativelanguage.googleapis.com
          // @connect      mitmachim.top
          // @connect      bina.top
          // @run-at       document-end
          // ==/UserScript==
          
          (function () {
            'use strict';
          
            function getSiteOrigin() {
              const host = location.hostname.toLowerCase();
              if (host === 'bina.top' || host.endsWith('.bina.top')) {
                return 'https://bina.top';
              }
              return 'https://mitmachim.top';
            }
          
            const SITE_ORIGIN = getSiteOrigin();
            const SITE_HOST = new URL(SITE_ORIGIN).hostname;
          
            const K = {
              apiKey: 'mt_ai_gemini_key',
              context: 'mt_ai_context',
              persona: 'mt_ai_persona',
              sessions: 'mt_ai_sessions_list',
              currentSessionId: 'mt_ai_current_session_id'
            };
          
            const get = (k, d = '') => GM_getValue(k, d);
            const set = (k, v) => GM_setValue(k, v);
          
            function request(details) {
              return new Promise((resolve, reject) => {
                GM_xmlhttpRequest({
                  ...details,
                  onload: resolve,
                  onerror: () => reject(new Error('שגיאת רשת')),
                  ontimeout: () => reject(new Error('זמן קצוב עבר'))
                });
              });
            }
          
            async function fetchText(url) {
              const res = await request({ method: 'GET', url, timeout: 25000 });
              if (res.status < 200 || res.status >= 300) throw new Error('שגיאה בטעינת נתונים');
              return res.responseText;
            }
          
            function htmlToText(root) {
              if (!root) return '';
              const clone = root.cloneNode(true);
              clone.querySelectorAll('script,style').forEach(x => x.remove());
              clone.querySelectorAll('a[href]').forEach(a => {
                try {
                  const href = new URL(a.getAttribute('href'), SITE_ORIGIN).href;
                  const label = (a.textContent || '').trim();
                  const replacement = label && label !== href ? `${label} (${href})` : href;
                  a.replaceWith(document.createTextNode(' ' + replacement + ' '));
                } catch {}
              });
              clone.querySelectorAll('br').forEach(br => br.replaceWith(document.createTextNode('\n')));
              clone.querySelectorAll('p,div,li,blockquote,tr,h1,h2,h3,h4,h5,h6').forEach(b => {
                b.appendChild(document.createTextNode('\n'));
              });
              return (clone.textContent || '')
                .replace(/[ \t]+/g, ' ')
                .replace(/ *\n */g, '\n')
                .replace(/\n{3,}/g, '\n\n')
                .trim();
            }
          
            function extractSearchHits(data) {
              const arr = data?.posts || data?.matches || data?.results || [];
              if (!Array.isArray(arr)) return [];
              return arr.map(p => {
                const topic = p.topic || p;
                const title = topic?.title || p.title || '(ללא כותרת)';
                const slug = topic?.slug || p.slug;
                const tid = topic?.tid || p.tid;
                let url = '';
                if (slug) url = `${SITE_ORIGIN}/topic/${slug}`;
                else if (tid) url = `${SITE_ORIGIN}/topic/${tid}`;
                return { title, url };
              }).filter(h => h.url);
            }
          
            async function legacySearchScrape(query) {
              try {
                const url = `${SITE_ORIGIN}/search?term=${encodeURIComponent(query)}`;
                const html = await fetchText(url);
                const doc = new DOMParser().parseFromString(html, 'text/html');
                doc.querySelectorAll('script,style,nav,header,footer').forEach(x => x.remove());
                const results = [];
                doc.querySelectorAll('a[href*="/topic/"]').forEach(a => {
                  if (results.length >= 6) return;
                  const href = a.getAttribute('href');
                  const text = (a.textContent || '').trim();
                  if (href && text && text.length > 3) {
                    try {
                      const absolute = new URL(href, url).href;
                      if (!results.some(r => r.url === absolute)) {
                        results.push({ title: text, url: absolute });
                      }
                    } catch {}
                  }
                });
                return results;
              } catch {
                return [];
              }
            }
          
            async function searchUserProfile(query) {
              query = String(query || '').trim();
              if (!query) return '';
              try {
                const apiUrl = `${SITE_ORIGIN}/api/users?query=${encodeURIComponent(query)}&page=1`;
                const raw = await fetchText(apiUrl);
                const data = JSON.parse(raw);
                const users = data?.users || [];
                if (!users.length) return '';
          
                let block = `משתמשים שנמצאו בפורום עבור "${query}":\n\n`;
                users.slice(0, 5).forEach(u => {
                  const username = u.username || 'לא ידוע';
                  const fullname = u.fullname ? ` (${u.fullname})` : '';
                  const reputation = u.reputation !== undefined ? u.reputation : 'לא ידוע';
                  const postCount = u.postcount !== undefined ? u.postcount : 'לא ידוע';
                  const profileUrl = `${SITE_ORIGIN}/user/${u.userslug || username}`;
                  block += `- משתמש: ${username}${fullname}\n  קישור לפרופיל: ${profileUrl}\n  מוניטין: ${reputation} | הודעות: ${postCount}\n\n`;
                });
                return block;
              } catch {
                return '';
              }
            }
          
            async function quickForumSearch(query) {
              query = String(query || '').trim();
              if (!query) return '';
          
              let userBlock = '';
              if (query.includes('משתמש') || query.includes('פרופיל') || query.includes('מוניטין')) {
                const cleanName = query.replace(/משתמש|פרופיל|מוניטין|של/g, '').trim();
                if (cleanName) {
                  userBlock = await searchUserProfile(cleanName);
                }
              }
          
              let hits = [];
              try {
                const apiUrl = `${SITE_ORIGIN}/api/search?term=${encodeURIComponent(query)}`;
                const raw = await fetchText(apiUrl);
                const data = JSON.parse(raw);
                hits = extractSearchHits(data);
              } catch {
                hits = [];
              }
          
              if (!hits.length) {
                hits = await legacySearchScrape(query);
              }
          
              let block = userBlock ? userBlock + '\n' : '';
          
              if (hits.length > 0) {
                const seen = new Set();
                const uniqueHits = hits.filter(h => {
                  if (seen.has(h.url)) return false;
                  seen.add(h.url);
                  return true;
                });
          
                const topResults = uniqueHits.slice(0, 3);
                const enriched = await Promise.all(topResults.map(async r => {
                  const snippet = await fetchTopicSnippet(r.url);
                  return { ...r, snippet };
                }));
          
                block += `תוצאות חיפוש אשכולות בפורום ${SITE_HOST} עבור "${query}":\n\n`;
                enriched.forEach((r, i) => {
                  block += `--- נושא ${i + 1}: ${r.title} ---\nקישור מלא: ${r.url}\n`;
                  block += r.snippet ? `תוכן הנושא:\n${r.snippet}\n\n` : '(לא ניתן היה לשלוף את תוכן הנושא)\n\n';
                });
              }
          
              return block;
            }
          
            async function fetchTopicSnippet(url, maxChars = 1400) {
              try {
                const html = await fetchText(url);
                const doc = new DOMParser().parseFromString(html, 'text/html');
                doc.querySelectorAll('script,style,nav,header,footer,aside,form').forEach(x => x.remove());
          
                const postEls = Array.from(doc.querySelectorAll('[component="post"]'));
                let text = '';
          
                if (postEls.length) {
                  const parts = postEls.slice(0, 8).map((post, i) => {
                    const contentEl = post.querySelector('[component="post/content"]') || post;
                    const authorEl = post.querySelector('[component="user/username"]') || post.querySelector('a[href*="/user/"]');
                    const author = authorEl ? authorEl.textContent.trim() : '';
                    const postText = htmlToText(contentEl);
                    return postText ? `[פוסט ${i + 1}${author ? ' מאת ' + author : ''}]\n${postText}` : '';
                  }).filter(Boolean);
                  text = parts.join('\n\n');
                }
          
                if (!text) {
                  const container = doc.querySelector('[component="topic"]') || doc.querySelector('main') || doc.body;
                  text = htmlToText(container);
                }
          
                if (text.length > maxChars) text = text.slice(0, maxChars) + '\n...[הטקסט קוצץ]';
                return text;
              } catch {
                return '';
              }
            }
          
            function getPageContext() {
              try {
                const main = document.querySelector('[component="topic"]') || document.querySelector('main') || document.body;
                let text = htmlToText(main);
                if (text.length > 1500) {
                  text = text.slice(0, 1500) + '\n...[הטקסט קוצץ]';
                }
                return `אתר: ${SITE_HOST}\nכותרת: ${document.title}\nתוכן העמוד:\n${text}`;
              } catch {
                return '';
              }
            }
          
            const MODEL_CANDIDATES = ['gemini-3.6-flash', 'gemini-3.5-flash-lite', 'gemini-2.5-flash-lite'];
          
            function sleep(ms) {
              return new Promise(resolve => setTimeout(resolve, ms));
            }
          
            async function callGeminiWithModel(model, key, body) {
              const url = `https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent?key=${encodeURIComponent(key)}`;
          
              const res = await request({
                method: 'POST',
                url,
                headers: { 'Content-Type': 'application/json' },
                data: JSON.stringify(body),
                timeout: 30000
              });
          
              let data;
              try {
                data = JSON.parse(res.responseText);
              } catch {
                throw new Error('תשובת השרת אינה תקינה.');
              }
          
              if (res.status < 200 || res.status >= 300) {
                const err = new Error(data?.error?.message || `שגיאה (${res.status})`);
                err.status = res.status;
                throw err;
              }
          
              const parts = data?.candidates?.[0]?.content?.parts || [];
              const answer = parts.filter(p => !p.thought).map(p => p.text || '').join('');
          
              const finishReason = data?.candidates?.[0]?.finishReason;
              if (finishReason === 'MAX_TOKENS' && answer.trim()) {
                return answer + '\n\n⚠️ (התשובה נקטעה עקב מגבלת אורך)';
              }
          
              return answer || '(לא התקבלה תשובה)';
            }
          
            async function callGemini(history, searchResults) {
              const key = get(K.apiKey, '').trim();
              if (!key) throw new Error('לא הוגדר מפתח API בהגדרות.');
          
              let systemText = `אתה עוזר AI לפורום ${SITE_HOST}. ענה בעברית ברורה, מדויקת ולעניין. באפשרותך לחפש ולהציג גם פרופילים, מוניטין ונתוני משתמשים בפורום במידת הצורך.`;
              const persona = get(K.persona, '');
              if (persona) systemText += '\n\n' + persona;
          
              if (get(K.context, true)) {
                const context = getPageContext();
                if (context) systemText += '\n\n' + context;
              }
          
              if (searchResults) {
                systemText += '\n\nמידע שנמצא בחיפוש בפורום ובמשתמשים:\n' + searchResults;
              }
          
              const contents = history.map(m => {
                const parts = [];
                if (m.fileData) {
                  parts.push({
                    inlineData: {
                      mimeType: m.fileData.mimeType,
                      data: m.fileData.data
                    }
                  });
                }
                parts.push({ text: m.text });
                return { role: m.role === 'model' ? 'model' : 'user', parts };
              });
          
              const body = {
                contents,
                generationConfig: { maxOutputTokens: 2500 }
              };
          
              if (systemText) {
                body.systemInstruction = { parts: [{ text: systemText }] };
              }
          
              let lastError;
              for (const model of MODEL_CANDIDATES) {
                for (let attempt = 0; attempt < 2; attempt++) {
                  try {
                    return await callGeminiWithModel(model, key, body);
                  } catch (e) {
                    lastError = e;
                    const retryable = e.status === 503 || e.status === 429;
                    if (retryable && attempt === 0) {
                      await sleep(1200);
                      continue;
                    }
                    break;
                  }
                }
              }
          
              throw lastError || new Error('כל המודלים נכשלו.');
            }
          
            // --- UI Elements & Styling ---
            const style = document.createElement('style');
            style.textContent = `
              #bina-ai-button { position:fixed; bottom:22px; left:22px; width:58px; height:58px; border-radius:50%; border:0; background:linear-gradient(135deg,#4f8cff,#7c5cff); color:white; font-size:27px; cursor:pointer; z-index:999999; box-shadow:0 5px 20px rgba(0,0,0,.3); }
              #bina-ai-panel { position:fixed; left:22px; bottom:92px; width:400px; max-width:92vw; height:560px; max-height:80vh; background:white; border-radius:15px; overflow:hidden; display:none; flex-direction:column; z-index:999999; box-shadow:0 10px 40px rgba(0,0,0,.3); direction:rtl; font-family:Arial,sans-serif; border:1px solid #ddd; }
              #bina-ai-panel.open { display:flex; }
              #bina-ai-panel.fullscreen { inset:0; width:100vw; height:100vh; max-width:none; max-height:none; border-radius:0; }
              #bina-ai-header { padding:11px; background:linear-gradient(135deg,#4f8cff,#7c5cff); color:white; font-weight:bold; display:flex; justify-content:space-between; align-items:center; cursor:move; user-select:none; }
              #bina-ai-header button { border:0; background:transparent; color:white; font-size:15px; cursor:pointer; margin-right:4px; }
              #bina-ai-new-btn { background: #ffffff !important; color: #4f8cff !important; padding: 4px 10px; border-radius: 8px; font-size: 12px !important; font-weight: bold; margin-left: 8px; box-shadow: 0 2px 5px rgba(0,0,0,0.15); transition: all 0.2s; cursor: pointer; }
              #bina-ai-new-btn:hover { background: #f0f4ff !important; transform: translateY(-1px); }
              #bina-ai-info { padding:6px 10px; font-size:11px; background:#fafafa; border-bottom:1px solid #eee; color:#666; display:flex; justify-content:space-between; align-items:center; }
              #bina-ai-messages { flex:1; overflow-y:auto; padding:10px; background:#f5f6fa; display:flex; flex-direction:column; gap:8px; }
              .bina-ai-msg { padding:9px 11px; border-radius:10px; max-width:88%; font-size:13px; line-height:1.5; white-space:pre-wrap; word-break:break-word; }
              .bina-ai-user { align-self:flex-end; background:#4f8cff; color:white; }
              .bina-ai-model { align-self:flex-start; background:white; border:1px solid #ddd; color:#222; }
              .bina-ai-error { align-self:center; color:#a00000; background:#ffe3e3; border:1px solid #f0b0b0; }
              .bina-ai-step { align-self:center; color:#444; background:#eef2ff; font-size:11px; }
              .bina-ai-msg a { color:#2a5fd6; text-decoration:underline; word-break:break-all; }
              .bina-ai-user a { color:#eaf1ff; }
              #bina-ai-inputbar { display:flex; gap:6px; padding:8px; border-top:1px solid #ddd; background: #fff; align-items: center; }
              #bina-ai-input { flex:1; resize:none; height:40px; border:1px solid #ddd; border-radius:8px; padding:8px; font-family:inherit; }
              #bina-ai-send { border:0; border-radius:8px; padding:0 14px; background:#4f8cff; color:white; font-weight:bold; cursor:pointer; height:40px; }
              #bina-ai-file-btn { border:0; border-radius:8px; width:40px; height:40px; background:#f0f2f5; color:#555; font-size:18px; cursor:pointer; display:flex; align-items:center; justify-content:center; }
              #bina-ai-file-btn:hover { background:#e4e6eb; }
              #bina-file-indicator { font-size: 11px; color: #4f8cff; padding: 2px 10px; background: #eef2ff; display: none; align-items: center; justify-content: space-between; border-bottom: 1px solid #ddd; }
              #bina-ai-settings { position:fixed; inset:0; display:none; align-items:center; justify-content:center; background:rgba(0,0,0,.45); z-index:1000000; }
              #bina-ai-settings.open { display:flex; }
              #bina-ai-settings-box { width:460px; max-width:92vw; max-height:88vh; overflow:auto; background:white; border-radius:15px; padding:18px; direction:rtl; font-family:Arial,sans-serif; }
              .bina-provider { border:1px solid #ddd; border-radius:10px; padding:10px; margin-bottom:9px; }
              .bina-provider-title { font-weight:bold; margin-bottom:8px; }
              .bina-provider input[type=password] { width:100%; box-sizing:border-box; padding:6px; margin-top:5px; border:1px solid #ddd; border-radius:6px; }
              .bina-field { margin-top:10px; }
              .bina-field label { display:block; font-weight:bold; font-size:12px; margin-bottom:5px; }
              .bina-field textarea { width:100%; box-sizing:border-box; padding:8px; border:1px solid #ddd; border-radius:8px; }
              .bina-buttons { display:flex; justify-content:flex-end; gap:8px; margin-top:15px; }
              .bina-buttons button { padding:8px 16px; border:0; border-radius:8px; cursor:pointer; }
              #bina-ai-save { background:#4f8cff; color:white; }
              .session-item { display: flex; justify-content: space-between; align-items: center; padding: 8px 10px; border-bottom: 1px solid #eee; font-size: 13px; }
              .session-item:hover { background: #f8f9fa; }
              .session-title { cursor: pointer; color: #2a5fd6; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; margin-left: 10px; font-weight: 500; }
              .session-title:hover { text-decoration: underline; }
              .session-actions button { background: #ff4d4d; color: white; border: none; border-radius: 4px; padding: 4px 8px; cursor: pointer; font-size: 11px; margin-right: 4px; }
              .session-actions button.load-btn { background: #4f8cff; }
            `;
            document.head.appendChild(style);
          
            const button = document.createElement('button');
            button.id = 'bina-ai-button';
            button.textContent = '🤖';
            button.title = `עוזר AI — ${SITE_HOST}`;
            document.body.appendChild(button);
          
            const panel = document.createElement('div');
            panel.id = 'bina-ai-panel';
            panel.innerHTML = `
              <div id="bina-ai-header">
                <div style="display:flex; align-items:center;">
                  <span>🤖 עוזר AI</span>
                  <button id="bina-ai-new-btn" title="התחל שיחה חדשה">💬 שיחה חדשה</button>
                </div>
                <div>
                  <button id="bina-ai-settings-btn" title="הגדרות והיסטוריית שיחות">⚙️</button>
                  <button id="bina-ai-fullscreen" title="מסך מלא">⛶</button>
                  <button id="bina-ai-close" title="סגור">✕</button>
                </div>
              </div>
              <div id="bina-ai-info">
                <div>🌐 מחובר ל-${SITE_HOST}</div>
                <div>
                  <label><input type="checkbox" id="bina-ai-context"> הקשר עמוד</label>
                </div>
              </div>
              <div id="bina-file-indicator">
                <span id="bina-file-name">📎 קובץ צורף</span>
                <button id="bina-remove-file" style="background:none; border:none; color:#a00000; cursor:pointer; font-weight:bold;">הסר ✕</button>
              </div>
              <div id="bina-ai-messages"></div>
              <div id="bina-ai-inputbar">
                <input type="file" id="bina-ai-file-input" style="display:none;" />
                <button id="bina-ai-file-btn" type="button" title="צירוף קובץ או תמונה">📎</button>
                <textarea id="bina-ai-input" placeholder="שאל שאלה, חפש אשכול, בדוק משתמש או הדבק תמונה/קובץ (Ctrl+V)..."></textarea>
                <button id="bina-ai-send" type="button">שלח</button>
              </div>
            `;
            document.body.appendChild(panel);
          
            // --- Dragging Logic ---
            const header = document.querySelector('#bina-ai-header');
            let isDragging = false, startX, startY, initialX, initialY;
          
            header.addEventListener('mousedown', e => {
              if (e.target.tagName === 'BUTTON') return;
              isDragging = true;
              startX = e.clientX;
              startY = e.clientY;
              const rect = panel.getBoundingClientRect();
              initialX = rect.left;
              initialY = rect.top;
              panel.style.bottom = 'auto';
              panel.style.left = initialX + 'px';
              panel.style.top = initialY + 'px';
              document.addEventListener('mousemove', onMouseMove);
              document.addEventListener('mouseup', onMouseUp);
            });
          
            function onMouseMove(e) {
              if (!isDragging) return;
              const dx = e.clientX - startX;
              const dy = e.clientY - startY;
              panel.style.left = (initialX + dx) + 'px';
              panel.style.top = (initialY + dy) + 'px';
            }
          
            function onMouseUp() {
              isDragging = false;
              document.removeEventListener('mousemove', onMouseMove);
              document.removeEventListener('mouseup', onMouseUp);
            }
          
            // --- File Attachment & Paste Logic ---
            let attachedFile = null;
            const fileInput = document.querySelector('#bina-ai-file-input');
            const fileBtn = document.querySelector('#bina-ai-file-btn');
            const fileIndicator = document.querySelector('#bina-file-indicator');
            const fileNameSpan = document.querySelector('#bina-file-name');
            const removeFileBtn = document.querySelector('#bina-remove-file');
            const input = document.querySelector('#bina-ai-input');
          
            fileBtn.onclick = () => fileInput.click();
          
            function processFile(file) {
              if (!file) return;
              const reader = new FileReader();
              reader.onload = function (uploadEvent) {
                const base64Data = uploadEvent.target.result.split(',')[1];
                attachedFile = {
                  mimeType: file.type || 'application/octet-stream',
                  data: base64Data,
                  name: file.name || 'קובץ מודבק'
                };
                fileNameSpan.textContent = `📎 ${attachedFile.name} צורף בהצלחה`;
                fileIndicator.style.display = 'flex';
              };
              reader.readAsDataURL(file);
            }
          
            fileInput.onchange = (e) => {
              processFile(e.target.files[0]);
            };
          
            // תמיכה בהדבקת קובץ/תמונה ישירות לתיבת הטקסט (Ctrl + V)
            input.addEventListener('paste', (e) => {
              const items = (e.clipboardData || e.originalEvent.clipboardData).items;
              for (let index in items) {
                const item = items[index];
                if (item.kind === 'file') {
                  const blob = item.getAsFile();
                  if (blob) {
                    e.preventDefault();
                    processFile(blob);
                    break;
                  }
                }
              }
            });
          
            removeFileBtn.onclick = () => {
              attachedFile = null;
              fileInput.value = '';
              fileIndicator.style.display = 'none';
            };
          
            // --- Sessions Management Logic ---
            let sessions = [];
            try {
              sessions = JSON.parse(get(K.sessions, '[]'));
              if (!Array.isArray(sessions)) sessions = [];
            } catch (e) {
              sessions = [];
            }
            let currentSessionId = get(K.currentSessionId, '');
            let history = [];
          
            function saveSessionsToStorage() {
              set(K.sessions, JSON.stringify(sessions));
              set(K.currentSessionId, currentSessionId);
            }
          
            function startNewSession() {
              const newId = 'session_' + Date.now();
              const newSession = { id: newId, title: 'שיחה חדשה', history: [] };
              sessions.unshift(newSession);
              if (sessions.length > 20) sessions.pop();
              currentSessionId = newId;
              history = [];
              saveSessionsToStorage();
              renderMessages();
              welcome();
              renderSessionsList();
            }
          
            function loadSession(id) {
              const found = sessions.find(s => s.id === id);
              if (found) {
                currentSessionId = found.id;
                history = [...found.history];
                saveSessionsToStorage();
                renderMessages();
                if (history.length === 0) welcome();
                renderSessionsList();
              }
            }
          
            function deleteSession(id) {
              sessions = sessions.filter(s => s.id !== id);
              if (currentSessionId === id) {
                if (sessions.length > 0) {
                  loadSession(sessions[0].id);
                } else {
                  startNewSession();
                }
              } else {
                saveSessionsToStorage();
                renderSessionsList();
              }
            }
          
            // --- Settings & History Modal ---
            const settings = document.createElement('div');
            settings.id = 'bina-ai-settings';
            settings.innerHTML = `
              <div id="bina-ai-settings-box">
                <h3>⚙️ הגדרות והיסטוריית שיחות</h3>
                <div style="font-size:11px;color:#777;margin-bottom:12px">האתר הנוכחי: <b>${SITE_HOST}</b></div>
          
                <div class="bina-provider">
                  <div class="bina-provider-title">🔵 Gemini API Key</div>
                  <div style="font-size:11px;margin-bottom:3px;color:#555;">מפתח API:</div>
                  <input type="password" id="gemini-key" placeholder="הכנס כאן את המפתח">
                </div>
          
                <div class="bina-field"><label>הנחיות אישיות</label><textarea id="bina-persona" placeholder="לדוגמה: ענה בקצרה..."></textarea></div>
          
                <div class="bina-field" style="margin-top:15px;">
                  <label>📜 היסטוריית שיחות שמורות</label>
                  <div id="bina-sessions-container" style="max-height:180px; overflow-y:auto; border:1px solid #ddd; border-radius:6px; margin-top:5px; background:#fafafa;"></div>
                </div>
          
                <div class="bina-buttons"><button id="bina-cancel">סגור</button><button id="bina-ai-save">שמור הגדרות</button></div>
              </div>
            `;
            document.body.appendChild(settings);
          
            function renderSessionsList() {
              const container = document.querySelector('#bina-sessions-container');
              if (!container) return;
              if (sessions.length === 0) {
                container.innerHTML = '<div style="padding:10px; font-size:12px; color:#777; text-align:center;">אין שיחות שמורות</div>';
                return;
              }
              container.innerHTML = '';
              sessions.forEach(s => {
                const item = document.createElement('div');
                item.className = 'session-item';
                if (s.id === currentSessionId) {
                  item.style.background = '#eef2ff';
                  item.style.fontWeight = 'bold';
                }
          
                const titleSpan = document.createElement('span');
                titleSpan.className = 'session-title';
                titleSpan.textContent = s.title || 'שיחה ללא כותרת';
                titleSpan.title = s.title;
                titleSpan.onclick = () => {
                  loadSession(s.id);
                  settings.classList.remove('open');
                };
          
                const actionsDiv = document.createElement('div');
                actionsDiv.className = 'session-actions';
          
                const loadBtn = document.createElement('button');
                loadBtn.className = 'load-btn';
                loadBtn.textContent = 'המשך';
                loadBtn.onclick = () => {
                  loadSession(s.id);
                  settings.classList.remove('open');
                };
          
                const delBtn = document.createElement('button');
                delBtn.textContent = 'מחק';
                delBtn.onclick = () => {
                  deleteSession(s.id);
                };
          
                actionsDiv.appendChild(loadBtn);
                actionsDiv.appendChild(delBtn);
          
                item.appendChild(titleSpan);
                item.appendChild(actionsDiv);
                container.appendChild(item);
              });
            }
          
            function loadSettings() {
              document.querySelector('#gemini-key').value = get(K.apiKey, '');
              document.querySelector('#bina-persona').value = get(K.persona, '');
              document.querySelector('#bina-ai-context').checked = get(K.context, true);
              renderSessionsList();
            }
          
            function saveSettings() {
              set(K.apiKey, document.querySelector('#gemini-key').value.trim());
              set(K.persona, document.querySelector('#bina-persona').value.trim());
              set(K.context, document.querySelector('#bina-ai-context').checked);
              settings.classList.remove('open');
            }
          
            document.querySelector('#bina-ai-settings-btn').onclick = () => { loadSettings(); settings.classList.add('open'); };
            document.querySelector('#bina-cancel').onclick = () => settings.classList.remove('open');
            document.querySelector('#bina-ai-save').onclick = saveSettings;
          
            document.querySelector('#bina-ai-new-btn').onclick = () => {
              startNewSession();
            };
          
            const messagesContainer = document.querySelector('#bina-ai-messages');
            const sendButton = document.querySelector('#bina-ai-send');
          
            function escapeHtml(str) {
              return String(str)
                .replace(/&/g, '&amp;')
                .replace(/</g, '&lt;')
                .replace(/>/g, '&gt;');
            }
          
            function linkify(escapedText) {
              const urlRegex = /(https?:\/\/[^\s<>"')]+)/g;
              return escapedText.replace(urlRegex, raw => {
                const trimmed = raw.replace(/[).,;:!?]+$/, '');
                const trailing = raw.slice(trimmed.length);
                return `<a href="${trimmed}" target="_blank" rel="noopener noreferrer">${trimmed}</a>${trailing}`;
              });
            }
          
            function renderMessages() {
              messagesContainer.innerHTML = '';
              history.forEach(m => {
                const type = m.role === 'user' ? 'bina-ai-user' : 'bina-ai-model';
                const div = document.createElement('div');
                div.className = 'bina-ai-msg ' + type;
                let contentHtml = linkify(escapeHtml(m.text)).replace(/\n/g, '<br>');
                if (m.fileData && m.fileData.name) {
                  contentHtml = `📎 <b>[קובץ: ${m.fileData.name}]</b><br>` + contentHtml;
                }
                div.innerHTML = contentHtml;
                messagesContainer.appendChild(div);
              });
              messagesContainer.scrollTop = messagesContainer.scrollHeight;
            }
          
            function addMessage(text, type, fileInfo = null) {
              const div = document.createElement('div');
              div.className = 'bina-ai-msg ' + type;
              let contentHtml = linkify(escapeHtml(text)).replace(/\n/g, '<br>');
              if (fileInfo && fileInfo.name) {
                contentHtml = `📎 <b>[קובץ: ${fileInfo.name}]</b><br>` + contentHtml;
              }
              div.innerHTML = contentHtml;
              messagesContainer.appendChild(div);
              messagesContainer.scrollTop = messagesContainer.scrollHeight;
              return div;
            }
          
            function welcome() {
              addMessage(`שלום! 🤖\nאני עוזר ה-AI של ${SITE_HOST}.\n\nשאל אותי כל שאלה, חפש אשכולות, בדוק פרופילים או צרף/הדבק קובץ ותמונה!`, 'bina-ai-model');
              if (!get(K.apiKey)) {
                addMessage('⚠️ עדיין לא הוגדר מפתח API. פתח ⚙️ והוסף.', 'bina-ai-error');
              }
            }
          
            button.onclick = () => panel.classList.toggle('open');
            document.querySelector('#bina-ai-close').onclick = () => panel.classList.remove('open');
            document.querySelector('#bina-ai-fullscreen').onclick = () => panel.classList.toggle('fullscreen');
          
            async function send() {
              const text = input.value.trim();
              const currentFile = attachedFile;
          
              if (!text && !currentFile) return;
              if (!get(K.apiKey)) {
                addMessage('⚠️ אין מפתח API פעיל. פתח ⚙️ והגדר.', 'bina-ai-error');
                return;
              }
          
              if (!currentSessionId || sessions.length === 0) {
                startNewSession();
              }
          
              const messageText = text || 'צורף קובץ לעיון';
              addMessage(messageText, 'bina-ai-user', currentFile);
          
              history.push({
                role: 'user',
                text: messageText,
                fileData: currentFile ? { mimeType: currentFile.mimeType, data: currentFile.data, name: currentFile.name } : null
              });
          
              input.value = '';
              attachedFile = null;
              fileInput.value = '';
              fileIndicator.style.display = 'none';
              sendButton.disabled = true;
          
              const currentSession = sessions.find(s => s.id === currentSessionId);
              if (currentSession && currentSession.title === 'שיחה חדשה') {
                currentSession.title = messageText.slice(0, 25) + (messageText.length > 25 ? '...' : '');
              }
          
              const stepMsg = addMessage('🔎 מחפש בנתוני הפורום והמשתמשים...', 'bina-ai-step');
          
              try {
                const searchResults = await quickForumSearch(messageText);
                stepMsg.remove();
          
                const pending = addMessage('🤖 מנתח תשובה...', 'bina-ai-model');
                const answer = await callGemini(history, searchResults);
                pending.remove();
          
                addMessage(answer, 'bina-ai-model');
                history.push({ role: 'model', text: answer, fileData: null });
          
                if (currentSession) {
                  currentSession.history = [...history];
                  saveSessionsToStorage();
                }
              } catch (e) {
                stepMsg.remove();
                addMessage('⚠️ ' + (e?.message || String(e)), 'bina-ai-error');
              } finally {
                sendButton.disabled = false;
                input.focus();
              }
            }
          
            sendButton.onclick = send;
            input.addEventListener('keydown', e => {
              if (e.key === 'Enter' && !e.shiftKey) {
                e.preventDefault();
                send();
              }
            });
          
            GM_registerMenuCommand('⚙️ הגדרות עוזר AI', () => { loadSettings(); settings.classList.add('open'); });
          
            if (sessions.length > 0) {
              if (!currentSessionId || !sessions.some(s => s.id === currentSessionId)) {
                currentSessionId = sessions[0].id;
              }
              loadSession(currentSessionId);
            } else {
              startNewSession();
            }
          })();
          

          כמה תמונות מהעוזר גרסת "חפרן" שעשיתי:

          bbf4fc34-c7cd-4443-985d-3025c914a766-image.jpeg
          2c0532ee-5f87-4bf7-bd9d-ce1bf8f559b8-image.jpeg
          6ca78945-c7f0-4da5-93ff-17bb9ac20bae-image.jpeg

          י מנותק
          י מנותק
          יאיר י.
          כתב נערך לאחרונה על ידי יאיר י.
          #87

          @מוטל-2 איך אני מעדכן את הגירסא הקודמת שיש לי?
          @יודע-ומייבין

          תגובה 1 תגובה אחרונה
          0
          • מ מוטל 2

            שלום וברכה,

            כיון שזה היה חשוב לי, ישבתי על הקוד שלו שעות, וב"ה הצלחתי לעשות לו שטיפת מוח, כולל כמה וכמה שיפורים {כגון הסטוריית בקשות, וקישורים לחיצים וכן אפשרות לגרור את החלון ממקום למקום, וכן הוספתי אפשרות להוספת קבצים או תמונות לדיוק השאלה או הבקשה}.

            הקוד המתוקן בספויילר:

            // ==UserScript==
            // @name         מתמחים טופ + בינה טופ - עוזר AI מושלם עם תמיכה בקבצים, תמונות והדבקה ישירה
            // @namespace    https://mitmachim.top/
            // @version      23.0.0
            // @description  עוזר AI צף עם תמיכה בצירוף והדבקת קבצים ותמונות, חיפוש משתמשים ואשכולות, היסטוריית שיחות וגרירת חלון
            // @author       you
            // @match        https://mitmachim.top/*
            // @match        https://bina.top/*
            // @icon         https://mitmachim.top/favicon.ico
            // @grant        GM_setValue
            // @grant        GM_getValue
            // @grant        GM_registerMenuCommand
            // @grant        GM_xmlhttpRequest
            // @connect      generativelanguage.googleapis.com
            // @connect      mitmachim.top
            // @connect      bina.top
            // @run-at       document-end
            // ==/UserScript==
            
            (function () {
              'use strict';
            
              function getSiteOrigin() {
                const host = location.hostname.toLowerCase();
                if (host === 'bina.top' || host.endsWith('.bina.top')) {
                  return 'https://bina.top';
                }
                return 'https://mitmachim.top';
              }
            
              const SITE_ORIGIN = getSiteOrigin();
              const SITE_HOST = new URL(SITE_ORIGIN).hostname;
            
              const K = {
                apiKey: 'mt_ai_gemini_key',
                context: 'mt_ai_context',
                persona: 'mt_ai_persona',
                sessions: 'mt_ai_sessions_list',
                currentSessionId: 'mt_ai_current_session_id'
              };
            
              const get = (k, d = '') => GM_getValue(k, d);
              const set = (k, v) => GM_setValue(k, v);
            
              function request(details) {
                return new Promise((resolve, reject) => {
                  GM_xmlhttpRequest({
                    ...details,
                    onload: resolve,
                    onerror: () => reject(new Error('שגיאת רשת')),
                    ontimeout: () => reject(new Error('זמן קצוב עבר'))
                  });
                });
              }
            
              async function fetchText(url) {
                const res = await request({ method: 'GET', url, timeout: 25000 });
                if (res.status < 200 || res.status >= 300) throw new Error('שגיאה בטעינת נתונים');
                return res.responseText;
              }
            
              function htmlToText(root) {
                if (!root) return '';
                const clone = root.cloneNode(true);
                clone.querySelectorAll('script,style').forEach(x => x.remove());
                clone.querySelectorAll('a[href]').forEach(a => {
                  try {
                    const href = new URL(a.getAttribute('href'), SITE_ORIGIN).href;
                    const label = (a.textContent || '').trim();
                    const replacement = label && label !== href ? `${label} (${href})` : href;
                    a.replaceWith(document.createTextNode(' ' + replacement + ' '));
                  } catch {}
                });
                clone.querySelectorAll('br').forEach(br => br.replaceWith(document.createTextNode('\n')));
                clone.querySelectorAll('p,div,li,blockquote,tr,h1,h2,h3,h4,h5,h6').forEach(b => {
                  b.appendChild(document.createTextNode('\n'));
                });
                return (clone.textContent || '')
                  .replace(/[ \t]+/g, ' ')
                  .replace(/ *\n */g, '\n')
                  .replace(/\n{3,}/g, '\n\n')
                  .trim();
              }
            
              function extractSearchHits(data) {
                const arr = data?.posts || data?.matches || data?.results || [];
                if (!Array.isArray(arr)) return [];
                return arr.map(p => {
                  const topic = p.topic || p;
                  const title = topic?.title || p.title || '(ללא כותרת)';
                  const slug = topic?.slug || p.slug;
                  const tid = topic?.tid || p.tid;
                  let url = '';
                  if (slug) url = `${SITE_ORIGIN}/topic/${slug}`;
                  else if (tid) url = `${SITE_ORIGIN}/topic/${tid}`;
                  return { title, url };
                }).filter(h => h.url);
              }
            
              async function legacySearchScrape(query) {
                try {
                  const url = `${SITE_ORIGIN}/search?term=${encodeURIComponent(query)}`;
                  const html = await fetchText(url);
                  const doc = new DOMParser().parseFromString(html, 'text/html');
                  doc.querySelectorAll('script,style,nav,header,footer').forEach(x => x.remove());
                  const results = [];
                  doc.querySelectorAll('a[href*="/topic/"]').forEach(a => {
                    if (results.length >= 6) return;
                    const href = a.getAttribute('href');
                    const text = (a.textContent || '').trim();
                    if (href && text && text.length > 3) {
                      try {
                        const absolute = new URL(href, url).href;
                        if (!results.some(r => r.url === absolute)) {
                          results.push({ title: text, url: absolute });
                        }
                      } catch {}
                    }
                  });
                  return results;
                } catch {
                  return [];
                }
              }
            
              async function searchUserProfile(query) {
                query = String(query || '').trim();
                if (!query) return '';
                try {
                  const apiUrl = `${SITE_ORIGIN}/api/users?query=${encodeURIComponent(query)}&page=1`;
                  const raw = await fetchText(apiUrl);
                  const data = JSON.parse(raw);
                  const users = data?.users || [];
                  if (!users.length) return '';
            
                  let block = `משתמשים שנמצאו בפורום עבור "${query}":\n\n`;
                  users.slice(0, 5).forEach(u => {
                    const username = u.username || 'לא ידוע';
                    const fullname = u.fullname ? ` (${u.fullname})` : '';
                    const reputation = u.reputation !== undefined ? u.reputation : 'לא ידוע';
                    const postCount = u.postcount !== undefined ? u.postcount : 'לא ידוע';
                    const profileUrl = `${SITE_ORIGIN}/user/${u.userslug || username}`;
                    block += `- משתמש: ${username}${fullname}\n  קישור לפרופיל: ${profileUrl}\n  מוניטין: ${reputation} | הודעות: ${postCount}\n\n`;
                  });
                  return block;
                } catch {
                  return '';
                }
              }
            
              async function quickForumSearch(query) {
                query = String(query || '').trim();
                if (!query) return '';
            
                let userBlock = '';
                if (query.includes('משתמש') || query.includes('פרופיל') || query.includes('מוניטין')) {
                  const cleanName = query.replace(/משתמש|פרופיל|מוניטין|של/g, '').trim();
                  if (cleanName) {
                    userBlock = await searchUserProfile(cleanName);
                  }
                }
            
                let hits = [];
                try {
                  const apiUrl = `${SITE_ORIGIN}/api/search?term=${encodeURIComponent(query)}`;
                  const raw = await fetchText(apiUrl);
                  const data = JSON.parse(raw);
                  hits = extractSearchHits(data);
                } catch {
                  hits = [];
                }
            
                if (!hits.length) {
                  hits = await legacySearchScrape(query);
                }
            
                let block = userBlock ? userBlock + '\n' : '';
            
                if (hits.length > 0) {
                  const seen = new Set();
                  const uniqueHits = hits.filter(h => {
                    if (seen.has(h.url)) return false;
                    seen.add(h.url);
                    return true;
                  });
            
                  const topResults = uniqueHits.slice(0, 3);
                  const enriched = await Promise.all(topResults.map(async r => {
                    const snippet = await fetchTopicSnippet(r.url);
                    return { ...r, snippet };
                  }));
            
                  block += `תוצאות חיפוש אשכולות בפורום ${SITE_HOST} עבור "${query}":\n\n`;
                  enriched.forEach((r, i) => {
                    block += `--- נושא ${i + 1}: ${r.title} ---\nקישור מלא: ${r.url}\n`;
                    block += r.snippet ? `תוכן הנושא:\n${r.snippet}\n\n` : '(לא ניתן היה לשלוף את תוכן הנושא)\n\n';
                  });
                }
            
                return block;
              }
            
              async function fetchTopicSnippet(url, maxChars = 1400) {
                try {
                  const html = await fetchText(url);
                  const doc = new DOMParser().parseFromString(html, 'text/html');
                  doc.querySelectorAll('script,style,nav,header,footer,aside,form').forEach(x => x.remove());
            
                  const postEls = Array.from(doc.querySelectorAll('[component="post"]'));
                  let text = '';
            
                  if (postEls.length) {
                    const parts = postEls.slice(0, 8).map((post, i) => {
                      const contentEl = post.querySelector('[component="post/content"]') || post;
                      const authorEl = post.querySelector('[component="user/username"]') || post.querySelector('a[href*="/user/"]');
                      const author = authorEl ? authorEl.textContent.trim() : '';
                      const postText = htmlToText(contentEl);
                      return postText ? `[פוסט ${i + 1}${author ? ' מאת ' + author : ''}]\n${postText}` : '';
                    }).filter(Boolean);
                    text = parts.join('\n\n');
                  }
            
                  if (!text) {
                    const container = doc.querySelector('[component="topic"]') || doc.querySelector('main') || doc.body;
                    text = htmlToText(container);
                  }
            
                  if (text.length > maxChars) text = text.slice(0, maxChars) + '\n...[הטקסט קוצץ]';
                  return text;
                } catch {
                  return '';
                }
              }
            
              function getPageContext() {
                try {
                  const main = document.querySelector('[component="topic"]') || document.querySelector('main') || document.body;
                  let text = htmlToText(main);
                  if (text.length > 1500) {
                    text = text.slice(0, 1500) + '\n...[הטקסט קוצץ]';
                  }
                  return `אתר: ${SITE_HOST}\nכותרת: ${document.title}\nתוכן העמוד:\n${text}`;
                } catch {
                  return '';
                }
              }
            
              const MODEL_CANDIDATES = ['gemini-3.6-flash', 'gemini-3.5-flash-lite', 'gemini-2.5-flash-lite'];
            
              function sleep(ms) {
                return new Promise(resolve => setTimeout(resolve, ms));
              }
            
              async function callGeminiWithModel(model, key, body) {
                const url = `https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent?key=${encodeURIComponent(key)}`;
            
                const res = await request({
                  method: 'POST',
                  url,
                  headers: { 'Content-Type': 'application/json' },
                  data: JSON.stringify(body),
                  timeout: 30000
                });
            
                let data;
                try {
                  data = JSON.parse(res.responseText);
                } catch {
                  throw new Error('תשובת השרת אינה תקינה.');
                }
            
                if (res.status < 200 || res.status >= 300) {
                  const err = new Error(data?.error?.message || `שגיאה (${res.status})`);
                  err.status = res.status;
                  throw err;
                }
            
                const parts = data?.candidates?.[0]?.content?.parts || [];
                const answer = parts.filter(p => !p.thought).map(p => p.text || '').join('');
            
                const finishReason = data?.candidates?.[0]?.finishReason;
                if (finishReason === 'MAX_TOKENS' && answer.trim()) {
                  return answer + '\n\n⚠️ (התשובה נקטעה עקב מגבלת אורך)';
                }
            
                return answer || '(לא התקבלה תשובה)';
              }
            
              async function callGemini(history, searchResults) {
                const key = get(K.apiKey, '').trim();
                if (!key) throw new Error('לא הוגדר מפתח API בהגדרות.');
            
                let systemText = `אתה עוזר AI לפורום ${SITE_HOST}. ענה בעברית ברורה, מדויקת ולעניין. באפשרותך לחפש ולהציג גם פרופילים, מוניטין ונתוני משתמשים בפורום במידת הצורך.`;
                const persona = get(K.persona, '');
                if (persona) systemText += '\n\n' + persona;
            
                if (get(K.context, true)) {
                  const context = getPageContext();
                  if (context) systemText += '\n\n' + context;
                }
            
                if (searchResults) {
                  systemText += '\n\nמידע שנמצא בחיפוש בפורום ובמשתמשים:\n' + searchResults;
                }
            
                const contents = history.map(m => {
                  const parts = [];
                  if (m.fileData) {
                    parts.push({
                      inlineData: {
                        mimeType: m.fileData.mimeType,
                        data: m.fileData.data
                      }
                    });
                  }
                  parts.push({ text: m.text });
                  return { role: m.role === 'model' ? 'model' : 'user', parts };
                });
            
                const body = {
                  contents,
                  generationConfig: { maxOutputTokens: 2500 }
                };
            
                if (systemText) {
                  body.systemInstruction = { parts: [{ text: systemText }] };
                }
            
                let lastError;
                for (const model of MODEL_CANDIDATES) {
                  for (let attempt = 0; attempt < 2; attempt++) {
                    try {
                      return await callGeminiWithModel(model, key, body);
                    } catch (e) {
                      lastError = e;
                      const retryable = e.status === 503 || e.status === 429;
                      if (retryable && attempt === 0) {
                        await sleep(1200);
                        continue;
                      }
                      break;
                    }
                  }
                }
            
                throw lastError || new Error('כל המודלים נכשלו.');
              }
            
              // --- UI Elements & Styling ---
              const style = document.createElement('style');
              style.textContent = `
                #bina-ai-button { position:fixed; bottom:22px; left:22px; width:58px; height:58px; border-radius:50%; border:0; background:linear-gradient(135deg,#4f8cff,#7c5cff); color:white; font-size:27px; cursor:pointer; z-index:999999; box-shadow:0 5px 20px rgba(0,0,0,.3); }
                #bina-ai-panel { position:fixed; left:22px; bottom:92px; width:400px; max-width:92vw; height:560px; max-height:80vh; background:white; border-radius:15px; overflow:hidden; display:none; flex-direction:column; z-index:999999; box-shadow:0 10px 40px rgba(0,0,0,.3); direction:rtl; font-family:Arial,sans-serif; border:1px solid #ddd; }
                #bina-ai-panel.open { display:flex; }
                #bina-ai-panel.fullscreen { inset:0; width:100vw; height:100vh; max-width:none; max-height:none; border-radius:0; }
                #bina-ai-header { padding:11px; background:linear-gradient(135deg,#4f8cff,#7c5cff); color:white; font-weight:bold; display:flex; justify-content:space-between; align-items:center; cursor:move; user-select:none; }
                #bina-ai-header button { border:0; background:transparent; color:white; font-size:15px; cursor:pointer; margin-right:4px; }
                #bina-ai-new-btn { background: #ffffff !important; color: #4f8cff !important; padding: 4px 10px; border-radius: 8px; font-size: 12px !important; font-weight: bold; margin-left: 8px; box-shadow: 0 2px 5px rgba(0,0,0,0.15); transition: all 0.2s; cursor: pointer; }
                #bina-ai-new-btn:hover { background: #f0f4ff !important; transform: translateY(-1px); }
                #bina-ai-info { padding:6px 10px; font-size:11px; background:#fafafa; border-bottom:1px solid #eee; color:#666; display:flex; justify-content:space-between; align-items:center; }
                #bina-ai-messages { flex:1; overflow-y:auto; padding:10px; background:#f5f6fa; display:flex; flex-direction:column; gap:8px; }
                .bina-ai-msg { padding:9px 11px; border-radius:10px; max-width:88%; font-size:13px; line-height:1.5; white-space:pre-wrap; word-break:break-word; }
                .bina-ai-user { align-self:flex-end; background:#4f8cff; color:white; }
                .bina-ai-model { align-self:flex-start; background:white; border:1px solid #ddd; color:#222; }
                .bina-ai-error { align-self:center; color:#a00000; background:#ffe3e3; border:1px solid #f0b0b0; }
                .bina-ai-step { align-self:center; color:#444; background:#eef2ff; font-size:11px; }
                .bina-ai-msg a { color:#2a5fd6; text-decoration:underline; word-break:break-all; }
                .bina-ai-user a { color:#eaf1ff; }
                #bina-ai-inputbar { display:flex; gap:6px; padding:8px; border-top:1px solid #ddd; background: #fff; align-items: center; }
                #bina-ai-input { flex:1; resize:none; height:40px; border:1px solid #ddd; border-radius:8px; padding:8px; font-family:inherit; }
                #bina-ai-send { border:0; border-radius:8px; padding:0 14px; background:#4f8cff; color:white; font-weight:bold; cursor:pointer; height:40px; }
                #bina-ai-file-btn { border:0; border-radius:8px; width:40px; height:40px; background:#f0f2f5; color:#555; font-size:18px; cursor:pointer; display:flex; align-items:center; justify-content:center; }
                #bina-ai-file-btn:hover { background:#e4e6eb; }
                #bina-file-indicator { font-size: 11px; color: #4f8cff; padding: 2px 10px; background: #eef2ff; display: none; align-items: center; justify-content: space-between; border-bottom: 1px solid #ddd; }
                #bina-ai-settings { position:fixed; inset:0; display:none; align-items:center; justify-content:center; background:rgba(0,0,0,.45); z-index:1000000; }
                #bina-ai-settings.open { display:flex; }
                #bina-ai-settings-box { width:460px; max-width:92vw; max-height:88vh; overflow:auto; background:white; border-radius:15px; padding:18px; direction:rtl; font-family:Arial,sans-serif; }
                .bina-provider { border:1px solid #ddd; border-radius:10px; padding:10px; margin-bottom:9px; }
                .bina-provider-title { font-weight:bold; margin-bottom:8px; }
                .bina-provider input[type=password] { width:100%; box-sizing:border-box; padding:6px; margin-top:5px; border:1px solid #ddd; border-radius:6px; }
                .bina-field { margin-top:10px; }
                .bina-field label { display:block; font-weight:bold; font-size:12px; margin-bottom:5px; }
                .bina-field textarea { width:100%; box-sizing:border-box; padding:8px; border:1px solid #ddd; border-radius:8px; }
                .bina-buttons { display:flex; justify-content:flex-end; gap:8px; margin-top:15px; }
                .bina-buttons button { padding:8px 16px; border:0; border-radius:8px; cursor:pointer; }
                #bina-ai-save { background:#4f8cff; color:white; }
                .session-item { display: flex; justify-content: space-between; align-items: center; padding: 8px 10px; border-bottom: 1px solid #eee; font-size: 13px; }
                .session-item:hover { background: #f8f9fa; }
                .session-title { cursor: pointer; color: #2a5fd6; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; margin-left: 10px; font-weight: 500; }
                .session-title:hover { text-decoration: underline; }
                .session-actions button { background: #ff4d4d; color: white; border: none; border-radius: 4px; padding: 4px 8px; cursor: pointer; font-size: 11px; margin-right: 4px; }
                .session-actions button.load-btn { background: #4f8cff; }
              `;
              document.head.appendChild(style);
            
              const button = document.createElement('button');
              button.id = 'bina-ai-button';
              button.textContent = '🤖';
              button.title = `עוזר AI — ${SITE_HOST}`;
              document.body.appendChild(button);
            
              const panel = document.createElement('div');
              panel.id = 'bina-ai-panel';
              panel.innerHTML = `
                <div id="bina-ai-header">
                  <div style="display:flex; align-items:center;">
                    <span>🤖 עוזר AI</span>
                    <button id="bina-ai-new-btn" title="התחל שיחה חדשה">💬 שיחה חדשה</button>
                  </div>
                  <div>
                    <button id="bina-ai-settings-btn" title="הגדרות והיסטוריית שיחות">⚙️</button>
                    <button id="bina-ai-fullscreen" title="מסך מלא">⛶</button>
                    <button id="bina-ai-close" title="סגור">✕</button>
                  </div>
                </div>
                <div id="bina-ai-info">
                  <div>🌐 מחובר ל-${SITE_HOST}</div>
                  <div>
                    <label><input type="checkbox" id="bina-ai-context"> הקשר עמוד</label>
                  </div>
                </div>
                <div id="bina-file-indicator">
                  <span id="bina-file-name">📎 קובץ צורף</span>
                  <button id="bina-remove-file" style="background:none; border:none; color:#a00000; cursor:pointer; font-weight:bold;">הסר ✕</button>
                </div>
                <div id="bina-ai-messages"></div>
                <div id="bina-ai-inputbar">
                  <input type="file" id="bina-ai-file-input" style="display:none;" />
                  <button id="bina-ai-file-btn" type="button" title="צירוף קובץ או תמונה">📎</button>
                  <textarea id="bina-ai-input" placeholder="שאל שאלה, חפש אשכול, בדוק משתמש או הדבק תמונה/קובץ (Ctrl+V)..."></textarea>
                  <button id="bina-ai-send" type="button">שלח</button>
                </div>
              `;
              document.body.appendChild(panel);
            
              // --- Dragging Logic ---
              const header = document.querySelector('#bina-ai-header');
              let isDragging = false, startX, startY, initialX, initialY;
            
              header.addEventListener('mousedown', e => {
                if (e.target.tagName === 'BUTTON') return;
                isDragging = true;
                startX = e.clientX;
                startY = e.clientY;
                const rect = panel.getBoundingClientRect();
                initialX = rect.left;
                initialY = rect.top;
                panel.style.bottom = 'auto';
                panel.style.left = initialX + 'px';
                panel.style.top = initialY + 'px';
                document.addEventListener('mousemove', onMouseMove);
                document.addEventListener('mouseup', onMouseUp);
              });
            
              function onMouseMove(e) {
                if (!isDragging) return;
                const dx = e.clientX - startX;
                const dy = e.clientY - startY;
                panel.style.left = (initialX + dx) + 'px';
                panel.style.top = (initialY + dy) + 'px';
              }
            
              function onMouseUp() {
                isDragging = false;
                document.removeEventListener('mousemove', onMouseMove);
                document.removeEventListener('mouseup', onMouseUp);
              }
            
              // --- File Attachment & Paste Logic ---
              let attachedFile = null;
              const fileInput = document.querySelector('#bina-ai-file-input');
              const fileBtn = document.querySelector('#bina-ai-file-btn');
              const fileIndicator = document.querySelector('#bina-file-indicator');
              const fileNameSpan = document.querySelector('#bina-file-name');
              const removeFileBtn = document.querySelector('#bina-remove-file');
              const input = document.querySelector('#bina-ai-input');
            
              fileBtn.onclick = () => fileInput.click();
            
              function processFile(file) {
                if (!file) return;
                const reader = new FileReader();
                reader.onload = function (uploadEvent) {
                  const base64Data = uploadEvent.target.result.split(',')[1];
                  attachedFile = {
                    mimeType: file.type || 'application/octet-stream',
                    data: base64Data,
                    name: file.name || 'קובץ מודבק'
                  };
                  fileNameSpan.textContent = `📎 ${attachedFile.name} צורף בהצלחה`;
                  fileIndicator.style.display = 'flex';
                };
                reader.readAsDataURL(file);
              }
            
              fileInput.onchange = (e) => {
                processFile(e.target.files[0]);
              };
            
              // תמיכה בהדבקת קובץ/תמונה ישירות לתיבת הטקסט (Ctrl + V)
              input.addEventListener('paste', (e) => {
                const items = (e.clipboardData || e.originalEvent.clipboardData).items;
                for (let index in items) {
                  const item = items[index];
                  if (item.kind === 'file') {
                    const blob = item.getAsFile();
                    if (blob) {
                      e.preventDefault();
                      processFile(blob);
                      break;
                    }
                  }
                }
              });
            
              removeFileBtn.onclick = () => {
                attachedFile = null;
                fileInput.value = '';
                fileIndicator.style.display = 'none';
              };
            
              // --- Sessions Management Logic ---
              let sessions = [];
              try {
                sessions = JSON.parse(get(K.sessions, '[]'));
                if (!Array.isArray(sessions)) sessions = [];
              } catch (e) {
                sessions = [];
              }
              let currentSessionId = get(K.currentSessionId, '');
              let history = [];
            
              function saveSessionsToStorage() {
                set(K.sessions, JSON.stringify(sessions));
                set(K.currentSessionId, currentSessionId);
              }
            
              function startNewSession() {
                const newId = 'session_' + Date.now();
                const newSession = { id: newId, title: 'שיחה חדשה', history: [] };
                sessions.unshift(newSession);
                if (sessions.length > 20) sessions.pop();
                currentSessionId = newId;
                history = [];
                saveSessionsToStorage();
                renderMessages();
                welcome();
                renderSessionsList();
              }
            
              function loadSession(id) {
                const found = sessions.find(s => s.id === id);
                if (found) {
                  currentSessionId = found.id;
                  history = [...found.history];
                  saveSessionsToStorage();
                  renderMessages();
                  if (history.length === 0) welcome();
                  renderSessionsList();
                }
              }
            
              function deleteSession(id) {
                sessions = sessions.filter(s => s.id !== id);
                if (currentSessionId === id) {
                  if (sessions.length > 0) {
                    loadSession(sessions[0].id);
                  } else {
                    startNewSession();
                  }
                } else {
                  saveSessionsToStorage();
                  renderSessionsList();
                }
              }
            
              // --- Settings & History Modal ---
              const settings = document.createElement('div');
              settings.id = 'bina-ai-settings';
              settings.innerHTML = `
                <div id="bina-ai-settings-box">
                  <h3>⚙️ הגדרות והיסטוריית שיחות</h3>
                  <div style="font-size:11px;color:#777;margin-bottom:12px">האתר הנוכחי: <b>${SITE_HOST}</b></div>
            
                  <div class="bina-provider">
                    <div class="bina-provider-title">🔵 Gemini API Key</div>
                    <div style="font-size:11px;margin-bottom:3px;color:#555;">מפתח API:</div>
                    <input type="password" id="gemini-key" placeholder="הכנס כאן את המפתח">
                  </div>
            
                  <div class="bina-field"><label>הנחיות אישיות</label><textarea id="bina-persona" placeholder="לדוגמה: ענה בקצרה..."></textarea></div>
            
                  <div class="bina-field" style="margin-top:15px;">
                    <label>📜 היסטוריית שיחות שמורות</label>
                    <div id="bina-sessions-container" style="max-height:180px; overflow-y:auto; border:1px solid #ddd; border-radius:6px; margin-top:5px; background:#fafafa;"></div>
                  </div>
            
                  <div class="bina-buttons"><button id="bina-cancel">סגור</button><button id="bina-ai-save">שמור הגדרות</button></div>
                </div>
              `;
              document.body.appendChild(settings);
            
              function renderSessionsList() {
                const container = document.querySelector('#bina-sessions-container');
                if (!container) return;
                if (sessions.length === 0) {
                  container.innerHTML = '<div style="padding:10px; font-size:12px; color:#777; text-align:center;">אין שיחות שמורות</div>';
                  return;
                }
                container.innerHTML = '';
                sessions.forEach(s => {
                  const item = document.createElement('div');
                  item.className = 'session-item';
                  if (s.id === currentSessionId) {
                    item.style.background = '#eef2ff';
                    item.style.fontWeight = 'bold';
                  }
            
                  const titleSpan = document.createElement('span');
                  titleSpan.className = 'session-title';
                  titleSpan.textContent = s.title || 'שיחה ללא כותרת';
                  titleSpan.title = s.title;
                  titleSpan.onclick = () => {
                    loadSession(s.id);
                    settings.classList.remove('open');
                  };
            
                  const actionsDiv = document.createElement('div');
                  actionsDiv.className = 'session-actions';
            
                  const loadBtn = document.createElement('button');
                  loadBtn.className = 'load-btn';
                  loadBtn.textContent = 'המשך';
                  loadBtn.onclick = () => {
                    loadSession(s.id);
                    settings.classList.remove('open');
                  };
            
                  const delBtn = document.createElement('button');
                  delBtn.textContent = 'מחק';
                  delBtn.onclick = () => {
                    deleteSession(s.id);
                  };
            
                  actionsDiv.appendChild(loadBtn);
                  actionsDiv.appendChild(delBtn);
            
                  item.appendChild(titleSpan);
                  item.appendChild(actionsDiv);
                  container.appendChild(item);
                });
              }
            
              function loadSettings() {
                document.querySelector('#gemini-key').value = get(K.apiKey, '');
                document.querySelector('#bina-persona').value = get(K.persona, '');
                document.querySelector('#bina-ai-context').checked = get(K.context, true);
                renderSessionsList();
              }
            
              function saveSettings() {
                set(K.apiKey, document.querySelector('#gemini-key').value.trim());
                set(K.persona, document.querySelector('#bina-persona').value.trim());
                set(K.context, document.querySelector('#bina-ai-context').checked);
                settings.classList.remove('open');
              }
            
              document.querySelector('#bina-ai-settings-btn').onclick = () => { loadSettings(); settings.classList.add('open'); };
              document.querySelector('#bina-cancel').onclick = () => settings.classList.remove('open');
              document.querySelector('#bina-ai-save').onclick = saveSettings;
            
              document.querySelector('#bina-ai-new-btn').onclick = () => {
                startNewSession();
              };
            
              const messagesContainer = document.querySelector('#bina-ai-messages');
              const sendButton = document.querySelector('#bina-ai-send');
            
              function escapeHtml(str) {
                return String(str)
                  .replace(/&/g, '&amp;')
                  .replace(/</g, '&lt;')
                  .replace(/>/g, '&gt;');
              }
            
              function linkify(escapedText) {
                const urlRegex = /(https?:\/\/[^\s<>"')]+)/g;
                return escapedText.replace(urlRegex, raw => {
                  const trimmed = raw.replace(/[).,;:!?]+$/, '');
                  const trailing = raw.slice(trimmed.length);
                  return `<a href="${trimmed}" target="_blank" rel="noopener noreferrer">${trimmed}</a>${trailing}`;
                });
              }
            
              function renderMessages() {
                messagesContainer.innerHTML = '';
                history.forEach(m => {
                  const type = m.role === 'user' ? 'bina-ai-user' : 'bina-ai-model';
                  const div = document.createElement('div');
                  div.className = 'bina-ai-msg ' + type;
                  let contentHtml = linkify(escapeHtml(m.text)).replace(/\n/g, '<br>');
                  if (m.fileData && m.fileData.name) {
                    contentHtml = `📎 <b>[קובץ: ${m.fileData.name}]</b><br>` + contentHtml;
                  }
                  div.innerHTML = contentHtml;
                  messagesContainer.appendChild(div);
                });
                messagesContainer.scrollTop = messagesContainer.scrollHeight;
              }
            
              function addMessage(text, type, fileInfo = null) {
                const div = document.createElement('div');
                div.className = 'bina-ai-msg ' + type;
                let contentHtml = linkify(escapeHtml(text)).replace(/\n/g, '<br>');
                if (fileInfo && fileInfo.name) {
                  contentHtml = `📎 <b>[קובץ: ${fileInfo.name}]</b><br>` + contentHtml;
                }
                div.innerHTML = contentHtml;
                messagesContainer.appendChild(div);
                messagesContainer.scrollTop = messagesContainer.scrollHeight;
                return div;
              }
            
              function welcome() {
                addMessage(`שלום! 🤖\nאני עוזר ה-AI של ${SITE_HOST}.\n\nשאל אותי כל שאלה, חפש אשכולות, בדוק פרופילים או צרף/הדבק קובץ ותמונה!`, 'bina-ai-model');
                if (!get(K.apiKey)) {
                  addMessage('⚠️ עדיין לא הוגדר מפתח API. פתח ⚙️ והוסף.', 'bina-ai-error');
                }
              }
            
              button.onclick = () => panel.classList.toggle('open');
              document.querySelector('#bina-ai-close').onclick = () => panel.classList.remove('open');
              document.querySelector('#bina-ai-fullscreen').onclick = () => panel.classList.toggle('fullscreen');
            
              async function send() {
                const text = input.value.trim();
                const currentFile = attachedFile;
            
                if (!text && !currentFile) return;
                if (!get(K.apiKey)) {
                  addMessage('⚠️ אין מפתח API פעיל. פתח ⚙️ והגדר.', 'bina-ai-error');
                  return;
                }
            
                if (!currentSessionId || sessions.length === 0) {
                  startNewSession();
                }
            
                const messageText = text || 'צורף קובץ לעיון';
                addMessage(messageText, 'bina-ai-user', currentFile);
            
                history.push({
                  role: 'user',
                  text: messageText,
                  fileData: currentFile ? { mimeType: currentFile.mimeType, data: currentFile.data, name: currentFile.name } : null
                });
            
                input.value = '';
                attachedFile = null;
                fileInput.value = '';
                fileIndicator.style.display = 'none';
                sendButton.disabled = true;
            
                const currentSession = sessions.find(s => s.id === currentSessionId);
                if (currentSession && currentSession.title === 'שיחה חדשה') {
                  currentSession.title = messageText.slice(0, 25) + (messageText.length > 25 ? '...' : '');
                }
            
                const stepMsg = addMessage('🔎 מחפש בנתוני הפורום והמשתמשים...', 'bina-ai-step');
            
                try {
                  const searchResults = await quickForumSearch(messageText);
                  stepMsg.remove();
            
                  const pending = addMessage('🤖 מנתח תשובה...', 'bina-ai-model');
                  const answer = await callGemini(history, searchResults);
                  pending.remove();
            
                  addMessage(answer, 'bina-ai-model');
                  history.push({ role: 'model', text: answer, fileData: null });
            
                  if (currentSession) {
                    currentSession.history = [...history];
                    saveSessionsToStorage();
                  }
                } catch (e) {
                  stepMsg.remove();
                  addMessage('⚠️ ' + (e?.message || String(e)), 'bina-ai-error');
                } finally {
                  sendButton.disabled = false;
                  input.focus();
                }
              }
            
              sendButton.onclick = send;
              input.addEventListener('keydown', e => {
                if (e.key === 'Enter' && !e.shiftKey) {
                  e.preventDefault();
                  send();
                }
              });
            
              GM_registerMenuCommand('⚙️ הגדרות עוזר AI', () => { loadSettings(); settings.classList.add('open'); });
            
              if (sessions.length > 0) {
                if (!currentSessionId || !sessions.some(s => s.id === currentSessionId)) {
                  currentSessionId = sessions[0].id;
                }
                loadSession(currentSessionId);
              } else {
                startNewSession();
              }
            })();
            

            כמה תמונות מהעוזר גרסת "חפרן" שעשיתי:

            bbf4fc34-c7cd-4443-985d-3025c914a766-image.jpeg
            2c0532ee-5f87-4bf7-bd9d-ce1bf8f559b8-image.jpeg
            6ca78945-c7f0-4da5-93ff-17bb9ac20bae-image.jpeg

            י מחובר
            י מחובר
            יודע ומייבין
            כתב נערך לאחרונה על ידי יודע ומייבין
            #88

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

            מ תגובה 1 תגובה אחרונה
            0
            • י יודע ומייבין

              -אוקיי‌​‌‌​‌​​​​​‌ חברים,-
              אז בניתי תוסף שהופך את מתמחים טופ לחכם הרבה יותר. מרגע שמתקינים אותו, יש כפתור 🤖 צף בכל עמוד בפורום - ומאחוריו עוזר AI אמיתי שיודע לחפש, לבדוק ולהמליץ בשבילכם, ולא סתם לענות שאלות כללי
              מה הוא יודע לעשות?

              • לחפש בפורום אשכולות אמיתיים לפי נושא
              • לבדוק מוניטין ופרופיל של משתמש
              • להמליץ מה לכתוב בתגובה
              • פריט רשימה
              • "לראות" את העמוד שאתם נמצאים בו כרגע כדי לתת תשובות רלוונטיות
              • אפשר לחבר בו-זמנית כמה ספקי AI (Gemini, Grok, ChatGPT) עם המפתח האישי שלכם, והשאלה נשלחת לכולם במקביל - התשובה שמגיעה ראשונה היא זו שמוצגת.
                התקנה
                יש להתקין כמובן את התוסף של Tampermonkey מהקישור הזה
                ואז יש להתקין את הסקריפט מכאן
                בהצלחה
              מ מנותק
              מ מנותק
              מה זה משנה אה
              כתב נערך לאחרונה על ידי
              #89

              @יודע-ומייבין
              לא עובד
              ניסיתי גם גימיני וגם גרוק
              בגרוק כתב שתשובת גרוק לא תקינה
              ובגימיני הוא חשב מלא זמן ובסוף רשם שגיאה

              י תגובה 1 תגובה אחרונה
              0
              • מ מה זה משנה אה

                @יודע-ומייבין
                לא עובד
                ניסיתי גם גימיני וגם גרוק
                בגרוק כתב שתשובת גרוק לא תקינה
                ובגימיני הוא חשב מלא זמן ובסוף רשם שגיאה

                י מחובר
                י מחובר
                יודע ומייבין
                כתב נערך לאחרונה על ידי
                #90

                @מה-זה-משנה-אה https://mitmachim.top/post/1235373

                מ תגובה 1 תגובה אחרונה
                0
                • ה מנותק
                  ה מנותק
                  המפתיע
                  כתב נערך לאחרונה על ידי
                  #91

                  זה כל פעם עושהלי ככה מה זה ???צילום מסך 2026-08-31 222657.png

                  י תגובה 1 תגובה אחרונה
                  0
                  • י יודע ומייבין

                    @מה-זה-משנה-אה https://mitmachim.top/post/1235373

                    מ מנותק
                    מ מנותק
                    מה זה משנה אה
                    כתב נערך לאחרונה על ידי
                    #92

                    @יודע-ומייבין
                    הגרסא ש @מוטל-2 עשה כן עובדת?

                    יאיר דניאלי תגובה 1 תגובה אחרונה
                    0
                    • ה המפתיע

                      זה כל פעם עושהלי ככה מה זה ???צילום מסך 2026-08-31 222657.png

                      י מחובר
                      י מחובר
                      יודע ומייבין
                      כתב נערך לאחרונה על ידי
                      #93

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

                      תגובה 1 תגובה אחרונה
                      0
                      • מ מה זה משנה אה

                        @יודע-ומייבין
                        הגרסא ש @מוטל-2 עשה כן עובדת?

                        יאיר דניאלי מנותק
                        יאיר דניאלי מנותק
                        יאיר דניאל
                        כתב נערך לאחרונה על ידי
                        #94

                        @מה-זה-משנה-אה כרגע‌​‌‌​‌​​​​​‌ כן

                        מ תגובה 1 תגובה אחרונה
                        0
                        • יאיר דניאלי יאיר דניאל

                          @מה-זה-משנה-אה כרגע‌​‌‌​‌​​​​​‌ כן

                          מ מנותק
                          מ מנותק
                          מה זה משנה אה
                          כתב נערך לאחרונה על ידי
                          #95

                          @יאיר-דניאל
                          ניסיתי וגם זה לא

                          מ תגובה 1 תגובה אחרונה
                          0
                          • י יודע ומייבין

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

                            מ מחובר
                            מ מחובר
                            מוטל 2
                            כתב נערך לאחרונה על ידי מוטל 2
                            #96

                            @יודע-ומייבין

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

                            י תגובה 1 תגובה אחרונה
                            0
                            • מ מוטל 2

                              @יודע-ומייבין

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

                              י מחובר
                              י מחובר
                              יודע ומייבין
                              כתב נערך לאחרונה על ידי
                              #97

                              @מוטל-2 ממש הגזמת זה בסדר

                              מ תגובה 1 תגובה אחרונה
                              1
                              • מ מה זה משנה אה

                                @יאיר-דניאל
                                ניסיתי וגם זה לא

                                מ מחובר
                                מ מחובר
                                מוטל 2
                                כתב נערך לאחרונה על ידי
                                #98

                                @מה-זה-משנה-אה
                                מה הבעיה שזה עשה לך?

                                תגובה 1 תגובה אחרונה
                                0
                                • י יודע ומייבין

                                  @מוטל-2 ממש הגזמת זה בסדר

                                  מ מחובר
                                  מ מחובר
                                  מוטל 2
                                  כתב נערך לאחרונה על ידי
                                  #99

                                  @יודע-ומייבין
                                  אני מחזיר את הפוסט

                                  יאיר דניאלי תגובה 1 תגובה אחרונה
                                  1
                                  • מ מוטל 2

                                    @יודע-ומייבין
                                    אני מחזיר את הפוסט

                                    יאיר דניאלי מנותק
                                    יאיר דניאלי מנותק
                                    יאיר דניאל
                                    כתב נערך לאחרונה על ידי
                                    #100

                                    @מוטל-2 עובד‌​‌‌​‌​​​​​‌ מצויין!!!
                                    5bc49392-e02d-4cf4-b23f-1c4095918898-image.jpeg

                                    י תגובה 1 תגובה אחרונה
                                    1
                                    • יאיר דניאלי יאיר דניאל

                                      @מוטל-2 עובד‌​‌‌​‌​​​​​‌ מצויין!!!
                                      5bc49392-e02d-4cf4-b23f-1c4095918898-image.jpeg

                                      י מחובר
                                      י מחובר
                                      יודע ומייבין
                                      כתב נערך לאחרונה על ידי יודע ומייבין
                                      #101

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

                                      יאיר דניאלי תגובה 1 תגובה אחרונה
                                      🤦 😂
                                      0
                                      • י יודע ומייבין

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

                                        יאיר דניאלי מנותק
                                        יאיר דניאלי מנותק
                                        יאיר דניאל
                                        כתב נערך לאחרונה על ידי
                                        #102

                                        @יודע-ומייבין אז‌​‌‌​‌​​​​​‌ א"כ - זה לא עובד טוב!!! הוא היה צריך לתקן אותי! 🙂

                                        י מ 2 תגובות תגובה אחרונה
                                        0
                                        • יאיר דניאלי יאיר דניאל

                                          @יודע-ומייבין אז‌​‌‌​‌​​​​​‌ א"כ - זה לא עובד טוב!!! הוא היה צריך לתקן אותי! 🙂

                                          י מחובר
                                          י מחובר
                                          יודע ומייבין
                                          כתב נערך לאחרונה על ידי
                                          #103

                                          @יאיר-דניאל לא אני עשיתי את העדכון😂 😂

                                          תגובה 1 תגובה אחרונה
                                          0

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

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

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

                                          הרשמה התחברות

                                          • התחברות

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

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