grid-cortex-client 0.5.1__tar.gz → 0.6.0__tar.gz
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.
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/PKG-INFO +1 -1
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/model_type.py +43 -21
- grid_cortex_client-0.6.0/src/grid_cortex_client/models/c_radio.py +129 -0
- grid_cortex_client-0.6.0/tests/test_c_radio.py +124 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/.gitignore +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/CLAUDE.md +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/README.md +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/pyproject.toml +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/__init__.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/client.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/cortex_client.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/cortex_hub_client.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/models/__init__.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/models/base_model.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/models/contact_graspnet.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/models/da3metric.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/models/fast_foundation_stereo.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/models/finetune_pi05.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/models/foundation_stereo.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/models/graspgen.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/models/graspgenx.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/models/gsam2.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/models/locate_anything.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/models/metric3d.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/models/moondream.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/models/oneformer.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/models/owlv2.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/models/pi05.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/models/qwen_vl.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/models/sam2.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/models/sam3.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/models/ur5e_pyroki_collision_batch.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/models/ur5e_pyroki_fk.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/models/zoedepth.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/preprocessing.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/tools/__init__.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/tools/generate_enum.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/tools/registry.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/utils.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/ws.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/tests/README.md +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/tests/__init__.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/tests/conftest.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/tests/test_contact_graspnet.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/tests/test_cortex_hub_client.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/tests/test_da3metric.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/tests/test_fast_foundation_stereo.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/tests/test_finetune_pi05.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/tests/test_foundation_stereo.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/tests/test_graspgen.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/tests/test_graspgenx.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/tests/test_gsam2.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/tests/test_locate_anything.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/tests/test_metric3d.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/tests/test_moondream.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/tests/test_oneformer.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/tests/test_owlv2.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/tests/test_pi05.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/tests/test_qwen_vl.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/tests/test_sam2.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/tests/test_sam3.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/tests/test_ur5e_pyroki_collision_batch.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/tests/test_ur5e_pyroki_fk.py +0 -0
- {grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/tests/test_zoedepth.py +0 -0
|
@@ -13,36 +13,54 @@ from enum import Enum
|
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
class ModelType(Enum):
|
|
16
|
-
|
|
16
|
+
C_RADIO = "c-radio"
|
|
17
17
|
"""
|
|
18
|
-
|
|
19
|
-
(+ optional segmentation mask) using Contact-GraspNet (PyTorch port).
|
|
18
|
+
Compute an L2-normalized embedding for a single RGB image.
|
|
20
19
|
|
|
21
20
|
Args:
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
seg_image (Union[str, Image.Image, np.ndarray, None]): Optional segmentation mask (uint8 H×W).
|
|
25
|
-
When supplied + aux_args["filter_grasps"] = True, grasps are restricted to the masked region.
|
|
26
|
-
aux_args (Dict[str, Any]): Optional dict. Keys:
|
|
27
|
-
- "top_k" (int, default 64): cap on returned grasps after score-sort.
|
|
28
|
-
- "z_range" ([float, float], default [0.2, 1.8]): z-axis crop in metres.
|
|
29
|
-
- "local_regions" (bool, default False): crop 3D regions around segments.
|
|
30
|
-
- "filter_grasps" (bool, default False): restrict grasps to segmap; requires seg_image.
|
|
31
|
-
- "forward_passes" (int, default 1): how many forward passes to ensemble.
|
|
32
|
-
timeout (float | None): Optional HTTP timeout.
|
|
21
|
+
image_input (Union[str, Image.Image, np.ndarray]): RGB image as file path, URL, PIL Image, or numpy array.
|
|
22
|
+
timeout (float | None): Optional timeout in seconds for the HTTP request.
|
|
33
23
|
|
|
34
24
|
Returns:
|
|
35
|
-
|
|
36
|
-
-
|
|
37
|
-
- confidence: Array of confidence scores in [0, 1], shape (N,).
|
|
38
|
-
- latency_ms: Optional server-reported latency in milliseconds.
|
|
25
|
+
np.ndarray: Embedding as numpy array of shape ``(D,)``, dtype ``float32``,
|
|
26
|
+
L2-normalized so dot products give cosine similarity directly.
|
|
39
27
|
|
|
40
28
|
Raises:
|
|
41
|
-
ValueError: If
|
|
29
|
+
ValueError: If image cannot be loaded.
|
|
42
30
|
RuntimeError: If no HTTP transport is configured.
|
|
43
31
|
Exception: If the HTTP request fails.
|
|
44
32
|
|
|
45
33
|
Example:
|
|
34
|
+
>>> from grid_cortex_client import CortexClient, ModelType
|
|
35
|
+
>>> import numpy as np
|
|
36
|
+
>>> from PIL import Image
|
|
37
|
+
>>> client = CortexClient()
|
|
38
|
+
>>> image = np.array(Image.open("cat.jpg"))
|
|
39
|
+
>>> emb = client.run(ModelType.C_RADIO, image_input=image)
|
|
40
|
+
>>> print(emb.shape, float(np.linalg.norm(emb))) # (D,) 1.0
|
|
41
|
+
"""
|
|
42
|
+
CONTACT_GRASPNET = "contact-graspnet"
|
|
43
|
+
"""
|
|
44
|
+
Generate grasps using ContactGraspNet.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
depth_image (Union[str, Image.Image, np.ndarray, None]): Depth image (required).
|
|
48
|
+
camera_intrinsics (Union[str, np.ndarray, None]): 3×3 intrinsics matrix (required).
|
|
49
|
+
seg_image (Union[str, Image.Image, np.ndarray, None]): Optional segmentation mask (uint8 H×W).
|
|
50
|
+
aux_args (Dict[str, Any] | None): Optional dict. Keys: ``top_k`` (int, default 64),
|
|
51
|
+
``z_range`` ([float, float], default [0.2, 1.8]),
|
|
52
|
+
``local_regions`` (bool, default False),
|
|
53
|
+
``filter_grasps`` (bool, default False; requires ``seg_image``),
|
|
54
|
+
``forward_passes`` (int, default 1).
|
|
55
|
+
timeout (float | None): Optional HTTP timeout.
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
Dict with:
|
|
59
|
+
- ``grasps``: (N, 4, 4) array of grasp poses in camera frame
|
|
60
|
+
- ``confidence``: (N,) array of confidence scores in [0, 1]
|
|
61
|
+
- ``latency_ms``: server-reported latency
|
|
62
|
+
|
|
63
|
+
Examples:
|
|
46
64
|
>>> from grid_cortex_client import CortexClient, ModelType
|
|
47
65
|
>>> import numpy as np
|
|
48
66
|
>>> client = CortexClient()
|
|
@@ -302,14 +320,18 @@ class ModelType(Enum):
|
|
|
302
320
|
"""
|
|
303
321
|
METRIC3D = "metric3d"
|
|
304
322
|
"""
|
|
305
|
-
Estimate metric depth and surface normals from a single RGB image.
|
|
323
|
+
Estimate metric depth and/or surface normals from a single RGB image.
|
|
306
324
|
|
|
307
325
|
Args:
|
|
308
326
|
image_input (Union[str, Image.Image, np.ndarray]): RGB image as file path, URL, PIL Image, or numpy array.
|
|
309
327
|
timeout (float | None): Optional timeout in seconds for the HTTP request.
|
|
328
|
+
outputs (Optional[Union[str, Sequence[str]]]): Keyword-only. Optional selection of maps to return —
|
|
329
|
+
``"depth"``, ``"normals"``, or a non-empty subset of both.
|
|
330
|
+
``None`` (default) returns both. Requesting only what you need
|
|
331
|
+
shrinks the response payload (normals are 3x the size of depth).
|
|
310
332
|
|
|
311
333
|
Returns:
|
|
312
|
-
Dict with
|
|
334
|
+
Dict with the requested subset of:
|
|
313
335
|
- ``"depth"``: (H, W) float32 array, metric depth in metres.
|
|
314
336
|
- ``"normals"``: (H, W, 3) float32 array, unit surface normals.
|
|
315
337
|
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"""C-RADIO wrapper.
|
|
2
|
+
|
|
3
|
+
Client-side helper for the dense visual embedding endpoint powered by
|
|
4
|
+
NVIDIA C-RADIOv4-SO400M.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from io import BytesIO
|
|
10
|
+
from typing import Any, Dict, Union
|
|
11
|
+
|
|
12
|
+
import numpy as np
|
|
13
|
+
from PIL import Image
|
|
14
|
+
|
|
15
|
+
from ..preprocessing import load_image, image_to_bytes
|
|
16
|
+
from .base_model import BaseModel
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class CRadio(BaseModel):
|
|
20
|
+
"""Dense visual embedding (C-RADIOv4-SO400M).
|
|
21
|
+
|
|
22
|
+
Preferred usage (through :class:`CortexClient`)
|
|
23
|
+
---------------------------------------------
|
|
24
|
+
```pycon
|
|
25
|
+
>>> emb = CortexClient().run(ModelType.C_RADIO, image_input=img)
|
|
26
|
+
>>> emb.shape
|
|
27
|
+
(2304,)
|
|
28
|
+
>>> float(np.linalg.norm(emb))
|
|
29
|
+
1.0
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Args (for :py:meth:`run`)
|
|
33
|
+
------------------------
|
|
34
|
+
image_input: RGB image (path, URL, ``PIL.Image`` or ``np.ndarray``).
|
|
35
|
+
|
|
36
|
+
Returns
|
|
37
|
+
-------
|
|
38
|
+
np.ndarray
|
|
39
|
+
L2-normalized embedding vector (``float32``, 1-D). Cosine similarity
|
|
40
|
+
between two outputs is a plain ``a @ b``.
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
name: str = "c-radio"
|
|
44
|
+
model_id: str = "c-radio"
|
|
45
|
+
|
|
46
|
+
def __init__(self, *, transport=None) -> None:
|
|
47
|
+
"""Create a C-RADIO wrapper.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
transport: Optional shared HTTP transport injected by
|
|
51
|
+
:class:`~grid_cortex_client.CortexClient`.
|
|
52
|
+
"""
|
|
53
|
+
super().__init__(transport=transport)
|
|
54
|
+
|
|
55
|
+
# ------------------------------------------------------------------
|
|
56
|
+
# BaseModel interface
|
|
57
|
+
# ------------------------------------------------------------------
|
|
58
|
+
|
|
59
|
+
def preprocess(
|
|
60
|
+
self,
|
|
61
|
+
*,
|
|
62
|
+
image_input: Union[str, Image.Image, np.ndarray],
|
|
63
|
+
) -> Dict[str, Any]:
|
|
64
|
+
"""Return msgpack-ready payload with raw JPEG image bytes."""
|
|
65
|
+
pil_img = load_image(image_input)
|
|
66
|
+
return {"image_input": image_to_bytes(pil_img, encoding_format="JPEG")}
|
|
67
|
+
|
|
68
|
+
def postprocess(
|
|
69
|
+
self,
|
|
70
|
+
response_data: Dict[str, Any],
|
|
71
|
+
**_: Any,
|
|
72
|
+
) -> np.ndarray:
|
|
73
|
+
"""Decode backend response into an L2-normalized embedding array.
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
response_data: Backend dict (or list-wrapped dict) containing an
|
|
77
|
+
``"output"`` key holding ``.npy`` bytes for a 1-D float vector.
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
np.ndarray of shape ``(D,)``, dtype ``float32``, L2-normalized.
|
|
81
|
+
|
|
82
|
+
Raises:
|
|
83
|
+
ValueError: If the payload is missing or cannot be decoded.
|
|
84
|
+
"""
|
|
85
|
+
if isinstance(response_data, list):
|
|
86
|
+
response_dict = response_data[0]
|
|
87
|
+
else:
|
|
88
|
+
response_dict = response_data
|
|
89
|
+
|
|
90
|
+
emb_bytes = response_dict.get("output")
|
|
91
|
+
if not isinstance(emb_bytes, (bytes, bytearray, memoryview)):
|
|
92
|
+
raise ValueError("'output' field missing or not bytes")
|
|
93
|
+
|
|
94
|
+
arr = np.load(BytesIO(emb_bytes), allow_pickle=False)
|
|
95
|
+
return arr.astype(np.float32)
|
|
96
|
+
|
|
97
|
+
def run(
|
|
98
|
+
self,
|
|
99
|
+
image_input: Union[str, Image.Image, np.ndarray],
|
|
100
|
+
timeout: float | None = None,
|
|
101
|
+
) -> np.ndarray:
|
|
102
|
+
"""Compute an L2-normalized embedding for a single RGB image.
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
image_input: RGB image as file path, URL, PIL Image, or numpy array.
|
|
106
|
+
timeout: Optional timeout in seconds for the HTTP request.
|
|
107
|
+
|
|
108
|
+
Returns:
|
|
109
|
+
Embedding as numpy array of shape ``(D,)``, dtype ``float32``,
|
|
110
|
+
L2-normalized so dot products give cosine similarity directly.
|
|
111
|
+
|
|
112
|
+
Raises:
|
|
113
|
+
ValueError: If image cannot be loaded.
|
|
114
|
+
RuntimeError: If no HTTP transport is configured.
|
|
115
|
+
Exception: If the HTTP request fails.
|
|
116
|
+
|
|
117
|
+
Example:
|
|
118
|
+
>>> from grid_cortex_client import CortexClient, ModelType
|
|
119
|
+
>>> import numpy as np
|
|
120
|
+
>>> from PIL import Image
|
|
121
|
+
>>> client = CortexClient()
|
|
122
|
+
>>> image = np.array(Image.open("cat.jpg"))
|
|
123
|
+
>>> emb = client.run(ModelType.C_RADIO, image_input=image)
|
|
124
|
+
>>> print(emb.shape, float(np.linalg.norm(emb))) # (D,) 1.0
|
|
125
|
+
"""
|
|
126
|
+
return super().run(
|
|
127
|
+
image_input=image_input,
|
|
128
|
+
timeout=timeout,
|
|
129
|
+
)
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"""Test C-RADIO model."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import time
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
import pytest
|
|
8
|
+
|
|
9
|
+
from grid_cortex_client import AsyncCortexClient, CortexClient, CortexHubClient, ModelType
|
|
10
|
+
from grid_cortex_client.client import CortexAPIError
|
|
11
|
+
|
|
12
|
+
from .conftest import BaseModelTestHTTP, run_concurrent_requests, is_gpu_mem_close
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class TestCRadioHTTP(BaseModelTestHTTP):
|
|
16
|
+
"""HTTP-based tests for C-RADIO dense visual embedding model."""
|
|
17
|
+
|
|
18
|
+
@property
|
|
19
|
+
def batch_size(self) -> int:
|
|
20
|
+
"""C-RADIO model batch size (matches `max_ongoing_requests` in config.yaml)."""
|
|
21
|
+
return 8
|
|
22
|
+
|
|
23
|
+
@property
|
|
24
|
+
def gpu_mem(self) -> float:
|
|
25
|
+
"""C-RADIO model GPU memory budget (MB, matches config.yaml `gpu_mem`)."""
|
|
26
|
+
return 2000.0
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
def max_input_size(self) -> tuple:
|
|
30
|
+
"""C-RADIO model maximum input size (width, height)."""
|
|
31
|
+
return (720, 1280)
|
|
32
|
+
|
|
33
|
+
def test_basic_inference(self, client: CortexClient, rgb_image_np: np.ndarray):
|
|
34
|
+
"""Test basic embedding extraction with valid input."""
|
|
35
|
+
emb = client.run(ModelType.C_RADIO, image_input=rgb_image_np)
|
|
36
|
+
|
|
37
|
+
assert emb is not None
|
|
38
|
+
assert isinstance(emb, np.ndarray)
|
|
39
|
+
assert emb.ndim == 1, f"emb.ndim {emb.ndim} != 1"
|
|
40
|
+
assert emb.shape[0] == 2304, f"emb dim {emb.shape[0]} != 2304 (C-RADIOv4-SO400M summary)"
|
|
41
|
+
assert emb.dtype == np.float32, f"emb.dtype {emb.dtype} != float32"
|
|
42
|
+
assert np.isfinite(emb).all(), "embedding contains NaN/Inf"
|
|
43
|
+
# L2-normalized → magnitude should be 1.0 within float32 tolerance.
|
|
44
|
+
norm = float(np.linalg.norm(emb))
|
|
45
|
+
assert abs(norm - 1.0) < 1e-3, f"embedding not L2-normalized (||emb|| = {norm})"
|
|
46
|
+
|
|
47
|
+
def test_image_input_list_rejected(self, client: CortexClient, rgb_image_np: np.ndarray):
|
|
48
|
+
"""List image_input is rejected — at the client (TypeError) or server (422)."""
|
|
49
|
+
with pytest.raises((TypeError, CortexAPIError)):
|
|
50
|
+
client.run(ModelType.C_RADIO, image_input=[rgb_image_np, rgb_image_np])
|
|
51
|
+
|
|
52
|
+
def test_maximum_payload_size(self, client: CortexClient):
|
|
53
|
+
"""Test that inference works with maximum allowed payload size."""
|
|
54
|
+
large_image = np.random.randint(0, 255, (*self.max_input_size, 3), dtype=np.uint8)
|
|
55
|
+
emb = client.run(ModelType.C_RADIO, image_input=large_image)
|
|
56
|
+
|
|
57
|
+
assert emb is not None
|
|
58
|
+
assert isinstance(emb, np.ndarray)
|
|
59
|
+
assert emb.ndim == 1
|
|
60
|
+
|
|
61
|
+
oversized_image = np.random.randint(0, 255, (4096, 4096, 3), dtype=np.uint8)
|
|
62
|
+
with pytest.raises(CortexAPIError) as exc_info:
|
|
63
|
+
client.run(ModelType.C_RADIO, image_input=oversized_image)
|
|
64
|
+
assert exc_info.value.status_code == 413
|
|
65
|
+
|
|
66
|
+
large_image = np.random.randint(0, 255, (*self.max_input_size, 3), dtype=np.uint8)
|
|
67
|
+
emb = client.run(ModelType.C_RADIO, image_input=large_image)
|
|
68
|
+
|
|
69
|
+
assert emb is not None
|
|
70
|
+
assert isinstance(emb, np.ndarray)
|
|
71
|
+
assert emb.ndim == 1
|
|
72
|
+
|
|
73
|
+
def test_inference_latency(self, client: CortexClient, rgb_image_np: np.ndarray):
|
|
74
|
+
"""Test that inference latency is within acceptable range."""
|
|
75
|
+
start_time = time.time()
|
|
76
|
+
emb = client.run(ModelType.C_RADIO, image_input=rgb_image_np)
|
|
77
|
+
elapsed_time = time.time() - start_time
|
|
78
|
+
|
|
79
|
+
assert emb is not None
|
|
80
|
+
assert elapsed_time < 10.0, f"Inference took {elapsed_time:.2f}s, expected < 10s"
|
|
81
|
+
|
|
82
|
+
@pytest.mark.asyncio
|
|
83
|
+
async def test_concurrent_requests(self, async_client: AsyncCortexClient, rgb_image_np: np.ndarray):
|
|
84
|
+
"""Test that multiple concurrent requests are handled correctly."""
|
|
85
|
+
|
|
86
|
+
async def make_request():
|
|
87
|
+
return await async_client.run(ModelType.C_RADIO, image_input=rgb_image_np)
|
|
88
|
+
|
|
89
|
+
results = await run_concurrent_requests(make_request, num_requests=self.batch_size)
|
|
90
|
+
|
|
91
|
+
assert len(results) == self.batch_size
|
|
92
|
+
assert all(not isinstance(r, Exception) for r in results)
|
|
93
|
+
assert all(isinstance(r, np.ndarray) for r in results)
|
|
94
|
+
assert all(r.ndim == 1 for r in results)
|
|
95
|
+
|
|
96
|
+
@pytest.mark.asyncio
|
|
97
|
+
async def test_gpu_memory_usage(self, async_client: AsyncCortexClient, rgb_image_np: np.ndarray):
|
|
98
|
+
"""Test that GPU memory usage is within expected limits during inference."""
|
|
99
|
+
large_image = np.random.randint(0, 255, (*self.max_input_size, 3), dtype=np.uint8)
|
|
100
|
+
|
|
101
|
+
async def make_request():
|
|
102
|
+
return await async_client.run(ModelType.C_RADIO, image_input=large_image, raw_response=True)
|
|
103
|
+
|
|
104
|
+
results = await run_concurrent_requests(make_request, num_requests=self.batch_size)
|
|
105
|
+
|
|
106
|
+
assert len(results) == self.batch_size
|
|
107
|
+
assert all(not isinstance(r, Exception) for r in results)
|
|
108
|
+
assert all(is_gpu_mem_close(self.gpu_mem, result["gpu_stats"]["mem_usage_mb"]) for result in results), (
|
|
109
|
+
f"GPU memory peak too high: {[result['gpu_stats']['mem_usage_mb'] for result in results]} MB"
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
@pytest.mark.asyncio
|
|
113
|
+
async def test_cortex_hub(self, rgb_image_np: np.ndarray):
|
|
114
|
+
"""Test C-RADIO inference via CortexHubClient (WebSocket)."""
|
|
115
|
+
api_key = os.getenv("GRID_CORTEX_API_KEY") or os.getenv("CORTEX_API_KEY")
|
|
116
|
+
if not api_key:
|
|
117
|
+
pytest.skip("GRID_CORTEX_API_KEY or CORTEX_API_KEY not set")
|
|
118
|
+
|
|
119
|
+
async with CortexHubClient(api_key=api_key) as hub:
|
|
120
|
+
emb = await hub.run(ModelType.C_RADIO, image_input=rgb_image_np)
|
|
121
|
+
|
|
122
|
+
assert emb is not None
|
|
123
|
+
assert isinstance(emb, np.ndarray)
|
|
124
|
+
assert emb.ndim == 1
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/cortex_client.py
RENAMED
|
File without changes
|
{grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/cortex_hub_client.py
RENAMED
|
File without changes
|
{grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/models/__init__.py
RENAMED
|
File without changes
|
{grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/models/base_model.py
RENAMED
|
File without changes
|
|
File without changes
|
{grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/models/da3metric.py
RENAMED
|
File without changes
|
|
File without changes
|
{grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/models/finetune_pi05.py
RENAMED
|
File without changes
|
|
File without changes
|
{grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/models/graspgen.py
RENAMED
|
File without changes
|
{grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/models/graspgenx.py
RENAMED
|
File without changes
|
{grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/models/gsam2.py
RENAMED
|
File without changes
|
|
File without changes
|
{grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/models/metric3d.py
RENAMED
|
File without changes
|
{grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/models/moondream.py
RENAMED
|
File without changes
|
{grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/models/oneformer.py
RENAMED
|
File without changes
|
{grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/models/owlv2.py
RENAMED
|
File without changes
|
|
File without changes
|
{grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/models/qwen_vl.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/models/zoedepth.py
RENAMED
|
File without changes
|
{grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/preprocessing.py
RENAMED
|
File without changes
|
{grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/tools/__init__.py
RENAMED
|
File without changes
|
{grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/tools/generate_enum.py
RENAMED
|
File without changes
|
{grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/src/grid_cortex_client/tools/registry.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{grid_cortex_client-0.5.1 → grid_cortex_client-0.6.0}/tests/test_ur5e_pyroki_collision_batch.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|