| |
| |
| |
| |
|
|
| document.addEventListener('DOMContentLoaded', function() { |
| |
| const uploadButton = document.getElementById('uploadButton'); |
| const uploadSuccess = document.getElementById('uploadSuccess'); |
| const uploadSuccessMessage = document.getElementById('uploadSuccessMessage'); |
| const uploadError = document.getElementById('uploadError'); |
| const uploadErrorMessage = document.getElementById('uploadErrorMessage'); |
| const refreshStatus = document.getElementById('refreshStatus'); |
| const databaseStats = document.getElementById('databaseStats'); |
| const documentsContainer = document.getElementById('documentsContainer'); |
| |
| |
| Dropzone.autoDiscover = false; |
| |
| const documentUploadDropzone = new Dropzone("#documentUploadForm", { |
| url: "/api/upload", |
| maxFilesize: 10, |
| acceptedFiles: ".txt,.md,.pdf,.docx,.csv", |
| addRemoveLinks: true, |
| dictDefaultMessage: "ํ์ผ์ ๋์ด๋ค ๋๊ฑฐ๋ ํด๋ฆญํ์ฌ ์ ํํ์ธ์", |
| dictRemoveFile: "์ ๊ฑฐ", |
| dictCancelUpload: "์
๋ก๋ ์ทจ์", |
| dictUploadCanceled: "์
๋ก๋ ์ทจ์๋จ", |
| dictFileTooBig: "ํ์ผ์ด ๋๋ฌด ํฝ๋๋ค ({{filesize}}MB). ์ต๋ ํ์ผ ํฌ๊ธฐ: {{maxFilesize}}MB.", |
| dictInvalidFileType: "์ด ํ์์ ํ์ผ์ ์
๋ก๋ํ ์ ์์ต๋๋ค.", |
| autoProcessQueue: false, |
| maxFiles: 1 |
| }); |
| |
| |
| documentUploadDropzone.on("addedfile", function(file) { |
| uploadButton.disabled = false; |
| hideAlerts(); |
| }); |
| |
| |
| documentUploadDropzone.on("removedfile", function(file) { |
| if (documentUploadDropzone.files.length === 0) { |
| uploadButton.disabled = true; |
| } |
| }); |
| |
| |
| uploadButton.addEventListener('click', function() { |
| if (documentUploadDropzone.files.length > 0) { |
| uploadButton.disabled = true; |
| uploadButton.innerHTML = '<span class="spinner-border spinner-border-sm me-2" role="status"></span>์
๋ก๋ ์ค...'; |
| documentUploadDropzone.processQueue(); |
| } |
| }); |
| |
| |
| documentUploadDropzone.on("success", function(file, response) { |
| uploadButton.innerHTML = '<i class="fas fa-upload me-2"></i>์
๋ก๋'; |
| uploadButton.disabled = true; |
| |
| |
| uploadSuccess.classList.remove('d-none'); |
| uploadSuccessMessage.textContent = response.message || "๋ฌธ์๊ฐ ์ฑ๊ณต์ ์ผ๋ก ์
๋ก๋๋์์ต๋๋ค."; |
| |
| |
| documentUploadDropzone.removeFile(file); |
| |
| |
| setTimeout(fetchDatabaseStats, 1000); |
| setTimeout(fetchDocuments, 1000); |
| }); |
| |
| |
| documentUploadDropzone.on("error", function(file, errorMessage, xhr) { |
| uploadButton.innerHTML = '<i class="fas fa-upload me-2"></i>์
๋ก๋'; |
| uploadButton.disabled = false; |
| |
| |
| uploadError.classList.remove('d-none'); |
| |
| if (typeof errorMessage === 'object' && errorMessage.error) { |
| uploadErrorMessage.textContent = errorMessage.error; |
| } else if (typeof errorMessage === 'string') { |
| uploadErrorMessage.textContent = errorMessage; |
| } else { |
| uploadErrorMessage.textContent = "์
๋ก๋ ์ค ์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค."; |
| } |
| }); |
| |
| |
| refreshStatus.addEventListener('click', function() { |
| fetchDatabaseStats(); |
| fetchDocuments(); |
| }); |
| |
| |
| |
| |
| function hideAlerts() { |
| uploadSuccess.classList.add('d-none'); |
| uploadError.classList.add('d-none'); |
| } |
| |
| |
| |
| |
| async function fetchDatabaseStats() { |
| try { |
| databaseStats.innerHTML = ` |
| <div class="d-flex justify-content-center align-items-center" style="height: 100px;"> |
| <div class="spinner-border text-primary" role="status"> |
| <span class="visually-hidden">Loading...</span> |
| </div> |
| </div> |
| `; |
| |
| const response = await fetch('/api/documents'); |
| |
| if (!response.ok) { |
| throw new Error('API ์์ฒญ ์คํจ'); |
| } |
| |
| const data = await response.json(); |
| |
| if (data.enabled === false) { |
| databaseStats.innerHTML = ` |
| <div class="alert alert-warning mb-0"> |
| <i class="fas fa-exclamation-triangle me-2"></i>์บ์๊ฐ ํ์ฑํ๋์ง ์์์ต๋๋ค. |
| </div> |
| `; |
| return; |
| } |
| |
| const stats = data.stats || {}; |
| |
| databaseStats.innerHTML = ` |
| <div class="row text-center"> |
| <div class="col-6 border-end"> |
| <h3 class="mb-0">${stats.size || 0}</h3> |
| <p class="text-muted mb-0">์บ์ ํญ๋ชฉ</p> |
| </div> |
| <div class="col-6"> |
| <h3 class="mb-0">${stats.max_size || 0}</h3> |
| <p class="text-muted mb-0">์ต๋ ํญ๋ชฉ ์</p> |
| </div> |
| </div> |
| <hr> |
| <div class="text-center"> |
| <p class="mb-0">์บ์ TTL: ${stats.ttl || 0}์ด</p> |
| <p class="mb-2">์ต๋ ํญ๋ชฉ ๋์ด: ${(stats.oldest_item_age || 0).toFixed(1)}์ด</p> |
| </div> |
| <div class="d-grid"> |
| <button class="btn btn-sm btn-outline-primary" id="clearCache">์บ์ ๋น์ฐ๊ธฐ</button> |
| </div> |
| `; |
| |
| |
| document.getElementById('clearCache').addEventListener('click', clearCache); |
| |
| } catch (err) { |
| console.error('์ง์๋ฒ ์ด์ค ์ํ ๊ฐ์ ธ์ค๊ธฐ ์คํจ:', err); |
| databaseStats.innerHTML = ` |
| <div class="alert alert-danger mb-0"> |
| <i class="fas fa-exclamation-circle me-2"></i>์ง์๋ฒ ์ด์ค ์ํ๋ฅผ ๊ฐ์ ธ์ค๋ ์ค ์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค. |
| </div> |
| `; |
| } |
| } |
| |
| |
| |
| |
| async function fetchDocuments() { |
| try { |
| documentsContainer.innerHTML = ` |
| <div class="text-center p-4"> |
| <div class="spinner-border text-primary" role="status"> |
| <span class="visually-hidden">Loading...</span> |
| </div> |
| <p class="mt-2">๋ฌธ์ ๋ชฉ๋ก์ ๋ถ๋ฌ์ค๋ ์ค...</p> |
| </div> |
| `; |
| |
| const response = await fetch('/api/documents'); |
| |
| if (!response.ok) { |
| throw new Error('API ์์ฒญ ์คํจ'); |
| } |
| |
| const data = await response.json(); |
| const documents = data.documents || []; |
| |
| if (documents.length === 0) { |
| documentsContainer.innerHTML = ` |
| <div class="text-center p-4"> |
| <i class="fas fa-file-alt fa-3x mb-3 text-muted"></i> |
| <p>์ง์๋ฒ ์ด์ค์ ๋ฑ๋ก๋ ๋ฌธ์๊ฐ ์์ต๋๋ค.</p> |
| <p class="text-muted small">์ผ์ชฝ ํจ๋์์ ๋ฌธ์๋ฅผ ์
๋ก๋ํ์ธ์.</p> |
| </div> |
| `; |
| return; |
| } |
| |
| |
| const documentsList = document.createElement('div'); |
| documentsList.className = 'list-group list-group-flush'; |
| |
| documents.forEach(doc => { |
| const docItem = createDocumentItem(doc); |
| documentsList.appendChild(docItem); |
| }); |
| |
| documentsContainer.innerHTML = ''; |
| documentsContainer.appendChild(documentsList); |
| |
| } catch (err) { |
| console.error('๋ฌธ์ ๋ชฉ๋ก ๊ฐ์ ธ์ค๊ธฐ ์คํจ:', err); |
| documentsContainer.innerHTML = ` |
| <div class="alert alert-danger m-3"> |
| <i class="fas fa-exclamation-circle me-2"></i>๋ฌธ์ ๋ชฉ๋ก์ ๊ฐ์ ธ์ค๋ ์ค ์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค. |
| </div> |
| `; |
| } |
| } |
| |
| |
| |
| |
| |
| |
| function createDocumentItem(doc) { |
| const template = document.getElementById('documentItemTemplate'); |
| const docNode = template.content.cloneNode(true); |
| |
| docNode.querySelector('.document-name').textContent = doc.filename || doc.source || 'Unnamed Document'; |
| docNode.querySelector('.document-chunks').textContent = doc.chunks || 0; |
| docNode.querySelector('.document-type').textContent = doc.filetype || 'UNKNOWN'; |
| |
| return docNode.firstElementChild; |
| } |
| |
| |
| |
| |
| async function clearCache() { |
| try { |
| if (!confirm('์ ๋ง ์บ์๋ฅผ ๋น์ฐ์๊ฒ ์ต๋๊น?')) { |
| return; |
| } |
| |
| const response = await fetch('/api/cache/clear', { |
| method: 'POST' |
| }); |
| |
| if (!response.ok) { |
| throw new Error('API ์์ฒญ ์คํจ'); |
| } |
| |
| alert('์บ์๊ฐ ์ฑ๊ณต์ ์ผ๋ก ๋น์์ก์ต๋๋ค.'); |
| fetchDatabaseStats(); |
| |
| } catch (err) { |
| console.error('์บ์ ๋น์ฐ๊ธฐ ์คํจ:', err); |
| alert('์บ์ ๋น์ฐ๊ธฐ ์คํจ: ' + err.message); |
| } |
| } |
| |
| |
| fetchDatabaseStats(); |
| fetchDocuments(); |
| }); |
|
|