llm-project-3 / index.html
jerwng's picture
Create index.html
b167106 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>LLM Personality Chat</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
padding: 20px;
}
.container {
max-width: 800px;
width: 100%;
background: white;
border-radius: 20px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
overflow: hidden;
display: flex;
flex-direction: column;
height: 90vh;
max-height: 700px;
}
.header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 20px;
text-align: center;
}
.header h1 {
font-size: 24px;
margin-bottom: 10px;
}
.personality-selector {
padding: 20px;
background: #f8f9fa;
border-bottom: 1px solid #e0e0e0;
}
.personality-selector label {
font-weight: 600;
color: #333;
display: block;
margin-bottom: 10px;
}
.personality-buttons {
display: flex;
gap: 10px;
flex-wrap: wrap;
}
.personality-btn {
flex: 1;
min-width: 150px;
padding: 12px 20px;
border: 2px solid #667eea;
background: white;
color: #667eea;
border-radius: 10px;
cursor: pointer;
font-weight: 600;
transition: all 0.3s ease;
font-size: 14px;
}
.personality-btn:hover {
background: #f0f0f0;
}
.personality-btn.active {
background: #667eea;
color: white;
}
.personality-description {
margin-top: 10px;
padding: 10px;
background: white;
border-radius: 8px;
font-size: 14px;
color: #666;
font-style: italic;
}
.chat-container {
flex: 1;
overflow-y: auto;
padding: 20px;
background: #f8f9fa;
}
.message {
margin-bottom: 20px;
display: flex;
flex-direction: column;
animation: fadeIn 0.3s ease;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.message.user {
align-items: flex-end;
}
.message.assistant {
align-items: flex-start;
}
.message-content {
max-width: 70%;
padding: 12px 16px;
border-radius: 18px;
word-wrap: break-word;
}
.message.user .message-content {
background: #667eea;
color: white;
border-bottom-right-radius: 4px;
}
.message.assistant .message-content {
background: white;
color: #333;
border-bottom-left-radius: 4px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
}
.message-label {
font-size: 12px;
color: #666;
margin-bottom: 5px;
font-weight: 600;
}
.input-container {
padding: 20px;
background: white;
border-top: 1px solid #e0e0e0;
display: flex;
gap: 10px;
}
#messageInput {
flex: 1;
padding: 12px 16px;
border: 2px solid #e0e0e0;
border-radius: 25px;
font-size: 14px;
outline: none;
transition: border-color 0.3s ease;
}
#messageInput:focus {
border-color: #667eea;
}
#sendBtn {
padding: 12px 30px;
background: #667eea;
color: white;
border: none;
border-radius: 25px;
cursor: pointer;
font-weight: 600;
transition: background 0.3s ease;
font-size: 14px;
}
#sendBtn:hover:not(:disabled) {
background: #5568d3;
}
#sendBtn:disabled {
background: #ccc;
cursor: not-allowed;
}
.loading {
display: none;
padding: 12px 16px;
background: white;
border-radius: 18px;
max-width: 70%;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
}
.loading.show {
display: block;
}
.loading-dots {
display: flex;
gap: 5px;
}
.loading-dots span {
width: 8px;
height: 8px;
background: #667eea;
border-radius: 50%;
animation: bounce 1.4s infinite ease-in-out;
}
.loading-dots span:nth-child(1) {
animation-delay: -0.32s;
}
.loading-dots span:nth-child(2) {
animation-delay: -0.16s;
}
@keyframes bounce {
0%,
80%,
100% {
transform: scale(0);
}
40% {
transform: scale(1);
}
}
.empty-state {
text-align: center;
color: #999;
padding: 40px 20px;
}
.empty-state h2 {
font-size: 20px;
margin-bottom: 10px;
}
.empty-state p {
font-size: 14px;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🤖 LLM Personality Chat</h1>
<p>Chat with different AI personalities</p>
</div>
<div class="personality-selector">
<label>Select a Character:</label>
<div class="personality-buttons">
<button class="personality-btn active" data-personality="dwight">
🥾 Dwight
</button>
<button class="personality-btn" data-personality="michael">
😎 Michael
</button>
<button class="personality-btn" data-personality="spongebob">
🧽 SpongeBob
</button>
</div>
<div class="personality-description" id="personalityDescription">
Assistant Regional Manager with beet farm wisdom
</div>
</div>
<div class="chat-container" id="chatContainer">
<div class="empty-state">
<h2>Start a Conversation</h2>
<p>
Type a message below to begin chatting with your chosen AI
personality
</p>
</div>
</div>
<div class="input-container">
<input
type="text"
id="messageInput"
placeholder="Type your message here..."
autocomplete="off"
/>
<button id="sendBtn">Send</button>
</div>
</div>
<script>
let currentPersonality = "dwight";
const descriptions = {
dwight: "Assistant Regional Manager with beet farm wisdom",
michael: "World's Best Boss with unique management style",
spongebob: "Optimistic fry cook from Bikini Bottom",
};
const chatContainer = document.getElementById("chatContainer");
const messageInput = document.getElementById("messageInput");
const sendBtn = document.getElementById("sendBtn");
const personalityBtns = document.querySelectorAll(".personality-btn");
const personalityDescription = document.getElementById(
"personalityDescription"
);
// Handle personality selection
personalityBtns.forEach((btn) => {
btn.addEventListener("click", () => {
personalityBtns.forEach((b) => b.classList.remove("active"));
btn.classList.add("active");
currentPersonality = btn.dataset.personality;
personalityDescription.textContent = descriptions[currentPersonality];
});
});
// Add message to chat
function addMessage(content, isUser, personalityName = "") {
// Remove empty state if it exists
const emptyState = chatContainer.querySelector(".empty-state");
if (emptyState) {
emptyState.remove();
}
const messageDiv = document.createElement("div");
messageDiv.className = `message ${isUser ? "user" : "assistant"}`;
const label = document.createElement("div");
label.className = "message-label";
label.textContent = isUser ? "You" : personalityName;
const contentDiv = document.createElement("div");
contentDiv.className = "message-content";
contentDiv.textContent = content;
messageDiv.appendChild(label);
messageDiv.appendChild(contentDiv);
chatContainer.appendChild(messageDiv);
// Scroll to bottom
chatContainer.scrollTop = chatContainer.scrollHeight;
}
// Show loading indicator
function showLoading() {
const loading = document.createElement("div");
loading.className = "loading show";
loading.id = "loadingIndicator";
loading.innerHTML = `
<div class="loading-dots">
<span></span>
<span></span>
<span></span>
</div>
`;
chatContainer.appendChild(loading);
chatContainer.scrollTop = chatContainer.scrollHeight;
}
// Hide loading indicator
function hideLoading() {
const loading = document.getElementById("loadingIndicator");
if (loading) {
loading.remove();
}
}
// Send message
async function sendMessage() {
const message = messageInput.value.trim();
if (!message) return;
// Add user message
addMessage(message, true);
messageInput.value = "";
sendBtn.disabled = true;
messageInput.disabled = true;
// Show loading
showLoading();
try {
const response = await fetch("/chat", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
message: message,
personality: currentPersonality,
}),
});
const data = await response.json();
hideLoading();
if (response.ok) {
addMessage(data.response, false, data.personality_name);
} else {
addMessage(
"Sorry, there was an error processing your message.",
false,
"Error"
);
}
} catch (error) {
hideLoading();
addMessage("Sorry, could not connect to the server.", false, "Error");
} finally {
sendBtn.disabled = false;
messageInput.disabled = false;
messageInput.focus();
}
}
// Event listeners
sendBtn.addEventListener("click", sendMessage);
messageInput.addEventListener("keypress", (e) => {
if (e.key === "Enter") {
sendMessage();
}
});
// Focus input on load
messageInput.focus();
</script>
</body>
</html>