/
sobyanin
/
SmartTagger
Обзор
Документация
Войти
/
sobyanin
/
SmartTagger
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
static/script.js
238 строк
7 KB
sobyanin
upload files
16 дек 2025, 22:44
16 дек 2025, 22:44
68f7f79
Код
Авторство
О чём код?
/* ============================ Smart Image Tagger — Frontend PostgreSQL Edition ============================ */ const uploadArea = document.getElementById("uploadArea"); const fileInput = document.getElementById("fileInput"); const chooseBtn = document.getElementById("chooseBtn"); const pasteBtn = document.getElementById("pasteBtn"); const previewSection = document.getElementById("previewSection"); const previewImg = document.getElementById("previewImg"); const fileNameEl = document.getElementById("fileName"); const fileSizeEl = document.getElementById("fileSize"); const fileDimensionsEl = document.getElementById("fileDimensions"); const analyzeBtn = document.getElementById("analyzeBtn"); const downloadBtn = document.getElementById("downloadBtn"); const resultsSection = document.getElementById("resultsSection"); const tagsGrid = document.getElementById("tagsGrid"); const mlDetails = document.getElementById("mlDetails"); const confidenceList = document.getElementById("confidenceList"); const historyGrid = document.getElementById("historyGrid"); const clearHistoryBtn = document.getElementById("clearHistoryBtn"); const analysisStatus = document.getElementById("analysisStatus"); const processingTimeEl = document.getElementById("processingTime"); const imageIdEl = document.getElementById("imageId"); const originalNameEl = document.getElementById("originalName"); const notification = document.getElementById("notification"); let selectedFile = null; let activeImageId = null; /* =============== NOTIFICATION =============== */ function notify(msg) { notification.innerText = msg; notification.hidden = false; setTimeout(() => { notification.hidden = true; }, 2200); } /* =============== IMAGE HANDLING =============== */ function showPreview(file) { const reader = new FileReader(); reader.onload = () => { previewImg.src = reader.result; previewSection.classList.remove("hidden"); }; reader.readAsDataURL(file); fileNameEl.textContent = file.name; fileSizeEl.textContent = `${(file.size / 1024).toFixed(2)} KB`; const imgTemp = new Image(); imgTemp.onload = () => { fileDimensionsEl.textContent = `${imgTemp.width} × ${imgTemp.height}`; }; imgTemp.src = URL.createObjectURL(file); selectedFile = file; } /* Upload handlers */ uploadArea.addEventListener("click", () => fileInput.click()); chooseBtn.addEventListener("click", () => fileInput.click()); fileInput.addEventListener("change", (e) => { const file = e.target.files[0]; if (file) showPreview(file); }); /* Drag & Drop */ uploadArea.addEventListener("dragover", (e) => { e.preventDefault(); uploadArea.classList.add("drag"); }); uploadArea.addEventListener("dragleave", () => uploadArea.classList.remove("drag")); uploadArea.addEventListener("drop", (e) => { e.preventDefault(); uploadArea.classList.remove("drag"); const file = e.dataTransfer.files[0]; if (file) showPreview(file); }); /* Paste */ pasteBtn.addEventListener("click", async () => { navigator.clipboard.read().then(async (items) => { for (const item of items) { if (item.types.includes("image/png") || item.types.includes("image/jpeg")) { const blob = await item.getType(item.types[0]); const file = new File([blob], "pasted.png", { type: blob.type }); showPreview(file); } } }); }); /* ============================ ANALYZE IMAGE (UPLOAD + ML) ============================ */ analyzeBtn.addEventListener("click", async () => { if (!selectedFile) return; analysisStatus.textContent = "Анализ..."; resultsSection.classList.remove("hidden"); const formData = new FormData(); formData.append("file", selectedFile); const resp = await fetch("/api/images", { method: "POST", body: formData }); const data = await resp.json(); if (!data.success) { notify("Ошибка анализа"); return; } /* Fill UI */ activeImageId = data.id; imageIdEl.textContent = data.id; originalNameEl.textContent = data.original_name; processingTimeEl.textContent = data.processing_time; /* Tags */ tagsGrid.innerHTML = ""; data.tags.forEach((tag) => { tagsGrid.innerHTML += ` <div class="tag-pill"> <strong>${tag}</strong> </div> `; }); /* Top-5 details */ confidenceList.innerHTML = ""; data.top5.forEach((item) => { confidenceList.innerHTML += ` <div class="conf-item"> <div class="conf-label"> <span>${item.label}</span> <span>${(item.confidence * 100).toFixed(1)}%</span> </div> <div class="progress-bg"> <div class="progress-fill" style="width:${item.confidence * 100}%; background:var(--accent1)"></div> </div> </div> `; }); mlDetails.classList.remove("hidden"); analysisStatus.textContent = "Готово"; await loadHistory(); }); /* ============================ HISTORY ============================ */ async function loadHistory(filterTag = "") { let url = "/api/history"; if (filterTag.length > 0) { url = `/api/search?tags=${encodeURIComponent(filterTag)}`; } const resp = await fetch(url); const data = await resp.json(); const list = data.history || data.results || []; historyGrid.innerHTML = ""; if (list.length === 0) { historyGrid.innerHTML = `<div class="empty">История пуста</div>`; return; } list.forEach((item) => { const el = document.createElement("div"); el.className = "history-item"; el.innerHTML = ` <img src="${item.url}" alt=""> <div> <strong>${item.original_name}</strong><br> <small class="muted">${Math.round(item.size / 1024)} KB</small> </div> <button class="delete-btn" data-id="${item.id}" style="margin-left:auto;color:var(--danger)"> <i class="fas fa-trash-alt"></i> </button> `; el.querySelector(".delete-btn").addEventListener("click", async (e) => { e.stopPropagation(); await fetch(`/api/images/${item.id}`, { method: "DELETE" }); notify("Удалено"); await loadHistory(); }); historyGrid.appendChild(el); }); } document.addEventListener("DOMContentLoaded", loadHistory); /* ============================ CLEAR HISTORY ============================ */ clearHistoryBtn.addEventListener("click", async () => { if (!confirm("Удалить ВСЮ историю?")) return; await fetch("/api/history", { method: "DELETE" }); notify("История очищена"); await loadHistory(); });