tkadkghdlf commited on
Commit
e8137ff
·
verified ·
1 Parent(s): a821b6f

Sync DemoService 42773efa3fee367a7ac26de8f7f0006519a6e1e8

Browse files
api/ai-service/app/api/v1/endpoints/route_generation.py CHANGED
@@ -437,8 +437,8 @@ def _run_fast_road_pipeline(
437
  rank_projections = getattr(module, "rank_road_template_projections", None)
438
  for search_distance_km in (6.0, 11.0, 18.0):
439
  template_kwargs = {}
440
- if selected_label == "symbol_star" and callable(rank_projections):
441
- # Screen every supplied star outline against this road graph;
442
  # only the best fits enter the expensive shortest-path stage.
443
  template_kwargs["template_examples"] = rank_projections(
444
  graph, examples, search_distance_km * 1000.0,
 
437
  rank_projections = getattr(module, "rank_road_template_projections", None)
438
  for search_distance_km in (6.0, 11.0, 18.0):
439
  template_kwargs = {}
440
+ if selected_label in {"symbol_star", "dog"} and callable(rank_projections):
441
+ # Screen every supplied animal/shape outline against this road graph;
442
  # only the best fits enter the expensive shortest-path stage.
443
  template_kwargs["template_examples"] = rank_projections(
444
  graph, examples, search_distance_km * 1000.0,
api/ai-service/tests/test_gpx_shape_templates.py CHANGED
@@ -11,6 +11,7 @@ APPROVED_TEMPLATES = ROOT / "router" / "ai" / "data" / "approved_road_shape_temp
11
  TSHIRT_TEMPLATES = ROOT / "router" / "ai" / "data" / "tshirt_shape_templates.json"
12
  STAR_TEMPLATES = ROOT / "router" / "ai" / "data" / "star_shape_templates.json"
13
  ALL_STAR_TEMPLATES = ROOT / "router" / "ai" / "data" / "star_shape_templates_all.json"
 
14
 
15
 
16
  def test_dog_and_star_gpx_examples_are_normalized_and_closed():
@@ -69,6 +70,20 @@ def test_new_star_gpx_examples_are_available_for_road_generation():
69
  assert all([tuple(point) for point in outline] in loaded["symbol_star"] for outline in all_outlines)
70
 
71
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  def test_every_star_outline_is_screened_before_road_pathfinding():
73
  import math
74
  import networkx as nx
 
11
  TSHIRT_TEMPLATES = ROOT / "router" / "ai" / "data" / "tshirt_shape_templates.json"
12
  STAR_TEMPLATES = ROOT / "router" / "ai" / "data" / "star_shape_templates.json"
13
  ALL_STAR_TEMPLATES = ROOT / "router" / "ai" / "data" / "star_shape_templates_all.json"
14
+ ALL_DOG_TEMPLATES = ROOT / "router" / "ai" / "data" / "dog_shape_templates_all.json"
15
 
16
 
17
  def test_dog_and_star_gpx_examples_are_normalized_and_closed():
 
70
  assert all([tuple(point) for point in outline] in loaded["symbol_star"] for outline in all_outlines)
71
 
72
 
73
+ def test_new_dog_gpx_examples_are_available_for_road_generation():
74
+ outlines = json.loads(ALL_DOG_TEMPLATES.read_text(encoding="utf-8"))["dog"]
75
+ assert len(outlines) == 998
76
+ assert len({tuple(map(tuple, outline)) for outline in outlines}) == 998
77
+ assert all(outline[0] == outline[-1] for outline in outlines)
78
+ script = ROOT / "router" / "ai" / "scripts" / "clip_osm_region_test.py"
79
+ tree = ast.parse(script.read_text(encoding="utf-8-sig"))
80
+ loader = next(node for node in tree.body if isinstance(node, ast.FunctionDef) and node.name == "_load_gpx_shape_templates")
81
+ scope = {"__file__": str(script), "Path": Path, "json": json}
82
+ exec(compile(ast.Module(body=[loader], type_ignores=[]), str(script), "exec"), scope)
83
+ loaded = scope["_load_gpx_shape_templates"]()
84
+ assert all([tuple(point) for point in outline] in loaded["dog"] for outline in outlines)
85
+
86
+
87
  def test_every_star_outline_is_screened_before_road_pathfinding():
88
  import math
89
  import networkx as nx
api/ai-service/tests/test_route_generation_recovery.py CHANGED
@@ -157,7 +157,8 @@ def test_shape_priority_searches_multiple_lengths_and_ranks_by_shape(monkeypatch
157
  assert result["target_distance_km"] == 0
158
 
159
 
160
- def test_star_search_screens_all_outlines_before_road_routing(monkeypatch):
 
161
  examples = [[(index, 0), (index, 1), (index + 1, 1), (index, 0)] for index in range(1000)]
162
  screened = []
163
  routed = []
@@ -172,7 +173,7 @@ def test_star_search_screens_all_outlines_before_road_routing(monkeypatch):
172
  "shape_quality": 0.6, "is_loop": True}]
173
 
174
  module = SimpleNamespace(
175
- GPX_SHAPE_TEMPLATES={"symbol_star": examples},
176
  _build_or_get_walk_graph=lambda *_: (object(), "test"),
177
  rank_road_template_projections=screen,
178
  generate_candidate_routes=candidates,
@@ -181,7 +182,7 @@ def test_star_search_screens_all_outlines_before_road_routing(monkeypatch):
181
  monkeypatch.setattr(routes, "_route_nodes_to_coords", lambda _graph, nodes: [[nodes[0], 0], [nodes[1], 1]])
182
  monkeypatch.setattr(routes, "best_gpx_shape_match", lambda _coords, templates: (0.9, len(templates) - 1))
183
  routes._run_fast_road_pipeline(module, place=None, center_lat=37, center_lon=127,
184
- radius_km=5, route_count=2, target_distance_km=6, selected_label="symbol_star", shape_priority=True)
185
  assert screened == [(1000, 6000), (1000, 11000), (1000, 18000)]
186
  assert len(routed) == 3
187
  assert all(len(templates) == 36 and templates[-1] == examples[-1] for templates in routed)
 
157
  assert result["target_distance_km"] == 0
158
 
159
 
160
+ @pytest.mark.parametrize("label", ["symbol_star", "dog"])
161
+ def test_gpx_search_screens_all_outlines_before_road_routing(monkeypatch, label):
162
  examples = [[(index, 0), (index, 1), (index + 1, 1), (index, 0)] for index in range(1000)]
163
  screened = []
164
  routed = []
 
173
  "shape_quality": 0.6, "is_loop": True}]
174
 
175
  module = SimpleNamespace(
176
+ GPX_SHAPE_TEMPLATES={label: examples},
177
  _build_or_get_walk_graph=lambda *_: (object(), "test"),
178
  rank_road_template_projections=screen,
179
  generate_candidate_routes=candidates,
 
182
  monkeypatch.setattr(routes, "_route_nodes_to_coords", lambda _graph, nodes: [[nodes[0], 0], [nodes[1], 1]])
183
  monkeypatch.setattr(routes, "best_gpx_shape_match", lambda _coords, templates: (0.9, len(templates) - 1))
184
  routes._run_fast_road_pipeline(module, place=None, center_lat=37, center_lon=127,
185
+ radius_km=5, route_count=2, target_distance_km=6, selected_label=label, shape_priority=True)
186
  assert screened == [(1000, 6000), (1000, 11000), (1000, 18000)]
187
  assert len(routed) == 3
188
  assert all(len(templates) == 36 and templates[-1] == examples[-1] for templates in routed)
router/ai/data/dog_shape_templates_all.json ADDED
The diff for this file is too large to render. See raw diff
 
router/ai/scripts/build_dog_shape_templates.py ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Package location-free dog outlines from a multi-track GPX file.
2
+
3
+ Usage: python build_dog_shape_templates.py DOG_ALL.gpx OUTPUT_JSON
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ import json
9
+ import sys
10
+ import xml.etree.ElementTree as ET
11
+ from pathlib import Path
12
+
13
+ from build_gpx_shape_templates import normalized_outline_from_track
14
+
15
+
16
+ def build(source: Path) -> dict[str, list[list[list[float]]]]:
17
+ outlines = []
18
+ seen = set()
19
+ root = ET.parse(source).getroot()
20
+ for index, track in enumerate(node for node in root if node.tag.rsplit("}", 1)[-1] == "trk"):
21
+ points = [
22
+ (float(node.attrib["lat"]), float(node.attrib["lon"]))
23
+ for node in track.iter()
24
+ if node.tag.rsplit("}", 1)[-1] == "trkpt"
25
+ ]
26
+ outline = normalized_outline_from_track(points, f"{source.name}:{index}")
27
+ signature = tuple(map(tuple, outline))
28
+ if signature not in seen:
29
+ seen.add(signature)
30
+ outlines.append(outline)
31
+ if not outlines:
32
+ raise ValueError("No dog outlines found")
33
+ return {"dog": outlines}
34
+
35
+
36
+ if __name__ == "__main__":
37
+ if len(sys.argv) != 3:
38
+ raise SystemExit("Usage: build_dog_shape_templates.py DOG_ALL.gpx OUTPUT_JSON")
39
+ output = Path(sys.argv[2])
40
+ templates = build(Path(sys.argv[1]))
41
+ output.parent.mkdir(parents=True, exist_ok=True)
42
+ output.write_text(json.dumps(templates, separators=(",", ":")) + "\n", encoding="utf-8")
43
+ print({label: len(items) for label, items in templates.items()})
router/ai/scripts/clip_osm_region_test.py CHANGED
@@ -147,7 +147,7 @@ def _load_gpx_shape_templates() -> dict[str, list[list[tuple[float, float]]]]:
147
  data_dir = Path(__file__).resolve().parents[1] / "data"
148
  templates: dict[str, list[list[tuple[float, float]]]] = {"dog": [], "symbol_star": [], "t_shirt": []}
149
  seen: dict[str, set[tuple[tuple[float, float], ...]]] = {label: set() for label in templates}
150
- for filename in ("gpx_shape_templates.json", "approved_road_shape_templates.json", "tshirt_shape_templates.json", "star_shape_templates.json", "star_shape_templates_all.json"):
151
  try:
152
  payload = json.loads((data_dir / filename).read_text(encoding="utf-8"))
153
  except (OSError, ValueError, TypeError):
 
147
  data_dir = Path(__file__).resolve().parents[1] / "data"
148
  templates: dict[str, list[list[tuple[float, float]]]] = {"dog": [], "symbol_star": [], "t_shirt": []}
149
  seen: dict[str, set[tuple[tuple[float, float], ...]]] = {label: set() for label in templates}
150
+ for filename in ("gpx_shape_templates.json", "approved_road_shape_templates.json", "tshirt_shape_templates.json", "star_shape_templates.json", "star_shape_templates_all.json", "dog_shape_templates_all.json"):
151
  try:
152
  payload = json.loads((data_dir / filename).read_text(encoding="utf-8"))
153
  except (OSError, ValueError, TypeError):