fix(inference): METADATA-35 fit Call 1/2 images to 1024 long edge
Downscale processed PNGs only on the inference send path (keep alpha, never upscale). Stored inventory/Woo blobs unchanged. Adds Pillow + unit/e2e-style tests; cite tests on METADATA-35.
This commit is contained in:
@@ -126,3 +126,82 @@ def test_test_inference_unconfigured(env):
|
||||
r = client.post("/api/v1/admin/test-inference")
|
||||
assert r.status_code == 200
|
||||
assert r.json()["ok"] is False and r.json()["mode"] == "fail"
|
||||
|
||||
|
||||
def _rgba_png(w: int, h: int) -> bytes:
|
||||
"""RGBA PNG: opaque body + transparent top-left block (capture-like alpha)."""
|
||||
from PIL import Image
|
||||
import io
|
||||
im = Image.new("RGBA", (w, h), (10, 20, 30, 255))
|
||||
for y in range(min(80, h)):
|
||||
for x in range(min(80, w)):
|
||||
im.putpixel((x, y), (0, 0, 0, 0))
|
||||
buf = io.BytesIO()
|
||||
im.save(buf, format="PNG")
|
||||
return buf.getvalue()
|
||||
|
||||
|
||||
def test_fit_long_edge_png_downscales_over_1024():
|
||||
"""METADATA-35: Call 1 images long edge <= 1024; never upscale; keep alpha."""
|
||||
from backend.inference import fit_long_edge_png
|
||||
from PIL import Image
|
||||
import io
|
||||
|
||||
src = _rgba_png(800, 1067) # inventory 3:4, long edge 1067
|
||||
out = fit_long_edge_png(src, max_long_edge=1024)
|
||||
im = Image.open(io.BytesIO(out)).convert("RGBA")
|
||||
assert max(im.size) == 1024
|
||||
assert min(im.size) < 1024
|
||||
w, h = im.size
|
||||
assert abs((w / h) - (800 / 1067)) < 0.02
|
||||
# Transparent block still transparent near origin after downscale
|
||||
assert im.getpixel((0, 0))[3] == 0
|
||||
assert im.getpixel((5, 5))[3] == 0
|
||||
|
||||
|
||||
def test_fit_long_edge_png_leaves_small_unchanged_dims():
|
||||
from backend.inference import fit_long_edge_png
|
||||
from PIL import Image
|
||||
import io
|
||||
|
||||
src = _rgba_png(400, 300)
|
||||
out = fit_long_edge_png(src, max_long_edge=1024)
|
||||
im = Image.open(io.BytesIO(out))
|
||||
assert im.size == (400, 300)
|
||||
|
||||
|
||||
def test_call1_sends_long_edge_at_most_1024(env, monkeypatch):
|
||||
"""METADATA-35 end-to-end: messages to the model use <=1024 long edge."""
|
||||
client, conn = env
|
||||
conn.execute("INSERT OR REPLACE INTO settings(key,value,value_enc) VALUES ('inference_enabled','true',NULL)")
|
||||
conn.execute(
|
||||
"INSERT INTO slabs(id,sku,length_in,thickness_in,status,server_rev,client_rev,created_at,updated_at) "
|
||||
"VALUES ('s1','SLAB-01',100,2,'calibrated',1,1,'t','t')"
|
||||
)
|
||||
big = _rgba_png(800, 1067)
|
||||
conn.execute(
|
||||
"INSERT INTO slab_photos(id,slab_id,seq,processed_blob,created_at) VALUES ('p1','s1',1,?, 't')",
|
||||
(big,),
|
||||
)
|
||||
conn.commit()
|
||||
from backend.inference import InferenceClient
|
||||
from PIL import Image
|
||||
import io
|
||||
|
||||
captured = {}
|
||||
|
||||
def fake_chat(self, messages):
|
||||
captured["messages"] = messages
|
||||
return json.dumps({"species_id": 1, "species_confidence": 0.9})
|
||||
|
||||
monkeypatch.setattr(InferenceClient, "chat", fake_chat)
|
||||
r = client.post("/api/v1/slabs/s1/inference/call1")
|
||||
assert r.status_code == 200, r.text
|
||||
content = captured["messages"][0]["content"]
|
||||
imgs = [p for p in content if isinstance(p, dict) and p.get("type") == "image_url"]
|
||||
assert len(imgs) == 1
|
||||
url = imgs[0]["image_url"]["url"]
|
||||
assert url.startswith("data:image/png;base64,")
|
||||
raw = base64.b64decode(url.split(",", 1)[1])
|
||||
im = Image.open(io.BytesIO(raw))
|
||||
assert max(im.size) <= 1024
|
||||
|
||||
Reference in New Issue
Block a user