cocoindex 0.1.75__cp313-cp313-manylinux_2_28_x86_64.whl → 0.1.76__cp313-cp313-manylinux_2_28_x86_64.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.
cocoindex/functions.py CHANGED
@@ -1,6 +1,7 @@
1
1
  """All builtin functions."""
2
2
 
3
3
  import dataclasses
4
+ import functools
4
5
  from typing import Annotated, Any, Literal
5
6
 
6
7
  import numpy as np
@@ -23,6 +24,16 @@ class CustomLanguageSpec:
23
24
  aliases: list[str] = dataclasses.field(default_factory=list)
24
25
 
25
26
 
27
+ @dataclasses.dataclass
28
+ class ColPaliModelInfo:
29
+ """Data structure for ColPali model and processor."""
30
+
31
+ model: Any
32
+ processor: Any
33
+ dimension: int
34
+ device: Any
35
+
36
+
26
37
  class SplitRecursively(op.FunctionSpec):
27
38
  """Split a document (in string) recursively."""
28
39
 
@@ -99,3 +110,189 @@ class SentenceTransformerEmbedExecutor:
99
110
  assert self._model is not None
100
111
  result: NDArray[np.float32] = self._model.encode(text, convert_to_numpy=True)
101
112
  return result
113
+
114
+
115
+ @functools.cache
116
+ def _get_colpali_model_and_processor(model_name: str) -> ColPaliModelInfo:
117
+ """Get or load ColPali model and processor, with caching."""
118
+ try:
119
+ from colpali_engine.models import ColPali, ColPaliProcessor # type: ignore[import-untyped]
120
+ from colpali_engine.utils.torch_utils import get_torch_device # type: ignore[import-untyped]
121
+ import torch
122
+ except ImportError as e:
123
+ raise ImportError(
124
+ "ColPali is not available. Make sure cocoindex is installed with ColPali support."
125
+ ) from e
126
+
127
+ device = get_torch_device("auto")
128
+ model = ColPali.from_pretrained(
129
+ model_name, device_map=device, torch_dtype=torch.bfloat16
130
+ ).eval()
131
+ processor = ColPaliProcessor.from_pretrained(model_name)
132
+
133
+ # Get dimension from the actual model
134
+ dimension = _detect_colpali_dimension(model, processor, device)
135
+
136
+ return ColPaliModelInfo(
137
+ model=model,
138
+ processor=processor,
139
+ dimension=dimension,
140
+ device=device,
141
+ )
142
+
143
+
144
+ def _detect_colpali_dimension(model: Any, processor: Any, device: Any) -> int:
145
+ """Detect ColPali embedding dimension from the actual model config."""
146
+ # Try to access embedding dimension
147
+ if hasattr(model.config, "embedding_dim"):
148
+ dim = model.config.embedding_dim
149
+ else:
150
+ # Fallback: infer from output shape with dummy data
151
+ from PIL import Image
152
+ import numpy as np
153
+ import torch
154
+
155
+ dummy_img = Image.fromarray(np.zeros((224, 224, 3), np.uint8))
156
+ # Use the processor to process the dummy image
157
+ processed = processor.process_images([dummy_img]).to(device)
158
+ with torch.no_grad():
159
+ output = model(**processed)
160
+ dim = int(output.shape[-1])
161
+ if isinstance(dim, int):
162
+ return dim
163
+ else:
164
+ raise ValueError(f"Expected integer dimension, got {type(dim)}: {dim}")
165
+ return dim
166
+
167
+
168
+ class ColPaliEmbedImage(op.FunctionSpec):
169
+ """
170
+ `ColPaliEmbedImage` embeds images using the ColPali multimodal model.
171
+
172
+ ColPali (Contextual Late-interaction over Patches) uses late interaction
173
+ between image patch embeddings and text token embeddings for retrieval.
174
+
175
+ Args:
176
+ model: The ColPali model name to use (e.g., "vidore/colpali-v1.2")
177
+
178
+ Note:
179
+ This function requires the optional colpali-engine dependency.
180
+ Install it with: pip install 'cocoindex[embeddings]'
181
+ """
182
+
183
+ model: str
184
+
185
+
186
+ @op.executor_class(
187
+ gpu=True,
188
+ cache=True,
189
+ behavior_version=1,
190
+ )
191
+ class ColPaliEmbedImageExecutor:
192
+ """Executor for ColPaliEmbedImage."""
193
+
194
+ spec: ColPaliEmbedImage
195
+ _model_info: ColPaliModelInfo
196
+
197
+ def analyze(self, _img_bytes: Any) -> type:
198
+ # Get shared model and dimension
199
+ self._model_info = _get_colpali_model_and_processor(self.spec.model)
200
+
201
+ # Return multi-vector type: Variable patches x Fixed hidden dimension
202
+ dimension = self._model_info.dimension
203
+ return Vector[Vector[np.float32, Literal[dimension]]] # type: ignore
204
+
205
+ def __call__(self, img_bytes: bytes) -> Any:
206
+ try:
207
+ from PIL import Image
208
+ import torch
209
+ import io
210
+ except ImportError as e:
211
+ raise ImportError(
212
+ "Required dependencies (PIL, torch) are missing for ColPali image embedding."
213
+ ) from e
214
+
215
+ model = self._model_info.model
216
+ processor = self._model_info.processor
217
+ device = self._model_info.device
218
+
219
+ pil_image = Image.open(io.BytesIO(img_bytes)).convert("RGB")
220
+ inputs = processor.process_images([pil_image]).to(device)
221
+ with torch.no_grad():
222
+ embeddings = model(**inputs)
223
+
224
+ # Return multi-vector format: [patches, hidden_dim]
225
+ if len(embeddings.shape) != 3:
226
+ raise ValueError(
227
+ f"Expected 3D tensor [batch, patches, hidden_dim], got shape {embeddings.shape}"
228
+ )
229
+
230
+ # Keep patch-level embeddings: [batch, patches, hidden_dim] -> [patches, hidden_dim]
231
+ patch_embeddings = embeddings[0] # Remove batch dimension
232
+
233
+ return patch_embeddings.cpu().to(torch.float32).numpy()
234
+
235
+
236
+ class ColPaliEmbedQuery(op.FunctionSpec):
237
+ """
238
+ `ColPaliEmbedQuery` embeds text queries using the ColPali multimodal model.
239
+
240
+ This produces query embeddings compatible with ColPali image embeddings
241
+ for late interaction scoring (MaxSim).
242
+
243
+ Args:
244
+ model: The ColPali model name to use (e.g., "vidore/colpali-v1.2")
245
+
246
+ Note:
247
+ This function requires the optional colpali-engine dependency.
248
+ Install it with: pip install 'cocoindex[embeddings]'
249
+ """
250
+
251
+ model: str
252
+
253
+
254
+ @op.executor_class(
255
+ gpu=True,
256
+ cache=True,
257
+ behavior_version=1,
258
+ )
259
+ class ColPaliEmbedQueryExecutor:
260
+ """Executor for ColPaliEmbedQuery."""
261
+
262
+ spec: ColPaliEmbedQuery
263
+ _model_info: ColPaliModelInfo
264
+
265
+ def analyze(self, _query: Any) -> type:
266
+ # Get shared model and dimension
267
+ self._model_info = _get_colpali_model_and_processor(self.spec.model)
268
+
269
+ # Return multi-vector type: Variable tokens x Fixed hidden dimension
270
+ dimension = self._model_info.dimension
271
+ return Vector[Vector[np.float32, Literal[dimension]]] # type: ignore
272
+
273
+ def __call__(self, query: str) -> Any:
274
+ try:
275
+ import torch
276
+ except ImportError as e:
277
+ raise ImportError(
278
+ "Required dependencies (torch) are missing for ColPali query embedding."
279
+ ) from e
280
+
281
+ model = self._model_info.model
282
+ processor = self._model_info.processor
283
+ device = self._model_info.device
284
+
285
+ inputs = processor.process_queries([query]).to(device)
286
+ with torch.no_grad():
287
+ embeddings = model(**inputs)
288
+
289
+ # Return multi-vector format: [tokens, hidden_dim]
290
+ if len(embeddings.shape) != 3:
291
+ raise ValueError(
292
+ f"Expected 3D tensor [batch, tokens, hidden_dim], got shape {embeddings.shape}"
293
+ )
294
+
295
+ # Keep token-level embeddings: [batch, tokens, hidden_dim] -> [tokens, hidden_dim]
296
+ token_embeddings = embeddings[0] # Remove batch dimension
297
+
298
+ return token_embeddings.cpu().to(torch.float32).numpy()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cocoindex
3
- Version: 0.1.75
3
+ Version: 0.1.76
4
4
  Requires-Dist: click>=8.1.8
