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

    עוזר AI מדויק עבור ימות המשיח! בדף html! גירסה 2

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

      עוזר AI מדויק עבור ימות המשיח! גירסה 2 !!ממשק משופר ואפשרות לשליחת רק חלק מההגדרות

      עדכון: ניתן לבחור שלוחות מסוימות שישלחו לגמיניי, וכך גם חוסכים טוקנים, וגם גמיניי הרבה יותר ממוקד!!!

      קרדיט ענק ל @perfect על קובץ הזיפ המסודר!!!

      הדף עובד על מפתח API גמיני שבכל שיחה שולח קובץ זיפ עם כל הגדרות המערכת!

      ניתן להזין מספר מפתחות API וברגע שמפתח אחד נכשל, הדף עובר בצורה אוטמטית למפתח הבא!
      (שימו לב חובה להעלאות קובץ זיפ באופן חד פעמי, כמו כן אין אחריות על אופצית העלאה לימות המשיח האופציה טרם נבדקה כדי הצורך, הקריינות כרגע עדיין לא עובדת)
      יש להוריד את קובץ הזיפ מפה קובץ אזור התעשייה.zi ולהוסיף P בסוף הסיומת

      להלן קוד דף הhtml המעודכן !!

      [4aa0e732-fa68-443f-9c42-b120b1dd5273-מומחה לימות.html](/assets/uploads/files/1786649972515-4aa0e732-fa68-443f-9c42-b120b1dd5273-מומחה-לימות.html) <!DOCTYPE html>
      <html lang="he" dir="rtl">
      <head>
          <meta charset="UTF-8">
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
          <title>מומחה AI ימות המשיח - סביבת פיתוח מתקדמת</title>
          <!-- Fonts & Icons -->
          <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
          <link href="https://fonts.googleapis.com/css2?family=Rubik:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;500;700&display=swap" rel="stylesheet">
          <!-- JSZip for dynamic zip extraction and folder repackaging -->
          <script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script>
          <!-- Marked.js for Markdown -->
          <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
          <!-- Highlight.js for Syntax Highlighting -->
          <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/styles/tokyo-night-dark.min.css">
          <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js"></script>
          <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/languages/ini.min.js"></script>
      
          <style>
              /* Theme Palettes */
              :root, body[data-theme="cyberpunk"] {
                  --bg-dark: #070913;
                  --bg-gradient: radial-gradient(circle at 50% -20%, #1e1b4b 0%, #0c1022 50%, #070913 100%);
                  --panel-bg: rgba(18, 24, 43, 0.7);
                  --panel-border: rgba(99, 102, 241, 0.18);
                  --panel-border-hover: rgba(99, 102, 241, 0.4);
                  --user-msg: linear-gradient(135deg, #2563eb, #1d4ed8);
                  --ai-msg: rgba(26, 34, 56, 0.75);
                  --accent-glow: #38bdf8;
                  --accent-blue: #3b82f6;
                  --accent-purple: #818cf8;
                  --success: #10b981;
                  --success-glow: rgba(16, 185, 129, 0.2);
                  --text-main: #f8fafc;
                  --text-muted: #94a3b8;
                  --code-bg: #0d1322;
                  --analysis-bg: rgba(28, 25, 68, 0.7);
                  --analysis-border: #6366f1;
                  --shadow-subtle: 0 10px 30px rgba(0, 0, 0, 0.35);
              }
      
              body[data-theme="obsidian"] {
                  --bg-dark: #000000;
                  --bg-gradient: radial-gradient(circle at 50% 0%, #141414 0%, #000000 80%);
                  --panel-bg: rgba(18, 18, 18, 0.85);
                  --panel-border: #262626;
                  --panel-border-hover: #404040;
                  --user-msg: linear-gradient(135deg, #27272a, #18181b);
                  --ai-msg: rgba(20, 20, 20, 0.85);
                  --accent-glow: #10b981;
                  --accent-blue: #10b981;
                  --accent-purple: #059669;
                  --success: #10b981;
                  --success-glow: rgba(16, 185, 129, 0.15);
                  --text-main: #ffffff;
                  --text-muted: #a3a3a3;
                  --code-bg: #080808;
                  --analysis-bg: #121212;
                  --analysis-border: #2e2e2e;
                  --shadow-subtle: 0 10px 30px rgba(0, 0, 0, 0.7);
              }
      
              body[data-theme="espresso"] {
                  --bg-dark: #140d08;
                  --bg-gradient: radial-gradient(circle at 50% -10%, #382417 0%, #1c120b 60%, #140d08 100%);
                  --panel-bg: rgba(38, 25, 17, 0.8);
                  --panel-border: rgba(217, 119, 6, 0.2);
                  --panel-border-hover: rgba(217, 119, 6, 0.45);
                  --user-msg: linear-gradient(135deg, #b45309, #78350f);
                  --ai-msg: rgba(48, 31, 22, 0.8);
                  --accent-glow: #fcd34d;
                  --accent-blue: #d97706;
                  --accent-purple: #b45309;
                  --success: #10b981;
                  --success-glow: rgba(16, 185, 129, 0.2);
                  --text-main: #fffbeb;
                  --text-muted: #d6b89e;
                  --code-bg: #1b1008;
                  --analysis-bg: rgba(69, 42, 28, 0.7);
                  --analysis-border: #d97706;
                  --shadow-subtle: 0 10px 30px rgba(0, 0, 0, 0.5);
              }
      
              body[data-theme="daylight"] {
                  --bg-dark: #f8fafc;
                  --bg-gradient: radial-gradient(circle at 50% -20%, #e0e7ff 0%, #f1f5f9 60%, #f8fafc 100%);
                  --panel-bg: rgba(255, 255, 255, 0.85);
                  --panel-border: #cbd5e1;
                  --panel-border-hover: #94a3b8;
                  --user-msg: linear-gradient(135deg, #2563eb, #1d4ed8);
                  --ai-msg: rgba(241, 245, 249, 0.9);
                  --accent-glow: #2563eb;
                  --accent-blue: #2563eb;
                  --accent-purple: #4f46e5;
                  --success: #059669;
                  --success-glow: rgba(5, 150, 105, 0.15);
                  --text-main: #0f172a;
                  --text-muted: #64748b;
                  --code-bg: #ffffff;
                  --analysis-bg: #eef2ff;
                  --analysis-border: #818cf8;
                  --shadow-subtle: 0 10px 30px rgba(0, 0, 0, 0.06);
              }
      
              /* Font Sizes */
              body[data-font="small"] { font-size: 14px; }
              body[data-font="medium"] { font-size: 15.5px; }
              body[data-font="large"] { font-size: 17.5px; }
              body[data-font="huge"] { font-size: 19.5px; }
      
              * { box-sizing: border-box; margin: 0; padding: 0; font-family: 'Rubik', sans-serif; }
              body { background-color: var(--bg-dark); color: var(--text-main); height: 100vh; display: flex; flex-direction: column; overflow: hidden; background-image: var(--bg-gradient); transition: background 0.3s ease, color 0.3s ease; }
      
              /* Custom Scrollbar */
              ::-webkit-scrollbar { width: 6px; height: 6px; }
              ::-webkit-scrollbar-track { background: transparent; }
              ::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.12); border-radius: 10px; }
              ::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,0.22); }
      
              /* Navigation Header */
              header { 
                  background: var(--panel-bg); 
                  backdrop-filter: blur(20px); 
                  border-bottom: 1px solid var(--panel-border); 
                  padding: 10px 24px; 
                  display: flex; 
                  justify-content: space-between; 
                  align-items: center; 
                  z-index: 20; 
                  box-shadow: var(--shadow-subtle);
                  transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1); 
              }
      
              .logo-area { display: flex; align-items: center; gap: 16px; }
              .logo { 
                  font-size: 1.35rem; 
                  font-weight: 800; 
                  background: linear-gradient(135deg, var(--accent-glow), var(--accent-purple)); 
                  -webkit-background-clip: text; 
                  -webkit-text-fill-color: transparent; 
                  display: flex; 
                  align-items: center; 
                  gap: 10px; 
                  letter-spacing: -0.5px;
              }
      
              /* Topbar Status Badge */
              .topbar-status-badge {
                  display: inline-flex;
                  align-items: center;
                  gap: 7px;
                  padding: 4px 12px;
                  border-radius: 20px;
                  font-size: 0.78rem;
                  font-weight: 600;
                  background: rgba(255,255,255,0.04);
                  border: 1px solid var(--panel-border);
                  color: var(--text-muted);
              }
              .topbar-status-badge.active {
                  background: var(--success-glow);
                  border-color: rgba(16, 185, 129, 0.4);
                  color: var(--success);
              }
              .status-dot { width: 7px; height: 7px; border-radius: 50%; background: #64748b; }
              .topbar-status-badge.active .status-dot { background: var(--success); box-shadow: 0 0 8px var(--success); animation: pulse-dot 2s infinite; }
      
              @keyframes pulse-dot { 0%, 100% { transform: scale(1); opacity: 1; } 50% { transform: scale(1.3); opacity: 0.7; } }
      
              .header-actions { display: flex; align-items: center; gap: 10px; }
              .tabs { display: flex; gap: 8px; }
              .tab-btn { 
                  background: rgba(255,255,255,0.03); 
                  border: 1px solid var(--panel-border); 
                  color: var(--text-main); 
                  padding: 7px 16px; 
                  border-radius: 10px; 
                  cursor: pointer; 
                  transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1); 
                  font-size: 0.9rem; 
                  font-weight: 600; 
                  display: flex; 
                  align-items: center; 
                  gap: 8px; 
              }
              .tab-btn.active { 
                  background: linear-gradient(135deg, var(--accent-blue), var(--accent-purple)); 
                  border-color: transparent; 
                  color: #fff; 
                  box-shadow: 0 4px 15px rgba(59, 130, 246, 0.35); 
              }
              .tab-btn:hover:not(.active) { background: rgba(255,255,255,0.08); border-color: var(--panel-border-hover); }
      
              /* Workspace Grid */
              main { flex: 1; overflow: hidden; position: relative; }
              .tab-content { display: none; height: 100%; padding: 16px 20px; }
              .tab-content.active { display: flex; gap: 16px; }
      
              /* Sidebar Sessions */
              .history-sidebar { 
                  width: 280px; 
                  background: var(--panel-bg); 
                  backdrop-filter: blur(20px); 
                  border: 1px solid var(--panel-border); 
                  border-radius: 18px; 
                  padding: 16px; 
                  display: flex; 
                  flex-direction: column; 
                  gap: 12px; 
                  box-shadow: var(--shadow-subtle);
                  transition: all 0.3s ease; 
              }
              .new-chat-btn { 
                  width: 100%; 
                  background: linear-gradient(135deg, var(--accent-blue), var(--accent-purple)); 
                  border: none; 
                  color: white; 
                  padding: 11px 16px; 
                  border-radius: 12px; 
                  cursor: pointer; 
                  font-weight: 700; 
                  font-size: 0.92rem; 
                  display: flex; 
                  align-items: center; 
                  justify-content: center; 
                  gap: 8px; 
                  transition: all 0.2s ease; 
                  box-shadow: 0 4px 14px rgba(59, 130, 246, 0.3); 
              }
              .new-chat-btn:hover { opacity: 0.95; transform: translateY(-1.5px); box-shadow: 0 6px 18px rgba(59, 130, 246, 0.45); }
              
              .history-list { flex: 1; overflow-y: auto; display: flex; flex-direction: column; gap: 6px; padding-left: 4px; }
              .history-item { 
                  background: rgba(255,255,255,0.02); 
                  border: 1px solid transparent; 
                  padding: 9px 12px; 
                  border-radius: 10px; 
                  cursor: pointer; 
                  transition: all 0.2s; 
                  display: flex; 
                  justify-content: space-between; 
                  align-items: center; 
                  font-size: 0.86rem; 
                  color: var(--text-muted); 
              }
              .history-item:hover, .history-item.active { 
                  background: rgba(99, 102, 241, 0.12); 
                  border-color: rgba(99, 102, 241, 0.3); 
                  color: var(--text-main); 
              }
              .history-item .title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; }
              .history-item .delete-btn { opacity: 0; transition: opacity 0.2s; color: #ef4444; padding: 2px 6px; }
              .history-item:hover .delete-btn { opacity: 1; }
      
              /* Main Chat Window */
              .chat-main { flex: 1; display: flex; flex-direction: column; height: 100%; position: relative; }
              .chat-container { 
                  flex: 1; 
                  overflow-y: auto; 
                  padding: 10px 10px 30px 10px; 
                  display: flex; 
                  flex-direction: column; 
                  gap: 18px; 
                  scroll-behavior: smooth; 
              }
              .message { 
                  max-width: 85%; 
                  padding: 16px 22px; 
                  border-radius: 18px; 
                  line-height: 1.7; 
                  word-wrap: break-word; 
                  box-shadow: var(--shadow-subtle); 
                  backdrop-filter: blur(14px); 
                  animation: messageIn 0.25s cubic-bezier(0.4, 0, 0.2, 1);
              }
      
              @keyframes messageIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }
      
              .message.user { align-self: flex-start; background: var(--user-msg); color: white; border-bottom-right-radius: 3px; }
              .message.model { align-self: flex-end; background: var(--ai-msg); border-bottom-left-radius: 3px; border: 1px solid var(--panel-border); }
              
              .message-attachments { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 8px; }
              .msg-att-chip { background: rgba(0,0,0,0.25); border: 1px solid rgba(255,255,255,0.15); padding: 3px 10px; border-radius: 6px; font-size: 0.78rem; display: flex; align-items: center; gap: 6px; }
      
              /* Loading UI Animation */
              .loading-shimmer { display: inline-flex; align-items: center; gap: 10px; font-weight: 500; color: var(--accent-glow); }
              .loading-shimmer i { font-size: 1.1rem; animation: spin 1s linear infinite; }
              @keyframes spin { 100% { transform: rotate(360deg); } }
      
              /* Analysis Component */
              .analysis-box { background: var(--analysis-bg); border: 1px solid var(--analysis-border); border-radius: 14px; margin-bottom: 14px; overflow: hidden; box-shadow: 0 4px 15px rgba(0,0,0,0.15); }
              .analysis-header { padding: 11px 16px; background: rgba(99, 102, 241, 0.22); cursor: pointer; font-weight: 700; font-size: 0.9rem; color: var(--accent-glow); display: flex; justify-content: space-between; align-items: center; user-select: none; }
              .analysis-content { padding: 16px; font-size: 0.9rem; color: var(--text-main); display: none; border-top: 1px solid var(--analysis-border); white-space: pre-wrap; line-height: 1.6; }
              .analysis-box.open .analysis-content { display: block; }
      
              /* Attachments Bar */
              .attachments-preview { display: flex; gap: 8px; flex-wrap: wrap; padding: 0 4px; }
              .att-chip { background: rgba(56, 189, 248, 0.12); border: 1px solid var(--accent-glow); padding: 5px 12px; border-radius: 8px; font-size: 0.82rem; display: flex; align-items: center; gap: 8px; color: var(--text-main); }
              .att-chip .remove-att { cursor: pointer; color: #ef4444; font-weight: bold; }
      
              /* Input Controls Area */
              .input-area { 
                  background: var(--panel-bg); 
                  backdrop-filter: blur(20px); 
                  padding: 14px 18px; 
                  border: 1px solid var(--panel-border); 
                  border-radius: 18px; 
                  display: flex; 
                  flex-direction: column; 
                  gap: 10px; 
                  margin-top: 8px; 
                  box-shadow: var(--shadow-subtle);
              }
              .controls-row { display: flex; justify-content: space-between; align-items: center; font-size: 0.85rem; color: var(--text-muted); flex-wrap: wrap; gap: 10px; }
              .input-wrapper { display: flex; gap: 8px; align-items: center; }
              textarea { 
                  flex: 1; 
                  background: rgba(0, 0, 0, 0.25); 
                  border: 1px solid var(--panel-border); 
                  color: var(--text-main); 
                  padding: 12px 16px; 
                  border-radius: 14px; 
                  resize: none; 
                  height: 60px; 
                  outline: none; 
                  font-size: 0.98rem; 
                  transition: all 0.2s ease; 
              }
              textarea:focus { border-color: var(--accent-glow); box-shadow: 0 0 12px rgba(56, 189, 248, 0.2); }
              
              .btn-action { 
                  background: linear-gradient(135deg, var(--accent-blue), var(--accent-purple)); 
                  border: none; 
                  color: white; 
                  padding: 0 22px; 
                  height: 60px; 
                  border-radius: 14px; 
                  cursor: pointer; 
                  font-weight: 700; 
                  font-size: 1rem; 
                  transition: all 0.2s ease; 
                  display: flex; 
                  align-items: center; 
                  justify-content: center; 
                  gap: 8px; 
                  box-shadow: 0 4px 14px rgba(59, 130, 246, 0.3);
              }
              .btn-action:hover { opacity: 0.95; transform: translateY(-1.5px); box-shadow: 0 6px 20px rgba(59, 130, 246, 0.45); }
              .btn-action:disabled { opacity: 0.5; cursor: not-allowed; transform: none; box-shadow: none; }
              
              .btn-icon-ctl { 
                  background: rgba(255,255,255,0.03); 
                  border: 1px solid var(--panel-border); 
                  color: var(--text-main); 
                  width: 60px; 
                  height: 60px; 
                  border-radius: 14px; 
                  cursor: pointer; 
                  font-size: 1.2rem; 
                  transition: all 0.2s ease; 
                  display: flex; 
                  align-items: center; 
                  justify-content: center; 
              }
              .btn-icon-ctl:hover { background: rgba(255,255,255,0.08); border-color: var(--accent-glow); transform: translateY(-1px); }
              .btn-icon-ctl.recording { background: #ef4444; color: white; animation: pulse 1.2s infinite; }
      
              @keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.7); } 70% { box-shadow: 0 0 0 12px rgba(239, 68, 68, 0); } 100% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0); } }
      
              /* Code Block Styling */
              .code-container { position: relative; margin: 14px 0; border-radius: 12px; overflow: hidden; border: 1px solid var(--panel-border); background: var(--code-bg); box-shadow: 0 6px 20px rgba(0,0,0,0.3); }
              .code-header { background: rgba(255,255,255,0.03); padding: 9px 16px; display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid var(--panel-border); font-size: 0.82rem; color: var(--text-muted); }
              .code-actions { display: flex; gap: 6px; }
              .code-btn { background: rgba(255,255,255,0.05); border: 1px solid var(--panel-border); color: var(--text-main); padding: 4px 10px; border-radius: 6px; font-size: 0.78rem; cursor: pointer; transition: 0.2s; display: flex; align-items: center; gap: 5px; font-weight: 500; }
              .code-btn:hover { background: var(--accent-blue); color: white; border-color: transparent; }
              pre { margin: 0 !important; }
              pre code { font-family: 'JetBrains Mono', monospace !important; font-size: 0.92rem; padding: 16px !important; line-height: 1.55; }
      
              /* Settings Panels */
              .settings-card { 
                  background: var(--panel-bg); 
                  backdrop-filter: blur(20px); 
                  padding: 24px; 
                  border-radius: 18px; 
                  border: 1px solid var(--panel-border); 
                  margin-bottom: 18px; 
                  width: 100%; 
                  max-width: 820px; 
                  box-shadow: var(--shadow-subtle);
              }
              .settings-card h3 { margin-bottom: 14px; color: var(--accent-glow); display: flex; align-items: center; gap: 10px; font-size: 1.15rem; font-weight: 700; }
              .input-field { width: 100%; padding: 11px 16px; background: rgba(0, 0, 0, 0.25); border: 1px solid var(--panel-border); color: var(--text-main); border-radius: 10px; margin-bottom: 12px; font-size: 0.95rem; outline: none; transition: 0.2s; }
              .input-field:focus { border-color: var(--accent-glow); }
              textarea.keys-input { height: 100px; font-family: 'JetBrains Mono', monospace; direction: ltr; }
              select { background: var(--panel-bg); color: var(--text-main); border: 1px solid var(--panel-border); padding: 6px 12px; border-radius: 8px; outline: none; font-weight: 500; }
      
              /* ZIP Management & Dynamic Folder Selector */
              .zip-status-container { 
                  border: 1px dashed var(--panel-border); 
                  border-radius: 14px; 
                  padding: 20px; 
                  background: rgba(0,0,0,0.15); 
                  display: flex; 
                  flex-direction: column; 
                  gap: 14px; 
                  transition: all 0.2s ease; 
              }
              .zip-status-container.has-file { 
                  border-style: solid; 
                  border-color: rgba(16, 185, 129, 0.4); 
                  background: var(--success-glow); 
              }
              .zip-info-row { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 10px; }
              .zip-info-details { display: flex; align-items: center; gap: 12px; }
              .zip-icon { font-size: 2rem; color: var(--success); }
              .zip-info-text .title { font-weight: 700; font-size: 0.98rem; }
              .zip-info-text .sub { font-size: 0.82rem; color: var(--text-muted); }
              .zip-actions { display: flex; gap: 8px; }
      
              /* Folder Picker Grid in Settings */
              .folder-picker-section { border-top: 1px solid var(--panel-border); padding-top: 14px; }
              .folder-picker-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; }
              .folder-picker-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 8px; max-height: 180px; overflow-y: auto; padding: 4px; }
              .folder-checkbox-item { background: rgba(0,0,0,0.25); border: 1px solid var(--panel-border); padding: 7px 12px; border-radius: 8px; display: flex; align-items: center; gap: 8px; font-size: 0.86rem; cursor: pointer; user-select: none; transition: 0.2s; }
              .folder-checkbox-item:hover { border-color: var(--accent-glow); background: rgba(56, 189, 248, 0.08); }
              .folder-checkbox-item input { cursor: pointer; }
      
              /* Zen Mode */
              body.zen-mode header { transform: translateY(-100%); height: 0; padding: 0; overflow: hidden; }
              body.zen-mode .history-sidebar { display: none; }
              body.zen-mode .tab-content { padding: 10px 14%; }
              .exit-zen-btn { display: none; position: fixed; top: 16px; left: 16px; background: linear-gradient(135deg, var(--accent-blue), var(--accent-purple)); color: white; border: none; padding: 9px 16px; border-radius: 10px; cursor: pointer; z-index: 1000; font-weight: bold; box-shadow: 0 4px 15px rgba(0,0,0,0.5); }
              body.zen-mode .exit-zen-btn { display: flex; align-items: center; gap: 6px; }
      
              /* Jump Button */
              .jump-bottom-btn { position: absolute; bottom: 130px; left: 50%; transform: translateX(-50%) translateY(20px); background: linear-gradient(135deg, var(--accent-blue), var(--accent-purple)); color: white; border: none; padding: 8px 18px; border-radius: 20px; cursor: pointer; font-size: 0.84rem; font-weight: bold; box-shadow: 0 4px 16px rgba(59, 130, 246, 0.4); display: flex; align-items: center; gap: 8px; opacity: 0; pointer-events: none; transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1); z-index: 50; }
              .jump-bottom-btn.show { opacity: 1; pointer-events: auto; transform: translateX(-50%) translateY(0); }
              .jump-bottom-btn:hover { transform: translateX(-50%) scale(1.05); }
          </style>
      </head>
      <body data-theme="cyberpunk" data-font="medium">
      
          <!-- Exit Zen Mode Button -->
          <button class="exit-zen-btn" onclick="toggleZenMode()"><i class="fa-solid fa-compress"></i> צא ממצב פוקוס</button>
      
          <header>
              <div class="logo-area">
                  <div class="logo">
                      <i class="fa-solid fa-headset"></i>
                      <span>מומחה AI ימות המשיח</span>
                  </div>
                  <!-- Live Topbar Context Indicator -->
                  <div class="topbar-status-badge" id="topbarZipBadge" title="סטטוס קובץ תיעוד ימות המשיח">
                      <div class="status-dot"></div>
                      <span id="topbarZipText">בודק תיעוד...</span>
                  </div>
              </div>
      
              <div class="header-actions">
                  <button class="tab-btn" onclick="toggleZenMode()" title="מצב פוקוס נקי (Zen Mode)"><i class="fa-solid fa-expand"></i> פוקוס</button>
                  <div class="tabs">
                      <button class="tab-btn active" onclick="switchTab('chatTab', event)"><i class="fa-solid fa-comments"></i> צ'אט וסביבת עבודה</button>
                      <button class="tab-btn" onclick="switchTab('settingsTab', event)"><i class="fa-solid fa-sliders"></i> הגדרות ותיעוד</button>
                  </div>
              </div>
          </header>
      
          <main>
              <!-- Chat Tab with History Sidebar -->
              <div id="chatTab" class="tab-content active">
                  <div class="history-sidebar">
                      <button class="new-chat-btn" onclick="createNewSession()"><i class="fa-solid fa-plus"></i> שיחה חדשה</button>
                      <div style="font-size: 0.78rem; color: var(--text-muted); font-weight: 700; margin-top: 6px; letter-spacing: 0.5px;">שיחות אחרונות</div>
                      <div class="history-list" id="historyList"></div>
                  </div>
      
                  <div class="chat-main">
                      <div class="chat-container" id="chatContainer" onscroll="handleChatScroll()">
                          <div class="message model">
                              שלום! אני עוזר ה-AI הבכיר שלך לבניית מרכזיות, שלוחות ו-Webhooks ב'ימות המשיח'.<br>
                              כעת ניתן <b>לבחור תיקיות ספציפיות</b> מתוך קובץ ה-ZIP של התיעוד לשליחה ממוקדת ומהירה!
                          </div>
                      </div>
                      
                      <button class="jump-bottom-btn" id="jumpBottomBtn" onclick="scrollToBottom(true)">
                          <i class="fa-solid fa-arrow-down"></i> קפוץ לקוד האחרון / למטה
                      </button>
      
                      <div class="input-area">
                          <div class="attachments-preview" id="attachmentsPreview"></div>
      
                          <div class="controls-row">
                              <div style="display: flex; align-items: center; gap: 12px; flex-wrap: wrap;">
                                  <div>
                                      <i class="fa-solid fa-robot"></i> מודל:
                                      <select id="modelSelect"></select>
                                  </div>
      
                                  <!-- Fast In-Chat Folder Scope Selector -->
                                  <div id="chatFolderScopeContainer" style="display: none;">
                                      <i class="fa-solid fa-folder-tree"></i> תיקיית תיעוד:
                                      <select id="chatFolderSelect" onchange="syncSelectedFolderFromChat(this.value)"></select>
                                  </div>
                              </div>
      
                              <div>
                                  <label style="cursor: pointer;">
                                      <input type="checkbox" id="deepAnalysisToggle" checked> דרוש ניתוח מעמיק (&lt;analysis&gt;)
                                  </label>
                              </div>
                          </div>
                          <div class="input-wrapper">
                              <input type="file" id="genericFileInput" multiple style="display: none;" onchange="handleGenericFileUpload(event)">
                              <button class="btn-icon-ctl" onclick="document.getElementById('genericFileInput').click()" title="צרף קבצים (קוד, תמונות, שמע, PDF, ZIP...)">
                                  <i class="fa-solid fa-paperclip"></i>
                              </button>
      
                              <button class="btn-icon-ctl" id="micBtn" onclick="toggleVoiceInput()" title="הקלטה קולית בעברית">
                                  <i class="fa-solid fa-microphone"></i>
                              </button>
                              
                              <textarea id="userInput" placeholder="תאר את השלוחה או שאל שאלה (ניתן לגרור קבצים לכאן)..." onkeydown="handleKeyDown(event)"></textarea>
                              <button class="btn-action" id="sendBtn" onclick="sendMessage()"><i class="fa-solid fa-paper-plane"></i> שלח</button>
                          </div>
                      </div>
                  </div>
              </div>
      
              <!-- Settings & UI Customization Tab -->
              <div id="settingsTab" class="tab-content" style="flex-direction: column; overflow-y: auto;">
                  
                  <!-- Dynamic ZIP & Folder Management Card -->
                  <div class="settings-card">
                      <h3><i class="fa-solid fa-file-zipper"></i> תיעוד ימות המשיח ובחירת תיקיות (Folder Filtering)</h3>
                      <p style="font-size: 0.88rem; color: var(--text-muted); margin-bottom: 14px;">קובץ ה-ZIP של התיעוד מנותח אוטומטית. תוכל לבחור לשלוח את כל התיעוד או רק תיקיות ספציפיות לקבלת מענה ממוקד ומהיר.</p>
                      
                      <input type="file" id="zipFileInput" accept=".zip" style="display: none;" onchange="handleZipUpload(event)">
                      
                      <div class="zip-status-container" id="zipStatusBox"></div>
                  </div>
      
                  <div class="settings-card">
                      <h3><i class="fa-solid fa-key"></i> שרשור מפתחות API (Gemini Key Rotation)</h3>
                      <textarea id="apiKeysInput" class="input-field keys-input" placeholder="הכנס מפתחות API (מפתח בכל שורה)..."></textarea>
                      <button class="tab-btn active" onclick="saveKeys()"><i class="fa-solid fa-floppy-disk"></i> שמור מפתחות וטען מודלים</button>
                  </div>
      
                  <div class="settings-card">
                      <h3><i class="fa-solid fa-palette"></i> התאמת מראה וסביבת עבודה (Themes & UI)</h3>
                      <div style="display: flex; gap: 16px; flex-wrap: wrap;">
                          <div style="flex: 1;">
                              <label style="display: block; margin-bottom: 6px; color: var(--text-muted); font-size: 0.88rem;">ערכת נושא (Theme):</label>
                              <select id="themeSelect" class="input-field" onchange="changeTheme(this.value)">
                                  <option value="cyberpunk">🌌 Midnight Cyberpunk (ניאון כהה)</option>
                                  <option value="obsidian">🖤 Obsidian Pure Black (שחור מוחלט)</option>
                                  <option value="espresso">☕ Warm Espresso (חום קפה חמים)</option>
                                  <option value="daylight">☀️ Clean Daylight (מצב יום בהיר)</option>
                              </select>
                          </div>
                          <div style="flex: 1;">
                              <label style="display: block; margin-bottom: 6px; color: var(--text-muted); font-size: 0.88rem;">גודל גופן (Font Size):</label>
                              <select id="fontSelect" class="input-field" onchange="changeFontSize(this.value)">
                                  <option value="small">קטן (14px)</option>
                                  <option value="medium" selected>בינוני (15.5px)</option>
                                  <option value="large">גדול (17.5px)</option>
                                  <option value="huge">ענק (19.5px)</option>
                              </select>
                          </div>
                      </div>
                  </div>
      
                  <div class="settings-card">
                      <h3><i class="fa-solid fa-cloud-arrow-up"></i> חיבור ישיר ל-API ימות המשיח</h3>
                      <input type="text" id="ymUsername" class="input-field" placeholder="מספר מערכת (System Username)">
                      <input type="password" id="ymPassword" class="input-field" placeholder="סיסמת מערכת (System Password)">
                      <button class="tab-btn active" onclick="saveYemotCredentials()"><i class="fa-solid fa-link"></i> שמור פרטי התחברות למערכת</button>
                  </div>
              </div>
          </main>
      
          <script>
              const SYSTEM_INSTRUCTION = `אתה מתכנת בכיר ומומחה לשלוחות, מרכזיות ופיתוח ב'ימות המשיח'. תפקידך לבנות קובצי ext.ini מדויקים, תפריטי IVR, ושרתי Webhook.
      לרשותך מצורף קובץ ZIP המכיל את התיעוד וההגדרות של ימות המשיח (בהתאם לתיקיות שנבחרו), לצד כל קובץ שהמשתמש מעלה ומצרף. עליך להתבסס על התיעוד באופן מוחלט בכל תשובה.
      
      הנחיות חובה:
      1. אם המשתמש ביקש ניתוח מעמיק (או כברירת מחדל), עליך לפתוח את תגובתך בניתוח מקיף ומעמיק של הדרישה, הפורמט, הלוגיקה, והפרמטרים הנדרשים עטוף כולו בתוך תגיות <analysis> ו-</analysis>.
      2. רק לאחר התגית הסוגרת </analysis> תציג את התשובה והקוד המלאים והסופיים.
      3. הקפד על כתיבת קוד ext.ini תקני, כולל הערות והסברים ברורים בעברית.`;
      
              const LOCAL_STORAGE_KEYS = {
                  API_KEYS: 'yemot_v8_gemini_api_keys',
                  ZIP_BASE64: 'yemot_v8_zip_base64',
                  ZIP_META: 'yemot_v8_zip_meta',
                  ZIP_FOLDERS: 'yemot_v8_zip_folders',
                  SELECTED_FOLDERS: 'yemot_v8_selected_folders',
                  SESSIONS: 'yemot_v8_chat_sessions',
                  YM_USER: 'yemot_v8_ym_username',
                  YM_PASS: 'yemot_v8_ym_password',
                  THEME: 'yemot_v8_theme',
                  FONT_SIZE: 'yemot_v8_font_size'
              };
      
              // App State
              let apiKeys = [];
              let zipBase64 = localStorage.getItem(LOCAL_STORAGE_KEYS.ZIP_BASE64) || null;
              let zipMeta = JSON.parse(localStorage.getItem(LOCAL_STORAGE_KEYS.ZIP_META) || 'null');
              let zipFolders = JSON.parse(localStorage.getItem(LOCAL_STORAGE_KEYS.ZIP_FOLDERS) || '[]');
              let selectedFolders = JSON.parse(localStorage.getItem(LOCAL_STORAGE_KEYS.SELECTED_FOLDERS) || '[]');
              let sessions = [];
              let currentSessionId = null;
              let isRecording = false;
              let recognition = null;
              let pendingAttachments = [];
      
              window.onload = async () => {
                  loadThemePreferences();
                  loadKeys();
                  loadYemotCredentials();
                  initSpeechRecognition();
                  initDragAndDrop();
                  loadSessions();
                  updateZipStatusUI();
                  if (apiKeys.length > 0) await fetchModels();
              };
      
              function switchTab(tabId, event) {
                  document.querySelectorAll('.tab-content').forEach(el => el.classList.remove('active'));
                  document.querySelectorAll('.tab-btn').forEach(el => el.classList.remove('active'));
                  document.getElementById(tabId).classList.add('active');
                  if(event) event.currentTarget.classList.add('active');
              }
      
              // --- Dynamic ZIP & Folder Analysis ---
              async function analyzeZipFolders(base64Data) {
                  try {
                      const zip = new JSZip();
                      await zip.loadAsync(base64Data, { base64: true });
                      
                      const folderSet = new Set();
                      zip.forEach((relativePath, file) => {
                          const parts = relativePath.split('/');
                          if (parts.length > 1 && parts[0].trim().length > 0) {
                              folderSet.add(parts[0]);
                          }
                      });
      
                      zipFolders = Array.from(folderSet).sort();
                      selectedFolders = [...zipFolders]; // Default: select all
                      localStorage.setItem(LOCAL_STORAGE_KEYS.ZIP_FOLDERS, JSON.stringify(zipFolders));
                      localStorage.setItem(LOCAL_STORAGE_KEYS.SELECTED_FOLDERS, JSON.stringify(selectedFolders));
                  } catch (err) {
                      console.error("Error analyzing ZIP folders:", err);
                      zipFolders = [];
                      selectedFolders = [];
                  }
              }
      
              function updateZipStatusUI() {
                  const statusBox = document.getElementById('zipStatusBox');
                  const topbarBadge = document.getElementById('topbarZipBadge');
                  const topbarText = document.getElementById('topbarZipText');
                  const chatFolderContainer = document.getElementById('chatFolderScopeContainer');
                  const chatFolderSelect = document.getElementById('chatFolderSelect');
      
                  if (zipBase64 && zipMeta) {
                      let folderCheckboxesHTML = '';
                      if (zipFolders.length > 0) {
                          folderCheckboxesHTML = `
                              <div class="folder-picker-section">
                                  <div class="folder-picker-header">
                                      <span style="font-weight: 700; font-size: 0.9rem;"><i class="fa-solid fa-folder-tree"></i> בחר תיקיות לשליחה כהקשר (${selectedFolders.length}/${zipFolders.length}):</span>
                                      <div style="display: flex; gap: 8px;">
                                          <button class="tab-btn" style="padding: 3px 10px; font-size: 0.78rem;" onclick="selectAllFolders(true)">בחר הכל</button>
                                          <button class="tab-btn" style="padding: 3px 10px; font-size: 0.78rem;" onclick="selectAllFolders(false)">נקה הכל</button>
                                      </div>
                                  </div>
                                  <div class="folder-picker-grid">
                                      ${zipFolders.map(folder => `
                                          <label class="folder-checkbox-item">
                                              <input type="checkbox" value="${escapeHtml(folder)}" ${selectedFolders.includes(folder) ? 'checked' : ''} onchange="toggleFolderSelection('${escapeHtml(folder)}')">
                                              <i class="fa-regular fa-folder" style="color: var(--accent-glow);"></i>
                                              <span>${escapeHtml(folder)}</span>
                                          </label>
                                      `).join('')}
                                  </div>
                              </div>
                          `;
                      }
      
                      statusBox.className = 'zip-status-container has-file';
                      statusBox.innerHTML = `
                          <div class="zip-info-row">
                              <div class="zip-info-details">
                                  <i class="fa-solid fa-circle-check zip-icon"></i>
                                  <div class="zip-info-text">
                                      <div class="title">קובץ תיעוד פעיל: ${escapeHtml(zipMeta.name)}</div>
                                      <div class="sub">גודל: ${zipMeta.size} | סה"כ ${zipFolders.length} תיקיות זוהו</div>
                                  </div>
                              </div>
                              <div class="zip-actions">
                                  <button class="tab-btn active" onclick="document.getElementById('zipFileInput').click()">
                                      <i class="fa-solid fa-arrows-rotate"></i> החלף ZIP
                                  </button>
                                  <button class="tab-btn" style="color: #ef4444; border-color: rgba(239, 68, 68, 0.3);" onclick="removeZipFile()">
                                      <i class="fa-solid fa-trash"></i> הסר
                                  </button>
                              </div>
                          </div>
                          ${folderCheckboxesHTML}
                      `;
      
                      topbarBadge.className = 'topbar-status-badge active';
                      const folderCountText = selectedFolders.length === zipFolders.length ? 'כל התיקיות' : `${selectedFolders.length} תיקיות`;
                      topbarText.innerText = `תיעוד פעיל (${folderCountText})`;
      
                      // Update In-Chat Quick Selector
                      if (zipFolders.length > 0) {
                          chatFolderContainer.style.display = 'block';
                          chatFolderSelect.innerHTML = `<option value="__ALL__">כל התיקיות (${zipFolders.length})</option>` + 
                              zipFolders.map(f => `<option value="${escapeHtml(f)}" ${selectedFolders.length === 1 && selectedFolders[0] === f ? 'selected' : ''}>📁 ${escapeHtml(f)}</option>`).join('');
                      } else {
                          chatFolderContainer.style.display = 'none';
                      }
      
                  } else {
                      statusBox.className = 'zip-status-container';
                      statusBox.innerHTML = `
                          <div class="zip-info-row" style="justify-content: center; text-align: center; padding: 10px 0;">
                              <div>
                                  <i class="fa-solid fa-cloud-arrow-up" style="font-size: 2.2rem; color: var(--text-muted); margin-bottom: 8px;"></i>
                                  <div style="font-weight: 700; margin-bottom: 4px;">טרם נטען קובץ ZIP של תיעוד ימות המשיח</div>
                                  <div style="font-size: 0.84rem; color: var(--text-muted); margin-bottom: 12px;">העלה את קובץ ההגדרות (~688 KB) כדי לאפשר בחירת תיקיות ממוקדת</div>
                                  <button class="tab-btn active" onclick="document.getElementById('zipFileInput').click()" style="margin: 0 auto;">
                                      <i class="fa-solid fa-upload"></i> בחר קובץ ZIP להעלאה
                                  </button>
                              </div>
                          </div>
                      `;
      
                      topbarBadge.className = 'topbar-status-badge';
                      topbarText.innerText = 'אין תיעוד ZIP טעון';
                      chatFolderContainer.style.display = 'none';
                  }
              }
      
              async function handleZipUpload(event) {
                  const file = event.target.files[0];
                  if (!file) return;
                  const reader = new FileReader();
                  reader.onload = async function(e) {
                      zipBase64 = e.target.result.split(',')[1];
                      zipMeta = {
                          name: file.name,
                          size: (file.size / 1024).toFixed(1) + ' KB'
                      };
                      
                      await analyzeZipFolders(zipBase64);
      
                      try {
                          localStorage.setItem(LOCAL_STORAGE_KEYS.ZIP_BASE64, zipBase64);
                          localStorage.setItem(LOCAL_STORAGE_KEYS.ZIP_META, JSON.stringify(zipMeta));
                      } catch (err) {
                          console.warn('Zip stored in runtime memory.');
                      }
                      updateZipStatusUI();
                  };
                  reader.readAsDataURL(file);
                  event.target.value = '';
              }
      
              function toggleFolderSelection(folder) {
                  if (selectedFolders.includes(folder)) {
                      selectedFolders = selectedFolders.filter(f => f !== folder);
                  } else {
                      selectedFolders.push(folder);
                  }
                  localStorage.setItem(LOCAL_STORAGE_KEYS.SELECTED_FOLDERS, JSON.stringify(selectedFolders));
                  updateZipStatusUI();
              }
      
              function selectAllFolders(selectAll) {
                  selectedFolders = selectAll ? [...zipFolders] : [];
                  localStorage.setItem(LOCAL_STORAGE_KEYS.SELECTED_FOLDERS, JSON.stringify(selectedFolders));
                  updateZipStatusUI();
              }
      
              function syncSelectedFolderFromChat(folderVal) {
                  if (folderVal === '__ALL__') {
                      selectedFolders = [...zipFolders];
                  } else {
                      selectedFolders = [folderVal];
                  }
                  localStorage.setItem(LOCAL_STORAGE_KEYS.SELECTED_FOLDERS, JSON.stringify(selectedFolders));
                  updateZipStatusUI();
              }
      
              function removeZipFile() {
                  if (!confirm('האם להסיר את קובץ ה-ZIP של התיעוד?')) return;
                  zipBase64 = null;
                  zipMeta = null;
                  zipFolders = [];
                  selectedFolders = [];
                  localStorage.removeItem(LOCAL_STORAGE_KEYS.ZIP_BASE64);
                  localStorage.removeItem(LOCAL_STORAGE_KEYS.ZIP_META);
                  localStorage.removeItem(LOCAL_STORAGE_KEYS.ZIP_FOLDERS);
                  localStorage.removeItem(LOCAL_STORAGE_KEYS.SELECTED_FOLDERS);
                  updateZipStatusUI();
              }
      
              // --- Generate Filtered ZIP Payload On-The-Fly ---
              async function getFilteredZipBase64() {
                  if (!zipBase64) return null;
                  if (zipFolders.length === 0 || selectedFolders.length === zipFolders.length) {
                      return zipBase64; // Send full ZIP
                  }
                  if (selectedFolders.length === 0) {
                      return null; // No folders selected
                  }
      
                  try {
                      const sourceZip = new JSZip();
                      await sourceZip.loadAsync(zipBase64, { base64: true });
      
                      const filteredZip = new JSZip();
                      const promises = [];
      
                      sourceZip.forEach((relativePath, file) => {
                          const topFolder = relativePath.split('/')[0];
                          if (selectedFolders.includes(topFolder) && !file.dir) {
                              const p = file.async('uint8array').then(content => {
                                  filteredZip.file(relativePath, content);
                              });
                              promises.push(p);
                          }
                      });
      
                      await Promise.all(promises);
                      return await filteredZip.generateAsync({ type: 'base64' });
                  } catch (err) {
                      console.error("Error generating filtered ZIP:", err);
                      return zipBase64;
                  }
              }
      
              // --- File Uploads & Drag-and-Drop ---
              function handleGenericFileUpload(event) {
                  const files = Array.from(event.target.files);
                  processFiles(files);
                  event.target.value = '';
              }
      
              function initDragAndDrop() {
                  const textarea = document.getElementById('userInput');
                  ['dragenter', 'dragover'].forEach(eventName => {
                      textarea.addEventListener(eventName, (e) => {
                          e.preventDefault();
                          textarea.style.borderColor = 'var(--accent-glow)';
                      }, false);
                  });
                  ['dragleave', 'drop'].forEach(eventName => {
                      textarea.addEventListener(eventName, (e) => {
                          e.preventDefault();
                          textarea.style.borderColor = 'var(--panel-border)';
                      }, false);
                  });
                  textarea.addEventListener('drop', (e) => {
                      const dt = e.dataTransfer;
                      const files = Array.from(dt.files);
                      if (files.length > 0) processFiles(files);
                  });
              }
      
              function processFiles(files) {
                  files.forEach(file => {
                      const reader = new FileReader();
                      reader.onload = function(e) {
                          const base64Data = e.target.result.split(',')[1];
                          let mimeType = file.type || getFallbackMime(file.name);
                          pendingAttachments.push({
                              name: file.name,
                              mimeType: mimeType,
                              data: base64Data,
                              size: (file.size / 1024).toFixed(1) + ' KB'
                          });
                          renderAttachmentsPreview();
                      };
                      reader.readAsDataURL(file);
                  });
              }
      
              function getFallbackMime(filename) {
                  const ext = filename.split('.').pop().toLowerCase();
                  const map = {
                      'ini': 'text/plain', 'txt': 'text/plain', 'wav': 'audio/wav',
                      'mp3': 'audio/mp3', 'pdf': 'application/pdf', 'csv': 'text/csv',
                      'json': 'application/json', 'zip': 'application/zip',
                      'js': 'text/javascript', 'php': 'text/x-php', 'png': 'image/png',
                      'jpg': 'image/jpeg', 'jpeg': 'image/jpeg'
                  };
                  return map[ext] || 'application/octet-stream';
              }
      
              function removeAttachment(index) {
                  pendingAttachments.splice(index, 1);
                  renderAttachmentsPreview();
              }
      
              function renderAttachmentsPreview() {
                  const previewEl = document.getElementById('attachmentsPreview');
                  previewEl.innerHTML = '';
                  pendingAttachments.forEach((att, idx) => {
                      const chip = document.createElement('div');
                      chip.className = 'att-chip';
                      chip.innerHTML = `
                          <i class="fa-solid fa-file"></i>
                          <span>${escapeHtml(att.name)} (${att.size})</span>
                          <span class="remove-att" onclick="removeAttachment(${idx})">&times;</span>
                      `;
                      previewEl.appendChild(chip);
                  });
              }
      
              // --- Zen & Themes ---
              function toggleZenMode() {
                  document.body.classList.toggle('zen-mode');
              }
      
              document.addEventListener('keydown', (e) => {
                  if (e.key === 'Escape' && document.body.classList.contains('zen-mode')) {
                      toggleZenMode();
                  }
              });
      
              function changeTheme(theme) {
                  document.body.setAttribute('data-theme', theme);
                  localStorage.setItem(LOCAL_STORAGE_KEYS.THEME, theme);
              }
      
              function changeFontSize(size) {
                  document.body.setAttribute('data-font', size);
                  localStorage.setItem(LOCAL_STORAGE_KEYS.FONT_SIZE, size);
              }
      
              function loadThemePreferences() {
                  const savedTheme = localStorage.getItem(LOCAL_STORAGE_KEYS.THEME) || 'cyberpunk';
                  const savedFont = localStorage.getItem(LOCAL_STORAGE_KEYS.FONT_SIZE) || 'medium';
                  changeTheme(savedTheme);
                  changeFontSize(savedFont);
                  document.getElementById('themeSelect').value = savedTheme;
                  document.getElementById('fontSelect').value = savedFont;
              }
      
              function handleChatScroll() {
                  const container = document.getElementById('chatContainer');
                  const jumpBtn = document.getElementById('jumpBottomBtn');
                  const distanceFromBottom = container.scrollHeight - container.scrollTop - container.clientHeight;
                  if (distanceFromBottom > 200) {
                      jumpBtn.classList.add('show');
                  } else {
                      jumpBtn.classList.remove('show');
                  }
              }
      
              function scrollToBottom(smooth = true) {
                  const container = document.getElementById('chatContainer');
                  container.scrollTo({ top: container.scrollHeight, behavior: smooth ? 'smooth' : 'auto' });
              }
      
              // --- Session Engine ---
              function loadSessions() {
                  try {
                      const saved = localStorage.getItem(LOCAL_STORAGE_KEYS.SESSIONS);
                      sessions = saved ? JSON.parse(saved) : [];
                  } catch (e) { sessions = []; }
      
                  if (sessions.length === 0) {
                      createNewSession();
                  } else {
                      currentSessionId = sessions[0].id;
                      renderSessionsList();
                      renderCurrentSessionChat();
                  }
              }
      
              function saveSessions() {
                  try {
                      localStorage.setItem(LOCAL_STORAGE_KEYS.SESSIONS, JSON.stringify(sessions));
                  } catch (e) { console.warn('LocalStorage limit reached.'); }
                  renderSessionsList();
              }
      
              function createNewSession() {
                  const newSession = {
                      id: Date.now().toString(),
                      title: 'שיחה חדשה',
                      timestamp: new Date().toLocaleTimeString('he-IL', {hour: '2-digit', minute:'2-digit'}),
                      history: []
                  };
                  sessions.unshift(newSession);
                  currentSessionId = newSession.id;
                  saveSessions();
                  renderCurrentSessionChat();
              }
      
              function switchSession(id) {
                  currentSessionId = id;
                  renderSessionsList();
                  renderCurrentSessionChat();
              }
      
              function deleteSession(id, event) {
                  event.stopPropagation();
                  sessions = sessions.filter(s => s.id !== id);
                  if (sessions.length === 0) {
                      createNewSession();
                  } else {
                      if (currentSessionId === id) currentSessionId = sessions[0].id;
                      saveSessions();
                      renderCurrentSessionChat();
                  }
              }
      
              function renderSessionsList() {
                  const listEl = document.getElementById('historyList');
                  listEl.innerHTML = '';
                  sessions.forEach(s => {
                      const item = document.createElement('div');
                      item.className = `history-item ${s.id === currentSessionId ? 'active' : ''}`;
                      item.onclick = () => switchSession(s.id);
                      item.innerHTML = `
                          <span class="title"><i class="fa-regular fa-message"></i> ${escapeHtml(s.title)}</span>
                          <i class="fa-solid fa-trash delete-btn" onclick="deleteSession('${s.id}', event)" title="מחק שיחה"></i>
                      `;
                      listEl.appendChild(item);
                  });
              }
      
              function getCurrentSession() {
                  return sessions.find(s => s.id === currentSessionId);
              }
      
              function renderCurrentSessionChat() {
                  const container = document.getElementById('chatContainer');
                  container.innerHTML = `
                      <div class="message model">
                          שלום! אני עוזר ה-AI הבכיר שלך לבניית מרכזיות, שלוחות ו-Webhooks ב'ימות המשיח'.<br>
                          העלה קבצים, שאל שאלות, או סנן תיקיות תיעוד ספציפיות לקבלת קובצי <code>ext.ini</code> מדויקים!
                      </div>`;
      
                  const session = getCurrentSession();
                  if (!session) return;
      
                  session.history.forEach(msg => {
                      if (msg.role === 'user') {
                          appendMessageUI('user', msg.text, msg.attachedNames || [], false);
                      } else if (msg.role === 'model') {
                          renderModelResponseUI(msg.text);
                      }
                  });
                  scrollToBottom(false);
              }
      
              // --- Keys & Storage ---
              function loadKeys() {
                  const saved = localStorage.getItem(LOCAL_STORAGE_KEYS.API_KEYS);
                  if (saved) {
                      apiKeys = JSON.parse(saved);
                      document.getElementById('apiKeysInput').value = apiKeys.join('\n');
                  }
              }
              async function saveKeys() {
                  const lines = document.getElementById('apiKeysInput').value.split('\n').map(k => k.trim()).filter(k => k.length > 0);
                  apiKeys = lines;
                  localStorage.setItem(LOCAL_STORAGE_KEYS.API_KEYS, JSON.stringify(apiKeys));
                  alert('מפתחות ה-API נשמרו בהצלחה!');
                  await fetchModels();
              }
      
              function saveYemotCredentials() {
                  localStorage.setItem(LOCAL_STORAGE_KEYS.YM_USER, document.getElementById('ymUsername').value);
                  localStorage.setItem(LOCAL_STORAGE_KEYS.YM_PASS, document.getElementById('ymPassword').value);
                  alert('פרטי החיבור נשמרו!');
              }
              function loadYemotCredentials() {
                  document.getElementById('ymUsername').value = localStorage.getItem(LOCAL_STORAGE_KEYS.YM_USER) || '';
                  document.getElementById('ymPassword').value = localStorage.getItem(LOCAL_STORAGE_KEYS.YM_PASS) || '';
              }
      
              // --- API Rotation & Models ---
              async function makeGeminiApiCall(fetchFunction) {
                  if (apiKeys.length === 0) {
                      alert('אנא הוסף לפחות מפתח API אחד בלשונית ההגדרות.');
                      switchTab('settingsTab');
                      throw new Error('No API keys configured');
                  }
                  let lastError = null;
                  for (let i = 0; i < apiKeys.length; i++) {
                      try {
                          return await fetchFunction(apiKeys[i]);
                      } catch (err) {
                          console.warn(`Key ${i + 1} failed, trying next...`, err);
                          lastError = err;
                      }
                  }
                  throw new Error(`כל המפתחות נכשלו: ${lastError?.message}`);
              }
      
              async function fetchModels() {
                  try {
                      const data = await makeGeminiApiCall(async (key) => {
                          const res = await fetch(`https://generativelanguage.googleapis.com/v1beta/models?key=${key}`);
                          return await res.json();
                      });
                      
                      let models = (data.models || [])
                          .filter(m => m.supportedGenerationMethods?.includes('generateContent'))
                          .map(m => m.name.replace('models/', ''));
      
                      if (!models.includes('gemini-3.6-flash')) {
                          models.unshift('gemini-3.6-flash');
                      }
      
                      const select = document.getElementById('modelSelect');
                      select.innerHTML = '';
      
                      models.forEach(m => {
                          const opt = document.createElement('option');
                          opt.value = m; opt.textContent = m;
                          select.appendChild(opt);
                      });
                      
                      select.value = 'gemini-3.6-flash';
      
                  } catch(e) { 
                      console.error(e);
                      const select = document.getElementById('modelSelect');
                      select.innerHTML = '<option value="gemini-3.6-flash">gemini-3.6-flash</option><option value="gemini-1.5-flash">gemini-1.5-flash</option>';
                      select.value = 'gemini-3.6-flash';
                  }
              }
      
              // --- Speech Input ---
              function initSpeechRecognition() {
                  if ('webkitSpeechRecognition' in window || 'SpeechRecognition' in window) {
                      const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
                      recognition = new SpeechRecognition();
                      recognition.lang = 'he-IL';
                      recognition.onresult = (event) => {
                          const transcript = event.results[0][0].transcript;
                          const inputEl = document.getElementById('userInput');
                          inputEl.value += (inputEl.value ? ' ' : '') + transcript;
                          toggleVoiceInput();
                      };
                      recognition.onerror = () => toggleVoiceInput();
                  } else {
                      document.getElementById('micBtn').style.display = 'none';
                  }
              }
      
              function toggleVoiceInput() {
                  if (!recognition) return;
                  const micBtn = document.getElementById('micBtn');
                  if (!isRecording) {
                      recognition.start();
                      isRecording = true;
                      micBtn.classList.add('recording');
                  } else {
                      recognition.stop();
                      isRecording = false;
                      micBtn.classList.remove('recording');
                  }
              }
      
              // --- Message Dispatcher with Dynamic ZIP Folder Filtering ---
              async function sendMessage() {
                  const inputEl = document.getElementById('userInput');
                  const text = inputEl.value.trim();
                  if (!text && pendingAttachments.length === 0) return;
      
                  const sendBtn = document.getElementById('sendBtn');
                  const deepAnalysis = document.getElementById('deepAnalysisToggle').checked;
                  const selectedModel = document.getElementById('modelSelect').value || 'gemini-3.6-flash';
      
                  const session = getCurrentSession();
                  if (session.history.length === 0) {
                      session.title = text ? (text.substring(0, 25) + '...') : (pendingAttachments[0]?.name || 'קובץ מצורף');
                  }
      
                  const currentTurnAttachments = [...pendingAttachments];
                  const attachedNames = currentTurnAttachments.map(a => a.name);
      
                  appendMessageUI('user', text || '(קבצים מצורפים)', attachedNames, false);
                  inputEl.value = '';
                  pendingAttachments = [];
                  renderAttachmentsPreview();
                  sendBtn.disabled = true;
                  scrollToBottom();
      
                  session.history.push({ role: 'user', text: text || '(קבצים מצורפים)', attachedNames: attachedNames });
                  saveSessions();
      
                  const loadingDiv = appendMessageUI('model', '<div class="loading-shimmer"><i class="fa-solid fa-spinner"></i> <span>אורז תיקיות נבחרות ומנתח תיעוד...</span></div>', [], true);
                  scrollToBottom();
      
                  try {
                      // Dynamically prepare filtered ZIP payload based on selected folders
                      const effectiveZipBase64 = await getFilteredZipBase64();
      
                      let contentsPayload = [];
      
                      session.history.forEach((msg, idx) => {
                          let parts = [];
                          
                          // Inject filtered ZIP documentation context on the first user turn
                          if (idx === 0 && msg.role === 'user' && effectiveZipBase64) {
                              parts.push({
                                  inline_data: {
                                      mime_type: "application/zip",
                                      data: effectiveZipBase64
                                  }
                              });
                          }
      
                          if (idx === session.history.length - 1 && msg.role === 'user' && currentTurnAttachments.length > 0) {
                              currentTurnAttachments.forEach(att => {
                                  parts.push({
                                      inline_data: {
                                      mime_type: att.mimeType,
                                          data: att.data
                                      }
                                  });
                              });
                          }
      
                          let promptText = msg.text;
                          if (idx === session.history.length - 1 && msg.role === 'user' && deepAnalysis) {
                              promptText = `[הוראת חובה לניתוח מעמיק של הפורמט]:
      לפני מתן התשובה והקוד הסופיים, עליך לבצע ניתוח מקיף ומעמיק של הדרישה, הפורמט המבוקש (כגון ext.ini, HTML, Webhook, תפריטי IVR), לוגיקת הרכיבים, בדיקת קצה ומבנה הנתונים.
      חובה לעטוף את *כל* הניתוח המעמיק בתוך תגיות <analysis> ו-</analysis>.
      רק לאחר התגית הסוגרת </analysis> תציג את התשובה והקוד המלאים והסופיים.
      
      בקשת המשתמש:
      ${msg.text}`;
                          }
      
                          parts.push({ text: promptText });
                          contentsPayload.push({ role: msg.role, parts: parts });
                      });
      
                      const responseData = await makeGeminiApiCall(async (key) => {
                          const res = await fetch(`https://generativelanguage.googleapis.com/v1beta/models/${selectedModel}:generateContent?key=${key}`, {
                              method: 'POST',
                              headers: { 'Content-Type': 'application/json' },
                              body: JSON.stringify({
                                  system_instruction: { parts: [{ text: SYSTEM_INSTRUCTION }] },
                                  contents: contentsPayload
                              })
                          });
                          if (!res.ok) {
                              const errBody = await res.text();
                              throw new Error(`HTTP ${res.status}: ${errBody}`);
                          }
                          return await res.json();
                      });
      
                      const replyText = responseData?.candidates?.[0]?.content?.parts?.[0]?.text;
                      if (!replyText) throw new Error('התקבלה תשובה ריקה מהמודל.');
      
                      session.history.push({ role: 'model', text: replyText });
                      saveSessions();
      
                      loadingDiv.remove();
                      renderModelResponseUI(replyText);
                      scrollToBottom();
      
                  } catch (err) {
                      loadingDiv.innerHTML = `<span style="color:#ef4444;"><i class="fa-solid fa-circle-exclamation"></i> שגיאה: ${err.message}</span>`;
                  } finally {
                      sendBtn.disabled = false;
                  }
              }
      
              // Render AI Model Response
              function renderModelResponseUI(text) {
                  const container = document.getElementById('chatContainer');
                  const msgDiv = document.createElement('div');
                  msgDiv.className = 'message model';
      
                  let analysisHTML = '';
                  let mainContent = text;
      
                  const analysisMatch = text.match(/<analysis>([\s\S]*?)<\/analysis>/);
                  if (analysisMatch) {
                      const analysisText = analysisMatch[1].trim();
                      mainContent = text.replace(/<analysis>[\s\S]*?<\/analysis>/, '').trim();
      
                      analysisHTML = `
                          <div class="analysis-box">
                              <div class="analysis-header" onclick="this.parentElement.classList.toggle('open')">
                                  <span><i class="fa-solid fa-brain"></i> ניתוח מעמיק של הפורמט והלוגיקה (לחץ לפתיחה)</span>
                                  <i class="fa-solid fa-chevron-down"></i>
                              </div>
                              <div class="analysis-content">${escapeHtml(analysisText)}</div>
                          </div>
                      `;
                  }
      
                  msgDiv.innerHTML = analysisHTML + marked.parse(mainContent);
                  container.appendChild(msgDiv);
      
                  // Enhance Code Blocks
                  msgDiv.querySelectorAll('pre code').forEach((codeBlock) => {
                      const rawCode = codeBlock.innerText;
                      const parentPre = codeBlock.parentNode;
      
                      const wrapper = document.createElement('div');
                      wrapper.className = 'code-container';
      
                      const header = document.createElement('div');
                      header.className = 'code-header';
                      header.innerHTML = `<span><i class="fa-solid fa-code"></i> קוד תצורה (ext.ini)</span>`;
      
                      const actions = document.createElement('div');
                      actions.className = 'code-actions';
      
                      const copyBtn = document.createElement('button');
                      copyBtn.className = 'code-btn';
                      copyBtn.innerHTML = '<i class="fa-solid fa-copy"></i> העתק';
                      copyBtn.onclick = () => { navigator.clipboard.writeText(rawCode); copyBtn.innerHTML = '<i class="fa-solid fa-check"></i> הועתק!'; setTimeout(() => copyBtn.innerHTML = '<i class="fa-solid fa-copy"></i> העתק', 2000); };
      
                      const dlBtn = document.createElement('button');
                      dlBtn.className = 'code-btn';
                      dlBtn.innerHTML = '<i class="fa-solid fa-download"></i> הורד ext.ini';
                      dlBtn.onclick = () => downloadCodeFile(rawCode, 'ext.ini');
      
                      const uploadBtn = document.createElement('button');
                      uploadBtn.className = 'code-btn';
                      uploadBtn.style.color = '#10b981';
                      uploadBtn.innerHTML = '<i class="fa-solid fa-cloud-arrow-up"></i> העלה למרכזיה';
                      uploadBtn.onclick = () => uploadDirectToYemot(rawCode);
      
                      const geminiTtsBtn = document.createElement('button');
                      geminiTtsBtn.className = 'code-btn';
                      geminiTtsBtn.style.color = '#38bdf8';
                      geminiTtsBtn.innerHTML = '<i class="fa-solid fa-wand-magic-sparkles"></i> שמע Gemini AI';
                      geminiTtsBtn.onclick = () => generateGeminiAudio(rawCode);
      
                      actions.appendChild(copyBtn);
                      actions.appendChild(dlBtn);
                      actions.appendChild(geminiTtsBtn);
                      actions.appendChild(uploadBtn);
      
                      header.appendChild(actions);
                      wrapper.appendChild(header);
      
                      parentPre.parentNode.insertBefore(wrapper, parentPre);
                      wrapper.appendChild(parentPre);
      
                      hljs.highlightElement(codeBlock);
                  });
              }
      
              // Audio TTS
              async function generateGeminiAudio(code) {
                  let textToRead = prompt('הכנס את הטקסט שברצונך שה-Gemini AI יכין ויקריא עבור המרכזייה:', 'ברוכים הבאים למערכת שלנו');
                  if (!textToRead) return;
      
                  const selectedModel = document.getElementById('modelSelect').value || 'gemini-3.6-flash';
      
                  try {
                      const responseData = await makeGeminiApiCall(async (key) => {
                          const res = await fetch(`https://generativelanguage.googleapis.com/v1beta/models/${selectedModel}:generateContent?key=${key}`, {
                              method: 'POST',
                              headers: { 'Content-Type': 'application/json' },
                              body: JSON.stringify({
                                  contents: [{
                                      parts: [{ text: `עבד והכשר את הניסוח הבא לקריאה קולית נקייה ומדויקת בלבד במרכזיה (ללא סימני פיסוק או הערות נוספות):\n"${textToRead}"` }]
                                  }]
                              })
                          });
                          return await res.json();
                      });
      
                      const speechText = responseData?.candidates?.[0]?.content?.parts?.[0]?.text || textToRead;
                      
                      window.speechSynthesis.cancel();
                      const utterance = new SpeechSynthesisUtterance(speechText);
                      utterance.lang = 'he-IL';
                      utterance.rate = 0.95;
                      window.speechSynthesis.speak(utterance);
      
                  } catch (err) {
                      window.speechSynthesis.cancel();
                      const utterance = new SpeechSynthesisUtterance(textToRead);
                      utterance.lang = 'he-IL';
                      window.speechSynthesis.speak(utterance);
                  }
              }
      
              // Direct Yemot Push
              async function uploadDirectToYemot(code) {
                  const username = localStorage.getItem(LOCAL_STORAGE_KEYS.YM_USER);
                  const password = localStorage.getItem(LOCAL_STORAGE_KEYS.YM_PASS);
      
                  if (!username || !password) {
                      alert('אנא הגדר פרטי התחברות לימות המשיח בלשונית ההגדרות.');
                      switchTab('settingsTab');
                      return;
                  }
      
                  const path = prompt('הכנס את נתיב השלוחה להעלאה (לדוגמה: 1/2 או 0 לראשית):', '1');
                  if (!path) return;
      
                  try {
                      const loginRes = await fetch(`https://www.call2all.co.il/ym/api/Login?username=${username}&password=${password}`);
                      const loginData = await loginRes.json();
      
                      if (loginData.responseStatus !== 'OK') {
                          throw new Error('התחברות למערכת ימות המשיח נכשלה.');
                      }
      
                      const token = loginData.token;
                      const formData = new FormData();
                      const blob = new Blob([code], { type: 'text/plain' });
                      formData.append('file', blob, 'ext.ini');
      
                      const uploadRes = await fetch(`https://www.call2all.co.il/ym/api/UploadFile?token=${token}&path=ivr2:${path}/ext.ini`, {
                          method: 'POST',
                          body: formData
                      });
                      const uploadData = await uploadRes.json();
      
                      if (uploadData.responseStatus === 'OK') {
                          alert(`הקוד הועלה בהצלחה לשלוחה ${path}!`);
                      } else {
                          alert(`שגיאה: ${uploadData.message || 'תקלה לא ידועה'}`);
                      }
      
                  } catch (err) {
                      alert(`שגיאה: ${err.message}`);
                  }
              }
      
              function downloadCodeFile(code, filename) {
                  const blob = new Blob([code], { type: 'text/plain;charset=utf-8' });
                  const link = document.createElement('a');
                  link.href = URL.createObjectURL(blob);
                  link.download = filename;
                  link.click();
              }
      
              function appendMessageUI(role, content, attachedNames = [], isHTML = false) {
                  const container = document.getElementById('chatContainer');
                  const msgDiv = document.createElement('div');
                  msgDiv.className = `message ${role}`;
                  
                  let attachmentsHTML = '';
                  if (attachedNames && attachedNames.length > 0) {
                      attachmentsHTML = '<div class="message-attachments">' + 
                          attachedNames.map(n => `<span class="msg-att-chip"><i class="fa-solid fa-paperclip"></i> ${escapeHtml(n)}</span>`).join('') + 
                          '</div>';
                  }
      
                  const bodyContent = isHTML ? content : `<div>${escapeHtml(content)}</div>`;
                  msgDiv.innerHTML = attachmentsHTML + bodyContent;
                  container.appendChild(msgDiv);
                  return msgDiv;
              }
      
              function handleKeyDown(e) {
                  if (e.key === 'Enter' && !e.shiftKey) {
                      e.preventDefault();
                      sendMessage();
                  }
              }
      
              function escapeHtml(text) {
                  return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
              }
          </script>
      </body>
      </html>
      

      כמו כן ניתן להוריד את הקובץ יש להוסיף את האות l בסוף הסיומת
      ‏‏מומחה לימות.htm

      ניתן להגיב כאן

      Gemini_Generated_Image_3rcgov3rcgov3rcg.png

      תגובה 1 תגובה אחרונה תגובה ציטוט 3
      • L lavitoren הטי"ל התייחס לנושא זה

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

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

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

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