ricetta: camera e modo di analisi (impulsiva / in linea) nel task visione, immagine gia' analizzata all'ingresso dell'operatore #97

Closed
opened 2026-10-24 16:18:20 +00:00 by Adriano · 1 comment
Owner

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)

  • recipe_tasks.acquisition_json: JSON nullable, migrazione alembic 021_task_acquisition.py (down_revision = quella di 020_station_camera.py).
    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)

  1. vision_service: la calibrazione si legge dalla CAMERA DEL TASK (GET {camera_url}/camera/calibration?source=), non solo dalla stazione: generalizzare fetch_station_calibration in fetch_calibration(camera_url, camera_source) e usarla in execute con la regola sopra. Stessi esiti CAL_*.
  2. POST /api/vision/check (require_measurement_tec), Form: task_id, image, production_run_id opzionale. Esegue il grafo con la stessa calibrazione di execute, NON salva nulla (ne' vision_result ne' misure). Risposta:
    {"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.
  3. Test pytest backend per migrazione/modello/copy-on-write, check (non salva: conteggi DB invariati), calibrazione dalla camera del task.

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.

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) - recipe_tasks.acquisition_json: JSON nullable, migrazione alembic 021_task_acquisition.py (down_revision = quella di 020_station_camera.py). 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) 1. vision_service: la calibrazione si legge dalla CAMERA DEL TASK (GET {camera_url}/camera/calibration?source=), non solo dalla stazione: generalizzare fetch_station_calibration in fetch_calibration(camera_url, camera_source) e usarla in execute con la regola sopra. Stessi esiti CAL_*. 2. POST /api/vision/check (require_measurement_tec), Form: task_id, image, production_run_id opzionale. Esegue il grafo con la stessa calibrazione di execute, NON salva nulla (ne' vision_result ne' misure). Risposta: {"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. 3. Test pytest backend per migrazione/modello/copy-on-write, check (non salva: conteggi DB invariati), calibrazione dalla camera del task. 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.
Adriano added the sviluppo label 2026-10-24 16:18:20 +00:00
Author
Owner

Soluzione

ESITO: fatto
RIF: gitea:Adriano/TieMeasureFlow#97, ramo lavoro/daitarn-tmf-dxfcal, merge 4b1b23c (A 8f97318+661b782, B 25f8b4d, C 67337fa)
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.

**Soluzione** ESITO: fatto RIF: gitea:Adriano/TieMeasureFlow#97, ramo lavoro/daitarn-tmf-dxfcal, merge 4b1b23c (A 8f97318+661b782, B 25f8b4d, C 67337fa) 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.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Adriano/TieMeasureFlow#97