cocoindex 0.2.23__cp311-abi3-win_amd64.whl → 0.3.1__cp311-abi3-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.pyd CHANGED
Binary file
@@ -2,7 +2,7 @@
2
2
 
3
3
  import functools
4
4
  from dataclasses import dataclass
5
- from typing import Any, Optional, TYPE_CHECKING, Literal
5
+ from typing import Any, TYPE_CHECKING, Literal
6
6
  import numpy as np
7
7
 
8
8
  from .. import op
@@ -22,18 +22,11 @@ class ColPaliModelInfo:
22
22
  dimension: int
23
23
 
24
24
 
25
- @functools.lru_cache(maxsize=None)
25
+ @functools.cache
26
26
  def _get_colpali_model_and_processor(model_name: str) -> ColPaliModelInfo:
27
27
  """Load and cache ColPali model and processor with shared device setup."""
28
28
  try:
29
- from colpali_engine import ( # type: ignore[import-untyped]
30
- ColPali,
31
- ColPaliProcessor,
32
- ColQwen2,
33
- ColQwen2Processor,
34
- ColSmol,
35
- ColSmolProcessor,
36
- )
29
+ import colpali_engine as ce # type: ignore[import-untyped]
37
30
  import torch
38
31
  except ImportError as e:
39
32
  raise ImportError(
@@ -42,29 +35,30 @@ def _get_colpali_model_and_processor(model_name: str) -> ColPaliModelInfo:
42
35
  ) from e
43
36
 
44
37
  device = "cuda" if torch.cuda.is_available() else "cpu"
38
+ lower_model_name = model_name.lower()
45
39
 
46
40
  # Determine model type from name
