"Update .env and migration files for database schema"

This commit is contained in:
2025-05-10 18:07:49 +02:00
parent 858fdf5c44
commit 2e68ae30b8
4 changed files with 82 additions and 144 deletions

2
.env
View File

@@ -7,7 +7,7 @@ FLASK_ENV=development
SECRET_KEY=your-secret-key-replace-in-production SECRET_KEY=your-secret-key-replace-in-production
# 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

Binary file not shown.

224
app.py
View File

@@ -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
@@ -1471,163 +1495,77 @@ 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):
""" """

Binary file not shown.