"Update .env and migration files for database schema"
This commit is contained in:
2
.env
2
.env
@@ -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
224
app.py
@@ -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.
Reference in New Issue
Block a user