"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
# OpenAI API
OPENAI_API_KEY=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
# Datenbank
# 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
import secrets
from sqlalchemy.sql import func
import openai
from openai import OpenAI
from dotenv import load_dotenv
from flask_socketio import SocketIO, emit
from flask_migrate import Migrate
import sqlalchemy
import ssl
import certifi
import os
# Modelle importieren
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
# OpenAI API-Konfiguration
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.")
api_key = os.environ.get("OPENAI_API_KEY", "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")
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
@app.before_request
@@ -1471,163 +1495,77 @@ def too_many_requests(e):
# OpenAI-Integration für KI-Assistenz
@app.route('/api/assistant', methods=['POST'])
def chat_with_assistant():
"""Chatbot-API mit OpenAI Integration und Datenbankzugriff."""
"""Chat mit dem KI-Assistenten"""
data = request.json
user_message = data.get('message', '')
# Prüfen, ob wir ein einzelnes Prompt oder ein messages-Array haben
if 'messages' in data:
messages = data.get('messages', [])
if not messages:
return jsonify({
'error': 'Keine Nachrichten vorhanden.'
}), 400
# 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}"
})
# Überprüfe, ob die OpenAI-API verfügbar ist
if not openai_available or client is None:
# Fallback-Antwort, wenn OpenAI nicht verfügbar ist
fallback_message = {
"response": "Der KI-Assistent ist derzeit nicht verfügbar. Bitte versuchen Sie es später erneut oder kontaktieren Sie den Administrator.",
"thoughts": "Leider konnte keine Verbindung zur OpenAI-API hergestellt werden. Dies kann an SSL-Zertifikatsproblemen, Netzwerkproblemen oder API-Schlüsselproblemen liegen."
}
return jsonify(fallback_message)
# Versuche, eine Antwort von OpenAI zu erhalten
try:
# OpenAI-Client mit dem API-Key initialisieren
client = OpenAI(api_key=api_key)
# Ü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!")
# Check, ob es eine Datenbankanfrage ist
is_db_query, db_query_result = check_database_query(user_message)
if is_db_query:
return jsonify({
'error': 'Der OpenAI API-Key ist nicht korrekt konfiguriert. Bitte konfigurieren Sie die Umgebungsvariable OPENAI_API_KEY.'
}), 500
# API-Aufruf mit Timeout
import time
start_time = time.time()
"response": db_query_result,
"thoughts": "Ihre Anfrage wurde als Datenbankanfrage erkannt und direkt beantwortet."
})
system_message = """Du bist SysTades, ein intelligenter Assistent in einer Wissensmanagement-Anwendung.
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(
model="gpt-4o-mini",
messages=api_messages,
max_tokens=1000,
messages=[
{"role": "system", "content": system_message},
{"role": "user", "content": user_message}
],
temperature=0.7,
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({
'response': answer
"response": assistant_response,
"thoughts": thoughts
})
except Exception as e:
print(f"Fehler bei der OpenAI-Anfrage: {e}")
import traceback
error_message = str(e)
stack_trace = traceback.format_exc()
print(f"Stack Trace: {traceback.format_exc()}")
print(f"Fehler bei der OpenAI-Anfrage: {error_message}")
print(f"Stack Trace: {stack_trace}")
# Überprüfen auf spezifische Fehlertypen
if "timeout" in error_message.lower():
return jsonify({
'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
# Fallback-Antwort bei Fehler
fallback_message = {
"response": "Es tut mir leid, aber ich konnte Ihre Anfrage nicht verarbeiten. Bitte versuchen Sie es später erneut.",
"thoughts": "Ein technisches Problem ist aufgetreten. Dies könnte an Netzwerkproblemen, API-Grenzen oder Serverauslastung liegen."
}
return jsonify(fallback_message)
def check_database_query(user_message):
"""

Binary file not shown.