cocoindex 0.3.4__cp311-abi3-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/__init__.py +114 -0
- cocoindex/_engine.abi3.so +0 -0
- cocoindex/auth_registry.py +44 -0
- cocoindex/cli.py +830 -0
- cocoindex/engine_object.py +214 -0
- cocoindex/engine_value.py +550 -0
- cocoindex/flow.py +1281 -0
- cocoindex/functions/__init__.py +40 -0
- cocoindex/functions/_engine_builtin_specs.py +66 -0
- cocoindex/functions/colpali.py +247 -0
- cocoindex/functions/sbert.py +77 -0
- cocoindex/index.py +50 -0
- cocoindex/lib.py +75 -0
- cocoindex/llm.py +47 -0
- cocoindex/op.py +1047 -0
- cocoindex/py.typed +0 -0
- cocoindex/query_handler.py +57 -0
- cocoindex/runtime.py +78 -0
- cocoindex/setting.py +171 -0
- cocoindex/setup.py +92 -0
- cocoindex/sources/__init__.py +5 -0
- cocoindex/sources/_engine_builtin_specs.py +120 -0
- cocoindex/subprocess_exec.py +277 -0
- cocoindex/targets/__init__.py +5 -0
- cocoindex/targets/_engine_builtin_specs.py +153 -0
- cocoindex/targets/lancedb.py +466 -0
- cocoindex/tests/__init__.py +0 -0
- cocoindex/tests/test_engine_object.py +331 -0
- cocoindex/tests/test_engine_value.py +1724 -0
- cocoindex/tests/test_optional_database.py +249 -0
- cocoindex/tests/test_transform_flow.py +300 -0
- cocoindex/tests/test_typing.py +553 -0
- cocoindex/tests/test_validation.py +134 -0
- cocoindex/typing.py +834 -0
- cocoindex/user_app_loader.py +53 -0
- cocoindex/utils.py +20 -0
- cocoindex/validation.py +104 -0
- cocoindex-0.3.4.dist-info/METADATA +288 -0
- cocoindex-0.3.4.dist-info/RECORD +42 -0
- cocoindex-0.3.4.dist-info/WHEEL +4 -0
- cocoindex-0.3.4.dist-info/entry_points.txt +2 -0
- cocoindex-0.3.4.dist-info/licenses/THIRD_PARTY_NOTICES.html +13249 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"""Functions module for cocoindex.
|
|
2
|
+
|
|
3
|
+
This module provides various function specifications and executors for data processing,
|
|
4
|
+
including embedding functions, text processing, and multimodal operations.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
# Import all engine builtin function specs
|
|
8
|
+
from ._engine_builtin_specs import *
|
|
9
|
+
|
|
10
|
+
# Import SentenceTransformer embedding functionality
|
|
11
|
+
from .sbert import (
|
|
12
|
+
SentenceTransformerEmbed,
|
|
13
|
+
SentenceTransformerEmbedExecutor,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
# Import ColPali multimodal embedding functionality
|
|
17
|
+
from .colpali import (
|
|
18
|
+
ColPaliEmbedImage,
|
|
19
|
+
ColPaliEmbedImageExecutor,
|
|
20
|
+
ColPaliEmbedQuery,
|
|
21
|
+
ColPaliEmbedQueryExecutor,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
__all__ = [
|
|
25
|
+
# Engine builtin specs
|
|
26
|
+
"DetectProgrammingLanguage",
|
|
27
|
+
"EmbedText",
|
|
28
|
+
"ExtractByLlm",
|
|
29
|
+
"ParseJson",
|
|
30
|
+
"SplitBySeparators",
|
|
31
|
+
"SplitRecursively",
|
|
32
|
+
# SentenceTransformer
|
|
33
|
+
"SentenceTransformerEmbed",
|
|
34
|
+
"SentenceTransformerEmbedExecutor",
|
|
35
|
+
# ColPali
|
|
36
|
+
"ColPaliEmbedImage",
|
|
37
|
+
"ColPaliEmbedImageExecutor",
|
|
38
|
+
"ColPaliEmbedQuery",
|
|
39
|
+
"ColPaliEmbedQueryExecutor",
|
|
40
|
+
]
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"""All builtin function specs."""
|
|
2
|
+
|
|
3
|
+
import dataclasses
|
|
4
|
+
from typing import Literal
|
|
5
|
+
|
|
6
|
+
from .. import llm, op
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ParseJson(op.FunctionSpec):
|
|
10
|
+
"""Parse a text into a JSON object."""
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclasses.dataclass
|
|
14
|
+
class CustomLanguageSpec:
|
|
15
|
+
"""Custom language specification."""
|
|
16
|
+
|
|
17
|
+
language_name: str
|
|
18
|
+
separators_regex: list[str]
|
|
19
|
+
aliases: list[str] = dataclasses.field(default_factory=list)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class DetectProgrammingLanguage(op.FunctionSpec):
|
|
23
|
+
"""Detect the programming language of a file."""
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class SplitRecursively(op.FunctionSpec):
|
|
27
|
+
"""Split a document (in string) recursively."""
|
|
28
|
+
|
|
29
|
+
custom_languages: list[CustomLanguageSpec] = dataclasses.field(default_factory=list)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class SplitBySeparators(op.FunctionSpec):
|
|
33
|
+
"""
|
|
34
|
+
Split text by specified regex separators only.
|
|
35
|
+
Output schema matches SplitRecursively for drop-in compatibility:
|
|
36
|
+
KTable rows with fields: location (Range), text (Str), start, end.
|
|
37
|
+
Args:
|
|
38
|
+
separators_regex: list[str] # e.g., [r"\\n\\n+"]
|
|
39
|
+
keep_separator: Literal["NONE", "LEFT", "RIGHT"] = "NONE"
|
|
40
|
+
include_empty: bool = False
|
|
41
|
+
trim: bool = True
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
separators_regex: list[str] = dataclasses.field(default_factory=list)
|
|
45
|
+
keep_separator: Literal["NONE", "LEFT", "RIGHT"] = "NONE"
|
|
46
|
+
include_empty: bool = False
|
|
47
|
+
trim: bool = True
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class EmbedText(op.FunctionSpec):
|
|
51
|
+
"""Embed a text into a vector space."""
|
|
52
|
+
|
|
53
|
+
api_type: llm.LlmApiType
|
|
54
|
+
model: str
|
|
55
|
+
address: str | None = None
|
|
56
|
+
output_dimension: int | None = None
|
|
57
|
+
task_type: str | None = None
|
|
58
|
+
api_config: llm.VertexAiConfig | None = None
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class ExtractByLlm(op.FunctionSpec):
|
|
62
|
+
"""Extract information from a text using a LLM."""
|
|
63
|
+
|
|
64
|
+
llm_spec: llm.LlmSpec
|
|
65
|
+
output_type: type
|
|
66
|
+
instruction: str | None = None
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
"""ColPali image and query embedding functions for multimodal document retrieval."""
|
|
2
|
+
|
|
3
|
+
import functools
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from typing import Any, TYPE_CHECKING, Literal
|
|
6
|
+
import numpy as np
|
|
7
|
+
|
|
8
|
+
from .. import op
|
|
9
|
+
from ..typing import Vector
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
import torch
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass
|
|
16
|
+
class ColPaliModelInfo:
|
|
17
|
+
"""Shared model information for ColPali embedding functions."""
|
|
18
|
+
|
|
19
|
+
model: Any
|
|
20
|
+
processor: Any
|
|
21
|
+
device: Any
|
|
22
|
+
dimension: int
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@functools.cache
|
|
26
|
+
def _get_colpali_model_and_processor(model_name: str) -> ColPaliModelInfo:
|
|
27
|
+
"""Load and cache ColPali model and processor with shared device setup."""
|
|
28
|
+
try:
|
|
29
|
+
import colpali_engine as ce # type: ignore[import-untyped]
|
|
30
|
+
import torch
|
|
31
|
+
except ImportError as e:
|
|
32
|
+
raise ImportError(
|
|
33
|
+
"ColPali support requires the optional 'colpali' dependency. "
|
|
34
|
+
"Install it with: pip install 'cocoindex[colpali]'"
|
|
35
|
+
) from e
|
|
36
|
+
|
|
37
|
+
device = "cuda" if torch.cuda.is_available() else "cpu"
|
|
38
|
+
lower_model_name = model_name.lower()
|
|
39
|
+
|
|
40
|
+
# Determine model type from name
|
|
41
|
+
if lower_model_name.startswith("colpali"):
|
|
42
|
+
model = ce.ColPali.from_pretrained(
|
|
43
|
+
model_name, torch_dtype=torch.bfloat16, device_map=device
|
|
44
|
+
)
|
|
45
|
+
processor = ce.ColPaliProcessor.from_pretrained(model_name)
|
|
46
|
+
elif lower_model_name.startswith("colqwen2.5"):
|
|
47
|
+
model = ce.ColQwen2_5.from_pretrained(
|
|
48
|
+
model_name, torch_dtype=torch.bfloat16, device_map=device
|
|
49
|
+
)
|
|
50
|
+
processor = ce.ColQwen2_5_Processor.from_pretrained(model_name)
|
|
51
|
+
elif lower_model_name.startswith("colqwen"):
|
|
52
|
+
model = ce.ColQwen2.from_pretrained(
|
|
53
|
+
model_name, torch_dtype=torch.bfloat16, device_map=device
|
|
54
|
+
)
|
|
55
|
+
processor = ce.ColQwen2Processor.from_pretrained(model_name)
|
|
56
|
+
else:
|
|
57
|
+
# Fallback to ColPali for backwards compatibility
|
|
58
|
+
model = ce.ColPali.from_pretrained(
|
|
59
|
+
model_name, torch_dtype=torch.bfloat16, device_map=device
|
|
60
|
+
)
|
|
61
|
+
processor = ce.ColPaliProcessor.from_pretrained(model_name)
|
|
62
|
+
|
|
63
|
+
# Detect dimension
|
|
64
|
+
dimension = _detect_colpali_dimension(model, processor, device)
|
|
65
|
+
|
|
66
|
+
return ColPaliModelInfo(
|
|
67
|
+
model=model,
|
|
68
|
+
processor=processor,
|
|
69
|
+
dimension=dimension,
|
|
70
|
+
device=device,
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _detect_colpali_dimension(model: Any, processor: Any, device: Any) -> int:
|
|
75
|
+
"""Detect ColPali embedding dimension from the actual model config."""
|
|
76
|
+
# Try to access embedding dimension
|
|
77
|
+
if hasattr(model.config, "embedding_dim"):
|
|
78
|
+
dim = model.config.embedding_dim
|
|
79
|
+
else:
|
|
80
|
+
# Fallback: infer from output shape with dummy data
|
|
81
|
+
from PIL import Image
|
|
82
|
+
import numpy as np
|
|
83
|
+
import torch
|
|
84
|
+
|
|
85
|
+
dummy_img = Image.fromarray(np.zeros((224, 224, 3), np.uint8))
|
|
86
|
+
# Use the processor to process the dummy image
|
|
87
|
+
processed = processor.process_images([dummy_img]).to(device)
|
|
88
|
+
with torch.no_grad():
|
|
89
|
+
output = model(**processed)
|
|
90
|
+
dim = int(output.shape[-1])
|
|
91
|
+
if isinstance(dim, int):
|
|
92
|
+
return dim
|
|
93
|
+
else:
|
|
94
|
+
raise ValueError(f"Expected integer dimension, got {type(dim)}: {dim}")
|
|
95
|
+
return dim
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
class ColPaliEmbedImage(op.FunctionSpec):
|
|
99
|
+
"""
|
|
100
|
+
`ColPaliEmbedImage` embeds images using ColVision multimodal models.
|
|
101
|
+
|
|
102
|
+
Supports ALL models available in the colpali-engine library, including:
|
|
103
|
+
- ColPali models (colpali-*): PaliGemma-based, best for general document retrieval
|
|
104
|
+
- ColQwen2 models (colqwen-*): Qwen2-VL-based, excellent for multilingual text (29+ languages) and general vision
|
|
105
|
+
- ColSmol models (colsmol-*): Lightweight, good for resource-constrained environments
|
|
106
|
+
- Any future ColVision models supported by colpali-engine
|
|
107
|
+
|
|
108
|
+
These models use late interaction between image patch embeddings and text token
|
|
109
|
+
embeddings for retrieval.
|
|
110
|
+
|
|
111
|
+
Args:
|
|
112
|
+
model: Any ColVision model name supported by colpali-engine
|
|
113
|
+
(e.g., "vidore/colpali-v1.2", "vidore/colqwen2.5-v0.2", "vidore/colsmol-v1.0")
|
|
114
|
+
See https://github.com/illuin-tech/colpali for the complete list of supported models.
|
|
115
|
+
|
|
116
|
+
Note:
|
|
117
|
+
This function requires the optional colpali-engine dependency.
|
|
118
|
+
Install it with: pip install 'cocoindex[colpali]'
|
|
119
|
+
"""
|
|
120
|
+
|
|
121
|
+
model: str
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
@op.executor_class(
|
|
125
|
+
gpu=True,
|
|
126
|
+
cache=True,
|
|
127
|
+
batching=True,
|
|
128
|
+
max_batch_size=32,
|
|
129
|
+
behavior_version=1,
|
|
130
|
+
)
|
|
131
|
+
class ColPaliEmbedImageExecutor:
|
|
132
|
+
"""Executor for ColVision image embedding (ColPali, ColQwen2, ColSmol, etc.)."""
|
|
133
|
+
|
|
134
|
+
spec: ColPaliEmbedImage
|
|
135
|
+
_model_info: ColPaliModelInfo
|
|
136
|
+
|
|
137
|
+
def analyze(self) -> type:
|
|
138
|
+
# Get shared model and dimension
|
|
139
|
+
self._model_info = _get_colpali_model_and_processor(self.spec.model)
|
|
140
|
+
|
|
141
|
+
# Return multi-vector type: Variable patches x Fixed hidden dimension
|
|
142
|
+
dimension = self._model_info.dimension
|
|
143
|
+
return Vector[Vector[np.float32, Literal[dimension]]] # type: ignore
|
|
144
|
+
|
|
145
|
+
def __call__(self, img_bytes_list: list[bytes]) -> Any:
|
|
146
|
+
try:
|
|
147
|
+
from PIL import Image
|
|
148
|
+
import torch
|
|
149
|
+
import io
|
|
150
|
+
except ImportError as e:
|
|
151
|
+
raise ImportError(
|
|
152
|
+
"Required dependencies (PIL, torch) are missing for ColVision image embedding."
|
|
153
|
+
) from e
|
|
154
|
+
|
|
155
|
+
model = self._model_info.model
|
|
156
|
+
processor = self._model_info.processor
|
|
157
|
+
device = self._model_info.device
|
|
158
|
+
|
|
159
|
+
pil_images = [
|
|
160
|
+
Image.open(io.BytesIO(img_bytes)).convert("RGB")
|
|
161
|
+
for img_bytes in img_bytes_list
|
|
162
|
+
]
|
|
163
|
+
inputs = processor.process_images(pil_images).to(device)
|
|
164
|
+
with torch.no_grad():
|
|
165
|
+
embeddings = model(**inputs)
|
|
166
|
+
|
|
167
|
+
# Return multi-vector format: [patches, hidden_dim]
|
|
168
|
+
if len(embeddings.shape) != 3:
|
|
169
|
+
raise ValueError(
|
|
170
|
+
f"Expected 3D tensor [batch, patches, hidden_dim], got shape {embeddings.shape}"
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
# [patches, hidden_dim]
|
|
174
|
+
return embeddings.cpu().to(torch.float32).numpy()
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
class ColPaliEmbedQuery(op.FunctionSpec):
|
|
178
|
+
"""
|
|
179
|
+
`ColPaliEmbedQuery` embeds text queries using ColVision multimodal models.
|
|
180
|
+
|
|
181
|
+
Supports ALL models available in the colpali-engine library, including:
|
|
182
|
+
- ColPali models (colpali-*): PaliGemma-based, best for general document retrieval
|
|
183
|
+
- ColQwen2 models (colqwen-*): Qwen2-VL-based, excellent for multilingual text (29+ languages) and general vision
|
|
184
|
+
- ColSmol models (colsmol-*): Lightweight, good for resource-constrained environments
|
|
185
|
+
- Any future ColVision models supported by colpali-engine
|
|
186
|
+
|
|
187
|
+
This produces query embeddings compatible with ColVision image embeddings
|
|
188
|
+
for late interaction scoring (MaxSim).
|
|
189
|
+
|
|
190
|
+
Args:
|
|
191
|
+
model: Any ColVision model name supported by colpali-engine
|
|
192
|
+
(e.g., "vidore/colpali-v1.2", "vidore/colqwen2.5-v0.2", "vidore/colsmol-v1.0")
|
|
193
|
+
See https://github.com/illuin-tech/colpali for the complete list of supported models.
|
|
194
|
+
|
|
195
|
+
Note:
|
|
196
|
+
This function requires the optional colpali-engine dependency.
|
|
197
|
+
Install it with: pip install 'cocoindex[colpali]'
|
|
198
|
+
"""
|
|
199
|
+
|
|
200
|
+
model: str
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
@op.executor_class(
|
|
204
|
+
gpu=True,
|
|
205
|
+
cache=True,
|
|
206
|
+
behavior_version=1,
|
|
207
|
+
batching=True,
|
|
208
|
+
max_batch_size=32,
|
|
209
|
+
)
|
|
210
|
+
class ColPaliEmbedQueryExecutor:
|
|
211
|
+
"""Executor for ColVision query embedding (ColPali, ColQwen2, ColSmol, etc.)."""
|
|
212
|
+
|
|
213
|
+
spec: ColPaliEmbedQuery
|
|
214
|
+
_model_info: ColPaliModelInfo
|
|
215
|
+
|
|
216
|
+
def analyze(self) -> type:
|
|
217
|
+
# Get shared model and dimension
|
|
218
|
+
self._model_info = _get_colpali_model_and_processor(self.spec.model)
|
|
219
|
+
|
|
220
|
+
# Return multi-vector type: Variable tokens x Fixed hidden dimension
|
|
221
|
+
dimension = self._model_info.dimension
|
|
222
|
+
return Vector[Vector[np.float32, Literal[dimension]]] # type: ignore
|
|
223
|
+
|
|
224
|
+
def __call__(self, queries: list[str]) -> Any:
|
|
225
|
+
try:
|
|
226
|
+
import torch
|
|
227
|
+
except ImportError as e:
|
|
228
|
+
raise ImportError(
|
|
229
|
+
"Required dependencies (torch) are missing for ColVision query embedding."
|
|
230
|
+
) from e
|
|
231
|
+
|
|
232
|
+
model = self._model_info.model
|
|
233
|
+
processor = self._model_info.processor
|
|
234
|
+
device = self._model_info.device
|
|
235
|
+
|
|
236
|
+
inputs = processor.process_queries(queries).to(device)
|
|
237
|
+
with torch.no_grad():
|
|
238
|
+
embeddings = model(**inputs)
|
|
239
|
+
|
|
240
|
+
# Return multi-vector format: [tokens, hidden_dim]
|
|
241
|
+
if len(embeddings.shape) != 3:
|
|
242
|
+
raise ValueError(
|
|
243
|
+
f"Expected 3D tensor [batch, tokens, hidden_dim], got shape {embeddings.shape}"
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
# [tokens, hidden_dim]
|
|
247
|
+
return embeddings.cpu().to(torch.float32).numpy()
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"""SentenceTransformer embedding functionality."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Literal, cast
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
from numpy.typing import NDArray
|
|
7
|
+
|
|
8
|
+
from .. import op
|
|
9
|
+
from ..typing import Vector
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class SentenceTransformerEmbed(op.FunctionSpec):
|
|
13
|
+
"""
|
|
14
|
+
`SentenceTransformerEmbed` embeds a text into a vector space using the [SentenceTransformer](https://huggingface.co/sentence-transformers) library.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
|
|
18
|
+
model: The name of the SentenceTransformer model to use.
|
|
19
|
+
args: Additional arguments to pass to the SentenceTransformer constructor. e.g. {"trust_remote_code": True}
|
|
20
|
+
|
|
21
|
+
Note:
|
|
22
|
+
This function requires the optional sentence-transformers dependency.
|
|
23
|
+
Install it with: pip install 'cocoindex[embeddings]'
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
model: str
|
|
27
|
+
args: dict[str, Any] | None = None
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@op.executor_class(
|
|
31
|
+
gpu=True,
|
|
32
|
+
cache=True,
|
|
33
|
+
batching=True,
|
|
34
|
+
max_batch_size=512,
|
|
35
|
+
behavior_version=1,
|
|
36
|
+
arg_relationship=(op.ArgRelationship.EMBEDDING_ORIGIN_TEXT, "text"),
|
|
37
|
+
)
|
|
38
|
+
class SentenceTransformerEmbedExecutor:
|
|
39
|
+
"""Executor for SentenceTransformerEmbed."""
|
|
40
|
+
|
|
41
|
+
spec: SentenceTransformerEmbed
|
|
42
|
+
_model: Any | None = None
|
|
43
|
+
|
|
44
|
+
def analyze(self) -> type:
|
|
45
|
+
try:
|
|
46
|
+
# Only import sentence_transformers locally when it's needed, as its import is very slow.
|
|
47
|
+
import sentence_transformers # pylint: disable=import-outside-toplevel
|
|
48
|
+
except ImportError as e:
|
|
49
|
+
raise ImportError(
|
|
50
|
+
"sentence_transformers is required for SentenceTransformerEmbed function. "
|
|
51
|
+
"Install it with one of these commands:\n"
|
|
52
|
+
" pip install 'cocoindex[embeddings]'\n"
|
|
53
|
+
" pip install sentence-transformers"
|
|
54
|
+
) from e
|
|
55
|
+
|
|
56
|
+
args = self.spec.args or {}
|
|
57
|
+
self._model = sentence_transformers.SentenceTransformer(self.spec.model, **args)
|
|
58
|
+
dim = self._model.get_sentence_embedding_dimension()
|
|
59
|
+
return Vector[np.float32, Literal[dim]] # type: ignore
|
|
60
|
+
|
|
61
|
+
def __call__(self, text: list[str]) -> list[NDArray[np.float32]]:
|
|
62
|
+
assert self._model is not None
|
|
63
|
+
|
|
64
|
+
# Sort the text by length to minimize the number of padding tokens.
|
|
65
|
+
text_with_idx = [(idx, t) for idx, t in enumerate(text)]
|
|
66
|
+
text_with_idx.sort(key=lambda x: len(x[1]))
|
|
67
|
+
|
|
68
|
+
results: list[NDArray[np.float32]] = self._model.encode(
|
|
69
|
+
[t for _, t in text_with_idx], convert_to_numpy=True
|
|
70
|
+
)
|
|
71
|
+
final_results: list[NDArray[np.float32] | None] = [
|
|
72
|
+
None for _ in range(len(text))
|
|
73
|
+
]
|
|
74
|
+
for (idx, _), result in zip(text_with_idx, results):
|
|
75
|
+
final_results[idx] = result
|
|
76
|
+
|
|
77
|
+
return cast(list[NDArray[np.float32]], final_results)
|
cocoindex/index.py
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from typing import Sequence, Union
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class VectorSimilarityMetric(Enum):
|
|
7
|
+
COSINE_SIMILARITY = "CosineSimilarity"
|
|
8
|
+
L2_DISTANCE = "L2Distance"
|
|
9
|
+
INNER_PRODUCT = "InnerProduct"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class HnswVectorIndexMethod:
|
|
14
|
+
"""HNSW vector index parameters."""
|
|
15
|
+
|
|
16
|
+
kind: str = "Hnsw"
|
|
17
|
+
m: int | None = None
|
|
18
|
+
ef_construction: int | None = None
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@dataclass
|
|
22
|
+
class IvfFlatVectorIndexMethod:
|
|
23
|
+
"""IVFFlat vector index parameters."""
|
|
24
|
+
|
|
25
|
+
kind: str = "IvfFlat"
|
|
26
|
+
lists: int | None = None
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
VectorIndexMethod = Union[HnswVectorIndexMethod, IvfFlatVectorIndexMethod]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@dataclass
|
|
33
|
+
class VectorIndexDef:
|
|
34
|
+
"""
|
|
35
|
+
Define a vector index on a field.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
field_name: str
|
|
39
|
+
metric: VectorSimilarityMetric
|
|
40
|
+
method: VectorIndexMethod | None = None
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@dataclass
|
|
44
|
+
class IndexOptions:
|
|
45
|
+
"""
|
|
46
|
+
Options for an index.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
primary_key_fields: Sequence[str]
|
|
50
|
+
vector_indexes: Sequence[VectorIndexDef] = ()
|
cocoindex/lib.py
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Library level functions and states.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import threading
|
|
6
|
+
import warnings
|
|
7
|
+
|
|
8
|
+
from . import _engine # type: ignore
|
|
9
|
+
from . import flow, setting
|
|
10
|
+
from .engine_object import dump_engine_object
|
|
11
|
+
from .validation import validate_app_namespace_name
|
|
12
|
+
from typing import Any, Callable, overload
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def prepare_settings(settings: setting.Settings) -> Any:
|
|
16
|
+
"""Prepare the settings for the engine."""
|
|
17
|
+
if settings.app_namespace:
|
|
18
|
+
validate_app_namespace_name(settings.app_namespace)
|
|
19
|
+
return dump_engine_object(settings)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
_engine.set_settings_fn(lambda: prepare_settings(setting.Settings.from_env()))
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
_prev_settings_fn: Callable[[], setting.Settings] | None = None
|
|
26
|
+
_prev_settings_fn_lock: threading.Lock = threading.Lock()
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@overload
|
|
30
|
+
def settings(fn: Callable[[], setting.Settings]) -> Callable[[], setting.Settings]: ...
|
|
31
|
+
@overload
|
|
32
|
+
def settings(
|
|
33
|
+
fn: None,
|
|
34
|
+
) -> Callable[[Callable[[], setting.Settings]], Callable[[], setting.Settings]]: ...
|
|
35
|
+
def settings(fn: Callable[[], setting.Settings] | None = None) -> Any:
|
|
36
|
+
"""
|
|
37
|
+
Decorate a function that returns a settings.Settings object.
|
|
38
|
+
It registers the function as a settings provider.
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
def _inner(fn: Callable[[], setting.Settings]) -> Callable[[], setting.Settings]:
|
|
42
|
+
global _prev_settings_fn # pylint: disable=global-statement
|
|
43
|
+
with _prev_settings_fn_lock:
|
|
44
|
+
if _prev_settings_fn is not None:
|
|
45
|
+
warnings.warn(
|
|
46
|
+
f"Setting a new settings function will override the previous one {_prev_settings_fn}."
|
|
47
|
+
)
|
|
48
|
+
_prev_settings_fn = fn
|
|
49
|
+
_engine.set_settings_fn(lambda: prepare_settings(fn()))
|
|
50
|
+
return fn
|
|
51
|
+
|
|
52
|
+
if fn is not None:
|
|
53
|
+
return _inner(fn)
|
|
54
|
+
else:
|
|
55
|
+
return _inner
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def init(settings: setting.Settings | None = None) -> None:
|
|
59
|
+
"""
|
|
60
|
+
Initialize the cocoindex library.
|
|
61
|
+
|
|
62
|
+
If the settings are not provided, they are loaded from the environment variables.
|
|
63
|
+
"""
|
|
64
|
+
_engine.init(prepare_settings(settings) if settings is not None else None)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def start_server(settings: setting.ServerSettings) -> None:
|
|
68
|
+
"""Start the cocoindex server."""
|
|
69
|
+
flow.ensure_all_flows_built()
|
|
70
|
+
_engine.start_server(settings.__dict__)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def stop() -> None:
|
|
74
|
+
"""Stop the cocoindex library."""
|
|
75
|
+
_engine.stop()
|
cocoindex/llm.py
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from enum import Enum
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class LlmApiType(Enum):
|
|
6
|
+
"""The type of LLM API to use."""
|
|
7
|
+
|
|
8
|
+
OPENAI = "OpenAi"
|
|
9
|
+
OLLAMA = "Ollama"
|
|
10
|
+
GEMINI = "Gemini"
|
|
11
|
+
VERTEX_AI = "VertexAi"
|
|
12
|
+
ANTHROPIC = "Anthropic"
|
|
13
|
+
LITE_LLM = "LiteLlm"
|
|
14
|
+
OPEN_ROUTER = "OpenRouter"
|
|
15
|
+
VOYAGE = "Voyage"
|
|
16
|
+
VLLM = "Vllm"
|
|
17
|
+
BEDROCK = "Bedrock"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass
|
|
21
|
+
class VertexAiConfig:
|
|
22
|
+
"""A specification for a Vertex AI LLM."""
|
|
23
|
+
|
|
24
|
+
kind = "VertexAi"
|
|
25
|
+
|
|
26
|
+
project: str
|
|
27
|
+
region: str | None = None
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@dataclass
|
|
31
|
+
class OpenAiConfig:
|
|
32
|
+
"""A specification for a OpenAI LLM."""
|
|
33
|
+
|
|
34
|
+
kind = "OpenAi"
|
|
35
|
+
|
|
36
|
+
org_id: str | None = None
|
|
37
|
+
project_id: str | None = None
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@dataclass
|
|
41
|
+
class LlmSpec:
|
|
42
|
+
"""A specification for a LLM."""
|
|
43
|
+
|
|
44
|
+
api_type: LlmApiType
|
|
45
|
+
model: str
|
|
46
|
+
address: str | None = None
|
|
47
|
+
api_config: VertexAiConfig | OpenAiConfig | None = None
|