fastembed-gpu 0.4.2__tar.gz → 0.5.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.
Files changed (49) hide show
  1. {fastembed_gpu-0.4.2 → fastembed_gpu-0.5.0}/PKG-INFO +14 -11
  2. {fastembed_gpu-0.4.2 → fastembed_gpu-0.5.0}/README.md +3 -4
  3. {fastembed_gpu-0.4.2 → fastembed_gpu-0.5.0}/fastembed/common/model_management.py +23 -11
  4. {fastembed_gpu-0.4.2 → fastembed_gpu-0.5.0}/fastembed/common/onnx_model.py +11 -4
  5. {fastembed_gpu-0.4.2 → fastembed_gpu-0.5.0}/fastembed/common/preprocessor_utils.py +2 -2
  6. {fastembed_gpu-0.4.2 → fastembed_gpu-0.5.0}/fastembed/common/types.py +2 -2
  7. {fastembed_gpu-0.4.2 → fastembed_gpu-0.5.0}/fastembed/common/utils.py +6 -6
  8. {fastembed_gpu-0.4.2 → fastembed_gpu-0.5.0}/fastembed/image/image_embedding.py +5 -5
  9. {fastembed_gpu-0.4.2 → fastembed_gpu-0.5.0}/fastembed/image/onnx_embedding.py +18 -7
  10. {fastembed_gpu-0.4.2 → fastembed_gpu-0.5.0}/fastembed/image/onnx_image_model.py +7 -7
  11. {fastembed_gpu-0.4.2 → fastembed_gpu-0.5.0}/fastembed/image/transform/functional.py +34 -8
  12. {fastembed_gpu-0.4.2 → fastembed_gpu-0.5.0}/fastembed/image/transform/operators.py +99 -29
  13. {fastembed_gpu-0.4.2 → fastembed_gpu-0.5.0}/fastembed/late_interaction/colbert.py +13 -10
  14. {fastembed_gpu-0.4.2 → fastembed_gpu-0.5.0}/fastembed/late_interaction/jina_colbert.py +5 -5
  15. {fastembed_gpu-0.4.2 → fastembed_gpu-0.5.0}/fastembed/late_interaction/late_interaction_text_embedding.py +5 -5
  16. {fastembed_gpu-0.4.2 → fastembed_gpu-0.5.0}/fastembed/parallel_processor.py +8 -7
  17. {fastembed_gpu-0.4.2 → fastembed_gpu-0.5.0}/fastembed/rerank/cross_encoder/onnx_text_cross_encoder.py +57 -10
  18. fastembed_gpu-0.5.0/fastembed/rerank/cross_encoder/onnx_text_model.py +150 -0
  19. {fastembed_gpu-0.4.2 → fastembed_gpu-0.5.0}/fastembed/rerank/cross_encoder/text_cross_encoder.py +42 -9
  20. fastembed_gpu-0.5.0/fastembed/rerank/cross_encoder/text_cross_encoder_base.py +58 -0
  21. {fastembed_gpu-0.4.2 → fastembed_gpu-0.5.0}/fastembed/sparse/bm25.py +29 -15
  22. {fastembed_gpu-0.4.2 → fastembed_gpu-0.5.0}/fastembed/sparse/bm42.py +14 -14
  23. {fastembed_gpu-0.4.2 → fastembed_gpu-0.5.0}/fastembed/sparse/sparse_embedding_base.py +6 -10
  24. {fastembed_gpu-0.4.2 → fastembed_gpu-0.5.0}/fastembed/sparse/sparse_text_embedding.py +5 -5
  25. {fastembed_gpu-0.4.2 → fastembed_gpu-0.5.0}/fastembed/sparse/splade_pp.py +5 -5
  26. {fastembed_gpu-0.4.2 → fastembed_gpu-0.5.0}/fastembed/sparse/utils/tokenizer.py +2 -3
  27. {fastembed_gpu-0.4.2 → fastembed_gpu-0.5.0}/fastembed/text/clip_embedding.py +3 -3
  28. {fastembed_gpu-0.4.2 → fastembed_gpu-0.5.0}/fastembed/text/e5_onnx_embedding.py +5 -5
  29. {fastembed_gpu-0.4.2 → fastembed_gpu-0.5.0}/fastembed/text/onnx_embedding.py +28 -8
  30. {fastembed_gpu-0.4.2 → fastembed_gpu-0.5.0}/fastembed/text/onnx_text_model.py +8 -9
  31. {fastembed_gpu-0.4.2 → fastembed_gpu-0.5.0}/fastembed/text/pooled_embedding.py +3 -3
  32. {fastembed_gpu-0.4.2 → fastembed_gpu-0.5.0}/fastembed/text/pooled_normalized_embedding.py +30 -3
  33. {fastembed_gpu-0.4.2 → fastembed_gpu-0.5.0}/fastembed/text/text_embedding.py +6 -6
  34. {fastembed_gpu-0.4.2 → fastembed_gpu-0.5.0}/pyproject.toml +15 -9
  35. fastembed_gpu-0.4.2/fastembed/rerank/cross_encoder/onnx_text_model.py +0 -70
  36. fastembed_gpu-0.4.2/fastembed/rerank/cross_encoder/text_cross_encoder_base.py +0 -37
  37. {fastembed_gpu-0.4.2 → fastembed_gpu-0.5.0}/LICENSE +0 -0
  38. {fastembed_gpu-0.4.2 → fastembed_gpu-0.5.0}/NOTICE +0 -0
  39. {fastembed_gpu-0.4.2 → fastembed_gpu-0.5.0}/fastembed/__init__.py +0 -0
  40. {fastembed_gpu-0.4.2 → fastembed_gpu-0.5.0}/fastembed/common/__init__.py +0 -0
  41. {fastembed_gpu-0.4.2 → fastembed_gpu-0.5.0}/fastembed/embedding.py +0 -0
  42. {fastembed_gpu-0.4.2 → fastembed_gpu-0.5.0}/fastembed/image/__init__.py +0 -0
  43. {fastembed_gpu-0.4.2 → fastembed_gpu-0.5.0}/fastembed/image/image_embedding_base.py +0 -0
  44. {fastembed_gpu-0.4.2 → fastembed_gpu-0.5.0}/fastembed/late_interaction/__init__.py +0 -0
  45. {fastembed_gpu-0.4.2 → fastembed_gpu-0.5.0}/fastembed/late_interaction/late_interaction_embedding_base.py +0 -0
  46. {fastembed_gpu-0.4.2 → fastembed_gpu-0.5.0}/fastembed/rerank/cross_encoder/__init__.py +0 -0
  47. {fastembed_gpu-0.4.2 → fastembed_gpu-0.5.0}/fastembed/sparse/__init__.py +0 -0
  48. {fastembed_gpu-0.4.2 → fastembed_gpu-0.5.0}/fastembed/text/__init__.py +0 -0
  49. {fastembed_gpu-0.4.2 → fastembed_gpu-0.5.0}/fastembed/text/text_embedding_base.py +0 -0
