hammad-python 0.0.30__py3-none-any.whl → 0.0.31__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.
- ham/__init__.py +10 -0
- {hammad_python-0.0.30.dist-info → hammad_python-0.0.31.dist-info}/METADATA +6 -32
- hammad_python-0.0.31.dist-info/RECORD +6 -0
- hammad/__init__.py +0 -84
- hammad/_internal.py +0 -256
- hammad/_main.py +0 -226
- hammad/cache/__init__.py +0 -40
- hammad/cache/base_cache.py +0 -181
- hammad/cache/cache.py +0 -169
- hammad/cache/decorators.py +0 -261
- hammad/cache/file_cache.py +0 -80
- hammad/cache/ttl_cache.py +0 -74
- hammad/cli/__init__.py +0 -33
- hammad/cli/animations.py +0 -573
- hammad/cli/plugins.py +0 -867
- hammad/cli/styles/__init__.py +0 -55
- hammad/cli/styles/settings.py +0 -139
- hammad/cli/styles/types.py +0 -358
- hammad/cli/styles/utils.py +0 -634
- hammad/data/__init__.py +0 -90
- hammad/data/collections/__init__.py +0 -49
- hammad/data/collections/collection.py +0 -326
- hammad/data/collections/indexes/__init__.py +0 -37
- hammad/data/collections/indexes/qdrant/__init__.py +0 -1
- hammad/data/collections/indexes/qdrant/index.py +0 -723
- hammad/data/collections/indexes/qdrant/settings.py +0 -94
- hammad/data/collections/indexes/qdrant/utils.py +0 -210
- hammad/data/collections/indexes/tantivy/__init__.py +0 -1
- hammad/data/collections/indexes/tantivy/index.py +0 -426
- hammad/data/collections/indexes/tantivy/settings.py +0 -40
- hammad/data/collections/indexes/tantivy/utils.py +0 -176
- hammad/data/configurations/__init__.py +0 -35
- hammad/data/configurations/configuration.py +0 -564
- hammad/data/models/__init__.py +0 -50
- hammad/data/models/extensions/__init__.py +0 -4
- hammad/data/models/extensions/pydantic/__init__.py +0 -42
- hammad/data/models/extensions/pydantic/converters.py +0 -759
- hammad/data/models/fields.py +0 -546
- hammad/data/models/model.py +0 -1078
- hammad/data/models/utils.py +0 -280
- hammad/data/sql/__init__.py +0 -24
- hammad/data/sql/database.py +0 -576
- hammad/data/sql/types.py +0 -127
- hammad/data/types/__init__.py +0 -75
- hammad/data/types/file.py +0 -431
- hammad/data/types/multimodal/__init__.py +0 -36
- hammad/data/types/multimodal/audio.py +0 -200
- hammad/data/types/multimodal/image.py +0 -182
- hammad/data/types/text.py +0 -1308
- hammad/formatting/__init__.py +0 -33
- hammad/formatting/json/__init__.py +0 -27
- hammad/formatting/json/converters.py +0 -158
- hammad/formatting/text/__init__.py +0 -63
- hammad/formatting/text/converters.py +0 -723
- hammad/formatting/text/markdown.py +0 -131
- hammad/formatting/yaml/__init__.py +0 -26
- hammad/formatting/yaml/converters.py +0 -5
- hammad/genai/__init__.py +0 -217
- hammad/genai/a2a/__init__.py +0 -32
- hammad/genai/a2a/workers.py +0 -552
- hammad/genai/agents/__init__.py +0 -59
- hammad/genai/agents/agent.py +0 -1973
- hammad/genai/agents/run.py +0 -1024
- hammad/genai/agents/types/__init__.py +0 -42
- hammad/genai/agents/types/agent_context.py +0 -13
- hammad/genai/agents/types/agent_event.py +0 -128
- hammad/genai/agents/types/agent_hooks.py +0 -220
- hammad/genai/agents/types/agent_messages.py +0 -31
- hammad/genai/agents/types/agent_response.py +0 -125
- hammad/genai/agents/types/agent_stream.py +0 -327
- hammad/genai/graphs/__init__.py +0 -125
- hammad/genai/graphs/_utils.py +0 -190
- hammad/genai/graphs/base.py +0 -1828
- hammad/genai/graphs/plugins.py +0 -316
- hammad/genai/graphs/types.py +0 -638
- hammad/genai/models/__init__.py +0 -1
- hammad/genai/models/embeddings/__init__.py +0 -43
- hammad/genai/models/embeddings/model.py +0 -226
- hammad/genai/models/embeddings/run.py +0 -163
- hammad/genai/models/embeddings/types/__init__.py +0 -37
- hammad/genai/models/embeddings/types/embedding_model_name.py +0 -75
- hammad/genai/models/embeddings/types/embedding_model_response.py +0 -76
- hammad/genai/models/embeddings/types/embedding_model_run_params.py +0 -66
- hammad/genai/models/embeddings/types/embedding_model_settings.py +0 -47
- hammad/genai/models/language/__init__.py +0 -57
- hammad/genai/models/language/model.py +0 -1098
- hammad/genai/models/language/run.py +0 -878
- hammad/genai/models/language/types/__init__.py +0 -40
- hammad/genai/models/language/types/language_model_instructor_mode.py +0 -47
- hammad/genai/models/language/types/language_model_messages.py +0 -28
- hammad/genai/models/language/types/language_model_name.py +0 -239
- hammad/genai/models/language/types/language_model_request.py +0 -127
- hammad/genai/models/language/types/language_model_response.py +0 -217
- hammad/genai/models/language/types/language_model_response_chunk.py +0 -56
- hammad/genai/models/language/types/language_model_settings.py +0 -89
- hammad/genai/models/language/types/language_model_stream.py +0 -600
- hammad/genai/models/language/utils/__init__.py +0 -28
- hammad/genai/models/language/utils/requests.py +0 -421
- hammad/genai/models/language/utils/structured_outputs.py +0 -135
- hammad/genai/models/model_provider.py +0 -4
- hammad/genai/models/multimodal.py +0 -47
- hammad/genai/models/reranking.py +0 -26
- hammad/genai/types/__init__.py +0 -1
- hammad/genai/types/base.py +0 -215
- hammad/genai/types/history.py +0 -290
- hammad/genai/types/tools.py +0 -507
- hammad/logging/__init__.py +0 -35
- hammad/logging/decorators.py +0 -834
- hammad/logging/logger.py +0 -1018
- hammad/mcp/__init__.py +0 -53
- hammad/mcp/client/__init__.py +0 -35
- hammad/mcp/client/client.py +0 -624
- hammad/mcp/client/client_service.py +0 -400
- hammad/mcp/client/settings.py +0 -178
- hammad/mcp/servers/__init__.py +0 -26
- hammad/mcp/servers/launcher.py +0 -1161
- hammad/runtime/__init__.py +0 -32
- hammad/runtime/decorators.py +0 -142
- hammad/runtime/run.py +0 -299
- hammad/service/__init__.py +0 -49
- hammad/service/create.py +0 -527
- hammad/service/decorators.py +0 -283
- hammad/types.py +0 -288
- hammad/typing/__init__.py +0 -435
- hammad/web/__init__.py +0 -43
- hammad/web/http/__init__.py +0 -1
- hammad/web/http/client.py +0 -944
- hammad/web/models.py +0 -275
- hammad/web/openapi/__init__.py +0 -1
- hammad/web/openapi/client.py +0 -740
- hammad/web/search/__init__.py +0 -1
- hammad/web/search/client.py +0 -1023
- hammad/web/utils.py +0 -472
- hammad_python-0.0.30.dist-info/RECORD +0 -135
- {hammad → ham}/py.typed +0 -0
- {hammad_python-0.0.30.dist-info → hammad_python-0.0.31.dist-info}/WHEEL +0 -0
- {hammad_python-0.0.30.dist-info → hammad_python-0.0.31.dist-info}/licenses/LICENSE +0 -0
@@ -1,200 +0,0 @@
|
|
1
|
-
"""hammad.data.types.multimodal.audio"""
|
2
|
-
|
3
|
-
import httpx
|
4
|
-
import mimetypes
|
5
|
-
from pathlib import Path
|
6
|
-
from typing import Self
|
7
|
-
|
8
|
-
from ...types.file import File, FileSource, _FILE_SIGNATURES
|
9
|
-
from ...models.fields import field
|
10
|
-
|
11
|
-
|
12
|
-
__all__ = (
|
13
|
-
"Audio",
|
14
|
-
"read_audio_from_path",
|
15
|
-
"read_audio_from_url",
|
16
|
-
)
|
17
|
-
|
18
|
-
|
19
|
-
class Audio(File):
|
20
|
-
"""A representation of an audio file, that is loadable from both a URL, file path
|
21
|
-
or bytes."""
|
22
|
-
|
23
|
-
# Audio-specific metadata
|
24
|
-
_duration: float | None = field(default=None)
|
25
|
-
_sample_rate: int | None = field(default=None)
|
26
|
-
_channels: int | None = field(default=None)
|
27
|
-
_format: str | None = field(default=None)
|
28
|
-
|
29
|
-
@property
|
30
|
-
def is_valid_audio(self) -> bool:
|
31
|
-
"""Check if this is a valid audio file based on MIME type."""
|
32
|
-
return self.type is not None and self.type.startswith("audio/")
|
33
|
-
|
34
|
-
@property
|
35
|
-
def format(self) -> str | None:
|
36
|
-
"""Get the audio format from MIME type."""
|
37
|
-
if self._format is None and self.type:
|
38
|
-
# Extract format from MIME type (e.g., 'audio/mp3' -> 'mp3')
|
39
|
-
self._format = self.type.split("/")[-1].upper()
|
40
|
-
return self._format
|
41
|
-
|
42
|
-
@property
|
43
|
-
def duration(self) -> float | None:
|
44
|
-
"""Get the duration of the audio file in seconds."""
|
45
|
-
return self._duration
|
46
|
-
|
47
|
-
@property
|
48
|
-
def sample_rate(self) -> int | None:
|
49
|
-
"""Get the sample rate of the audio file in Hz."""
|
50
|
-
return self._sample_rate
|
51
|
-
|
52
|
-
@property
|
53
|
-
def channels(self) -> int | None:
|
54
|
-
"""Get the number of channels in the audio file."""
|
55
|
-
return self._channels
|
56
|
-
|
57
|
-
@classmethod
|
58
|
-
def from_url(
|
59
|
-
cls,
|
60
|
-
url: str,
|
61
|
-
*,
|
62
|
-
lazy: bool = True,
|
63
|
-
timeout: float = 30.0,
|
64
|
-
) -> Self:
|
65
|
-
"""Download and create an audio file from a URL.
|
66
|
-
|
67
|
-
Args:
|
68
|
-
url: The URL to download from.
|
69
|
-
lazy: If True, defer loading content until needed.
|
70
|
-
timeout: Request timeout in seconds.
|
71
|
-
|
72
|
-
Returns:
|
73
|
-
A new Audio instance.
|
74
|
-
"""
|
75
|
-
data = None
|
76
|
-
size = None
|
77
|
-
type = None
|
78
|
-
|
79
|
-
if not lazy:
|
80
|
-
with httpx.Client(timeout=timeout) as client:
|
81
|
-
response = client.get(url)
|
82
|
-
response.raise_for_status()
|
83
|
-
|
84
|
-
data = response.content
|
85
|
-
size = len(data)
|
86
|
-
|
87
|
-
# Get content type
|
88
|
-
content_type = response.headers.get("content-type", "")
|
89
|
-
type = content_type.split(";")[0] if content_type else None
|
90
|
-
|
91
|
-
# Validate it's audio
|
92
|
-
if type and not type.startswith("audio/"):
|
93
|
-
raise ValueError(f"URL does not point to an audio file: {type}")
|
94
|
-
|
95
|
-
return cls(
|
96
|
-
data=data,
|
97
|
-
type=type,
|
98
|
-
source=FileSource(
|
99
|
-
is_url=True,
|
100
|
-
url=url,
|
101
|
-
size=size,
|
102
|
-
),
|
103
|
-
)
|
104
|
-
|
105
|
-
@classmethod
|
106
|
-
def from_path(
|
107
|
-
cls,
|
108
|
-
path: str | Path,
|
109
|
-
) -> Self:
|
110
|
-
"""Create an audio file from a file path.
|
111
|
-
|
112
|
-
Args:
|
113
|
-
path: The path to the audio file.
|
114
|
-
|
115
|
-
Returns:
|
116
|
-
A new Audio instance.
|
117
|
-
|
118
|
-
Raises:
|
119
|
-
FileNotFoundError: If the file does not exist.
|
120
|
-
ValueError: If the file is not a valid audio file.
|
121
|
-
"""
|
122
|
-
path_obj = Path(path)
|
123
|
-
|
124
|
-
if not path_obj.exists():
|
125
|
-
raise FileNotFoundError(f"Audio file not found: {path}")
|
126
|
-
|
127
|
-
if not path_obj.is_file():
|
128
|
-
raise ValueError(f"Path is not a file: {path}")
|
129
|
-
|
130
|
-
# Read file data
|
131
|
-
data = path_obj.read_bytes()
|
132
|
-
|
133
|
-
# Determine MIME type
|
134
|
-
type = None
|
135
|
-
|
136
|
-
# Check file signature first
|
137
|
-
for signature, mime_type in _FILE_SIGNATURES.items():
|
138
|
-
if data.startswith(signature) and mime_type.startswith("audio/"):
|
139
|
-
type = mime_type
|
140
|
-
break
|
141
|
-
|
142
|
-
# Fall back to mimetypes module
|
143
|
-
if not type:
|
144
|
-
type, _ = mimetypes.guess_type(str(path))
|
145
|
-
|
146
|
-
# Validate it's an audio file
|
147
|
-
if type and not type.startswith("audio/"):
|
148
|
-
raise ValueError(f"File is not an audio file: {type}")
|
149
|
-
|
150
|
-
return cls(
|
151
|
-
data=data,
|
152
|
-
type=type,
|
153
|
-
source=FileSource(
|
154
|
-
is_file=True,
|
155
|
-
path=path_obj,
|
156
|
-
size=len(data),
|
157
|
-
),
|
158
|
-
)
|
159
|
-
|
160
|
-
|
161
|
-
def read_audio_from_url(
|
162
|
-
url: str,
|
163
|
-
*,
|
164
|
-
lazy: bool = True,
|
165
|
-
timeout: float = 30.0,
|
166
|
-
) -> Audio:
|
167
|
-
"""Download and create an audio file from a URL.
|
168
|
-
|
169
|
-
Args:
|
170
|
-
url: The URL to download from.
|
171
|
-
lazy: If True, defer loading content until needed.
|
172
|
-
timeout: Request timeout in seconds.
|
173
|
-
|
174
|
-
Returns:
|
175
|
-
A new Audio instance.
|
176
|
-
|
177
|
-
Raises:
|
178
|
-
httpx.RequestError: If the request fails.
|
179
|
-
httpx.HTTPStatusError: If the response has an error status code.
|
180
|
-
ValueError: If the URL does not point to an audio file.
|
181
|
-
"""
|
182
|
-
return Audio.from_url(url, lazy=lazy, timeout=timeout)
|
183
|
-
|
184
|
-
|
185
|
-
def read_audio_from_path(
|
186
|
-
path: str | Path,
|
187
|
-
) -> Audio:
|
188
|
-
"""Create an audio file from a file path.
|
189
|
-
|
190
|
-
Args:
|
191
|
-
path: The path to the audio file.
|
192
|
-
|
193
|
-
Returns:
|
194
|
-
A new Audio instance.
|
195
|
-
|
196
|
-
Raises:
|
197
|
-
FileNotFoundError: If the file does not exist.
|
198
|
-
ValueError: If the file is not a valid audio file.
|
199
|
-
"""
|
200
|
-
return Audio.from_path(path)
|
@@ -1,182 +0,0 @@
|
|
1
|
-
"""hammad.data.types.multimodal.image"""
|
2
|
-
|
3
|
-
import httpx
|
4
|
-
import mimetypes
|
5
|
-
from pathlib import Path
|
6
|
-
from typing import Self
|
7
|
-
|
8
|
-
from ...types.file import File, FileSource, _FILE_SIGNATURES
|
9
|
-
from ...models.fields import field
|
10
|
-
|
11
|
-
|
12
|
-
__all__ = (
|
13
|
-
"Image",
|
14
|
-
"read_image_from_path",
|
15
|
-
"read_image_from_url",
|
16
|
-
)
|
17
|
-
|
18
|
-
|
19
|
-
class Image(File):
|
20
|
-
"""A representation of an image, that is loadable from both a URL, file path
|
21
|
-
or bytes."""
|
22
|
-
|
23
|
-
# Image-specific metadata
|
24
|
-
_width: int | None = field(default=None)
|
25
|
-
_height: int | None = field(default=None)
|
26
|
-
_format: str | None = field(default=None)
|
27
|
-
|
28
|
-
@property
|
29
|
-
def is_valid_image(self) -> bool:
|
30
|
-
"""Check if this is a valid image based on MIME type."""
|
31
|
-
return self.type is not None and self.type.startswith("image/")
|
32
|
-
|
33
|
-
@property
|
34
|
-
def format(self) -> str | None:
|
35
|
-
"""Get the image format from MIME type."""
|
36
|
-
if self._format is None and self.type:
|
37
|
-
# Extract format from MIME type (e.g., 'image/png' -> 'png')
|
38
|
-
self._format = self.type.split("/")[-1].upper()
|
39
|
-
return self._format
|
40
|
-
|
41
|
-
@classmethod
|
42
|
-
def from_url(
|
43
|
-
cls,
|
44
|
-
url: str,
|
45
|
-
*,
|
46
|
-
lazy: bool = True,
|
47
|
-
timeout: float = 30.0,
|
48
|
-
) -> Self:
|
49
|
-
"""Download and create an image from a URL.
|
50
|
-
|
51
|
-
Args:
|
52
|
-
url: The URL to download from.
|
53
|
-
lazy: If True, defer loading content until needed.
|
54
|
-
timeout: Request timeout in seconds.
|
55
|
-
|
56
|
-
Returns:
|
57
|
-
A new Image instance.
|
58
|
-
"""
|
59
|
-
data = None
|
60
|
-
size = None
|
61
|
-
type = None
|
62
|
-
|
63
|
-
if not lazy:
|
64
|
-
with httpx.Client(timeout=timeout) as client:
|
65
|
-
response = client.get(url)
|
66
|
-
response.raise_for_status()
|
67
|
-
|
68
|
-
data = response.content
|
69
|
-
size = len(data)
|
70
|
-
|
71
|
-
# Get content type
|
72
|
-
content_type = response.headers.get("content-type", "")
|
73
|
-
type = content_type.split(";")[0] if content_type else None
|
74
|
-
|
75
|
-
# Validate it's an image
|
76
|
-
if type and not type.startswith("image/"):
|
77
|
-
raise ValueError(f"URL does not point to an image: {type}")
|
78
|
-
|
79
|
-
return cls(
|
80
|
-
data=data,
|
81
|
-
type=type,
|
82
|
-
source=FileSource(
|
83
|
-
is_url=True,
|
84
|
-
url=url,
|
85
|
-
size=size,
|
86
|
-
),
|
87
|
-
)
|
88
|
-
|
89
|
-
@classmethod
|
90
|
-
def from_path(
|
91
|
-
cls,
|
92
|
-
path: str | Path,
|
93
|
-
) -> Self:
|
94
|
-
"""Create an image from a file path.
|
95
|
-
|
96
|
-
Args:
|
97
|
-
path: The path to the image file.
|
98
|
-
|
99
|
-
Returns:
|
100
|
-
A new Image instance.
|
101
|
-
|
102
|
-
Raises:
|
103
|
-
FileNotFoundError: If the file does not exist.
|
104
|
-
ValueError: If the file is not a valid image.
|
105
|
-
"""
|
106
|
-
path_obj = Path(path)
|
107
|
-
|
108
|
-
if not path_obj.exists():
|
109
|
-
raise FileNotFoundError(f"Image file not found: {path}")
|
110
|
-
|
111
|
-
if not path_obj.is_file():
|
112
|
-
raise ValueError(f"Path is not a file: {path}")
|
113
|
-
|
114
|
-
# Read the file data
|
115
|
-
data = path_obj.read_bytes()
|
116
|
-
|
117
|
-
# Detect MIME type
|
118
|
-
type = None
|
119
|
-
for sig, mime in _FILE_SIGNATURES.items():
|
120
|
-
if data.startswith(sig):
|
121
|
-
type = mime
|
122
|
-
break
|
123
|
-
|
124
|
-
# Fallback to mimetypes module
|
125
|
-
if not type:
|
126
|
-
type, _ = mimetypes.guess_type(str(path))
|
127
|
-
|
128
|
-
# Validate it's an image
|
129
|
-
if type and not type.startswith("image/"):
|
130
|
-
raise ValueError(f"File is not an image: {type}")
|
131
|
-
|
132
|
-
return cls(
|
133
|
-
data=data,
|
134
|
-
type=type,
|
135
|
-
source=FileSource(
|
136
|
-
is_file=True,
|
137
|
-
path=path_obj,
|
138
|
-
size=len(data),
|
139
|
-
),
|
140
|
-
)
|
141
|
-
|
142
|
-
|
143
|
-
def read_image_from_url(
|
144
|
-
url: str,
|
145
|
-
*,
|
146
|
-
lazy: bool = True,
|
147
|
-
timeout: float = 30.0,
|
148
|
-
) -> Image:
|
149
|
-
"""Download and create an image from a URL.
|
150
|
-
|
151
|
-
Args:
|
152
|
-
url: The URL to download from.
|
153
|
-
lazy: If True, defer loading content until needed.
|
154
|
-
timeout: Request timeout in seconds.
|
155
|
-
|
156
|
-
Returns:
|
157
|
-
A new Image instance.
|
158
|
-
|
159
|
-
Raises:
|
160
|
-
httpx.RequestError: If the request fails.
|
161
|
-
httpx.HTTPStatusError: If the response has an error status code.
|
162
|
-
ValueError: If the URL does not point to an image.
|
163
|
-
"""
|
164
|
-
return Image.from_url(url, lazy=lazy, timeout=timeout)
|
165
|
-
|
166
|
-
|
167
|
-
def read_image_from_path(
|
168
|
-
path: str | Path,
|
169
|
-
) -> Image:
|
170
|
-
"""Create an image from a file path.
|
171
|
-
|
172
|
-
Args:
|
173
|
-
path: The path to the image file.
|
174
|
-
|
175
|
-
Returns:
|
176
|
-
A new Image instance.
|
177
|
-
|
178
|
-
Raises:
|
179
|
-
FileNotFoundError: If the file does not exist.
|
180
|
-
ValueError: If the file is not a valid image.
|
181
|
-
"""
|
182
|
-
return Image.from_path(path)
|