add experimental chat

This commit is contained in:
Pritimay Sarkar
2024-01-26 23:02:43 +05:30
parent b69791c246
commit 3e4f08b90e
6 changed files with 2020 additions and 44 deletions

42
src/components/Gemini.css Normal file
View File

@@ -0,0 +1,42 @@
.user-chat-input {
margin: 10px;
}
.user-message {
background-color: #aaffaa;
padding: 5px;
margin: 5px;
border-radius: 5px;
}
.other-message {
background-color: #aaaaff;
padding: 5px;
margin: 5px;
border-radius: 5px;
}
.typing-animation {
overflow: hidden; /* Hide overflowing text */
border-right: 0.1em solid #000; /* Add a border to simulate the cursor */
white-space: nowrap; /* Ensure the text stays in one line */
animation: typing 1s steps(40, end), blink-caret 0.5s step-end infinite; /* Typing animation */
}
@keyframes typing {
from {
width: 0;
}
to {
width: 100%;
}
}
@keyframes blink-caret {
from, to {
border-color: transparent; /* Blinking cursor effect */
}
50% {
border-color: #000;
}
}

155
src/components/Gemini.js Normal file
View File

@@ -0,0 +1,155 @@
import React, { useState, useEffect, useRef } from 'react';
import { query, collection, onSnapshot, addDoc, where, getDocs, orderBy } from 'firebase/firestore';
import ReactMarkdown from 'react-markdown';
import './Gemini.css'; // Make sure to have your CSS styles for the typewriter effect
import db from '../firebase';
function Gemini() {
const [messages, setMessages] = useState([]);
const [newMessage, setNewMessage] = useState('');
const [isTyping, setIsTyping] = useState(false);
const scrollRef = useRef(null);
useEffect(() => {
const loadChatHistory = async () => {
const uid = 'uid'; // Replace with your user ID
const discussionId = 'discussionId'; // Replace with your discussion ID
const collectionPath = `users/${uid}/discussions/${discussionId}/messages`;
const q = query(collection(db, collectionPath), orderBy('createTime'));
try {
const querySnapshot = await getDocs(q);
const loadedMessages = [];
querySnapshot.forEach((doc) => {
const data = doc.data();
loadedMessages.push({ text: data.prompt, sender: 'user' });
if (data.response) {
// Simulate delay for typewriter effect
setTimeout(() => {
// Update the state with the Gemini's response
setMessages((prevMessages) => [
...prevMessages,
{ text: data.response, sender: 'gemini' },
]);
if (scrollRef.current) {
// alert(scrollRef.current.scrollHeight)
scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
}
}, 1000); // You can adjust the delay as needed
}
});
// Sort the messages by createTime before updating the state
// loadedMessages.sort((a, b) => a.createTime - b.createTime);
setMessages(loadedMessages);
// Scroll to the bottom
if (scrollRef.current) {
// alert(scrollRef.current.scrollHeight)
scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
}
} catch (error) {
console.error('Error loading chat history:', error);
}
};
loadChatHistory();
}, []); // Empty dependency array ensures the effect runs only once on component mount
const handleSendMessage = async () => {
if (newMessage.trim() === '') return;
const uid = 'uid'; // Replace with your user ID
const discussionId = 'discussionId'; // Replace with your discussion ID
const collectionPath = `users/${uid}/discussions/${discussionId}/messages`;
const collectionRef = collection(db, collectionPath);
// Add user's message to the local state first
setMessages([...messages, { text: newMessage, sender: 'user' }]);
setNewMessage('');
// Then, add the user's message to the Firestore collection
// Your existing code for adding user's message remains unchanged
const docRef = await addDoc(collectionRef, {
prompt: newMessage,
});
// Listen for changes in the Firestore document
const unsub = onSnapshot(docRef, (doc) => {
const data = doc.data();
if (data && data.response) {
// Start typewriter animation
// setIsTyping(true);
// Simulate delay for typewriter effect
setTimeout(() => {
// Update the state with the Gemini's response
setMessages((prevMessages) => [...prevMessages, { text: data.response, sender: 'gemini' }]);
// Stop typewriter animation
// setIsTyping(false);
// Scroll to the bottom
if (scrollRef.current) {
scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
}
}, 1000); // You can adjust the delay as needed
}
});
if (scrollRef.current) {
scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
}
};
return (
<div>
<div style={{ height: '500px', overflowY: 'scroll', border: '1px solid #ccc' }} ref={scrollRef}>
{messages.map((message, index) => (
<div key={index} className={message.sender === 'user' ? 'user-message' : 'other-message'}>
{message.sender === 'gemini' && isTyping ? (
// Display typing animation for Gemini's response
<div className="typing-animation">Gemini is typing...</div>
) : (
// Display the actual message
<ReactMarkdown>{message.text}</ReactMarkdown>
)}
</div>
))}
</div>
<div className="user-chat-input">
<input
type="text"
value={newMessage}
onChange={(e) => setNewMessage(e.target.value)}
placeholder="Type your message..."
style={{ marginRight: '8px', padding: '8px', fontSize: '16px', width: '50vw' }}
/>
<button
onClick={handleSendMessage}
style={{
backgroundColor: '#4CAF50',
color: 'white',
padding: '10px 20px',
border: 'none',
borderRadius: '4px',
cursor: 'pointer',
fontSize: '16px',
}}
>
Send
</button>
</div>
</div>
);
}
export default Gemini;