chatbotv2 / index.html
sahil239's picture
Upload 5 files
2ee1461 verified
raw
history blame
20.1 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Tap Bot</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/showdown.min.js"></script>
<style>
body {
margin: 0;
padding: 0;
font-family: 'Segoe UI', sans-serif;
background: linear-gradient(-45deg, #1f1c2c, #928dab, #2b5876, #4e4376);
background-size: 400% 400%;
animation: gradientBG 15s ease infinite;
color: #fff;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 100vh;
text-align: center;
}
@keyframes gradientBG {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}
h1 {
font-size: 3em;
margin-bottom: 0.3em;
}
.store-buttons {
display: flex;
gap: 20px;
flex-wrap: wrap;
justify-content: center;
margin: 20px 0;
}
.store-buttons img {
width: 160px;
height: auto;
}
.try-btn {
background-color: #fff;
color: #2980b9;
border: none;
padding: 10px 20px;
font-size: 1.2em;
border-radius: 8px;
cursor: pointer;
transition: 0.3s ease;
}
.try-btn:hover {
background-color: #e0e0e0;
}
.chat-container {
position: fixed;
bottom: 20px;
right: 20px;
background: white;
color: black;
border-radius: 12px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
width: 350px;
height: 500px;
max-height: 90vh;
overflow: hidden;
display: none;
flex-direction: column;
/* Animation styles */
transform: scale(0);
opacity: 0;
transition: transform 0.3s ease, opacity 0.3s ease;
pointer-events: none;
}
.chat-container.open {
transform: scale(1);
opacity: 1;
pointer-events: auto;
}
.chat-header {
background-color: #2980b9;
color: white;
padding: 10px;
font-weight: bold;
display: flex;
justify-content: space-between;
align-items: center;
}
.chat-body {
padding: 10px;
overflow-y: auto;
flex-grow: 1;
}
.chat-input {
display: flex;
border-top: 1px solid #ccc;
}
.chat-input input {
flex-grow: 1;
border: none;
padding: 10px;
font-size: 1em;
}
.chat-input button {
border: none;
padding: 10px 15px;
background-color: #2980b9;
color: white;
cursor: pointer;
}
.msg.user {
text-align: right;
margin: 5px 0;
}
.msg.bot {
text-align: left;
margin: 5px 0;
}
.msg .bubble {
display: inline-block;
padding: 10px;
border-radius: 10px;
max-width: 85%;
}
.msg.user .bubble {
background: #d1eaff;
color: #000;
}
.msg.bot .bubble {
background: #f1f1f1;
color: #000;
}
.bubble.typing {
font-style: italic;
}
.copy-btn {
background: none;
border: none;
cursor: pointer;
font-size: 1em;
margin-left: 6px;
color: #555;
float: right;
position: relative;
}
.copy-btn::after {
content: "Copy";
position: absolute;
bottom: 100%;
left: 50%;
transform: translateX(-50%);
background: #000;
color: #fff;
padding: 4px 8px;
font-size: 0.75em;
border-radius: 4px;
opacity: 0;
white-space: nowrap;
pointer-events: none;
transition: opacity 0.2s;
}
.copy-btn:hover::after {
opacity: 1;
}
.toast {
visibility: hidden;
min-width: 120px;
background-color: #333;
color: #fff;
text-align: center;
border-radius: 6px;
padding: 10px;
position: fixed;
z-index: 1;
left: 50%;
bottom: 30px;
transform: translateX(-50%);
font-size: 0.9em;
opacity: 0;
transition: opacity 0.5s, bottom 0.5s;
}
.toast.show {
visibility: visible;
opacity: 1;
bottom: 50px;
}
#typing {
display: flex;
padding: 5px;
font-style: italic;
color: #555;
align-items: center;
}
#typing span.dot {
height: 10px;
width: 10px;
margin: 0 3px;
background-color: #999;
border-radius: 50%;
display: inline-block;
animation: blink 1.4s infinite;
}
#typing span.dot:nth-child(2) {
animation-delay: 0.2s;
}
#typing span.dot:nth-child(3) {
animation-delay: 0.4s;
}
@keyframes blink {
0%, 80%, 100% {
opacity: 0.2;
transform: scale(0.8);
}
40% {
opacity: 1;
transform: scale(1);
}
}
footer {
margin-top: 40px;
font-size: 0.9em;
}
@media (max-width: 600px) {
.store-buttons {
flex-direction: column;
align-items: center;
}
}
</style>
</head>
<div id="toast" class="toast">Copied!</div>
<body>
<h1 id="welcomeTitle"></h1>
<p id="welcomeSub"></p>
<div class="store-buttons">
<a href="#"><img
src="https://upload.wikimedia.org/wikipedia/commons/thumb/7/78/Google_Play_Store_badge_EN.svg/512px-Google_Play_Store_badge_EN.svg.png"
alt="Google Play"></a>
<a href="#"><img src="https://developer.apple.com/assets/elements/badges/download-on-the-app-store.svg"
alt="App Store"></a>
</div>
<button class="try-btn" onclick="openChat()">Try Now</button>
<footer>
<p><strong>Disclaimer:</strong> Tap Bot is powered by a fine-tuned language model trained using publicly available
data. </p>
<p> We do not claim ownership of the original data sources used for training. </p>
<p> Developed by <a href="https://sahildesai.dev" target="_blank" style="color:#fff;text-decoration:underline;">sahildesai.dev</a>
</p>
</footer>
<div class="chat-container" id="chatBox">
<div class="chat-header"><span id="chatTitle"></span>
<div>
<button onclick="clearChat()" style="background:none; border:none; cursor:pointer;">
<svg xmlns="http://www.w3.org/2000/svg" height="20" width="20" fill="white" viewBox="0 0 24 24">
<path d="M3 6h18v2H3V6zm2 3h14l-1.5 12.5H6.5L5 9zm5.5-5h3v2h-3V4z"/>
</svg>
</button>
<button onclick="toggleChat()"
style="background:none;border:none;color:white;font-size:1.2em;cursor:pointer;">X
</button>
</div>
</div>
<div class="chat-body" id="chatMessages">
<div class="msg bot" id="welcomeMessage">
<div class="bubble">Hi there! I’m Tap Bot. How can I help you today?</div>
</div>
</div>
<div class="chat-input">
<input type="text" id="userInput" placeholder="What's on your mind?" oninput="toggleSendButton()"
onkeydown="handleEnter(event)"/>
<button id="sendBtn" onclick="submitMessage()" disabled>Send</button>
</div>
</div>
<script>
const botName = "Tap Bot";
document.addEventListener("DOMContentLoaded", () => {
document.getElementById("welcomeTitle").textContent = `Welcome to ${botName}!`;
document.getElementById("welcomeSub").textContent = `Your AI-powered assistant is live.`;
document.getElementById("chatTitle").textContent = botName;
});
function copyToClipboard(button) {
const text = button.previousElementSibling.textContent;
navigator.clipboard.writeText(text).then(() => {
button.textContent = "✅";
setTimeout(() => (button.textContent = "📋"), 1500);
});
}
function openChat() {
const box = document.getElementById("chatBox");
box.classList.add("open");
document.getElementById("chatMessages").innerHTML = "";
const chatMessages = document.getElementById("chatMessages");
box.style.display = "flex";
chatMessages.innerHTML = ''; // Clear on open
// Add typing dots
const botDiv = document.createElement("div");
botDiv.className = "msg bot";
const typingDiv = document.createElement("div");
typingDiv.className = "bubble typing";
typingDiv.innerHTML = `<div id="typing"><span class="dot"></span><span class="dot"></span><span class="dot"></span></div>`;
botDiv.appendChild(typingDiv);
chatMessages.appendChild(botDiv);
chatMessages.scrollTop = chatMessages.scrollHeight;
// After delay, show welcome message with typing
setTimeout(() => {
const welcomeText = "Hi there! I’m Tap Bot. How can I help you today?";
let i = 0;
typingDiv.innerHTML = "";
const textNode = document.createElement("div");
typingDiv.appendChild(textNode);
function typeChar() {
if (i < welcomeText.length) {
textNode.textContent += welcomeText[i++];
chatMessages.scrollTop = chatMessages.scrollHeight;
setTimeout(typeChar, 30);
}
}
typeChar();
}, 500);
}
function toggleChat() {
const box = document.getElementById("chatBox");
box.classList.toggle("open");
}
function clearChat() {
const chatMessages = document.getElementById("chatMessages");
chatMessages.innerHTML = "";
const welcome = document.createElement("div");
welcome.className = "msg bot";
welcome.id = "welcomeMessage";
welcome.innerHTML = `<div class="bubble">Hi there! I’m Tap Bot. How can I help you today?</div>`;
chatMessages.appendChild(welcome);
chatMessages.scrollTop = chatMessages.scrollHeight;
setTimeout(() => {
const welcomeText = "Hi there! I’m Tap Bot. How can I help you today?";
let i = 0;
typingDiv.innerHTML = "";
function typeChar() {
if (i < welcomeText.length) {
typingDiv.innerHTML += welcomeText[i++];
chatMessages.scrollTop = chatMessages.scrollHeight;
setTimeout(typeChar, 30);
}
}
typeChar();
}, 500);
}
function toggleSendButton() {
const btn = document.getElementById("sendBtn");
const input = document.getElementById("userInput");
btn.disabled = input.value.trim().length === 0;
}
function handleEnter(e) {
if (e.key === "Enter") {
e.preventDefault();
if (!document.getElementById("sendBtn").disabled) {
submitMessage();
}
}
}
function showToast(message = "Copied!") {
const toast = document.getElementById("toast");
toast.textContent = message;
toast.classList.add("show");
setTimeout(() => {
toast.classList.remove("show");
}, 2000); // 2 seconds
}
/* async function submitMessage() {
const input = document.getElementById("userInput");
const msg = input.value.trim();
if (!msg) return;
const chatMessages = document.getElementById("chatMessages");
const converter = new showdown.Converter();
// Append user message
const userDiv = document.createElement("div");
userDiv.className = "msg user";
userDiv.innerHTML = `<div class="bubble">${msg}</div>`;
chatMessages.appendChild(userDiv);
// Bot typing placeholder with animated dots
const botDiv = document.createElement("div");
botDiv.className = "msg bot";
const typingDiv = document.createElement("div");
typingDiv.className = "bubble typing";
const typingIndicator = document.createElement("div");
typingIndicator.id = "typing";
typingIndicator.innerHTML = `
<span class="dot"></span>
<span class="dot"></span>
<span class="dot"></span>
`;
typingDiv.appendChild(typingIndicator);
botDiv.appendChild(typingDiv);
chatMessages.appendChild(botDiv);
chatMessages.scrollTop = chatMessages.scrollHeight;
input.value = "";
toggleSendButton();
try {
const res = await fetch("/chat", {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({prompt: msg})
});
const data = await res.json();
const text = data.response;
// Replace the dots with actual typing text
typingDiv.removeChild(typingIndicator);
const textNode = document.createElement("div");
typingDiv.appendChild(textNode);
let i = 0;
function typeChar() {
if (i < text.length) {
textNode.textContent += text[i++];
chatMessages.scrollTop = chatMessages.scrollHeight;
setTimeout(typeChar, 20);
} else {
typingDiv.classList.remove("typing");
// Copy button
const copyBtn = document.createElement("button");
copyBtn.className = "copy-btn";
copyBtn.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" height="18" width="18" viewBox="0 0 24 24" fill="white" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2" />
<rect x="8" y="2" width="8" height="4" rx="1" ry="1"/>
</svg>`;
copyBtn.onclick = function () {
navigator.clipboard.writeText(textNode.textContent).then(() => {
showToast("Copied!")
copyBtn.textContent = "✅";
setTimeout(() => (copyBtn.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" height="18" width="18" viewBox="0 0 24 24" fill="white" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2" />
<rect x="8" y="2" width="8" height="4" rx="1" ry="1"/>
</svg>`), 1500);
});
};
typingDiv.appendChild(copyBtn);
}
}
setTimeout(typeChar, 200); // slight delay after removing dots
} catch (e) {
typingDiv.textContent = "Something went wrong. " + e.message;
typingDiv.classList.remove("typing");
}
}*/
async function submitMessage() {
const input = document.getElementById("userInput");
const msg = input.value.trim();
if (!msg) return;
const chatMessages = document.getElementById("chatMessages");
// Append user message
const userDiv = document.createElement("div");
userDiv.className = "msg user";
userDiv.innerHTML = `<div class="bubble">${msg}</div>`;
chatMessages.appendChild(userDiv);
// Bot typing placeholder
const botDiv = document.createElement("div");
botDiv.className = "msg bot";
const typingDiv = document.createElement("div");
typingDiv.className = "bubble typing";
const typingIndicator = document.createElement("div");
typingIndicator.id = "typing";
typingIndicator.innerHTML = `<span class="dot"></span><span class="dot"></span><span class="dot"></span>`;
typingDiv.appendChild(typingIndicator);
botDiv.appendChild(typingDiv);
chatMessages.appendChild(botDiv);
chatMessages.scrollTop = chatMessages.scrollHeight;
input.value = "";
toggleSendButton();
try {
const res = await fetch("/chat", {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({prompt: msg})
});
const data = await res.json();
const fullText = data.response;
// Split text into complete sentences using full stop
const sentences = fullText.split(/(?<=\.)\s+/);
let selectedSentences = [];
for (const sentence of sentences) {
selectedSentences.push(sentence.trim());
}
// === END TOKEN TRIM LOGIC ===
// Replace typing dots with final output
const converter = new showdown.Converter();
const markdownOutput = selectedSentences.join("\n");
typingDiv.innerHTML = converter.makeHtml(markdownOutput);
typingDiv.classList.remove("typing");
// Optional copy button
const copyBtn = document.createElement("button");
copyBtn.className = "copy-btn";
copyBtn.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" height="18" width="18" viewBox="0 0 24 24" fill="white" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2" />
<rect x="8" y="2" width="8" height="4" rx="1" ry="1"/>
</svg>`;
copyBtn.onclick = function () {
navigator.clipboard.writeText(selectedSentences.join("\n")).then(() => {
showToast("Copied!");
copyBtn.textContent = "✅";
setTimeout(() => {
copyBtn.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" height="18" width="18" viewBox="0 0 24 24" fill="white" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2" />
<rect x="8" y="2" width="8" height="4" rx="1" ry="1"/>
</svg>`;
}, 1500);
});
};
typingDiv.appendChild(copyBtn);
} catch (e) {
typingDiv.textContent = "Something went wrong. " + e.message;
typingDiv.classList.remove("typing");
}
}
</script>
</body>
</html>