@@ -1,27 +1,31 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fastembed-gpu
3
- Version: 0.4.2
3
+ Version: 0.5.0
4
4
  Summary: Fast, light, accurate library built for retrieval embedding generation
5
5
  Home-page: https://github.com/qdrant/fastembed
6
6
  License: Apache License
7
7
  Keywords: vector,embedding,neural,search,qdrant,sentence-transformers
8
8
  Author: Qdrant Team
9
9
  Author-email: info@qdrant.tech
10
- Requires-Python: >=3.8.0,<3.13
10
+ Requires-Python: >=3.9.0
11
11
  Classifier: License :: Other/Proprietary License
12
12
  Classifier: Programming Language :: Python :: 3
13
- Classifier: Programming Language :: Python :: 3.8
14
13
  Classifier: Programming Language :: Python :: 3.9
15
14
  Classifier: Programming Language :: Python :: 3.10
16
15
  Classifier: Programming Language :: Python :: 3.11
17
16
  Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
18
  Requires-Dist: huggingface-hub (>=0.20,<1.0)
19
19
  Requires-Dist: loguru (>=0.7.2,<0.8.0)
20
20
  Requires-Dist: mmh3 (>=4.1.0,<5.0.0)
21
- Requires-Dist: numpy (>=1.21) ; python_version < "3.12"
22
- Requires-Dist: numpy (>=1.26) ; python_version >= "3.12"
23
- Requires-Dist: onnx (>=1.15.0,<2.0.0)
24
- Requires-Dist: onnxruntime-gpu (>=1.17.0,<1.20.0)
21
+ Requires-Dist: numpy (>=1.21) ; python_version >= "3.10" and python_version < "3.12"
22
+ Requires-Dist: numpy (>=1.21,<2.1.0) ; python_version < "3.10"
23
+ Requires-Dist: numpy (>=1.26) ; python_version >= "3.12" and python_version < "3.13"
24
+ Requires-Dist: numpy (>=2.1.0) ; python_version >= "3.13"
25
+ Requires-Dist: onnx (>=1.15.0)
26
+ Requires-Dist: onnxruntime-gpu (>1.20.0) ; python_version >= "3.13"
27
+ Requires-Dist: onnxruntime-gpu (>=1.17.0,!=1.20.0) ; python_version >= "3.10" and python_version < "3.13"
28
+ Requires-Dist: onnxruntime-gpu (>=1.17.0,<1.20.0) ; python_version < "3.10"
25
29
  Requires-Dist: pillow (>=10.3.0,<11.0.0)
