|
|
|
<!DOCTYPE html> |
|
<html lang="en"> |
|
<head> |
|
<meta charset="UTF-8"> |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> |
|
<title>AI Chat with Gemini</title> |
|
<style> |
|
:root { |
|
--background-color: #212121; |
|
--input-area-color: #212121; |
|
--user-bubble-color: #303030; |
|
--ai-bubble-color: #2a2a2a; |
|
--text-color: #e0e0e0; |
|
--placeholder-color: #888888; |
|
--icon-color: #b0b0b0; |
|
--send-button-color: #4CAF50; |
|
--border-color: #333333; |
|
--code-bg-color: #1e1e1e; |
|
--code-text-color: #f8f8f2; |
|
--link-color: #64b5f6; |
|
--quote-color: #4CAF50; |
|
} |
|
|
|
* { |
|
box-sizing: border-box; |
|
margin: 0; |
|
padding: 0; |
|
} |
|
|
|
html, body { |
|
height: 100%; |
|
overflow: hidden; |
|
} |
|
|
|
body { |
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; |
|
background-color: var(--background-color); |
|
color: var(--text-color); |
|
display: flex; |
|
flex-direction: column; |
|
height: 100%; |
|
line-height: 1.6; |
|
} |
|
|
|
.chat-container { |
|
display: flex; |
|
flex-direction: column; |
|
height: 100%; |
|
width: 100%; |
|
max-width: 800px; |
|
margin: 0 auto; |
|
} |
|
|
|
.chat-area { |
|
flex-grow: 1; |
|
overflow-y: auto; |
|
padding: 20px 16px; |
|
display: flex; |
|
flex-direction: column; |
|
} |
|
|
|
.welcome-screen { |
|
text-align: center; |
|
margin: auto; |
|
color: var(--placeholder-color); |
|
} |
|
|
|
.welcome-screen h2 { |
|
font-size: 1.8rem; |
|
font-weight: 400; |
|
margin-bottom: 10px; |
|
} |
|
|
|
.welcome-screen.hidden { |
|
display: none; |
|
} |
|
|
|
.message { |
|
max-width: 85%; |
|
padding: 12px 16px; |
|
border-radius: 18px; |
|
margin-bottom: 12px; |
|
word-wrap: break-word; |
|
line-height: 1.6; |
|
font-size: 1rem; |
|
} |
|
|
|
.user-message { |
|
background-color: var(--user-bubble-color); |
|
align-self: flex-end; |
|
border-bottom-right-radius: 4px; |
|
} |
|
|
|
.ai-message { |
|
background-color: var(--ai-bubble-color); |
|
align-self: flex-start; |
|
border-bottom-left-radius: 4px; |
|
} |
|
|
|
|
|
.ai-message-content { |
|
overflow: hidden; |
|
} |
|
|
|
.ai-message-content p { |
|
margin-bottom: 12px; |
|
} |
|
|
|
.ai-message-content p:last-child { |
|
margin-bottom: 0; |
|
} |
|
|
|
.ai-message-content strong { |
|
color: #ffffff; |
|
font-weight: 600; |
|
} |
|
|
|
.ai-message-content em { |
|
color: #d1d1d1; |
|
font-style: italic; |
|
} |
|
|
|
.ai-message-content a { |
|
color: var(--link-color); |
|
text-decoration: none; |
|
word-break: break-all; |
|
} |
|
|
|
.ai-message-content a:hover { |
|
text-decoration: underline; |
|
} |
|
|
|
.ai-message-content ul, |
|
.ai-message-content ol { |
|
padding-left: 24px; |
|
margin-bottom: 12px; |
|
} |
|
|
|
.ai-message-content li { |
|
margin-bottom: 6px; |
|
} |
|
|
|
.ai-message-content blockquote { |
|
border-left: 3px solid var(--quote-color); |
|
padding-left: 12px; |
|
margin-left: 0; |
|
color: #bdbdbd; |
|
margin-bottom: 12px; |
|
} |
|
|
|
.ai-message-content pre { |
|
background-color: var(--code-bg-color); |
|
border-radius: 6px; |
|
padding: 12px; |
|
overflow-x: auto; |
|
margin-bottom: 12px; |
|
} |
|
|
|
.ai-message-content code { |
|
font-family: 'Courier New', Courier, monospace; |
|
background-color: var(--code-bg-color); |
|
padding: 2px 4px; |
|
border-radius: 3px; |
|
color: var(--code-text-color); |
|
font-size: 0.9em; |
|
} |
|
|
|
.ai-message-content .code-block { |
|
display: block; |
|
white-space: pre-wrap; |
|
padding: 12px; |
|
border-radius: 6px; |
|
background-color: var(--code-bg-color); |
|
margin-bottom: 12px; |
|
} |
|
|
|
.typing-indicator { |
|
display: flex; |
|
align-items: center; |
|
padding: 12px 16px; |
|
} |
|
.typing-indicator span { |
|
height: 8px; |
|
width: 8px; |
|
background-color: var(--icon-color); |
|
border-radius: 50%; |
|
display: inline-block; |
|
margin: 0 2px; |
|
animation: bounce 1.4s infinite both; |
|
} |
|
.typing-indicator span:nth-child(2) { animation-delay: 0.2s; } |
|
.typing-indicator span:nth-child(3) { animation-delay: 0.4s; } |
|
|
|
@keyframes bounce { |
|
0%, 80%, 100% { transform: scale(0); } |
|
40% { transform: scale(1.0); } |
|
} |
|
|
|
.input-area { |
|
display: flex; |
|
align-items: flex-end; |
|
padding: 10px 16px; |
|
border-top: 1px solid var(--border-color); |
|
background-color: var(--input-area-color); |
|
flex-shrink: 0; |
|
} |
|
|
|
.input-wrapper { |
|
display: flex; |
|
align-items: center; |
|
width: 100%; |
|
background-color: var(--user-bubble-color); |
|
border-radius: 24px; |
|
padding: 4px; |
|
} |
|
|
|
.input-area textarea { |
|
flex-grow: 1; |
|
border: none; |
|
background: transparent; |
|
color: var(--text-color); |
|
resize: none; |
|
font-size: 1rem; |
|
line-height: 1.5; |
|
max-height: 120px; |
|
overflow-y: auto; |
|
padding: 8px 12px; |
|
font-family: inherit; |
|
} |
|
|
|
.input-area textarea:focus { |
|
outline: none; |
|
} |
|
|
|
.input-area textarea::placeholder { |
|
color: var(--placeholder-color); |
|
} |
|
|
|
.input-area .icon-button { |
|
background: none; |
|
border: none; |
|
padding: 8px; |
|
cursor: pointer; |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
} |
|
|
|
.input-area .icon-button svg { |
|
width: 24px; |
|
height: 24px; |
|
fill: var(--icon-color); |
|
} |
|
|
|
.send-button { |
|
background-color: var(--send-button-color); |
|
border-radius: 50%; |
|
padding: 8px; |
|
transition: background-color 0.2s; |
|
} |
|
|
|
.send-button.disabled { |
|
background-color: #555; |
|
cursor: not-allowed; |
|
} |
|
|
|
.send-button.disabled svg { |
|
fill: #888; |
|
} |
|
|
|
.send-button svg { |
|
fill: white; |
|
width: 24px; |
|
height: 24px; |
|
} |
|
|
|
|
|
@keyframes fadeIn { |
|
from { opacity: 0; transform: translateY(10px); } |
|
to { opacity: 1; transform: translateY(0); } |
|
} |
|
|
|
.message { |
|
animation: fadeIn 0.3s ease-out; |
|
} |
|
</style> |
|
</head> |
|
<body> |
|
<div class="chat-container"> |
|
<main class="chat-area"> |
|
<div class="welcome-screen"> |
|
<h2>What can I help with?</h2> |
|
<p>Ask me anything - I can explain concepts, generate ideas, or help with coding!</p> |
|
</div> |
|
</main> |
|
|
|
<footer class="input-area"> |
|
<form id="chat-form" class="input-wrapper"> |
|
<button type="button" class="icon-button" id="attach-button"> |
|
<svg viewBox="0 0 24 24"><path d="M16.5 6v11.5c0 2.21-1.79 4-4 4s-4-1.79-4-4V5a2.5 2.5 0 0 1 5 0v10.5c0 .83-.67 1.5-1.5 1.5s-1.5-.67-1.5-1.5V6H10v9.5a2.5 2.5 0 0 0 5 0V5c-1.38 0-2.5 1.12-2.5 2.5v10.5c0 1.38-1.12 2.5-2.5 2.5s-2.5-1.12-2.5-2.5V5a4 4 0 0 1 8 0v11.5c-1.1 0-2-.9-2-2V6h-1.5z"></path></svg> |
|
</button> |
|
<textarea id="message-input" placeholder="Ask anything..." rows="1"></textarea> |
|
<button type="submit" id="send-button" class="icon-button send-button disabled"> |
|
<svg viewBox="0 0 24 24"><path d="M2 21l21-9L2 3v7l15 2-15 2v7z"></path></svg> |
|
</button> |
|
</form> |
|
</footer> |
|
</div> |
|
|
|
<script> |
|
document.addEventListener('DOMContentLoaded', () => { |
|
const chatForm = document.getElementById('chat-form'); |
|
const messageInput = document.getElementById('message-input'); |
|
const chatArea = document.querySelector('.chat-area'); |
|
const welcomeScreen = document.querySelector('.welcome-screen'); |
|
const sendButton = document.getElementById('send-button'); |
|
const attachButton = document.getElementById('attach-button'); |
|
|
|
|
|
const adjustTextareaHeight = () => { |
|
messageInput.style.height = 'auto'; |
|
messageInput.style.height = `${messageInput.scrollHeight}px`; |
|
updateSendButtonState(); |
|
}; |
|
|
|
|
|
const updateSendButtonState = () => { |
|
if (messageInput.value.trim() === '') { |
|
sendButton.classList.add('disabled'); |
|
sendButton.disabled = true; |
|
} else { |
|
sendButton.classList.remove('disabled'); |
|
sendButton.disabled = false; |
|
} |
|
}; |
|
|
|
|
|
const scrollToBottom = () => { |
|
chatArea.scrollTop = chatArea.scrollHeight; |
|
}; |
|
|
|
|
|
const addMessage = (content, sender, isHTML = false) => { |
|
if (!welcomeScreen.classList.contains('hidden')) { |
|
welcomeScreen.classList.add('hidden'); |
|
} |
|
|
|
const messageElement = document.createElement('div'); |
|
messageElement.classList.add('message', `${sender}-message`); |
|
|
|
if (isHTML) { |
|
const contentDiv = document.createElement('div'); |
|
contentDiv.classList.add(`${sender}-message-content`); |
|
contentDiv.innerHTML = content; |
|
messageElement.appendChild(contentDiv); |
|
} else { |
|
messageElement.textContent = content; |
|
} |
|
|
|
chatArea.appendChild(messageElement); |
|
scrollToBottom(); |
|
return messageElement; |
|
}; |
|
|
|
|
|
const showTypingIndicator = () => { |
|
const indicatorElement = document.createElement('div'); |
|
indicatorElement.classList.add('message', 'ai-message', 'typing-indicator'); |
|
indicatorElement.innerHTML = '<span></span><span></span><span></span>'; |
|
chatArea.appendChild(indicatorElement); |
|
scrollToBottom(); |
|
return indicatorElement; |
|
}; |
|
|
|
|
|
const getAIResponse = async (userMessage) => { |
|
const indicator = showTypingIndicator(); |
|
|
|
try { |
|
const response = await fetch('/chat', { |
|
method: 'POST', |
|
headers: { |
|
'Content-Type': 'application/json', |
|
}, |
|
body: JSON.stringify({ message: userMessage }) |
|
}); |
|
|
|
const data = await response.json(); |
|
|
|
if (data.error) { |
|
throw new Error(data.error); |
|
} |
|
|
|
chatArea.removeChild(indicator); |
|
addMessage(data.response, 'ai', true); |
|
|
|
} catch (error) { |
|
chatArea.removeChild(indicator); |
|
addMessage("Sorry, I encountered an error. Please try again.", 'ai'); |
|
console.error("Error:", error); |
|
} |
|
}; |
|
|
|
|
|
chatForm.addEventListener('submit', async (e) => { |
|
e.preventDefault(); |
|
const message = messageInput.value.trim(); |
|
|
|
if (message) { |
|
addMessage(message, 'user'); |
|
messageInput.value = ''; |
|
adjustTextareaHeight(); |
|
|
|
await getAIResponse(message); |
|
} |
|
}); |
|
|
|
|
|
messageInput.addEventListener('keydown', (e) => { |
|
if (e.key === 'Enter' && !e.shiftKey) { |
|
e.preventDefault(); |
|
chatForm.dispatchEvent(new Event('submit')); |
|
} |
|
}); |
|
|
|
|
|
messageInput.addEventListener('input', adjustTextareaHeight); |
|
|
|
|
|
attachButton.addEventListener('click', () => { |
|
|
|
messageInput.focus(); |
|
}); |
|
|
|
|
|
updateSendButtonState(); |
|
messageInput.focus(); |
|
|
|
|
|
const isFirstVisit = !localStorage.getItem('chatVisited'); |
|
if (isFirstVisit) { |
|
localStorage.setItem('chatVisited', 'true'); |
|
setTimeout(() => { |
|
const welcomeMessage = ` |
|
<p>Hello! I'm your AI assistant powered by Gemini. I can help with:</p> |
|
<ul> |
|
<li>Answering questions</li> |
|
<li>Explaining concepts</li> |
|
<li>Generating ideas</li> |
|
<li>Coding help</li> |
|
</ul> |
|
<p>Try asking me something like: <em>"Explain quantum computing in simple terms"</em> or <em>"Help me debug this Python code"</em></p> |
|
`; |
|
addMessage(welcomeMessage, 'ai', true); |
|
}, 1000); |
|
} |
|
}); |
|
</script> |
|
</body> |
|
</html> |