ricetta: camera e modo di analisi (impulsiva / in linea) nel task visione, immagine gia' analizzata all'ingresso dell'operatore #97
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
CONTRATTO #97 (identico per i piani A, B, C; repo TieMeasureFlow, base ramo lavoro/daitarn-tmf-dxfcal
552f96b)Richiesta Adriano 24/10/2026: nella ricetta, per i task con immagine da camera (camera_measure, dxf_compare), si sceglie la camera (servizio di acquisizione fra quelli delle stazioni + sorgente) e il modo di analisi «impulsiva» o «in linea»; quando l'operatore entra nel task c'e' gia' un'immagine acquisita e analizzata.
Decisioni di Adriano (AskUserQuestion 24/10): servizio + sorgente fissi nel task (l'operatore usa quella da qualunque stazione); «in linea» = ciclo continuo acquisisci+analizza con esito dal vivo, l'operatore conferma; all'ingresso nel task immagine E analisi gia' fatte.
Decisione di Opus (da dire ad Adriano): l'analisi automatica (ingresso e ciclo in linea) NON salva misure; si salva con «Registra» sull'ultimo frame mostrato (stessa /vision/execute di oggi). Cosi' un pezzo non ancora in posizione non lascia misure sbagliate.
DATI (piano A)
Forma: {"camera_url": "http://host:porta", "camera_source": "camera:601020" | nome immagine | ..., "modo": "impulsiva" | "in_linea"}.
Validazione Pydantic nei modelli task (create/update/response, src/backend/models/api/task.py): camera_url con la normalizzazione http di station.py (_normalize_http_url), camera_source stringa 1-200 non vuota, modo fra i due valori (default "impulsiva"); null ammesso (= come oggi: camera della stazione).
Copiato nel copy-on-write delle versioni come vision_json (src/backend/services/recipe_service.py ~117).
Esposto in GET task e nelle risposte dove oggi c'e' vision_json.
CAMERA DI UN TASK (regola unica, usata da A e C)
camera del task = acquisition_json (camera_url, camera_source) se presente, altrimenti camera della stazione corrente (station.camera_url/camera_source, come oggi). Modo = acquisition_json.modo, altrimenti "impulsiva".
BACKEND (piano A)
{"outcome": str|null, "overlay": [...], "failures": [...], "measurements": [{"subtask_id": int, "value": float, "pass_fail": "pass"|"warning"|"fail"}], "calibration": "ok"|"no_camera"|"not_calibrated"|"unreachable"}
pass_fail con measurement_service.calculate_pass_fail sulle quote del task con vision_output (stesso ordine marker_number di execute). Stessi 422 di execute se manca il grafo o le quote.
FLASK MAKER (piano B) — src/frontend/flask_app/blueprints/maker.py, templates/maker/task_editor.html, static/js se serve
4. GET /maker/api/camera/servizi -> {"servizi": [{"camera_url": u, "stazioni": ["CODICE - nome", ...]}]}: camera_url distinti delle stazioni che ne hanno uno (dalla stessa fonte di /maker/api/stations).
5. GET /maker/api/camera/sorgenti?url=<camera_url> -> inoltra GET {url}/camera/sources (timeout 15 s) e restituisce {"sources": [...]}; 400 se url non e' fra i servizi del punto 4 (niente richieste verso indirizzi arbitrari); 502 se il servizio non risponde.
6. task_editor.html: per task camera_measure/dxf_compare, sezione «Acquisizione» (prima della ricetta visione): select «Servizio di acquisizione» (voce vuota «Camera della stazione dell'operatore» = acquisition_json null), select «Sorgente» (caricata dal punto 5 al cambio servizio, etichette dal servizio), radio «Analisi impulsiva» / «Analisi in linea». Salvataggio nel payload del task come acquisition_json (null con voce vuota). Testi italiani con _(). Verifica che il proxy di salvataggio task di maker.py inoltri il campo.
FLASK OPERATORE (piano C) — blueprints/measure.py, templates/measure/task_execute.html, static/js/vision_execute.js
7. POST /measure/api/vision/grab: accetta task_id (form o json); camera = regola sopra (acquisition_json del task letto dal backend, altrimenti stazione). Errori come oggi.
8. POST /measure/api/vision/check: proxy verso POST /api/vision/check (stessi campi di execute).
9. Pagina: entrando in un task visione con camera disponibile -> grab + check automatici; immagine e quote/esito mostrati (marcati «anteprima, non registrata»). Modo impulsiva: pulsante «Acquisisci» rifa' grab+check. Modo in linea: ciclo grab+check continuo (uno alla volta, pausa minima 300 ms, si ferma uscendo dal task, con la pagina nascosta e durante Registra), pulsante «Pausa/Riprendi». Pulsante «Registra» = POST execute (quello di oggi) sull'ULTIMO frame mostrato; dopo Registra il risultato salvato sostituisce l'anteprima (in linea il ciclo riparte solo con «Riprendi» o col pezzo successivo). Senza camera: comportamento di oggi (file o «Acquisisci dalla camera»).
10. Immagine in fit e niente scorrimento: regole di #96 (gia' sul ramo quando parte C).
PIANI: A backend (src/backend), B Flask maker (maker.py, task_editor.html), C Flask operatore (measure.py, task_execute.html, vision_execute.js; parte dopo #96). Rami lavoro/daitarn-tmf-97a, -97b, -97c, worktree separati; Opus unisce su lavoro/daitarn-tmf-dxfcal e fa la prova d'insieme.
Soluzione
ESITO: fatto
RIF: gitea:Adriano/TieMeasureFlow#97, ramo lavoro/daitarn-tmf-dxfcal, merge
4b1b23c(A 8f97318+661b782, B25f8b4d, C67337fa)COSA: camera (servizio+sorgente) e modo impulsiva/in linea nel task visione; all'ingresso grab+analisi senza salvare; Registra salva l'ultimo frame.
FILE: src/backend/migrations/versions/021_task_acquisition.py — recipe_tasks.acquisition_json; models/api/task.py AcquisitionConfig; services/vision_service.py fetch_calibration/task_camera/check_task (calibrazione dalla camera del task anche in execute); api/routers/vision.py POST /api/vision/check; recipe_service copy-on-write.
FILE: src/frontend/flask_app/blueprints/maker.py — /maker/api/camera/servizi, /maker/api/camera/sorgenti (400 url non di stazione, 502); templates/maker/task_editor.html sezione Acquisizione + static/js/task_acquisition.js.
FILE: src/frontend/flask_app/blueprints/measure.py — grab con task_id usa camera del task, proxy /measure/api/vision/check; task_execute.html + vision_execute.js: Acquisisci (impulsiva), Pausa/Riprendi (in linea, ciclo 1 richiesta, >=300 ms, fermo con pagina nascosta/uscita/Registra), Registra, badge Anteprima non registrata.
PROVA: backend task_acquisition+migrations+vision*+recipe*+task* → 218 passed; frontend → 391 passed, 13 failed tutti preesistenti (9 base + 4 locale .mo del worktree dxfcal); TMF riavviato: alembic 021_task_acquisition, /maker/api/camera/servizi → 8765 (ST-DEFAULT), sorgenti 4, url estraneo 400; POST /api/vision/check task 8 → 422 no vision graph (task senza ricetta, atteso).
MANCA: Form nuovo task senza campi acquisizione (si imposta modificando il task). Prova ciclo in linea con camera reale: Adriano. Backup DB C:/ProgramData/Tielogic/TieMeasureFlow/tmf.db.prima-97.