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; | |