Compare commits
6 Commits
2584bae149
...
6322e046c5
| Author | SHA1 | Date | |
|---|---|---|---|
| 6322e046c5 | |||
| 629813c486 | |||
| fe3cf81bc7 | |||
| 2e68ae30b8 | |||
| 858fdf5c44 | |||
| 4948f3ad2a |
6
.env
6
.env
@@ -3,11 +3,11 @@
|
|||||||
|
|
||||||
# Flask
|
# Flask
|
||||||
FLASK_APP=app.py
|
FLASK_APP=app.py
|
||||||
FLASK_DEBUG=1
|
FLASK_ENV=development
|
||||||
SECRET_KEY=ETMyh4JfBfvpZSscqfuzjCOAvelm5lEju
|
SECRET_KEY=your-secret-key-replace-in-production
|
||||||
|
|
||||||
# OpenAI API
|
# OpenAI API
|
||||||
OPENAI_API_KEY=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
|
OPENAI_API_KEY=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
|
||||||
|
|
||||||
# Datenbank
|
# Datenbank
|
||||||
# Bei Bedarf kann hier eine andere Datenbank-URL angegeben werden
|
# Bei Bedarf kann hier eine andere Datenbank-URL angegeben werden
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
449
app.py
449
app.py
@@ -15,11 +15,15 @@ from wtforms.validators import DataRequired, Email, Length, EqualTo, ValidationE
|
|||||||
from functools import wraps
|
from functools import wraps
|
||||||
import secrets
|
import secrets
|
||||||
from sqlalchemy.sql import func
|
from sqlalchemy.sql import func
|
||||||
|
import openai
|
||||||
from openai import OpenAI
|
from openai import OpenAI
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
from flask_socketio import SocketIO, emit
|
from flask_socketio import SocketIO, emit
|
||||||
from flask_migrate import Migrate
|
from flask_migrate import Migrate
|
||||||
import sqlalchemy
|
import sqlalchemy
|
||||||
|
import ssl
|
||||||
|
import certifi
|
||||||
|
import os
|
||||||
|
|
||||||
# Modelle importieren
|
# Modelle importieren
|
||||||
from models import (
|
from models import (
|
||||||
@@ -46,12 +50,32 @@ app.config['UPLOAD_FOLDER'] = os.getenv('UPLOAD_FOLDER', os.path.join(os.getcwd(
|
|||||||
app.config['WTF_CSRF_ENABLED'] = False
|
app.config['WTF_CSRF_ENABLED'] = False
|
||||||
|
|
||||||
# OpenAI API-Konfiguration
|
# OpenAI API-Konfiguration
|
||||||
api_key = "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"
|
api_key = os.environ.get("OPENAI_API_KEY", "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")
|
||||||
# api_key = os.environ.get("OPENAI_API_KEY")
|
|
||||||
# if not api_key:
|
|
||||||
# print("WARNUNG: Kein OPENAI_API_KEY in Umgebungsvariablen gefunden. KI-Funktionalität wird nicht verfügbar sein.")
|
|
||||||
|
|
||||||
client = OpenAI(api_key=api_key)
|
# Variable zur Überprüfung, ob OpenAI verfügbar ist
|
||||||
|
openai_available = True
|
||||||
|
|
||||||
|
# Client mit SSL-Verify-Deaktivierung für problematische Umgebungen
|
||||||
|
try:
|
||||||
|
# Versuche, den OpenAI-Client zu initialisieren und zu testen
|
||||||
|
client = OpenAI(api_key=api_key)
|
||||||
|
# Deaktiviere SSL-Verifizierung, falls in Windows-Umgebungen Probleme auftreten
|
||||||
|
client._client.proxies = {}
|
||||||
|
client._client.verify = False
|
||||||
|
|
||||||
|
# Testanfrage, um zu prüfen, ob die API funktioniert
|
||||||
|
try:
|
||||||
|
# Einfache Testanfrage
|
||||||
|
resp = client.models.list()
|
||||||
|
openai_available = True
|
||||||
|
print("OpenAI API-Verbindung erfolgreich hergestellt.")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"OpenAI API-Verbindungstest fehlgeschlagen: {e}")
|
||||||
|
openai_available = False
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Fehler bei der Initialisierung des OpenAI-Clients: {e}")
|
||||||
|
openai_available = False
|
||||||
|
client = None
|
||||||
|
|
||||||
# Dark Mode Einstellung in Session speichern
|
# Dark Mode Einstellung in Session speichern
|
||||||
@app.before_request
|
@app.before_request
|
||||||
@@ -98,6 +122,65 @@ socketio = SocketIO(app)
|
|||||||
|
|
||||||
migrate = Migrate(app, db)
|
migrate = Migrate(app, db)
|
||||||
|
|
||||||
|
# Automatische Datenbankinitialisierung - Aktualisiert für Flask 2.2+ Kompatibilität
|
||||||
|
def initialize_app():
|
||||||
|
"""Initialisierung der Anwendung"""
|
||||||
|
print("Initialisierung der Anwendung...")
|
||||||
|
with app.app_context():
|
||||||
|
# Prüfen, ob die Datenbank existiert und initialisiert ist
|
||||||
|
try:
|
||||||
|
# Prüfen, ob Tabellen existieren
|
||||||
|
db.create_all()
|
||||||
|
|
||||||
|
# Prüfen, ob Stammdaten vorhanden sind
|
||||||
|
if User.query.count() == 0:
|
||||||
|
print("Erstelle Standardbenutzer...")
|
||||||
|
create_default_users()
|
||||||
|
|
||||||
|
if Category.query.count() == 0:
|
||||||
|
print("Erstelle Standardkategorien...")
|
||||||
|
create_default_categories()
|
||||||
|
|
||||||
|
if MindMapNode.query.count() == 0 and Category.query.count() > 0:
|
||||||
|
print("Erstelle Beispiel-Mindmap...")
|
||||||
|
create_sample_mindmap()
|
||||||
|
|
||||||
|
print("Datenbank wurde erfolgreich initialisiert.")
|
||||||
|
except Exception as e:
|
||||||
|
import traceback
|
||||||
|
print(f"Fehler bei der Datenbankinitialisierung: {e}")
|
||||||
|
print(traceback.format_exc())
|
||||||
|
|
||||||
|
# Moderne Methode für die Datenbankinitialisierung in Flask 2.2+
|
||||||
|
with app.app_context():
|
||||||
|
initialize_app()
|
||||||
|
|
||||||
|
def create_default_users():
|
||||||
|
"""Erstellt Standardbenutzer für die Anwendung"""
|
||||||
|
users = [
|
||||||
|
{
|
||||||
|
'username': 'admin',
|
||||||
|
'email': 'admin@example.com',
|
||||||
|
'password': 'admin',
|
||||||
|
'role': 'admin'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'username': 'user',
|
||||||
|
'email': 'user@example.com',
|
||||||
|
'password': 'user',
|
||||||
|
'role': 'user'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
for user_data in users:
|
||||||
|
password = user_data.pop('password')
|
||||||
|
user = User(**user_data)
|
||||||
|
user.set_password(password)
|
||||||
|
db.session.add(user)
|
||||||
|
|
||||||
|
db.session.commit()
|
||||||
|
print(f"{len(users)} Benutzer wurden erstellt.")
|
||||||
|
|
||||||
def create_default_categories():
|
def create_default_categories():
|
||||||
"""Erstellt die Standardkategorien für die Mindmap"""
|
"""Erstellt die Standardkategorien für die Mindmap"""
|
||||||
# Hauptkategorien
|
# Hauptkategorien
|
||||||
@@ -1471,227 +1554,195 @@ def too_many_requests(e):
|
|||||||
# OpenAI-Integration für KI-Assistenz
|
# OpenAI-Integration für KI-Assistenz
|
||||||
@app.route('/api/assistant', methods=['POST'])
|
@app.route('/api/assistant', methods=['POST'])
|
||||||
def chat_with_assistant():
|
def chat_with_assistant():
|
||||||
"""Chatbot-API mit OpenAI Integration und Datenbankzugriff."""
|
"""Chat mit dem KI-Assistenten"""
|
||||||
data = request.json
|
data = request.json
|
||||||
|
user_message = data.get('message', '')
|
||||||
|
|
||||||
# Prüfen, ob wir ein einzelnes Prompt oder ein messages-Array haben
|
# Überprüfe, ob die OpenAI-API verfügbar ist
|
||||||
if 'messages' in data:
|
if not openai_available or client is None:
|
||||||
messages = data.get('messages', [])
|
# Fallback-Antwort, wenn OpenAI nicht verfügbar ist
|
||||||
if not messages:
|
fallback_message = {
|
||||||
return jsonify({
|
"response": "Der KI-Assistent ist derzeit nicht verfügbar. Bitte versuchen Sie es später erneut oder kontaktieren Sie den Administrator.",
|
||||||
'error': 'Keine Nachrichten vorhanden.'
|
"thoughts": "Leider konnte keine Verbindung zur OpenAI-API hergestellt werden. Dies kann an SSL-Zertifikatsproblemen, Netzwerkproblemen oder API-Schlüsselproblemen liegen."
|
||||||
}), 400
|
}
|
||||||
|
return jsonify(fallback_message)
|
||||||
# Extrahiere Systemnachricht falls vorhanden, sonst Standard-Systemnachricht
|
|
||||||
system_message = next((msg['content'] for msg in messages if msg['role'] == 'system'),
|
|
||||||
"Du bist ein spezialisierter Assistent für Systades, eine innovative Wissensmanagement-Plattform. "
|
|
||||||
"Systades ist ein intelligentes System zur Verwaltung, Verknüpfung und Visualisierung von Wissen. "
|
|
||||||
"Die Plattform ermöglicht es Nutzern, Gedanken zu erfassen, in Kategorien zu organisieren und durch Mindmaps zu visualisieren. "
|
|
||||||
"Wichtige Funktionen sind:\n"
|
|
||||||
"- Gedankenverwaltung mit Titeln, Zusammenfassungen und Keywords\n"
|
|
||||||
"- Kategorisierung und thematische Organisation\n"
|
|
||||||
"- Interaktive Mindmaps zur Wissensvisualisierung\n"
|
|
||||||
"- KI-gestützte Analyse und Zusammenfassung von Inhalten\n"
|
|
||||||
"- Kollaborative Wissensarbeit und Teilen von Inhalten\n\n"
|
|
||||||
"Du antwortest AUSSCHLIESSLICH auf Fragen bezüglich der Systades-Wissensdatenbank und Website. "
|
|
||||||
"Du kannst Informationen zu Gedanken, Kategorien und Mindmaps liefern und durch Themen führen. "
|
|
||||||
"Antworte informativ, sachlich und gut strukturiert auf Deutsch.")
|
|
||||||
|
|
||||||
# Formatiere Nachrichten für OpenAI API
|
|
||||||
api_messages = [{"role": "system", "content": system_message}]
|
|
||||||
|
|
||||||
# Füge Benutzer- und Assistenten-Nachrichten hinzu
|
|
||||||
for msg in messages:
|
|
||||||
if msg['role'] in ['user', 'assistant']:
|
|
||||||
api_messages.append({"role": msg['role'], "content": msg['content']})
|
|
||||||
else:
|
|
||||||
# Alte Implementierung für direktes Prompt
|
|
||||||
prompt = data.get('prompt', '')
|
|
||||||
context = data.get('context', '')
|
|
||||||
selected_items = data.get('selected_items', []) # Ausgewählte Elemente aus der Datenbank
|
|
||||||
|
|
||||||
if not prompt:
|
|
||||||
return jsonify({
|
|
||||||
'error': 'Prompt darf nicht leer sein.'
|
|
||||||
}), 400
|
|
||||||
|
|
||||||
# Zusammenfassen mehrerer Gedanken oder Analyse anfordern
|
|
||||||
system_message = (
|
|
||||||
"Du bist ein spezialisierter Assistent für Systades, eine innovative Wissensmanagement-Plattform. "
|
|
||||||
"Systades ist ein intelligentes System zur Verwaltung, Verknüpfung und Visualisierung von Wissen. "
|
|
||||||
"Die Plattform ermöglicht es Nutzern, Gedanken zu erfassen, in Kategorien zu organisieren und durch Mindmaps zu visualisieren. "
|
|
||||||
"Wichtige Funktionen sind:\n"
|
|
||||||
"- Gedankenverwaltung mit Titeln, Zusammenfassungen und Keywords\n"
|
|
||||||
"- Kategorisierung und thematische Organisation\n"
|
|
||||||
"- Interaktive Mindmaps zur Wissensvisualisierung\n"
|
|
||||||
"- KI-gestützte Analyse und Zusammenfassung von Inhalten\n"
|
|
||||||
"- Kollaborative Wissensarbeit und Teilen von Inhalten\n\n"
|
|
||||||
"Du antwortest AUSSCHLIESSLICH auf Fragen bezüglich der Systades-Wissensdatenbank und Website. "
|
|
||||||
"Du kannst Informationen zu Gedanken, Kategorien und Mindmaps liefern und durch Themen führen. "
|
|
||||||
"Antworte informativ, sachlich und gut strukturiert auf Deutsch."
|
|
||||||
)
|
|
||||||
|
|
||||||
if context:
|
|
||||||
system_message += f"\n\nKontext: {context}"
|
|
||||||
|
|
||||||
if selected_items:
|
|
||||||
system_message += "\n\nAusgewählte Elemente aus der Datenbank:\n"
|
|
||||||
for item in selected_items:
|
|
||||||
if 'type' in item and 'data' in item:
|
|
||||||
if item['type'] == 'thought':
|
|
||||||
system_message += f"- Gedanke: {item['data'].get('title', 'Unbekannter Titel')}\n"
|
|
||||||
system_message += f" Zusammenfassung: {item['data'].get('abstract', 'Keine Zusammenfassung')}\n"
|
|
||||||
system_message += f" Keywords: {item['data'].get('keywords', 'Keine Keywords')}\n"
|
|
||||||
elif item['type'] == 'category':
|
|
||||||
system_message += f"- Kategorie: {item['data'].get('name', 'Unbekannte Kategorie')}\n"
|
|
||||||
system_message += f" Beschreibung: {item['data'].get('description', 'Keine Beschreibung')}\n"
|
|
||||||
system_message += f" Unterkategorien: {item['data'].get('subcategories', 'Keine Unterkategorien')}\n"
|
|
||||||
elif item['type'] == 'mindmap':
|
|
||||||
system_message += f"- Mindmap: {item['data'].get('name', 'Unbekannte Mindmap')}\n"
|
|
||||||
system_message += f" Beschreibung: {item['data'].get('description', 'Keine Beschreibung')}\n"
|
|
||||||
system_message += f" Knoten: {item['data'].get('nodes', 'Keine Knoten')}\n"
|
|
||||||
|
|
||||||
api_messages = [
|
|
||||||
{"role": "system", "content": system_message},
|
|
||||||
{"role": "user", "content": prompt}
|
|
||||||
]
|
|
||||||
|
|
||||||
# Extrahiere die letzte Benutzernachricht für Datenbankabfragen
|
|
||||||
user_message = next((msg['content'] for msg in reversed(api_messages) if msg['role'] == 'user'), '')
|
|
||||||
|
|
||||||
# Prüfen, ob die Anfrage nach Datenbankinformationen sucht
|
|
||||||
db_context = check_database_query(user_message)
|
|
||||||
|
|
||||||
if db_context:
|
|
||||||
# Erweitere den Kontext mit Datenbankinformationen
|
|
||||||
api_messages.append({
|
|
||||||
"role": "system",
|
|
||||||
"content": f"Hier sind relevante Informationen aus der Datenbank:\n\n{db_context}"
|
|
||||||
})
|
|
||||||
|
|
||||||
|
# Versuche, eine Antwort von OpenAI zu erhalten
|
||||||
try:
|
try:
|
||||||
# OpenAI-Client mit dem API-Key initialisieren
|
# Check, ob es eine Datenbankanfrage ist
|
||||||
client = OpenAI(api_key=api_key)
|
is_db_query, db_query_result = check_database_query(user_message)
|
||||||
|
if is_db_query:
|
||||||
# Überprüfen ob OpenAI API-Key konfiguriert ist
|
|
||||||
if not api_key or api_key.startswith("sk-dummy"):
|
|
||||||
print("Warnung: OpenAI API-Key ist nicht oder nur als Dummy konfiguriert!")
|
|
||||||
return jsonify({
|
return jsonify({
|
||||||
'error': 'Der OpenAI API-Key ist nicht korrekt konfiguriert. Bitte konfigurieren Sie die Umgebungsvariable OPENAI_API_KEY.'
|
"response": db_query_result,
|
||||||
}), 500
|
"thoughts": "Ihre Anfrage wurde als Datenbankanfrage erkannt und direkt beantwortet."
|
||||||
|
})
|
||||||
# API-Aufruf mit Timeout
|
|
||||||
import time
|
system_message = """Du bist SysTades, ein intelligenter Assistent in einer Wissensmanagement-Anwendung.
|
||||||
start_time = time.time()
|
Deine Aufgabe ist es, tiefe, reflektierte Antworten auf Fragen der Benutzer zu geben.
|
||||||
|
Beziehe dich auf vorhandene Konzepte und betrachte Fragen stets aus mehreren Perspektiven.
|
||||||
|
Vermeide pauschale Antworten und beziehe immer verschiedene Denkansätze ein.
|
||||||
|
Antworte stets auf Deutsch und in einem nachdenklichen, philosophischen Ton.
|
||||||
|
"""
|
||||||
|
|
||||||
# Erhöhtes Timeout für die API-Anfrage
|
|
||||||
response = client.chat.completions.create(
|
response = client.chat.completions.create(
|
||||||
model="gpt-4o-mini",
|
model="gpt-4o-mini",
|
||||||
messages=api_messages,
|
messages=[
|
||||||
max_tokens=1000,
|
{"role": "system", "content": system_message},
|
||||||
|
{"role": "user", "content": user_message}
|
||||||
|
],
|
||||||
temperature=0.7,
|
temperature=0.7,
|
||||||
timeout=60 # Erhöht auf 60 Sekunden für bessere Zuverlässigkeit
|
timeout=60 # Erhöht auf 60 Sekunden für bessere Zuverlässigkeit
|
||||||
)
|
)
|
||||||
|
|
||||||
print(f"OpenAI API-Antwortzeit: {time.time() - start_time:.2f} Sekunden")
|
# Extrahiere die Antwort
|
||||||
|
assistant_response = response.choices[0].message.content
|
||||||
|
|
||||||
answer = response.choices[0].message.content
|
# Generiere zusätzliche "Gedanken" für verbesserte UX
|
||||||
|
thoughts_response = client.chat.completions.create(
|
||||||
|
model="gpt-4o-mini",
|
||||||
|
messages=[
|
||||||
|
{"role": "system", "content": "Gib kurze Einblicke in deine Gedankenprozesse zu dieser Frage. Schreibe 1-3 Sätze zur Reflexion über die Frage und die wichtigsten Aspekte deiner Antwort. Bleibe dabei informell und persönlich. Schreibe auf Deutsch."},
|
||||||
|
{"role": "user", "content": user_message},
|
||||||
|
{"role": "assistant", "content": assistant_response}
|
||||||
|
],
|
||||||
|
temperature=0.7,
|
||||||
|
max_tokens=150
|
||||||
|
)
|
||||||
|
thoughts = thoughts_response.choices[0].message.content
|
||||||
|
|
||||||
# Für das neue Format erwarten wir response statt answer
|
|
||||||
return jsonify({
|
return jsonify({
|
||||||
'response': answer
|
"response": assistant_response,
|
||||||
|
"thoughts": thoughts
|
||||||
})
|
})
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
print(f"Fehler bei der OpenAI-Anfrage: {e}")
|
||||||
import traceback
|
import traceback
|
||||||
error_message = str(e)
|
print(f"Stack Trace: {traceback.format_exc()}")
|
||||||
stack_trace = traceback.format_exc()
|
|
||||||
|
|
||||||
print(f"Fehler bei der OpenAI-Anfrage: {error_message}")
|
# Fallback-Antwort bei Fehler
|
||||||
print(f"Stack Trace: {stack_trace}")
|
fallback_message = {
|
||||||
|
"response": "Es tut mir leid, aber ich konnte Ihre Anfrage nicht verarbeiten. Bitte versuchen Sie es später erneut.",
|
||||||
# Überprüfen auf spezifische Fehlertypen
|
"thoughts": "Ein technisches Problem ist aufgetreten. Dies könnte an Netzwerkproblemen, API-Grenzen oder Serverauslastung liegen."
|
||||||
if "timeout" in error_message.lower():
|
}
|
||||||
return jsonify({
|
return jsonify(fallback_message)
|
||||||
'error': 'Die Anfrage hat zu lange gedauert. Bitte versuchen Sie es später erneut.'
|
|
||||||
}), 504
|
|
||||||
elif "rate limit" in error_message.lower():
|
|
||||||
return jsonify({
|
|
||||||
'error': 'API-Ratelimit erreicht. Bitte warten Sie einen Moment und versuchen Sie es erneut.'
|
|
||||||
}), 429
|
|
||||||
elif "internal server error" in error_message.lower() or "500" in error_message:
|
|
||||||
return jsonify({
|
|
||||||
'error': 'Es ist ein Serverfehler aufgetreten. Unser Team wurde benachrichtigt.'
|
|
||||||
}), 500
|
|
||||||
else:
|
|
||||||
# Allgemeine Fehlermeldung
|
|
||||||
return jsonify({
|
|
||||||
'error': 'Bei der Verarbeitung Ihrer Anfrage ist ein Fehler aufgetreten. Bitte versuchen Sie es später erneut.'
|
|
||||||
}), 500
|
|
||||||
|
|
||||||
def check_database_query(user_message):
|
def check_database_query(user_message):
|
||||||
"""
|
"""
|
||||||
Überprüft, ob die Benutzeranfrage nach Datenbankinformationen sucht und extrahiert
|
Prüft, ob die Benutzeranfrage nach Datenbankinformationen sucht
|
||||||
relevante Daten aus der Datenbank.
|
und gibt relevante Informationen aus der Datenbank zurück.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
(bool, str): Tupel aus (ist_db_anfrage, db_antwort)
|
||||||
"""
|
"""
|
||||||
context = []
|
user_message = user_message.lower()
|
||||||
|
|
||||||
# Prüfen auf verschiedene Datenbankabfragemuster
|
# Schlüsselwörter, die auf eine Datenbankanfrage hindeuten
|
||||||
if any(keyword in user_message.lower() for keyword in ['gedanken', 'thought', 'beitrag', 'inhalt']):
|
db_keywords = [
|
||||||
# Suche nach relevanten Gedanken
|
'wie viele', 'wieviele', 'anzahl', 'liste', 'zeige', 'zeig mir', 'datenbank',
|
||||||
thoughts = Thought.query.filter(
|
'statistik', 'stats', 'benutzer', 'gedanken', 'kategorien', 'mindmap',
|
||||||
db.or_(
|
'neueste', 'kürzlich', 'gespeichert', 'zähle', 'suche nach', 'finde'
|
||||||
Thought.title.ilike(f'%{word}%') for word in user_message.split()
|
]
|
||||||
if len(word) > 3 # Nur längere Wörter zur Suche verwenden
|
|
||||||
)
|
# Überprüfen, ob die Nachricht eine Datenbankanfrage sein könnte
|
||||||
).limit(5).all()
|
is_db_query = any(keyword in user_message for keyword in db_keywords)
|
||||||
|
|
||||||
|
if not is_db_query:
|
||||||
|
return False, ""
|
||||||
|
|
||||||
|
# Datenbank-Antwort vorbereiten
|
||||||
|
response = "Hier sind Informationen aus der Datenbank:\n\n"
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 1. Benutzer-Statistiken
|
||||||
|
if any(kw in user_message for kw in ['benutzer', 'user', 'nutzer']):
|
||||||
|
user_count = User.query.count()
|
||||||
|
active_users = User.query.filter_by(is_active=True).count()
|
||||||
|
admins = User.query.filter_by(role='admin').count()
|
||||||
|
|
||||||
|
response += f"**Benutzer-Statistiken:**\n"
|
||||||
|
response += f"- Gesamt: {user_count} Benutzer\n"
|
||||||
|
response += f"- Aktiv: {active_users} Benutzer\n"
|
||||||
|
response += f"- Administratoren: {admins} Benutzer\n\n"
|
||||||
|
|
||||||
if thoughts:
|
# 2. Gedanken-Statistiken
|
||||||
context.append("Relevante Gedanken:")
|
if any(kw in user_message for kw in ['gedanken', 'thought', 'inhalt']):
|
||||||
for thought in thoughts:
|
thought_count = Thought.query.count()
|
||||||
context.append(f"- Titel: {thought.title}")
|
|
||||||
context.append(f" Zusammenfassung: {thought.abstract if thought.abstract else 'Keine Zusammenfassung verfügbar'}")
|
if thought_count > 0:
|
||||||
context.append(f" Keywords: {thought.keywords if thought.keywords else 'Keine Keywords verfügbar'}")
|
avg_rating = db.session.query(func.avg(ThoughtRating.relevance_score)).scalar() or 0
|
||||||
context.append("")
|
avg_rating = round(avg_rating, 1)
|
||||||
|
|
||||||
if any(keyword in user_message.lower() for keyword in ['kategorie', 'category', 'themengebiet', 'bereich']):
|
recent_thoughts = Thought.query.order_by(Thought.created_at.desc()).limit(5).all()
|
||||||
# Suche nach Kategorien
|
|
||||||
categories = Category.query.filter(
|
response += f"**Gedanken-Statistiken:**\n"
|
||||||
db.or_(
|
response += f"- Gesamt: {thought_count} Gedanken\n"
|
||||||
Category.name.ilike(f'%{word}%') for word in user_message.split()
|
response += f"- Durchschnittliche Bewertung: {avg_rating}/5\n\n"
|
||||||
if len(word) > 3
|
|
||||||
)
|
if recent_thoughts:
|
||||||
).limit(5).all()
|
response += "**Neueste Gedanken:**\n"
|
||||||
|
for thought in recent_thoughts:
|
||||||
|
response += f"- {thought.title} (von {thought.author.username})\n"
|
||||||
|
response += "\n"
|
||||||
|
else:
|
||||||
|
response += "Es sind noch keine Gedanken in der Datenbank gespeichert.\n\n"
|
||||||
|
|
||||||
if categories:
|
# 3. Kategorien-Statistiken
|
||||||
context.append("Relevante Kategorien:")
|
if any(kw in user_message for kw in ['kategorie', 'category', 'thema']):
|
||||||
for category in categories:
|
category_count = Category.query.filter_by(parent_id=None).count()
|
||||||
context.append(f"- Name: {category.name}")
|
subcategory_count = Category.query.filter(Category.parent_id != None).count()
|
||||||
context.append(f" Beschreibung: {category.description}")
|
|
||||||
context.append("")
|
response += f"**Kategorien-Statistiken:**\n"
|
||||||
|
response += f"- Hauptkategorien: {category_count}\n"
|
||||||
if any(keyword in user_message.lower() for keyword in ['mindmap', 'karte', 'visualisierung']):
|
response += f"- Unterkategorien: {subcategory_count}\n\n"
|
||||||
# Suche nach öffentlichen Mindmaps
|
|
||||||
mindmap_nodes = MindMapNode.query.filter(
|
main_categories = Category.query.filter_by(parent_id=None).all()
|
||||||
db.and_(
|
if main_categories:
|
||||||
MindMapNode.is_public == True,
|
response += "**Hauptkategorien:**\n"
|
||||||
db.or_(
|
for category in main_categories:
|
||||||
MindMapNode.name.ilike(f'%{word}%') for word in user_message.split()
|
subcats = Category.query.filter_by(parent_id=category.id).count()
|
||||||
if len(word) > 3
|
response += f"- {category.name} ({subcats} Unterkategorien)\n"
|
||||||
)
|
response += "\n"
|
||||||
)
|
|
||||||
).limit(5).all()
|
|
||||||
|
|
||||||
if mindmap_nodes:
|
# 4. Mindmap-Statistiken
|
||||||
context.append("Relevante Mindmap-Knoten:")
|
if any(kw in user_message for kw in ['mindmap', 'karte', 'map', 'knoten']):
|
||||||
for node in mindmap_nodes:
|
public_nodes = MindMapNode.query.count()
|
||||||
context.append(f"- Name: {node.name}")
|
user_mindmaps = UserMindmap.query.count()
|
||||||
context.append(f" Beschreibung: {node.description if node.description else 'Keine Beschreibung verfügbar'}")
|
|
||||||
if node.category:
|
response += f"**Mindmap-Statistiken:**\n"
|
||||||
context.append(f" Kategorie: {node.category.name}")
|
response += f"- Öffentliche Knoten: {public_nodes}\n"
|
||||||
context.append("")
|
response += f"- Benutzerdefinierte Mindmaps: {user_mindmaps}\n\n"
|
||||||
|
|
||||||
return "\n".join(context) if context else ""
|
if user_mindmaps > 0:
|
||||||
|
recent_mindmaps = UserMindmap.query.order_by(UserMindmap.created_at.desc()).limit(3).all()
|
||||||
|
|
||||||
|
if recent_mindmaps:
|
||||||
|
response += "**Neueste Mindmaps:**\n"
|
||||||
|
for mindmap in recent_mindmaps:
|
||||||
|
response += f"- {mindmap.name} (von {mindmap.user.username})\n"
|
||||||
|
response += "\n"
|
||||||
|
|
||||||
|
# Wenn keine spezifischen Daten angefordert wurden, allgemeine Übersicht geben
|
||||||
|
if not any(kw in user_message for kw in ['benutzer', 'user', 'gedanken', 'thought', 'kategorie', 'category', 'mindmap']):
|
||||||
|
users = User.query.count()
|
||||||
|
thoughts = Thought.query.count()
|
||||||
|
categories = Category.query.count()
|
||||||
|
nodes = MindMapNode.query.count()
|
||||||
|
user_maps = UserMindmap.query.count()
|
||||||
|
|
||||||
|
response += f"**Übersicht über die Datenbank:**\n"
|
||||||
|
response += f"- Benutzer: {users}\n"
|
||||||
|
response += f"- Gedanken: {thoughts}\n"
|
||||||
|
response += f"- Kategorien: {categories}\n"
|
||||||
|
response += f"- Mindmap-Knoten: {nodes}\n"
|
||||||
|
response += f"- Benutzerdefinierte Mindmaps: {user_maps}\n"
|
||||||
|
|
||||||
|
return True, response
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
import traceback
|
||||||
|
print(f"Fehler bei der Datenbankabfrage: {e}")
|
||||||
|
print(traceback.format_exc())
|
||||||
|
return True, "Es ist ein Fehler bei der Abfrage der Datenbank aufgetreten. Bitte versuchen Sie es später erneut."
|
||||||
|
|
||||||
@app.route('/search')
|
@app.route('/search')
|
||||||
def search_thoughts_page():
|
def search_thoughts_page():
|
||||||
|
|||||||
Binary file not shown.
@@ -4,12 +4,12 @@
|
|||||||
# Flask
|
# Flask
|
||||||
FLASK_APP=app.py
|
FLASK_APP=app.py
|
||||||
FLASK_ENV=development
|
FLASK_ENV=development
|
||||||
SECRET_KEY=your-secret-key-replace-in-production
|
SECRET_KEY=mein-sicherer-schluessel-fuer-entwicklung
|
||||||
|
|
||||||
# OpenAI API
|
# OpenAI API
|
||||||
|
OPENAI_API_KEY=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
|
||||||
|
|
||||||
# Datenbank
|
# Datenbank
|
||||||
# Bei Bedarf kann hier eine andere Datenbank-URL angegeben werden
|
# Bei Bedarf kann hier eine andere Datenbank-URL angegeben werden
|
||||||
# Der Pfad wird relativ zum Projektverzeichnis angegeben
|
# Der Pfad wird relativ zum Projektverzeichnis angegeben
|
||||||
# SQLALCHEMY_DATABASE_URI=sqlite:////absoluter/pfad/zu/database/systades.db
|
SQLALCHEMY_DATABASE_URI=sqlite:///database/systades.db
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user