defuss-vectorsearch 0.0.0-stage → 0.1.0
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.
- package/LICENSE +21 -0
- package/README.md +479 -2
- package/dist/browser.d.mts +18 -0
- package/dist/browser.mjs +22 -0
- package/dist/client.cjs +62 -0
- package/dist/client.d.cts +15 -0
- package/dist/client.d.mts +15 -0
- package/dist/client.mjs +23 -0
- package/dist/core-DSMVtqZ6.mjs +353 -0
- package/dist/core-DaRhdYmA.cjs +355 -0
- package/dist/core-DnBchjh2.d.mts +39 -0
- package/dist/core-UGRF9Eqm.d.cts +39 -0
- package/dist/model-cache-qTj4Dnw0.cjs +380 -0
- package/dist/model-cache-qd7znbJ5.mjs +38 -0
- package/dist/model-cache.browser-BVWrcI3Y.mjs +322 -0
- package/dist/model-cache.node-C6M9XdFb.cjs +58 -0
- package/dist/model-cache.node-D4J7dSRw.mjs +51 -0
- package/dist/model-profiles-BDS-uZ4e.d.cts +48 -0
- package/dist/model-profiles-BDS-uZ4e.d.mts +48 -0
- package/dist/onnx.cjs +273 -0
- package/dist/onnx.d.cts +13 -0
- package/dist/onnx.d.mts +13 -0
- package/dist/onnx.mjs +34 -0
- package/dist/prompts-BbVgTLA6.mjs +163 -0
- package/dist/prompts-Cq8h-R6V.cjs +170 -0
- package/dist/server.cjs +74 -0
- package/dist/server.d.cts +15 -0
- package/dist/server.d.mts +15 -0
- package/dist/server.mjs +35 -0
- package/dist/shared.cjs +49 -0
- package/dist/shared.d.cts +29 -0
- package/dist/shared.d.mts +29 -0
- package/dist/shared.mjs +8 -0
- package/dist/turboquant.cjs +239 -0
- package/dist/turboquant.d.cts +17 -0
- package/dist/turboquant.d.mts +17 -0
- package/dist/turboquant.mjs +232 -0
- package/dist/vector-math-BDEYyzR7.d.cts +16 -0
- package/dist/vector-math-C29mf_rv.d.mts +16 -0
- package/dist/vector-math-D8tpjoQx.cjs +121 -0
- package/dist/vector-math-DwdA_xwv.mjs +113 -0
- package/dist/vector-search.cjs +135 -0
- package/dist/vector-search.d.cts +10 -0
- package/dist/vector-search.d.mts +10 -0
- package/dist/vector-search.mjs +126 -0
- package/dist/winzling-embedder-CthXBDRS.mjs +237 -0
- package/dist/winzling-embedder-Dqq64fVb.d.cts +245 -0
- package/dist/winzling-embedder-Dqq64fVb.d.mts +245 -0
- package/package.json +147 -4
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { B as BaseEmbeddingRuntime } from './core-DnBchjh2.mjs';
|
|
2
|
+
import { E as EmbedderInitOptions } from './winzling-embedder-Dqq64fVb.mjs';
|
|
3
|
+
export { B as BuildTurboQuantIndexOptions, f as EmbedOptions, g as Embedder, h as EmbeddingDType, i as EmbeddingDevice, j as ExactSearchMulticoreOptions, F as FeatureExtractorLike, M as ModelCacheClearFileResult, k as ModelCacheClearResult, l as ModelCacheFileStatus, m as ModelCacheInspectionResult, n as ModelCacheLocation, o as ModelCacheOptions, q as ModelLoadOptions, r as ModelPrefetchFile, s as ModelPrefetchOptions, t as ModelPrefetchResult, u as ModelSourceKind, O as OpenAICompatibleEmbeddingEndpointOptions, P as PoolingStrategy, Q as QueryEmbedOptions, v as QueryInstructionPreset, R as ResolvedModelSource, S as SearchHit, w as SearchResult, x as TensorLike, y as TransformersEnvLike, z as TransformersModuleLike, T as TurboQuantRerankResult, b as TurboQuantRerankedSearchHit, c as TurboQuantSearchIndex, A as Vector, V as Vectors } from './winzling-embedder-Dqq64fVb.mjs';
|
|
4
|
+
export { DEFAULT_MODEL_ID, DEFAULT_MODEL_REMOTE_HOST, DEFAULT_MODEL_REMOTE_PATH_TEMPLATE, DEFAULT_QUERY_INSTRUCTION_PRESET, DEFAULT_TRANSFORMERS_CACHE_NAME, LEGACY_MODEL_ID, QUERY_INSTRUCTION_PRESETS, buildNodeCacheKey, buildRemoteModelFileUrl, clearModelCache, formatInstructionQuery, getRequiredModelFiles, inspectModelCache, pathJoin, prefetchModel, resolveModelSource, resolveQueryInstruction } from './shared.mjs';
|
|
5
|
+
export { attachRecords, searchTopKMulticore } from './vector-search.mjs';
|
|
6
|
+
export { buildTurboQuantIndex, rerankSearchHits, scoreTurboQuantIndex, searchTurboQuantIndex, searchTurboQuantIndexRerank, selfCheckTurboQuant } from './turboquant.mjs';
|
|
7
|
+
export { S as SUPPORTED_MODELS, W as WINZLING_FILES, a as WINZLING_MODEL_ID, b as WINZLING_PROFILE, c as WINZLING_REVISION } from './model-profiles-BDS-uZ4e.mjs';
|
|
8
|
+
export { d as dotProduct, b as dotProductJS, n as normalizeVector, a as normalizeVectors, s as searchTopK, t as toFloat32, c as topKFromScores } from './vector-math-C29mf_rv.mjs';
|
|
9
|
+
|
|
10
|
+
declare class DefussEmbeddingClient extends BaseEmbeddingRuntime {
|
|
11
|
+
constructor(options?: EmbedderInitOptions);
|
|
12
|
+
}
|
|
13
|
+
declare const createEmbeddingClient: (options?: EmbedderInitOptions) => DefussEmbeddingClient;
|
|
14
|
+
|
|
15
|
+
export { BaseEmbeddingRuntime, DefussEmbeddingClient, EmbedderInitOptions, createEmbeddingClient };
|
package/dist/client.mjs
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { B as BaseEmbeddingRuntime } from './core-DSMVtqZ6.mjs';
|
|
2
|
+
export { D as DEFAULT_MODEL_ID, a as DEFAULT_MODEL_REMOTE_HOST, b as DEFAULT_MODEL_REMOTE_PATH_TEMPLATE, c as DEFAULT_TRANSFORMERS_CACHE_NAME, L as LEGACY_MODEL_ID, S as SUPPORTED_MODELS, W as WINZLING_FILES, d as WINZLING_MODEL_ID, e as WINZLING_PROFILE, f as WINZLING_REVISION, g as buildNodeCacheKey, h as buildRemoteModelFileUrl, i as getRequiredModelFiles, p as pathJoin, r as resolveModelSource } from './model-cache.browser-BVWrcI3Y.mjs';
|
|
3
|
+
export { D as DEFAULT_QUERY_INSTRUCTION_PRESET, Q as QUERY_INSTRUCTION_PRESETS, c as clearModelCache, f as formatInstructionQuery, i as inspectModelCache, p as prefetchModel, r as resolveQueryInstruction } from './prompts-BbVgTLA6.mjs';
|
|
4
|
+
export { attachRecords, searchTopKMulticore } from './vector-search.mjs';
|
|
5
|
+
export { buildTurboQuantIndex, rerankSearchHits, scoreTurboQuantIndex, searchTurboQuantIndex, searchTurboQuantIndexRerank, selfCheckTurboQuant } from './turboquant.mjs';
|
|
6
|
+
export { d as dotProduct, a as dotProductJS, n as normalizeVector, b as normalizeVectors, s as searchTopK, t as toFloat32, c as topKFromScores } from './vector-math-DwdA_xwv.mjs';
|
|
7
|
+
import './onnx.mjs';
|
|
8
|
+
import './model-cache-qd7znbJ5.mjs';
|
|
9
|
+
import './winzling-embedder-CthXBDRS.mjs';
|
|
10
|
+
import '@huggingface/tokenizers';
|
|
11
|
+
import 'defuss-db';
|
|
12
|
+
import 'defuss-db/client.js';
|
|
13
|
+
|
|
14
|
+
class DefussEmbeddingClient extends BaseEmbeddingRuntime {
|
|
15
|
+
constructor(options = {}) {
|
|
16
|
+
super(options, { allowLocalModels: false, useBrowserCache: true });
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
const createEmbeddingClient = (options = {}) => {
|
|
20
|
+
return new DefussEmbeddingClient(options);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export { BaseEmbeddingRuntime, DefussEmbeddingClient, createEmbeddingClient };
|
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
import { d as WINZLING_MODEL_ID, D as DEFAULT_MODEL_ID, r as resolveModelSource, f as WINZLING_REVISION, e as WINZLING_PROFILE } from './model-cache.browser-BVWrcI3Y.mjs';
|
|
2
|
+
import { p as prefetchModel, i as inspectModelCache, c as clearModelCache, f as formatInstructionQuery } from './prompts-BbVgTLA6.mjs';
|
|
3
|
+
import { createWinzlingExtractor } from './onnx.mjs';
|
|
4
|
+
import { n as normalizeVector } from './vector-math-DwdA_xwv.mjs';
|
|
5
|
+
|
|
6
|
+
const isRecord = (value) => {
|
|
7
|
+
return typeof value === "object" && value !== null;
|
|
8
|
+
};
|
|
9
|
+
const resolveFetch = (options) => {
|
|
10
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
11
|
+
if (typeof fetchImpl !== "function") {
|
|
12
|
+
throw new Error(
|
|
13
|
+
"OpenAI-compatible embedding endpoint mode requires a fetch implementation."
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
return fetchImpl;
|
|
17
|
+
};
|
|
18
|
+
const resolveOpenAICompatibleEmbeddingsUrl = (options) => {
|
|
19
|
+
if (options.endpoint) {
|
|
20
|
+
return new URL(options.endpoint).toString();
|
|
21
|
+
}
|
|
22
|
+
if (options.baseUrl) {
|
|
23
|
+
const baseUrl = options.baseUrl.endsWith("/") ? options.baseUrl : `${options.baseUrl}/`;
|
|
24
|
+
return new URL("embeddings", baseUrl).toString();
|
|
25
|
+
}
|
|
26
|
+
throw new Error(
|
|
27
|
+
"openAICompatible requires either endpoint or baseUrl to resolve the embeddings URL."
|
|
28
|
+
);
|
|
29
|
+
};
|
|
30
|
+
const buildRequestHeaders = (options) => {
|
|
31
|
+
const headers = new Headers();
|
|
32
|
+
headers.set("Accept", "application/json");
|
|
33
|
+
headers.set("Content-Type", "application/json");
|
|
34
|
+
for (const [key, value] of Object.entries(options.headers ?? {})) {
|
|
35
|
+
headers.set(key, value);
|
|
36
|
+
}
|
|
37
|
+
if (options.apiKey && !headers.has("Authorization")) {
|
|
38
|
+
headers.set("Authorization", `Bearer ${options.apiKey}`);
|
|
39
|
+
}
|
|
40
|
+
return headers;
|
|
41
|
+
};
|
|
42
|
+
const parseEmbeddingVector = (value, index) => {
|
|
43
|
+
if (!Array.isArray(value)) {
|
|
44
|
+
throw new Error(`Invalid embedding payload at index ${index}: expected an array.`);
|
|
45
|
+
}
|
|
46
|
+
const embedding = new Float32Array(value.length);
|
|
47
|
+
for (let offset = 0; offset < value.length; offset++) {
|
|
48
|
+
const numeric = Number(value[offset]);
|
|
49
|
+
if (!Number.isFinite(numeric)) {
|
|
50
|
+
throw new Error(
|
|
51
|
+
`Invalid embedding payload at index ${index}: value ${offset} is not numeric.`
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
embedding[offset] = numeric;
|
|
55
|
+
}
|
|
56
|
+
return embedding;
|
|
57
|
+
};
|
|
58
|
+
const parseEmbeddingResponse = (payload) => {
|
|
59
|
+
if (!isRecord(payload) || !Array.isArray(payload.data)) {
|
|
60
|
+
throw new Error("Invalid OpenAI-compatible embeddings response: expected a data array.");
|
|
61
|
+
}
|
|
62
|
+
const items = payload.data.map((entry, index) => {
|
|
63
|
+
if (Array.isArray(entry)) {
|
|
64
|
+
return {
|
|
65
|
+
index,
|
|
66
|
+
embedding: parseEmbeddingVector(entry, index)
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
if (!isRecord(entry)) {
|
|
70
|
+
throw new Error(`Invalid embedding payload at index ${index}: expected an object.`);
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
index: typeof entry.index === "number" ? entry.index : index,
|
|
74
|
+
embedding: parseEmbeddingVector(entry.embedding, index)
|
|
75
|
+
};
|
|
76
|
+
});
|
|
77
|
+
items.sort((a, b) => a.index - b.index);
|
|
78
|
+
return items.map((item) => item.embedding);
|
|
79
|
+
};
|
|
80
|
+
const fetchOpenAICompatibleEmbeddings = async (input, model, options) => {
|
|
81
|
+
const fetchImpl = resolveFetch(options);
|
|
82
|
+
const endpointUrl = resolveOpenAICompatibleEmbeddingsUrl(options);
|
|
83
|
+
const body = {
|
|
84
|
+
model,
|
|
85
|
+
input,
|
|
86
|
+
...options.encodingFormat !== void 0 ? { encoding_format: options.encodingFormat } : {},
|
|
87
|
+
...options.dimensions !== void 0 ? { dimensions: options.dimensions } : {},
|
|
88
|
+
...options.user !== void 0 ? { user: options.user } : {},
|
|
89
|
+
...options.extraBody
|
|
90
|
+
};
|
|
91
|
+
const response = await fetchImpl(endpointUrl, {
|
|
92
|
+
method: "POST",
|
|
93
|
+
headers: buildRequestHeaders(options),
|
|
94
|
+
body: JSON.stringify(body)
|
|
95
|
+
});
|
|
96
|
+
const rawBody = await response.text();
|
|
97
|
+
if (!response.ok) {
|
|
98
|
+
throw new Error(
|
|
99
|
+
`Failed to fetch embeddings from ${endpointUrl} (${response.status}): ${rawBody || response.statusText}`
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
let payload;
|
|
103
|
+
try {
|
|
104
|
+
payload = rawBody.length > 0 ? JSON.parse(rawBody) : {};
|
|
105
|
+
} catch (error) {
|
|
106
|
+
throw new Error(
|
|
107
|
+
`Invalid JSON from OpenAI-compatible embeddings endpoint ${endpointUrl}: ${error.message}`
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
return parseEmbeddingResponse(payload);
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const DEFAULT_MODEL = DEFAULT_MODEL_ID;
|
|
114
|
+
const DEFAULT_DTYPE = "fp32";
|
|
115
|
+
const DEFAULT_POOLING = "last_token";
|
|
116
|
+
const DEFAULT_NORMALIZE = true;
|
|
117
|
+
const getTransformersModule = async () => {
|
|
118
|
+
return import('@huggingface/transformers');
|
|
119
|
+
};
|
|
120
|
+
const configureEnv = (mod, options, defaults) => {
|
|
121
|
+
mod.env.allowRemoteModels = options.allowRemoteModels ?? true;
|
|
122
|
+
mod.env.allowLocalModels = options.allowLocalModels ?? defaults.allowLocalModels;
|
|
123
|
+
if (options.localModelPath !== void 0) mod.env.localModelPath = options.localModelPath;
|
|
124
|
+
if (options.cacheDir !== void 0) mod.env.cacheDir = options.cacheDir;
|
|
125
|
+
if (options.useBrowserCache !== void 0) mod.env.useBrowserCache = options.useBrowserCache;
|
|
126
|
+
else if (defaults.useBrowserCache !== void 0) mod.env.useBrowserCache = defaults.useBrowserCache;
|
|
127
|
+
if (options.useFSCache !== void 0) mod.env.useFSCache = options.useFSCache;
|
|
128
|
+
if (options.useFS !== void 0) mod.env.useFS = options.useFS;
|
|
129
|
+
if (options.logLevel !== void 0) mod.env.logLevel = options.logLevel;
|
|
130
|
+
};
|
|
131
|
+
const splitTensor = (tensor) => {
|
|
132
|
+
const dims = tensor.dims;
|
|
133
|
+
if (dims.length !== 2) {
|
|
134
|
+
throw new Error(`Expected pooled 2D tensor, got dims=${JSON.stringify(dims)}`);
|
|
135
|
+
}
|
|
136
|
+
const batch = dims[0];
|
|
137
|
+
const width = dims[1];
|
|
138
|
+
const data = tensor.data instanceof Float32Array ? tensor.data : Float32Array.from(tensor.data);
|
|
139
|
+
const embeddings = [];
|
|
140
|
+
for (let row = 0; row < batch; row++) {
|
|
141
|
+
const start = row * width;
|
|
142
|
+
embeddings[row] = data.slice(start, start + width);
|
|
143
|
+
}
|
|
144
|
+
return embeddings;
|
|
145
|
+
};
|
|
146
|
+
class BaseEmbeddingRuntime {
|
|
147
|
+
model;
|
|
148
|
+
get dtype() {
|
|
149
|
+
return this.options.dtype ?? (this.isWinzling() ? "q4" : DEFAULT_DTYPE);
|
|
150
|
+
}
|
|
151
|
+
get device() {
|
|
152
|
+
return this.options.device ?? (this.isWinzling() ? this.options.winzling?.device ?? "wasm" : void 0);
|
|
153
|
+
}
|
|
154
|
+
options;
|
|
155
|
+
runtimeDefaults;
|
|
156
|
+
resolvedModelSource;
|
|
157
|
+
requiredFiles;
|
|
158
|
+
queue = Promise.resolve();
|
|
159
|
+
closed = false;
|
|
160
|
+
closing;
|
|
161
|
+
extractorPromise = null;
|
|
162
|
+
constructor(options = {}, runtimeDefaults) {
|
|
163
|
+
this.options = options;
|
|
164
|
+
this.runtimeDefaults = runtimeDefaults;
|
|
165
|
+
this.model = options.model ?? options.openAICompatible?.model ?? (options.modelProfile === "winzling" ? WINZLING_MODEL_ID : DEFAULT_MODEL);
|
|
166
|
+
this.resolvedModelSource = options.openAICompatible ? null : resolveModelSource(this.model, {
|
|
167
|
+
revision: options.revision ?? (options.modelProfile === "winzling" ? WINZLING_REVISION : void 0)
|
|
168
|
+
});
|
|
169
|
+
this.requiredFiles = options.requiredFiles;
|
|
170
|
+
}
|
|
171
|
+
isWinzling() {
|
|
172
|
+
return !this.options.openAICompatible && (this.model === WINZLING_MODEL_ID || this.options.modelProfile === "winzling");
|
|
173
|
+
}
|
|
174
|
+
enqueue(operation) {
|
|
175
|
+
if (this.closed) return Promise.reject(new Error("Embedder has been disposed"));
|
|
176
|
+
const pending = this.queue.then(operation);
|
|
177
|
+
this.queue = pending.catch(() => {
|
|
178
|
+
});
|
|
179
|
+
return pending;
|
|
180
|
+
}
|
|
181
|
+
isOpenAICompatibleMode() {
|
|
182
|
+
return this.options.openAICompatible !== void 0;
|
|
183
|
+
}
|
|
184
|
+
getLocalModelSource(operation) {
|
|
185
|
+
if (this.resolvedModelSource === null) {
|
|
186
|
+
throw new Error(
|
|
187
|
+
`${operation} is unavailable when using an OpenAI-compatible embedding endpoint.`
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
return this.resolvedModelSource;
|
|
191
|
+
}
|
|
192
|
+
loadModel(urlOrRepoId, options = {}) {
|
|
193
|
+
return this.enqueue(() => this.loadModelInternal(urlOrRepoId, options));
|
|
194
|
+
}
|
|
195
|
+
async loadModelInternal(urlOrRepoId, options) {
|
|
196
|
+
const previous = await this.extractorPromise;
|
|
197
|
+
await previous?.dispose?.();
|
|
198
|
+
this.extractorPromise = null;
|
|
199
|
+
this.model = urlOrRepoId;
|
|
200
|
+
if (this.isOpenAICompatibleMode()) {
|
|
201
|
+
this.extractorPromise = null;
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
this.resolvedModelSource = resolveModelSource(urlOrRepoId, {
|
|
205
|
+
revision: options.revision ?? this.options.revision ?? (this.isWinzling() ? WINZLING_REVISION : void 0),
|
|
206
|
+
cacheKey: options.cacheKey,
|
|
207
|
+
remoteHost: options.remoteHost,
|
|
208
|
+
remotePathTemplate: options.remotePathTemplate
|
|
209
|
+
});
|
|
210
|
+
this.requiredFiles = options.requiredFiles ?? this.options.requiredFiles;
|
|
211
|
+
this.extractorPromise = null;
|
|
212
|
+
await this.getExtractor();
|
|
213
|
+
}
|
|
214
|
+
async prefetchModel(urlOrRepoId = this.model, options = {}) {
|
|
215
|
+
const source = this.getLocalModelSource("prefetchModel");
|
|
216
|
+
return prefetchModel(urlOrRepoId, {
|
|
217
|
+
revision: options.revision ?? source.revision,
|
|
218
|
+
dtype: options.dtype ?? this.dtype,
|
|
219
|
+
cacheKey: options.cacheKey,
|
|
220
|
+
remoteHost: options.remoteHost,
|
|
221
|
+
remotePathTemplate: options.remotePathTemplate,
|
|
222
|
+
cacheDir: options.cacheDir ?? this.options.cacheDir,
|
|
223
|
+
requiredFiles: options.requiredFiles ?? this.requiredFiles ?? (this.isWinzling() ? WINZLING_PROFILE.requiredFiles : void 0)
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
async inspectModelCache(urlOrRepoId = this.model, options = {}) {
|
|
227
|
+
const source = this.getLocalModelSource("inspectModelCache");
|
|
228
|
+
return inspectModelCache(urlOrRepoId, {
|
|
229
|
+
revision: options.revision ?? source.revision,
|
|
230
|
+
dtype: options.dtype ?? this.dtype,
|
|
231
|
+
cacheKey: options.cacheKey,
|
|
232
|
+
remoteHost: options.remoteHost,
|
|
233
|
+
remotePathTemplate: options.remotePathTemplate,
|
|
234
|
+
cacheDir: options.cacheDir ?? this.options.cacheDir,
|
|
235
|
+
requiredFiles: options.requiredFiles ?? this.requiredFiles ?? (this.isWinzling() ? WINZLING_PROFILE.requiredFiles : void 0)
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
async clearModelCache(urlOrRepoId = this.model, options = {}) {
|
|
239
|
+
const source = this.getLocalModelSource("clearModelCache");
|
|
240
|
+
return clearModelCache(urlOrRepoId, {
|
|
241
|
+
revision: options.revision ?? source.revision,
|
|
242
|
+
dtype: options.dtype ?? this.dtype,
|
|
243
|
+
cacheKey: options.cacheKey,
|
|
244
|
+
remoteHost: options.remoteHost,
|
|
245
|
+
remotePathTemplate: options.remotePathTemplate,
|
|
246
|
+
cacheDir: options.cacheDir ?? this.options.cacheDir,
|
|
247
|
+
requiredFiles: options.requiredFiles ?? this.requiredFiles ?? (this.isWinzling() ? WINZLING_PROFILE.requiredFiles : void 0)
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
embed(input, options = {}) {
|
|
251
|
+
const snapshot = Array.isArray(input) ? [...input] : input;
|
|
252
|
+
return this.enqueue(() => this.embedInternal(snapshot, options));
|
|
253
|
+
}
|
|
254
|
+
async embedInternal(input, options) {
|
|
255
|
+
if (Array.isArray(input) && input.length === 0) return [];
|
|
256
|
+
const shouldNormalize = options.normalize ?? this.options.normalize ?? (this.isWinzling() ? this.options.winzling?.normalize : void 0) ?? DEFAULT_NORMALIZE;
|
|
257
|
+
if (this.options.openAICompatible) {
|
|
258
|
+
const embeddings2 = await fetchOpenAICompatibleEmbeddings(
|
|
259
|
+
input,
|
|
260
|
+
this.model,
|
|
261
|
+
this.options.openAICompatible
|
|
262
|
+
);
|
|
263
|
+
return shouldNormalize ? embeddings2.map((embedding) => normalizeVector(embedding)) : embeddings2;
|
|
264
|
+
}
|
|
265
|
+
const extractor = await this.getExtractor();
|
|
266
|
+
const output = await extractor(input, {
|
|
267
|
+
pooling: options.pooling ?? this.options.pooling ?? (this.isWinzling() ? "mean" : DEFAULT_POOLING),
|
|
268
|
+
normalize: false
|
|
269
|
+
});
|
|
270
|
+
const embeddings = splitTensor(output);
|
|
271
|
+
return shouldNormalize ? embeddings.map((embedding) => normalizeVector(embedding)) : embeddings;
|
|
272
|
+
}
|
|
273
|
+
async embedDocuments(input, options = {}) {
|
|
274
|
+
return this.embed(input, options);
|
|
275
|
+
}
|
|
276
|
+
async embedOne(input, options = {}) {
|
|
277
|
+
const [embedding] = await this.embed(input, options);
|
|
278
|
+
if (!embedding) {
|
|
279
|
+
throw new Error("No embedding returned");
|
|
280
|
+
}
|
|
281
|
+
return embedding;
|
|
282
|
+
}
|
|
283
|
+
async embedQuery(input, options = {}) {
|
|
284
|
+
return (await this.embedQueries([input], options))[0];
|
|
285
|
+
}
|
|
286
|
+
async embedQueries(input, options = {}) {
|
|
287
|
+
const snapshot = [...input];
|
|
288
|
+
return this.enqueue(() => {
|
|
289
|
+
if (this.isWinzling() && (options.instruction || options.preset)) {
|
|
290
|
+
throw new Error("Winzling uses unprefixed queries; instructions/presets are not supported");
|
|
291
|
+
}
|
|
292
|
+
return this.embedInternal(this.isWinzling() ? snapshot : snapshot.map((query) => formatInstructionQuery(query, options)), options);
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
dispose() {
|
|
296
|
+
if (this.closing) return this.closing;
|
|
297
|
+
this.closed = true;
|
|
298
|
+
this.closing = this.queue.then(async () => {
|
|
299
|
+
const extractor = await this.extractorPromise;
|
|
300
|
+
await extractor?.dispose?.();
|
|
301
|
+
this.extractorPromise = null;
|
|
302
|
+
});
|
|
303
|
+
return this.closing;
|
|
304
|
+
}
|
|
305
|
+
async getExtractor() {
|
|
306
|
+
if (this.isOpenAICompatibleMode()) {
|
|
307
|
+
throw new Error(
|
|
308
|
+
"Local extractor access is unavailable when using an OpenAI-compatible embedding endpoint."
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
if (this.extractorPromise !== null) {
|
|
312
|
+
return this.extractorPromise;
|
|
313
|
+
}
|
|
314
|
+
this.extractorPromise = (async () => {
|
|
315
|
+
const source = this.getLocalModelSource("getExtractor");
|
|
316
|
+
if (this.isWinzling()) {
|
|
317
|
+
if (this.dtype !== "q4") throw new Error("Winzling requires dtype: q4 (the model_uint4.onnx artifact)");
|
|
318
|
+
if (source.kind === "repo" && source.input !== WINZLING_MODEL_ID) throw new Error(`modelProfile "winzling" accepts only ${WINZLING_MODEL_ID} or an HTTP(S) mirror, not ${source.input}`);
|
|
319
|
+
if (source.kind === "repo" && source.revision !== WINZLING_REVISION) throw new Error("Winzling support is pinned to the audited WINZLING_REVISION");
|
|
320
|
+
return createWinzlingExtractor({
|
|
321
|
+
...this.options.winzling,
|
|
322
|
+
device: this.options.device ?? this.options.winzling?.device ?? "wasm",
|
|
323
|
+
cacheDir: this.options.winzling?.cacheDir ?? this.options.cacheDir,
|
|
324
|
+
allowRemoteModels: this.options.winzling?.allowRemoteModels ?? this.options.allowRemoteModels,
|
|
325
|
+
...source.kind === "url" ? { modelBaseUrl: source.input } : {}
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
const shouldWarmCacheOnLoad = this.options.warmCacheOnLoad ?? (!this.options.moduleFactory && !this.options.pipelineFactory);
|
|
329
|
+
if (shouldWarmCacheOnLoad) {
|
|
330
|
+
await this.prefetchModel(this.model, {
|
|
331
|
+
revision: source.revision,
|
|
332
|
+
cacheDir: this.options.cacheDir
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
const mod = this.options.moduleFactory ? await this.options.moduleFactory() : await getTransformersModule();
|
|
336
|
+
configureEnv(mod, this.options, this.runtimeDefaults);
|
|
337
|
+
mod.env.remoteHost = source.remoteHost;
|
|
338
|
+
mod.env.remotePathTemplate = source.remotePathTemplate;
|
|
339
|
+
const pipelineFactory = this.options.pipelineFactory ?? mod.pipeline;
|
|
340
|
+
return pipelineFactory("feature-extraction", source.modelId, {
|
|
341
|
+
dtype: this.dtype,
|
|
342
|
+
...this.options.device ? { device: this.options.device } : {},
|
|
343
|
+
...source.revision ? { revision: source.revision } : {}
|
|
344
|
+
});
|
|
345
|
+
})().catch((error) => {
|
|
346
|
+
this.extractorPromise = null;
|
|
347
|
+
throw error;
|
|
348
|
+
});
|
|
349
|
+
return this.extractorPromise;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
export { BaseEmbeddingRuntime as B };
|