fix(work_plane): allow negative offset_mm + readable validation errors
- Drop the ge=0 constraint on FitReq.offset_mm (negative values are a documented usage: aggressive noise cull above the plane). - HTML input min lowered to -200 to match. - Render FastAPI 422 validation arrays as a human-readable string in the status chip (was showing "[object Object]"). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
92506d62c6
commit
76e0739620
3 files changed
+22
-4
No files matched your search
@@ -31,7 +31,10 @@ class FitReq(BaseModel):
|
|||||||
v_min: int = Field(..., ge=0)
|
v_min: int = Field(..., ge=0)
|
||||||
u_max: int = Field(..., gt=0)
|
u_max: int = Field(..., gt=0)
|
||||||
v_max: int = Field(..., gt=0)
|
v_max: int = Field(..., gt=0)
|
||||||
offset_mm: float = Field(5.0, ge=0.0, le=200.0)
|
# offset_mm può essere negativo: valore <0 esclude un buffer SOPRA il
|
||||||
|
# piano (toglie noise depth della superficie); valore >0 è permissivo
|
||||||
|
# (mantieni un buffer sotto il piano). Range esteso simmetricamente.
|
||||||
|
offset_mm: float = Field(5.0, ge=-200.0, le=200.0)
|
||||||
max_preview_points: int = Field(5000, ge=100, le=20000)
|
max_preview_points: int = Field(5000, ge=100, le=20000)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -205,7 +205,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="kv compact">
|
<div class="kv compact">
|
||||||
<label>ROI <span id="wpRoiInfo" class="dim">— · clicca 2 angoli sull'RGB</span></label>
|
<label>ROI <span id="wpRoiInfo" class="dim">— · clicca 2 angoli sull'RGB</span></label>
|
||||||
<label>offset (mm) <input type="number" id="wpOffset" value="5.0" step="0.5" min="0" max="200" /></label>
|
<label>offset (mm) <input type="number" id="wpOffset" value="5.0" step="0.5" min="-200" max="200" /></label>
|
||||||
</div>
|
</div>
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
<button id="wpFitBtn" class="primary" disabled>Calcola piano (preview)</button>
|
<button id="wpFitBtn" class="primary" disabled>Calcola piano (preview)</button>
|
||||||
|
|||||||
+17
-2
@@ -246,6 +246,21 @@ function renderDetails(plane) {
|
|||||||
$('wpDetails').textContent = JSON.stringify(plane, null, 2);
|
$('wpDetails').textContent = JSON.stringify(plane, null, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FastAPI 422 returns `detail` as an array of validation errors:
|
||||||
|
// [{loc, msg, type, ...}, ...]
|
||||||
|
// Plain HTTPException returns it as a string. Render either case usefully so
|
||||||
|
// the status chip never says "[object Object]".
|
||||||
|
function formatDetail(detail) {
|
||||||
|
if (typeof detail === 'string') return detail;
|
||||||
|
if (Array.isArray(detail)) {
|
||||||
|
return detail.map(e => {
|
||||||
|
const loc = Array.isArray(e.loc) ? e.loc.join('.') : e.loc;
|
||||||
|
return loc ? `${loc}: ${e.msg}` : (e.msg || JSON.stringify(e));
|
||||||
|
}).join('; ');
|
||||||
|
}
|
||||||
|
return JSON.stringify(detail);
|
||||||
|
}
|
||||||
|
|
||||||
async function doFit() {
|
async function doFit() {
|
||||||
if (!roi) return;
|
if (!roi) return;
|
||||||
setChip('fit…');
|
setChip('fit…');
|
||||||
@@ -259,7 +274,7 @@ async function doFit() {
|
|||||||
method: 'POST', headers: { 'Content-Type': 'application/json' },
|
method: 'POST', headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify(body),
|
body: JSON.stringify(body),
|
||||||
}).then((r) => r.json());
|
}).then((r) => r.json());
|
||||||
if (r.detail) throw new Error(r.detail);
|
if (r.detail) throw new Error(formatDetail(r.detail));
|
||||||
previewPlane = r.plane;
|
previewPlane = r.plane;
|
||||||
previewPoints = r.points_camera;
|
previewPoints = r.points_camera;
|
||||||
three.setPlane(previewPlane);
|
three.setPlane(previewPlane);
|
||||||
@@ -282,7 +297,7 @@ async function doSave() {
|
|||||||
method: 'POST', headers: { 'Content-Type': 'application/json' },
|
method: 'POST', headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({ plane: previewPlane }),
|
body: JSON.stringify({ plane: previewPlane }),
|
||||||
}).then((r) => r.json());
|
}).then((r) => r.json());
|
||||||
if (r.detail) throw new Error(r.detail);
|
if (r.detail) throw new Error(formatDetail(r.detail));
|
||||||
savedPlane = r.plane;
|
savedPlane = r.plane;
|
||||||
previewPlane = null;
|
previewPlane = null;
|
||||||
$('wpStateBlock').innerHTML = `piano salvato · RMS ${savedPlane.fit_rms_mm.toFixed(1)} mm · n_inliers ${savedPlane.n_inliers} · offset ${savedPlane.offset_mm} mm`;
|
$('wpStateBlock').innerHTML = `piano salvato · RMS ${savedPlane.fit_rms_mm.toFixed(1)} mm · n_inliers ${savedPlane.n_inliers} · offset ${savedPlane.offset_mm} mm`;
|
||||||
|
|||||||
Reference in new issue
Block a user