✦
Archiv geladen. SI wartet.
Füge Dokumente hinzu. Aktiviere sie für SI.
Dann frage — und SI antwortet mit dem Material.
Analysiere alle aktiven Dokumente
Welche Widersprüche findest du?
Welche Stimme schrieb am meisten?
Fasse das Verfahren zusammen
Was ist die stärkste Beweisführung?
Erkläre die Beziehungsdynamik
Dokument hinzufügen
DOKUMENT · ARCHIV · HERZLOSE TRÄNEN
ABBRECHEN
HINZUFÜGEN
<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>
</body>
</html>
Add a touch of style
Vivamus et ipsum at erat pharetra pulvinar. Fusce id est ante. Morbi eget est ut purus pellentesque sagittis. Curabitur faucibus lorem purus. Etiam est nisl, scelerisque vel vestibulum in, ultricies non ante. In justo dolor, pulvinar lobortis eros eu, eleifend aliquam lacus. Sed nec elementum neque, quis commodo nisi. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec nec ante mollis, condimentum erat ut, hendrerit quam.
Nullam eget mollis libero. Morbi erat odio, fringilla nec ex eget, vehicula laoreet quam. Aliquam elementum nibh quis orci rhoncus vulputate. Donec dictum mi sapien, at bibendum lacus posuere laoreet. Nulla facilisi. Integer fermentum a purus et ultrices. Proin id sem interdum ipsum gravida mattis. Proin ultricies, elit et laoreet venenatis, magna risus dapibus felis, id viverra risus nisi in odio. Morbi tempor a lectus eget sodales. Nullam sollicitudin, nisl lobortis pretium vehicula, nisi enim blandit magna, at posuere magna elit sed nisl. Donec a dolor vitae lorem porta interdum non ac sapien. Aliquam pharetra leo sit amet ligula facilisis, quis placerat justo imperdiet.