feat: selezione immagini da cartella IMAGES_DIR via .env

- .env con IMAGES_DIR=Test
- server: _load_env legge .env senza dip extra
- GET /images lista file, POST /load_from_folder carica per nome
- frontend: file picker sostituiti con 2 select popolati all avvio

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-24 10:50:37 +02:00
parent 1954bc6ffd
commit 1671a151da
4 changed files with 139 additions and 34 deletions
+65 -27
View File
@@ -62,15 +62,35 @@ function readAdvancedOverrides() {
return out;
}
// ---------- Upload ----------
async function uploadFile(file) {
const fd = new FormData();
fd.append("file", file);
const r = await fetch("/upload", { method: "POST", body: fd });
if (!r.ok) throw new Error("upload failed");
// ---------- Image loading from folder ----------
async function loadFromFolder(filename) {
const r = await fetch("/load_from_folder", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ filename }),
});
if (!r.ok) throw new Error(await r.text());
return await r.json();
}
async function fetchImagesList() {
const r = await fetch("/images");
if (!r.ok) return { files: [], dir: "" };
return await r.json();
}
function populateSelect(selectEl, files) {
selectEl.innerHTML = "";
const opt0 = document.createElement("option");
opt0.value = ""; opt0.textContent = "-- seleziona --";
selectEl.appendChild(opt0);
for (const f of files) {
const o = document.createElement("option");
o.value = f; o.textContent = f;
selectEl.appendChild(o);
}
}
function loadImage(src) {
return new Promise((res, rej) => {
const img = new Image();
@@ -80,24 +100,35 @@ function loadImage(src) {
});
}
async function onLoadModel(file) {
async function onSelectModel(filename) {
if (!filename) return;
setStatus("Caricamento modello...");
const meta = await uploadFile(file);
const img = await loadImage(`/image/${meta.id}/raw`);
state.model = { id: meta.id, w: meta.width, h: meta.height, img };
state.roi = null;
setStatus(`Modello: ${file.name} ${meta.width}x${meta.height} — trascina ROI`);
renderModel();
try {
const meta = await loadFromFolder(filename);
const img = await loadImage(`/image/${meta.id}/raw`);
state.model = { id: meta.id, w: meta.width, h: meta.height, img };
state.roi = null;
document.getElementById("roi-info").textContent = "ROI: (nessuna)";
setStatus(`Modello: ${filename} ${meta.width}x${meta.height} — trascina ROI`);
renderModel();
} catch (e) {
setStatus(`Errore modello: ${e.message}`);
}
}
async function onLoadScene(file) {
async function onSelectScene(filename) {
if (!filename) return;
setStatus("Caricamento scena...");
const meta = await uploadFile(file);
const img = await loadImage(`/image/${meta.id}/raw`);
state.scene = { id: meta.id, w: meta.width, h: meta.height, img };
state.matches = []; state.annotatedImg = null;
setStatus(`Scena: ${file.name} ${meta.width}x${meta.height}`);
renderScene();
try {
const meta = await loadFromFolder(filename);
const img = await loadImage(`/image/${meta.id}/raw`);
state.scene = { id: meta.id, w: meta.width, h: meta.height, img };
state.matches = []; state.annotatedImg = null;
setStatus(`Scena: ${filename} ${meta.width}x${meta.height}`);
renderScene();
} catch (e) {
setStatus(`Errore scena: ${e.message}`);
}
}
// ---------- Rendering ----------
@@ -274,15 +305,22 @@ function setStatus(s) {
}
// ---------- Init ----------
window.addEventListener("DOMContentLoaded", () => {
window.addEventListener("DOMContentLoaded", async () => {
buildAdvancedForm();
setupROI();
document.getElementById("file-model").addEventListener("change", (e) => {
if (e.target.files[0]) onLoadModel(e.target.files[0]);
});
document.getElementById("file-scene").addEventListener("change", (e) => {
if (e.target.files[0]) onLoadScene(e.target.files[0]);
});
// Popola dropdown immagini da IMAGES_DIR
const {files, dir} = await fetchImagesList();
const selM = document.getElementById("sel-model");
const selS = document.getElementById("sel-scene");
populateSelect(selM, files);
populateSelect(selS, files);
if (files.length === 0) {
setStatus(`Nessuna immagine in ${dir} (configura IMAGES_DIR in .env)`);
} else {
setStatus(`${files.length} immagini disponibili in ${dir}`);
}
selM.addEventListener("change", (e) => onSelectModel(e.target.value));
selS.addEventListener("change", (e) => onSelectScene(e.target.value));
document.getElementById("btn-match").addEventListener("click", doMatch);
const slider = document.getElementById("p-min-score");
slider.addEventListener("input", (e) => {