5
5
  Requires-Dist: rich>=14.0.0
6
6
  Requires-Dist: python-dotenv>=1.1.0
@@ -12,9 +12,12 @@ Requires-Dist: ruff ; extra == 'dev'
12
12
  Requires-Dist: mypy ; extra == 'dev'
13
13
  Requires-Dist: pre-commit ; extra == 'dev'
14
14
  Requires-Dist: sentence-transformers>=3.3.1 ; extra == 'embeddings'
15
+ Requires-Dist: colpali-engine ; extra == 'colpali'
15
16
  Requires-Dist: sentence-transformers>=3.3.1 ; extra == 'all'
17
+ Requires-Dist: colpali-engine ; extra == 'all'
16
18
  Provides-Extra: dev
17
19
  Provides-Extra: embeddings
20
+ Provides-Extra: colpali
18
21
  Provides-Extra: all
19
22
  License-File: LICENSE
20
23
  Summary: With CocoIndex, users declare the transformation, CocoIndex creates & maintains an index, and keeps the derived index up to date based on source update, with minimal computation and changes.
@@ -1,14 +1,14 @@
1
- cocoindex-0.1.75.dist-info/METADATA,sha256=kdYHdHSv-kunSaI3MoIUCoZ88Ne3pgeV5jS5WliHGrc,11533
2
- cocoindex-0.1.75.dist-info/WHEEL,sha256=9Ee4MwqZpMDLH1_kZE8rvruLKRVRs9cmbXRSBB0h-_M,108
3
- cocoindex-0.1.75.dist-info/entry_points.txt,sha256=_NretjYVzBdNTn7dK-zgwr7YfG2afz1u1uSE-5bZXF8,46
4
- cocoindex-0.1.75.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
1
+ cocoindex-0.1.76.dist-info/METADATA,sha256=w_VMnPWkx5iMgpwgAWTB3KRxSfcGaU1sVES6-jXiAjQ,11655
2
+ cocoindex-0.1.76.dist-info/WHEEL,sha256=9Ee4MwqZpMDLH1_kZE8rvruLKRVRs9cmbXRSBB0h-_M,108
3
+ cocoindex-0.1.76.dist-info/entry_points.txt,sha256=_NretjYVzBdNTn7dK-zgwr7YfG2afz1u1uSE-5bZXF8,46
4
+ cocoindex-0.1.76.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
5
5
  cocoindex/__init__.py,sha256=sLpSVO5Cotgn_82lawxvXnaqfa-qj33rytWBAe2MTtU,2201
