fix: responder a partir dos livros com embeddings em português

Usa o modelo multilingual, ignora trechos curtos e o template do Llama 3.2
para a resposta sair em uma frase completa. O chat deixa a API livre durante
a geração, o upload indexa o PDF e os agendamentos não são gravados duas vezes.
This commit is contained in:
lgcosta committed 2026-11-01 12:34:54 -03:00
1 parent 7af7ba530d
commit 8eeb6b89f4
11 files changed
+185 -90

No files matched your search

+34
View File
@@ -85,6 +85,7 @@ header p {
.message-content {
line-height: 1.6;
white-space: pre-wrap;
}
.message-source {
@@ -170,3 +171,36 @@ th {
border-color: #667eea;
background: #f9f9f9;
}
.book-item {
display: flex;
gap: 8px;
align-items: center;
padding: 8px 0;
border-bottom: 1px solid #eee;
}
.schedule-item {
display: flex;
justify-content: space-between;
align-items: center;
gap: 12px;
padding: 8px 0;
border-bottom: 1px solid #eee;
}
.schedule-info {
display: flex;
flex-direction: column;
gap: 4px;
}
button.schedule-delete {
width: auto;
padding: 8px 12px;
}
#upload-status {
margin-top: 10px;
min-height: 1.2em;
}
+42 -32
View File
@@ -17,9 +17,11 @@ document.addEventListener('DOMContentLoaded', () => {
async function sendChatMessage() {
const input = document.getElementById('chat-input');
const button = document.getElementById('send-btn');
const message = input.value.trim();
if (!message) return;
if (!message || button.disabled) return;
button.disabled = true;
// Add user message to chat
addMessage(message, 'user');
@@ -35,39 +37,39 @@ async function sendChatMessage() {
body: JSON.stringify({ message, top_k: 3 }),
});
const data = await response.json().catch(() => ({}));
if (!response.ok) {
throw new Error('Erro ao enviar mensagem');
const detail = typeof data.detail === 'string' ? data.detail : 'Erro ao enviar mensagem';
throw new Error(detail);
}
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);
const sourceText = data.sources.map((source) => {
const meta = source.metadata || source;
return `📖 ${meta.title || 'Desconhecido'} (trecho ${meta.chunk_id ?? '?'})`;
}).join('\n');
addMessage(`Fontes:\n${sourceText}`, 'bot');
}
} catch (error) {
hideLoading();
addMessage(`❌ Erro: ${error.message}`, 'bot');
addMessage(`Erro: ${error.message}`, 'bot');
} finally {
button.disabled = false;
input.focus();
}
}
function addMessage(content, type, isSource = false) {
function addMessage(content, type) {
const container = document.getElementById('chat-messages');
const messageDiv = document.createElement('div');
messageDiv.className = `message ${type}`;
if (isSource) {
messageDiv.style.fontSize = '0.85rem';
}
messageDiv.innerHTML = `<div class="message-content">${content}</div>`;
const body = document.createElement('div');
body.className = 'message-content';
body.textContent = content;
messageDiv.appendChild(body);
container.appendChild(messageDiv);
container.scrollTop = container.scrollHeight;
}
@@ -103,10 +105,13 @@ async function loadBooks() {
books.forEach(book => {
const bookDiv = document.createElement('div');
bookDiv.className = 'book-item';
bookDiv.innerHTML = `
<div class="book-icon">📖</div>
<div class="book-name">${book.title}</div>
`;
const icon = document.createElement('div');
icon.className = 'book-icon';
icon.textContent = '📖';
const name = document.createElement('div');
name.className = 'book-name';
name.textContent = book.title;
bookDiv.append(icon, name);
booksList.appendChild(bookDiv);
});
@@ -189,17 +194,22 @@ function renderSchedules(schedules) {
schedules.forEach(schedule => {
const div = document.createElement('div');
div.className = 'schedule-item';
div.innerHTML = `
<div class="schedule-info">
<span class="schedule-time">🕐 ${formatDateTime(schedule.time)}</span>
<span class="schedule-book">${schedule.book || 'Todos os livros'}</span>
</div>
<button class="schedule-delete" data-id="${schedule.id}">🗑️</button>
`;
const info = document.createElement('div');
info.className = 'schedule-info';
const time = document.createElement('span');
time.className = 'schedule-time';
time.textContent = formatDateTime(schedule.time);
const book = document.createElement('span');
book.className = 'schedule-book';
book.textContent = schedule.book || 'Todos os livros';
info.append(time, book);
const remove = document.createElement('button');
remove.className = 'schedule-delete';
remove.type = 'button';
remove.textContent = 'Excluir';
remove.addEventListener('click', () => deleteSchedule(schedule.id));
div.append(info, remove);
container.appendChild(div);
// Add delete handler
div.querySelector('.schedule-delete').addEventListener('click', () => deleteSchedule(schedule.id));
});
}