updates UI

This commit is contained in:
mike
2026-06-30 01:07:54 +02:00
parent 61268de34b
commit ad9a2ae078
13 changed files with 1375 additions and 397 deletions

View File

@@ -799,5 +799,308 @@ class TestAPIRegression(unittest.TestCase):
except Exception:
pass
def test_14_static_serialization_of_deep_metadata(self):
import edit_api
import database
import json
import os
from PIL import Image
# Create dummy image and person record
fn = "test_deep_meta_serialization_123.png"
fpath = os.path.join(self.output_dir, fn)
Image.new("RGB", (10, 10)).save(fpath)
conn = database.get_db_connection()
cur = conn.cursor()
try:
cur.execute("""
INSERT INTO person (filename, filepath, group_id, people_count, anatomical_completeness, facial_direction, objects)
VALUES (%s, %s, %s, %s, %s, %s, %s)
""", (fn, fpath, "test_group", 2, False, "front", json.dumps([{"tag": "hat", "score": 0.9}])))
conn.commit()
finally:
cur.close()
database._put_db_connection(conn)
try:
# Trigger write static images.json
edit_api._write_all_static()
# Read static file and check that the deep metadata properties are serialized correctly
static_file = os.path.join(self.output_dir, "_data", "images.json")
self.assertTrue(os.path.exists(static_file))
with open(static_file, "r") as f:
data = json.load(f)
imgs = data.get("images", [])
matched = [x for x in imgs if x["filename"] == fn]
self.assertEqual(len(matched), 1)
item = matched[0]
# Assert that the serialized dictionary has all of the deep metadata fields
self.assertEqual(item.get("people_count"), 2)
self.assertEqual(item.get("anatomical_completeness"), False)
self.assertEqual(item.get("facial_direction"), "front")
self.assertEqual(item.get("objects"), [{"tag": "hat", "score": 0.9}])
finally:
# Clean up
if os.path.exists(fpath):
os.remove(fpath)
conn = database.get_db_connection()
cur = conn.cursor()
try:
cur.execute("DELETE FROM person WHERE filename = %s", (fn,))
conn.commit()
finally:
cur.close()
database._put_db_connection(conn)
# Re-generate static to clean up the dummy entry
edit_api._write_all_static()
def test_15_anatomical_completeness_refinement(self):
import edit_api
# 17 keypoints matching COCO-17 format: [x, y, score]
# Nose (0), shoulders (5,6), elbows (7,8), wrists (9,10), hips (11,12), knees (13,14), ankles (15,16)
# All of them are visible with score >= 0.3, and well within bounds [0.1, 0.9]
complete_kpts = [
[50, 10, 0.9], # Nose (0)
[48, 11, 0.9], # L_Eye (1)
[52, 11, 0.9], # R_Eye (2)
[46, 12, 0.9], # L_Ear (3)
[54, 12, 0.9], # R_Ear (4)
[40, 20, 0.9], # L_Shoulder (5)
[60, 20, 0.9], # R_Shoulder (6)
[35, 35, 0.9], # L_Elbow (7)
[65, 35, 0.9], # R_Elbow (8)
[30, 50, 0.9], # L_Wrist (9)
[70, 50, 0.9], # R_Wrist (10)
[42, 55, 0.9], # L_Hip (11)
[58, 55, 0.9], # R_Hip (12)
[40, 75, 0.9], # L_Knee (13)
[60, 75, 0.9], # R_Knee (14)
[40, 90, 0.9], # L_Ankle (15)
[60, 90, 0.9], # R_Ankle (16)
]
# Test complete pose
res1 = edit_api._detect_anatomical_completeness(complete_kpts, 100, 100)
self.assertTrue(res1)
# Test partial pose: missing knees and ankles
partial_kpts = [list(kp) for kp in complete_kpts]
for idx in [13, 14, 15, 16]:
partial_kpts[idx][2] = 0.1 # Hide them
res2 = edit_api._detect_anatomical_completeness(partial_kpts, 100, 100)
self.assertFalse(res2)
# Test cropped pose: ankles too close to bottom edge (y=99 in height=100)
cropped_bottom_kpts = [list(kp) for kp in complete_kpts]
cropped_bottom_kpts[15][1] = 99
cropped_bottom_kpts[16][1] = 99
res3 = edit_api._detect_anatomical_completeness(cropped_bottom_kpts, 100, 100)
self.assertFalse(res3)
def test_16_object_bbox_estimation(self):
import edit_api
# Define some realistic keypoints
kpts = [
[50, 10, 0.9], # Nose (0)
[48, 11, 0.9], # L_Eye (1)
[52, 11, 0.9], # R_Eye (2)
[46, 12, 0.9], # L_Ear (3)
[54, 12, 0.9], # R_Ear (4)
[40, 20, 0.9], # L_Shoulder (5)
[60, 20, 0.9], # R_Shoulder (6)
[35, 35, 0.9], # L_Elbow (7)
[65, 35, 0.9], # R_Elbow (8)
[30, 50, 0.9], # L_Wrist (9)
[70, 50, 0.9], # R_Wrist (10)
[42, 55, 0.9], # L_Hip (11)
[58, 55, 0.9], # R_Hip (12)
[40, 75, 0.9], # L_Knee (13)
[60, 75, 0.9], # R_Knee (14)
[40, 90, 0.9], # L_Ankle (15)
[60, 90, 0.9], # R_Ankle (16)
]
# Test head / hair tag bbox estimation
bbox_hair = edit_api._estimate_bbox_for_tag("long_hair", kpts, 100, 100)
self.assertIsNotNone(bbox_hair)
self.assertEqual(len(bbox_hair), 4)
# Bounding box should surround the head/face region, which is y-centered around 10-12.
# So upper y (bbox_hair[1]) should be relatively small (close to 0/top)
self.assertLess(bbox_hair[1], 15)
# Test chest tag bbox estimation
bbox_breasts = edit_api._estimate_bbox_for_tag("breasts", kpts, 100, 100)
self.assertIsNotNone(bbox_breasts)
self.assertEqual(len(bbox_breasts), 4)
# Should be below shoulders (y=20) and above hips (y=55). Center around 30.
self.assertGreater(bbox_breasts[1], 15)
self.assertLess(bbox_breasts[3], 55)
# Test stomach tag bbox estimation
bbox_navel = edit_api._estimate_bbox_for_tag("navel", kpts, 100, 100)
self.assertIsNotNone(bbox_navel)
self.assertEqual(len(bbox_navel), 4)
# Should be around the stomach area, i.e. between 35 and 55.
self.assertGreater(bbox_navel[1], 25)
# Test arms tag bbox estimation
bbox_arms = edit_api._estimate_bbox_for_tag("sleeves", kpts, 100, 100)
self.assertIsNotNone(bbox_arms)
self.assertEqual(len(bbox_arms), 4)
# Test legs tag bbox estimation
bbox_legs = edit_api._estimate_bbox_for_tag("thighs", kpts, 100, 100)
self.assertIsNotNone(bbox_legs)
self.assertEqual(len(bbox_legs), 4)
def test_17_gaze_and_pose_description_enhancements(self):
import edit_api
# Test 1: Standard upright front facing pose with direct gaze
standing_kpts = [
[50, 12.5, 0.9], # Nose (0)
[52, 11, 0.9], # L_Eye (1)
[48, 11, 0.9], # R_Eye (2)
[54, 12, 0.9], # L_Ear (3)
[46, 12, 0.9], # R_Ear (4)
[60, 20, 0.9], # L_Shoulder (5)
[40, 20, 0.9], # R_Shoulder (6)
[65, 35, 0.9], # L_Elbow (7)
[35, 35, 0.9], # R_Elbow (8)
[70, 50, 0.9], # L_Wrist (9)
[30, 50, 0.9], # R_Wrist (10)
[58, 55, 0.9], # L_Hip (11)
[42, 55, 0.9], # R_Hip (12)
[60, 75, 0.9], # L_Knee (13)
[40, 75, 0.9], # R_Knee (14)
[60, 90, 0.9], # L_Ankle (15)
[40, 90, 0.9], # R_Ankle (16)
]
pose_desc = edit_api._describe_pose(standing_kpts)
self.assertIn("standing", pose_desc)
self.assertIn("facing forward", pose_desc)
gaze = edit_api._detect_facial_direction(standing_kpts)
self.assertEqual(gaze, "looking forward")
# Test 2: Gaze look left and up
left_up_kpts = [list(kp) for kp in standing_kpts]
# To look left: nose (0) moves to the left (smaller X than ear midpoint 50)
left_up_kpts[0][0] = 45 # Nose X
# To look up: nose (0) moves up (y-level close to eye level y=11)
left_up_kpts[0][1] = 11.2 # Nose Y
gaze_left_up = edit_api._detect_facial_direction(left_up_kpts)
self.assertEqual(gaze_left_up, "looking left and up")
# Test 3: Lying down / reclining pose
lying_kpts = [list(kp) for kp in standing_kpts]
# In lying down, nose is at y=10, hips are at y=12 (very horizontal)
# Head X = 10, Hip X = 80
lying_kpts[0][0] = 10 # Head X
lying_kpts[0][1] = 10 # Head Y
lying_kpts[11][0] = 80 # Hip X
lying_kpts[11][1] = 12 # Hip Y
lying_kpts[12][0] = 80
lying_kpts[12][1] = 12
pose_desc_lying = edit_api._describe_pose(lying_kpts)
self.assertIn("lying down", pose_desc_lying)
def test_18_designer_enhancements(self):
import unittest.mock as mock
import edit_api
# 1. Test Deduplication of Pose Names
# We will mock the external requests.post LLM call to return some mock poses,
# one of which collides with an existing pose name in poses.md (e.g., "The Clasp" or "standing")
mock_raw_response = (
"# standing\n"
"This is a standing pose description.\n"
"Perfect anatomy, photorealistic.\n\n"
"# Custom Pose\n"
"This is a custom pose description.\n"
"Anatomically precise, photorealistic.\n"
)
mock_response = mock.Mock()
mock_response.status_code = 200
mock_response.json.return_value = {
"choices": [
{
"message": {
"content": mock_raw_response
}
}
]
}
with mock.patch("requests.post", return_value=mock_response) as mock_post:
# Let's override _load_poses to return {"standing": "existing text"} to force a name collision
with mock.patch("edit_api._load_poses", return_value={"standing": {"text": "existing text", "beta": False}}):
payload = {
"n": 2,
"context": "standing and custom pose instructions",
"filename": None,
"beta": False,
"messages": None
}
response = self.client.post("/designer/generate", json=payload)
self.assertEqual(response.status_code, 200)
data = response.json()
self.assertEqual(data["status"], "success")
poses = data["poses"]
# The duplicate "standing" name should be renamed to "standing 2" instead of skipped!
self.assertIn("standing 2", poses)
self.assertIn("Custom Pose", poses)
self.assertEqual(poses["standing 2"], "This is a standing pose description. Perfect anatomy, photorealistic.")
self.assertEqual(poses["Custom Pose"], "This is a custom pose description. Anatomically precise, photorealistic.")
# 2. Test Multi-Turn Conversation/History Payload Building
with mock.patch("requests.post", return_value=mock_response) as mock_post:
with mock.patch("edit_api._load_poses", return_value={}):
# Send history messages in the request
history_messages = [
{"role": "user", "content": "Initial prompt"},
{"role": "assistant", "content": "# Some Pose\nbody text"}
]
payload_with_history = {
"n": 1,
"context": "make them sit down",
"filename": None,
"beta": False,
"messages": history_messages
}
response = self.client.post("/designer/generate", json=payload_with_history)
self.assertEqual(response.status_code, 200)
# Check that requests.post was called with the correct messages payload
self.assertTrue(mock_post.called)
call_args = mock_post.call_args
called_json = call_args[1]["json"]
called_messages = called_json["messages"]
# The payload should contain:
# 1. System message (DESIGNER_SYSTEM)
# 2. Initial user prompt
# 3. Assistant response
# 4. New user follow-up prompt incorporating "make them sit down"
self.assertEqual(len(called_messages), 4)
self.assertEqual(called_messages[0]["role"], "system")
self.assertEqual(called_messages[1]["role"], "user")
self.assertEqual(called_messages[1]["content"], "Initial prompt")
self.assertEqual(called_messages[2]["role"], "assistant")
self.assertEqual(called_messages[2]["content"], "# Some Pose\nbody text")
self.assertEqual(called_messages[3]["role"], "user")
self.assertIn("make them sit down", called_messages[3]["content"])
if __name__ == "__main__":
unittest.main()