388 lines
14 KiB
JavaScript
388 lines
14 KiB
JavaScript
import { showAlert } from './shared_functions.js';
|
|
|
|
let chatCount = 0; // Zähler für Chat-Sessions
|
|
let currentChatId = null; // Aktuell angezeigte Chat-ID
|
|
let useMarkdown = true;
|
|
|
|
document.getElementById('newChatButton').addEventListener('click', () => {
|
|
createNewChat();
|
|
});
|
|
|
|
document.getElementById('sendButton').addEventListener('click', () => {
|
|
const chatBox = document.getElementById('chatBox');
|
|
const chatInput = document.getElementById('chatInput');
|
|
const messageText = chatInput.value.trim();
|
|
|
|
if (messageText !== '' && currentChatId !== null) { // Stelle sicher, dass eine Chat-ID vorhanden ist
|
|
const messageElement = document.createElement('div');
|
|
messageElement.classList.add('chat-message', 'user');
|
|
//messageElement.innerText = messageText;
|
|
|
|
if (useMarkdown) {
|
|
messageElement.innerHTML = renderMarkdown(messageText);
|
|
} else {
|
|
messageElement.innerText = messageText;
|
|
}
|
|
|
|
chatBox.prepend(messageElement);
|
|
|
|
// Nachricht speichern
|
|
saveMessage(currentChatId, messageText); // Verwende die aktuelle Chat-ID
|
|
|
|
// Sidebar-Button für den Chat-Verlauf erstellen, falls noch nicht vorhanden
|
|
if (document.getElementById(`chatSession-${currentChatId}`) === null) {
|
|
createChatSessionButton(currentChatId);
|
|
}
|
|
|
|
chatInput.value = ''; // Input-Feld leeren
|
|
}
|
|
});
|
|
|
|
function createNewChat() {
|
|
// Erhöhe den Chat-Zähler und erstelle einen neuen Chat
|
|
const newChatId = chatCount++;
|
|
localStorage.setItem(`chatHistory-${newChatId}`, JSON.stringify([])); // Leeren Chat speichern
|
|
createChatSessionButton(newChatId); // Button für den neuen Chat erstellen
|
|
currentChatId = newChatId; // Setze die aktuelle Chat-ID
|
|
loadChatHistory(currentChatId); // Lade den neuen Chat
|
|
}
|
|
|
|
async function saveMessage(chatId, message) {
|
|
const chatHistory = JSON.parse(localStorage.getItem(`chatHistory-${chatId}`)) || [];
|
|
chatHistory.push({ role: "user", content: message });
|
|
localStorage.setItem(`chatHistory-${chatId}`, JSON.stringify(chatHistory));
|
|
|
|
// Aktualisiere den Button-Text in der Sidebar
|
|
updateChatSessionButton(chatId);
|
|
|
|
// Sende die Nachricht an den Chatbot
|
|
const userMessage = getLastUserMessage();
|
|
if (userMessage) {
|
|
let a = await stream_api_open_ai(userMessage);
|
|
console.log("Komplette Nachricht: " + a)
|
|
// Update progress bar:
|
|
let consumption = await tokenize_api_open_ai()
|
|
updateProgressBar(consumption.count, consumption.max_model_len);
|
|
|
|
const chatHistory = JSON.parse(localStorage.getItem(`chatHistory-${chatId}`)) || [];
|
|
chatHistory.push({ role: "assistant", content: a });
|
|
localStorage.setItem(`chatHistory-${chatId}`, JSON.stringify(chatHistory));
|
|
}
|
|
}
|
|
|
|
function updateChatSessionButton(chatId) {
|
|
const button = document.getElementById(`chatSession-${chatId}`);
|
|
if (button) {
|
|
const chatHistory = JSON.parse(localStorage.getItem(`chatHistory-${chatId}`)) || [];
|
|
// Hole die erste Nachricht oder lasse es leer, wenn keine vorhanden ist
|
|
const chatName = chatHistory.length > 0 ? chatHistory[0].content.slice(0, 10) : ''; // Nimm die ersten 10 Zeichen der ersten Nachricht
|
|
button.innerText = chatName + "..." || `Chat ${chatId + 1}`; // Falls leer, setze auf "Chat x"
|
|
}
|
|
}
|
|
|
|
function createChatSessionButton(chatId) {
|
|
const chatList = document.getElementById('chatList');
|
|
|
|
// Container für Chat-Button und Löschen-Button
|
|
const buttonContainer = document.createElement('div');
|
|
buttonContainer.classList.add('chat-session-button-container');
|
|
|
|
// Chat-Button
|
|
const button = document.createElement('button');
|
|
button.classList.add('chat-session-button');
|
|
button.id = `chatSession-${chatId}`;
|
|
button.innerText = `Chat ${chatId + 1}`; // Vorläufiger Name
|
|
button.addEventListener('click', () => {
|
|
loadChatHistory(chatId); // Lade den Chat-Verlauf und setze die aktuelle Chat-ID
|
|
currentChatId = chatId; // Setze die aktuelle Chat-ID auf die ausgewählte Chat-ID
|
|
});
|
|
|
|
// Löschen-Button
|
|
const deleteButton = document.createElement('button');
|
|
deleteButton.classList.add('delete-chat-button');
|
|
deleteButton.innerText = "✕";
|
|
deleteButton.addEventListener('click', (event) => {
|
|
event.stopPropagation(); // Verhindert, dass der Chat geladen wird, wenn auf Löschen geklickt wird
|
|
deleteChat(chatId, buttonContainer);
|
|
clearChat();
|
|
});
|
|
|
|
// Elemente hinzufügen
|
|
buttonContainer.appendChild(button);
|
|
buttonContainer.appendChild(deleteButton);
|
|
chatList.appendChild(buttonContainer);
|
|
}
|
|
|
|
function clearChat(){
|
|
const chatBox = document.getElementById('chatBox');
|
|
chatBox.innerHTML = ''; // Aktuellen Chat leeren
|
|
}
|
|
|
|
function loadChatHistory(chatId) {
|
|
const chatBox = document.getElementById('chatBox');
|
|
chatBox.innerHTML = ''; // Aktuellen Chat leeren
|
|
|
|
if (currentChatId === null) {
|
|
return; // Wenn kein Chat ausgewählt ist, nichts laden
|
|
}
|
|
|
|
const chatHistory = JSON.parse(localStorage.getItem(`chatHistory-${chatId}`)) || [];
|
|
chatHistory.forEach(entry => {
|
|
const messageElement = document.createElement('div');
|
|
messageElement.classList.add('chat-message', entry.role);
|
|
messageElement.innerHTML = renderMarkdown(entry.content);
|
|
chatBox.prepend(messageElement);
|
|
});
|
|
}
|
|
|
|
function deleteChat(chatId, buttonContainer) {
|
|
// Entferne den Chat-Verlauf aus dem LocalStorage
|
|
localStorage.removeItem(`chatHistory-${chatId}`);
|
|
// Entferne den Button aus der Sidebar
|
|
buttonContainer.remove();
|
|
}
|
|
|
|
// Lade alle Chat-Sitzungen beim Start
|
|
function loadAllChatSessions() {
|
|
Object.keys(localStorage).forEach((key) => {
|
|
if (key.startsWith('chatHistory-')) {
|
|
const chatId = parseInt(key.split('-')[1], 10);
|
|
createChatSessionButton(chatId);
|
|
chatCount = Math.max(chatCount, chatId + 1); // Chat-Zähler aktualisieren
|
|
}
|
|
});
|
|
|
|
for (let i = 0; i < chatCount; i++) {// Aktualisiere die Namen an der Seite
|
|
updateChatSessionButton(i);
|
|
}
|
|
// Lade den neuesten Chat-Verlauf
|
|
if (chatCount > 0) {
|
|
loadChatHistory(chatCount - 1);
|
|
currentChatId = chatCount - 1; // Setze die aktuelle Chat-ID
|
|
} else {
|
|
const chatBox = document.getElementById('chatBox');
|
|
chatBox.innerHTML = ''; // Chat-Box leer, wenn keine Chats existieren
|
|
}
|
|
}
|
|
|
|
// Beim Laden der Seite alle Chat-Sitzungen laden
|
|
window.addEventListener('DOMContentLoaded', loadAllChatSessions);
|
|
|
|
const chatInput = document.getElementById('chatInput');
|
|
|
|
// Event-Listener für das Senden der Nachricht und das Erstellen eines Zeilenumbruchs
|
|
chatInput.addEventListener('keydown', (event) => {
|
|
if (event.key === 'Enter') {
|
|
if (currentChatId == null){
|
|
createNewChat();
|
|
}
|
|
|
|
// Prüfen, ob die Shift-Taste nicht gedrückt wird
|
|
if (!event.shiftKey) {
|
|
event.preventDefault(); // Verhindert das Standardverhalten (Absenden des Formulars)
|
|
const messageText = chatInput.value.trim();
|
|
if (messageText !== '' && currentChatId !== null) {
|
|
const messageElement = document.createElement('div');
|
|
messageElement.classList.add('chat-message', 'user');
|
|
messageElement.innerText = messageText;
|
|
document.getElementById('chatBox').prepend(messageElement);
|
|
|
|
// Nachricht speichern
|
|
saveMessage(currentChatId, messageText);
|
|
|
|
// Sidebar-Button für den Chat-Verlauf erstellen, falls noch nicht vorhanden
|
|
if (document.getElementById(`chatSession-${currentChatId}`) === null) {
|
|
createChatSessionButton(currentChatId);
|
|
}
|
|
|
|
chatInput.value = ''; // Input-Feld leeren
|
|
}
|
|
} else {
|
|
// Shift + Enter: Zeilenumbruch
|
|
chatInput.value += '\n'; // Zeilenumbruch in das Textfeld einfügen
|
|
}
|
|
}
|
|
});
|
|
|
|
/* OpenAI zeug */
|
|
|
|
async function getModels() {
|
|
|
|
try {
|
|
const response = await fetch(`http://localhost:8015/v1/models`, {
|
|
method: 'GET',
|
|
headers: {
|
|
'Authorization': `Bearer YOUR_API_KEY`,
|
|
'Content-Type': 'application/json',
|
|
}
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
const models = await response.json();
|
|
return models.data[0].id
|
|
|
|
} catch (error) {
|
|
if (error.message.includes('502')) {
|
|
showAlert("Server Error: 502 \nMaybe the LLM is offline?")
|
|
console.error('Bad Gateway: The server is acting as a gateway or proxy and received an invalid response from the upstream server.');
|
|
} else {
|
|
// Handle other errors here
|
|
console.error('Error fetching models:', error);
|
|
}
|
|
}
|
|
}
|
|
|
|
function getAllCurrentChatMessages() {
|
|
const cookieData = JSON.parse(localStorage.getItem(`chatHistory-${currentChatId}`)) || [];
|
|
return cookieData
|
|
}
|
|
|
|
|
|
function getLastUserMessage() {
|
|
// Lade die Cookie-Daten (ersetze dies durch den tatsächlichen Weg zur Cookie-Datenstruktur)
|
|
const cookieData = JSON.parse(localStorage.getItem(`chatHistory-${currentChatId}`)) || [];
|
|
|
|
|
|
// Filter nur die User-Nachrichten heraus
|
|
const userMessages = cookieData.filter(message => message.role === "user");
|
|
|
|
// Falls es User-Nachrichten gibt, die letzte davon zurückgeben
|
|
if (userMessages.length > 0) {
|
|
return userMessages[userMessages.length - 1].content;
|
|
}
|
|
|
|
return ''; // Rückgabe eines leeren Strings, falls keine Nachricht gefunden wird
|
|
}
|
|
|
|
function renderMarkdown(content) {
|
|
return marked.parse(content);
|
|
}
|
|
|
|
async function stream_api_open_ai(userMessage) {
|
|
// Neues div-Element für die Antwort des Chatbots erstellen
|
|
const chatBox = document.getElementById('chatBox');
|
|
const botMessageDiv = document.createElement('div');
|
|
botMessageDiv.className = 'chat-message assistant';
|
|
chatBox.prepend(botMessageDiv);
|
|
|
|
let send_message_system = [{ role: "system", content: "You are a knowledgeable assistant." }];
|
|
let send_message_user = getAllCurrentChatMessages();
|
|
let send_message_final = send_message_system.concat(send_message_user)
|
|
console.log(send_message_final)
|
|
|
|
const response = await fetch('http://localhost:8015/v1/chat/completions', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'Authorization': `Bearer YOUR_API_KEY`,
|
|
},
|
|
body: JSON.stringify({
|
|
model: await getModels(),
|
|
messages: send_message_final,
|
|
stream: true,
|
|
temperature: 0.3
|
|
})
|
|
});
|
|
|
|
const reader = response.body.getReader();
|
|
const decoder = new TextDecoder('utf-8');
|
|
|
|
let result = '';
|
|
while (true) {
|
|
const { done, value } = await reader.read();
|
|
if (done) break;
|
|
|
|
const chunk = decoder.decode(value, { stream: true });
|
|
const lines = chunk.split('\n');
|
|
|
|
for (const line of lines) {
|
|
if (line && line.includes('data: ')) {
|
|
const jsonStr = line.replace('data: ', '').trim();
|
|
|
|
if (jsonStr === '[DONE]'){
|
|
break;
|
|
}
|
|
|
|
try {
|
|
const json = JSON.parse(jsonStr);
|
|
if (json.choices[0].delta.content) {
|
|
const token = json.choices[0].delta.content;
|
|
result += token;
|
|
|
|
if (useMarkdown) {
|
|
botMessageDiv.innerHTML = renderMarkdown(result);
|
|
} else {
|
|
botMessageDiv.textContent = result;
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('Error parsing JSON:', error, 'Received:', jsonStr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
function formatArrayToCustomString(array) {
|
|
return '[' +
|
|
array.map(dict => {
|
|
return '{' +
|
|
Object.entries(dict)
|
|
.map(([key, value]) => `'${key}':'${value}'`)
|
|
.join(', ') +
|
|
'}';
|
|
}).join(', ') +
|
|
']';
|
|
}
|
|
|
|
// Tokenizer
|
|
async function tokenize_api_open_ai() {
|
|
|
|
let send_message_system = [{ role: "system", content: "You are a knowledgeable assistant." }];
|
|
let send_message_user = getAllCurrentChatMessages();
|
|
let send_message_final = send_message_system.concat(send_message_user)
|
|
let formattedString = `"${formatArrayToCustomString(send_message_final)}"`;
|
|
console.log(formattedString)
|
|
|
|
const response = await fetch('http://localhost:8015/tokenize', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'Authorization': `Bearer YOUR_API_KEY`,
|
|
},
|
|
body: JSON.stringify({
|
|
model: await getModels(),
|
|
prompt: formattedString,
|
|
add_special_tokens: true
|
|
})
|
|
});
|
|
// Check if the response is successful
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
const json = await response.json(); // Await the response.json() promise
|
|
|
|
console.log(json); // Log the parsed JSON response
|
|
return json
|
|
|
|
}
|
|
|
|
// Progress Bar
|
|
|
|
// Function to update the progress bar
|
|
function updateProgressBar(currentUsage, maxUsage) {
|
|
const percentage = (currentUsage / maxUsage) * 100;
|
|
|
|
// Update the width of the progress bar
|
|
const progressBar = document.getElementById('progress-bar');
|
|
progressBar.style.width = `${percentage}%`;
|
|
|
|
// Update the text
|
|
const usageText = document.getElementById('usage-text');
|
|
usageText.innerText = `${currentUsage} / ${maxUsage} used`;
|
|
} |