Spaces:
Sleeping
Sleeping
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>SmartLearn - AI Tutor</title> | |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet"> | |
<style> | |
body { | |
font-family: 'Roboto', sans-serif; | |
margin: 0; | |
padding: 0; | |
background-color: #f0f2f5; | |
color: #333; | |
} | |
.back-button { | |
background-color: #3498db; | |
color: white; | |
border: none; | |
padding: 10px 15px; | |
border-radius: 5px; | |
cursor: pointer; | |
transition: background-color 0.3s ease; | |
position: absolute; | |
top: 20px; | |
left: 20px; | |
z-index: 10; | |
} | |
.back-button:hover { | |
background-color: #2980b9; | |
} | |
h1 { | |
text-align: center; | |
color: #3498db; | |
margin: 20px 0; | |
} | |
.chat-container { | |
max-width: 800px; | |
margin: 0 auto; | |
padding: 20px; | |
background-color: white; | |
border-radius: 10px; | |
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); | |
overflow: hidden; | |
position: relative; | |
z-index: 5; | |
} | |
.chat-messages { | |
height: 400px; | |
overflow-y: auto; | |
padding: 20px; | |
box-sizing: border-box; | |
display: flex; | |
flex-direction: column; | |
} | |
.chat-input { | |
display: flex; | |
align-items: center; | |
padding: 10px; | |
background-color: #ecf0f1; | |
box-sizing: border-box; | |
} | |
.chat-input input { | |
flex-grow: 1; | |
min-width: 0; | |
padding: 10px; | |
border: 1px solid #ccc; | |
border-radius: 20px; | |
font-size: 16px; | |
box-sizing: border-box; | |
overflow-wrap: break-word; | |
} | |
.chat-input button { | |
margin-left: 10px; | |
padding: 10px 20px; | |
background-color: #3498db; | |
color: white; | |
border: none; | |
border-radius: 20px; | |
cursor: pointer; | |
transition: background-color 0.3s ease; | |
} | |
.chat-input button:hover { | |
background-color: #2980b9; | |
} | |
.image-upload { | |
margin-right: 10px; | |
} | |
.image-upload input[type="file"] { | |
display: none; | |
} | |
.image-upload label { | |
cursor: pointer; | |
font-size: 24px; | |
color: #3498db; | |
transition: color 0.3s ease; | |
} | |
.image-upload label:hover { | |
color: #2980b9; | |
} | |
.message { | |
display: block; | |
max-width: 80%; | |
margin-bottom: 15px; | |
padding: 10px 15px; | |
border-radius: 20px; | |
box-sizing: border-box; | |
word-wrap: break-word; | |
position: relative; | |
clear: both; | |
} | |
.user-message { | |
background-color: #3498db; | |
color: white; | |
float: right; | |
} | |
.ai-message { | |
background-color: #7b989e; | |
color: #333; | |
float: left; | |
padding-bottom: 30px; /* Space for translate option */ | |
} | |
.message img { | |
max-width: 100%; | |
border-radius: 10px; | |
margin-top: 10px; | |
} | |
.background-image { | |
position: fixed; | |
top: 0; | |
left: 0; | |
width: 100%; | |
height: 100%; | |
background-image: url('https://hashagile.com/wp-content/uploads/2022/02/ils_13.svg'); | |
background-size: cover; | |
background-position: center; | |
opacity: 0.1; | |
z-index: -1; | |
} | |
.features { | |
display: flex; | |
justify-content: center; | |
margin-bottom: 20px; | |
} | |
.feature-icon { | |
font-size: 24px; | |
margin: 0 15px; | |
color: #3498db; | |
cursor: pointer; | |
transition: transform 0.3s ease, color 0.3s ease; | |
} | |
.feature-icon:hover { | |
transform: scale(1.2); | |
color: #2980b9; | |
} | |
.typing-indicator { | |
display: flex; | |
padding: 10px; | |
background-color: #ecf0f1; | |
border-radius: 20px; | |
margin-bottom: 15px; | |
align-items: center; | |
font-style: italic; | |
color: #7f8c8d; | |
align-self: flex-start; | |
clear: both; | |
} | |
.typing-indicator .dots { | |
display: flex; | |
margin-left: 10px; | |
} | |
.typing-indicator .dot { | |
width: 8px; | |
height: 8px; | |
background-color: #7f8c8d; | |
border-radius: 50%; | |
margin-right: 5px; | |
animation: pulse 1.5s infinite ease-in-out; | |
} | |
.typing-indicator .dot:nth-child(2) { | |
animation-delay: 0.2s; | |
} | |
.typing-indicator .dot:nth-child(3) { | |
animation-delay: 0.4s; | |
} | |
@keyframes pulse { | |
0% { transform: scale(1); } | |
50% { transform: scale(1.2); } | |
100% { transform: scale(1); } | |
} | |
.translate-link { | |
font-size: 14px; | |
color: #3498db; | |
cursor: pointer; | |
text-decoration: underline; | |
position: absolute; | |
right: 15px; | |
bottom: 10px; | |
} | |
.translate-link:hover { | |
color: #2980b9; | |
} | |
.rotate { | |
animation: rotation 2s; | |
} | |
.linear { | |
animation-timing-function: linear; | |
} | |
.infinite { | |
animation-iteration-count: infinite; | |
} | |
@keyframes rotation { | |
from { | |
transform: rotate(0deg); | |
} | |
to { | |
transform: rotate(359deg); | |
} | |
} | |
.center-rotate-container { | |
display: flex; | |
justify-content: center; | |
margin-top: 20px; | |
} | |
body { | |
font-family: 'Roboto', sans-serif; | |
margin: 0; | |
padding: 0; | |
background-color: #f0f2f5; | |
color: #333; | |
} | |
.back-button { | |
background-color: #3498db; | |
color: white; | |
border: none; | |
padding: 10px 15px; | |
border-radius: 5px; | |
cursor: pointer; | |
transition: background-color 0.3s ease; | |
position: absolute; | |
top: 20px; | |
left: 20px; | |
z-index: 10; | |
} | |
.back-button:hover { | |
background-color: #2980b9; | |
} | |
h1 { | |
text-align: center; | |
color: #3498db; | |
margin: 20px 0; | |
} | |
.chat-container { | |
max-width: 800px; | |
margin: 0 auto; | |
padding: 20px; | |
background-color: white; | |
border-radius: 10px; | |
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); | |
overflow: hidden; | |
position: relative; | |
z-index: 5; | |
padding-bottom: 80px; /* Extra padding to ensure the input box does not cover the last message */ | |
} | |
.chat-messages { | |
height: 400px; | |
overflow-y: auto; | |
padding: 20px; | |
box-sizing: border-box; | |
display: flex; | |
flex-direction: column; | |
} | |
.chat-input { | |
display: flex; | |
align-items: center; | |
padding: 10px; | |
background-color: #ecf0f1; | |
box-sizing: border-box; | |
position: fixed; | |
bottom: 0; | |
left: 0; | |
width: 100%; | |
} | |
.chat-input input { | |
flex-grow: 1; | |
min-width: 0; | |
padding: 10px; | |
border: 1px solid #ccc; | |
border-radius: 20px; | |
font-size: 16px; | |
box-sizing: border-box; | |
overflow-wrap: break-word; | |
} | |
.chat-input button { | |
margin-left: 10px; | |
padding: 10px 20px; | |
background-color: #3498db; | |
color: white; | |
border: none; | |
border-radius: 20px; | |
cursor: pointer; | |
transition: background-color 0.3s ease; | |
} | |
.chat-input button:hover { | |
background-color: #2980b9; | |
} | |
.image-upload { | |
margin-right: 10px; | |
} | |
.image-upload input[type="file"] { | |
display: none; | |
} | |
.image-upload label { | |
cursor: pointer; | |
font-size: 24px; | |
color: #3498db; | |
transition: color 0.3s ease; | |
} | |
.image-upload label:hover { | |
color: #2980b9; | |
} | |
.message { | |
display: block; | |
max-width: 80%; | |
margin-bottom: 15px; | |
padding: 10px 15px; | |
border-radius: 20px; | |
box-sizing: border-box; | |
word-wrap: break-word; | |
position: relative; | |
clear: both; | |
} | |
.user-message { | |
background-color: #3498db; | |
color: white; | |
float: right; | |
} | |
.ai-message { | |
background-color: #c1cccc; | |
color: #333; | |
float: left; | |
padding-bottom: 30px; /* Space for translate option */ | |
} | |
.message img { | |
max-width: 100%; | |
border-radius: 10px; | |
margin-top: 10px; | |
} | |
.background-image { | |
position: fixed; | |
top: 0; | |
left: 0; | |
width: 100%; | |
height: 100%; | |
background-image: url('https://hashagile.com/wp-content/uploads/2022/02/ils_13.svg'); | |
background-size: cover; | |
background-position: center; | |
opacity: 0.1; | |
z-index: -1; | |
} | |
.features { | |
display: flex; | |
justify-content: center; | |
margin-bottom: 20px; | |
} | |
.feature-icon { | |
font-size: 24px; | |
margin: 0 15px; | |
color: #3498db; | |
cursor: pointer; | |
transition: transform 0.3s ease, color 0.3s ease; | |
} | |
.feature-icon:hover { | |
transform: scale(1.2); | |
color: #2980b9; | |
} | |
.typing-indicator { | |
display: flex; | |
padding: 10px; | |
background-color: #ecf0f1; | |
border-radius: 20px; | |
margin-bottom: 15px; | |
align-items: center; | |
font-style: italic; | |
color: #7f8c8d; | |
align-self: flex-start; | |
clear: both; | |
} | |
.typing-indicator .dots { | |
display: flex; | |
margin-left: 10px; | |
} | |
.typing-indicator .dot { | |
width: 8px; | |
height: 8px; | |
background-color: #7f8c8d; | |
border-radius: 50%; | |
margin-right: 5px; | |
animation: pulse 1.5s infinite ease-in-out; | |
} | |
.typing-indicator .dot:nth-child(2) { | |
animation-delay: 0.2s; | |
} | |
.typing-indicator .dot:nth-child(3) { | |
animation-delay: 0.4s; | |
} | |
@keyframes pulse { | |
0% { transform: scale(1); } | |
50% { transform: scale(1.2); } | |
100% { transform: scale(1); } | |
} | |
.translate-link { | |
font-size: 14px; | |
color: #3498db; | |
cursor: pointer; | |
text-decoration: underline; | |
position: absolute; | |
right: 15px; | |
bottom: 10px; | |
} | |
.translate-link:hover { | |
color: #2980b9; | |
} | |
.rotate { | |
animation: rotation 2s; | |
} | |
.linear { | |
animation-timing-function: linear; | |
} | |
.infinite { | |
animation-iteration-count: infinite; | |
} | |
@keyframes rotation { | |
from { | |
transform: rotate(0deg); | |
} | |
to { | |
transform: rotate(359deg); | |
} | |
} | |
.center-rotate-container { | |
display: flex; | |
justify-content: center; | |
margin-top: 20px; | |
} | |
</style> | |
</head> | |
<body> | |
<div class="background-image"></div> | |
<button class="back-button" onclick="goBack()"><i class="fas fa-arrow-left"></i> Back</button> | |
<h1><i class="fas fa-robot"></i> AI Tutor</h1> | |
<div class="features"> | |
<i class="fas fa-microphone feature-icon" title="Voice Input"></i> | |
<i class="fas fa-language feature-icon" title="Language Translation"></i> | |
<i class="fas fa-book feature-icon" title="Study Resources"></i> | |
<i class="fas fa-chart-line feature-icon" title="Progress Tracking"></i> | |
</div> | |
<div class="center-rotate-container"> | |
<img src="https://hashagile.com/wp-content/uploads/2022/02/ils_13_1.svg" class="rotate linear infinite" width="150" height="150" /> | |
</div> | |
<div class=""> | |
<div id="chat-messages" class="chat-messages"></div> | |
<div class="chat-input"> | |
<div class="image-upload"> | |
<label for="image-file"> | |
<i class="fas fa-paperclip"></i> | |
</label> | |
<input type="file" id="image-file" accept="image/*"> | |
</div> | |
<input type="text" id="user-input" placeholder="Ask your question..."> | |
<button onclick="sendMessage()"><i class="fas fa-paper-plane"></i> Send</button> | |
</div> | |
</div> | |
<script> | |
function sendMessage() { | |
const message = document.getElementById('user-input').value.trim(); | |
if (message) { | |
addMessage(message, true); | |
document.getElementById('user-input').value = ''; | |
showTypingIndicator(); | |
fetch('/chat', { | |
method: 'POST', | |
headers: { | |
'Content-Type': 'application/json', | |
}, | |
body: JSON.stringify({ message: message }), | |
}) | |
.then(response => response.json()) | |
.then(data => { | |
hideTypingIndicator(); | |
addMessage(data.response, false); | |
}) | |
.catch(error => { | |
console.error('Error:', error); | |
hideTypingIndicator(); | |
}); | |
} | |
} | |
function addMessage(content, isUser, imageUrl) { | |
const messageWrapper = document.createElement('div'); | |
const messageDiv = document.createElement('div'); | |
messageDiv.className = `message ${isUser ? 'user-message' : 'ai-message'}`; | |
if (imageUrl) { | |
const img = document.createElement('img'); | |
img.src = imageUrl; | |
messageDiv.appendChild(img); | |
} | |
const textDiv = document.createElement('div'); | |
textDiv.textContent = content; | |
messageDiv.appendChild(textDiv); | |
if (!isUser) { | |
const translateLink = document.createElement('span'); | |
translateLink.className = 'translate-link'; | |
translateLink.textContent = 'Translate'; | |
translateLink.onclick = function() { | |
translateMessage(textDiv); | |
}; | |
messageDiv.appendChild(translateLink); | |
} | |
messageWrapper.appendChild(messageDiv); | |
document.getElementById('chat-messages').appendChild(messageWrapper); | |
document.getElementById('chat-messages').scrollTop = document.getElementById('chat-messages').scrollHeight; | |
} | |
function showTypingIndicator() { | |
const typingDiv = document.createElement('div'); | |
typingDiv.className = 'typing-indicator'; | |
typingDiv.innerHTML = 'AI is typing<div class="dots"><div class="dot"></div><div class="dot"></div><div class="dot"></div></div>'; | |
document.getElementById('chat-messages').appendChild(typingDiv); | |
document.getElementById('chat-messages').scrollTop = document.getElementById('chat-messages').scrollHeight; | |
} | |
function hideTypingIndicator() { | |
const typingIndicator = document.querySelector('.typing-indicator'); | |
if (typingIndicator) { | |
typingIndicator.remove(); | |
} | |
} | |
document.getElementById('user-input').addEventListener('keypress', function(e) { | |
if (e.key === 'Enter') { | |
sendMessage(); | |
} | |
}); | |
document.getElementById('image-file').addEventListener('change', function(event) { | |
const file = event.target.files[0]; | |
if (file) { | |
const reader = new FileReader(); | |
reader.onload = function(e) { | |
addMessage('Image uploaded', true, e.target.result); | |
} | |
reader.readAsDataURL(file); | |
const formData = new FormData(); | |
formData.append('image-file', file); | |
showTypingIndicator(); | |
fetch('/upload_image_for_ocr', { | |
method: 'POST', | |
body: formData | |
}) | |
.then(response => response.json()) | |
.then(data => { | |
hideTypingIndicator(); | |
addMessage(data.ai_response, false); | |
}) | |
.catch(error => { | |
console.error('Error:', error); | |
hideTypingIndicator(); | |
}); | |
} | |
}); | |
function goBack() { | |
window.history.back(); | |
} | |
// Add welcome message | |
window.onload = function() { | |
addMessage("Hello! I'm your AI Tutor. How can I help you today?", false); | |
} | |
function translateMessage(messageDiv) { | |
const text = messageDiv.textContent; | |
fetch('/translate', { | |
method: 'POST', | |
headers: { | |
'Content-Type': 'application/json' | |
}, | |
body: JSON.stringify({ text: text }) | |
}) | |
.then(response => response.json()) | |
.then(data => { | |
if (data.translated_text) { | |
messageDiv.textContent = data.translated_text; | |
} | |
}) | |
.catch(error => { | |
console.error('Error:', error); | |
}); | |
}</script> | |
</body> | |
</html> |