47
- if "colpali" in model_name.lower():
48
- model = ColPali.from_pretrained(
41
+ if lower_model_name.startswith("colpali"):
42
+ model = ce.ColPali.from_pretrained(
49
43
  model_name, torch_dtype=torch.bfloat16, device_map=device
50
44
  )
51
- processor = ColPaliProcessor.from_pretrained(model_name)
52
- elif "colqwen" in model_name.lower():
53
- model = ColQwen2.from_pretrained(
45
+ processor = ce.ColPaliProcessor.from_pretrained(model_name)
46
+ elif lower_model_name.startswith("colqwen2.5"):
47
+ model = ce.ColQwen2_5.from_pretrained(
54
48
  model_name, torch_dtype=torch.bfloat16, device_map=device
55
49
  )
56
- processor = ColQwen2Processor.from_pretrained(model_name)
57
- elif "colsmol" in model_name.lower():
58
- model = ColSmol.from_pretrained(
50
+ processor = ce.ColQwen2_5_Processor.from_pretrained(model_name)
51
+ elif lower_model_name.startswith("colqwen"):
52
+ model = ce.ColQwen2.from_pretrained(
59
53
  model_name, torch_dtype=torch.bfloat16, device_map=device
60
54
  )
61
- processor = ColSmolProcessor.from_pretrained(model_name)
55
+ processor = ce.ColQwen2Processor.from_pretrained(model_name)
62
56
  else:
63
57
  # Fallback to ColPali for backwards compatibility
64
- model = ColPali.from_pretrained(
58
+ model = ce.ColPali.from_pretrained(
65
59
  model_name, torch_dtype=torch.bfloat16, device_map=device
66
60
  )
67
- processor = ColPaliProcessor.from_pretrained(model_name)
61
+ processor = ce.ColPaliProcessor.from_pretrained(model_name)
68
62
 
69
63
  # Detect dimension
70
64
  dimension = _detect_colpali_dimension(model, processor, device)
@@ -130,6 +124,7 @@ class ColPaliEmbedImage(op.FunctionSpec):
130
124
  @op.executor_class(
131
125
  gpu=True,
132
126
  cache=True,
127
+ batching=True,
133
128
  behavior_version=1,
134
129
  )
135
130
  class ColPaliEmbedImageExecutor:
@@ -146,7 +141,7 @@ class ColPaliEmbedImageExecutor:
146
141
  dimension = self._model_info.dimension
147
142
  return Vector[Vector[np.float32, Literal[dimension]]] # type: ignore
148
143
 
149
- def __call__(self, img_bytes: bytes) -> Any:
144
+ def __call__(self, img_bytes_list: list[bytes]) -> Any:
150
145
  try:
151
146
  from PIL import Image
152
147
  import torch
@@ -160,8 +155,11 @@ class ColPaliEmbedImageExecutor:
160
155
  processor = self._model_info.processor
161
156
  device = self._model_info.device
162
157
 
163
- pil_image = Image.open(io.BytesIO(img_bytes)).convert("RGB")
164
- inputs = processor.process_images([pil_image]).to(device)
158
+ pil_images = [
159
+ Image.open(io.BytesIO(img_bytes)).convert("RGB")
160
+ for img_bytes in img_bytes_list
161
+ ]
162
+ inputs = processor.process_images(pil_images).to(device)
165
163
  with torch.no_grad():
166
164
  embeddings = model(**inputs)
167
165
 
@@ -171,10 +169,8 @@ class ColPaliEmbedImageExecutor:
171
169
  f"Expected 3D tensor [batch, patches, hidden_dim], got shape {embeddings.shape}"
172
170
  )
173
171
 
174
- # Keep patch-level embeddings: [batch, patches, hidden_dim] -> [patches, hidden_dim]
175
- patch_embeddings = embeddings[0] # Remove batch dimension
176
-
177
- return patch_embeddings.cpu().to(torch.float32).numpy()
172
+ # [patches, hidden_dim]
173
+ return embeddings.cpu().to(torch.float32).numpy()
178
174
 
179
175
 
180
176
  class ColPaliEmbedQuery(op.FunctionSpec):
@@ -207,6 +203,7 @@ class ColPaliEmbedQuery(op.FunctionSpec):
207
203
  gpu=True,
208
204
  cache=True,
209
205
  behavior_version=1,
206
+ batching=True,
210
207
  )
211
208
  class ColPaliEmbedQueryExecutor:
212
209
  """Executor for ColVision query embedding (ColPali, ColQwen2, ColSmol, etc.)."""
@@ -222,7 +219,7 @@ class ColPaliEmbedQueryExecutor:
222
219
  dimension = self._model_info.dimension
223
220
  return Vector[Vector[np.float32, Literal[dimension]]] # type: ignore
224
221
 
225
- def __call__(self, query: str) -> Any:
222
+ def __call__(self, queries: list[str]) -> Any:
226
223
  try:
227
224
  import torch
228
225
  except ImportError as e:
@@ -234,7 +231,7 @@ class ColPaliEmbedQueryExecutor:
234
231
  processor = self._model_info.processor
235
232
  device = self._model_info.device
236
233
 
237
- inputs = processor.process_queries([query]).to(device)
234
+ inputs = processor.process_queries(queries).to(device)
238
235
  with torch.no_grad():
239
236
  embeddings = model(**inputs)
240
237
 
@@ -244,7 +241,5 @@ class ColPaliEmbedQueryExecutor:
244
241
  f"Expected 3D tensor [batch, tokens, hidden_dim], got shape {embeddings.shape}"
245
242
  )
246
243
 
247
- # Keep token-level embeddings: [batch, tokens, hidden_dim] -> [tokens, hidden_dim]
248
- token_embeddings = embeddings[0] # Remove batch dimension
249
-
250
- return token_embeddings.cpu().to(torch.float32).numpy()
244
+ # [tokens, hidden_dim]
245
+ return embeddings.cpu().to(torch.float32).numpy()
@@ -31,6 +31,7 @@ class SentenceTransformerEmbed(op.FunctionSpec):
31
31
  @op.executor_class(
32
32
  gpu=True,
33
33
  cache=True,
34
+ batching=True,
34
35
  behavior_version=1,
35
36
  arg_relationship=(op.ArgRelationship.EMBEDDING_ORIGIN_TEXT, "text"),
36
37
  )
@@ -57,7 +58,9 @@ class SentenceTransformerEmbedExecutor:
57
58
  dim = self._model.get_sentence_embedding_dimension()
58
59
  return Vector[np.float32, Literal[dim]] # type: ignore
59
60
 
60
- def __call__(self, text: str) -> NDArray[np.float32]:
61
+ def __call__(self, text: list[str]) -> list[NDArray[np.float32]]:
61
62
  assert self._model is not None
62
- result: NDArray[np.float32] = self._model.encode(text, convert_to_numpy=True)
63
- return result
63
+ results: list[NDArray[np.float32]] = self._model.encode(
64
+ text, convert_to_numpy=True
65
+ )
66
+ return results
cocoindex/op.py CHANGED
@@ -32,6 +32,7 @@ from .engine_value import (
32
32
  )
33
33
  from .typing import (
34
34
  KEY_FIELD_NAME,
35
+ AnalyzedListType,
35
36
  AnalyzedTypeInfo,
36
37
  StructSchema,
37
38
  StructType,
@@ -45,6 +46,7 @@ from .typing import (
45
46
  EnrichedValueType,
46
47
  decode_engine_field_schemas,
47
48
  FieldSchema,
49
+ ValueType,
48
50
  )
49
51
  from .runtime import to_async_call
50
52
  from .index import IndexOptions
@@ -149,6 +151,7 @@ class OpArgs:
149
151
  """
150
152
  - gpu: Whether the executor will be executed on GPU.
151
153
  - cache: Whether the executor will be cached.
154
+ - batching: Whether the executor will be batched.
152
155
  - behavior_version: The behavior version of the executor. Cache will be invalidated if it
153
156
  changes. Must be provided if `cache` is True.
154
157
  - arg_relationship: It specifies the relationship between an input argument and the output,
@@ -158,6 +161,7 @@ class OpArgs:
158
161
 
159
162
  gpu: bool = False
160
163
  cache: bool = False
164
+ batching: bool = False
161
165
  behavior_version: int | None = None
162
166
  arg_relationship: tuple[ArgRelationship, str] | None = None
163
167
 
@@ -168,6 +172,16 @@ class _ArgInfo:
168
172
  is_required: bool
169
173
 
170
174
 
175
+ def _make_batched_engine_value_decoder(
176
+ field_path: list[str], src_type: ValueType, dst_type_info: AnalyzedTypeInfo
177
+ ) -> Callable[[Any], Any]:
178
+ if not isinstance(dst_type_info.variant, AnalyzedListType):
179
+ raise ValueError("Expected arguments for batching function to be a list type")
180
+ elem_type_info = analyze_type_info(dst_type_info.variant.elem_type)
181
+ base_decoder = make_engine_value_decoder(field_path, src_type, elem_type_info)
182
+ return lambda value: [base_decoder(v) for v in value]
183
+
184
+
171
185
  def _register_op_factory(
172
186
  category: OpCategory,
173
187
  expected_args: list[tuple[str, inspect.Parameter]],
@@ -181,6 +195,10 @@ def _register_op_factory(
181
195
  Register an op factory.
182
196
  """
183
197
 
198
+ if op_args.batching:
199
+ if len(expected_args) != 1:
200
+ raise ValueError("Batching is only supported for single argument functions")
201
+
184
202
  class _WrappedExecutor:
185
203
  _executor: Any
186
204
  _args_info: list[_ArgInfo]
@@ -208,7 +226,7 @@ def _register_op_factory(
208
226
  """
209
227
  self._args_info = []
210
228
  self._kwargs_info = {}
211
- attributes = []
229
+ attributes = {}
212
230
  potentially_missing_required_arg = False
213
231
 
214
232
  def process_arg(
@@ -220,14 +238,17 @@ def _register_op_factory(
220
238
  if op_args.arg_relationship is not None:
221
239
  related_attr, related_arg_name = op_args.arg_relationship
222
240
  if related_arg_name == arg_name:
223
- attributes.append(
224
- TypeAttr(related_attr.value, actual_arg.analyzed_value)
225
- )
241
+ attributes[related_attr.value] = actual_arg.analyzed_value
226
242
  type_info = analyze_type_info(arg_param.annotation)
227
243
  enriched = EnrichedValueType.decode(actual_arg.value_type)
228
- decoder = make_engine_value_decoder(
229
- [arg_name], enriched.type, type_info
230
- )
244
+ if op_args.batching:
245
+ decoder = _make_batched_engine_value_decoder(
246
+ [arg_name], enriched.type, type_info
247
+ )
248
+ else:
249
+ decoder = make_engine_value_decoder(
250
+ [arg_name], enriched.type, type_info
251
+ )
231
252
  is_required = not type_info.nullable
232
253
  if is_required and actual_arg.value_type.get("nullable", False):
233
254
  potentially_missing_required_arg = True
@@ -302,20 +323,32 @@ def _register_op_factory(
302
323
  if len(missing_args) > 0:
303
324
  raise ValueError(f"Missing arguments: {', '.join(missing_args)}")
304
325
 
326
+ analyzed_expected_return_type = analyze_type_info(expected_return)
327
+ self._result_encoder = make_engine_value_encoder(
328
+ analyzed_expected_return_type
329
+ )
330
+
305
331
  base_analyze_method = getattr(self._executor, "analyze", None)
306
332
  if base_analyze_method is not None:
307
- result_type = base_analyze_method()
333
+ analyzed_result_type = analyze_type_info(base_analyze_method())
308
334
  else:
309
- result_type = expected_return
335
+ if op_args.batching:
336
+ if not isinstance(
337
+ analyzed_expected_return_type.variant, AnalyzedListType
338
+ ):
339
+ raise ValueError(
340
+ "Expected return type for batching function to be a list type"
341
+ )
342
+ analyzed_result_type = analyze_type_info(
343
+ analyzed_expected_return_type.variant.elem_type
344
+ )
345
+ else:
346
+ analyzed_result_type = analyzed_expected_return_type
310
347
  if len(attributes) > 0:
311
- result_type = Annotated[result_type, *attributes]
312
-
313
- analyzed_result_type_info = analyze_type_info(result_type)
314
- encoded_type = encode_enriched_type_info(analyzed_result_type_info)
348
+ analyzed_result_type.attrs = attributes
315
349
  if potentially_missing_required_arg:
316
- encoded_type["nullable"] = True
317
-
318
- self._result_encoder = make_engine_value_encoder(analyzed_result_type_info)
350
+ analyzed_result_type.nullable = True
351
+ encoded_type = encode_enriched_type_info(analyzed_result_type)
319
352
 
320
353
  return encoded_type
321
354
 
@@ -359,7 +392,9 @@ def _register_op_factory(
359
392
 
360
393
  if category == OpCategory.FUNCTION:
361
394
  _engine.register_function_factory(
362
- op_kind, _EngineFunctionExecutorFactory(spec_loader, _WrappedExecutor)
395
+ op_kind,
396
+ _EngineFunctionExecutorFactory(spec_loader, _WrappedExecutor),
397
+ op_args.batching,
363
398
  )
364
399
  else:
365
400
  raise ValueError(f"Unsupported executor type {category}")
cocoindex/runtime.py CHANGED
@@ -6,8 +6,9 @@ manner.
6
6
  import threading
7
7
  import asyncio
8
8
  import inspect
9
- from typing import Any, Callable, Coroutine, TypeVar, Awaitable
9
+ import warnings
10
10
 
11
+ from typing import Any, Callable, Awaitable, TypeVar, Coroutine
11
12
 
12
13
  T = TypeVar("T")
13
14
 
@@ -24,15 +25,44 @@ class _ExecutionContext:
24
25
  """Get the event loop for the cocoindex library."""
25
26
  with self._lock:
26
27
  if self._event_loop is None:
27
- self._event_loop = asyncio.new_event_loop()
28
- threading.Thread(
29
- target=self._event_loop.run_forever, daemon=True
30
- ).start()
28
+ loop = asyncio.new_event_loop()
29
+ self._event_loop = loop
30
+
31
+ def _runner(l: asyncio.AbstractEventLoop) -> None:
32
+ asyncio.set_event_loop(l)
33
+ l.run_forever()
34
+
35
+ threading.Thread(target=_runner, args=(loop,), daemon=True).start()
31
36
  return self._event_loop
32
37
 
33
38
  def run(self, coro: Coroutine[Any, Any, T]) -> T:
34
39
  """Run a coroutine in the event loop, blocking until it finishes. Return its result."""
35
- return asyncio.run_coroutine_threadsafe(coro, self.event_loop).result()
40
+ try:
41
+ running_loop = asyncio.get_running_loop()
42
+ except RuntimeError:
43
+ running_loop = None
44
+
45
+ loop = self.event_loop
46
+
47
+ if running_loop is not None:
48
+ if running_loop is loop:
49
+ raise RuntimeError(
50
+ "CocoIndex sync API was called from inside CocoIndex's async context. "
51
+ "Use the async variant of this method instead."
52
+ )
53
+ warnings.warn(
54
+ "CocoIndex sync API was called inside an existing event loop. "
55
+ "This may block other tasks. Prefer the async method.",
56
+ RuntimeWarning,
57
+ stacklevel=2,
58
+ )
59
+
60
+ fut = asyncio.run_coroutine_threadsafe(coro, loop)
61
+ try:
62
+ return fut.result()
63
+ except KeyboardInterrupt:
64
+ fut.cancel()
65
+ raise
36
66
 
37
67
 
38
68
  execution_context = _ExecutionContext()
@@ -19,7 +19,6 @@ import threading
19
19
  import asyncio
20
20
  import os
21
21
  import time
22
- import atexit
23
22
  from .user_app_loader import load_user_app
24
23
  from .runtime import execution_context
25
24
  import logging
@@ -32,39 +31,14 @@ WATCHDOG_INTERVAL_SECONDS = 10.0
32
31
  # ---------------------------------------------
33
32
  _pool_lock = threading.Lock()
34
33
  _pool: ProcessPoolExecutor | None = None
35
- _pool_cleanup_registered = False
36
34
  _user_apps: list[str] = []
37
35
  _logger = logging.getLogger(__name__)
38
36
 
39
37
 
40
- def shutdown_pool_at_exit() -> None:
41
- """Best-effort shutdown of the global ProcessPoolExecutor on interpreter exit."""
42
- global _pool, _pool_cleanup_registered # pylint: disable=global-statement
43
- with _pool_lock:
44
- if _pool is not None:
45
- try:
46
- _pool.shutdown(wait=True, cancel_futures=True)
47
- except Exception as e:
48
- _logger.error(
49
- "Error during ProcessPoolExecutor shutdown at exit: %s",
50
- e,
51
- exc_info=True,
52
- )
53
- finally:
54
- _pool = None
55
- _pool_cleanup_registered = False
56
-
57
-
58
38
  def _get_pool() -> ProcessPoolExecutor:
59
- global _pool, _pool_cleanup_registered # pylint: disable=global-statement
39
+ global _pool # pylint: disable=global-statement
60
40
  with _pool_lock:
61
41
  if _pool is None:
62
- if not _pool_cleanup_registered:
63
- # Register the shutdown at exit at creation time (rather than at import time)
64
- # to make sure it's executed earlier in the shutdown sequence.
65
- atexit.register(shutdown_pool_at_exit)
66
- _pool_cleanup_registered = True
67
-
68
42
  # Single worker process as requested
69
43
  _pool = ProcessPoolExecutor(
70
44
  max_workers=1,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cocoindex
3
- Version: 0.2.23
3
+ Version: 0.3.1
4
4
  Classifier: Development Status :: 3 - Alpha
5
5
  Classifier: License :: OSI Approved :: Apache Software License
6
6
  Classifier: Operating System :: OS Independent
@@ -1,9 +1,9 @@
1
- cocoindex-0.2.23.dist-info/METADATA,sha256=FkEbYJPJxY3eXRX5B68d_a3GGAXMluA33FediNW8bgg,14427
2
- cocoindex-0.2.23.dist-info/WHEEL,sha256=QC3zdlgimDC1GtRrc0qfjqbzuc7G6nDvPrjaINbNOTw,95
3
- cocoindex-0.2.23.dist-info/entry_points.txt,sha256=_NretjYVzBdNTn7dK-zgwr7YfG2afz1u1uSE-5bZXF8,46
4
- cocoindex-0.2.23.dist-info/licenses/THIRD_PARTY_NOTICES.html,sha256=JkjceWLwTbf-svSD5D0wLkWQTF2nCHB_Ev3THD6IWOQ,750832
1
+ cocoindex-0.3.1.dist-info/METADATA,sha256=XVa358pgFtptG2qP5yJTbxgzqFe_1XjVm0_69HXchTg,14426
2
+ cocoindex-0.3.1.dist-info/WHEEL,sha256=QC3zdlgimDC1GtRrc0qfjqbzuc7G6nDvPrjaINbNOTw,95
3
+ cocoindex-0.3.1.dist-info/entry_points.txt,sha256=_NretjYVzBdNTn7dK-zgwr7YfG2afz1u1uSE-5bZXF8,46
4
+ cocoindex-0.3.1.dist-info/licenses/THIRD_PARTY_NOTICES.html,sha256=_9FT9tv3L_NmA0GOtdkqRZGf_4o5A16ui5YvPPi5-WM,750831
5
5
  cocoindex/__init__.py,sha256=MsjYflfJHL_sKL4OxcExfRwl57JFKwqvt9AWbiHsZ3Q,2744
6
- cocoindex/_engine.pyd,sha256=RfVCWs_NOrLRSwgDVkX7iAodLe4heB8W0pmMbXMc9Mk,77532160
6
+ cocoindex/_engine.pyd,sha256=5SgV6FV9mGZGq6hw0cUg5I8f9lf9lWuGxf2CMwGAkq0,77837312
7
7
  cocoindex/auth_registry.py,sha256=HK1vfKQh_6z310c8kgFDIQf9RdoiA3vWUwvFYbgybr0,1384
8
8
  cocoindex/cli.py,sha256=1Q_c4FzW41FhlCrdJNNkD93Z4zP48hmFzsaU2FJ3wzc,25622
9
9
  cocoindex/engine_object.py,sha256=JH27f2MLNUw3HQy6JuCpvRhMxuKZBkxplLIo0m7PU04,10322
@@ -11,20 +11,20 @@ cocoindex/engine_value.py,sha256=CYS_rdJQZoLEcKVcUXupcH0u8k-6ce80Xrzd3rgUBJE,239
11
11
  cocoindex/flow.py,sha256=MznA23dsIOlu-1uEBe6XVTfYlDjvH3bvky1BCUEnEng,41357
12
12
  cocoindex/functions/__init__.py,sha256=AZ4f7dBVZMkWyR85z9Gy1AgOAB0f1tex62CMP8MDLX4,1061
13
13
  cocoindex/functions/_engine_builtin_specs.py,sha256=6ZV91MUosqGSolnKNUjyRHZ_oTOOsQ_jMMEBGZW1EYo,1852
14
- cocoindex/functions/colpali.py,sha256=kinPow46CSW0PW_-a5PT9JfsCxpvxZG4ZFzQ_OYt9GU,9115
15
- cocoindex/functions/sbert.py,sha256=5X381jQFqnmomj_943Xrhcs1sWecA1sWZfb4On8mONg,2225
14
+ cocoindex/functions/colpali.py,sha256=Got7es-Em9KwWGwJAAXMJNFp1wFcbtEOj6vkV0cqSAA,8869
15
+ cocoindex/functions/sbert.py,sha256=HPieCBNuKRaWRIBIH8hW4ACFtGN2rHpg6N7mfURpUcQ,2289
16
16
  cocoindex/index.py,sha256=C__LzwIC918VIDGsBsyLwvNBO-4BiC5Coq01Fp1zXkI,1032
17
17
  cocoindex/lib.py,sha256=cyKGdn8cfH9bkYfrnJ7dlUBO8OVZkKyrkYhWHsMFW_g,2365
18
18
  cocoindex/llm.py,sha256=zvdvdFPsLdkVVRdNawOubkEtvdKXI_BlfJIFcDu0S6o,922
19
- cocoindex/op.py,sha256=pMMgPJ7KVuU1ptTIDJB9yVEntaeOrZ4in16H0Zqa1JE,37100
19
+ cocoindex/op.py,sha256=57OypW_F2j22xBM8W1iNVAX9iTQ4qs3cm-HqYoJ4lz0,38712
20
20
  cocoindex/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
21
  cocoindex/query_handler.py,sha256=vsw-VQ-Fh0ekr4boKchI0wpKHqaiBoeNStClrW4Zwog,1401
22
- cocoindex/runtime.py,sha256=ZjyPmohIWGFDRaOdS0MgeVuf4Ra2Ggbp6xraxwvHFBo,1386
22
+ cocoindex/runtime.py,sha256=h52Pj6kgHK6_87Rmm3D0HDvDQePPHCoktOk5az553KM,2372
23
23
  cocoindex/setting.py,sha256=oohs7H52_h1AulDcp96cS9SVAAm_uFaQyJYog9EvCj0,5131
24
24
  cocoindex/setup.py,sha256=KbJvmeFu0NbeoH-5iDmHZP86f26HIId8kHmGUNZAePI,3160
25
25
  cocoindex/sources/__init__.py,sha256=urtXAOyZFShYYZKpp2pISzoT4sHKFoX3_nYII3pAsHA,83
26
26
  cocoindex/sources/_engine_builtin_specs.py,sha256=J8RBT6b2WEL-varvTA-ti1aYcFfJ4WQ76JZdY7y4fYs,3714
27
- cocoindex/subprocess_exec.py,sha256=u_kF4C8dToPg-9a7NeFroR8pJCOFag_NT0icLe184QQ,10391
27
+ cocoindex/subprocess_exec.py,sha256=HHYclyNvaG0IO2GpA3qGcbd874lYDX6EQn-AdmJ3Qqw,9317
28
28
  cocoindex/targets/__init__.py,sha256=6cO57jLhBloC1o-sBHG6OXfIgBdRQtz5RDi6FLqlQhU,83
29
29
  cocoindex/targets/_engine_builtin_specs.py,sha256=iDVooiyLlr9DFuUCDwYyjeaVOELgzay5U3ME8VdDHo8,3528
30
30
  cocoindex/targets/lancedb.py,sha256=RQZREffJMsO75W6SuvNnFBufMGEaJatHQa-f70dIUGc,16215
@@ -39,4 +39,4 @@ cocoindex/typing.py,sha256=dC8CmltIbT85TAgiFXwmHT_lePdiHRQLrURjgZWF6oo,24716
39
39
  cocoindex/user_app_loader.py,sha256=ZkvUG9aJNNECAjwTY0ZYtNpFd9dNBPVoPKGTtB7dSZg,1926
40
40
  cocoindex/utils.py,sha256=U3W39zD2uZpXX8v84tJD7sRmbC5ar3z_ljAP1cJrYXI,618
41
41
  cocoindex/validation.py,sha256=4ZjsW-SZT8X_TEEhEE6QG6D-8Oq_TkPAhTqP0mdFYSE,3194
42
- cocoindex-0.2.23.dist-info/RECORD,,
42
+ cocoindex-0.3.1.dist-info/RECORD,,
@@ -2846,7 +2846,7 @@ Software.
2846
2846
  <h3 id="Apache-2.0">Apache License 2.0</h3>
2847
2847
  <h4>Used by:</h4>
2848
2848
  <ul class="license-used-by">
2849
- <li><a href=" https://crates.io/crates/cocoindex ">cocoindex 0.2.23</a></li>
2849
+ <li><a href=" https://crates.io/crates/cocoindex ">cocoindex 0.3.1</a></li>
2850
2850
  <li><a href=" https://github.com/awesomized/crc-fast-rust ">crc-fast 1.3.0</a></li>
2851
2851
  <li><a href=" https://github.com/qdrant/rust-client ">qdrant-client 1.15.0</a></li>
2852
2852
  </ul>