cocoindex 0.1.75__cp313-cp313-win_amd64.whl → 0.1.76__cp313-cp313-win_amd64.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/_engine.cp313-win_amd64.pyd +0 -0
- cocoindex/functions.py +197 -0
- {cocoindex-0.1.75.dist-info → cocoindex-0.1.76.dist-info}/METADATA +4 -1
- {cocoindex-0.1.75.dist-info → cocoindex-0.1.76.dist-info}/RECORD +7 -7
- {cocoindex-0.1.75.dist-info → cocoindex-0.1.76.dist-info}/WHEEL +0 -0
- {cocoindex-0.1.75.dist-info → cocoindex-0.1.76.dist-info}/entry_points.txt +0 -0
- {cocoindex-0.1.75.dist-info → cocoindex-0.1.76.dist-info}/licenses/LICENSE +0 -0
Binary file
|
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.
|
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.
|
2
|
-
cocoindex-0.1.
|
3
|
-
cocoindex-0.1.
|
4
|
-
cocoindex-0.1.
|
1
|
+
cocoindex-0.1.76.dist-info/METADATA,sha256=1S5SYoO7DCKsw7aMEIXrJki83RclbmSdxzxf4p84gQY,11867
|
2
|
+
cocoindex-0.1.76.dist-info/WHEEL,sha256=OASh95bEME3UNqnnxl-DTJ7jIUFeKxREESTsmRdKzNQ,96
|
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=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
|
5
5
|
cocoindex/__init__.py,sha256=5zwuS_X-n7QAE5uBSufqXp77OW8KVVD8E5t_6koDLRc,2293
|
6
|
-
cocoindex/_engine.cp313-win_amd64.pyd,sha256=
|
6
|
+
cocoindex/_engine.cp313-win_amd64.pyd,sha256=40SXaZVZd2a6GuVXu-wlb_1etHOxmi_sQmttHCmDPL0,70297088
|
7
7
|
cocoindex/auth_registry.py,sha256=Qq1IVZb-7K4luRrQSDlOPbISnGEZ4kIDsrCU8H2ARw0,1529
|
8
8
|
cocoindex/cli.py,sha256=zjZv7EH-ZLoO1-3Ua2U7Yt3n2A_T7pN2NCuv7FB8WA0,23097
|
9
9
|
cocoindex/convert.py,sha256=HVnnfanWxEeSiPq8SBrk9Tf6vXFHgD8LtBE-Umi5LcU,18793
|
10
10
|
cocoindex/flow.py,sha256=sZRe3wqwvZWPCdqtfNURCkPGCh3OMMeX6H1DX8NbhjM,37734
|
11
|
-
cocoindex/functions.py,sha256=
|
11
|
+
cocoindex/functions.py,sha256=mKOYe-XozuOykrsmFE1cNLZjO2PlXiD6UfFEEHmuGT8,9826
|
12
12
|
cocoindex/index.py,sha256=GrqTm1rLwICQ8hadtNvJAxVg7GWMvtMmFcbiNtNzmP0,569
|
13
13
|
cocoindex/lib.py,sha256=cZosix4nwROvod4QJOwCzrm6U1CVy_wKMMk7sDDG_Z0,849
|
14
14
|
cocoindex/llm.py,sha256=TDUyTxW7ooFmpA_jDNezABhReXksOXN8F8zY9aiuNTw,709
|
@@ -28,4 +28,4 @@ cocoindex/tests/test_validation.py,sha256=I4wr8lAMAjmy5xgG5N_OJKveXt8XIa96MsQTXh
|
|
28
28
|
cocoindex/typing.py,sha256=gMNJIpGGe-SiXlihDQ-Dw2YdebQvOyG-bWovR-veO6g,13817
|
29
29
|
cocoindex/utils.py,sha256=U3W39zD2uZpXX8v84tJD7sRmbC5ar3z_ljAP1cJrYXI,618
|
30
30
|
cocoindex/validation.py,sha256=4ZjsW-SZT8X_TEEhEE6QG6D-8Oq_TkPAhTqP0mdFYSE,3194
|
31
|
-
cocoindex-0.1.
|
31
|
+
cocoindex-0.1.76.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|