Spaces:
Sleeping
Sleeping
class DocumentSearchChatBot { | |
constructor() { | |
this.selectedDocuments = new Set(); | |
this.searchResults = []; | |
this.chatHistory = []; | |
this.initializeEventListeners(); | |
this.updateThresholdDisplay(); | |
} | |
initializeEventListeners() { | |
// Search form | |
document.getElementById('search-form').addEventListener('submit', (e) => { | |
e.preventDefault(); | |
this.performSearch(); | |
}); | |
// Threshold slider | |
document.getElementById('threshold').addEventListener('input', (e) => { | |
this.updateThresholdDisplay(); | |
}); | |
// Selection controls | |
document.getElementById('select-all').addEventListener('click', () => { | |
this.selectAllDocuments(); | |
}); | |
document.getElementById('unselect-all').addEventListener('click', () => { | |
this.unselectAllDocuments(); | |
}); | |
// Chat launch | |
document.getElementById('start-chat').addEventListener('click', () => { | |
this.startChat(); | |
}); | |
// Chat form | |
document.getElementById('chat-form').addEventListener('submit', (e) => { | |
e.preventDefault(); | |
this.sendChatMessage(); | |
}); | |
// Back to search | |
document.getElementById('back-to-search').addEventListener('click', () => { | |
this.backToSearch(); | |
}); | |
// Modal close | |
document.querySelector('.modal-close').addEventListener('click', () => { | |
this.closeModal(); | |
}); | |
// Close modal on background click | |
document.getElementById('modal').addEventListener('click', (e) => { | |
if (e.target.id === 'modal') { | |
this.closeModal(); | |
} | |
}); | |
} | |
updateThresholdDisplay() { | |
const threshold = document.getElementById('threshold').value; | |
document.getElementById('threshold-value').textContent = threshold; | |
} | |
async performSearch() { | |
const keyword = document.getElementById('keyword').value.trim(); | |
const threshold = parseFloat(document.getElementById('threshold').value); | |
if (!keyword) return; | |
this.showLoading(); | |
try { | |
const response = await fetch('/search', { | |
method: 'POST', | |
headers: { | |
'Content-Type': 'application/json', | |
}, | |
body: JSON.stringify({ | |
keyword: keyword, | |
threshold: threshold | |
}) | |
}); | |
if (!response.ok) { | |
throw new Error(`HTTP error! status: ${response.status}`); | |
} | |
const data = await response.json(); | |
this.searchResults = data.results || []; | |
this.displayResults(); | |
} catch (error) { | |
console.error('Erreur lors de la recherche:', error); | |
this.showError('Erreur lors de la recherche. Veuillez réessayer.'); | |
} finally { | |
this.hideLoading(); | |
} | |
} | |
displayResults() { | |
const resultsContainer = document.getElementById('results-container'); | |
const resultsSection = document.getElementById('results-section'); | |
if (this.searchResults.length === 0) { | |
resultsContainer.innerHTML = '<p class="no-results">Aucun résultat trouvé.</p>'; | |
resultsSection.classList.remove('hidden'); | |
return; | |
} | |
resultsContainer.innerHTML = ''; | |
this.searchResults.forEach((result, index) => { | |
const card = this.createResultCard(result, index); | |
resultsContainer.appendChild(card); | |
let viewBtn = card.querySelector('.view-btn'); | |
viewBtn.addEventListener('click', () => { | |
this.showDocumentContent(result.id, result.section, result.content); | |
}); | |
}); | |
resultsSection.classList.remove('hidden'); | |
this.updateChatButtonState(); | |
} | |
createResultCard(result, index) { | |
const card = document.createElement('div'); | |
card.className = 'result-card'; | |
card.dataset.index = index; | |
card.innerHTML = ` | |
<div class="card-header"> | |
<div class="card-info"> | |
<div class="card-id">ID: ${result.id}</div> | |
<div class="card-title">${result.title}</div> | |
<div class="card-section">${result.section}</div> | |
</div> | |
<div class="similarity-score">${result.similarity}%</div> | |
</div> | |
<div class="card-actions"> | |
<button class="view-btn" data-id="${result.id}" data-section="${result.section}" data-content="${result.content}"> | |
<span class="material-icons">visibility</span> | |
Voir le contenu | |
</button> | |
<input type="checkbox" class="select-checkbox" onchange="app.toggleDocumentSelection(${index})"> | |
</div> | |
`; | |
return card; | |
} | |
toggleDocumentSelection(index) { | |
const card = document.querySelector(`[data-index="${index}"]`); | |
const checkbox = card.querySelector('.select-checkbox'); | |
if (checkbox.checked) { | |
this.selectedDocuments.add(index); | |
card.classList.add('selected'); | |
} else { | |
this.selectedDocuments.delete(index); | |
card.classList.remove('selected'); | |
} | |
this.updateChatButtonState(); | |
} | |
selectAllDocuments() { | |
const checkboxes = document.querySelectorAll('.select-checkbox'); | |
checkboxes.forEach((checkbox, index) => { | |
checkbox.checked = true; | |
this.selectedDocuments.add(index); | |
checkbox.closest('.result-card').classList.add('selected'); | |
}); | |
this.updateChatButtonState(); | |
} | |
unselectAllDocuments() { | |
const checkboxes = document.querySelectorAll('.select-checkbox'); | |
checkboxes.forEach((checkbox, index) => { | |
checkbox.checked = false; | |
this.selectedDocuments.delete(index); | |
checkbox.closest('.result-card').classList.remove('selected'); | |
}); | |
this.updateChatButtonState(); | |
} | |
updateChatButtonState() { | |
const chatButton = document.getElementById('start-chat'); | |
chatButton.disabled = this.selectedDocuments.size === 0; | |
} | |
showDocumentContent(id, section, content) { | |
// Simuler le contenu du document (remplacer par un appel API réel) | |
document.getElementById('modal-title').textContent = `Specification n°${id} - ${section}`; | |
document.getElementById('modal-body').textContent = content; | |
document.getElementById('modal').style.display = 'block'; | |
} | |
closeModal() { | |
document.getElementById('modal').style.display = 'none'; | |
} | |
startChat() { | |
if (this.selectedDocuments.size === 0) return; | |
const selectedDocs = Array.from(this.selectedDocuments).map(index => { | |
const doc = this.searchResults[index]; | |
return `(${doc.id} ${doc.title} ${doc.section} ${doc.content || ""})` | |
}).join("\n"); | |
this.chatHistory = [{"role": "system", "content": `You are a helpful AI assistant. You will answer any questions related to the following specifications: ${selectedDocs}`}]; | |
document.getElementById('search-section').classList.add('hidden'); | |
document.getElementById('results-section').classList.add('hidden'); | |
document.getElementById('chat-section').classList.remove('hidden'); | |
// Ajouter un message de bienvenue | |
this.addChatMessage('bot', `Bonjour ! Je suis prêt à répondre à vos questions sur les ${this.selectedDocuments.size} document(s) sélectionné(s). Que souhaitez-vous savoir ?`); | |
} | |
backToSearch() { | |
document.getElementById('chat-section').classList.add('hidden'); | |
document.getElementById('search-section').classList.remove('hidden'); | |
document.getElementById('results-section').classList.remove('hidden'); | |
// Vider les messages du chat | |
document.getElementById('chat-messages').innerHTML = ''; | |
} | |
async sendChatMessage() { | |
const input = document.getElementById('chat-input'); | |
const message = input.value.trim(); | |
const model = document.getElementById('model-select').value; | |
if (!message) return; | |
// Ajouter le message de l'utilisateur | |
this.addChatMessage('user', message); | |
input.value = ''; | |
this.chatHistory.push({"role": "user", "content": message}); | |
// Désactiver le formulaire pendant l'envoi | |
const form = document.getElementById('chat-form'); | |
const submitBtn = form.querySelector('button'); | |
submitBtn.disabled = true; | |
try { | |
const response = await fetch('/chat', { | |
method: 'POST', | |
headers: { | |
'Content-Type': 'application/json' | |
}, | |
body: JSON.stringify({ | |
messages: this.chatHistory, | |
model: model, | |
}) | |
}); | |
if (!response.ok) { | |
this.chatHistory.push({"role": "assistant", "content": `HTTP error! status: ${response.status}`}) | |
throw new Error(`HTTP error! status: ${response.status}`); | |
} | |
const data = await response.json(); | |
this.addChatMessage('bot', data.response); | |
this.chatHistory.push({"role": "assistant", "content": data.response}) | |
} catch (error) { | |
console.error('Erreur lors de l\'envoi du message:', error); | |
this.addChatMessage('bot', 'Désolé, une erreur s\'est produite. Veuillez réessayer.'); | |
} finally { | |
submitBtn.disabled = false; | |
} | |
} | |
addChatMessage(sender, message) { | |
const messagesContainer = document.getElementById('chat-messages'); | |
const messageDiv = document.createElement('div'); | |
messageDiv.className = `message ${sender}`; | |
messageDiv.textContent = message; | |
messagesContainer.appendChild(messageDiv); | |
messagesContainer.scrollTop = messagesContainer.scrollHeight; | |
} | |
showLoading() { | |
document.getElementById('loading').classList.remove('hidden'); | |
} | |
hideLoading() { | |
document.getElementById('loading').classList.add('hidden'); | |
} | |
showError(message) { | |
// Vous pouvez implémenter une notification d'erreur plus sophistiquée | |
alert(message); | |
} | |
} | |
// Initialiser l'application | |
const app = new DocumentSearchChatBot(); | |
// Fonction globale pour les événements onclick dans le HTML | |
window.app = app; | |