openplot 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- openplot/__init__.py +3 -0
- openplot/api/__init__.py +1 -0
- openplot/api/schemas.py +132 -0
- openplot/cli.py +139 -0
- openplot/desktop.py +437 -0
- openplot/domain/__init__.py +1 -0
- openplot/domain/annotations.py +45 -0
- openplot/domain/regions.py +52 -0
- openplot/executor.py +726 -0
- openplot/feedback.py +141 -0
- openplot/mcp_server.py +353 -0
- openplot/models.py +408 -0
- openplot/release_versioning.py +305 -0
- openplot/server.py +11120 -0
- openplot/services/__init__.py +1 -0
- openplot/services/naming.py +75 -0
- openplot/static/assets/MarkdownRenderer-DqMDEmDw.js +2 -0
- openplot/static/assets/geist-cyrillic-wght-normal-CHSlOQsW.woff2 +0 -0
- openplot/static/assets/geist-latin-ext-wght-normal-DMtmJ5ZE.woff2 +0 -0
- openplot/static/assets/geist-latin-wght-normal-Dm3htQBi.woff2 +0 -0
- openplot/static/assets/iconify-xdk4cov8.js +1 -0
- openplot/static/assets/index-9qrwxLoh.css +1 -0
- openplot/static/assets/index-DhwX5yIi.js +19 -0
- openplot/static/assets/lucide-DCaNFHhh.js +1 -0
- openplot/static/assets/markdown-BgYhP8km.js +29 -0
- openplot/static/assets/openplot-DYqSIMi_.png +0 -0
- openplot/static/assets/react-vendor-C4hNv3Lv.js +9 -0
- openplot/static/assets/ui-DjPaK12C.js +12 -0
- openplot/static/index.html +17 -0
- openplot/static/vite.svg +1 -0
- openplot-1.0.0.dist-info/METADATA +332 -0
- openplot-1.0.0.dist-info/RECORD +34 -0
- openplot-1.0.0.dist-info/WHEEL +4 -0
- openplot-1.0.0.dist-info/entry_points.txt +4 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Shared domain helpers for OpenPlot."""
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""Shared helpers for annotation ordering and context filtering."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any, Mapping
|
|
6
|
+
|
|
7
|
+
from ..models import Annotation, AnnotationStatus, PlotSession
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def pending_annotations_for_context(session: PlotSession) -> list[Annotation]:
|
|
11
|
+
"""Pending annotations in the active branch, ordered FIFO."""
|
|
12
|
+
active_branch_id = session.active_branch_id
|
|
13
|
+
pending = [
|
|
14
|
+
ann
|
|
15
|
+
for ann in session.annotations
|
|
16
|
+
if ann.status == AnnotationStatus.pending
|
|
17
|
+
and (not ann.branch_id or ann.branch_id == active_branch_id)
|
|
18
|
+
]
|
|
19
|
+
return sorted(pending, key=lambda ann: (ann.created_at, ann.id))
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def pending_annotation_dicts_for_context(
|
|
23
|
+
session: Mapping[str, Any],
|
|
24
|
+
) -> list[dict[str, Any]]:
|
|
25
|
+
"""Pending annotation payloads in the active branch, ordered FIFO."""
|
|
26
|
+
annotations = session.get("annotations", [])
|
|
27
|
+
if not isinstance(annotations, list):
|
|
28
|
+
return []
|
|
29
|
+
|
|
30
|
+
active_branch_id = session.get("active_branch_id")
|
|
31
|
+
pending = [
|
|
32
|
+
ann
|
|
33
|
+
for ann in annotations
|
|
34
|
+
if isinstance(ann, dict)
|
|
35
|
+
and ann.get("status") == AnnotationStatus.pending.value
|
|
36
|
+
and (
|
|
37
|
+
not active_branch_id
|
|
38
|
+
or not ann.get("branch_id")
|
|
39
|
+
or ann.get("branch_id") == active_branch_id
|
|
40
|
+
)
|
|
41
|
+
]
|
|
42
|
+
return sorted(
|
|
43
|
+
pending,
|
|
44
|
+
key=lambda ann: (str(ann.get("created_at") or ""), str(ann.get("id") or "")),
|
|
45
|
+
)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""Shared helpers for raster-region normalization and descriptions."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def clamp_01(value: float) -> float:
|
|
9
|
+
return max(0.0, min(1.0, value))
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def region_bounds_from_points(
|
|
13
|
+
points: Any,
|
|
14
|
+
) -> tuple[float, float, float, float] | None:
|
|
15
|
+
"""Return normalized region bounds as (x0, y0, x1, y1)."""
|
|
16
|
+
if not isinstance(points, list) or not points:
|
|
17
|
+
return None
|
|
18
|
+
|
|
19
|
+
xs: list[float] = []
|
|
20
|
+
ys: list[float] = []
|
|
21
|
+
for point in points:
|
|
22
|
+
if not isinstance(point, dict):
|
|
23
|
+
continue
|
|
24
|
+
raw_x = point.get("x")
|
|
25
|
+
raw_y = point.get("y")
|
|
26
|
+
if not isinstance(raw_x, (int, float)) or not isinstance(raw_y, (int, float)):
|
|
27
|
+
continue
|
|
28
|
+
xs.append(clamp_01(float(raw_x)))
|
|
29
|
+
ys.append(clamp_01(float(raw_y)))
|
|
30
|
+
|
|
31
|
+
if not xs or not ys:
|
|
32
|
+
return None
|
|
33
|
+
|
|
34
|
+
return min(xs), min(ys), max(xs), max(ys)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def region_zone_hint_from_bounds(bounds: tuple[float, float, float, float]) -> str:
|
|
38
|
+
"""A simple vertical zone hint to reduce subplot-scope ambiguity."""
|
|
39
|
+
_x0, y0, _x1, y1 = bounds
|
|
40
|
+
y_mid = (y0 + y1) / 2.0
|
|
41
|
+
if y_mid < 1 / 3:
|
|
42
|
+
return "upper figure zone"
|
|
43
|
+
if y_mid < 2 / 3:
|
|
44
|
+
return "middle figure zone"
|
|
45
|
+
return "lower figure zone"
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def region_zone_hint_from_points(points: Any) -> str:
|
|
49
|
+
bounds = region_bounds_from_points(points)
|
|
50
|
+
if bounds is None:
|
|
51
|
+
return "unknown figure zone"
|
|
52
|
+
return region_zone_hint_from_bounds(bounds)
|