operatore: immagine gia' analizzata all'ingresso, analisi impulsiva o in linea, Registra (Refs #97)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
"""MeasurementTec blueprint - recipe selection and measurement execution."""
|
||||
import json
|
||||
import urllib.parse
|
||||
|
||||
import requests as http_requests
|
||||
@@ -337,6 +338,14 @@ def task_execute(task_id: int):
|
||||
measurement_interval_minutes = recipe_resp.get("measurement_interval_minutes")
|
||||
allow_manual_input = bool(recipe_resp.get("allow_manual_input", True))
|
||||
|
||||
# #97: camera del task (acquisition_json) o della stazione; il modo di analisi
|
||||
# (impulsiva / in_linea) viene dal task. Solo i task visione ne hanno bisogno.
|
||||
camera = None
|
||||
camera_mode = "impulsiva"
|
||||
if task_resp.get("task_type") in ("camera_measure", "dxf_compare"):
|
||||
camera = _task_camera(task_resp, _current_station()[0])
|
||||
camera_mode = _task_mode(task_resp)
|
||||
|
||||
return render_template(
|
||||
"measure/task_execute.html",
|
||||
task=task_resp,
|
||||
@@ -345,7 +354,8 @@ def task_execute(task_id: int):
|
||||
all_task_ids=all_task_ids,
|
||||
measurement_interval_minutes=measurement_interval_minutes,
|
||||
allow_manual_input=allow_manual_input,
|
||||
camera_enabled=_station_camera(_current_station()[0]) is not None,
|
||||
camera_enabled=camera is not None,
|
||||
camera_mode=camera_mode,
|
||||
)
|
||||
|
||||
|
||||
@@ -1001,6 +1011,42 @@ def api_vision_execute():
|
||||
return jsonify(resp), 200
|
||||
|
||||
|
||||
# #97: analysis of a frame without saving anything (preview before «Registra»).
|
||||
@measure_bp.route("/api/vision/check", methods=["POST"])
|
||||
@login_required
|
||||
@role_required("MeasurementTec")
|
||||
def api_vision_check():
|
||||
"""Proxy: run the task's VisionSuite recipe on the image, nothing is saved."""
|
||||
image = request.files.get("image")
|
||||
task_id = request.form.get("task_id")
|
||||
if image is None or not task_id:
|
||||
return jsonify({
|
||||
"error": True,
|
||||
"detail": _("Dati mancanti: task_id e image sono obbligatori"),
|
||||
}), 400
|
||||
|
||||
form = {"task_id": task_id}
|
||||
if request.form.get("production_run_id"):
|
||||
form["production_run_id"] = request.form["production_run_id"]
|
||||
|
||||
resp = api_client.post(
|
||||
"/api/vision/check",
|
||||
data=form,
|
||||
files={"image": (
|
||||
image.filename or "capture.jpg",
|
||||
image.read(),
|
||||
image.mimetype or "application/octet-stream",
|
||||
)},
|
||||
)
|
||||
if resp.get("error"):
|
||||
status_code = resp.get("status_code", 500)
|
||||
body = {"error": True, "detail": resp.get("detail", _("Errore nell'esecuzione"))}
|
||||
if resp.get("session_expired"):
|
||||
body["session_expired"] = True
|
||||
return jsonify(body), status_code if status_code >= 400 else 500
|
||||
return jsonify(resp), 200
|
||||
|
||||
|
||||
def _station_camera(station_code: str | None) -> tuple[str, str] | None:
|
||||
"""(camera_url, camera_source) of the station, None when it has no camera.
|
||||
|
||||
@@ -1019,6 +1065,31 @@ def _station_camera(station_code: str | None) -> tuple[str, str] | None:
|
||||
return str(url), str(source)
|
||||
|
||||
|
||||
def _task_acquisition(task: dict | None) -> dict | None:
|
||||
"""#97: acquisition_json of a task as a dict, None when absent or unreadable."""
|
||||
acq = task.get("acquisition_json") if isinstance(task, dict) else None
|
||||
if isinstance(acq, str):
|
||||
try:
|
||||
acq = json.loads(acq)
|
||||
except ValueError:
|
||||
return None
|
||||
return acq if isinstance(acq, dict) else None
|
||||
|
||||
|
||||
def _task_camera(task: dict | None, station_code: str | None) -> tuple[str, str] | None:
|
||||
"""#97: camera of a task = its acquisition_json (url + source), else the station's."""
|
||||
acq = _task_acquisition(task)
|
||||
if acq and acq.get("camera_url") and acq.get("camera_source"):
|
||||
return str(acq["camera_url"]), str(acq["camera_source"])
|
||||
return _station_camera(station_code)
|
||||
|
||||
|
||||
def _task_mode(task: dict | None) -> str:
|
||||
"""#97: analysis mode of a task, «impulsiva» unless acquisition_json says «in_linea»."""
|
||||
acq = _task_acquisition(task)
|
||||
return "in_linea" if acq and acq.get("modo") == "in_linea" else "impulsiva"
|
||||
|
||||
|
||||
# #72: the browser asks the station's camera service (vs-gui) for a frame; the
|
||||
# service address is a server-side matter, so Flask relays and the PNG goes back as is.
|
||||
@measure_bp.route("/api/vision/grab", methods=["POST"])
|
||||
@@ -1026,7 +1097,16 @@ def _station_camera(station_code: str | None) -> tuple[str, str] | None:
|
||||
@role_required("MeasurementTec")
|
||||
def api_vision_grab():
|
||||
"""Proxy: grab one frame from the current station's camera, answer a PNG."""
|
||||
camera = _station_camera(_current_station()[0])
|
||||
# #97: con task_id (form o json) la camera e' quella del task, altrimenti della stazione
|
||||
payload = request.get_json(silent=True) or {}
|
||||
task_id = request.form.get("task_id") or payload.get("task_id")
|
||||
task = None
|
||||
if task_id:
|
||||
try:
|
||||
task = api_client.get(f"/api/tasks/{int(task_id)}")
|
||||
except (TypeError, ValueError):
|
||||
task = None
|
||||
camera = _task_camera(task, _current_station()[0])
|
||||
if camera is None:
|
||||
return jsonify({
|
||||
"error": True,
|
||||
|
||||
Reference in New Issue
Block a user