// API base URL
const API_BASE = '/api';
// Initialize
document.addEventListener('DOMContentLoaded', () => {
loadBooks();
loadSchedules();
// Event listeners
document.getElementById('send-btn').addEventListener('click', sendChatMessage);
document.getElementById('chat-input').addEventListener('keypress', (e) => {
if (e.key === 'Enter') sendChatMessage();
});
document.getElementById('upload-btn').addEventListener('click', uploadPDF);
document.getElementById('add-schedule-btn').addEventListener('click', addSchedule);
});
async function sendChatMessage() {
const input = document.getElementById('chat-input');
const message = input.value.trim();
if (!message) return;
// Add user message to chat
addMessage(message, 'user');
input.value = '';
// Show loading
showLoading();
try {
const response = await fetch(`${API_BASE}/chat`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message, top_k: 3 }),
});
if (!response.ok) {
throw new Error('Erro ao enviar mensagem');
}
const data = await response.json();
// Remove loading
hideLoading();
// Add bot response
addMessage(data.response, 'bot');
// Add sources
if (data.sources && data.sources.length > 0) {
const sourceText = data.sources.map(s => `📖 ${s.metadata.title} (chunk ${s.metadata.chunk_id})`).join('\n');
addMessage(`Fontes: ${sourceText}`, 'bot', true);
}
} catch (error) {
hideLoading();
addMessage(`❌ Erro: ${error.message}`, 'bot');
}
}
function addMessage(content, type, isSource = false) {
const container = document.getElementById('chat-messages');
const messageDiv = document.createElement('div');
messageDiv.className = `message ${type}`;
if (isSource) {
messageDiv.style.fontSize = '0.85rem';
}
messageDiv.innerHTML = `
${content}
`;
container.appendChild(messageDiv);
container.scrollTop = container.scrollHeight;
}
function showLoading() {
const container = document.getElementById('chat-messages');
const loadingDiv = document.createElement('div');
loadingDiv.id = 'chat-loading';
loadingDiv.className = 'message bot';
loadingDiv.innerHTML = 'Carregando...
';
container.appendChild(loadingDiv);
container.scrollTop = container.scrollHeight;
}
function hideLoading() {
const loading = document.getElementById('chat-loading');
if (loading) loading.remove();
}
async function loadBooks() {
try {
const response = await fetch(`${API_BASE}/books`);
const books = await response.json();
const booksList = document.getElementById('books-list');
booksList.innerHTML = '';
if (books.length === 0) {
booksList.innerHTML = 'Nenhum livro encontrado.
';
return;
}
books.forEach(book => {
const bookDiv = document.createElement('div');
bookDiv.className = 'book-item';
bookDiv.innerHTML = `
📖
${book.title}
`;
booksList.appendChild(bookDiv);
});
// Update book dropdown
const select = document.getElementById('schedule-book');
select.innerHTML = '';
books.forEach(book => {
const option = document.createElement('option');
option.value = book.title;
option.textContent = book.title;
select.appendChild(option);
});
} catch (error) {
console.error('Erro ao carregar livros:', error);
}
}
async function uploadPDF() {
const fileInput = document.getElementById('file-input');
const file = fileInput.files[0];
if (!file) {
alert('Selecione um arquivo PDF primeiro');
return;
}
const statusDiv = document.getElementById('upload-status');
statusDiv.textContent = 'Enviando...';
try {
const formData = new FormData();
formData.append('file', file);
const response = await fetch(`${API_BASE}/upload`, {
method: 'POST',
body: formData,
});
if (!response.ok) {
throw new Error('Erro ao fazer upload');
}
const data = await response.json();
statusDiv.textContent = `✅ ${data.filename} enviado com sucesso!`;
statusDiv.style.color = '#4caf50';
setTimeout(() => {
statusDiv.textContent = '';
fileInput.value = '';
}, 3000);
// Reload books
loadBooks();
} catch (error) {
statusDiv.textContent = `❌ Erro: ${error.message}`;
statusDiv.style.color = '#f44336';
}
}
async function loadSchedules() {
try {
const response = await fetch(`${API_BASE}/schedules`);
const schedules = await response.json();
renderSchedules(schedules);
} catch (error) {
console.error('Erro ao carregar agendamentos:', error);
}
}
function renderSchedules(schedules) {
const container = document.getElementById('schedules-list');
container.innerHTML = '';
if (schedules.length === 0) {
container.innerHTML = 'Nenhum agendamento.
';
return;
}
schedules.forEach(schedule => {
const div = document.createElement('div');
div.className = 'schedule-item';
div.innerHTML = `
🕐 ${formatDateTime(schedule.time)}
${schedule.book || 'Todos os livros'}
`;
container.appendChild(div);
// Add delete handler
div.querySelector('.schedule-delete').addEventListener('click', () => deleteSchedule(schedule.id));
});
}
async function addSchedule() {
const timeInput = document.getElementById('schedule-time');
const bookSelect = document.getElementById('schedule-book');
if (!timeInput.value) {
alert('Selecione uma data e hora');
return;
}
try {
const response = await fetch(`${API_BASE}/schedules`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
time: timeInput.value,
book: bookSelect.value || null,
enabled: true,
}),
});
if (!response.ok) {
throw new Error('Erro ao criar agendamento');
}
const schedule = await response.json();
loadSchedules();
timeInput.value = '';
bookSelect.value = '';
} catch (error) {
alert(`Erro: ${error.message}`);
}
}
async function deleteSchedule(scheduleId) {
if (!confirm('Tem certeza que deseja excluir este agendamento?')) {
return;
}
try {
const response = await fetch(`${API_BASE}/schedules/${scheduleId}`, {
method: 'DELETE',
});
if (!response.ok) {
throw new Error('Erro ao excluir agendamento');
}
loadSchedules();
} catch (error) {
alert(`Erro: ${error.message}`);
}
}
function formatDateTime(dateString) {
const date = new Date(dateString);
return date.toLocaleString('pt-BR');
}