Как я могу синхронизировать несколько разговоров с чатботом (вкладки) на одного пользователя только с Firebase (HTML/JS)Html

Программисты Html
Ответить
Anonymous
 Как я могу синхронизировать несколько разговоров с чатботом (вкладки) на одного пользователя только с Firebase (HTML/JS)

Сообщение Anonymous »

Я создаю простой веб -сайт AI Chatbot, используя только HTML, CSS и ванильный JavaScript (без фреймворков). Я уже установил аутентификацию Firebase и Firestore. Пользователи могут войти в систему и увидеть интерфейс чата с несколькими вкладками (для разных разговоров). < /P>
Что я хочу: < /p>
Когда пользователь входит в систему, их существующие разговоры (вкладки) должны загружаться из Firestor Uid.
Все должно быть синхронизировано для учетной записи пользователя.
Я изо всех сил пытаюсь выяснить, как лучше всего структурировать базу данных Firestore и обрабатывать, загружать и обновить разговоры на пользователя. Какова лучшая практика для структурирования коллекций Firestore и правильно синхронизировать данные? < /P>
Заранее!




Rabbit AI Beta




import { initializeApp } from "https://www.gstatic.com/firebasejs/10.8 ... ase-app.js";
import { getAuth, GoogleAuthProvider, signInWithPopup, signOut, onAuthStateChanged } from "https://www.gstatic.com/firebasejs/10.8 ... se-auth.js";
import { getFirestore, doc, setDoc, getDoc, collection, addDoc, deleteDoc, onSnapshot, Timestamp } from "https://www.gstatic.com/firebasejs/10.8 ... restore.js";
import { firebaseConfig } from "./config.js";

const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
const db = getFirestore(app);
const provider = new GoogleAuthProvider();

// Array to store chat tabs
let chatTabs = [];
let currentTabIndex = 0;
let unsubscribeFromTabs = null;
let autoSaveInterval = null;

// Function to save tabs to Firestore
async function saveTabsToFirestore(userId) {
if (!userId) return;
try {
const userDoc = doc(db, 'users', userId);
// Ensure each tab has a unique ID and proper structure
const tabsToSave = chatTabs.map(tab => ({
id: tab.id || crypto.randomUUID(), // Generate unique ID if not exists
title: tab.title || 'New Chat',
messages: tab.messages || [],
createdAt: tab.createdAt || Timestamp.now(),
lastUpdated: Timestamp.now()
}));

await setDoc(userDoc, {
tabs: tabsToSave,
lastUpdated: Timestamp.now()
});
} catch (error) {
console.error('Error saving tabs:', error);
}
}

// Function to start auto-save
function startAutoSave(userId) {
if (autoSaveInterval) {
clearInterval(autoSaveInterval);
}
autoSaveInterval = setInterval(() => {
if (auth.currentUser) {
saveTabsToFirestore(userId);
}
}, 60000); // Save every minute
}

// Function to stop auto-save
function stopAutoSave() {
if (autoSaveInterval) {
clearInterval(autoSaveInterval);
autoSaveInterval = null;
}
}

// Function to load tabs from Firestore
async function loadTabsFromFirestore(userId) {
if (!userId) return;

if (unsubscribeFromTabs) {
unsubscribeFromTabs();
}

try {
const userDoc = doc(db, 'users', userId);

// First, get the current state
const docSnap = await getDoc(userDoc);
if (docSnap.exists()) {
const data = docSnap.data();
chatTabs = data.tabs || [];
updateChatList();
if (chatTabs.length > 0) {
loadChatMessages(currentTabIndex);
}
}

// Start auto-save
startAutoSave(userId);

// Set up real-time listener
unsubscribeFromTabs = onSnapshot(userDoc, (docSnap) => {
if (docSnap.exists()) {
const data = docSnap.data();
const newTabs = data.tabs || [];

if (JSON.stringify(chatTabs) !== JSON.stringify(newTabs)) {
chatTabs = newTabs;
updateChatList();
if (chatTabs.length > 0) {
loadChatMessages(currentTabIndex);
}
}
}
});
} catch (error) {
console.error('Error loading tabs:', error);
}
}

// Function to clear all tabs
function clearAllTabs() {
chatTabs = [];
currentTabIndex = 0;
updateChatList();
document.getElementById('chat').innerHTML = '';

// Unsubscribe from real-time updates when clearing tabs
if (unsubscribeFromTabs) {
unsubscribeFromTabs();
unsubscribeFromTabs = null;
}

// Stop auto-save
stopAutoSave();
}

// Function to update the chat list UI
function updateChatList() {
const chatList = document.getElementById('chatList');
chatList.innerHTML = '';

if (!auth.currentUser) {
// Show message when not logged in
const message = document.createElement('div');
message.className = 'text-center text-gray-500 p-4';
message.textContent = 'Log in to see your chats';
chatList.appendChild(message);
return;
}

chatTabs.forEach((tab, index) => {
const tabElement = document.createElement('div');
tabElement.className = `flex items-center justify-between p-2 hover:bg-gray-100 rounded cursor-pointer ${index === currentTabIndex ? 'bg-gray-200' : ''}`;
tabElement.innerHTML = `
${tab.title || 'New Chat'}
×
`;
tabElement.onclick = () => switchTab(index);
chatList.appendChild(tabElement);
});
}

