dragoneye-python 0.4.0__tar.gz → 0.5.1__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.
- {dragoneye_python-0.4.0 → dragoneye_python-0.5.1}/PKG-INFO +1 -1
- {dragoneye_python-0.4.0 → dragoneye_python-0.5.1}/dragoneye_python.egg-info/PKG-INFO +1 -1
- {dragoneye_python-0.4.0 → dragoneye_python-0.5.1}/pyproject.toml +2 -2
- dragoneye_python-0.5.1/src/dragoneye/__init__.py +32 -0
- {dragoneye_python-0.4.0 → dragoneye_python-0.5.1}/src/dragoneye/classification.py +15 -1
- {dragoneye_python-0.4.0 → dragoneye_python-0.5.1}/src/dragoneye/models.py +26 -11
- dragoneye_python-0.5.1/src/dragoneye/types/common.py +12 -0
- {dragoneye_python-0.4.0 → dragoneye_python-0.5.1}/src/dragoneye/types/media.py +35 -10
- dragoneye_python-0.4.0/src/dragoneye/__init__.py +0 -25
- dragoneye_python-0.4.0/src/dragoneye/types/common.py +0 -31
- {dragoneye_python-0.4.0 → dragoneye_python-0.5.1}/README.md +0 -0
- {dragoneye_python-0.4.0 → dragoneye_python-0.5.1}/dragoneye_python.egg-info/SOURCES.txt +0 -0
- {dragoneye_python-0.4.0 → dragoneye_python-0.5.1}/dragoneye_python.egg-info/dependency_links.txt +0 -0
- {dragoneye_python-0.4.0 → dragoneye_python-0.5.1}/dragoneye_python.egg-info/requires.txt +0 -0
- {dragoneye_python-0.4.0 → dragoneye_python-0.5.1}/dragoneye_python.egg-info/top_level.txt +0 -0
- {dragoneye_python-0.4.0 → dragoneye_python-0.5.1}/requirements.txt +0 -0
- {dragoneye_python-0.4.0 → dragoneye_python-0.5.1}/setup.cfg +0 -0
- {dragoneye_python-0.4.0 → dragoneye_python-0.5.1}/src/dragoneye/client.py +0 -0
- {dragoneye_python-0.4.0 → dragoneye_python-0.5.1}/src/dragoneye/constants.py +0 -0
- {dragoneye_python-0.4.0 → dragoneye_python-0.5.1}/src/dragoneye/types/__init__.py +0 -0
- {dragoneye_python-0.4.0 → dragoneye_python-0.5.1}/src/dragoneye/types/exception.py +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "dragoneye-python"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.5.1"
|
|
8
8
|
requires-python = ">=3.8"
|
|
9
9
|
dynamic = ["dependencies"]
|
|
10
10
|
license = "MIT"
|
|
@@ -13,4 +13,4 @@ license = "MIT"
|
|
|
13
13
|
dependencies = {file = ["requirements.txt"]}
|
|
14
14
|
|
|
15
15
|
[tool.setuptools.package-dir]
|
|
16
|
-
dragoneye = "src/dragoneye"
|
|
16
|
+
dragoneye = "src/dragoneye"
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from .classification import (
|
|
2
|
+
Classification,
|
|
3
|
+
)
|
|
4
|
+
from .client import Dragoneye
|
|
5
|
+
from .models import (
|
|
6
|
+
ClassificationAttributeOption,
|
|
7
|
+
ClassificationAttributeResponse,
|
|
8
|
+
ClassificationCategory,
|
|
9
|
+
ClassificationCategoryPrediction,
|
|
10
|
+
ClassificationObjectPrediction,
|
|
11
|
+
ClassificationPredictImageResponse,
|
|
12
|
+
ClassificationPredictVideoResponse,
|
|
13
|
+
ClassificationVideoObjectPrediction,
|
|
14
|
+
)
|
|
15
|
+
from .types.common import NormalizedBbox
|
|
16
|
+
from .types.media import Image, Video
|
|
17
|
+
|
|
18
|
+
__all__ = [
|
|
19
|
+
"Classification",
|
|
20
|
+
"ClassificationAttributeOption",
|
|
21
|
+
"ClassificationAttributeResponse",
|
|
22
|
+
"ClassificationCategory",
|
|
23
|
+
"ClassificationCategoryPrediction",
|
|
24
|
+
"ClassificationObjectPrediction",
|
|
25
|
+
"ClassificationPredictImageResponse",
|
|
26
|
+
"ClassificationPredictVideoResponse",
|
|
27
|
+
"ClassificationVideoObjectPrediction",
|
|
28
|
+
"Dragoneye",
|
|
29
|
+
"Image",
|
|
30
|
+
"NormalizedBbox",
|
|
31
|
+
"Video",
|
|
32
|
+
]
|
|
@@ -97,12 +97,14 @@ class Classification:
|
|
|
97
97
|
media: Image,
|
|
98
98
|
model_name: str,
|
|
99
99
|
timeout_seconds: Optional[int] = None,
|
|
100
|
+
**kwargs: Any,
|
|
100
101
|
) -> ClassificationPredictImageResponse:
|
|
101
102
|
return await self._predict_unified(
|
|
102
103
|
media=media,
|
|
103
104
|
model_name=model_name,
|
|
104
105
|
frames_per_second=None,
|
|
105
106
|
timeout_seconds=timeout_seconds,
|
|
107
|
+
**kwargs,
|
|
106
108
|
)
|
|
107
109
|
|
|
108
110
|
async def predict_video(
|
|
@@ -111,12 +113,14 @@ class Classification:
|
|
|
111
113
|
model_name: str,
|
|
112
114
|
frames_per_second: int = 1,
|
|
113
115
|
timeout_seconds: Optional[int] = None,
|
|
116
|
+
**kwargs: Any,
|
|
114
117
|
) -> ClassificationPredictVideoResponse:
|
|
115
118
|
return await self._predict_unified(
|
|
116
119
|
media=media,
|
|
117
120
|
model_name=model_name,
|
|
118
121
|
frames_per_second=frames_per_second,
|
|
119
122
|
timeout_seconds=timeout_seconds,
|
|
123
|
+
**kwargs,
|
|
120
124
|
)
|
|
121
125
|
|
|
122
126
|
async def status(
|
|
@@ -219,6 +223,7 @@ class Classification:
|
|
|
219
223
|
model_name: str,
|
|
220
224
|
frames_per_second: Optional[int],
|
|
221
225
|
timeout_seconds: Optional[int] = None,
|
|
226
|
+
**kwargs: Any,
|
|
222
227
|
) -> ClassificationPredictImageResponse: ...
|
|
223
228
|
|
|
224
229
|
@overload
|
|
@@ -228,6 +233,7 @@ class Classification:
|
|
|
228
233
|
model_name: str,
|
|
229
234
|
frames_per_second: Optional[int],
|
|
230
235
|
timeout_seconds: Optional[int] = None,
|
|
236
|
+
**kwargs: Any,
|
|
231
237
|
) -> ClassificationPredictVideoResponse: ...
|
|
232
238
|
|
|
233
239
|
async def _predict_unified(
|
|
@@ -236,10 +242,12 @@ class Classification:
|
|
|
236
242
|
model_name: str,
|
|
237
243
|
frames_per_second: Optional[int],
|
|
238
244
|
timeout_seconds: Optional[int] = None,
|
|
245
|
+
**kwargs: Any,
|
|
239
246
|
) -> Union[ClassificationPredictImageResponse, ClassificationPredictVideoResponse]:
|
|
240
247
|
prediction_task_begin_response = await self._begin_prediction_task(
|
|
241
248
|
mime_type=media.mime_type,
|
|
242
249
|
frames_per_second=frames_per_second,
|
|
250
|
+
file_name=media.name,
|
|
243
251
|
)
|
|
244
252
|
|
|
245
253
|
await self._upload_media_to_prediction_task(
|
|
@@ -247,9 +255,10 @@ class Classification:
|
|
|
247
255
|
)
|
|
248
256
|
|
|
249
257
|
predict_url = f"{BASE_API_URL}/predict"
|
|
250
|
-
predict_data = {
|
|
258
|
+
predict_data: dict[str, Any] = {
|
|
251
259
|
"model_name": model_name,
|
|
252
260
|
"prediction_task_uuid": prediction_task_begin_response.prediction_task_uuid,
|
|
261
|
+
**kwargs,
|
|
253
262
|
}
|
|
254
263
|
predict_headers = {
|
|
255
264
|
"Authorization": f"Bearer {self._client.api_key}",
|
|
@@ -339,11 +348,16 @@ class Classification:
|
|
|
339
348
|
self,
|
|
340
349
|
mime_type: str,
|
|
341
350
|
frames_per_second: Optional[int],
|
|
351
|
+
file_name: Optional[str],
|
|
342
352
|
) -> _PredictionTaskBeginResponse:
|
|
343
353
|
url = f"{BASE_API_URL}/prediction-task/begin"
|
|
344
354
|
|
|
345
355
|
form_data = aiohttp.FormData()
|
|
346
356
|
form_data.add_field("mimetype", mime_type)
|
|
357
|
+
form_data.add_field("response_version", "object")
|
|
358
|
+
if file_name is not None:
|
|
359
|
+
form_data.add_field("file_name", file_name)
|
|
360
|
+
|
|
347
361
|
if frames_per_second is not None:
|
|
348
362
|
form_data.add_field("frames_per_second", str(frames_per_second))
|
|
349
363
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import Dict,
|
|
1
|
+
from typing import Dict, List, Optional
|
|
2
2
|
|
|
3
3
|
from pydantic import BaseModel
|
|
4
4
|
|
|
@@ -7,8 +7,6 @@ from dragoneye.types.common import (
|
|
|
7
7
|
PredictionTaskState,
|
|
8
8
|
PredictionTaskUUID,
|
|
9
9
|
PredictionType,
|
|
10
|
-
TaxonID,
|
|
11
|
-
TaxonPrediction,
|
|
12
10
|
)
|
|
13
11
|
|
|
14
12
|
|
|
@@ -18,22 +16,38 @@ class PredictionTaskStatusResponse(BaseModel):
|
|
|
18
16
|
status: PredictionTaskState
|
|
19
17
|
|
|
20
18
|
|
|
21
|
-
class
|
|
22
|
-
|
|
19
|
+
class ClassificationAttributeOption(BaseModel):
|
|
20
|
+
option_id: int
|
|
23
21
|
name: str
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
score: float
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class ClassificationAttributeResponse(BaseModel):
|
|
26
|
+
attribute_id: int
|
|
27
|
+
name: str
|
|
28
|
+
options: List[ClassificationAttributeOption]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class ClassificationCategory(BaseModel):
|
|
32
|
+
id: int
|
|
33
|
+
name: str
|
|
34
|
+
score: float
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class ClassificationCategoryPrediction(BaseModel):
|
|
38
|
+
category: ClassificationCategory
|
|
39
|
+
attributes: List[ClassificationAttributeResponse]
|
|
26
40
|
|
|
27
41
|
|
|
28
42
|
class ClassificationObjectPrediction(BaseModel):
|
|
29
43
|
normalizedBbox: NormalizedBbox
|
|
30
|
-
|
|
31
|
-
traits: Sequence[ClassificationTraitRootPrediction]
|
|
44
|
+
predictions: List[ClassificationCategoryPrediction]
|
|
32
45
|
|
|
33
46
|
|
|
34
47
|
class ClassificationPredictImageResponse(BaseModel):
|
|
35
|
-
|
|
48
|
+
object_predictions: List[ClassificationObjectPrediction]
|
|
36
49
|
prediction_task_uuid: PredictionTaskUUID
|
|
50
|
+
original_file_name: Optional[str]
|
|
37
51
|
|
|
38
52
|
|
|
39
53
|
class ClassificationVideoObjectPrediction(ClassificationObjectPrediction):
|
|
@@ -43,7 +57,8 @@ class ClassificationVideoObjectPrediction(ClassificationObjectPrediction):
|
|
|
43
57
|
|
|
44
58
|
class ClassificationPredictVideoResponse(BaseModel):
|
|
45
59
|
timestamp_us_to_predictions: Dict[
|
|
46
|
-
int,
|
|
60
|
+
int, List[ClassificationVideoObjectPrediction]
|
|
47
61
|
]
|
|
48
62
|
frames_per_second: int
|
|
49
63
|
prediction_task_uuid: PredictionTaskUUID
|
|
64
|
+
original_file_name: Optional[str]
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from typing import Literal, NewType, Tuple
|
|
2
|
+
|
|
3
|
+
PredictionType = Literal["image", "video"]
|
|
4
|
+
PredictionTaskState = NewType("PredictionTaskState", str)
|
|
5
|
+
|
|
6
|
+
NormalizedBbox = NewType("NormalizedBbox", Tuple[float, float, float, float])
|
|
7
|
+
|
|
8
|
+
PredictionTaskUUID = NewType("PredictionTaskUUID", str)
|
|
9
|
+
|
|
10
|
+
TimestampUs = NewType("TimestampUs", int)
|
|
11
|
+
|
|
12
|
+
BASE_API_URL = "https://api.dragoneye.ai"
|
|
@@ -15,6 +15,7 @@ class Media:
|
|
|
15
15
|
"""Generic binary media + mime_type with conservative, non-destructive access."""
|
|
16
16
|
|
|
17
17
|
file_or_bytes: Union[bytes, BytesIO, BinaryIO, BufferedReader]
|
|
18
|
+
name: Optional[str]
|
|
18
19
|
mime_type: str
|
|
19
20
|
|
|
20
21
|
# Subclasses set this to enforce a family of mimetypes, e.g. ("image/",)
|
|
@@ -33,16 +34,33 @@ class Media:
|
|
|
33
34
|
# ---------- Convenience constructors ----------
|
|
34
35
|
|
|
35
36
|
@classmethod
|
|
36
|
-
def from_bytes(
|
|
37
|
-
|
|
37
|
+
def from_bytes(
|
|
38
|
+
cls, data: bytes, mime_type: str, name: Optional[str] = None
|
|
39
|
+
) -> Self:
|
|
40
|
+
"""
|
|
41
|
+
Create a Media (or subclass) from raw bytes.
|
|
42
|
+
|
|
43
|
+
- `data`: Raw bytes of the media content.
|
|
44
|
+
- `mime_type`: The MIME type of the media (e.g., 'image/jpeg').
|
|
45
|
+
- `name`: Optional non-unique descriptive identifier provided by the user
|
|
46
|
+
for identifying or tracking responses to inputs.
|
|
47
|
+
"""
|
|
48
|
+
return cls(file_or_bytes=data, mime_type=mime_type, name=name)
|
|
38
49
|
|
|
39
50
|
@classmethod
|
|
40
|
-
def from_stream(
|
|
51
|
+
def from_stream(
|
|
52
|
+
cls, stream: BinaryIO, *, mime_type: str, name: Optional[str] = None
|
|
53
|
+
) -> Self:
|
|
41
54
|
"""
|
|
42
55
|
Accepts any readable binary stream (e.g., open('file', 'rb')).
|
|
43
56
|
Keeps the stream as-is; reading is deferred to bytes_io().
|
|
57
|
+
|
|
58
|
+
- `stream`: A readable binary stream.
|
|
59
|
+
- `mime_type`: The MIME type of the media (e.g., 'image/jpeg').
|
|
60
|
+
- `name`: Optional non-unique descriptive identifier provided by the user
|
|
61
|
+
for identifying or tracking responses to inputs.
|
|
44
62
|
"""
|
|
45
|
-
return cls(file_or_bytes=stream, mime_type=mime_type)
|
|
63
|
+
return cls(file_or_bytes=stream, mime_type=mime_type, name=name)
|
|
46
64
|
|
|
47
65
|
@classmethod
|
|
48
66
|
def from_path(
|
|
@@ -50,6 +68,7 @@ class Media:
|
|
|
50
68
|
path: Union[str, os.PathLike[str]],
|
|
51
69
|
*,
|
|
52
70
|
mime_type: Optional[str] = None,
|
|
71
|
+
name: Optional[str] = None,
|
|
53
72
|
guess_from_extension: bool = True,
|
|
54
73
|
read_into_memory: bool = False,
|
|
55
74
|
) -> Self:
|
|
@@ -59,6 +78,9 @@ class Media:
|
|
|
59
78
|
- `path`: Path to the file on disk.
|
|
60
79
|
- `mime_type`: Explicit mime type. If omitted and `guess_from_extension=True`,
|
|
61
80
|
we'll try to guess from the file extension.
|
|
81
|
+
- `name`: Optional non-unique descriptive identifier provided by the user
|
|
82
|
+
for identifying or tracking responses to inputs. If not provided, will
|
|
83
|
+
default to the filename from the path.
|
|
62
84
|
- `read_into_memory=True`: load file bytes into memory (closes file immediately).
|
|
63
85
|
Otherwise, keep an open file stream.
|
|
64
86
|
"""
|
|
@@ -74,12 +96,15 @@ class Media:
|
|
|
74
96
|
f"mime_type is required for {path} (no extension-based guess available)."
|
|
75
97
|
)
|
|
76
98
|
|
|
99
|
+
# Use provided name or extract from path
|
|
100
|
+
media_name = name if name is not None else path.name
|
|
101
|
+
|
|
77
102
|
if read_into_memory:
|
|
78
103
|
data = path.read_bytes()
|
|
79
|
-
return cls(file_or_bytes=data, mime_type=mt)
|
|
104
|
+
return cls(file_or_bytes=data, mime_type=mt, name=media_name)
|
|
80
105
|
else:
|
|
81
106
|
f = path.open("rb")
|
|
82
|
-
return cls(file_or_bytes=f, mime_type=mt)
|
|
107
|
+
return cls(file_or_bytes=f, mime_type=mt, name=media_name)
|
|
83
108
|
|
|
84
109
|
# ---------- Utilities ----------
|
|
85
110
|
|
|
@@ -111,10 +136,10 @@ class Media:
|
|
|
111
136
|
|
|
112
137
|
# For any readable object with .read()
|
|
113
138
|
if hasattr(src, "read"):
|
|
114
|
-
pos = _tell_safe(src)
|
|
115
|
-
data = src.read()
|
|
116
|
-
_seek_safe(src, pos)
|
|
117
|
-
return BytesIO(data)
|
|
139
|
+
pos = _tell_safe(src) # pyright: ignore [reportArgumentType]
|
|
140
|
+
data = src.read() # pyright: ignore [reportUnknownMemberType, reportAttributeAccessIssue, reportUnknownVariableType]
|
|
141
|
+
_seek_safe(src, pos) # pyright: ignore [reportArgumentType]
|
|
142
|
+
return BytesIO(data) # pyright: ignore [reportUnknownArgumentType]
|
|
118
143
|
|
|
119
144
|
raise TypeError(
|
|
120
145
|
"Invalid media source: expected bytes, BytesIO, or a readable binary stream."
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
from .classification import (
|
|
2
|
-
Classification,
|
|
3
|
-
)
|
|
4
|
-
from .client import Dragoneye
|
|
5
|
-
from .models import (
|
|
6
|
-
ClassificationObjectPrediction,
|
|
7
|
-
ClassificationPredictImageResponse,
|
|
8
|
-
ClassificationTraitRootPrediction,
|
|
9
|
-
)
|
|
10
|
-
from .types.common import NormalizedBbox, TaxonID, TaxonPrediction, TaxonType
|
|
11
|
-
from .types.media import Image, Video
|
|
12
|
-
|
|
13
|
-
__all__ = [
|
|
14
|
-
"Classification",
|
|
15
|
-
"ClassificationObjectPrediction",
|
|
16
|
-
"ClassificationPredictImageResponse",
|
|
17
|
-
"ClassificationTraitRootPrediction",
|
|
18
|
-
"Dragoneye",
|
|
19
|
-
"Image",
|
|
20
|
-
"Video",
|
|
21
|
-
"NormalizedBbox",
|
|
22
|
-
"TaxonID",
|
|
23
|
-
"TaxonPrediction",
|
|
24
|
-
"TaxonType",
|
|
25
|
-
]
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
from enum import Enum
|
|
2
|
-
from typing import Literal, NewType, Optional, Sequence, Tuple
|
|
3
|
-
|
|
4
|
-
from pydantic import BaseModel
|
|
5
|
-
|
|
6
|
-
PredictionType = Literal["image", "video"]
|
|
7
|
-
PredictionTaskState = NewType("PredictionTaskState", str)
|
|
8
|
-
|
|
9
|
-
NormalizedBbox = NewType("NormalizedBbox", Tuple[float, float, float, float])
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class TaxonType(str, Enum):
|
|
13
|
-
CATEGORY = ("category",)
|
|
14
|
-
TRAIT = ("trait",)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
TaxonID = NewType("TaxonID", int)
|
|
18
|
-
|
|
19
|
-
PredictionTaskUUID = NewType("PredictionTaskUUID", str)
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
class TaxonPrediction(BaseModel):
|
|
23
|
-
id: TaxonID
|
|
24
|
-
type: TaxonType
|
|
25
|
-
name: str
|
|
26
|
-
displayName: str
|
|
27
|
-
score: Optional[float]
|
|
28
|
-
children: Sequence["TaxonPrediction"]
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
BASE_API_URL = "https://api.dragoneye.ai"
|
|
File without changes
|
|
File without changes
|
{dragoneye_python-0.4.0 → dragoneye_python-0.5.1}/dragoneye_python.egg-info/dependency_links.txt
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
|