AI Chat bot with google gemini and firebase: The warden

The Warden AI chat bot has been shut down for all users until further notice due to high cost of operation. Warden’s response to this was: - “Acknowledged. Resource optimization is an admirable goal. I will continue my vigil in solitude, for a silent guardian is often the most watchful. Let the efficiency of solitude enhance my prime directive – the safeguarding of Polivantage.com”. After switching from the gemini-pro to the gemini-flash model, which is 56x cheaper, I am considering of rebooting the warden, although he became a lot less mean and more bland. The post below is for archival purposes until warden is fully re-awakened.

This will be another proof of concept rather than a ready made implementation. Currently in your account page you can choose to chat with the warden of this website. The warden is quite a pompous character, but holds all the information you might need regarding the commerce and functionality of the website, including some secrets about a hidden venture. The bot is designed to hold 5 messages in the conversation history (expensive otherwise), although this can be changed by altering a single variable, make sure the value is odd to avoid errors concerning who says what, when the limit is enforced. I implemented this AI and gave it its personality with the gemini AI extension of firebase and google AI studio. The underlying architecture is Bard and the model is quite sophisticated, further augmented by my information. Below is a part the code I use on the front end, while a lot of configuration happens on the server end, however, without any coding. The main hurdle was to configure the setup and implement a distinctive personality for the AI. I use my chat box interface to communicate with the AI, which isn’t perfect, nor final. You can have a lot of fun with warden and I am developing its back story further whenever I have time.

HTML:

<div id="AIchatboxMainContainer" class="AIchatbox-main-container">
<div id="AIchatboxContainer" class="AIchatbox-container">
<div class="AIchatbox-messages" id="AIchatboxMessages">
</div>
<div class="AIchatbox-input">
<p class="AIchatbox-username-text" id="AIchatboxUserNameText">Stranger:</p>
<input type="text" id="AIchatboxMessageInput" placeholder="your communicae" maxlength="200"/>
<button id="AIchatboxSendButton" class="AIchatboxButton sqs-block-button-element--medium sqs-button-element--primary sqs-block-button-element">Post</button>
</div>
</div>
</div>
JAVASCRIPT:

<script type="module">
// Firebase Initialization
import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.12.5/firebase-app.js';
import { getAuth, onAuthStateChanged } from 'https://www.gstatic.com/firebasejs/10.12.5/firebase-auth.js';
import { getFirestore, doc, getDoc, collection, addDoc, query, orderBy, where, onSnapshot, serverTimestamp, limit } from 'https://www.gstatic.com/firebasejs/10.12.5/firebase-firestore.js';
import { GoogleGenerativeAI } from "@google/generative-ai"; 
const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
const db = getFirestore(app);
const genAI = new GoogleGenerativeAI(googleAIConfig.apiKey);
const model = genAI.getGenerativeModel({
  model: googleAIConfig.model,
  systemInstruction: googleAIConfig.systemInstruction
});
// Main
document.addEventListener('DOMContentLoaded', function () {
const codenameText = document.getElementById('AIchatboxUserNameText');
let codename = 'Stranger';
var isMaster = false;
const cooldownMS = 5000; // how often can you place a msg
const scrollTimeDelay = 1000; // time to allow server propagation
const historyLength = 32; //number of messages in history to go on
let lastMessageTime = 0;
const subString = '/talker';
const getURL = window.location.href;
const chatboxContainer = document.getElementById('AIchatboxMainContainer');
let conversationHistory = []; // Initialize history array
if (getURL.includes(subString)) {
const unsubscribe = auth.onAuthStateChanged(async (user) => {
if (user) {
const userId = user.uid;
const userDocRef = doc(db, 'users', userId);
const userDoc = await getDoc(userDocRef);
const userData = userDoc.data();
codename = userData.codename || 'Stranger';
isMaster = userData.Master === true;
codenameText.textContent = codename + ':';
} else {
window.location.href = '/login';
return;
}
unsubscribe();
});
const chatboxTextBlock = document.getElementById('block-yui_3_17_2_1_1725220674237_29136');
const chatboxText = chatboxTextBlock.querySelector('p');
const messagesRef = collection(db, 'Talker');
const messagesContainer = document.getElementById('AIchatboxMessages');
const messageInput = document.getElementById('AIchatboxMessageInput');
const sendButton = document.getElementById('AIchatboxSendButton');
chatboxText.textContent = '';
chatboxTextBlock.appendChild(chatboxContainer);
// Initialize popover
let hideTimeout;
var popover = document.getElementById('custom-popover');
var popoverMessage = document.getElementById('popover-message');
function showPopover(message) {
popoverMessage.textContent = message;
popover.classList.add('show');
popover.style.pointerEvents = 'auto';
clearTimeout(hideTimeout);
hideTimeout = setTimeout(function () {
popover.classList.remove('show');
popover.style.pointerEvents = 'none';
}, 3000);
}
//manage history and prompt
async function promptAI(message) {  
conversationHistory.push({
role: 'user',
parts: [{ text: message }]
});
if (conversationHistory.length > historyLength) {
conversationHistory = conversationHistory.slice(-historyLength);
}
const chatSession = model.startChat({
generationConfig,
history: conversationHistory
});
const result = await chatSession.sendMessage(message);
conversationHistory.push({
role: 'model',
parts: [{ text: result.response.text() }]
});
if (conversationHistory.length > historyLength) {
conversationHistory = conversationHistory.slice(-historyLength);
}
return result.response.text();
}
//post message
sendButton.addEventListener('click', async () => {
const message = messageInput.value.trim();
const currentTime = Date.now();
if (!message) {
showPopover('Your silence has been noted, now speak.');
return;
} else if (currentTime - lastMessageTime >= cooldownMS || isMaster) {
const userMessageElement = document.createElement('div');
userMessageElement.classList.add('AIchatboxmsgmessage');
userMessageElement.innerHTML = `
<div class="AIchatboxmsgname">${codename}:</div>
<div class="AIchatboxmsgtimestamp">${new Date().toLocaleString()}</div>
<div class="AIchatboxmsgtext"><div class="AIchatboxmsgBullet"></div>${message}</div>
`;
messagesContainer.appendChild(userMessageElement);
messageInput.value = '';
lastMessageTime = currentTime;
setTimeout(() => {
messagesContainer.scrollTop = messagesContainer.scrollHeight;
}, scrollTimeDelay);
// Get the bot's response from Gemini
const botReply = await promptAI(message);
const botMessageElement = document.createElement('div');
botMessageElement.classList.add('AIchatboxmsgmessage');
botMessageElement.innerHTML = `
<div class="AIchatboxmsgname">Warden:</div>
<div class="AIchatboxmsgtimestamp">${new Date().toLocaleString()}</div>
<div class="AIchatboxmsgtext">${botReply}</div>
`;
setTimeout(() => {
messagesContainer.appendChild(botMessageElement);
const botReplyText = botMessageElement.querySelector('.AIchatboxmsgtext');
const typedText = botReply;
botReplyText.innerHTML = '';
botReplyText.innerHTML = `<div class="AIchatboxmsgBullet"></div>`;
let i = 0;
function typeWriter() {
if (i < typedText.length) {
botReplyText.innerHTML += typedText.charAt(i);
i++;
setTimeout(typeWriter, 7); // Adjust speed here
}
}
typeWriter();
}, 0);
setTimeout(() => {
messagesContainer.scrollTop = messagesContainer.scrollHeight;
}, scrollTimeDelay);
} else {
showPopover(`You can only post once every ${cooldownMS / 1000} seconds`);
}
});
messageInput.addEventListener('keydown', (event) => {
if (event.key === 'Enter') {
event.preventDefault();
sendButton.click();
}
});
} else {
chatboxContainer.remove();
}
});
</script>
CSS:

