"""Phase 3 vision + Qwythos API smoke tests.""" from __future__ import annotations import json import sys import threading import time from pathlib import Path import numpy as np sys.path.insert(0, str(Path(__file__).resolve().parents[1])) from hoa64.analysis import angular_error_deg from hoa64.server import TOOL_SCHEMA, handle_analyze from hoa64.vision import encode_boxes_to_hoa, fuse_reports, report_from_boxes def test_vision_point_doa(): rep = report_from_boxes( [{"az": 45.0, "el": -10.0, "kind": "point", "weight": 1.0, "label": "p"}], max_order=3, ) err = angular_error_deg(45.0, -10.0, rep.doa_az_deg, rep.doa_el_deg) # intensity on static field works; peak should be tight perr = angular_error_deg(45.0, -10.0, rep.peak_az_deg, rep.peak_el_deg) assert perr < 8.0, f"peak err={perr} doa=({rep.doa_az_deg},{rep.doa_el_deg})" assert rep.kind == "spatial_vision" assert rep.sources_hint[0]["label"] == "p" def test_vision_box_lobe_near_center(): hoa = encode_boxes_to_hoa( [{"az": 0.0, "el": 0.0, "w_deg": 15, "h_deg": 15, "weight": 1.0}], max_order=3, n_azi=48, n_el=24, ) assert hoa.shape[0] == 64 assert np.linalg.norm(hoa) > 0 # W channel should dominate for broad front lobe assert abs(hoa[0]) > 0 def test_fuse_agreement(): audio = {"doa_az_deg": 10.0, "doa_el_deg": 0.0, "energy": 1.0} vision = {"doa_az_deg": 12.0, "doa_el_deg": 1.0, "energy": 0.8} f = fuse_reports(audio, vision) assert f["agreement"] is True assert f["angular_separation_deg"] < 15 assert "one_liner" in f def test_fuse_disagreement(): audio = {"doa_az_deg": 0.0, "doa_el_deg": 0.0, "energy": 1.0} vision = {"doa_az_deg": 90.0, "doa_el_deg": 0.0, "energy": 1.0} f = fuse_reports(audio, vision) assert f["agreement"] is False assert f["angular_separation_deg"] > 80 def test_handle_analyze_vision_and_demo(): d = handle_analyze({"mode": "demo_scene", "order": 2}) assert d["schema"].startswith("spatial-hoa") assert "one_liner" in d v = handle_analyze( { "mode": "vision", "order": 3, "boxes": [{"az": -30, "el": 5, "kind": "ray", "label": "x"}], } ) assert v["kind"] == "spatial_vision" err = angular_error_deg(-30, 5, v["peak_az_deg"], v["peak_el_deg"]) assert err < 10.0 def test_tool_schema_shape(): assert TOOL_SCHEMA["type"] == "function" assert TOOL_SCHEMA["function"]["name"] == "spatial_analyze" if __name__ == "__main__": test_vision_point_doa() print("OK test_vision_point_doa") test_vision_box_lobe_near_center() print("OK test_vision_box_lobe_near_center") test_fuse_agreement() print("OK test_fuse_agreement") test_fuse_disagreement() print("OK test_fuse_disagreement") test_handle_analyze_vision_and_demo() print("OK test_handle_analyze_vision_and_demo") test_tool_schema_shape() print("OK test_tool_schema_shape")