Overhaul website to modernize design, integrate SVG visualizations, and enhance KI functionality; update documentation for MindMapProjekt.
This commit is contained in:
280
static/js/modules/chatgpt-assistant.js
Normal file
280
static/js/modules/chatgpt-assistant.js
Normal file
@@ -0,0 +1,280 @@
|
||||
/**
|
||||
* ChatGPT Assistent Modul
|
||||
* Verwaltet die Interaktion mit der OpenAI API und die Benutzeroberfläche des Assistenten
|
||||
*/
|
||||
|
||||
class ChatGPTAssistant {
|
||||
constructor() {
|
||||
this.messages = [];
|
||||
this.isOpen = false;
|
||||
this.isLoading = false;
|
||||
this.container = null;
|
||||
this.chatHistory = null;
|
||||
this.inputField = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialisiert den Assistenten und fügt die UI zum DOM hinzu
|
||||
*/
|
||||
init() {
|
||||
// Assistent-Container erstellen
|
||||
this.createAssistantUI();
|
||||
|
||||
// Event-Listener hinzufügen
|
||||
this.setupEventListeners();
|
||||
|
||||
// Ersten Willkommensnachricht anzeigen
|
||||
this.addMessage("assistant", "Frage den KI-Assistenten");
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstellt die UI-Elemente für den Assistenten
|
||||
*/
|
||||
createAssistantUI() {
|
||||
// Hauptcontainer erstellen
|
||||
this.container = document.createElement('div');
|
||||
this.container.id = 'chatgpt-assistant';
|
||||
this.container.className = 'fixed bottom-4 right-4 z-50 flex flex-col';
|
||||
|
||||
// Button zum Öffnen/Schließen des Assistenten
|
||||
const toggleButton = document.createElement('button');
|
||||
toggleButton.id = 'assistant-toggle';
|
||||
toggleButton.className = 'ml-auto bg-primary-600 hover:bg-primary-700 text-white rounded-full p-3 shadow-lg transition-all duration-300 mb-2';
|
||||
toggleButton.innerHTML = '<i class="fas fa-robot text-xl"></i>';
|
||||
|
||||
// Chat-Container
|
||||
const chatContainer = document.createElement('div');
|
||||
chatContainer.id = 'assistant-chat';
|
||||
chatContainer.className = 'bg-white dark:bg-dark-800 rounded-lg shadow-xl overflow-hidden transition-all duration-300 w-80 sm:w-96 max-h-0 opacity-0';
|
||||
|
||||
// Chat-Header
|
||||
const header = document.createElement('div');
|
||||
header.className = 'bg-primary-600 text-white p-3 flex items-center justify-between';
|
||||
header.innerHTML = `
|
||||
<div class="flex items-center">
|
||||
<i class="fas fa-robot mr-2"></i>
|
||||
<span>KI-Assistent</span>
|
||||
</div>
|
||||
<button id="assistant-close" class="text-white hover:text-gray-200">
|
||||
<i class="fas fa-times"></i>
|
||||
</button>
|
||||
`;
|
||||
|
||||
// Chat-Verlauf
|
||||
this.chatHistory = document.createElement('div');
|
||||
this.chatHistory.id = 'assistant-history';
|
||||
this.chatHistory.className = 'p-3 overflow-y-auto max-h-80 space-y-3';
|
||||
|
||||
// Chat-Eingabe
|
||||
const inputContainer = document.createElement('div');
|
||||
inputContainer.className = 'border-t border-gray-200 dark:border-dark-600 p-3 flex items-center';
|
||||
|
||||
this.inputField = document.createElement('input');
|
||||
this.inputField.type = 'text';
|
||||
this.inputField.placeholder = 'Frage den KI-Assistenten';
|
||||
this.inputField.className = 'flex-1 border border-gray-300 dark:border-dark-600 dark:bg-dark-700 dark:text-white rounded-l-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-primary-500';
|
||||
|
||||
const sendButton = document.createElement('button');
|
||||
sendButton.id = 'assistant-send';
|
||||
sendButton.className = 'bg-primary-600 hover:bg-primary-700 text-white px-4 py-2 rounded-r-lg';
|
||||
sendButton.innerHTML = '<i class="fas fa-paper-plane"></i>';
|
||||
|
||||
// Elemente zusammenfügen
|
||||
inputContainer.appendChild(this.inputField);
|
||||
inputContainer.appendChild(sendButton);
|
||||
|
||||
chatContainer.appendChild(header);
|
||||
chatContainer.appendChild(this.chatHistory);
|
||||
chatContainer.appendChild(inputContainer);
|
||||
|
||||
this.container.appendChild(toggleButton);
|
||||
this.container.appendChild(chatContainer);
|
||||
|
||||
// Zum DOM hinzufügen
|
||||
document.body.appendChild(this.container);
|
||||
}
|
||||
|
||||
/**
|
||||
* Richtet Event-Listener für die Benutzeroberfläche ein
|
||||
*/
|
||||
setupEventListeners() {
|
||||
// Toggle-Button
|
||||
const toggleButton = document.getElementById('assistant-toggle');
|
||||
toggleButton.addEventListener('click', () => this.toggleAssistant());
|
||||
|
||||
// Schließen-Button
|
||||
const closeButton = document.getElementById('assistant-close');
|
||||
closeButton.addEventListener('click', () => this.toggleAssistant(false));
|
||||
|
||||
// Senden-Button
|
||||
const sendButton = document.getElementById('assistant-send');
|
||||
sendButton.addEventListener('click', () => this.sendMessage());
|
||||
|
||||
// Enter-Taste im Eingabefeld
|
||||
this.inputField.addEventListener('keyup', (e) => {
|
||||
if (e.key === 'Enter') {
|
||||
this.sendMessage();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Öffnet oder schließt den Assistenten
|
||||
* @param {boolean} state - Optional: erzwingt einen bestimmten Zustand
|
||||
*/
|
||||
toggleAssistant(state = null) {
|
||||
const chatContainer = document.getElementById('assistant-chat');
|
||||
this.isOpen = state !== null ? state : !this.isOpen;
|
||||
|
||||
if (this.isOpen) {
|
||||
chatContainer.classList.remove('max-h-0', 'opacity-0');
|
||||
chatContainer.classList.add('max-h-96', 'opacity-100');
|
||||
this.inputField.focus();
|
||||
} else {
|
||||
chatContainer.classList.remove('max-h-96', 'opacity-100');
|
||||
chatContainer.classList.add('max-h-0', 'opacity-0');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fügt eine Nachricht zum Chat-Verlauf hinzu
|
||||
* @param {string} sender - 'user' oder 'assistant'
|
||||
* @param {string} text - Nachrichtentext
|
||||
*/
|
||||
addMessage(sender, text) {
|
||||
// Nachricht zum Verlauf hinzufügen
|
||||
this.messages.push({ role: sender, content: text });
|
||||
|
||||
// DOM-Element erstellen
|
||||
const messageEl = document.createElement('div');
|
||||
messageEl.className = `flex ${sender === 'user' ? 'justify-end' : 'justify-start'}`;
|
||||
|
||||
const bubble = document.createElement('div');
|
||||
bubble.className = sender === 'user'
|
||||
? 'bg-primary-100 dark:bg-primary-900 text-gray-800 dark:text-white rounded-lg py-2 px-3 max-w-[85%]'
|
||||
: 'bg-gray-100 dark:bg-dark-700 text-gray-800 dark:text-white rounded-lg py-2 px-3 max-w-[85%]';
|
||||
bubble.textContent = text;
|
||||
|
||||
messageEl.appendChild(bubble);
|
||||
this.chatHistory.appendChild(messageEl);
|
||||
|
||||
// Scroll zum Ende des Verlaufs
|
||||
this.chatHistory.scrollTop = this.chatHistory.scrollHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sendet die Benutzernachricht an den Server und zeigt die Antwort an
|
||||
*/
|
||||
async sendMessage() {
|
||||
const userInput = this.inputField.value.trim();
|
||||
if (!userInput || this.isLoading) return;
|
||||
|
||||
// Benutzernachricht anzeigen
|
||||
this.addMessage('user', userInput);
|
||||
|
||||
// Eingabefeld zurücksetzen
|
||||
this.inputField.value = '';
|
||||
|
||||
// Ladeindikator anzeigen
|
||||
this.isLoading = true;
|
||||
this.showLoadingIndicator();
|
||||
|
||||
try {
|
||||
// Anfrage an den Server senden
|
||||
const response = await fetch('/api/assistant', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
messages: this.messages
|
||||
}),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Netzwerkfehler oder Serverproblem');
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
// Ladeindikator entfernen
|
||||
this.removeLoadingIndicator();
|
||||
|
||||
// Antwort anzeigen
|
||||
this.addMessage('assistant', data.response);
|
||||
} catch (error) {
|
||||
console.error('Fehler bei der Kommunikation mit dem Assistenten:', error);
|
||||
|
||||
// Ladeindikator entfernen
|
||||
this.removeLoadingIndicator();
|
||||
|
||||
// Fehlermeldung anzeigen
|
||||
this.addMessage('assistant', 'Es tut mir leid, aber es gab ein Problem bei der Verarbeitung deiner Anfrage. Bitte versuche es später noch einmal.');
|
||||
} finally {
|
||||
this.isLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Zeigt einen Ladeindikator im Chat an
|
||||
*/
|
||||
showLoadingIndicator() {
|
||||
const loadingEl = document.createElement('div');
|
||||
loadingEl.id = 'assistant-loading';
|
||||
loadingEl.className = 'flex justify-start';
|
||||
|
||||
const bubble = document.createElement('div');
|
||||
bubble.className = 'bg-gray-100 dark:bg-dark-700 text-gray-800 dark:text-white rounded-lg py-2 px-3';
|
||||
bubble.innerHTML = '<div class="typing-indicator"><span></span><span></span><span></span></div>';
|
||||
|
||||
loadingEl.appendChild(bubble);
|
||||
this.chatHistory.appendChild(loadingEl);
|
||||
|
||||
// Scroll zum Ende des Verlaufs
|
||||
this.chatHistory.scrollTop = this.chatHistory.scrollHeight;
|
||||
|
||||
// Stil für den Typing-Indikator
|
||||
const style = document.createElement('style');
|
||||
style.textContent = `
|
||||
.typing-indicator {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.typing-indicator span {
|
||||
height: 8px;
|
||||
width: 8px;
|
||||
background-color: #888;
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
margin: 0 2px;
|
||||
opacity: 0.4;
|
||||
animation: typing 1.5s infinite ease-in-out;
|
||||
}
|
||||
.typing-indicator span:nth-child(2) {
|
||||
animation-delay: 0.2s;
|
||||
}
|
||||
.typing-indicator span:nth-child(3) {
|
||||
animation-delay: 0.4s;
|
||||
}
|
||||
@keyframes typing {
|
||||
0% { transform: translateY(0); }
|
||||
50% { transform: translateY(-5px); }
|
||||
100% { transform: translateY(0); }
|
||||
}
|
||||
`;
|
||||
document.head.appendChild(style);
|
||||
}
|
||||
|
||||
/**
|
||||
* Entfernt den Ladeindikator aus dem Chat
|
||||
*/
|
||||
removeLoadingIndicator() {
|
||||
const loadingEl = document.getElementById('assistant-loading');
|
||||
if (loadingEl) {
|
||||
loadingEl.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Exportiere die Klasse für die Verwendung in anderen Modulen
|
||||
export default ChatGPTAssistant;
|
||||
Reference in New Issue
Block a user