harismlnaslm's picture
Add Llama models to AI training: Include Llama 3.1 8B, 3.2 1B, and 3.2 3B as training options
c80b7c6
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>🤖 Textilindo AI Assistant</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;
}
.chat-container {
background: white;
border-radius: 20px;
box-shadow: 0 20px 40px rgba(0,0,0,0.1);
width: 100%;
max-width: 800px;
height: 600px;
display: flex;
flex-direction: column;
overflow: hidden;
}
.chat-header {
background: linear-gradient(135deg, #2196f3, #21cbf3);
color: white;
padding: 20px;
text-align: center;
}
.chat-header h1 {
font-size: 24px;
margin-bottom: 5px;
}
.chat-header p {
opacity: 0.9;
font-size: 14px;
}
.chat-messages {
flex: 1;
padding: 20px;
overflow-y: auto;
display: flex;
flex-direction: column;
gap: 15px;
}
.message {
max-width: 80%;
padding: 12px 16px;
border-radius: 18px;
word-wrap: break-word;
animation: fadeIn 0.3s ease-in;
}
.user-message {
background: #2196f3;
color: white;
align-self: flex-end;
border-bottom-right-radius: 5px;
}
.assistant-message {
background: #f5f5f5;
color: #333;
align-self: flex-start;
border-bottom-left-radius: 5px;
}
.chat-input-container {
padding: 20px;
background: #f8f9fa;
border-top: 1px solid #e9ecef;
display: flex;
gap: 10px;
}
.chat-input {
flex: 1;
padding: 12px 16px;
border: 2px solid #e9ecef;
border-radius: 25px;
outline: none;
font-size: 14px;
transition: border-color 0.3s ease;
}
.chat-input:focus {
border-color: #2196f3;
}
.send-button {
background: #2196f3;
color: white;
border: none;
border-radius: 50%;
width: 45px;
height: 45px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: background-color 0.3s ease;
}
.send-button:hover {
background: #1976d2;
}
.send-button:disabled {
background: #ccc;
cursor: not-allowed;
}
.typing-indicator {
display: none;
align-self: flex-start;
background: #f5f5f5;
padding: 12px 16px;
border-radius: 18px;
border-bottom-left-radius: 5px;
color: #666;
font-style: italic;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes typing {
0%, 60%, 100% { opacity: 0.3; }
30% { opacity: 1; }
}
.typing-dots {
display: inline-block;
}
.typing-dots::after {
content: '...';
animation: typing 1.5s infinite;
}
.welcome-message {
text-align: center;
color: #666;
font-style: italic;
margin: 20px 0;
}
@media (max-width: 600px) {
.chat-container {
height: 100vh;
border-radius: 0;
}
.message {
max-width: 90%;
}
}
/* Training Section Styles */
.training-section {
background: #f8f9fa;
border: 1px solid #e9ecef;
border-radius: 10px;
padding: 15px;
margin: 10px 0;
}
.training-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
.training-header h3 {
margin: 0;
color: #333;
font-size: 16px;
}
.training-panel {
margin-top: 10px;
}
.training-controls {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 10px;
margin-bottom: 15px;
}
.control-group {
display: flex;
flex-direction: column;
}
.control-group label {
font-size: 12px;
font-weight: bold;
margin-bottom: 5px;
color: #555;
}
.control-group select,
.control-group input {
padding: 5px;
border: 1px solid #ddd;
border-radius: 5px;
font-size: 12px;
}
.training-buttons {
display: flex;
gap: 5px;
flex-wrap: wrap;
}
.training-buttons button {
padding: 5px 10px;
font-size: 11px;
border: none;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.3s;
}
.training-buttons button:first-child {
background: #28a745;
color: white;
}
.training-buttons button:nth-child(2) {
background: #dc3545;
color: white;
}
.training-buttons button:last-child {
background: #007bff;
color: white;
}
.training-buttons button:hover {
opacity: 0.8;
}
.training-buttons button:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.training-status {
background: white;
border: 1px solid #ddd;
border-radius: 5px;
padding: 10px;
}
.progress-bar {
width: 100%;
height: 20px;
background: #e9ecef;
border-radius: 10px;
overflow: hidden;
margin: 10px 0;
}
.progress-fill {
height: 100%;
background: linear-gradient(90deg, #28a745, #20c997);
transition: width 0.3s ease;
}
.training-logs {
max-height: 100px;
overflow-y: auto;
font-size: 11px;
color: #666;
background: #f8f9fa;
padding: 5px;
border-radius: 3px;
}
</style>
</head>
<body>
<div class="chat-container">
<div class="chat-header">
<h1>🤖 Textilindo AI Assistant</h1>
<p>Asisten AI untuk membantu pertanyaan tentang Textilindo</p>
</div>
<div class="chat-messages" id="chatMessages">
<div class="welcome-message">
👋 Halo! Saya adalah asisten AI Textilindo. Bagaimana saya bisa membantu Anda hari ini?
</div>
<!-- Training Section -->
<div class="training-section" id="trainingSection" style="display: none;">
<div class="training-header">
<h3>🤖 AI Training</h3>
<button id="toggleTraining" onclick="toggleTrainingPanel()">Show Training</button>
</div>
<div class="training-panel" id="trainingPanel" style="display: none;">
<div class="training-controls">
<div class="control-group">
<label>Model:</label>
<select id="modelSelect">
<option value="meta-llama/Llama-3.1-8B-Instruct">Llama 3.1 8B (Best Quality)</option>
<option value="meta-llama/Llama-3.2-1B-Instruct">Llama 3.2 1B (Fast)</option>
<option value="meta-llama/Llama-3.2-3B-Instruct">Llama 3.2 3B (Balanced)</option>
<option value="gpt2">GPT-2 (Lightweight)</option>
<option value="distilgpt2">DistilGPT-2 (Smallest)</option>
<option value="microsoft/DialoGPT-small">DialoGPT Small (Conversational)</option>
</select>
</div>
<div class="control-group">
<label>Epochs:</label>
<input type="number" id="epochsInput" value="3" min="1" max="10">
</div>
<div class="control-group">
<label>Batch Size:</label>
<input type="number" id="batchSizeInput" value="4" min="1" max="16">
</div>
<div class="training-buttons">
<button id="startTraining" onclick="startTraining()">Start Training</button>
<button id="stopTraining" onclick="stopTraining()" disabled>Stop Training</button>
<button onclick="getTrainingStatus()">Check Status</button>
</div>
</div>
<div class="training-status" id="trainingStatus">
<p>Status: <span id="statusText">Ready</span></p>
<div class="progress-bar">
<div class="progress-fill" id="progressFill" style="width: 0%"></div>
</div>
<div class="training-logs" id="trainingLogs"></div>
</div>
</div>
</div>
</div>
<div class="typing-indicator" id="typingIndicator">
<span class="typing-dots">AI sedang mengetik</span>
</div>
<div class="chat-input-container">
<input
type="text"
id="messageInput"
class="chat-input"
placeholder="Tulis pesan Anda..."
autocomplete="off"
>
<button id="sendButton" class="send-button" onclick="sendMessage()">
</button>
</div>
</div>
<script>
const chatMessages = document.getElementById('chatMessages');
const messageInput = document.getElementById('messageInput');
const sendButton = document.getElementById('sendButton');
const typingIndicator = document.getElementById('typingIndicator');
// Focus on input when page loads
messageInput.focus();
// Handle Enter key
messageInput.addEventListener('keypress', function(e) {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
sendMessage();
}
});
// Auto-resize input
messageInput.addEventListener('input', function() {
this.style.height = 'auto';
this.style.height = this.scrollHeight + 'px';
});
async function sendMessage() {
const message = messageInput.value.trim();
if (!message) return;
// Disable input and button
messageInput.disabled = true;
sendButton.disabled = true;
// Add user message
addMessage(message, 'user');
messageInput.value = '';
messageInput.style.height = 'auto';
// Show typing indicator
showTypingIndicator();
try {
const response = await fetch('/chat', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ message: message })
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
hideTypingIndicator();
addMessage(data.response, 'assistant');
} catch (error) {
console.error('Error:', error);
hideTypingIndicator();
addMessage('Maaf, terjadi kesalahan. Silakan coba lagi.', 'assistant');
} finally {
// Re-enable input and button
messageInput.disabled = false;
sendButton.disabled = false;
messageInput.focus();
}
}
function addMessage(text, sender) {
const messageDiv = document.createElement('div');
messageDiv.className = `message ${sender}-message`;
messageDiv.textContent = text;
chatMessages.appendChild(messageDiv);
chatMessages.scrollTop = chatMessages.scrollHeight;
}
function showTypingIndicator() {
typingIndicator.style.display = 'block';
chatMessages.appendChild(typingIndicator);
chatMessages.scrollTop = chatMessages.scrollHeight;
}
function hideTypingIndicator() {
typingIndicator.style.display = 'none';
if (typingIndicator.parentNode) {
typingIndicator.parentNode.removeChild(typingIndicator);
}
}
// Add some sample questions
const sampleQuestions = [
"dimana lokasi textilindo?",
"jam berapa textilindo beroperasional?",
"berapa ketentuan pembelian?",
"apa ada gratis ongkir?",
"apa bisa dikirimkan sample?"
];
// Add sample questions as clickable buttons
function addSampleQuestions() {
const sampleContainer = document.createElement('div');
sampleContainer.style.marginTop = '20px';
sampleContainer.innerHTML = '<p style="text-align: center; color: #666; margin-bottom: 10px;">Pertanyaan yang sering diajukan:</p>';
sampleQuestions.forEach(question => {
const button = document.createElement('button');
button.textContent = question;
button.style.cssText = `
display: block;
width: 100%;
margin: 5px 0;
padding: 8px 12px;
background: #f8f9fa;
border: 1px solid #e9ecef;
border-radius: 15px;
cursor: pointer;
font-size: 12px;
text-align: left;
transition: background-color 0.3s ease;
`;
button.addEventListener('mouseenter', () => {
button.style.backgroundColor = '#e9ecef';
});
button.addEventListener('mouseleave', () => {
button.style.backgroundColor = '#f8f9fa';
});
button.addEventListener('click', () => {
messageInput.value = question;
sendMessage();
});
sampleContainer.appendChild(button);
});
chatMessages.appendChild(sampleContainer);
}
// Add sample questions after welcome message
setTimeout(addSampleQuestions, 1000);
// Training Functions
function toggleTrainingPanel() {
const panel = document.getElementById('trainingPanel');
const button = document.getElementById('toggleTraining');
const section = document.getElementById('trainingSection');
if (panel.style.display === 'none') {
panel.style.display = 'block';
button.textContent = 'Hide Training';
section.style.display = 'block';
} else {
panel.style.display = 'none';
button.textContent = 'Show Training';
}
}
async function startTraining() {
const model = document.getElementById('modelSelect').value;
const epochs = parseInt(document.getElementById('epochsInput').value);
const batchSize = parseInt(document.getElementById('batchSizeInput').value);
const startBtn = document.getElementById('startTraining');
const stopBtn = document.getElementById('stopTraining');
startBtn.disabled = true;
stopBtn.disabled = false;
try {
const response = await fetch('/api/train/start', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
model_name: model,
epochs: epochs,
batch_size: batchSize
})
});
const result = await response.json();
if (result.success) {
updateTrainingStatus('Training started...', 0);
// Start polling for status
pollTrainingStatus();
} else {
alert('Error starting training: ' + result.message);
startBtn.disabled = false;
stopBtn.disabled = true;
}
} catch (error) {
alert('Error: ' + error.message);
startBtn.disabled = false;
stopBtn.disabled = true;
}
}
async function stopTraining() {
try {
const response = await fetch('/api/train/stop', {
method: 'POST'
});
const result = await response.json();
updateTrainingStatus('Training stopped', 0);
document.getElementById('startTraining').disabled = false;
document.getElementById('stopTraining').disabled = true;
} catch (error) {
alert('Error stopping training: ' + error.message);
}
}
async function getTrainingStatus() {
try {
const response = await fetch('/api/train/status');
const result = await response.json();
if (result.success) {
const status = result.status;
updateTrainingStatus(status.status, status.progress);
if (status.is_training) {
pollTrainingStatus();
} else {
document.getElementById('startTraining').disabled = false;
document.getElementById('stopTraining').disabled = true;
}
}
} catch (error) {
console.error('Error getting training status:', error);
}
}
function updateTrainingStatus(status, progress) {
document.getElementById('statusText').textContent = status;
document.getElementById('progressFill').style.width = progress + '%';
const logs = document.getElementById('trainingLogs');
const timestamp = new Date().toLocaleTimeString();
logs.innerHTML += `<div>[${timestamp}] ${status}</div>`;
logs.scrollTop = logs.scrollHeight;
}
function pollTrainingStatus() {
setTimeout(async () => {
await getTrainingStatus();
}, 2000); // Poll every 2 seconds
}
// Show training section on page load
document.addEventListener('DOMContentLoaded', function() {
document.getElementById('trainingSection').style.display = 'block';
});
</script>
</body>
</html>