6
- cocoindex/_engine.cpython-313-x86_64-linux-gnu.so,sha256=ay8KAvvTUo9j0webtFd6Hwr2mqWNg1QiMbnweVeDg0Q,71097144
6
+ cocoindex/_engine.cpython-313-x86_64-linux-gnu.so,sha256=sIEYde0TfFKjUS1vPsht_7DPZjbvlApMxb_U2CbiIJw,71114160
7
7
  cocoindex/auth_registry.py,sha256=PE1-kVkcyC1G2C_V7b1kvYzeq73OFQehWKQP7ln7fJ8,1478
8
8
  cocoindex/cli.py,sha256=-gp639JSyQN6YjnhGqCakIzYoSSqXxQMbxbkcYGP0QY,22359
9
9
  cocoindex/convert.py,sha256=HodeDl1HVX8nnBH02lQKarw5i3xmkjB0nGj-DXt7Ifc,18284
10
10
  cocoindex/flow.py,sha256=egKbBG2X9DjAqmcATcndyRhe9zMZHRd-YxKCpt9BsUg,36551
11
- cocoindex/functions.py,sha256=LLu_ausirvqnsx_k3euZpv8sLCpBZ4DF77h2HOzbinE,3109
11
+ cocoindex/functions.py,sha256=34sZWoS0zGnaKyooIODQgc6QEPZKiJoWhfb8jKIWwps,9528
12
12
  cocoindex/index.py,sha256=j93B9jEvvLXHtpzKWL88SY6wCGEoPgpsQhEGHlyYGFg,540
13
13
  cocoindex/lib.py,sha256=f--9dAYd84CZosbDZqNW0oGbBLsY3dXiUTR1VrfQ_QY,817
14
14
  cocoindex/llm.py,sha256=WxmWUbNcf9HOCM5xkbDeFs9lF67M3mr810B7deDDc-8,673
@@ -28,4 +28,4 @@ cocoindex/tests/test_validation.py,sha256=X6AQzVs-hVKIXcrHMEMQnhfUE8at7iXQnPq8nH
28
28
  cocoindex/typing.py,sha256=qQ0ANF3iuQDeSqipHgL2SDiiXL2reTMUN0aj4ve_T0w,13359
29
29
  cocoindex/utils.py,sha256=hUhX-XV6XGCtJSEIpBOuDv6VvqImwPlgBxztBTw7u0U,598
30
30
  cocoindex/validation.py,sha256=PZnJoby4sLbsmPv9fOjOQXuefjfZ7gmtsiTGU8SH-tc,3090
31
- cocoindex-0.1.75.dist-info/RECORD,,
31
+ cocoindex-0.1.76.dist-info/RECORD,,