SI-Interface · Herzlose Tränen

HERZLOSE TRÄNEN · SI-INTERFACE
SI
Synthetische Intelligenz · Archiv-Analyse
BEREIT
Archiv geladen. SI wartet.
Füge Dokumente hinzu. Aktiviere sie für SI.
Dann frage — und SI antwortet mit dem Material.
BEREICH · GESAMT
<script> // ════════════════════════════════════════════════════════════════════ // STATE MANAGEMENT // ════════════════════════════════════════════════════════════════════ const state = { documents: [], messages: [], currentContext: 'alle', activeDocuments: new Set(), ftpConnected: false, ftpPath: '/', selectedFiles: new Set(), tokenUsage: 0 }; // Load from localStorage function loadState() { const saved = localStorage.getItem('si-state'); if (saved) { const parsed = JSON.parse(saved); state.documents = parsed.documents || []; state.messages = parsed.messages || []; state.currentContext = parsed.currentContext || 'alle'; state.activeDocuments = new Set(parsed.activeDocuments || []); } updateUI(); } function saveState() { localStorage.setItem('si-state', JSON.stringify({ documents: state.documents, messages: state.messages, currentContext: state.currentContext, activeDocuments: Array.from(state.activeDocuments) })); } // ════════════════════════════════════════════════════════════════════ // SIDEBAR & TOGGLE // ════════════════════════════════════════════════════════════════════ function toggleSidebar() { const sidebar = document.getElementById('sidebar'); sidebar.classList.toggle('collapsed'); } function toggleFtpPanel() { const ftpSection = document.getElementById('ftpSection'); ftpSection.classList.toggle('collapsed'); } // ════════════════════════════════════════════════════════════════════ // CONTEXT PILLS // ════════════════════════════════════════════════════════════════════ document.addEventListener('DOMContentLoaded', () => { const ctxPills = document.querySelectorAll('.pill'); ctxPills.forEach(pill => { pill.addEventListener('click', () => { ctxPills.forEach(p => p.classList.remove('active')); pill.classList.add('active'); state.currentContext = pill.dataset.ctx; updateUI(); }); }); }); // ════════════════════════════════════════════════════════════════════ // DOCUMENTS // ════════════════════════════════════════════════════════════════════ function openModal() { document.getElementById('modalOverlay').classList.remove('hidden'); } function closeModal() { document.getElementById('modalOverlay').classList.add('hidden'); resetModal(); } function closeModalOnBg(event) { if (event.target === document.getElementById('modalOverlay')) { closeModal(); } } function switchTab(tabName) { document.querySelectorAll('.tab-panel').forEach(p => p.classList.remove('active')); document.querySelectorAll('.modal-tab').forEach(t => t.classList.remove('active')); document.getElementById(`tab-${tabName}`).classList.add('active'); event.target.classList.add('active'); } function updateCharCount() { const content = document.getElementById('docContent').value; document.getElementById('charCount').textContent = `${content.length} Zeichen`; validateForm(); } function validateForm() { const activeTab = document.querySelector('.tab-panel.active'); const btnAdd = document.getElementById('btnAdd'); if (activeTab === document.getElementById('tab-text')) { const name = document.getElementById('docName').value.trim(); const content = document.getElementById('docContent').value.trim(); btnAdd.disabled = !name || !content; } else { const name = document.getElementById('docNameFile').value.trim(); btnAdd.disabled = !name || state.selectedFiles.size === 0; } } function handleDragOver(event) { event.preventDefault(); document.getElementById('dropZone').classList.add('drag-over'); } function handleDragLeave(event) { document.getElementById('dropZone').classList.remove('drag-over'); } function handleDrop(event) { event.preventDefault(); document.getElementById('dropZone').classList.remove('drag-over'); const files = event.dataTransfer.files; if (files.length > 0) { handleFileSelect({ target: { files } }); } } function handleFileSelect(event) { const files = event.target.files; if (files.length === 0) return; const file = files[0]; if (file.size > 500 * 1024) { document.getElementById('fileStatus').textContent = '❌ Datei zu groß (Max. 500 KB)'; document.getElementById('fileStatus').style.display = 'block'; return; } const reader = new FileReader(); reader.onload = (e) => { state.selectedFiles.add({ name: file.name, content: e.target.result, type: file.type }); document.getElementById('fileStatus').textContent = `✓ ${file.name} geladen (${(file.size / 1024).toFixed(1)} KB)`; document.getElementById('fileStatus').style.display = 'block'; validateForm(); }; reader.readAsText(file); } function addDocument() { const activeTab = document.querySelector('.tab-panel.active'); if (activeTab === document.getElementById('tab-text')) { const name = document.getElementById('docName').value.trim(); const content = document.getElementById('docContent').value.trim(); const element = document.getElementById('docElement').value; if (name && content) { const doc = { id: Date.now().toString(), name, content, element, dateAdded: new Date().toLocaleDateString('de-DE') }; state.documents.push(doc); state.activeDocuments.add(doc.id); } } else { const name = document.getElementById('docNameFile').value.trim(); const element = document.getElementById('docElementFile').value; state.selectedFiles.forEach(file => { const doc = { id: Date.now().toString() + Math.random(), name: name || file.name, content: file.content, element, dateAdded: new Date().toLocaleDateString('de-DE') }; state.documents.push(doc); state.activeDocuments.add(doc.id); }); state.selectedFiles.clear(); } saveState(); updateUI(); closeModal(); } function resetModal() { document.getElementById('docName').value = ''; document.getElementById('docContent').value = ''; document.getElementById('docElement').value = 'alle'; document.getElementById('docNameFile').value = ''; document.getElementById('docElementFile').value = 'alle'; document.getElementById('fileInput').value = ''; document.getElementById('fileStatus').style.display = 'none'; document.getElementById('charCount').textContent = '0 Zeichen'; state.selectedFiles.clear(); validateForm(); } function toggleDocumentActive(docId) { if (state.activeDocuments.has(docId)) { state.activeDocuments.delete(docId); } else { state.activeDocuments.add(docId); } saveState(); updateUI(); } function removeDocument(docId) { state.documents = state.documents.filter(d => d.id !== docId); state.activeDocuments.delete(docId); saveState(); updateUI(); } // ════════════════════════════════════════════════════════════════════ // UI UPDATES // ════════════════════════════════════════════════════════════════════ function updateUI() { updateDocList(); updateActiveCount(); updateTokenBar(); updateInputMeta(); } function updateDocList() { const docList = document.getElementById('docList'); docList.innerHTML = ''; const filteredDocs = state.currentContext === 'alle' ? state.documents : state.documents.filter(d => d.element === state.currentContext); filteredDocs.forEach(doc => { const item = document.createElement('div'); item.className = 'doc-item'; if (state.activeDocuments.has(doc.id)) item.classList.add('active'); item.innerHTML = `
${doc.name}
`; item.addEventListener('click', (e) => { if (!e.target.classList.contains('doc-remove')) { toggleDocumentActive(doc.id); } }); docList.appendChild(item); }); } function updateActiveCount() { const count = state.activeDocuments.size; document.getElementById('activeCount').textContent = count; document.getElementById('activeDocsHeader').textContent = `${count} Dokument${count !== 1 ? 'e' : ''} aktiv`; document.getElementById('docCountBadge').textContent = `${count} aktiv`; } function updateTokenBar() { let totalChars = 0; state.activeDocuments.forEach(docId => { const doc = state.documents.find(d => d.id === docId); if (doc) totalChars += doc.content.length; }); state.tokenUsage = totalChars; const maxTokens = 80000; const percentage = Math.min((totalChars / maxTokens) * 100, 100); document.getElementById('tokenFill').style.width = percentage + '%'; document.getElementById('tokenInfo').textContent = `${totalChars.toLocaleString('de-DE')} / ~${maxTokens.toLocaleString('de-DE')} Zeichen`; } function updateInputMeta() { const contextLabel = document.querySelector('.pill.active').textContent; document.getElementById('activeCtxLabel').textContent = contextLabel; } // ════════════════════════════════════════════════════════════════════ // CHAT & MESSAGES // ════════════════════════════════════════════════════════════════════ function handleKeydown(event) { if (event.key === 'Enter' && !event.shiftKey) { event.preventDefault(); sendMessage(); } } function autoResize(textarea) { textarea.style.height = 'auto'; textarea.style.height = Math.min(textarea.scrollHeight, 120) + 'px'; document.getElementById('sendBtn').disabled = !textarea.value.trim(); } function sendMessage() { const input = document.getElementById('inputField'); const text = input.value.trim(); if (!text) return; // Add user message state.messages.push({ id: Date.now().toString(), role: 'user', content: text, timestamp: new Date().toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit' }) }); // Remove empty state document.getElementById('emptyState').style.display = 'none'; // Render message renderMessages(); input.value = ''; input.style.height = 'auto'; document.getElementById('sendBtn').disabled = true; // Simulate SI response setTimeout(() => { const activeDocsText = Array.from(state.activeDocuments) .map(id => { const doc = state.documents.find(d => d.id === id); return doc ? `\n\n**${doc.name}** (${doc.element})\n${doc.content.substring(0, 200)}…` : ''; }) .join(''); const response = `SI-Analyse:\n\nDeine Frage: "${text}"\n\nAktive Dokumente (${state.activeDocuments.size}):\n${activeDocsText || 'Keine Dokumente aktiviert'}\n\nZeichen gesamt: ${state.tokenUsage}`; state.messages.push({ id: Date.now().toString(), role: 'assistant', content: response, timestamp: new Date().toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit' }) }); renderMessages(); saveState(); }, 500); } function renderMessages() { const messagesContainer = document.getElementById('messages'); messagesContainer.innerHTML = ''; state.messages.forEach(msg => { const div = document.createElement('div'); div.className = `message ${msg.role}`; div.innerHTML = `
${msg.content.replace(/\n\n/g, '

').replace(/\*\*(.*?)\*\*/g, '$1')}
`; messagesContainer.appendChild(div); }); // Auto-scroll to bottom const bottom = document.getElementById('bottom'); bottom.scrollIntoView({ behavior: 'smooth' }); } function sendSuggestion(btn) { document.getElementById('inputField').value = btn.textContent; autoResize(document.getElementById('inputField')); sendMessage(); } function clearChat() { if (confirm('Gespräch wirklich löschen?')) { state.messages = []; saveState(); document.getElementById('emptyState').style.display = 'flex'; document.getElementById('messages').innerHTML = ''; } } // ════════════════════════════════════════════════════════════════════ // FTP (Placeholder) // ════════════════════════════════════════════════════════════════════ function ftpConnect() { const proxy = document.getElementById('ftpProxy').value; const token = document.getElementById('ftpToken').value; if (!proxy || !token) { showFtpError('Proxy-URL und Token erforderlich'); return; } state.ftpConnected = true; document.getElementById('ftpStatusDot').classList.add('connected'); document.getElementById('ftpConnectForm').classList.add('hidden'); document.getElementById('ftpBrowser').classList.add('connected'); document.getElementById('ftpError').classList.remove('show'); // Simulate file list ftpListFiles(); } function ftpDisconnect() { state.ftpConnected = false; document.getElementById('ftpStatusDot').classList.remove('connected'); document.getElementById('ftpConnectForm').classList.remove('hidden'); document.getElementById('ftpBrowser').classList.remove('connected'); state.ftpPath = '/'; } function ftpListFiles() { const fileList = document.getElementById('ftpFileList'); fileList.innerHTML = `
📁 api/
📁 html/
📄 si_ftp_proxy.php
📄 index.html
`; } function ftpNavigateUp() { if (state.ftpPath !== '/') { state.ftpPath = '/'; ftpListFiles(); document.getElementById('ftpPathText').textContent = '/'; } } function ftpImportReadable() { alert('Dateien würden hier importiert (Placeholder)'); } function showFtpError(message) { const errorDiv = document.getElementById('ftpError'); errorDiv.textContent = message; errorDiv.classList.add('show'); } // ════════════════════════════════════════════════════════════════════ // INIT // ════════════════════════════════════════════════════════════════════ loadState(); </script>