libembedding-ng 1.0.1__py3-none-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.
- libembedding/__init__.py +48 -0
- libembedding/_binding.py +31 -0
- libembedding/_cdefs.h +319 -0
- libembedding/_status.py +36 -0
- libembedding/exceptions.py +47 -0
- libembedding/image_embedding.py +197 -0
- libembedding/libcurl.dll +0 -0
- libembedding/libembedding.dll +0 -0
- libembedding/models.py +128 -0
- libembedding/onnxruntime.dll +0 -0
- libembedding/onnxruntime_providers_shared.dll +0 -0
- libembedding/reranker.py +157 -0
- libembedding/similarity.py +40 -0
- libembedding/sparse_text_embedding.py +163 -0
- libembedding/text_embedding.py +206 -0
- libembedding/types.py +57 -0
- libembedding/z.dll +0 -0
- libembedding_ng-1.0.1.dist-info/METADATA +366 -0
- libembedding_ng-1.0.1.dist-info/RECORD +22 -0
- libembedding_ng-1.0.1.dist-info/WHEEL +5 -0
- libembedding_ng-1.0.1.dist-info/licenses/LICENSE +21 -0
- libembedding_ng-1.0.1.dist-info/top_level.txt +1 -0
libembedding/__init__.py
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""libembedding — Fast ONNX-based text, image, and sparse embeddings for Python."""
|
|
2
|
+
|
|
3
|
+
try:
|
|
4
|
+
from importlib.metadata import version, PackageNotFoundError
|
|
5
|
+
__version__ = version("libembedding-ng")
|
|
6
|
+
except PackageNotFoundError:
|
|
7
|
+
__version__ = "0.0.0"
|
|
8
|
+
|
|
9
|
+
from .text_embedding import TextEmbedding
|
|
10
|
+
from .sparse_text_embedding import SparseTextEmbedding
|
|
11
|
+
from .image_embedding import ImageEmbedding
|
|
12
|
+
from .reranker import Reranker
|
|
13
|
+
from .types import SparseEmbedding, RerankResult, ModelInfo, ModelDesc, Stats
|
|
14
|
+
from .models import (
|
|
15
|
+
list_text_models,
|
|
16
|
+
list_sparse_models,
|
|
17
|
+
list_image_models,
|
|
18
|
+
list_reranker_models,
|
|
19
|
+
)
|
|
20
|
+
from .similarity import cosine_similarity, dot_product, euclidean_distance
|
|
21
|
+
from .exceptions import LembedError
|
|
22
|
+
|
|
23
|
+
# Version from C API (runtime)
|
|
24
|
+
try:
|
|
25
|
+
from ._binding import lib
|
|
26
|
+
__version__ = lib.lembed_version().decode("utf-8", errors="replace")
|
|
27
|
+
except Exception:
|
|
28
|
+
pass # fall back to importlib.metadata version above
|
|
29
|
+
|
|
30
|
+
__all__ = [
|
|
31
|
+
"TextEmbedding",
|
|
32
|
+
"SparseTextEmbedding",
|
|
33
|
+
"ImageEmbedding",
|
|
34
|
+
"Reranker",
|
|
35
|
+
"SparseEmbedding",
|
|
36
|
+
"RerankResult",
|
|
37
|
+
"ModelInfo",
|
|
38
|
+
"ModelDesc",
|
|
39
|
+
"Stats",
|
|
40
|
+
"list_text_models",
|
|
41
|
+
"list_sparse_models",
|
|
42
|
+
"list_image_models",
|
|
43
|
+
"list_reranker_models",
|
|
44
|
+
"cosine_similarity",
|
|
45
|
+
"dot_product",
|
|
46
|
+
"euclidean_distance",
|
|
47
|
+
"LembedError",
|
|
48
|
+
]
|
libembedding/_binding.py
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""Low-level cffi binding layer. Loads the shared library and exposes ffi/lib."""
|
|
2
|
+
|
|
3
|
+
import cffi
|
|
4
|
+
import platform
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
ffi = cffi.FFI()
|
|
8
|
+
|
|
9
|
+
_cdefs_path = Path(__file__).with_name("_cdefs.h")
|
|
10
|
+
ffi.cdef(_cdefs_path.read_text())
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _find_library() -> str:
|
|
14
|
+
ext = {"Darwin": ".dylib", "Linux": ".so", "Windows": ".dll"}.get(
|
|
15
|
+
platform.system(), ".so"
|
|
16
|
+
)
|
|
17
|
+
pkg_dir = Path(__file__).parent
|
|
18
|
+
candidates = [
|
|
19
|
+
pkg_dir / f"libembedding{ext}",
|
|
20
|
+
pkg_dir / f"lib" / f"libembedding{ext}",
|
|
21
|
+
# Development: look in build directory relative to project root
|
|
22
|
+
pkg_dir.parent.parent.parent.parent / "build" / f"python" / f"libembedding{ext}",
|
|
23
|
+
pkg_dir.parent.parent.parent.parent / "build" / f"libembedding{ext}",
|
|
24
|
+
]
|
|
25
|
+
for c in candidates:
|
|
26
|
+
if c.exists():
|
|
27
|
+
return str(c)
|
|
28
|
+
return f"libembedding{ext}"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
lib = ffi.dlopen(_find_library())
|
libembedding/_cdefs.h
ADDED
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
/* Flattened C declarations for cffi — derived from libembedding public headers.
|
|
2
|
+
* No preprocessor directives, no C++ constructs. */
|
|
3
|
+
|
|
4
|
+
/* ── Error handling ─────────────────────────────────────────────── */
|
|
5
|
+
|
|
6
|
+
typedef enum {
|
|
7
|
+
LEMBED_OK = 0,
|
|
8
|
+
LEMBED_ERROR_INVALID_ARGUMENT,
|
|
9
|
+
LEMBED_ERROR_OUT_OF_MEMORY,
|
|
10
|
+
LEMBED_ERROR_ONNX_RUNTIME,
|
|
11
|
+
LEMBED_ERROR_TOKENIZER,
|
|
12
|
+
LEMBED_ERROR_DOWNLOAD,
|
|
13
|
+
LEMBED_ERROR_IO,
|
|
14
|
+
LEMBED_ERROR_MODEL_NOT_FOUND,
|
|
15
|
+
LEMBED_ERROR_UNSUPPORTED,
|
|
16
|
+
LEMBED_ERROR_BATCH_SIZE,
|
|
17
|
+
} lembed_status_t;
|
|
18
|
+
|
|
19
|
+
const char* lembed_status_message(lembed_status_t status);
|
|
20
|
+
const char* lembed_last_error(void);
|
|
21
|
+
const char* lembed_version(void);
|
|
22
|
+
|
|
23
|
+
/* ── Enums ──────────────────────────────────────────────────────── */
|
|
24
|
+
|
|
25
|
+
typedef enum {
|
|
26
|
+
LEMBED_PROVIDER_CPU = 0,
|
|
27
|
+
LEMBED_PROVIDER_CUDA,
|
|
28
|
+
LEMBED_PROVIDER_COREML,
|
|
29
|
+
LEMBED_PROVIDER_DIRECTML,
|
|
30
|
+
LEMBED_PROVIDER_TENSORRT,
|
|
31
|
+
} lembed_execution_provider_t;
|
|
32
|
+
|
|
33
|
+
typedef enum {
|
|
34
|
+
LEMBED_POOLING_CLS = 0,
|
|
35
|
+
LEMBED_POOLING_MEAN,
|
|
36
|
+
} lembed_pooling_t;
|
|
37
|
+
|
|
38
|
+
typedef enum {
|
|
39
|
+
LEMBED_QUANTIZATION_NONE = 0,
|
|
40
|
+
LEMBED_QUANTIZATION_STATIC,
|
|
41
|
+
LEMBED_QUANTIZATION_DYNAMIC,
|
|
42
|
+
} lembed_quantization_t;
|
|
43
|
+
|
|
44
|
+
typedef enum {
|
|
45
|
+
LEMBED_TEXT_ALL_MINILM_L6_V2 = 0,
|
|
46
|
+
LEMBED_TEXT_ALL_MINILM_L6_V2_Q,
|
|
47
|
+
LEMBED_TEXT_ALL_MINILM_L12_V2,
|
|
48
|
+
LEMBED_TEXT_ALL_MINILM_L12_V2_Q,
|
|
49
|
+
LEMBED_TEXT_ALL_MPNET_BASE_V2,
|
|
50
|
+
LEMBED_TEXT_BGE_BASE_EN_V15,
|
|
51
|
+
LEMBED_TEXT_BGE_BASE_EN_V15_Q,
|
|
52
|
+
LEMBED_TEXT_BGE_LARGE_EN_V15,
|
|
53
|
+
LEMBED_TEXT_BGE_LARGE_EN_V15_Q,
|
|
54
|
+
LEMBED_TEXT_BGE_SMALL_EN_V15,
|
|
55
|
+
LEMBED_TEXT_BGE_SMALL_EN_V15_Q,
|
|
56
|
+
LEMBED_TEXT_NOMIC_EMBED_TEXT_V1,
|
|
57
|
+
LEMBED_TEXT_NOMIC_EMBED_TEXT_V15,
|
|
58
|
+
LEMBED_TEXT_NOMIC_EMBED_TEXT_V15_Q,
|
|
59
|
+
LEMBED_TEXT_PARAPHRASE_ML_MINILM_L12_V2,
|
|
60
|
+
LEMBED_TEXT_PARAPHRASE_ML_MINILM_L12_V2_Q,
|
|
61
|
+
LEMBED_TEXT_PARAPHRASE_ML_MPNET_BASE_V2,
|
|
62
|
+
LEMBED_TEXT_BGE_SMALL_ZH_V15,
|
|
63
|
+
LEMBED_TEXT_BGE_LARGE_ZH_V15,
|
|
64
|
+
LEMBED_TEXT_BGE_M3,
|
|
65
|
+
LEMBED_TEXT_MODERNBERT_EMBED_LARGE,
|
|
66
|
+
LEMBED_TEXT_MULTILINGUAL_E5_SMALL,
|
|
67
|
+
LEMBED_TEXT_MULTILINGUAL_E5_BASE,
|
|
68
|
+
LEMBED_TEXT_MULTILINGUAL_E5_LARGE,
|
|
69
|
+
LEMBED_TEXT_MXBAI_EMBED_LARGE_V1,
|
|
70
|
+
LEMBED_TEXT_MXBAI_EMBED_LARGE_V1_Q,
|
|
71
|
+
LEMBED_TEXT_GTE_BASE_EN_V15,
|
|
72
|
+
LEMBED_TEXT_GTE_BASE_EN_V15_Q,
|
|
73
|
+
LEMBED_TEXT_GTE_LARGE_EN_V15,
|
|
74
|
+
LEMBED_TEXT_GTE_LARGE_EN_V15_Q,
|
|
75
|
+
LEMBED_TEXT_CLIP_VIT_B32,
|
|
76
|
+
LEMBED_TEXT_JINA_EMBEDDINGS_V2_BASE_CODE,
|
|
77
|
+
LEMBED_TEXT_JINA_EMBEDDINGS_V2_BASE_EN,
|
|
78
|
+
LEMBED_TEXT_EMBEDDING_GEMMA_300M,
|
|
79
|
+
LEMBED_TEXT_SNOWFLAKE_ARCTIC_EMBED_XS,
|
|
80
|
+
LEMBED_TEXT_SNOWFLAKE_ARCTIC_EMBED_XS_Q,
|
|
81
|
+
LEMBED_TEXT_SNOWFLAKE_ARCTIC_EMBED_S,
|
|
82
|
+
LEMBED_TEXT_SNOWFLAKE_ARCTIC_EMBED_S_Q,
|
|
83
|
+
LEMBED_TEXT_SNOWFLAKE_ARCTIC_EMBED_M,
|
|
84
|
+
LEMBED_TEXT_SNOWFLAKE_ARCTIC_EMBED_M_Q,
|
|
85
|
+
LEMBED_TEXT_SNOWFLAKE_ARCTIC_EMBED_M_LONG,
|
|
86
|
+
LEMBED_TEXT_SNOWFLAKE_ARCTIC_EMBED_M_LONG_Q,
|
|
87
|
+
LEMBED_TEXT_SNOWFLAKE_ARCTIC_EMBED_L,
|
|
88
|
+
LEMBED_TEXT_SNOWFLAKE_ARCTIC_EMBED_L_Q,
|
|
89
|
+
LEMBED_TEXT_MODEL_COUNT,
|
|
90
|
+
} lembed_text_model_t;
|
|
91
|
+
|
|
92
|
+
typedef enum {
|
|
93
|
+
LEMBED_SPARSE_SPLADE_PP_V1 = 0,
|
|
94
|
+
LEMBED_SPARSE_BGE_M3,
|
|
95
|
+
LEMBED_SPARSE_MODEL_COUNT,
|
|
96
|
+
} lembed_sparse_model_t;
|
|
97
|
+
|
|
98
|
+
typedef enum {
|
|
99
|
+
LEMBED_IMAGE_CLIP_VIT_B32 = 0,
|
|
100
|
+
LEMBED_IMAGE_RESNET50,
|
|
101
|
+
LEMBED_IMAGE_UNICOM_VIT_B16,
|
|
102
|
+
LEMBED_IMAGE_UNICOM_VIT_B32,
|
|
103
|
+
LEMBED_IMAGE_NOMIC_EMBED_VISION_V15,
|
|
104
|
+
LEMBED_IMAGE_MODEL_COUNT,
|
|
105
|
+
} lembed_image_model_t;
|
|
106
|
+
|
|
107
|
+
typedef enum {
|
|
108
|
+
LEMBED_RERANKER_BGE_BASE = 0,
|
|
109
|
+
LEMBED_RERANKER_BGE_V2_M3,
|
|
110
|
+
LEMBED_RERANKER_JINA_V1_TURBO_EN,
|
|
111
|
+
LEMBED_RERANKER_JINA_V2_BASE_MULTILINGUAL,
|
|
112
|
+
LEMBED_RERANKER_MODEL_COUNT,
|
|
113
|
+
} lembed_reranker_model_t;
|
|
114
|
+
|
|
115
|
+
/* ── Structs ────────────────────────────────────────────────────── */
|
|
116
|
+
|
|
117
|
+
typedef struct {
|
|
118
|
+
const char* model_name;
|
|
119
|
+
const char* model_code;
|
|
120
|
+
const char* model_file;
|
|
121
|
+
const char* description;
|
|
122
|
+
int dim;
|
|
123
|
+
int max_tokens;
|
|
124
|
+
int pooling;
|
|
125
|
+
int quantization;
|
|
126
|
+
} lembed_model_info_t;
|
|
127
|
+
|
|
128
|
+
typedef struct {
|
|
129
|
+
const char* name;
|
|
130
|
+
int dimension;
|
|
131
|
+
int max_length;
|
|
132
|
+
int pooling;
|
|
133
|
+
int num_threads;
|
|
134
|
+
int batch_size;
|
|
135
|
+
lembed_execution_provider_t provider;
|
|
136
|
+
int device_id;
|
|
137
|
+
} lembed_model_desc_t;
|
|
138
|
+
|
|
139
|
+
typedef struct {
|
|
140
|
+
unsigned long long texts_embedded;
|
|
141
|
+
unsigned long long batches_run;
|
|
142
|
+
double avg_latency_ms;
|
|
143
|
+
} lembed_stats_t;
|
|
144
|
+
|
|
145
|
+
typedef struct lembed_text_embedding lembed_text_embedding_t;
|
|
146
|
+
typedef struct lembed_sparse_embedding lembed_sparse_embedding_ctx_t;
|
|
147
|
+
typedef struct lembed_image_embedding lembed_image_embedding_t;
|
|
148
|
+
typedef struct lembed_reranker lembed_reranker_t;
|
|
149
|
+
|
|
150
|
+
typedef struct {
|
|
151
|
+
float* data;
|
|
152
|
+
int num_embeddings;
|
|
153
|
+
int dim;
|
|
154
|
+
} lembed_embeddings_t;
|
|
155
|
+
|
|
156
|
+
typedef struct {
|
|
157
|
+
int32_t* indices;
|
|
158
|
+
float* values;
|
|
159
|
+
int length;
|
|
160
|
+
} lembed_sparse_embedding_t;
|
|
161
|
+
|
|
162
|
+
typedef struct {
|
|
163
|
+
lembed_sparse_embedding_t* items;
|
|
164
|
+
int count;
|
|
165
|
+
} lembed_sparse_embeddings_t;
|
|
166
|
+
|
|
167
|
+
typedef struct {
|
|
168
|
+
int index;
|
|
169
|
+
float score;
|
|
170
|
+
} lembed_rerank_result_t;
|
|
171
|
+
|
|
172
|
+
typedef struct {
|
|
173
|
+
lembed_rerank_result_t* items;
|
|
174
|
+
int count;
|
|
175
|
+
} lembed_rerank_results_t;
|
|
176
|
+
|
|
177
|
+
typedef struct {
|
|
178
|
+
lembed_text_model_t model;
|
|
179
|
+
lembed_execution_provider_t provider;
|
|
180
|
+
int device_id;
|
|
181
|
+
const char* cache_dir;
|
|
182
|
+
int max_length;
|
|
183
|
+
int num_threads;
|
|
184
|
+
int show_download_progress;
|
|
185
|
+
int batch_size;
|
|
186
|
+
int offline;
|
|
187
|
+
int pooling;
|
|
188
|
+
int dim;
|
|
189
|
+
} lembed_text_options_t;
|
|
190
|
+
|
|
191
|
+
typedef struct {
|
|
192
|
+
lembed_sparse_model_t model;
|
|
193
|
+
lembed_execution_provider_t provider;
|
|
194
|
+
int device_id;
|
|
195
|
+
const char* cache_dir;
|
|
196
|
+
int max_length;
|
|
197
|
+
int num_threads;
|
|
198
|
+
int show_download_progress;
|
|
199
|
+
int batch_size;
|
|
200
|
+
int offline;
|
|
201
|
+
} lembed_sparse_options_t;
|
|
202
|
+
|
|
203
|
+
typedef struct {
|
|
204
|
+
lembed_image_model_t model;
|
|
205
|
+
lembed_execution_provider_t provider;
|
|
206
|
+
int device_id;
|
|
207
|
+
const char* cache_dir;
|
|
208
|
+
int num_threads;
|
|
209
|
+
int show_download_progress;
|
|
210
|
+
int batch_size;
|
|
211
|
+
int offline;
|
|
212
|
+
int dim;
|
|
213
|
+
} lembed_image_options_t;
|
|
214
|
+
|
|
215
|
+
typedef struct {
|
|
216
|
+
lembed_reranker_model_t model;
|
|
217
|
+
lembed_execution_provider_t provider;
|
|
218
|
+
int device_id;
|
|
219
|
+
const char* cache_dir;
|
|
220
|
+
int max_length;
|
|
221
|
+
int num_threads;
|
|
222
|
+
int show_download_progress;
|
|
223
|
+
int batch_size;
|
|
224
|
+
int offline;
|
|
225
|
+
} lembed_reranker_options_t;
|
|
226
|
+
|
|
227
|
+
typedef struct {
|
|
228
|
+
const unsigned char* onnx_data;
|
|
229
|
+
size_t onnx_data_size;
|
|
230
|
+
const unsigned char* tokenizer_json;
|
|
231
|
+
size_t tokenizer_json_size;
|
|
232
|
+
const unsigned char* config_json;
|
|
233
|
+
size_t config_json_size;
|
|
234
|
+
lembed_pooling_t pooling;
|
|
235
|
+
int dim;
|
|
236
|
+
int max_length;
|
|
237
|
+
} lembed_user_defined_model_t;
|
|
238
|
+
|
|
239
|
+
/* ── Functions ──────────────────────────────────────────────────── */
|
|
240
|
+
|
|
241
|
+
/* Options defaults */
|
|
242
|
+
lembed_text_options_t lembed_text_options_default(void);
|
|
243
|
+
lembed_sparse_options_t lembed_sparse_options_default(void);
|
|
244
|
+
lembed_image_options_t lembed_image_options_default(void);
|
|
245
|
+
lembed_reranker_options_t lembed_reranker_options_default(void);
|
|
246
|
+
|
|
247
|
+
/* Text embedding */
|
|
248
|
+
lembed_status_t lembed_text_embedding_create(const lembed_text_options_t* options, lembed_text_embedding_t** out);
|
|
249
|
+
lembed_status_t lembed_text_embedding_create_custom(const lembed_user_defined_model_t* model, lembed_execution_provider_t provider, int num_threads, lembed_text_embedding_t** out);
|
|
250
|
+
lembed_status_t lembed_text_embedding_create_from_path(const char* dir_path, const lembed_text_options_t* options, lembed_text_embedding_t** out);
|
|
251
|
+
lembed_status_t lembed_text_embedding_embed(lembed_text_embedding_t* ctx, const char* const* texts, int num_texts, int batch_size, lembed_embeddings_t* result);
|
|
252
|
+
lembed_status_t lembed_text_embedding_embed_stream(lembed_text_embedding_t* ctx, const char* const* texts, int num_texts, int batch_size, void (*callback)(const float* embedding, int dim, void* userdata), void* userdata);
|
|
253
|
+
int lembed_text_embedding_dim(const lembed_text_embedding_t* ctx);
|
|
254
|
+
const lembed_model_desc_t* lembed_text_embedding_desc(const lembed_text_embedding_t* ctx);
|
|
255
|
+
const char* lembed_text_embedding_model_name(const lembed_text_embedding_t* ctx);
|
|
256
|
+
int lembed_text_embedding_max_length(const lembed_text_embedding_t* ctx);
|
|
257
|
+
void lembed_text_embedding_stats(const lembed_text_embedding_t* ctx, lembed_stats_t* out);
|
|
258
|
+
void lembed_text_embedding_free(lembed_text_embedding_t* ctx);
|
|
259
|
+
|
|
260
|
+
/* Sparse text embedding */
|
|
261
|
+
lembed_status_t lembed_sparse_text_embedding_create(const lembed_sparse_options_t* options, lembed_sparse_embedding_ctx_t** out);
|
|
262
|
+
lembed_status_t lembed_sparse_text_embedding_create_from_path(const char* dir_path, const lembed_sparse_options_t* options, lembed_sparse_embedding_ctx_t** out);
|
|
263
|
+
lembed_status_t lembed_sparse_text_embedding_embed(lembed_sparse_embedding_ctx_t* ctx, const char* const* texts, int num_texts, int batch_size, lembed_sparse_embeddings_t* result);
|
|
264
|
+
const lembed_model_desc_t* lembed_sparse_text_embedding_desc(const lembed_sparse_embedding_ctx_t* ctx);
|
|
265
|
+
const char* lembed_sparse_text_embedding_model_name(const lembed_sparse_embedding_ctx_t* ctx);
|
|
266
|
+
int lembed_sparse_text_embedding_max_length(const lembed_sparse_embedding_ctx_t* ctx);
|
|
267
|
+
void lembed_sparse_text_embedding_stats(const lembed_sparse_embedding_ctx_t* ctx, lembed_stats_t* out);
|
|
268
|
+
void lembed_sparse_text_embedding_free(lembed_sparse_embedding_ctx_t* ctx);
|
|
269
|
+
|
|
270
|
+
/* Image embedding */
|
|
271
|
+
lembed_status_t lembed_image_embedding_create(const lembed_image_options_t* options, lembed_image_embedding_t** out);
|
|
272
|
+
lembed_status_t lembed_image_embedding_create_from_path(const char* dir_path, const lembed_image_options_t* options, lembed_image_embedding_t** out);
|
|
273
|
+
lembed_status_t lembed_image_embedding_embed_files(lembed_image_embedding_t* ctx, const char* const* file_paths, int num_images, int batch_size, lembed_embeddings_t* result);
|
|
274
|
+
lembed_status_t lembed_image_embedding_embed_bytes(lembed_image_embedding_t* ctx, const unsigned char* const* image_data, const int* image_sizes, int num_images, int batch_size, lembed_embeddings_t* result);
|
|
275
|
+
int lembed_image_embedding_dim(const lembed_image_embedding_t* ctx);
|
|
276
|
+
const lembed_model_desc_t* lembed_image_embedding_desc(const lembed_image_embedding_t* ctx);
|
|
277
|
+
const char* lembed_image_embedding_model_name(const lembed_image_embedding_t* ctx);
|
|
278
|
+
int lembed_image_embedding_max_length(const lembed_image_embedding_t* ctx);
|
|
279
|
+
void lembed_image_embedding_stats(const lembed_image_embedding_t* ctx, lembed_stats_t* out);
|
|
280
|
+
void lembed_image_embedding_free(lembed_image_embedding_t* ctx);
|
|
281
|
+
|
|
282
|
+
/* Reranker */
|
|
283
|
+
lembed_status_t lembed_reranker_create(const lembed_reranker_options_t* options, lembed_reranker_t** out);
|
|
284
|
+
lembed_status_t lembed_reranker_create_from_path(const char* dir_path, const lembed_reranker_options_t* options, lembed_reranker_t** out);
|
|
285
|
+
lembed_status_t lembed_reranker_rerank(lembed_reranker_t* ctx, const char* query, const char* const* documents, int num_documents, int batch_size, lembed_rerank_results_t* result);
|
|
286
|
+
const lembed_model_desc_t* lembed_reranker_desc(const lembed_reranker_t* ctx);
|
|
287
|
+
const char* lembed_reranker_model_name(const lembed_reranker_t* ctx);
|
|
288
|
+
int lembed_reranker_max_length(const lembed_reranker_t* ctx);
|
|
289
|
+
void lembed_reranker_stats(const lembed_reranker_t* ctx, lembed_stats_t* out);
|
|
290
|
+
void lembed_reranker_free(lembed_reranker_t* ctx);
|
|
291
|
+
|
|
292
|
+
/* Model registry */
|
|
293
|
+
lembed_status_t lembed_get_text_model_info(lembed_text_model_t model, lembed_model_info_t* out);
|
|
294
|
+
lembed_status_t lembed_get_sparse_model_info(lembed_sparse_model_t model, lembed_model_info_t* out);
|
|
295
|
+
lembed_status_t lembed_get_image_model_info(lembed_image_model_t model, lembed_model_info_t* out);
|
|
296
|
+
lembed_status_t lembed_get_reranker_model_info(lembed_reranker_model_t model, lembed_model_info_t* out);
|
|
297
|
+
lembed_status_t lembed_list_text_models(const lembed_model_info_t** out, int* count);
|
|
298
|
+
lembed_status_t lembed_list_sparse_models(const lembed_model_info_t** out, int* count);
|
|
299
|
+
lembed_status_t lembed_list_image_models(const lembed_model_info_t** out, int* count);
|
|
300
|
+
lembed_status_t lembed_list_reranker_models(const lembed_model_info_t** out, int* count);
|
|
301
|
+
int lembed_find_text_model_by_code(const char* model_code);
|
|
302
|
+
int lembed_find_sparse_model_by_code(const char* model_code);
|
|
303
|
+
|
|
304
|
+
/* Downloader */
|
|
305
|
+
lembed_status_t lembed_ensure_text_model(lembed_text_model_t model, const char* cache_dir, int show_progress, int offline, char** model_dir_out);
|
|
306
|
+
lembed_status_t lembed_ensure_sparse_model(lembed_sparse_model_t model, const char* cache_dir, int show_progress, int offline, char** model_dir_out);
|
|
307
|
+
lembed_status_t lembed_ensure_image_model(lembed_image_model_t model, const char* cache_dir, int show_progress, int offline, char** model_dir_out);
|
|
308
|
+
lembed_status_t lembed_ensure_reranker_model(lembed_reranker_model_t model, const char* cache_dir, int show_progress, int offline, char** model_dir_out);
|
|
309
|
+
void lembed_free_string(char* s);
|
|
310
|
+
|
|
311
|
+
/* Similarity */
|
|
312
|
+
float lembed_cosine_similarity(const float* a, const float* b, int dim);
|
|
313
|
+
float lembed_dot_product(const float* a, const float* b, int dim);
|
|
314
|
+
float lembed_euclidean_distance(const float* a, const float* b, int dim);
|
|
315
|
+
|
|
316
|
+
/* Memory free */
|
|
317
|
+
void lembed_embeddings_free(lembed_embeddings_t* result);
|
|
318
|
+
void lembed_sparse_embeddings_free(lembed_sparse_embeddings_t* result);
|
|
319
|
+
void lembed_rerank_results_free(lembed_rerank_results_t* result);
|
libembedding/_status.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""Status code checking — raises Python exceptions from C status codes."""
|
|
2
|
+
|
|
3
|
+
from ._binding import ffi, lib
|
|
4
|
+
from .exceptions import (
|
|
5
|
+
LembedError,
|
|
6
|
+
InvalidArgumentError,
|
|
7
|
+
OutOfMemoryError,
|
|
8
|
+
OnnxRuntimeError,
|
|
9
|
+
TokenizerError,
|
|
10
|
+
DownloadError,
|
|
11
|
+
IOError,
|
|
12
|
+
ModelNotFoundError,
|
|
13
|
+
UnsupportedError,
|
|
14
|
+
BatchSizeError,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
_STATUS_MAP = {
|
|
18
|
+
1: InvalidArgumentError,
|
|
19
|
+
2: OutOfMemoryError,
|
|
20
|
+
3: OnnxRuntimeError,
|
|
21
|
+
4: TokenizerError,
|
|
22
|
+
5: DownloadError,
|
|
23
|
+
6: IOError,
|
|
24
|
+
7: ModelNotFoundError,
|
|
25
|
+
8: UnsupportedError,
|
|
26
|
+
9: BatchSizeError,
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def check_status(status: int) -> None:
|
|
31
|
+
if status == 0:
|
|
32
|
+
return
|
|
33
|
+
msg = ffi.string(lib.lembed_status_message(status)).decode("utf-8", errors="replace")
|
|
34
|
+
detail = ffi.string(lib.lembed_last_error()).decode("utf-8", errors="replace")
|
|
35
|
+
exc_cls = _STATUS_MAP.get(status, LembedError)
|
|
36
|
+
raise exc_cls(status, msg, detail)
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""Exception hierarchy mapped from lembed_status_t."""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class LembedError(Exception):
|
|
5
|
+
"""Base exception for libembedding errors."""
|
|
6
|
+
|
|
7
|
+
def __init__(self, status_code: int, message: str, detail: str = ""):
|
|
8
|
+
self.status_code = status_code
|
|
9
|
+
self.message = message
|
|
10
|
+
self.detail = detail
|
|
11
|
+
super().__init__(f"{message}: {detail}" if detail else message)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class InvalidArgumentError(LembedError):
|
|
15
|
+
pass
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class OutOfMemoryError(LembedError):
|
|
19
|
+
pass
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class OnnxRuntimeError(LembedError):
|
|
23
|
+
pass
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class TokenizerError(LembedError):
|
|
27
|
+
pass
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class DownloadError(LembedError):
|
|
31
|
+
pass
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class IOError(LembedError):
|
|
35
|
+
pass
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class ModelNotFoundError(LembedError):
|
|
39
|
+
pass
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class UnsupportedError(LembedError):
|
|
43
|
+
pass
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class BatchSizeError(LembedError):
|
|
47
|
+
pass
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
"""High-level image embedding API."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import warnings
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
|
|
9
|
+
from ._binding import ffi, lib
|
|
10
|
+
from ._status import check_status
|
|
11
|
+
from .models import (
|
|
12
|
+
resolve_image_model,
|
|
13
|
+
list_image_models,
|
|
14
|
+
_PROVIDER_MAP,
|
|
15
|
+
_desc_from_c,
|
|
16
|
+
_is_local_path,
|
|
17
|
+
)
|
|
18
|
+
from .types import ModelDesc, Stats
|
|
19
|
+
from .exceptions import ModelNotFoundError
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class ImageEmbedding:
|
|
23
|
+
"""Generate dense vector embeddings from images.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
model_name: Model name (e.g. "openai/clip-vit-base-patch32") or local
|
|
27
|
+
directory path.
|
|
28
|
+
provider: Execution provider.
|
|
29
|
+
cache_dir: Model cache directory.
|
|
30
|
+
threads: Number of threads (0 = auto).
|
|
31
|
+
batch_size: Internal batch size (default 32).
|
|
32
|
+
offline: If True, use cached models only (default False).
|
|
33
|
+
show_download_progress: Show download progress bar.
|
|
34
|
+
dim: Output dimension for local models without config.json (0 = auto).
|
|
35
|
+
num_threads: Deprecated; use ``threads``.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
def __init__(
|
|
39
|
+
self,
|
|
40
|
+
model_name: str = "Qdrant/clip-ViT-B-32-vision",
|
|
41
|
+
*,
|
|
42
|
+
provider: str = "cpu",
|
|
43
|
+
device_id: int = 0,
|
|
44
|
+
cache_dir: str | None = None,
|
|
45
|
+
threads: int = 0,
|
|
46
|
+
batch_size: int = 30,
|
|
47
|
+
offline: bool = False,
|
|
48
|
+
show_download_progress: bool = True,
|
|
49
|
+
dim: int = 0,
|
|
50
|
+
num_threads: int | None = None,
|
|
51
|
+
):
|
|
52
|
+
if num_threads is not None:
|
|
53
|
+
warnings.warn(
|
|
54
|
+
"num_threads is deprecated, use threads",
|
|
55
|
+
DeprecationWarning,
|
|
56
|
+
stacklevel=2,
|
|
57
|
+
)
|
|
58
|
+
threads = num_threads
|
|
59
|
+
|
|
60
|
+
opts = lib.lembed_image_options_default()
|
|
61
|
+
opts.provider = _PROVIDER_MAP[provider.lower()]
|
|
62
|
+
opts.device_id = device_id
|
|
63
|
+
self._cache_dir_buf = (
|
|
64
|
+
ffi.new("char[]", cache_dir.encode("utf-8")) if cache_dir else ffi.NULL
|
|
65
|
+
)
|
|
66
|
+
opts.cache_dir = self._cache_dir_buf
|
|
67
|
+
opts.num_threads = threads
|
|
68
|
+
opts.batch_size = batch_size
|
|
69
|
+
opts.offline = int(offline)
|
|
70
|
+
opts.show_download_progress = int(show_download_progress)
|
|
71
|
+
opts.dim = dim
|
|
72
|
+
|
|
73
|
+
ctx_ptr = ffi.new("lembed_image_embedding_t **")
|
|
74
|
+
|
|
75
|
+
try:
|
|
76
|
+
model_idx = resolve_image_model(model_name)
|
|
77
|
+
opts.model = model_idx
|
|
78
|
+
check_status(lib.lembed_image_embedding_create(
|
|
79
|
+
ffi.addressof(opts), ctx_ptr))
|
|
80
|
+
except ModelNotFoundError:
|
|
81
|
+
if _is_local_path(model_name):
|
|
82
|
+
check_status(lib.lembed_image_embedding_create_from_path(
|
|
83
|
+
model_name.encode("utf-8"), ffi.addressof(opts), ctx_ptr))
|
|
84
|
+
else:
|
|
85
|
+
raise
|
|
86
|
+
|
|
87
|
+
self._ctx = ffi.gc(ctx_ptr[0], lib.lembed_image_embedding_free)
|
|
88
|
+
self._dim = lib.lembed_image_embedding_dim(self._ctx)
|
|
89
|
+
self._batch_size = batch_size
|
|
90
|
+
|
|
91
|
+
@staticmethod
|
|
92
|
+
def list_supported_models():
|
|
93
|
+
"""Return a list of all supported image embedding models."""
|
|
94
|
+
return list_image_models()
|
|
95
|
+
|
|
96
|
+
@property
|
|
97
|
+
def dim(self) -> int:
|
|
98
|
+
return self._dim
|
|
99
|
+
|
|
100
|
+
@property
|
|
101
|
+
def batch_size(self) -> int:
|
|
102
|
+
"""Configured internal batch size."""
|
|
103
|
+
return self._batch_size
|
|
104
|
+
|
|
105
|
+
def info(self) -> ModelDesc:
|
|
106
|
+
"""Return runtime model descriptor."""
|
|
107
|
+
desc_ptr = lib.lembed_image_embedding_desc(self._ctx)
|
|
108
|
+
return _desc_from_c(desc_ptr)
|
|
109
|
+
|
|
110
|
+
@property
|
|
111
|
+
def name(self) -> str:
|
|
112
|
+
"""Model name or local path."""
|
|
113
|
+
name_ptr = lib.lembed_image_embedding_model_name(self._ctx)
|
|
114
|
+
return ffi.string(name_ptr).decode("utf-8", errors="replace") if name_ptr else ""
|
|
115
|
+
|
|
116
|
+
def embed_files(self, paths: list[str], *, batch_size: int | None = None) -> np.ndarray:
|
|
117
|
+
"""Embed images from file paths.
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
numpy array of shape (len(paths), dim) with dtype float32.
|
|
121
|
+
"""
|
|
122
|
+
n = len(paths)
|
|
123
|
+
if n == 0:
|
|
124
|
+
return np.empty((0, self._dim), dtype=np.float32)
|
|
125
|
+
|
|
126
|
+
bs = 0 if batch_size is None else batch_size
|
|
127
|
+
|
|
128
|
+
encoded = [p.encode("utf-8") for p in paths]
|
|
129
|
+
c_strs = [ffi.new("char[]", e) for e in encoded]
|
|
130
|
+
c_paths = ffi.new("char*[]", c_strs)
|
|
131
|
+
|
|
132
|
+
result = ffi.new("lembed_embeddings_t *")
|
|
133
|
+
check_status(
|
|
134
|
+
lib.lembed_image_embedding_embed_files(self._ctx, c_paths, n, bs, result)
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
try:
|
|
138
|
+
buf = ffi.buffer(result.data, result.num_embeddings * result.dim * 4)
|
|
139
|
+
arr = np.frombuffer(buf, dtype=np.float32).copy()
|
|
140
|
+
return arr.reshape(result.num_embeddings, result.dim)
|
|
141
|
+
finally:
|
|
142
|
+
lib.lembed_embeddings_free(result)
|
|
143
|
+
|
|
144
|
+
def embed_bytes(self, images: list[bytes], *, batch_size: int | None = None) -> np.ndarray:
|
|
145
|
+
"""Embed images from raw bytes (JPEG, PNG, etc.).
|
|
146
|
+
|
|
147
|
+
Returns:
|
|
148
|
+
numpy array of shape (len(images), dim) with dtype float32.
|
|
149
|
+
"""
|
|
150
|
+
n = len(images)
|
|
151
|
+
if n == 0:
|
|
152
|
+
return np.empty((0, self._dim), dtype=np.float32)
|
|
153
|
+
|
|
154
|
+
bs = 0 if batch_size is None else batch_size
|
|
155
|
+
|
|
156
|
+
c_data = ffi.new("unsigned char*[]", n)
|
|
157
|
+
c_sizes = ffi.new("int[]", n)
|
|
158
|
+
kept = []
|
|
159
|
+
for i, img in enumerate(images):
|
|
160
|
+
buf = ffi.new("unsigned char[]", img)
|
|
161
|
+
kept.append(buf)
|
|
162
|
+
c_data[i] = buf
|
|
163
|
+
c_sizes[i] = len(img)
|
|
164
|
+
|
|
165
|
+
result = ffi.new("lembed_embeddings_t *")
|
|
166
|
+
check_status(
|
|
167
|
+
lib.lembed_image_embedding_embed_bytes(
|
|
168
|
+
self._ctx, c_data, c_sizes, n, bs, result
|
|
169
|
+
)
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
try:
|
|
173
|
+
buf = ffi.buffer(result.data, result.num_embeddings * result.dim * 4)
|
|
174
|
+
arr = np.frombuffer(buf, dtype=np.float32).copy()
|
|
175
|
+
return arr.reshape(result.num_embeddings, result.dim)
|
|
176
|
+
finally:
|
|
177
|
+
lib.lembed_embeddings_free(result)
|
|
178
|
+
|
|
179
|
+
def stats(self) -> Stats:
|
|
180
|
+
"""Return runtime usage statistics."""
|
|
181
|
+
s = ffi.new("lembed_stats_t *")
|
|
182
|
+
lib.lembed_image_embedding_stats(self._ctx, s)
|
|
183
|
+
return Stats(
|
|
184
|
+
texts_embedded=s.texts_embedded,
|
|
185
|
+
batches_run=s.batches_run,
|
|
186
|
+
avg_latency_ms=s.avg_latency_ms,
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
def close(self) -> None:
|
|
190
|
+
"""Release the underlying C resources."""
|
|
191
|
+
self._ctx = None
|
|
192
|
+
|
|
193
|
+
def __enter__(self):
|
|
194
|
+
return self
|
|
195
|
+
|
|
196
|
+
def __exit__(self, *args):
|
|
197
|
+
self.close()
|
libembedding/libcurl.dll
ADDED
|
Binary file
|
|
Binary file
|