|
|
|
<!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; |
|
} |
|
|
|
* { |
|
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%; |
|
} |
|
|
|
.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.5; |
|
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; |
|
} |
|
|
|
.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; |
|
} |
|
</style> |
|
</head> |
|
<body> |
|
<div class="chat-container"> |
|
<main class="chat-area"> |
|
<div class="welcome-screen"> |
|
<h2>What can I help with?</h2> |
|
</div> |
|
</main> |
|
|
|
<footer class="input-area"> |
|
<form id="chat-form" class="input-wrapper"> |
|
<button type="button" class="icon-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 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 = (message, sender) => { |
|
if (!welcomeScreen.classList.contains('hidden')) { |
|
welcomeScreen.classList.add('hidden'); |
|
} |
|
|
|
const messageElement = document.createElement('div'); |
|
messageElement.classList.add('message', `${sender}-message`); |
|
messageElement.textContent = message; |
|
chatArea.appendChild(messageElement); |
|
scrollToBottom(); |
|
}; |
|
|
|
|
|
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'); |
|
|
|
} 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); |
|
|
|
|
|
updateSendButtonState(); |
|
}); |
|
</script> |
|
</body> |
|
</html> |