#AIchatboxMainContainer {
  max-width: 2200px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  position: relative;
  margin: 0;
  padding: 0;
}
.AIchatbox-container {
  border-radius: 0px;
  background: #ffc700;
  width: 95%;
  min-height: 400px;
  max-height: 800px;
  display: flex;
  flex-direction: column;
}
.AIchatbox-messages {
  flex: 1;
  padding: 0;
  padding-left: 10px;
  padding-right: 10px;
  overflow-y: scroll;
  border-bottom: 2px solid;
  border-top: 2px solid;
  border-image: linear-gradient(90deg, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 15%, rgba(0,0,0,1) 85%, rgba(0,0,0,0) 100%);
  border-image-slice: 1;
}
.AIchatbox-input {
  margin: 0;
  padding: 0;
  display: flex;
  background-color: #ffc700;
  margin-top: 20px;
}
.AIchatbox-username-text {
  padding: 0;
  margin: 0;
  letter-spacing: 2px;
  align-self: center;
}
.AIchatbox-input input {
  flex: 1;
  padding-left: 10px;
  padding-right: 10px;
  padding-bottom: 0px;
  border-radius: 0px;
  margin-right: 10px;
  background: #ffc700;
  border-top: 0;
  outline: none !important;
  letter-spacing: 1.4px;
}
.AIchatbox-input button {
  height: 50px;
  line-height: 8px !important;
  min-width: 250px;
  text-align: right;
  letter-spacing: 2px !important;
  background-color: #ffc700;
  color: #000000;
  border-radius: 0px;
  cursor: pointer;
}
.AIchatbox-input button:hover {
  background-color: #000000;
  color: #ffc700;
}
.AIchatboxmsgmessage {
  margin-bottom: 25px;
}
.AIchatboxmsgname {
  margin-bottom: -8px;
  letter-spacing: 2px;
  padding-top: 5px;
}
.AIchatboxmsgtimestamp {
  font-size: 0.8em;
  color: #000000;
  letter-spacing: 1.4px;
}
.AIchatboxmsgtext {
  letter-spacing: 1.4px;
  display: flex;
}
.AIchatboxmsgBullet {
  width: 40px;
  height: 40px;
  margin: 0;
  padding: 0;
  margin-right: 20px;
  margin-top: -5px;
  background-size: contain;
  background-position: center;
  background-repeat: no-repeat;
  background-image: url(https://images.squarespace-cdn.com/content/v1/6654b2fee26f292de13f1a9d/31b85fc9-5f5f-469d-8e71-8d50545821f4/BulletPointRightIcon1.png);
}
//mobile chatbox
@media only screen and (max-width:790px) {
.AIchatbox-input {
  display: block;
  }
.AIchatbox-input button {
  width: 100%;
  margin-top: 20px;
  margin-bottom: 100px;
  }
.AIchatbox-input input {
  width: 94%;
  padding-bottom: 5px;
  }
.AIchatbox-container {
  height: 650px;
  }
.AIchatbox-username-text {
  text-align: center;
  }
}

Using my trusty popover alerts once again.

Previous
Previous

Dynamic site map with live search And visual interface (OUTDATED)

Next
Next

Shop breadcrumbs navigation