Ricetta creata da DXF: riaprirla e modificarla nel wizard #105

Closed
opened 2026-10-25 15:20:49 +00:00 by Adriano · 2 comments
Owner

Richiesta Adriano 25/10/2026. Analisi nel commento.

Richiesta Adriano 25/10/2026. Analisi nel commento.
Adriano added the sviluppo label 2026-10-25 15:20:49 +00:00
Author
Owner

ESITO: richiesta
RIF: gitea:Adriano/TieMeasureFlow#105
COSA: una ricetta creata con «Crea ricetta da DXF» deve potersi modificare. Il wizard si riapre compilato con DXF, immagine di riferimento, mm/px, banda, soglia e polarità; si cambia, si prova e si salva sopra.

Richiesta di Adriano 25/10/2026: «se ho creato una ricetta con Crea ricetta da DXF devo poterla modificare».

STATO OGGI
VERIFICATO leggendo il codice, ramo lavoro/daitarn-tmf-dxfcal 711abc9.

  • POST /api/vision/tasks/{id}/recipe/dxf-compare con save=true, in src/backend/api/routers/vision.py (~riga 383), salva sul task:
    • task.vision_json = il grafo;
    • task.vision_recipe_dir = la cartella immutabile vision/recipes/<task>/<digest> (vision_service.store_recipe_folder).
  • I file della cartella sono recipe.json, disegno.dxf e calibrazione.json ({"px_per_mm": f}).
  • L'immagine usata per costruire la ricetta NON viene salvata: oggi non si può riaprire.
  • I parametri stanno nel grafo (src/vision/costruttori.py::_graph):
    • tool id="pezzo", kind LocateBlob: values.polarity ('dark' | 'light');
    • tool id="dxf", kind CompareDxf: values.band_plus (= banda mm) e values.points_in_pct_nominal (= soglia %).
  • vision_service.ensure_points_quote crea la quota «Punti in tolleranza» (ltl = soglia) una volta sola. Se la soglia cambia, la quota resta col valore vecchio.
  • Non esiste una rotta per leggere i file di una cartella ricetta.

CONTRATTO (identico per piano A e piano B)

  • Backend GET /api/vision/tasks/{task_id}/recipe/dxf-compare/source (require_maker):
    • 200 {"band_mm": f, "min_points_pct": f, "polarity": "dark"|"light", "px_per_mm": f|null, "dxf": "disegno.dxf"|null, "image": ""|null}
    • 404 {"detail": "nessuna ricetta da DXF su questo task"} se il task non ha una ricetta, o se il grafo non ha i tool pezzo/LocateBlob e dxf/CompareDxf.
    • px_per_mm viene da calibrazione.json della cartella; null se manca o non è leggibile.
    • dxf e image sono i nomi dei file presenti nella cartella, null se assenti.
  • Backend GET /api/vision/tasks/{task_id}/recipe/files/{path:path} (require_maker):
    • restituisce i byte del file della cartella ricetta del task, con media type dall'estensione (mimetypes, default application/octet-stream);
    • path non sicuro → 404, mai 500 (usa vision_service._safe_join);
    • file assente, o task senza ricetta → 404.
  • Flask, piano B:
    • GET /maker/api/vision/tasks/<id>/recipe/dxf-compare/source;
    • GET /maker/api/vision/tasks/<id>/recipe/files/<path:path>.
      Entrambe inoltrano codice, corpo e content-type; i file passano come byte, non come JSON.

