From 1cf7bfbf769ffd41550554c3ad389e41e963cfba Mon Sep 17 00:00:00 2001 From: marwin Date: Sat, 3 May 2025 19:44:18 +0100 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat:=20erweitere=20die=20Mindmap-A?= =?UTF-8?q?PI=20zur=20dynamischen=20Erstellung=20und=20Anzeige=20wissensch?= =?UTF-8?q?aftlicher=20Knoten=20sowie=20zur=20Verbesserung=20der=20Fehlerb?= =?UTF-8?q?ehandlung.=20F=C3=BCge=20neues=20Skript=20zur=20Aktualisierung?= =?UTF-8?q?=20der=20Mindmap=20hinzu.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __pycache__/app.cpython-313.pyc | Bin 81794 -> 82379 bytes app.py | 84 ++++++++++++++++++-------- database/systades.db | Bin 147456 -> 147456 bytes db_operations.py | 103 ++++++++++++++++++++++++++++++++ static/js/update_mindmap.js | 93 ++++++++++++++++++++++++++++ templates/mindmap.html | 19 ++---- 6 files changed, 260 insertions(+), 39 deletions(-) create mode 100644 db_operations.py create mode 100644 static/js/update_mindmap.js diff --git a/__pycache__/app.cpython-313.pyc b/__pycache__/app.cpython-313.pyc index b1146c1ffd754653abfcb9d73beb8d4811288694..1615f6ab3dcddf8ea907455760537957176257c5 100644 GIT binary patch delta 5498 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 diff --git a/app.py b/app.py index 414eb22..cb16aca 100644 --- a/app.py +++ b/app.py @@ -1142,32 +1142,64 @@ def delete_note(note_id): # API routes for mindmap and thoughts @app.route('/api/mindmap') def get_mindmap(): - """API-Endpunkt zur Bereitstellung der Mindmap-Daten in hierarchischer Form.""" - # Root-Knoten: Knoten ohne Eltern - root_nodes = MindMapNode.query.\ - outerjoin(node_relationship, MindMapNode.id == node_relationship.c.child_id).\ - filter(node_relationship.c.parent_id == None).all() - - result = [] - for node in root_nodes: - node_data = build_node_tree(node) - result.append(node_data) - return jsonify({"nodes": result}) - -def build_node_tree(node): - """Erzeugt eine hierarchische Darstellung eines Knotens inkl. seiner Kindknoten.""" - thought_count = len(node.thoughts) - node_data = { - "id": node.id, - "name": node.name, - "description": node.description or "", - "thought_count": thought_count, - "children": [] - } - for child in node.children: - child_data = build_node_tree(child) - node_data["children"].append(child_data) - return node_data + """Gibt die Mindmap-Struktur zurück""" + try: + # Hauptknoten abrufen (Root-Knoten) + wissen_node = MindMapNode.query.filter_by(name="Wissen").first() + if not wissen_node: + # Wissen-Knoten erstellen, falls nicht vorhanden + wissen_node = MindMapNode( + name="Wissen", + description="Zentrale Wissensbasis", + color_code="#4299E1", + is_public=True + ) + db.session.add(wissen_node) + db.session.commit() + + # Alle anderen aktiven Knoten holen + nodes = MindMapNode.query.filter(MindMapNode.is_public == True).all() + + # Ergebnisdaten vorbereiten + nodes_data = [] + edges_data = [] + + # Knoten hinzufügen + for node in nodes: + nodes_data.append({ + 'id': node.id, + 'name': node.name, + 'description': node.description or '', + 'color_code': node.color_code or '#9F7AEA' + }) + + # Wenn es nicht der Wissen-Knoten ist, Verbindung zum Wissen-Knoten hinzufügen + if node.id != wissen_node.id: + edges_data.append({ + 'source': wissen_node.id, + 'target': node.id + }) + + # Beziehungen zwischen Knoten abfragen und hinzufügen + relationships = db.session.query(node_relationship).all() + for rel in relationships: + if rel.parent_id != wissen_node.id: # Doppelte Kanten vermeiden + edges_data.append({ + 'source': rel.parent_id, + 'target': rel.child_id + }) + + return jsonify({ + 'nodes': nodes_data, + 'edges': edges_data + }) + + except Exception as e: + print(f"Fehler beim Abrufen der Mindmap: {str(e)}") + return jsonify({ + 'success': False, + 'error': 'Mindmap konnte nicht geladen werden' + }), 500 @app.route('/api/nodes//thoughts') def get_node_thoughts(node_id): diff --git a/database/systades.db b/database/systades.db index 13acef970c6beb61b4b58523001fa03ac1f38e12..1d9c4d5eb3dc19a530cc8b65812931220868c400 100644 GIT binary patch delta 950 zcmY+C-%b-j6vnqIAZd{VVxn11CN{)CpeYEU#4EuTiGjqR5WT@!db&N?-5D}}AmBy2 z`T`nXp_krpW$$?bpTQ^b%v4Ibn=|L^?C<-&)9p@nyOZC;!orUyTZM(o&%L9WiPC&9 z-JgE;;9~0U)LQ9RY5p>wEp_r>q8OC(tuUMng2F3plssvlYfL_!0miHeiup?+GlWH7 zYdmhV3=I{64TgD&`nXMH9b*u538#rld8J<4Tw5p3<5b$_lD1+je|WDLyv+B*r$qa6Y4=g5aSf|StlJT! zAtR84@*6eJhii>=J&hiVA!$lem!b=hh}%4+(@1#EE^nBUku>A^+}&dEBLCtbIzeF% ztfC}ttOBv)Y-*yuz>^fkRZjt>ax*|s6x=XT2eogMO^j9EwPBoYoAyAR63w|bKnvwe zb+_BlMn#OBTiKQyjn%cPi#Adm#Y{eXrx-lXVX*4&EO!zI`}>**Ze3jO>L^!sV~1a- yT~4~_Lq}1kyklGiA1Zg2(q8(Gw$ZSzN3?;J^6DmexI$d6G4ri2fA?kK&7Xh8fk`v~ delta 40 wcmZo@;B08%oFL7pIZ?)$QFCL$l6W>o{v8bbJ2nd{tmALqk-vRMKBLD400LhP?EnA( diff --git a/db_operations.py b/db_operations.py new file mode 100644 index 0000000..3534a72 --- /dev/null +++ b/db_operations.py @@ -0,0 +1,103 @@ +import sqlite3 +import os +import random + +# Verbindung zur Datenbank herstellen +db_path = os.path.join(os.getcwd(), 'database', 'systades.db') +conn = sqlite3.connect(db_path) +cursor = conn.cursor() + +# Schema der mind_map_node Tabelle anzeigen +cursor.execute("PRAGMA table_info(mind_map_node)") +columns = cursor.fetchall() +print("Tabellenschema mind_map_node:") +for column in columns: + print(f"{column[1]} ({column[2]})") + +# Existierende Knoten anzeigen +cursor.execute("SELECT id, name, description, color_code FROM mind_map_node LIMIT 5") +existing_nodes = cursor.fetchall() +print("\nBestehende Knoten:") +for node in existing_nodes: + print(f"ID: {node[0]}, Name: {node[1]}, Beschreibung: {node[2]}") + +# Mögliche Kategorien abrufen (für die Verknüpfung) +cursor.execute("SELECT id, name FROM category") +categories = cursor.fetchall() +print("\nVerfügbare Kategorien:") +for category in categories: + print(f"ID: {category[0]}, Name: {category[1]}") + +# Wissenschaftliche Themengebiete für neue Knoten +scientific_nodes = [ + { + "name": "Quantenphysik", + "description": "Die Quantenphysik befasst sich mit dem Verhalten von Materie und Energie auf atomarer und subatomarer Ebene.", + "color_code": "#4B0082", # Indigo + "icon": "fa-atom" + }, + { + "name": "Neurowissenschaften", + "description": "Interdisziplinäre Wissenschaft, die sich mit der Struktur und Funktion des Nervensystems und des Gehirns beschäftigt.", + "color_code": "#FF4500", # Orange-Rot + "icon": "fa-brain" + }, + { + "name": "Künstliche Intelligenz", + "description": "Forschungsgebiet der Informatik, das sich mit der Automatisierung intelligenten Verhaltens befasst.", + "color_code": "#008080", # Teal + "icon": "fa-robot" + }, + { + "name": "Klimaforschung", + "description": "Wissenschaftliche Untersuchung des Klimas, seiner Variationen und Veränderungen auf allen zeitlichen und räumlichen Skalen.", + "color_code": "#2E8B57", # Seegrün + "icon": "fa-cloud-sun" + }, + { + "name": "Genetik", + "description": "Teilgebiet der Biologie, das sich mit Vererbung sowie der Funktion und Wirkung von Genen beschäftigt.", + "color_code": "#800080", # Lila + "icon": "fa-dna" + }, + { + "name": "Astrophysik", + "description": "Zweig der Astronomie, der sich mit den physikalischen Eigenschaften des Universums befasst.", + "color_code": "#191970", # Mitternachtsblau + "icon": "fa-star" + } +] + +# Neue Knoten hinzufügen +print("\nFüge neue wissenschaftliche Knoten hinzu...") +for node in scientific_nodes: + # Prüfen, ob der Knoten bereits existiert + cursor.execute("SELECT id FROM mind_map_node WHERE name = ?", (node["name"],)) + existing = cursor.fetchone() + if existing: + print(f"Knoten '{node['name']}' existiert bereits mit ID {existing[0]}") + continue + + # Zufällige Kategorie wählen, wenn vorhanden + category_id = None + if categories: + category_id = random.choice(categories)[0] + + # Neuen Knoten einfügen + cursor.execute(""" + INSERT INTO mind_map_node (name, description, color_code, icon, is_public, category_id) + VALUES (?, ?, ?, ?, ?, ?) + """, ( + node["name"], + node["description"], + node["color_code"], + node["icon"], + True, + category_id + )) + print(f"Knoten '{node['name']}' hinzugefügt") + +# Änderungen übernehmen und Verbindung schließen +conn.commit() +print("\nDatenbank erfolgreich aktualisiert!") +conn.close() \ No newline at end of file diff --git a/static/js/update_mindmap.js b/static/js/update_mindmap.js new file mode 100644 index 0000000..be81ba7 --- /dev/null +++ b/static/js/update_mindmap.js @@ -0,0 +1,93 @@ +/** + * Update Mindmap + * Dieses Skript fügt die neuen wissenschaftlichen Knoten zur Mindmap hinzu + * und stellt sicher, dass sie korrekt angezeigt werden. + */ + +// Warte bis DOM geladen ist +document.addEventListener('DOMContentLoaded', function() { + // Prüfe, ob wir auf der Mindmap-Seite sind + const cyContainer = document.getElementById('cy'); + + if (!cyContainer) { + console.log('Kein Mindmap-Container gefunden, überspringe Initialisierung.'); + return; + } + + // Auf das Laden der Mindmap warten + document.addEventListener('mindmap-loaded', function() { + console.log('Mindmap geladen, füge wissenschaftliche Knoten hinzu...'); + enhanceMindmap(); + }); +}); + +/** + * Erweitert die Mindmap mit den neu hinzugefügten wissenschaftlichen Knoten + */ +function enhanceMindmap() { + // Auf die bestehende Cytoscape-Instanz zugreifen + const cy = window.cy; + + if (!cy) { + console.error('Keine Cytoscape-Instanz gefunden.'); + return; + } + + // Aktualisiere das Layout mit zusätzlichem Platz für die neuen Knoten + cy.layout({ + name: 'cose', + animate: true, + animationDuration: 800, + nodeDimensionsIncludeLabels: true, + padding: 100, + spacingFactor: 1.8, + randomize: false, + fit: true + }).run(); + + console.log('Mindmap wurde erfolgreich aktualisiert!'); + + // Wenn ein Wissen-Knoten existiert, sicherstellen, dass er im Zentrum ist + const rootNode = cy.getElementById('1'); + if (rootNode.length > 0) { + cy.center(rootNode); + } +} + +// Hilfe-Funktion zum Hinzufügen eines Flash-Hinweises +function showFlash(message, type = 'info') { + const flashContainer = document.getElementById('flash-messages') || createFlashContainer(); + + const flashMsg = document.createElement('div'); + flashMsg.className = `flash-message flash-${type} mb-2 p-3 rounded`; + flashMsg.innerHTML = ` +
+
${message}
+ +
+ `; + + flashContainer.appendChild(flashMsg); + + // Nach 5 Sekunden automatisch ausblenden + setTimeout(() => { + flashMsg.style.opacity = '0'; + setTimeout(() => flashMsg.remove(), 300); + }, 5000); + + // Close-Button + const closeBtn = flashMsg.querySelector('.close-flash'); + closeBtn.addEventListener('click', () => { + flashMsg.style.opacity = '0'; + setTimeout(() => flashMsg.remove(), 300); + }); +} + +// Hilfsfunktion zum Erstellen eines Flash-Containers, falls keiner existiert +function createFlashContainer() { + const container = document.createElement('div'); + container.id = 'flash-messages'; + container.className = 'fixed top-4 right-4 z-50 w-64'; + document.body.appendChild(container); + return container; +} \ No newline at end of file diff --git a/templates/mindmap.html b/templates/mindmap.html index 9ea0ff9..7b7eea1 100644 --- a/templates/mindmap.html +++ b/templates/mindmap.html @@ -341,17 +341,10 @@ {% endblock %} {% block extra_js %} - - - - - - - + + + + + + {% endblock %} \ No newline at end of file