Files
john 1aaef71f52 Initial commit: Happy Up monorepo through Sprint 5.
Document-driven MVP with FastAPI backend, Vue H5, WeChat mini shell, product demo, and Docker dev stack.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-23 11:42:40 +08:00

86 lines
3.4 KiB
Python

def test_pose_metrics_screening():
from app.ai.pose_metrics import LEFT_HIP, LEFT_SHOULDER, NOSE, RIGHT_HIP, RIGHT_SHOULDER, build_screening_report
good_frame = {
NOSE: {"x": 0.5, "y": 0.25, "visibility": 0.95},
LEFT_SHOULDER: {"x": 0.42, "y": 0.35, "visibility": 0.95},
RIGHT_SHOULDER: {"x": 0.58, "y": 0.35, "visibility": 0.95},
LEFT_HIP: {"x": 0.44, "y": 0.55, "visibility": 0.95},
RIGHT_HIP: {"x": 0.56, "y": 0.55, "visibility": 0.95},
}
bad_frame = {
NOSE: {"x": 0.72, "y": 0.28, "visibility": 0.95},
LEFT_SHOULDER: {"x": 0.42, "y": 0.35, "visibility": 0.95},
RIGHT_SHOULDER: {"x": 0.58, "y": 0.42, "visibility": 0.95},
LEFT_HIP: {"x": 0.44, "y": 0.58, "visibility": 0.95},
RIGHT_HIP: {"x": 0.56, "y": 0.52, "visibility": 0.95},
}
report = build_screening_report([good_frame] * 4 + [bad_frame] * 4)
assert report["riskLevel"] in ("low", "medium", "high")
assert len(report["metrics"]) >= 2
assert report["summary"]
def test_pose_metrics_movement():
from app.ai.pose_metrics import LEFT_SHOULDER, NOSE, RIGHT_SHOULDER, build_movement_report
frame = {
NOSE: {"x": 0.5, "y": 0.25, "visibility": 0.95},
LEFT_SHOULDER: {"x": 0.42, "y": 0.35, "visibility": 0.95},
RIGHT_SHOULDER: {"x": 0.58, "y": 0.35, "visibility": 0.95},
}
report = build_movement_report([frame] * 8)
assert 50 <= report["score"] <= 100
assert report["dimensions"]["stability"] >= 50
def test_report_list_and_pdf(client, auth_headers):
child_id = client.post(
"/api/children",
headers=auth_headers,
json={"name": "PDF测试", "birthday": "2016-01-01", "gender": "male"},
).json()["data"]["id"]
object_key = f"videos/{child_id}/pdf-test.mp4"
video_id = client.post(
"/api/videos",
headers=auth_headers,
json={"childId": child_id, "objectKey": object_key, "scene": "front_posture"},
).json()["data"]["id"]
task = client.post(
"/api/analysis/tasks",
headers={**auth_headers, "Idempotency-Key": "sprint5-pdf"},
json={"childId": child_id, "videoId": video_id, "taskType": "posture_screening"},
).json()["data"]
assert task["reportId"]
list_resp = client.get(f"/api/reports?childId={child_id}", headers=auth_headers)
assert list_resp.status_code == 200
assert any(item["id"] == task["reportId"] for item in list_resp.json()["data"]["list"])
pdf_resp = client.get(f"/api/reports/{task['reportId']}/pdf", headers=auth_headers)
assert pdf_resp.status_code == 200
assert pdf_resp.headers["content-type"] == "application/pdf"
assert pdf_resp.content[:4] == b"%PDF"
def test_oss_public_url(monkeypatch):
from app.config import settings
from app.services import oss as oss_service
monkeypatch.setattr(settings, "oss_enabled", True)
monkeypatch.setattr(settings, "oss_provider", "aliyun")
monkeypatch.setattr(settings, "oss_endpoint", "https://oss-cn-hangzhou.aliyuncs.com")
monkeypatch.setattr(settings, "oss_bucket", "happy-up-prod")
monkeypatch.setattr(settings, "oss_cdn_base_url", "https://cdn.example.com")
assert oss_service.public_object_url("videos/1/a.mp4") == "https://cdn.example.com/videos/1/a.mp4"
monkeypatch.setattr(settings, "oss_cdn_base_url", "")
assert (
oss_service.public_object_url("videos/1/a.mp4")
== "https://oss-cn-hangzhou.aliyuncs.com/happy-up-prod/videos/1/a.mp4"
)