35890-vm/assets/js/main.js
2025-11-21 21:40:28 +00:00

280 lines
12 KiB
JavaScript

document.addEventListener('DOMContentLoaded', function() {
const messageForm = document.getElementById('message-form');
const messageInput = document.getElementById('message-input');
const chatBox = document.getElementById('chat-box');
const typingIndicator = document.getElementById('typing-indicator');
let currentUser = '';
let lastAnimatedMessageId = null;
function showTypingIndicator() {
if (typingIndicator) {
typingIndicator.style.display = 'block';
chatBox.scrollTop = chatBox.scrollHeight;
}
}
function hideTypingIndicator() {
if (typingIndicator) {
typingIndicator.style.display = 'none';
}
}
function createAvatar(message) {
const avatar = document.createElement('div');
avatar.classList.add('avatar');
const initial = message.user_initial || (message.username === 'AI' ? 'A' : '?');
avatar.textContent = initial;
// Add a color based on the username
const colors = ['#f44336', '#e91e63', '#9c27b0', '#673ab7', '#3f51b5', '#2196f3', '#03a9f4', '#00bcd4', '#009688', '#4caf50', '#8bc34a', '#cddc39', '#ffeb3b', '#ffc107', '#ff9800', '#ff5722', '#795548', '#607d8b'];
const colorIndex = message.username.charCodeAt(0) % colors.length;
avatar.style.backgroundColor = colors[colorIndex];
return avatar;
}
function renderMessage(message) {
const isSent = message.username === currentUser;
if (isSent || message.username === 'AI') {
hideTypingIndicator();
}
const messageElement = document.createElement('div');
messageElement.classList.add('message', isSent ? 'sent' : 'received');
messageElement.dataset.messageId = message.id;
const avatar = createAvatar(message);
messageElement.appendChild(avatar);
const messageBody = document.createElement('div');
messageBody.classList.add('message-body');
if (!isSent) {
const usernameElement = document.createElement('div');
usernameElement.classList.add('message-username');
usernameElement.textContent = message.username;
messageBody.appendChild(usernameElement);
}
const messageP = document.createElement('p');
messageP.classList.add('message-text');
messageP.textContent = message.message;
const messageTime = document.createElement('span');
messageTime.classList.add('message-time');
const time = new Date(message.created_at);
messageTime.textContent = time.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
messageBody.appendChild(messageP);
messageBody.appendChild(messageTime);
messageElement.appendChild(messageBody);
chatBox.appendChild(messageElement);
chatBox.scrollTop = chatBox.scrollHeight;
}
function renderMessageWithStreaming(message) {
renderMessage({ ...message, message: '' }); // Render the container first
const messageP = chatBox.querySelector(`[data-message-id="${message.id}"] .message-text`);
if (!messageP) return;
const words = message.message.split(' ');
let i = 0;
const interval = setInterval(() => {
if (i < words.length) {
messageP.textContent += (i > 0 ? ' ' : '') + words[i];
chatBox.scrollTop = chatBox.scrollHeight;
i++;
} else {
clearInterval(interval);
}
}, 100);
}
async function fetchMessages() {
try {
const response = await fetch('/api/chat.php');
if (!response.ok) {
if (response.status === 401) window.location.href = 'login.php';
throw new Error('Network response was not ok');
}
const data = await response.json();
if (data.success) {
currentUser = data.currentUser;
const messages = data.messages || [];
const existingMessageIds = new Set([...chatBox.querySelectorAll('.message')].map(m => m.dataset.messageId));
messages.forEach(message => {
if (!existingMessageIds.has(message.id.toString())) {
const isAI = message.username === 'AI';
const isNewer = message.id > lastAnimatedMessageId;
if (isAI && isNewer) {
lastAnimatedMessageId = message.id;
renderMessageWithStreaming(message);
} else {
renderMessage(message);
}
}
});
if (messages.length > 0) {
const lastMessage = messages[messages.length - 1];
if (lastMessage.username !== 'AI') {
hideTypingIndicator();
}
}
}
} catch (error) {
console.error('Error fetching messages:', error);
hideTypingIndicator();
}
}
async function resetChat() {
try {
const response = await fetch('/api/chat.php?action=reset');
const result = await response.json();
if (result.success) {
chatBox.innerHTML = '';
} else {
console.error('Error resetting chat:', result.error);
}
} catch (error) {
console.error('Error resetting chat:', error);
}
}
if (chatBox) {
fetchMessages();
setInterval(fetchMessages, 3000);
if (messageForm) {
messageForm.addEventListener('submit', async function(e) {
e.preventDefault();
const messageText = messageInput.value.trim();
if (messageText === '/reset') {
messageInput.value = '';
await resetChat();
return;
}
if (messageText !== '') {
messageInput.value = '';
messageInput.focus();
showTypingIndicator();
// Optimistically render user's message
const tempId = `temp_${new Date().getTime()}`;
renderMessage({
id: tempId,
username: currentUser,
message: messageText,
created_at: new Date().toISOString(),
user_initial: currentUser.charAt(0).toUpperCase()
});
const personality = document.getElementById('ai-personality').value.trim();
try {
const response = await fetch('/api/chat.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message: messageText, personality: personality })
});
const result = await response.json();
if (!result.success) {
console.error('Error saving message:', result.error);
// Optionally remove the optimistic message or show an error
const failedMsg = chatBox.querySelector(`[data-message-id="${tempId}"]`);
if(failedMsg) failedMsg.classList.add('error');
}
// The poller will fetch the confirmed message from the server
} catch (error) {
console.error('Error sending message:', error);
hideTypingIndicator();
const failedMsg = chatBox.querySelector(`[data-message-id="${tempId}"]`);
if(failedMsg) failedMsg.classList.add('error');
}
}
});
}
}
// Security Panel Logic
const vpnConnectBtn = document.getElementById('vpn-connect-btn');
const vpnStatus = document.getElementById('vpn-status');
const vpnCountrySelect = document.getElementById('vpn-country');
const antivirusScanBtn = document.getElementById('antivirus-scan-btn');
const antivirusResult = document.getElementById('antivirus-result');
let isVpnConnected = false;
if (vpnConnectBtn) {
vpnConnectBtn.addEventListener('click', async () => {
isVpnConnected = !isVpnConnected;
if (isVpnConnected) {
const selectedCountry = vpnCountrySelect.value;
vpnConnectBtn.textContent = 'Desconectar';
vpnConnectBtn.classList.remove('btn-primary');
vpnConnectBtn.classList.add('btn-danger');
vpnStatus.innerHTML = '<p class="text-primary">Conectando...</p>';
const prompt = `Simule que você está estabelecendo uma conexão VPN para o país ${selectedCountry}. Descreva o processo e, ao final, confirme a conexão segura e forneça um endereço de IP fictício para esse país.`;
try {
const response = await fetch('/api/chat.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message: prompt, context: 'vpn' }) // Add context for the API
});
const result = await response.json();
if (result.success && result.data) {
vpnStatus.innerHTML = `<p class="text-success">${result.data.replace(/\n/g, '<br>')}</p>`;
} else {
vpnStatus.innerHTML = '<p class="text-danger">Falha ao conectar. Tente novamente.</p>';
}
} catch (error) {
console.error('VPN connection error:', error);
vpnStatus.innerHTML = '<p class="text-danger">Ocorreu um erro na simulação.</p>';
}
} else {
vpnConnectBtn.textContent = 'Conectar';
vpnConnectBtn.classList.remove('btn-danger');
vpnConnectBtn.classList.add('btn-primary');
vpnStatus.innerHTML = '<p class="text-muted">Status: Desconectado</p>';
}
});
}
if (antivirusScanBtn) {
antivirusScanBtn.addEventListener('click', async () => {
antivirusScanBtn.disabled = true;
antivirusResult.innerHTML = '<p class="text-primary">Verificando sistema... Isso pode levar um momento.</p>';
const prompt = `Simule uma verificação completa de um sistema de computador em busca de vírus e malware. Descreva as etapas da verificação (ex: verificação de memória, arquivos de inicialização, registro, arquivos do sistema). Ao final, apresente um relatório com os resultados, informando se alguma ameaça foi encontrada ou se o sistema está limpo.`;
try {
const response = await fetch('/api/chat.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message: prompt, context: 'antivirus' }) // Add context for the API
});
const result = await response.json();
if (result.success && result.data) {
antivirusResult.innerHTML = `<p class="text-success">${result.data.replace(/\n/g, '<br>')}</p>`;
} else {
antivirusResult.innerHTML = '<p class="text-danger">A verificação falhou. Tente novamente.</p>';
} catch (error) {
console.error('Antivirus scan error:', error);
antivirusResult.innerHTML = '<p class="text-danger">Ocorreu um erro na simulação da verificação.</p>';
} finally {
antivirusScanBtn.disabled = false;
}
});
}
});