feat: upload file nella cartella IMAGES_DIR
POST /upload_to_folder: sanitizza nome, valida estensione e contenuto via cv2.imdecode, auto-rename su collisione. Toolbar UI: bottone 'Carica file', dopo upload ricarica picker. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+34
-5
@@ -82,6 +82,21 @@ async function fetchImagesList() {
|
||||
return await r.json();
|
||||
}
|
||||
|
||||
async function uploadToFolder(file) {
|
||||
const fd = new FormData();
|
||||
fd.append("file", file);
|
||||
const r = await fetch("/upload_to_folder", { method: "POST", body: fd });
|
||||
if (!r.ok) throw new Error(await r.text());
|
||||
return await r.json();
|
||||
}
|
||||
|
||||
async function refreshPickers() {
|
||||
const {files, dir} = await fetchImagesList();
|
||||
buildThumbPicker("picker-model", files, onSelectModel);
|
||||
buildThumbPicker("picker-scene", files, onSelectScene);
|
||||
return {files, dir};
|
||||
}
|
||||
|
||||
function buildThumbPicker(pickerId, files, onSelect) {
|
||||
const picker = document.getElementById(pickerId);
|
||||
const current = picker.querySelector(".picker-current");
|
||||
@@ -351,14 +366,28 @@ window.addEventListener("DOMContentLoaded", async () => {
|
||||
buildAdvancedForm();
|
||||
setupROI();
|
||||
// Popola picker immagini da IMAGES_DIR (con thumbnail)
|
||||
const {files, dir} = await fetchImagesList();
|
||||
buildThumbPicker("picker-model", files, onSelectModel);
|
||||
buildThumbPicker("picker-scene", files, onSelectScene);
|
||||
const {files, dir} = await refreshPickers();
|
||||
if (files.length === 0) {
|
||||
setStatus(`Nessuna immagine in ${dir} (configura IMAGES_DIR in .env)`);
|
||||
setStatus(`Nessuna immagine in ${dir} (carica file o configura IMAGES_DIR)`);
|
||||
} else {
|
||||
setStatus(`${files.length} immagini disponibili in ${dir}`);
|
||||
setStatus(`${files.length} immagini in ${dir}`);
|
||||
}
|
||||
|
||||
// Upload file nella folder
|
||||
const upEl = document.getElementById("file-upload");
|
||||
upEl.addEventListener("change", async (e) => {
|
||||
const f = e.target.files[0];
|
||||
if (!f) return;
|
||||
setStatus(`Caricamento ${f.name} nella cartella...`);
|
||||
try {
|
||||
const res = await uploadToFolder(f);
|
||||
await refreshPickers();
|
||||
setStatus(`Salvato come ${res.saved_as} (${res.files.length} file totali)`);
|
||||
} catch (err) {
|
||||
setStatus(`Errore upload: ${err.message}`);
|
||||
}
|
||||
e.target.value = ""; // consente re-upload stesso file
|
||||
});
|
||||
document.getElementById("btn-match").addEventListener("click", doMatch);
|
||||
const slider = document.getElementById("p-min-score");
|
||||
slider.addEventListener("input", (e) => {
|
||||
|
||||
@@ -26,6 +26,10 @@
|
||||
<div class="picker-list"></div>
|
||||
</div>
|
||||
<button class="btn btn-go" id="btn-match">▶ MATCH</button>
|
||||
<label class="btn" title="Carica nuovo file nella cartella immagini">
|
||||
⬆ Carica file
|
||||
<input type="file" id="file-upload" accept="image/*" hidden>
|
||||
</label>
|
||||
<span id="status">Seleziona modello, disegna ROI, seleziona scena</span>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
Reference in New Issue
Block a user