"""S7 inference tests (METADATA-105/106, 45, 55, 70, SETTINGS-45).""" import base64 import json import os import shutil import tempfile import pytest from fastapi.testclient import TestClient import backend.db as db_mod @pytest.fixture def env(monkeypatch): tmp = tempfile.mkdtemp(prefix="inf_") os.environ["SLAB_DB_PATH"] = os.path.join(tmp, "i.db") os.environ["SLAB_IMAGES_DIR"] = tmp os.environ["WOO_BASE_URL"] = "https://x.com" os.environ["SLAB_AES_KEY"] = base64.b64encode(b"0123456789abcdef0123456789abcdef").decode() db_mod._reset_for_tests() from backend.crypto import encrypt conn = db_mod.init_db() conn.execute("INSERT OR REPLACE INTO settings(key,value,value_enc) VALUES ('inference_base_url',NULL,?)", (encrypt("https://infer.example.com"),)) conn.execute("INSERT OR REPLACE INTO settings(key,value,value_enc) VALUES ('inference_api_key',NULL,?)", (encrypt("sk-test"),)) conn.execute("INSERT OR REPLACE INTO settings(key,value,value_enc) VALUES ('inference_model','gpt-test',NULL)") conn.commit() from backend.app import app yield TestClient(app), conn db_mod._reset_for_tests() shutil.rmtree(tmp, ignore_errors=True) def test_prompt_seed_and_revision(env): client, conn = env r = client.get("/api/v1/prompts/call1") assert r.status_code == 200 body = r.json() assert body["active_content"] is not None assert len(body["revisions"]) == 1 # seed only r = client.post("/api/v1/prompts/call1/revisions", json={"content": "revised prompt v2"}) assert r.status_code == 201 new_rev = r.json()["id"] # new revision becomes active r = client.get("/api/v1/prompts/call1") assert r.json()["active_revision_id"] == new_rev assert r.json()["active_content"] == "revised prompt v2" assert len(r.json()["revisions"]) == 2 # activate back to seed seed_rev = 1 r = client.post("/api/v1/prompts/call1/activate", json={"revision_id": seed_rev}) assert r.status_code == 200 assert client.get("/api/v1/prompts/call1").json()["active_content"] is not None def test_call1_confidence_gate(env, monkeypatch): client, conn = env # enable inference conn.execute("INSERT OR REPLACE INTO settings(key,value,value_enc) VALUES ('inference_enabled','true',NULL)") conn.execute("INSERT INTO woo_categories(id,name,slug,parent_id,woo_id) VALUES (1,'Black Walnut','black-walnut',NULL,100)") 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')") conn.execute("INSERT INTO slab_photos(id,slab_id,seq,processed_blob,created_at) VALUES ('p1','s1',1,X'89504E47','t')") conn.commit() from backend.inference import InferenceClient def fake_chat(self, messages): return json.dumps({ "species_id": 1, "species_confidence": 0.9, "wood_category_ids": [1], "wood_category_confidence": 0.5, # below threshold "grade_term_id": 7, "grade_confidence": 0.3, # below "figure_term_ids": [2], "figure_confidence": 0.8, # at/above }) monkeypatch.setattr(InferenceClient, "chat", fake_chat) r = client.post("/api/v1/slabs/s1/inference/call1") assert r.status_code == 200, r.text s = r.json()["suggestions"] assert s.get("species_id") == 1 assert s.get("figure_term_ids") == [2] assert "wood_category_ids" not in s # gated out assert "grade_term_id" not in s # gated out # inference_log written with call=1 assert conn.execute("SELECT call FROM inference_log").fetchone()["call"] == 1 def test_call2_stores_description(env, monkeypatch): client, conn = env conn.execute("INSERT OR REPLACE INTO settings(key,value,value_enc) VALUES ('content_llm_enabled','true',NULL)") conn.execute("INSERT INTO slabs(id,sku,length_in,thickness_in,width_avg_in,bdft,title,status,server_rev,client_rev,created_at,updated_at) VALUES ('s1','SLAB-01',100,2,20,18,'Walnut Slab','ready',1,1,'t','t')") conn.execute("INSERT INTO slab_photos(id,slab_id,seq,processed_blob,created_at) VALUES ('p1','s1',1,X'89504E47','t')") conn.commit() from backend.inference import InferenceClient monkeypatch.setattr(InferenceClient, "chat", lambda self, messages: "

A fine walnut slab.

") r = client.post("/api/v1/slabs/s1/inference/call2") assert r.status_code == 200, r.text assert r.json()["description"] == "

A fine walnut slab.

" row = conn.execute("SELECT description, content_source FROM slabs WHERE id='s1'").fetchone() assert row["description"] == "

A fine walnut slab.

" assert row["content_source"] == "llm" def test_inference_off_call1_409(env): client, conn = env conn.execute("INSERT INTO slabs(id,sku,status,server_rev,client_rev,created_at,updated_at) VALUES ('s1','SLAB-01','calibrated',1,1,'t','t')") conn.commit() r = client.post("/api/v1/slabs/s1/inference/call1") assert r.status_code == 409 # inference_enabled default off def test_server_description_inference_off(env): from backend.inference import server_description d = server_description({"title": "Figured Walnut Slab", "length_in": 114.0, "width_avg_in": 24.0, "thickness_in": 1.75, "bdft": 18.4}) assert "114.0in" in d and "18.4" in d def test_test_inference_unconfigured(env): client, conn = env conn.execute("UPDATE settings SET value_enc=NULL WHERE key='inference_api_key'") conn.commit() r = client.post("/api/v1/admin/test-inference") assert r.status_code == 200 assert r.json()["ok"] is False and r.json()["mode"] == "fail"