26
30
  Requires-Dist: py-rust-stemmers (>=0.1.0,<0.2.0)
27
31
  Requires-Dist: requests (>=2.31,<3.0)
@@ -60,10 +64,10 @@ pip install fastembed-gpu
60
64
 
61
65
  ```python
62
66
  from fastembed import TextEmbedding
63
- from typing import List
67
+
64
68
 
65
69
  # Example list of documents
66
- documents: List[str] = [
70
+ documents: list[str] = [
67
71
  "This is built to be faster and lighter than other embedding libraries e.g. Transformers, Sentence-Transformers, etc.",
68
72
  "fastembed is supported by and maintained by Qdrant.",
69
73
  ]
@@ -171,11 +175,10 @@ embeddings = list(model.embed(images))
171
175
 
172
176
  ### 🔄 Rerankers
173
177
  ```python
174
- from typing import List
175
178
  from fastembed.rerank.cross_encoder import TextCrossEncoder
176
179
 
177
180
  query = "Who is maintaining Qdrant?"
178
- documents: List[str] = [
181
+ documents: list[str] = [
179
182
  "This is built to be faster and lighter than other embedding libraries e.g. Transformers, Sentence-Transformers, etc.",
180
183
  "fastembed is supported by and maintained by Qdrant.",
181
184
  ]
@@ -28,10 +28,10 @@ pip install fastembed-gpu
28
28
 
29
29
  ```python
30
30
  from fastembed import TextEmbedding
31
- from typing import List
31
+
32
32
 
33
33
  # Example list of documents
34
- documents: List[str] = [
34
+ documents: list[str] = [
35
35
  "This is built to be faster and lighter than other embedding libraries e.g. Transformers, Sentence-Transformers, etc.",
36
36
  "fastembed is supported by and maintained by Qdrant.",
37
37
  ]
@@ -139,11 +139,10 @@ embeddings = list(model.embed(images))
139
139
 
140
140
  ### 🔄 Rerankers
141
141
  ```python
142
- from typing import List
143
142
  from fastembed.rerank.cross_encoder import TextCrossEncoder
144
143
 
145
144
  query = "Who is maintaining Qdrant?"
146
- documents: List[str] = [
145
+ documents: list[str] = [
147
146
  "This is built to be faster and lighter than other embedding libraries e.g. Transformers, Sentence-Transformers, etc.",
148
147
  "fastembed is supported by and maintained by Qdrant.",
149
148
  ]
@@ -3,27 +3,31 @@ import time
3
3
  import shutil
4
4
  import tarfile
5
5
  from pathlib import Path
6
- from typing import Any, Dict, List, Optional
6
+ from typing import Any, Optional
7
7
 
8
8
  import requests
9
9
  from huggingface_hub import snapshot_download
10
- from huggingface_hub.utils import RepositoryNotFoundError
10
+ from huggingface_hub.utils import (
11
+ RepositoryNotFoundError,
12
+ disable_progress_bars,
13
+ enable_progress_bars,
14
+ )
11
15
  from loguru import logger
12
16
  from tqdm import tqdm
13
17
 
14
18
 
15
19
  class ModelManagement:
16
20
  @classmethod
17
- def list_supported_models(cls) -> List[Dict[str, Any]]:
21
+ def list_supported_models(cls) -> list[dict[str, Any]]:
18
22
  """Lists the supported models.
19
23
 
20
24
  Returns:
21
- List[Dict[str, Any]]: A list of dictionaries containing the model information.
25
+ list[dict[str, Any]]: A list of dictionaries containing the model information.
22
26
  """
23
27
  raise NotImplementedError()
24
28
 
25
29
  @classmethod
26
- def _get_model_description(cls, model_name: str) -> Dict[str, Any]:
30
+ def _get_model_description(cls, model_name: str) -> dict[str, Any]:
27
31
  """
28
32
  Gets the model description from the model_name.
29
33
 
@@ -34,7 +38,7 @@ class ModelManagement:
34
38
  ValueError: If the model_name is not supported.
35
39
 
36
40
  Returns:
37
- Dict[str, Any]: The model description.
41
+ dict[str, Any]: The model description.
38
42
  """
39
43
  for model in cls.list_supported_models():
40
44
  if model_name.lower() == model["model"].lower():
@@ -93,8 +97,8 @@ class ModelManagement:
93
97
  def download_files_from_huggingface(
94
98
  cls,
95
99
  hf_source_repo: str,
96
- cache_dir: Optional[str] = None,
97
- extra_patterns: Optional[List[str]] = None,
100
+ cache_dir: str,
101
+ extra_patterns: Optional[list[str]] = None,
98
102
  local_files_only: bool = False,
99
103
  **kwargs,
100
104
  ) -> str:
@@ -103,7 +107,7 @@ class ModelManagement:
103
107
  Args:
104
108
  hf_source_repo (str): Name of the model on HuggingFace Hub, e.g. "qdrant/all-MiniLM-L6-v2-onnx".
105
109
  cache_dir (Optional[str]): The path to the cache directory.
106
- extra_patterns (Optional[List[str]]): extra patterns to allow in the snapshot download, typically
110
+ extra_patterns (Optional[list[str]]): extra patterns to allow in the snapshot download, typically
107
111
  includes the required model files.
108
112
  local_files_only (bool, optional): Whether to only use local files. Defaults to False.
109
113
  Returns:
@@ -119,6 +123,12 @@ class ModelManagement:
119
123
  if extra_patterns is not None:
120
124
  allow_patterns.extend(extra_patterns)
121
125
 
126
+ snapshot_dir = Path(cache_dir) / f"models--{hf_source_repo.replace('/', '--')}"
127
+ is_cached = snapshot_dir.exists()
128
+
129
+ if is_cached:
130
+ disable_progress_bars()
131
+
122
132
  return snapshot_download(
123
133
  repo_id=hf_source_repo,
124
134
  allow_patterns=allow_patterns,
@@ -211,13 +221,13 @@ class ModelManagement:
211
221
 
212
222
  @classmethod
213
223
  def download_model(
214
- cls, model: Dict[str, Any], cache_dir: Path, retries: int = 3, **kwargs
224
+ cls, model: dict[str, Any], cache_dir: Path, retries: int = 3, **kwargs
215
225
  ) -> Path:
216
226
  """
217
227
  Downloads a model from HuggingFace Hub or Google Cloud Storage.
218
228
 
219
229
  Args:
220
- model (Dict[str, Any]): The model description.
230
+ model (dict[str, Any]): The model description.
221
231
  Example:
222
232
  ```
223
233
  {
@@ -265,6 +275,8 @@ class ModelManagement:
265
275
  f"Could not download model from HuggingFace: {e} "
266
276
  "Falling back to other sources."
267
277
  )
278
+ finally:
279
+ enable_progress_bars()
268
280
  if url_source or local_files_only:
269
281
  try:
270
282
  return cls.retrieve_model_gcs(
@@ -1,7 +1,7 @@
1
1
  import warnings
2
2
  from dataclasses import dataclass
3
3
  from pathlib import Path
4
- from typing import Any, Dict, Generic, Iterable, Optional, Sequence, Tuple, Type, TypeVar
4
+ from typing import Any, Generic, Iterable, Optional, Sequence, Type, TypeVar
5
5
 
6
6
  import numpy as np
7
7
  import onnxruntime as ort
@@ -33,8 +33,8 @@ class OnnxModel(Generic[T]):
33
33
  self.tokenizer = None
34
34
 
35
35
  def _preprocess_onnx_input(
36
- self, onnx_input: Dict[str, np.ndarray], **kwargs
37
- ) -> Dict[str, np.ndarray]:
36
+ self, onnx_input: dict[str, np.ndarray], **kwargs
37
+ ) -> dict[str, np.ndarray]:
38
38
  """
39
39
  Preprocess the onnx input.
40
40
  """
@@ -52,6 +52,13 @@ class OnnxModel(Generic[T]):
52
52
  model_path = model_dir / model_file
53
53
  # List of Execution Providers: https://onnxruntime.ai/docs/execution-providers
54
54
 
55
+ if cuda and providers is not None:
56
+ warnings.warn(
57
+ f"`cuda` and `providers` are mutually exclusive parameters, cuda: {cuda}, providers: {providers}",
58
+ category=UserWarning,
59
+ stacklevel=6,
60
+ )
61
+
55
62
  if providers is not None:
56
63
  onnx_providers = list(providers)
57
64
  elif cuda:
@@ -121,5 +128,5 @@ class EmbeddingWorker(Worker):
121
128
  def start(cls, model_name: str, cache_dir: str, **kwargs: Any) -> "EmbeddingWorker":
122
129
  return cls(model_name=model_name, cache_dir=cache_dir, **kwargs)
123
130
 
124
- def process(self, items: Iterable[Tuple[int, Any]]) -> Iterable[Tuple[int, Any]]:
131
+ def process(self, items: Iterable[tuple[int, Any]]) -> Iterable[tuple[int, Any]]:
125
132
  raise NotImplementedError("Subclasses must implement this method")
@@ -1,6 +1,6 @@
1
1
  import json
2
2
  from pathlib import Path
3
- from typing import Tuple
3
+
4
4
  from tokenizers import AddedToken, Tokenizer
5
5
 
6
6
  from fastembed.image.transform.operators import Compose
@@ -17,7 +17,7 @@ def load_special_tokens(model_dir: Path) -> dict:
17
17
  return tokens_map
18
18
 
19
19
 
20
- def load_tokenizer(model_dir: Path) -> Tuple[Tokenizer, dict]:
20
+ def load_tokenizer(model_dir: Path) -> tuple[Tokenizer, dict]:
21
21
  config_path = model_dir / "config.json"
22
22
  if not config_path.exists():
23
23
  raise ValueError(f"Could not find config.json in {model_dir}")
@@ -1,7 +1,7 @@
1
1
  import os
2
2
  import sys
3
3
  from PIL import Image
4
- from typing import Any, Dict, Iterable, Tuple, Union
4
+ from typing import Any, Iterable, Union
5
5
 
6
6
  if sys.version_info >= (3, 10):
7
7
  from typing import TypeAlias
@@ -13,4 +13,4 @@ PathInput: TypeAlias = Union[str, os.PathLike]
13
13
  PilInput: TypeAlias = Union[Image.Image, Iterable[Image.Image]]
14
14
  ImageInput: TypeAlias = Union[PathInput, Iterable[PathInput], PilInput]
15
15
 
16
- OnnxProvider: TypeAlias = Union[str, Tuple[str, Dict[Any, Any]]]
16
+ OnnxProvider: TypeAlias = Union[str, tuple[str, dict[Any, Any]]]
@@ -1,13 +1,13 @@
1
1
  import os
2
+ import sys
3
+ import re
2
4
  import tempfile
3
- from itertools import islice
5
+ import unicodedata
4
6
  from pathlib import Path
7
+ from itertools import islice
5
8
  from typing import Generator, Iterable, Optional, Union
6
- import unicodedata
7
- import sys
9
+
8
10
  import numpy as np
9
- import re
10
- from typing import Set
11
11
 
12
12
 
13
13
  def normalize(input_array, p=2, dim=1, eps=1e-12) -> np.ndarray:
@@ -45,7 +45,7 @@ def define_cache_dir(cache_dir: Optional[str] = None) -> Path:
45
45
  return cache_path
46
46
 
47
47
 
48
- def get_all_punctuation() -> Set[str]:
48
+ def get_all_punctuation() -> set[str]:
49
49
  return set(
50
50
  chr(i) for i in range(sys.maxunicode) if unicodedata.category(chr(i)).startswith("P")
51
51
  )
@@ -1,4 +1,4 @@
1
- from typing import Any, Dict, Iterable, List, Optional, Sequence, Type
1
+ from typing import Any, Iterable, Optional, Sequence, Type
2
2
 
3
3
  import numpy as np
4
4
 
@@ -8,15 +8,15 @@ from fastembed.image.onnx_embedding import OnnxImageEmbedding
8
8
 
9
9
 
10
10
  class ImageEmbedding(ImageEmbeddingBase):
11
- EMBEDDINGS_REGISTRY: List[Type[ImageEmbeddingBase]] = [OnnxImageEmbedding]
11
+ EMBEDDINGS_REGISTRY: list[Type[ImageEmbeddingBase]] = [OnnxImageEmbedding]
12
12
 
13
13
  @classmethod
14
- def list_supported_models(cls) -> List[Dict[str, Any]]:
14
+ def list_supported_models(cls) -> list[dict[str, Any]]:
15
15
  """
16
16
  Lists the supported models.
17
17
 
18
18
  Returns:
19
- List[Dict[str, Any]]: A list of dictionaries containing the model information.
19
+ list[dict[str, Any]]: A list of dictionaries containing the model information.
20
20
 
21
21
  Example:
22
22
  ```
@@ -47,7 +47,7 @@ class ImageEmbedding(ImageEmbeddingBase):
47
47
  threads: Optional[int] = None,
48
48
  providers: Optional[Sequence[OnnxProvider]] = None,
49
49
  cuda: bool = False,
50
- device_ids: Optional[List[int]] = None,
50
+ device_ids: Optional[list[int]] = None,
51
51
  lazy_load: bool = False,
52
52
  **kwargs,
53
53
  ):
@@ -1,4 +1,4 @@
1
- from typing import Any, Dict, Iterable, List, Optional, Sequence, Type
1
+ from typing import Any, Iterable, Optional, Sequence, Type
2
2
 
3
3
  import numpy as np
4
4
 
@@ -53,6 +53,17 @@ supported_onnx_models = [
53
53
  },
54
54
  "model_file": "model.onnx",
55
55
  },
56
+ {
57
+ "model": "jinaai/jina-clip-v1",
58
+ "dim": 768,
59
+ "description": "Image embeddings, Multimodal (text&image), 2024 year",
60
+ "license": "apache-2.0",
61
+ "size_in_GB": 0.34,
62
+ "sources": {
63
+ "hf": "jinaai/jina-clip-v1",
64
+ },
65
+ "model_file": "onnx/vision_model.onnx",
66
+ },
56
67
  ]
57
68
 
58
69
 
@@ -64,7 +75,7 @@ class OnnxImageEmbedding(ImageEmbeddingBase, OnnxImageModel[np.ndarray]):
64
75
  threads: Optional[int] = None,
65
76
  providers: Optional[Sequence[OnnxProvider]] = None,
66
77
  cuda: bool = False,
67
- device_ids: Optional[List[int]] = None,
78
+ device_ids: Optional[list[int]] = None,
68
79
  lazy_load: bool = False,
69
80
  device_id: Optional[int] = None,
70
81
  **kwargs,
@@ -80,7 +91,7 @@ class OnnxImageEmbedding(ImageEmbeddingBase, OnnxImageModel[np.ndarray]):
80
91
  Mutually exclusive with the `cuda` and `device_ids` arguments. Defaults to None.
81
92
  cuda (bool, optional): Whether to use cuda for inference. Mutually exclusive with `providers`
82
93
  Defaults to False.
83
- device_ids (Optional[List[int]], optional): The list of device ids to use for data parallel processing in
94
+ device_ids (Optional[list[int]], optional): The list of device ids to use for data parallel processing in
84
95
  workers. Should be used with `cuda=True`, mutually exclusive with `providers`. Defaults to None.
85
96
  lazy_load (bool, optional): Whether to load the model during class initialization or on demand.
86
97
  Should be set to True when using multiple-gpu and parallel encoding. Defaults to False.
@@ -129,12 +140,12 @@ class OnnxImageEmbedding(ImageEmbeddingBase, OnnxImageModel[np.ndarray]):
129
140
  )
130
141
 
131
142
  @classmethod
132
- def list_supported_models(cls) -> List[Dict[str, Any]]:
143
+ def list_supported_models(cls) -> list[dict[str, Any]]:
133
144
  """
134
145
  Lists the supported models.
135
146
 
136
147
  Returns:
137
- List[Dict[str, Any]]: A list of dictionaries containing the model information.
148
+ list[Dict[str, Any]]: A list of dictionaries containing the model information.
138
149
  """
139
150
  return supported_onnx_models
140
151
 
@@ -178,8 +189,8 @@ class OnnxImageEmbedding(ImageEmbeddingBase, OnnxImageModel[np.ndarray]):
178
189
  return OnnxImageEmbeddingWorker
179
190
 
180
191
  def _preprocess_onnx_input(
181
- self, onnx_input: Dict[str, np.ndarray], **kwargs
182
- ) -> Dict[str, np.ndarray]:
192
+ self, onnx_input: dict[str, np.ndarray], **kwargs
193
+ ) -> dict[str, np.ndarray]:
183
194
  """
184
195
  Preprocess the onnx input.
185
196
  """
@@ -2,7 +2,7 @@ import contextlib
2
2
  import os
3
3
  from multiprocessing import get_all_start_methods
4
4
  from pathlib import Path
5
- from typing import Any, Dict, Iterable, List, Optional, Sequence, Tuple, Type
5
+ from typing import Any, Iterable, Optional, Sequence, Type
6
6
 
7
7
  import numpy as np
8
8
  from PIL import Image
@@ -29,8 +29,8 @@ class OnnxImageModel(OnnxModel[T]):
29
29
  self.processor = None
30
30
 
31
31
  def _preprocess_onnx_input(
32
- self, onnx_input: Dict[str, np.ndarray], **kwargs
33
- ) -> Dict[str, np.ndarray]:
32
+ self, onnx_input: dict[str, np.ndarray], **kwargs
33
+ ) -> dict[str, np.ndarray]:
34
34
  """
35
35
  Preprocess the onnx input.
36
36
  """
@@ -58,10 +58,10 @@ class OnnxImageModel(OnnxModel[T]):
58
58
  def load_onnx_model(self) -> None:
59
59
  raise NotImplementedError("Subclasses must implement this method")
60
60
 
61
- def _build_onnx_input(self, encoded: np.ndarray) -> Dict[str, np.ndarray]:
61
+ def _build_onnx_input(self, encoded: np.ndarray) -> dict[str, np.ndarray]:
62
62
  return {node.name: encoded for node in self.model.get_inputs()}
63
63
 
64
- def onnx_embed(self, images: List[ImageInput], **kwargs) -> OnnxOutputContext:
64
+ def onnx_embed(self, images: list[ImageInput], **kwargs) -> OnnxOutputContext:
65
65
  with contextlib.ExitStack():
66
66
  image_files = [
67
67
  Image.open(image) if not isinstance(image, Image.Image) else image
@@ -83,7 +83,7 @@ class OnnxImageModel(OnnxModel[T]):
83
83
  parallel: Optional[int] = None,
84
84
  providers: Optional[Sequence[OnnxProvider]] = None,
85
85
  cuda: bool = False,
86
- device_ids: Optional[List[int]] = None,
86
+ device_ids: Optional[list[int]] = None,
87
87
  **kwargs,
88
88
  ) -> Iterable[T]:
89
89
  is_small = False
@@ -125,7 +125,7 @@ class OnnxImageModel(OnnxModel[T]):
125
125
 
126
126
 
127
127
  class ImageEmbeddingWorker(EmbeddingWorker):
128
- def process(self, items: Iterable[Tuple[int, Any]]) -> Iterable[Tuple[int, Any]]:
128
+ def process(self, items: Iterable[tuple[int, Any]]) -> Iterable[tuple[int, Any]]:
129
129
  for idx, batch in items:
130
130
  embeddings = self.model.onnx_embed(batch)
131
131
  yield idx, embeddings
@@ -1,4 +1,4 @@
1
- from typing import Sized, Tuple, Union
1
+ from typing import Sized, Union
2
2
 
3
3
  import numpy as np
4
4
  from PIL import Image
@@ -14,7 +14,7 @@ def convert_to_rgb(image: Image.Image) -> Image.Image:
14
14
 
15
15
  def center_crop(
16
16
  image: Union[Image.Image, np.ndarray],
17
- size: Tuple[int, int],
17
+ size: tuple[int, int],
18
18
  ) -> np.ndarray:
19
19
  if isinstance(image, np.ndarray):
20
20
  _, orig_height, orig_width = image.shape
@@ -62,8 +62,8 @@ def center_crop(
62
62
 
63
63
  def normalize(
64
64
  image: np.ndarray,
65
- mean=Union[float, np.ndarray],
66
- std=Union[float, np.ndarray],
65
+ mean: Union[float, np.ndarray],
66
+ std: Union[float, np.ndarray],
67
67
  ) -> np.ndarray:
68
68
  if not isinstance(image, np.ndarray):
69
69
  raise ValueError("image must be a numpy array")
@@ -96,10 +96,10 @@ def normalize(
96
96
 
97
97
 
98
98
  def resize(
99
- image: Image,
100
- size: Union[int, Tuple[int, int]],
101
- resample: Image.Resampling = Image.Resampling.BILINEAR,
102
- ) -> Image:
99
+ image: Image.Image,
100
+ size: Union[int, tuple[int, int]],
101
+ resample: Union[int, Image.Resampling] = Image.Resampling.BILINEAR,
102
+ ) -> Image.Image:
103
103
  if isinstance(size, tuple):
104
104
  return image.resize(size, resample)
105
105
 
@@ -122,3 +122,29 @@ def pil2ndarray(image: Union[Image.Image, np.ndarray]):
122
122
  if isinstance(image, Image.Image):
123
123
  return np.asarray(image).transpose((2, 0, 1))
124
124
  return image
125
+
126
+
127
+ def pad2square(
128
+ image: Image.Image,
129
+ size: int,
130
+ fill_color: Union[str, int, tuple[int, ...]] = 0,
131
+ ) -> Image.Image:
132
+ height, width = image.height, image.width
133
+
134
+ left, right = 0, width
135
+ top, bottom = 0, height
136
+
137
+ crop_required = False
138
+ if width > size:
139
+ left = (width - size) // 2
140
+ right = left + size
141
+ crop_required = True
142
+
143
+ if height > size:
144
+ top = (height - size) // 2
145
+ bottom = top + size
146
+ crop_required = True
147
+
148
+ new_image = Image.new(mode="RGB", size=(size, size), color=fill_color)
149
+ new_image.paste(image.crop((left, top, right, bottom)) if crop_required else image)
150
+ return new_image