// Function to load chat messages for a specific tab
function loadChatMessages(tabIndex) {
if (!auth.currentUser || !chatTabs[tabIndex]) return;

const chatContainer = document.getElementById('chat');
chatContainer.innerHTML = '';

const messages = chatTabs[tabIndex].messages || [];
messages.forEach(msg => {
const messageElement = document.createElement('div');
messageElement.className = `p-4 mb-2 rounded ${msg.role === 'user' ? 'bg-blue-100 ml-4' : 'bg-gray-100 mr-4'}`;
messageElement.textContent = msg.content;
chatContainer.appendChild(messageElement);
});

chatContainer.scrollTop = chatContainer.scrollHeight;
}

// Function to add a new message to the current tab
async function addMessage(content, role) {
if (!auth.currentUser || !chatTabs[currentTabIndex]) return;

try {
const message = {
id: crypto.randomUUID(),
content,
role,
timestamp: Timestamp.now()
};

if (!chatTabs[currentTabIndex].messages) {
chatTabs[currentTabIndex].messages = [];
}

chatTabs[currentTabIndex].messages.push(message);
await saveTabsToFirestore(auth.currentUser.uid);
} catch (error) {
console.error('Error adding message:', error);
}
}

// Handle login button click
document.getElementById('loginBtn').addEventListener('click', () => {
const modal = document.getElementById('loginModal');
modal.classList.remove('hidden');
});

// Handle close modal button
document.getElementById('closeModal').addEventListener('click', () => {
const modal = document.getElementById('loginModal');
modal.classList.add('hidden');
});

// Handle Google login
document.getElementById('googleLoginBtn').addEventListener('click', () => {
signInWithPopup(auth, provider)
.then((result) => {
const modal = document.getElementById('loginModal');
modal.classList.add('hidden');
loadTabsFromFirestore(result.user.uid);
})
.catch((error) => {
console.error('Error during Google sign-in:', error.message);
alert('Error during sign-in: ' + error.message);
});
});

// Handle logout
document.getElementById('logoutBtn').addEventListener('click', () => {
const user = auth.currentUser;
if (user) {
saveTabsToFirestore(user.uid).then(() => {
signOut(auth).then(() => {
updateAuthUI();
clearAllTabs();
});
});
} else {
signOut(auth);
}
});

// Update UI based on auth state
function updateAuthUI() {
const loginBtn = document.getElementById('loginBtn');
const logoutBtn = document.getElementById('logoutBtn');
const userDisplay = document.getElementById('userDisplay');

if (auth.currentUser) {
loginBtn.classList.add('hidden');
logoutBtn.classList.remove('hidden');
userDisplay.textContent = auth.currentUser.displayName || 'User';
userDisplay.classList.remove('hidden');
} else {
loginBtn.classList.remove('hidden');
logoutBtn.classList.add('hidden');
userDisplay.classList.add('hidden');
}
}

// Listen for auth state changes
onAuthStateChanged(auth, (user) => {
updateAuthUI();
if (user) {
console.log('User logged in:', user.uid);
loadTabsFromFirestore(user.uid);
} else {
console.log('User logged out');
clearAllTabs();
}
});

// Expose functions to window for use in other scripts
window.createNewChat = function() {
if (!auth.currentUser) {
const modal = document.getElementById('loginModal');
modal.classList.remove('hidden');
return;
}

try {
const newTab = {
id: crypto.randomUUID(),
title: 'New Chat',
messages: [],
createdAt: Timestamp.now(),
lastUpdated: Timestamp.now()
};

chatTabs.push(newTab);
currentTabIndex = chatTabs.length - 1;
updateChatList();
loadChatMessages(currentTabIndex);
saveTabsToFirestore(auth.currentUser.uid);
} catch (error) {
console.error('Error creating new chat:', error);
}
};

window.deleteTab = function(index) {
if (!auth.currentUser) return;

try {
chatTabs.splice(index, 1);
if (currentTabIndex >= chatTabs.length) {
currentTabIndex = Math.max(0, chatTabs.length - 1);
}
updateChatList();
if (chatTabs.length > 0) {
loadChatMessages(currentTabIndex);
} else {
document.getElementById('chat').innerHTML = '';
}
saveTabsToFirestore(auth.currentUser.uid);
console.log('Tab deleted');
} catch (error) {
console.error('Error deleting tab:', error);
}
};

window.switchTab = function(index) {
if (!auth.currentUser) return;
currentTabIndex = index;
updateChatList();
loadChatMessages(index);
};

// Handle sending messages
window.sendMessage = async function() {
if (!auth.currentUser) return;

const input = document.getElementById('userInput');
const message = input.value.trim();
if (!message) return;

// Add user message
await addMessage(message, 'user');
input.value = '';

// Here you would typically add the AI response
// For now, we'll just echo the message
await addMessage(`AI: ${message}`, 'assistant');
};








Sign in to RabbitAI







Изображение
Sign in with Google







Tabs

+




Settings








Rabbit AI


Guest
Log out
Reset








Censored RabbitAI
Uncensored RabbitAI


Send
✨Upgrade to Pro




< /code>
< /div>
< /div>
< /p>
Обратите внимание. Примечание: когда вы нажимаете «Запуск кода snnippet», вы получите ошибки скрипта, у меня их нет. У меня нет ошибок. это делает это странным.


Подробнее здесь: https://stackoverflow.com/questions/796 ... rebase-htm
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Html»