Muhammed Rishdin T
Upload 23 files
171bfe2 verified
Raw History Blame Contribute Delete
11.6 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
body {
background-color: white; /* Ensure the iframe has a white background */
}
</style>
</head>
<body>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>SOFTGPT AI Chat (Streaming)</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Orbitron:wght@500;600;700&display=swap');
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
background: linear-gradient(135deg, #0f0c29 0%, #302b63 25%, #24243e 100%);
color: #f0f0f0;
display: flex;
flex-direction: column;
align-items: center;
min-height: 100vh;
padding: 20px;
position: relative;
overflow-x: hidden;
}
/* Animated background particles */
.particles {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: -1;
}
.particle {
position: absolute;
width: 4px;
height: 4px;
background: rgba(0, 255, 204, 0.3);
border-radius: 50%;
animation: float 15s infinite linear;
opacity: 0.6;
}
.particle:nth-child(2n) {
background: rgba(255, 204, 0, 0.3);
width: 3px;
height: 3px;
}
.particle:nth-child(3n) {
background: rgba(0, 204, 255, 0.3);
width: 5px;
height: 5px;
}
@keyframes float {
0% {
transform: translateY(0) translateX(0) rotate(0deg);
opacity: 0;
}
10% {
opacity: 0.6;
}
90% {
opacity: 0.6;
}
100% {
transform: translateY(-100vh) translateX(100px) rotate(360deg);
opacity: 0;
}
}
.container {
width: 100%;
max-width: 800px;
display: flex;
flex-direction: column;
gap: 24px;
margin-top: 20px;
position: relative;
z-index: 2;
}
.header {
text-align: center;
padding: 20px 0;
position: relative;
}
.header::before {
content: '';
position: absolute;
top: 50%;
left: 0;
right: 0;
height: 1px;
background: linear-gradient(90deg, transparent, rgba(0, 255, 204, 0.3), transparent);
transform: translateY(-50%);
}
h2 {
font-family: 'Orbitron', sans-serif;
font-size: 2.8rem;
font-weight: 700;
background: linear-gradient(90deg, #00ffcc 0%, #00ccff 50%, #ffcc00 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
text-shadow: 0 0 20px rgba(0, 255, 204, 0.3);
letter-spacing: 1px;
position: relative;
display: inline-block;
animation: glow 3s ease-in-out infinite alternate;
}
@keyframes glow {
from {
text-shadow: 0 0 10px rgba(0, 255, 204, 0.3), 0 0 20px rgba(0, 255, 204, 0.2);
}
to {
text-shadow: 0 0 20px rgba(0, 255, 204, 0.6), 0 0 30px rgba(0, 255, 204, 0.4), 0 0 40px rgba(0, 255, 204, 0.2);
}
}
#chatbox {
width: 100%;
height: 500px;
background: rgba(15, 12, 41, 0.7);
backdrop-filter: blur(12px);
padding: 24px;
border-radius: 24px;
overflow-y: auto;
border: 1px solid rgba(255, 255, 255, 0.1);
box-shadow: 0 15px 35px rgba(0, 0, 0, 0.4);
position: relative;
overflow-x: hidden;
}
#chatbox::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 3px;
background: linear-gradient(90deg, transparent, #00ffcc, #ffcc00, transparent);
opacity: 0.8;
}
.message {
margin: 20px 0;
padding: 18px 24px;
border-radius: 18px;
position: relative;
animation: fadeInScale 0.4s cubic-bezier(0.4, 0, 0.2, 1);
line-height: 1.6;
word-wrap: break-word;
font-size: 16px;
transition: all 0.3s ease;
}
@keyframes fadeInScale {
from {
opacity: 0;
transform: translateY(15px) scale(0.95);
}
to {
opacity: 1;
transform: translateY(0) scale(1);
}
}
.user {
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
color: #00ffcc;
margin-left: 70px;
border-left: 4px solid #00ffcc;
box-shadow: 0 4px 15px rgba(0, 255, 204, 0.15);
}
.user:hover {
box-shadow: 0 6px 20px rgba(0, 255, 204, 0.25);
transform: translateY(-2px);
}
.ai {
background: linear-gradient(135deg, #2d1b69 0%, #1a1a2e 100%);
color: #ffcc00;
margin-right: 70px;
border-right: 4px solid #ffcc00;
box-shadow: 0 4px 15px rgba(255, 204, 0, 0.15);
}
.ai:hover {
box-shadow: 0 6px 20px rgba(255, 204, 0, 0.25);
transform: translateY(-2px);
}
.message-prefix {
font-family: 'Orbitron', sans-serif;
font-weight: 600;
font-size: 14px;
margin-bottom: 8px;
text-transform: uppercase;
letter-spacing: 1px;
opacity: 0.9;
}
.user .message-prefix {
color: #00ffcc;
text-shadow: 0 0 10px rgba(0, 255, 204, 0.3);
}
.ai .message-prefix {
color: #ffcc00;
text-shadow: 0 0 10px rgba(255, 204, 0, 0.3);
}
.user::before,
.ai::before {
content: '';
position: absolute;
width: 14px;
height: 14px;
border-radius: 50%;
top: 18px;
box-shadow: 0 0 15px currentColor;
}
.user::before {
background: #00ffcc;
right: -25px;
}
.ai::before {
background: #ffcc00;
left: -25px;
}
.input-container {
width: 100%;
position: relative;
}
#user-input {
width: 100%;
padding: 18px 28px;
border-radius: 50px;
border: none;
background: rgba(26, 26, 46, 0.8);
backdrop-filter: blur(12px);
color: #f0f0f0;
font-size: 16px;
font-family: 'Inter', sans-serif;
border: 2px solid rgba(255, 255, 255, 0.1);
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.3);
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
outline: none;
font-weight: 400;
}
#user-input:focus {
border-color: rgba(0, 255, 204, 0.6);
box-shadow: 0 8px 30px rgba(0, 255, 204, 0.3);
transform: translateY(-3px);
}
#user-input::placeholder {
color: #aaa;
font-weight: 300;
font-style: italic;
}
/* Scrollbar styling */
#chatbox::-webkit-scrollbar {
width: 10px;
}
#chatbox::-webkit-scrollbar-track {
background: rgba(255, 255, 255, 0.03);
border-radius: 5px;
}
#chatbox::-webkit-scrollbar-thumb {
background: linear-gradient(135deg, #00ffcc 0%, #ffcc00 100%);
border-radius: 5px;
border: 2px solid rgba(15, 12, 41, 0.7);
}
#chatbox::-webkit-scrollbar-thumb:hover {
background: linear-gradient(135deg, #ffcc00 0%, #00ffcc 100%);
}
/* Responsive design */
@media (max-width: 768px) {
h2 {
font-size: 2.2rem;
}
#chatbox {
height: 420px;
padding: 18px;
}
.message {
margin: 16px 0;
padding: 14px 20px;
font-size: 15px;
}
.user {
margin-left: 40px;
}
.ai {
margin-right: 40px;
}
.user::before,
.ai::before {
width: 12px;
height: 12px;
top: 14px;
}
.user::before {
right: -20px;
}
.ai::before {
left: -20px;
}
#user-input {
padding: 16px 24px;
font-size: 15px;
}
}
@media (max-width: 480px) {
h2 {
font-size: 1.8rem;
}
#chatbox {
height: 380px;
}
.user, .ai {
margin-left: 20px;
margin-right: 20px;
}
.message-prefix {
font-size: 12px;
}
}
</style>
</head>
<body>
<div class="particles" id="particles"></div>
<div class="container">
<div class="header">
<h2>SOFTGPT</h2>
</div>
<div id="chatbox"></div>
<div class="input-container">
<input id="user-input" placeholder="Type your message and hit Enter..." autofocus />
</div>
</div>
<script>
// Create animated background particles
function createParticles() {
const particlesContainer = document.getElementById('particles');
const particleCount = 50;
for (let i = 0; i < particleCount; i++) {
const particle = document.createElement('div');
particle.className = 'particle';
// Random position
const posX = Math.random() * 100;
const posY = Math.random() * 100;
particle.style.left = `${posX}%`;
particle.style.top = `${posY}%`;
// Random size
const size = Math.random() * 3 + 2;
particle.style.width = `${size}px`;
particle.style.height = `${size}px`;
// Random animation delay and duration
const delay = Math.random() * 15;
const duration = Math.random() * 10 + 10;
particle.style.animationDelay = `${delay}s`;
particle.style.animationDuration = `${duration}s`;
particlesContainer.appendChild(particle);
}
}
// Initialize particles
createParticles();
const chatbox = document.getElementById("chatbox");
const input = document.getElementById("user-input");
// Add welcome message
addMessage("ai", "Hello! I'm SoftGPT AI. How can I assist you today?");
input.addEventListener("keypress", async e => {
if(e.key === "Enter"){
const message = input.value.trim();
if(!message) return;
addMessage("user", message);
input.value = "";
const aiDiv = addMessage("ai", ""); // placeholder for streaming
const evtSource = new EventSource(`/chat_stream?message=${encodeURIComponent(message)}`);
evtSource.onmessage = e => {
// Simply append the token to the existing text content
// This preserves spaces and formatting exactly as received
aiDiv.textContent += e.data;
chatbox.scrollTop = chatbox.scrollHeight;
};
evtSource.onerror = e => {
evtSource.close();
};
}
});
function addMessage(role, text){
const div = document.createElement("div");
div.className = `message ${role}`;
// Add prefix
const prefix = document.createElement("div");
prefix.className = "message-prefix";
prefix.textContent = role === "user" ? "You:" : "SoftGPT:";
div.appendChild(prefix);
// Add message content
const content = document.createElement("div");
content.textContent = text;
div.appendChild(content);
chatbox.appendChild(div);
chatbox.scrollTop = chatbox.scrollHeight;
return content; // Return the content div for token appending
}
</script>
</body>
</html>
<script>
const tokenSpan = document.createElement('span');
tokenSpan.className = 'token-appear';
tokenSpan.textContent = e.data;
aiDiv.appendChild(tokenSpan);
aiDiv.textContent += e.data;
</script>
</body>
</html>