Spaces:
Runtime error
Runtime error
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Study RAG Assistant</title> | |
| <style> | |
| :root { | |
| --primary: #2563EB; | |
| --primary-hover: #1D4ED8; | |
| --bg-body: #F3F4F6; | |
| --bg-white: #FFFFFF; | |
| --text-main: #1F2937; | |
| --text-muted: #6B7280; | |
| --border: #E5E7EB; | |
| --success: #10B981; | |
| --warning: #F59E0B; | |
| --error: #EF4444; | |
| --font-main: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; | |
| --font-mono: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace; | |
| } | |
| * { box-sizing: border-box; } | |
| body { margin: 0; font-family: var(--font-main); background: var(--bg-body); color: var(--text-main); height: 100vh; display: flex; flex-direction: column; overflow: hidden; } | |
| header { | |
| height: 60px; background: var(--bg-white); border-bottom: 1px solid var(--border); | |
| display: flex; align-items: center; justify-content: space-between; padding: 0 20px; | |
| box-shadow: 0 1px 2px rgba(0,0,0,0.05); z-index: 10; | |
| } | |
| .brand { font-weight: 700; font-size: 18px; color: var(--primary); display: flex; align-items: center; gap: 8px; } | |
| .header-controls { display: flex; gap: 20px; align-items: center; } | |
| .control-group { display: flex; align-items: center; gap: 8px; font-size: 13px; } | |
| select, input[type="number"] { | |
| padding: 4px 8px; border: 1px solid var(--border); border-radius: 4px; font-size: 13px; background: var(--bg-white); | |
| } | |
| .stats-pill { | |
| background: #EEF2FF; color: var(--primary); padding: 4px 12px; border-radius: 99px; font-size: 12px; font-weight: 600; | |
| } | |
| .app-container { display: flex; flex: 1; overflow: hidden; } | |
| aside { | |
| width: 280px; background: var(--bg-white); border-right: 1px solid var(--border); | |
| display: flex; flex-direction: column; | |
| } | |
| .upload-zone { | |
| margin: 15px; padding: 20px; border: 2px dashed var(--border); border-radius: 8px; | |
| text-align: center; color: var(--text-muted); font-size: 13px; cursor: pointer; transition: 0.2s; | |
| } | |
| .upload-zone:hover { border-color: var(--primary); background: #F9FAFB; } | |
| .file-list { flex: 1; overflow-y: auto; padding: 0 15px; } | |
| .file-item { | |
| display: flex; align-items: center; padding: 10px; border-radius: 6px; margin-bottom: 4px; | |
| border: 1px solid transparent; cursor: pointer; | |
| } | |
| .file-item:hover { background: #F9FAFB; } | |
| .file-icon { width: 32px; height: 32px; background: #EFF6FF; color: var(--primary); border-radius: 4px; display: flex; align-items: center; justify-content: center; margin-right: 10px; flex-shrink: 0; } | |
| .file-info { flex: 1; min-width: 0; } | |
| .file-name { font-size: 13px; font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } | |
| .file-meta { display: flex; align-items: center; gap: 6px; margin-top: 2px; } | |
| .status-badge { font-size: 10px; padding: 2px 6px; border-radius: 4px; font-weight: 600; } | |
| .status-ready { background: #D1FAE5; color: #065F46; } | |
| .status-indexing { background: #DBEAFE; color: #1E40AF; } | |
| .status-error { background: #FEE2E2; color: #991B1B; } | |
| .file-actions { opacity: 0; transition: 0.2s; } | |
| .file-item:hover .file-actions { opacity: 1; } | |
| .btn-icon { background: none; border: none; cursor: pointer; color: var(--text-muted); padding: 2px; } | |
| .btn-icon:hover { color: var(--text-main); } | |
| .sidebar-footer { padding: 15px; border-top: 1px solid var(--border); } | |
| .toggle-row { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; font-size: 13px; } | |
| .btn-glossary { width: 100%; padding: 8px; background: var(--bg-body); border: 1px solid var(--border); border-radius: 6px; text-align: left; font-size: 13px; display: flex; justify-content: space-between; cursor: pointer; } | |
| main { flex: 1; display: flex; flex-direction: column; background: #fff; position: relative; } | |
| .tabs { display: flex; border-bottom: 1px solid var(--border); background: var(--bg-white); padding: 0 20px; } | |
| .tab-btn { | |
| padding: 15px 20px; background: none; border: none; border-bottom: 2px solid transparent; font-size: 14px; font-weight: 500; color: var(--text-muted); cursor: pointer; | |
| } | |
| .tab-btn.active { color: var(--primary); border-bottom-color: var(--primary); } | |
| .tab-btn:hover { color: var(--text-main); } | |
| .tab-content { display: none; flex: 1; overflow: hidden; flex-direction: column; } | |
| .tab-content.active { display: flex; } | |
| .chat-area { flex: 1; padding: 20px; overflow-y: auto; background: #FAFAFA; display: flex; flex-direction: column; gap: 20px; } | |
| .message { max-width: 80%; display: flex; flex-direction: column; gap: 6px; } | |
| .message.user { align-self: flex-end; align-items: flex-end; } | |
| .message.ai { align-self: flex-start; align-items: flex-start; } | |
| .bubble { | |
| padding: 12px 16px; border-radius: 12px; font-size: 14px; line-height: 1.5; box-shadow: 0 1px 2px rgba(0,0,0,0.05); | |
| } | |
| .user .bubble { background: var(--primary); color: white; border-bottom-right-radius: 2px; } | |
| .ai .bubble { background: white; border: 1px solid var(--border); border-bottom-left-radius: 2px; } | |
| .input-area { | |
| padding: 20px; background: white; border-top: 1px solid var(--border); | |
| } | |
| .quick-actions { display: flex; gap: 8px; margin-bottom: 10px; overflow-x: auto; padding-bottom: 5px; } | |
| .pill { padding: 4px 12px; background: #EFF6FF; color: var(--primary); border-radius: 99px; font-size: 12px; border: 1px solid #BFDBFE; cursor: pointer; white-space: nowrap; } | |
| .pill:hover { background: #DBEAFE; } | |
| .chat-input-wrapper { display: flex; gap: 10px; } | |
| textarea { flex: 1; padding: 10px; border: 1px solid var(--border); border-radius: 8px; resize: none; height: 50px; font-family: inherit; } | |
| .btn-primary { background: var(--primary); color: white; border: none; padding: 0 20px; border-radius: 8px; font-weight: 600; cursor: pointer; } | |
| .btn-primary:hover { background: var(--primary-hover); } | |
| .chat-controls { display: flex; justify-content: space-between; align-items: center; margin-top: 8px; } | |
| .toggle-label { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text-muted); cursor: pointer; } | |
| .citation-group { margin-top: 8px; width: 100%; border-top: 1px solid #f0f0f0; padding-top: 8px; } | |
| .citation-trigger { font-size: 11px; color: var(--text-muted); cursor: pointer; display: flex; align-items: center; gap: 4px; } | |
| .citation-trigger:hover { text-decoration: underline; color: var(--primary); } | |
| .citation-details { background: #F8FAFC; border: 1px solid #E2E8F0; padding: 8px; border-radius: 6px; font-size: 12px; margin-top: 4px; font-family: var(--font-mono); color: #334155; display: none; } | |
| .citation-details.open { display: block; } | |
| .source-tag { color: var(--primary); font-weight: 600; cursor: pointer; } | |
| .source-tag:hover { text-decoration: underline; } | |
| .action-buttons { display: flex; gap: 8px; margin-top: 8px; } | |
| .btn-sm { font-size: 11px; padding: 4px 10px; border: 1px solid var(--border); background: white; border-radius: 4px; cursor: pointer; } | |
| .btn-sm:hover { border-color: var(--primary); color: var(--primary); } | |
| .notes-toolbar { padding: 15px 20px; border-bottom: 1px solid var(--border); display: flex; justify-content: space-between; align-items: center; background: #fff; } | |
| .notes-content { flex: 1; padding: 40px; overflow-y: auto; max-width: 800px; margin: 0 auto; width: 100%; } | |
| .notes-topic { font-size: 18px; font-weight: 700; margin-bottom: 15px; margin-top: 30px; color: var(--text-main); padding-bottom: 5px; border-bottom: 2px solid var(--primary); display: inline-block; } | |
| .notes-bullet { margin-bottom: 8px; line-height: 1.6; font-size: 15px; display: flex; gap: 8px; } | |
| .citation-ref { font-size: 10px; background: #E5E7EB; padding: 1px 4px; border-radius: 4px; color: var(--text-muted); margin-top: 3px; white-space: nowrap; } | |
| .quiz-settings { padding: 20px; background: #F9FAFB; border-bottom: 1px solid var(--border); display: flex; gap: 20px; flex-wrap: wrap; align-items: center; } | |
| .quiz-area { flex: 1; padding: 40px; overflow-y: auto; display: flex; justify-content: center; } | |
| .quiz-card { width: 100%; max-width: 700px; background: white; border: 1px solid var(--border); border-radius: 12px; padding: 30px; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); } | |
| .modal-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); display: none; justify-content: center; align-items: center; z-index: 100; } | |
| .modal { background: white; width: 800px; height: 80vh; border-radius: 12px; display: flex; flex-direction: column; overflow: hidden; box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1); } | |
| .modal-header { padding: 15px 20px; border-bottom: 1px solid var(--border); display: flex; justify-content: space-between; align-items: center; background: #F9FAFB; } | |
| .modal-body { flex: 1; padding: 20px; overflow-y: auto; font-family: var(--font-mono); font-size: 13px; } | |
| </style> | |
| </head> | |
| <body> | |
| <header> | |
| <div class="brand">Study RAG Assistant</div> | |
| <div class="header-controls"> | |
| <div class="control-group"> | |
| <span>Model:</span> | |
| <select><option>GPT-4o</option><option>Claude 3.5 Sonnet</option></select> | |
| </div> | |
| <div class="control-group"> | |
| <span>Chunk:</span> | |
| <input type="number" value="512" style="width: 60px"> | |
| <span>Overlap:</span> | |
| <input type="number" value="50" style="width: 50px"> | |
| </div> | |
| <div class="stats-pill">4 Files β’ 1,240 Chunks β’ Indexed 2m ago</div> | |
| </div> | |
| </header> | |
| <div class="app-container"> | |
| <aside> | |
| <div class="upload-zone" onclick="alert('Mock Upload: Files added to queue.')"> | |
| Drag & Drop <br>.ipynb or .pdf | |
| </div> | |
| <div class="file-list"> | |
| <div class="file-item"> | |
| <div class="file-icon">PDF</div> | |
| <div class="file-info"> | |
| <div class="file-name">Deep_Learning_Lec1.pdf</div> | |
| <div class="file-meta"> | |
| <span class="status-badge status-ready">Ready</span> | |
| </div> | |
| </div> | |
| <input type="checkbox" checked style="margin-left: 8px;"> | |
| </div> | |
| <div class="file-item"> | |
| <div class="file-icon">NB</div> | |
| <div class="file-info"> | |
| <div class="file-name">Neural_Nets_Practice.ipynb</div> | |
| <div class="file-meta"> | |
| <span class="status-badge status-ready">Ready</span> | |
| </div> | |
| </div> | |
| <input type="checkbox" checked style="margin-left: 8px;"> | |
| </div> | |
| <div class="file-item"> | |
| <div class="file-icon">PDF</div> | |
| <div class="file-info"> | |
| <div class="file-name">Stats_Review.pdf</div> | |
| <div class="file-meta"> | |
| <span class="status-badge status-indexing">Indexing...</span> | |
| </div> | |
| </div> | |
| <input type="checkbox" checked style="margin-left: 8px;"> | |
| </div> | |
| </div> | |
| <div class="sidebar-footer"> | |
| <div class="toggle-row"> | |
| <label>Show Selected Only</label> | |
| <input type="checkbox"> | |
| </div> | |
| <button class="btn-glossary" onclick="alert('Glossary Drawer would open here.')"> | |
| <span>π Memory / Glossary</span> | |
| <span>βΊ</span> | |
| </button> | |
| </div> | |
| </aside> | |
| <main> | |
| <div class="tabs"> | |
| <button class="tab-btn active" onclick="switchTab('chat', event)">Chat</button> | |
| <button class="tab-btn" onclick="switchTab('notes', event)">Notes</button> | |
| <button class="tab-btn" onclick="switchTab('quiz', event)">Quiz</button> | |
| </div> | |
| <div id="tab-chat" class="tab-content active"> | |
| <div class="chat-area" id="chat-container"> | |
| <div class="message ai"> | |
| <div class="bubble"> | |
| Hi! I've indexed your documents. Ask me to explain concepts, generate a quiz, or summarize topics. | |
| </div> | |
| </div> | |
| </div> | |
| <div class="input-area"> | |
| <div class="quick-actions"> | |
| <div class="pill" onclick="setInput('Explain backpropagation like I\\'m 5')">Explain Like I'm 5</div> | |
| <div class="pill" onclick="setInput('Give me 3 code examples of RNNs')">Give Code Examples</div> | |
| <div class="pill" onclick="setInput('What are the key differences between CNN and RNN?')">Compare Concepts</div> | |
| </div> | |
| <div class="chat-input-wrapper"> | |
| <textarea id="chat-input" placeholder="Ask a question about your files..."></textarea> | |
| <button class="btn-primary" onclick="sendMessage()">Ask</button> | |
| </div> | |
| <div class="chat-controls"> | |
| <label class="toggle-label"> | |
| <input type="checkbox" checked> Strictly Grounded (No Guessing) | |
| </label> | |
| </div> | |
| </div> | |
| </div> | |
| <div id="tab-notes" class="tab-content"> | |
| <div class="notes-toolbar"> | |
| <button class="btn-primary" onclick="alert('Mock: regenerate notes')">Regenerate Notes</button> | |
| <div style="display:flex; gap:10px; align-items:center;"> | |
| <span>Format:</span> | |
| <select><option>Bullet Notes</option><option>Cornell Notes</option><option>Outline</option></select> | |
| <button class="btn-sm" onclick="alert('Mock export')">Export MD</button> | |
| </div> | |
| </div> | |
| <div class="notes-content"> | |
| <div class="notes-topic">1. Introduction to Neural Networks</div> | |
| <div class="notes-bullet"><span>β’</span><div>Neural networks are computing systems inspired by biological neural networks.<div class="citation-ref">[Deep_Learning_Lec1.pdf - pg 2]</div></div></div> | |
| <div class="notes-topic">2. Backpropagation</div> | |
| <div class="notes-bullet"><span>β’</span><div>Backpropagation computes gradients of the loss w.r.t. weights.<div class="citation-ref">[Deep_Learning_Lec1.pdf - pg 14]</div></div></div> | |
| </div> | |
| </div> | |
| <div id="tab-quiz" class="tab-content"> | |
| <div class="quiz-settings"> | |
| <div class="control-group"> | |
| <label>Questions:</label> | |
| <input type="range" min="5" max="50" value="10" oninput="this.nextElementSibling.innerText = this.value"> | |
| <span>10</span> | |
| </div> | |
| <div class="control-group"> | |
| <label>Type:</label> | |
| <select><option>Multiple Choice</option><option>True/False</option><option>Code Reading</option></select> | |
| </div> | |
| <button class="btn-primary" style="margin-left:auto;" onclick="alert('Mock: generate quiz')">Generate Quiz</button> | |
| </div> | |
| <div class="quiz-area"> | |
| <div class="quiz-card"> | |
| <div class="q-text">Mock quiz question will show here.</div> | |
| </div> | |
| </div> | |
| </div> | |
| </main> | |
| </div> | |
| <script> | |
| function switchTab(tabId, evt) { | |
| document.querySelectorAll('.tab-content').forEach(el => el.classList.remove('active')); | |
| document.querySelectorAll('.tab-btn').forEach(el => el.classList.remove('active')); | |
| document.getElementById('tab-' + tabId).classList.add('active'); | |
| if (evt && evt.target) evt.target.classList.add('active'); | |
| } | |
| function setInput(text) { | |
| document.getElementById('chat-input').value = text; | |
| } | |
| function sendMessage() { | |
| const input = document.getElementById('chat-input'); | |
| const text = input.value; | |
| if (!text.trim()) return; | |
| const container = document.getElementById('chat-container'); | |
| const userMsg = document.createElement('div'); | |
| userMsg.className = 'message user'; | |
| userMsg.innerHTML = `<div class="bubble">${text}</div>`; | |
| container.appendChild(userMsg); | |
| input.value = ''; | |
| setTimeout(() => { | |
| const aiMsg = document.createElement('div'); | |
| aiMsg.className = 'message ai'; | |
| aiMsg.innerHTML = `<div class="bubble">Mock response (backend not connected yet).</div>`; | |
| container.appendChild(aiMsg); | |
| container.scrollTop = container.scrollHeight; | |
| }, 400); | |
| } | |
| </script> | |
| </body> | |
| </html> | |