PIANO A — backend (worktree C:/Users/Adriano/lavoro/TieMeasureFlow-105a, ramo lavoro/daitarn-tmf-105a, base 711abc9)

  1. In create_dxf_compare_recipe con save=true, l'immagine ricevuta si aggiunge ai file della cartella come riferimento.<ext>:
    • ext da _IMAGE_EXTENSIONS[image.content_type], come add_reference_image;
    • va aggiunta a placed prima di _store_validate_assign, così finisce nel digest della cartella.
      PRIMA verificare che il worker /validate (src/vision_worker/main.py ~riga 216 e il codice vs-task in vendor, sola lettura) e l'esecuzione accettino un file in più non citato in meta. Se lo rifiutano, fermarsi e riportarlo, senza aggirarlo.
      Nella risposta di save, files resta com'è oggi: la riga «File» del componente visionRecipe lo mostrerà.
  2. Rotta /source come da contratto. Funzione pura in vision_service, dxf_compare_source(graph, recipe_dir) -> dict | None, testabile senza DB.
  3. Rotta /files/{path:path} come da contratto (FileResponse o Response con i byte).
  4. ensure_points_quote: se esiste già una quota con vision_output == "dxf.points_in_pct" e description == "Punti in tolleranza" (cioè creata da qui), la versione non ha misure e ltl != min_points_pct, allora aggiorna ltl = min_points_pct. Tutto il resto resta com'è. Ritorna True anche in quel caso. Aggiornare docstring e commento.
  5. Ogni modifica porta un commento breve «#105».
    TEST A
  • In src/backend/tests/, sullo schema dei test esistenti di vision e dxf-compare (cercare test_vision* e dxf_compare nei test):
    • save salva riferimento.bmp o .png nella cartella;
    • /source restituisce i valori di un grafo costruito come _graph, e 404 su un task senza ricetta o con un grafo non wizard;
    • /files restituisce i byte, e 404 su ../x e su un file assente;
    • ensure_points_quote aggiorna ltl.
  • Comando: PYTHONPATH=. C:/Users/Adriano/lavoro/TieMeasureFlow-dxfcal-backend/.venv/Scripts/python.exe -m pytest src/backend/tests/<file> -q -p no:cacheprovider. Lanciare anche gli altri test vision del backend: non devono comparire fallimenti nuovi.
    NON TOCCARE (A): src/frontend/, src/vision/, vendor/**.

PIANO B — Flask e wizard (dopo il merge di #104: stessi file)

  1. Due proxy in blueprints/maker.py, sul modello delle rotte vision esistenti (per i byte vedere come il proxy di camera/grab restituisce il blob).
  2. dxf_recipe_wizard.js:
    • all'init, e dopo l'evento 'dxf-recipe-saved', GET /source → existing (null se 404);
    • etichetta del bottone: «Modifica ricetta da DXF» se existing, altrimenti «Crea ricetta da DXF»;
    • all'apertura con existing:
      • bandMm, minPointsPct e dark = polarity === 'dark' dai valori salvati;
      • mmPx = 1/px_per_mm (fino a 6 cifre significative, virgola);
      • fetch del DXF → File('disegno.dxf') → dxfFile e loadDxfPreview();
      • se image c'è: fetch → File → _setImage, con imageSource = 'file';
      • altrimenti, avviso «Immagine di riferimento non salvata (ricetta creata prima): acquisiscila o caricala».
    • riga informativa «Ricetta esistente caricata: Prova e poi Salva ricetta per sostituirla».
    • Il resto (Prova, Salva) è invariato: il salvataggio scrive una cartella nuova e il task punta lì.
  3. Testi con _() e voci .po, test JS col node, test delle rotte Flask, commenti «#105».

PROVA (Opus): dopo il merge e il riavvio, headless Edge sul task 8 della ricetta 3.

  • Crea e salva la ricetta MEVIS _profilo.dxf + sider_2_1.bmp, mm/px 0,01406, banda 0,3.
  • Ricarica la pagina: il bottone dice «Modifica ricetta da DXF» e il wizard si apre compilato (immagine, DXF, 0,01406, 0,3).
  • Banda 0,2 → Prova → Salva: la cartella cambia e la quota «Punti in tolleranza» segue la soglia.
ESITO: richiesta RIF: gitea:Adriano/TieMeasureFlow#105 COSA: una ricetta creata con «Crea ricetta da DXF» deve potersi modificare. Il wizard si riapre compilato con DXF, immagine di riferimento, mm/px, banda, soglia e polarità; si cambia, si prova e si salva sopra. Richiesta di Adriano 25/10/2026: «se ho creato una ricetta con Crea ricetta da DXF devo poterla modificare». STATO OGGI VERIFICATO leggendo il codice, ramo lavoro/daitarn-tmf-dxfcal 711abc9. - `POST /api/vision/tasks/{id}/recipe/dxf-compare` con save=true, in `src/backend/api/routers/vision.py` (~riga 383), salva sul task: - `task.vision_json` = il grafo; - `task.vision_recipe_dir` = la cartella immutabile `vision/recipes/<task>/<digest>` (`vision_service.store_recipe_folder`). - I file della cartella sono `recipe.json`, `disegno.dxf` e `calibrazione.json` ({"px_per_mm": f}). - L'immagine usata per costruire la ricetta NON viene salvata: oggi non si può riaprire. - I parametri stanno nel grafo (`src/vision/costruttori.py::_graph`): - tool `id="pezzo"`, kind LocateBlob: `values.polarity` ('dark' | 'light'); - tool `id="dxf"`, kind CompareDxf: `values.band_plus` (= banda mm) e `values.points_in_pct_nominal` (= soglia %). - `vision_service.ensure_points_quote` crea la quota «Punti in tolleranza» (ltl = soglia) una volta sola. Se la soglia cambia, la quota resta col valore vecchio. - Non esiste una rotta per leggere i file di una cartella ricetta. CONTRATTO (identico per piano A e piano B) - Backend `GET /api/vision/tasks/{task_id}/recipe/dxf-compare/source` (require_maker): - 200 {"band_mm": f, "min_points_pct": f, "polarity": "dark"|"light", "px_per_mm": f|null, "dxf": "disegno.dxf"|null, "image": "<nome file>"|null} - 404 {"detail": "nessuna ricetta da DXF su questo task"} se il task non ha una ricetta, o se il grafo non ha i tool `pezzo`/LocateBlob e `dxf`/CompareDxf. - `px_per_mm` viene da `calibrazione.json` della cartella; null se manca o non è leggibile. - `dxf` e `image` sono i nomi dei file presenti nella cartella, null se assenti. - Backend `GET /api/vision/tasks/{task_id}/recipe/files/{path:path}` (require_maker): - restituisce i byte del file della cartella ricetta del task, con media type dall'estensione (`mimetypes`, default application/octet-stream); - path non sicuro → 404, mai 500 (usa `vision_service._safe_join`); - file assente, o task senza ricetta → 404. - Flask, piano B: - `GET /maker/api/vision/tasks/<id>/recipe/dxf-compare/source`; - `GET /maker/api/vision/tasks/<id>/recipe/files/<path:path>`. Entrambe inoltrano codice, corpo e content-type; i file passano come byte, non come JSON. PIANO A — backend (worktree C:/Users/Adriano/lavoro/TieMeasureFlow-105a, ramo lavoro/daitarn-tmf-105a, base 711abc9) 1. In `create_dxf_compare_recipe` con save=true, l'immagine ricevuta si aggiunge ai file della cartella come `riferimento.<ext>`: - ext da `_IMAGE_EXTENSIONS[image.content_type]`, come `add_reference_image`; - va aggiunta a `placed` prima di `_store_validate_assign`, così finisce nel digest della cartella. PRIMA verificare che il worker `/validate` (src/vision_worker/main.py ~riga 216 e il codice vs-task in vendor, sola lettura) e l'esecuzione accettino un file in più non citato in meta. Se lo rifiutano, fermarsi e riportarlo, senza aggirarlo. Nella risposta di save, `files` resta com'è oggi: la riga «File» del componente visionRecipe lo mostrerà. 2. Rotta `/source` come da contratto. Funzione pura in vision_service, `dxf_compare_source(graph, recipe_dir) -> dict | None`, testabile senza DB. 3. Rotta `/files/{path:path}` come da contratto (FileResponse o Response con i byte). 4. `ensure_points_quote`: se esiste già una quota con `vision_output == "dxf.points_in_pct"` e `description == "Punti in tolleranza"` (cioè creata da qui), la versione non ha misure e `ltl != min_points_pct`, allora aggiorna `ltl = min_points_pct`. Tutto il resto resta com'è. Ritorna True anche in quel caso. Aggiornare docstring e commento. 5. Ogni modifica porta un commento breve «#105». TEST A - In `src/backend/tests/`, sullo schema dei test esistenti di vision e dxf-compare (cercare `test_vision*` e `dxf_compare` nei test): - save salva `riferimento.bmp` o `.png` nella cartella; - `/source` restituisce i valori di un grafo costruito come `_graph`, e 404 su un task senza ricetta o con un grafo non wizard; - `/files` restituisce i byte, e 404 su `../x` e su un file assente; - `ensure_points_quote` aggiorna ltl. - Comando: `PYTHONPATH=. C:/Users/Adriano/lavoro/TieMeasureFlow-dxfcal-backend/.venv/Scripts/python.exe -m pytest src/backend/tests/<file> -q -p no:cacheprovider`. Lanciare anche gli altri test vision del backend: non devono comparire fallimenti nuovi. NON TOCCARE (A): src/frontend/**, src/vision/**, vendor/**. PIANO B — Flask e wizard (dopo il merge di #104: stessi file) 1. Due proxy in `blueprints/maker.py`, sul modello delle rotte vision esistenti (per i byte vedere come il proxy di `camera/grab` restituisce il blob). 2. `dxf_recipe_wizard.js`: - all'init, e dopo l'evento 'dxf-recipe-saved', GET `/source` → `existing` (null se 404); - etichetta del bottone: «Modifica ricetta da DXF» se `existing`, altrimenti «Crea ricetta da DXF»; - all'apertura con `existing`: - `bandMm`, `minPointsPct` e `dark = polarity === 'dark'` dai valori salvati; - `mmPx` = 1/px_per_mm (fino a 6 cifre significative, virgola); - fetch del DXF → File('disegno.dxf') → `dxfFile` e `loadDxfPreview()`; - se `image` c'è: fetch → File → `_setImage`, con `imageSource = 'file'`; - altrimenti, avviso «Immagine di riferimento non salvata (ricetta creata prima): acquisiscila o caricala». - riga informativa «Ricetta esistente caricata: Prova e poi Salva ricetta per sostituirla». - Il resto (Prova, Salva) è invariato: il salvataggio scrive una cartella nuova e il task punta lì. 3. Testi con `_()` e voci .po, test JS col node, test delle rotte Flask, commenti «#105». PROVA (Opus): dopo il merge e il riavvio, headless Edge sul task 8 della ricetta 3. - Crea e salva la ricetta MEVIS `_profilo.dxf` + sider_2_1.bmp, mm/px 0,01406, banda 0,3. - Ricarica la pagina: il bottone dice «Modifica ricetta da DXF» e il wizard si apre compilato (immagine, DXF, 0,01406, 0,3). - Banda 0,2 → Prova → Salva: la cartella cambia e la quota «Punti in tolleranza» segue la soglia.
Author
Owner

Soluzione

ESITO: fatto. Ramo lavoro/daitarn-tmf-dxfcal (push 08616aa). FILE: src/backend/api/routers/vision.py (save salva riferimento. nella cartella; GET /tasks/{id}/recipe/dxf-compare/source; GET /tasks/{id}/recipe/files/{path}), src/backend/services/vision_service.py (dxf_compare_source, recipe_file_path, ensure_points_quote aggiorna ltl della quota «Punti in tolleranza» senza misure), blueprints/maker.py (2 proxy), dxf_recipe_wizard.js (existing, applyExisting, bottone «Modifica ricetta da DXF», contatori contro sovrascrittura), task_editor.html, messages.po; test src/backend/tests/test_vision_dxf_source.py (10). Commit 6080e6a, 9b8e729, 39b9ad7, bdef1f1. PROVA dal vivo task 8: apertura compilata (banda 0.1, soglia 90, mm/px 0,014, DXF 1 entità, avviso immagine assente); Salva → riapertura con riferimento.bmp, avviso sparito; ricetta originale ripristinata (cartella b7068a6ca92f70f8). Ricette salvate prima di #105: niente immagine, va ricaricata una volta.

**Soluzione** ESITO: fatto. Ramo lavoro/daitarn-tmf-dxfcal (push 08616aa). FILE: src/backend/api/routers/vision.py (save salva riferimento.<ext> nella cartella; GET /tasks/{id}/recipe/dxf-compare/source; GET /tasks/{id}/recipe/files/{path}), src/backend/services/vision_service.py (dxf_compare_source, recipe_file_path, ensure_points_quote aggiorna ltl della quota «Punti in tolleranza» senza misure), blueprints/maker.py (2 proxy), dxf_recipe_wizard.js (existing, applyExisting, bottone «Modifica ricetta da DXF», contatori contro sovrascrittura), task_editor.html, messages.po; test src/backend/tests/test_vision_dxf_source.py (10). Commit 6080e6a, 9b8e729, 39b9ad7, bdef1f1. PROVA dal vivo task 8: apertura compilata (banda 0.1, soglia 90, mm/px 0,014, DXF 1 entità, avviso immagine assente); Salva → riapertura con riferimento.bmp, avviso sparito; ricetta originale ripristinata (cartella b7068a6ca92f70f8). Ricette salvate prima di #105: niente immagine, va ricaricata una volta.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Adriano/TieMeasureFlow#105