sweet-search 0.0.1 → 2.3.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 +190 -0
- package/NOTICE +23 -0
- package/core/cli.js +51 -0
- package/core/config.js +27 -0
- package/core/embedding/embedding-cache.js +467 -0
- package/core/embedding/embedding-local-model.js +845 -0
- package/core/embedding/embedding-remote.js +492 -0
- package/core/embedding/embedding-service.js +712 -0
- package/core/embedding/embedding-telemetry.js +219 -0
- package/core/embedding/index.js +40 -0
- package/core/graph/community-detector.js +294 -0
- package/core/graph/graph-expansion.js +839 -0
- package/core/graph/graph-extractor.js +2304 -0
- package/core/graph/graph-search.js +2148 -0
- package/core/graph/hcgs-generator.js +666 -0
- package/core/graph/index.js +16 -0
- package/core/graph/leiden-algorithm.js +547 -0
- package/core/graph/relationship-resolver.js +366 -0
- package/core/graph/repo-map.js +408 -0
- package/core/graph/summary-manager.js +549 -0
- package/core/indexing/artifact-builder.js +1054 -0
- package/core/indexing/ast-chunker.js +709 -0
- package/core/indexing/chunking/chunk-builder.js +170 -0
- package/core/indexing/chunking/markdown-chunker.js +503 -0
- package/core/indexing/chunking/plaintext-chunker.js +104 -0
- package/core/indexing/dedup/dedup-phase.js +159 -0
- package/core/indexing/dedup/exemplar-selector.js +65 -0
- package/core/indexing/document-chunker.js +56 -0
- package/core/indexing/incremental-parser.js +390 -0
- package/core/indexing/incremental-tracker.js +761 -0
- package/core/indexing/index-codebase-v21.js +472 -0
- package/core/indexing/index-maintainer.mjs +1674 -0
- package/core/indexing/index.js +90 -0
- package/core/indexing/indexer-ann.js +1077 -0
- package/core/indexing/indexer-build.js +742 -0
- package/core/indexing/indexer-phases.js +800 -0
- package/core/indexing/indexer-pool.js +764 -0
- package/core/indexing/indexer-sparse-gram.js +98 -0
- package/core/indexing/indexer-utils.js +536 -0
- package/core/indexing/indexer-worker.js +148 -0
- package/core/indexing/li-skip-policy.js +225 -0
- package/core/indexing/merkle-tracker.js +244 -0
- package/core/indexing/model-pool.js +166 -0
- package/core/infrastructure/code-graph-repository.js +120 -0
- package/core/infrastructure/codebase-repository.js +131 -0
- package/core/infrastructure/config/dedup.js +54 -0
- package/core/infrastructure/config/embedding.js +298 -0
- package/core/infrastructure/config/graph.js +80 -0
- package/core/infrastructure/config/index.js +82 -0
- package/core/infrastructure/config/indexing.js +8 -0
- package/core/infrastructure/config/platform.js +254 -0
- package/core/infrastructure/config/ranking.js +221 -0
- package/core/infrastructure/config/search.js +396 -0
- package/core/infrastructure/config/translation.js +89 -0
- package/core/infrastructure/config/vector-store.js +114 -0
- package/core/infrastructure/constants.js +86 -0
- package/core/infrastructure/coreml-cascade.js +909 -0
- package/core/infrastructure/coreml-cascade.json +46 -0
- package/core/infrastructure/coreml-provider.js +81 -0
- package/core/infrastructure/db-utils.js +69 -0
- package/core/infrastructure/dedup-hashing.js +83 -0
- package/core/infrastructure/hardware-capability.js +332 -0
- package/core/infrastructure/index.js +104 -0
- package/core/infrastructure/language-patterns/maps.js +121 -0
- package/core/infrastructure/language-patterns/registry-core.js +323 -0
- package/core/infrastructure/language-patterns/registry-data-query.js +155 -0
- package/core/infrastructure/language-patterns/registry-object-oriented.js +285 -0
- package/core/infrastructure/language-patterns/registry-tooling.js +240 -0
- package/core/infrastructure/language-patterns/registry-web-style.js +143 -0
- package/core/infrastructure/language-patterns/registry.js +19 -0
- package/core/infrastructure/language-patterns.js +141 -0
- package/core/infrastructure/llm-provider.js +733 -0
- package/core/infrastructure/manifest.json +46 -0
- package/core/infrastructure/maxsim.wasm +0 -0
- package/core/infrastructure/model-fetcher.js +423 -0
- package/core/infrastructure/model-registry.js +214 -0
- package/core/infrastructure/native-inference.js +587 -0
- package/core/infrastructure/native-resolver.js +187 -0
- package/core/infrastructure/native-sparse-gram.js +257 -0
- package/core/infrastructure/native-tokenizer.js +160 -0
- package/core/infrastructure/onnx-mutex.js +45 -0
- package/core/infrastructure/onnx-session-utils.js +261 -0
- package/core/infrastructure/ort-pipeline.js +111 -0
- package/core/infrastructure/project-detector.js +102 -0
- package/core/infrastructure/quantization.js +410 -0
- package/core/infrastructure/simd-distance.js +502 -0
- package/core/infrastructure/simd-distance.wasm +0 -0
- package/core/infrastructure/tree-sitter-provider.js +665 -0
- package/core/infrastructure/webgpu-maxsim.js +222 -0
- package/core/query/index.js +35 -0
- package/core/query/intent-detector.js +201 -0
- package/core/query/intent-router.js +156 -0
- package/core/query/query-router-catboost.js +222 -0
- package/core/query/query-router-ml.js +266 -0
- package/core/query/query-router.js +213 -0
- package/core/ranking/cascaded-scorer.js +379 -0
- package/core/ranking/flashrank.js +810 -0
- package/core/ranking/index.js +49 -0
- package/core/ranking/late-interaction-index.js +2383 -0
- package/core/ranking/late-interaction-model.js +812 -0
- package/core/ranking/local-reranker.js +374 -0
- package/core/ranking/mmr.js +379 -0
- package/core/ranking/quality-scorer.js +363 -0
- package/core/search/context-expander.js +1167 -0
- package/core/search/dedup/sibling-expander.js +327 -0
- package/core/search/index.js +16 -0
- package/core/search/search-boost.js +259 -0
- package/core/search/search-cli.js +544 -0
- package/core/search/search-format.js +282 -0
- package/core/search/search-fusion.js +327 -0
- package/core/search/search-hybrid.js +204 -0
- package/core/search/search-pattern-chunks.js +337 -0
- package/core/search/search-pattern-planner.js +439 -0
- package/core/search/search-pattern-prefilter.js +412 -0
- package/core/search/search-pattern-ripgrep.js +663 -0
- package/core/search/search-pattern.js +463 -0
- package/core/search/search-postprocess.js +452 -0
- package/core/search/search-semantic.js +706 -0
- package/core/search/search-server.js +554 -0
- package/core/search/session-daemon-prewarm.mjs +164 -0
- package/core/search/session-warmup.js +595 -0
- package/core/search/sweet-search.js +632 -0
- package/core/search/warmup-metrics.js +532 -0
- package/core/start-server.js +6 -0
- package/core/training/query-router/features/extractor.js +762 -0
- package/core/training/query-router/features/multilingual-patterns.js +431 -0
- package/core/training/query-router/features/text-segmenter.js +303 -0
- package/core/training/query-router/features/unicode-utils.js +383 -0
- package/core/training/query-router/output/v45_router_d4.js +11521 -0
- package/core/training/query-router/output/v46_router_d4.js +11498 -0
- package/core/vector-store/binary-heap.js +227 -0
- package/core/vector-store/binary-hnsw-index.js +1004 -0
- package/core/vector-store/float-vector-store.js +234 -0
- package/core/vector-store/hnsw-index.js +580 -0
- package/core/vector-store/index.js +39 -0
- package/core/vector-store/seismic-index.js +498 -0
- package/core/vocabulary/index.js +84 -0
- package/core/vocabulary/vocab-constants.js +20 -0
- package/core/vocabulary/vocab-miner-extractors.js +375 -0
- package/core/vocabulary/vocab-miner-nl.js +404 -0
- package/core/vocabulary/vocab-miner-utils.js +146 -0
- package/core/vocabulary/vocab-miner.js +574 -0
- package/core/vocabulary/vocab-prewarm-cli.js +110 -0
- package/core/vocabulary/vocab-ranker.js +492 -0
- package/core/vocabulary/vocab-warmer.js +523 -0
- package/core/vocabulary/vocab-warmup-orchestrator.js +425 -0
- package/core/vocabulary/vocabulary-utils.js +704 -0
- package/crates/wasm-router/pkg/package.json +13 -0
- package/crates/wasm-router/pkg/query_router_wasm.d.ts +36 -0
- package/crates/wasm-router/pkg/query_router_wasm.js +271 -0
- package/crates/wasm-router/pkg/query_router_wasm_bg.wasm +0 -0
- package/crates/wasm-router/pkg/query_router_wasm_bg.wasm.d.ts +19 -0
- package/mcp/config-gen.js +121 -0
- package/mcp/server.js +335 -0
- package/mcp/tool-handlers.js +476 -0
- package/package.json +131 -9
- package/scripts/benchmark-harness.js +794 -0
- package/scripts/init.js +1058 -0
- package/scripts/smoke-test.js +435 -0
- package/scripts/uninstall.js +478 -0
- package/scripts/verify-runtime.js +176 -0
|
@@ -0,0 +1,712 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Embedding Service v2.2 (SOTA December 2025)
|
|
5
|
+
*
|
|
6
|
+
* Facade module - imports from specialized sub-modules and re-exports all public APIs.
|
|
7
|
+
* Hub functions (generateEmbedding, getEmbedding, etc.) live here because they
|
|
8
|
+
* orchestrate across remote, local-model, and cache sub-modules.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { EMBEDDING_CONFIG, EMBEDDING_PROVIDERS } from '../infrastructure/config/index.js';
|
|
12
|
+
import { wasmHammingDistance, wasmInt8Cosine, wasmAsymmetricDistance, wasmInt8BatchDot, isWasmAvailable } from '../infrastructure/simd-distance.js';
|
|
13
|
+
|
|
14
|
+
// --- Sub-module imports (no circular deps) ---
|
|
15
|
+
import {
|
|
16
|
+
circuitBreaker,
|
|
17
|
+
_providerCompressionSupport,
|
|
18
|
+
looksLikeJson,
|
|
19
|
+
RateLimiter,
|
|
20
|
+
TimeWindowRateLimiter,
|
|
21
|
+
rateLimiters,
|
|
22
|
+
timeWindowLimiters,
|
|
23
|
+
callVoyageAPI,
|
|
24
|
+
callMistralAPI,
|
|
25
|
+
callJinaAPI,
|
|
26
|
+
} from './embedding-remote.js';
|
|
27
|
+
|
|
28
|
+
import {
|
|
29
|
+
INDEXING_MAX_LENGTH,
|
|
30
|
+
QUERY_MAX_LENGTH,
|
|
31
|
+
callLocalModel,
|
|
32
|
+
callLocalModelBucketed,
|
|
33
|
+
applyLocalQueryPrefix,
|
|
34
|
+
getLocalPipeline,
|
|
35
|
+
unloadLocalModel,
|
|
36
|
+
isLocalModelLoaded,
|
|
37
|
+
configureLocalModelRuntime,
|
|
38
|
+
resetLocalModelRuntime,
|
|
39
|
+
} from './embedding-local-model.js';
|
|
40
|
+
|
|
41
|
+
import {
|
|
42
|
+
queryCache,
|
|
43
|
+
vocabulary,
|
|
44
|
+
semanticCache,
|
|
45
|
+
queryDeduplicator,
|
|
46
|
+
queryStats,
|
|
47
|
+
cacheStats,
|
|
48
|
+
getCacheStats as _getCacheStats,
|
|
49
|
+
getSemanticCacheStats,
|
|
50
|
+
clearCache,
|
|
51
|
+
getFrequentQueries,
|
|
52
|
+
addToVocabulary as _addToVocabulary,
|
|
53
|
+
expandVocabulary as _expandVocabulary,
|
|
54
|
+
autoPersistFrequentQueries,
|
|
55
|
+
registerAutoPersistOnExit,
|
|
56
|
+
} from './embedding-cache.js';
|
|
57
|
+
|
|
58
|
+
// Re-export sub-module symbols that were previously named exports
|
|
59
|
+
export { circuitBreaker };
|
|
60
|
+
export { TimeWindowRateLimiter };
|
|
61
|
+
|
|
62
|
+
// =============================================================================
|
|
63
|
+
// UNIFIED EMBEDDING SERVICE (hub functions)
|
|
64
|
+
// =============================================================================
|
|
65
|
+
|
|
66
|
+
/** Generate embedding using the active provider with circuit breaker */
|
|
67
|
+
async function generateEmbedding(text, provider = EMBEDDING_CONFIG.provider, isQuery = false) {
|
|
68
|
+
const localText = isQuery ? applyLocalQueryPrefix(text) : text;
|
|
69
|
+
const localMaxLength = isQuery ? QUERY_MAX_LENGTH : INDEXING_MAX_LENGTH;
|
|
70
|
+
|
|
71
|
+
const config = EMBEDDING_PROVIDERS[provider];
|
|
72
|
+
if (!config || !config.enabled) {
|
|
73
|
+
return (await callLocalModel([localText], { maxLength: localMaxLength }))[0];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (provider !== 'local') {
|
|
77
|
+
const circuitCheck = circuitBreaker.canRequest();
|
|
78
|
+
if (!circuitCheck.allowed) {
|
|
79
|
+
console.warn(`[embedding-service] Circuit breaker blocked request: ${circuitCheck.reason}, falling back to local`);
|
|
80
|
+
return (await callLocalModel([localText], { maxLength: localMaxLength }))[0];
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const rateLimit = config.rateLimit;
|
|
85
|
+
let lastError = null;
|
|
86
|
+
|
|
87
|
+
for (let attempt = 0; attempt < (rateLimit?.maxRetries || 3); attempt++) {
|
|
88
|
+
try {
|
|
89
|
+
if (rateLimiters[provider]) {
|
|
90
|
+
await rateLimiters[provider].waitForSlot(text.length);
|
|
91
|
+
}
|
|
92
|
+
cacheStats.apiCalls++;
|
|
93
|
+
|
|
94
|
+
let result;
|
|
95
|
+
switch (provider) {
|
|
96
|
+
case 'voyage':
|
|
97
|
+
result = (await callVoyageAPI([text], config, { inputType: isQuery ? 'query' : 'document' }))[0];
|
|
98
|
+
break;
|
|
99
|
+
case 'mistral':
|
|
100
|
+
result = (await callMistralAPI([text], config))[0];
|
|
101
|
+
break;
|
|
102
|
+
case 'jina':
|
|
103
|
+
result = (await callJinaAPI([text], config, { task: isQuery ? 'retrieval.query' : 'retrieval.passage' }))[0];
|
|
104
|
+
break;
|
|
105
|
+
case 'local':
|
|
106
|
+
result = (await callLocalModel([localText], { maxLength: localMaxLength }))[0];
|
|
107
|
+
break;
|
|
108
|
+
default:
|
|
109
|
+
throw new Error(`Unknown provider: ${provider}`);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (provider !== 'local') circuitBreaker.recordSuccess();
|
|
113
|
+
return result;
|
|
114
|
+
} catch (err) {
|
|
115
|
+
lastError = err;
|
|
116
|
+
if (provider !== 'local') circuitBreaker.recordFailure();
|
|
117
|
+
const delay = (rateLimit?.retryDelay || 1000) * Math.pow(rateLimit?.backoffMultiplier || 2, attempt);
|
|
118
|
+
console.warn(`Embedding attempt ${attempt + 1} failed: ${err.message}, retrying in ${delay}ms`);
|
|
119
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
console.warn(`All attempts failed for ${provider}, falling back to local model`);
|
|
124
|
+
return (await callLocalModel([localText], { maxLength: localMaxLength }))[0];
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** Generate embeddings for multiple texts (batched, V2 concurrent) */
|
|
128
|
+
async function generateEmbeddings(texts, provider = EMBEDDING_CONFIG.provider, options = {}) {
|
|
129
|
+
if (!texts || texts.length === 0) return [];
|
|
130
|
+
|
|
131
|
+
const localBucketOptions = {
|
|
132
|
+
maxLength: options.maxLength,
|
|
133
|
+
hardCap: options.hardCap,
|
|
134
|
+
resolveHardCap: options.resolveHardCap,
|
|
135
|
+
batchingSafety: options.batchingSafety,
|
|
136
|
+
onProgress: options.onProgress,
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
const config = EMBEDDING_PROVIDERS[provider];
|
|
140
|
+
// Local model: always use direct bucketed path for global length-sorting.
|
|
141
|
+
// The API-style batched path (below) splits texts into batchSize=32 chunks
|
|
142
|
+
// which destroys length-sorting and causes massive padding waste (5.5x slower).
|
|
143
|
+
if (!config || !config.enabled || provider === 'local') {
|
|
144
|
+
return callLocalModelBucketed(texts, localBucketOptions);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const batchSize = config.batchSize || 32;
|
|
148
|
+
const concurrency = options.concurrency || 4;
|
|
149
|
+
|
|
150
|
+
const apiOptions = {};
|
|
151
|
+
if (options.outputDimension) apiOptions.outputDimension = options.outputDimension;
|
|
152
|
+
if (options.inputType) apiOptions.inputType = options.inputType;
|
|
153
|
+
|
|
154
|
+
const batches = [];
|
|
155
|
+
for (let i = 0; i < texts.length; i += batchSize) {
|
|
156
|
+
batches.push(texts.slice(i, i + batchSize));
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const results = [];
|
|
160
|
+
|
|
161
|
+
async function embedBatch(batch) {
|
|
162
|
+
if (timeWindowLimiters[provider]) {
|
|
163
|
+
await timeWindowLimiters[provider].acquire();
|
|
164
|
+
}
|
|
165
|
+
cacheStats.apiCalls++;
|
|
166
|
+
|
|
167
|
+
switch (provider) {
|
|
168
|
+
case 'voyage': return callVoyageAPI(batch, config, apiOptions);
|
|
169
|
+
case 'mistral': return callMistralAPI(batch, config, apiOptions);
|
|
170
|
+
case 'jina': return callJinaAPI(batch, config, apiOptions);
|
|
171
|
+
case 'local': return callLocalModelBucketed(batch, localBucketOptions);
|
|
172
|
+
default: throw new Error(`Unknown provider: ${provider}`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
for (let i = 0; i < batches.length; i += concurrency) {
|
|
177
|
+
const concurrent = batches.slice(i, i + concurrency);
|
|
178
|
+
const batchResults = await Promise.all(
|
|
179
|
+
concurrent.map(async (batch) => {
|
|
180
|
+
try {
|
|
181
|
+
return await embedBatch(batch);
|
|
182
|
+
} catch (err) {
|
|
183
|
+
console.warn(`Batch embedding failed: ${err.message}, falling back to local`);
|
|
184
|
+
return callLocalModelBucketed(batch, localBucketOptions);
|
|
185
|
+
}
|
|
186
|
+
})
|
|
187
|
+
);
|
|
188
|
+
for (const batchResult of batchResults) {
|
|
189
|
+
results.push(...batchResult);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return results;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/** Get embedding with caching (LRU -> Vocabulary -> Semantic Cache -> API) */
|
|
197
|
+
export async function getEmbedding(text, options = {}) {
|
|
198
|
+
const { useCache = true, useSemanticCache = true, isQuery = false } = options;
|
|
199
|
+
const start = performance.now();
|
|
200
|
+
const cacheKey = isQuery ? `q:${text}` : text;
|
|
201
|
+
|
|
202
|
+
if (useCache && EMBEDDING_CONFIG.cache?.enabled) {
|
|
203
|
+
const cached = queryCache.get(cacheKey);
|
|
204
|
+
if (cached) {
|
|
205
|
+
cacheStats.hits++;
|
|
206
|
+
return { embedding: cached, cached: true, source: 'lru', latency_us: Math.round((performance.now() - start) * 1000) };
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (isQuery) {
|
|
210
|
+
await vocabulary.load();
|
|
211
|
+
const vocabHit = vocabulary.get(text);
|
|
212
|
+
if (vocabHit) {
|
|
213
|
+
cacheStats.vocabularyHits++;
|
|
214
|
+
queryCache.set(cacheKey, vocabHit);
|
|
215
|
+
return { embedding: vocabHit, cached: true, source: 'vocabulary', latency_us: Math.round((performance.now() - start) * 1000) };
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (isQuery && useSemanticCache && EMBEDDING_CONFIG.isRemote) {
|
|
221
|
+
const semanticResult = await semanticCache.findSimilar(text);
|
|
222
|
+
if (semanticResult?.voyageEmb) {
|
|
223
|
+
cacheStats.hits++;
|
|
224
|
+
if (useCache && EMBEDDING_CONFIG.cache?.enabled) {
|
|
225
|
+
queryCache.set(cacheKey, semanticResult.voyageEmb);
|
|
226
|
+
}
|
|
227
|
+
return {
|
|
228
|
+
embedding: semanticResult.voyageEmb,
|
|
229
|
+
cached: true,
|
|
230
|
+
source: 'semantic-cache',
|
|
231
|
+
similarity: semanticResult.similarity,
|
|
232
|
+
matchedQuery: semanticResult.matchedQuery,
|
|
233
|
+
latency_us: Math.round((performance.now() - start) * 1000),
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
var localEmbForCache = semanticResult?.localEmb;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
cacheStats.misses++;
|
|
240
|
+
|
|
241
|
+
const inflight = queryDeduplicator.get(cacheKey);
|
|
242
|
+
if (inflight) {
|
|
243
|
+
const result = await inflight;
|
|
244
|
+
return { ...result, source: 'deduplicated', latency_us: Math.round((performance.now() - start) * 1000) };
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const embeddingPromise = generateEmbedding(text, EMBEDDING_CONFIG.provider, isQuery);
|
|
248
|
+
queryDeduplicator.set(cacheKey, embeddingPromise.then(emb => ({ embedding: emb })));
|
|
249
|
+
const embedding = await embeddingPromise;
|
|
250
|
+
|
|
251
|
+
if (useCache && EMBEDDING_CONFIG.cache?.enabled) {
|
|
252
|
+
queryCache.set(cacheKey, embedding);
|
|
253
|
+
if (localEmbForCache) {
|
|
254
|
+
semanticCache.add(text, localEmbForCache, embedding);
|
|
255
|
+
}
|
|
256
|
+
if (isQuery && EMBEDDING_CONFIG.cache?.autoExpand) {
|
|
257
|
+
await queryStats.load();
|
|
258
|
+
const usageCount = queryStats.increment(text);
|
|
259
|
+
queryStats.save().catch(() => {});
|
|
260
|
+
const threshold = EMBEDDING_CONFIG.cache?.expansionThreshold || 3;
|
|
261
|
+
if (usageCount >= threshold && !vocabulary.has(text)) {
|
|
262
|
+
vocabulary.set(text, embedding);
|
|
263
|
+
vocabulary.save().catch(() => {});
|
|
264
|
+
console.log(`Vocabulary: Auto-added "${text}" (used ${usageCount}x)`);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
return {
|
|
270
|
+
embedding,
|
|
271
|
+
cached: false,
|
|
272
|
+
source: EMBEDDING_CONFIG.provider,
|
|
273
|
+
latency_us: Math.round((performance.now() - start) * 1000),
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
export async function embed(text, options = {}) {
|
|
278
|
+
const result = await getEmbedding(text, options);
|
|
279
|
+
return result.embedding;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
export async function getEmbeddings(texts, options = {}) {
|
|
283
|
+
const {
|
|
284
|
+
useCache = true,
|
|
285
|
+
provider = EMBEDDING_CONFIG.provider,
|
|
286
|
+
providerOptions = {},
|
|
287
|
+
onProgress,
|
|
288
|
+
} = options;
|
|
289
|
+
|
|
290
|
+
const hasShapeAffectingProviderOptions =
|
|
291
|
+
provider !== EMBEDDING_CONFIG.provider ||
|
|
292
|
+
providerOptions.maxLength !== undefined ||
|
|
293
|
+
providerOptions.outputDimension !== undefined ||
|
|
294
|
+
providerOptions.outputDtype !== undefined ||
|
|
295
|
+
providerOptions.inputType !== undefined;
|
|
296
|
+
const allowCache = useCache && !hasShapeAffectingProviderOptions;
|
|
297
|
+
|
|
298
|
+
const results = new Array(texts.length);
|
|
299
|
+
const uncachedIndices = [];
|
|
300
|
+
const uncachedTexts = [];
|
|
301
|
+
|
|
302
|
+
if (allowCache && EMBEDDING_CONFIG.cache?.enabled) {
|
|
303
|
+
for (let i = 0; i < texts.length; i++) {
|
|
304
|
+
const cached = queryCache.get(texts[i]);
|
|
305
|
+
if (cached) {
|
|
306
|
+
results[i] = { embedding: cached, cached: true };
|
|
307
|
+
cacheStats.hits++;
|
|
308
|
+
} else {
|
|
309
|
+
uncachedIndices.push(i);
|
|
310
|
+
uncachedTexts.push(texts[i]);
|
|
311
|
+
cacheStats.misses++;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
} else {
|
|
315
|
+
for (let i = 0; i < texts.length; i++) {
|
|
316
|
+
uncachedIndices.push(i);
|
|
317
|
+
uncachedTexts.push(texts[i]);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
if (uncachedTexts.length > 0) {
|
|
322
|
+
const newEmbeddings = await generateEmbeddings(uncachedTexts, provider, { ...providerOptions, onProgress });
|
|
323
|
+
for (let i = 0; i < uncachedIndices.length; i++) {
|
|
324
|
+
const idx = uncachedIndices[i];
|
|
325
|
+
results[idx] = { embedding: newEmbeddings[i], cached: false };
|
|
326
|
+
if (allowCache && EMBEDDING_CONFIG.cache?.enabled) {
|
|
327
|
+
queryCache.set(texts[idx], newEmbeddings[i]);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
return results;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// =============================================================================
|
|
336
|
+
// QUANTIZATION / MATH RE-EXPORTS (canonical impls in infrastructure/quantization.js)
|
|
337
|
+
// =============================================================================
|
|
338
|
+
|
|
339
|
+
import {
|
|
340
|
+
truncateForHNSW as _truncateForHNSW,
|
|
341
|
+
fisherYatesShuffle,
|
|
342
|
+
floatToBinary,
|
|
343
|
+
computeCentroid,
|
|
344
|
+
generateSignVector,
|
|
345
|
+
walshHadamardTransform,
|
|
346
|
+
fastRotate,
|
|
347
|
+
asymmetricDocEncode,
|
|
348
|
+
asymmetricQueryEncode,
|
|
349
|
+
floatToInt8,
|
|
350
|
+
normalizedFloatToInt8,
|
|
351
|
+
} from '../infrastructure/quantization.js';
|
|
352
|
+
|
|
353
|
+
export { fisherYatesShuffle, floatToBinary, computeCentroid, generateSignVector, walshHadamardTransform, fastRotate, asymmetricDocEncode, asymmetricQueryEncode };
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Truncate embedding to target dimension and L2 re-normalize.
|
|
357
|
+
* Thin wrapper that supplies the domain-specific default dimension.
|
|
358
|
+
* @param {number[]} embedding
|
|
359
|
+
* @param {number} [targetDim] - defaults to EMBEDDING_CONFIG.hnswDimension
|
|
360
|
+
*/
|
|
361
|
+
export function truncateForHNSW(embedding, targetDim = EMBEDDING_CONFIG.hnswDimension) {
|
|
362
|
+
return _truncateForHNSW(embedding, targetDim);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* Asymmetric distance: 1-bit document vs 4-bit query.
|
|
367
|
+
* Approximates squared distance via asymmetric dot product + correction.
|
|
368
|
+
*/
|
|
369
|
+
export function asymmetricDistance(docBinary, queryInt4, queryNorm) {
|
|
370
|
+
// Delegate to WASM when available
|
|
371
|
+
if (isWasmAvailable()) {
|
|
372
|
+
// WASM version expects integer-scaled queryNorm
|
|
373
|
+
return wasmAsymmetricDistance(docBinary, queryInt4, Math.round(queryNorm));
|
|
374
|
+
}
|
|
375
|
+
let approxDot = 0;
|
|
376
|
+
const dim = queryInt4.length;
|
|
377
|
+
for (let byteIdx = 0; byteIdx < docBinary.length; byteIdx++) {
|
|
378
|
+
let byte = docBinary[byteIdx];
|
|
379
|
+
const baseIdx = byteIdx * 8;
|
|
380
|
+
for (let bit = 7; bit >= 0; bit--) {
|
|
381
|
+
const idx = baseIdx + (7 - bit);
|
|
382
|
+
if (idx >= dim) break;
|
|
383
|
+
if (byte & (1 << bit)) {
|
|
384
|
+
approxDot += queryInt4[idx];
|
|
385
|
+
} else {
|
|
386
|
+
approxDot -= queryInt4[idx];
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
return queryNorm - 2 * approxDot;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
export { floatToInt8, normalizedFloatToInt8 };
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Batch int8 dot product scoring for normalized vectors.
|
|
397
|
+
* Returns scores in cosine-similarity scale [~-1, ~1].
|
|
398
|
+
*
|
|
399
|
+
* For int8 vectors from L2-normalized floats:
|
|
400
|
+
* rawDot ≈ 127² × cos(a_float, b_float)
|
|
401
|
+
* normalizedScore = rawDot / (127 * 127)
|
|
402
|
+
*
|
|
403
|
+
* @param {Int8Array} query - Query int8 vector (from normalizedFloatToInt8)
|
|
404
|
+
* @param {Int8Array[]} candidates - Candidate int8 vectors
|
|
405
|
+
* @returns {Float64Array} Cosine-approximation scores
|
|
406
|
+
*/
|
|
407
|
+
export function int8BatchDotScores(query, candidates) {
|
|
408
|
+
const rawDots = wasmInt8BatchDot(query, candidates);
|
|
409
|
+
const scale = 1.0 / (127 * 127);
|
|
410
|
+
const scores = new Float64Array(rawDots.length);
|
|
411
|
+
for (let i = 0; i < rawDots.length; i++) {
|
|
412
|
+
scores[i] = rawDots[i] * scale;
|
|
413
|
+
}
|
|
414
|
+
return scores;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
const POPCOUNT_TABLE = new Uint8Array(256);
|
|
418
|
+
for (let i = 0; i < 256; i++) {
|
|
419
|
+
POPCOUNT_TABLE[i] = (i & 1) + POPCOUNT_TABLE[i >> 1];
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
export function hammingDistance(a, b) {
|
|
423
|
+
if (a.length !== b.length) {
|
|
424
|
+
throw new Error(`Hamming dimension mismatch: ${a.length} vs ${b.length}`);
|
|
425
|
+
}
|
|
426
|
+
if (isWasmAvailable()) {
|
|
427
|
+
return wasmHammingDistance(a, b);
|
|
428
|
+
}
|
|
429
|
+
let distance = 0;
|
|
430
|
+
for (let i = 0; i < a.length; i++) {
|
|
431
|
+
distance += POPCOUNT_TABLE[a[i] ^ b[i]];
|
|
432
|
+
}
|
|
433
|
+
return distance;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
export function int8CosineSimilarity(a, b) {
|
|
437
|
+
if (a.length !== b.length) {
|
|
438
|
+
throw new Error(`int8CosineSimilarity dimension mismatch: ${a.length} vs ${b.length}`);
|
|
439
|
+
}
|
|
440
|
+
if (isWasmAvailable()) {
|
|
441
|
+
return wasmInt8Cosine(a, b);
|
|
442
|
+
}
|
|
443
|
+
let dot = 0, normA = 0, normB = 0;
|
|
444
|
+
for (let i = 0; i < a.length; i++) {
|
|
445
|
+
dot += a[i] * b[i];
|
|
446
|
+
normA += a[i] * a[i];
|
|
447
|
+
normB += b[i] * b[i];
|
|
448
|
+
}
|
|
449
|
+
normA = Math.sqrt(normA);
|
|
450
|
+
normB = Math.sqrt(normB);
|
|
451
|
+
if (normA === 0 || normB === 0) return 0;
|
|
452
|
+
return dot / (normA * normB);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/** @deprecated Use int8CosineSimilarity (for cosine) or int8BatchDotScores (for normalized dot). */
|
|
456
|
+
export { int8CosineSimilarity as int8DotProduct };
|
|
457
|
+
|
|
458
|
+
// =============================================================================
|
|
459
|
+
// BINARY / INT8 EMBEDDING
|
|
460
|
+
// =============================================================================
|
|
461
|
+
|
|
462
|
+
export async function getBinaryEmbedding(text) {
|
|
463
|
+
const start = performance.now();
|
|
464
|
+
const cacheKey = `binary:${text}`;
|
|
465
|
+
if (EMBEDDING_CONFIG.cache?.enabled) {
|
|
466
|
+
const cached = queryCache.get(cacheKey);
|
|
467
|
+
if (cached) {
|
|
468
|
+
cacheStats.hits++;
|
|
469
|
+
return { binary: cached.binary, float: cached.float, cached: true, source: 'cache', latency_us: Math.round((performance.now() - start) * 1000) };
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// Voyage-native binary (outputDtype: 'ubinary') bypasses the asymmetric
|
|
474
|
+
// quantization pipeline. All providers use client-side quantization so
|
|
475
|
+
// query vectors match the index-time center→rotate→quantize encoding.
|
|
476
|
+
|
|
477
|
+
const floatResult = await getEmbedding(text, { isQuery: true });
|
|
478
|
+
const truncated = truncateForHNSW(floatResult.embedding);
|
|
479
|
+
const binary = floatToBinary(truncated);
|
|
480
|
+
const result = { binary, float: floatResult.embedding, cached: false, source: 'client-quantized', latency_us: Math.round((performance.now() - start) * 1000) };
|
|
481
|
+
if (EMBEDDING_CONFIG.cache?.enabled) queryCache.set(cacheKey, { binary: result.binary, float: result.float });
|
|
482
|
+
return result;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
export async function getInt8Embedding(text) {
|
|
486
|
+
const start = performance.now();
|
|
487
|
+
const cacheKey = `int8:${text}`;
|
|
488
|
+
if (EMBEDDING_CONFIG.cache?.enabled) {
|
|
489
|
+
const cached = queryCache.get(cacheKey);
|
|
490
|
+
if (cached) {
|
|
491
|
+
cacheStats.hits++;
|
|
492
|
+
return { int8: cached.int8, float: cached.float, cached: true, source: 'cache', latency_us: Math.round((performance.now() - start) * 1000) };
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
// All providers use client-side int8 quantization for consistency.
|
|
497
|
+
|
|
498
|
+
const floatResult = await getEmbedding(text, { isQuery: true });
|
|
499
|
+
const truncated = truncateForHNSW(floatResult.embedding);
|
|
500
|
+
const int8 = floatToInt8(truncated);
|
|
501
|
+
const result = { int8, float: floatResult.embedding, cached: false, source: 'client-quantized', latency_us: Math.round((performance.now() - start) * 1000) };
|
|
502
|
+
if (EMBEDDING_CONFIG.cache?.enabled) queryCache.set(cacheKey, { int8: result.int8, float: result.float });
|
|
503
|
+
return result;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
// =============================================================================
|
|
507
|
+
// WARMUP / LIFECYCLE
|
|
508
|
+
// =============================================================================
|
|
509
|
+
|
|
510
|
+
export async function warmup(options = {}) {
|
|
511
|
+
const { initVocabulary = true, initSemanticCache = true } = options;
|
|
512
|
+
|
|
513
|
+
console.log(`\nWarming up embedding service...`);
|
|
514
|
+
console.log(` Provider: ${EMBEDDING_CONFIG.provider} (${EMBEDDING_CONFIG.model})`);
|
|
515
|
+
console.log(` Dimensions: ${EMBEDDING_CONFIG.dimension}d full, ${EMBEDDING_CONFIG.hnswDimension}d HNSW`);
|
|
516
|
+
|
|
517
|
+
const warmupStart = performance.now();
|
|
518
|
+
const warmupTasks = [];
|
|
519
|
+
|
|
520
|
+
if (EMBEDDING_CONFIG.provider === 'local') {
|
|
521
|
+
warmupTasks.push(
|
|
522
|
+
getLocalPipeline().then(() => console.log(` ✓ Local embedding model loaded`))
|
|
523
|
+
);
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
if (initSemanticCache && EMBEDDING_CONFIG.isRemote) {
|
|
527
|
+
warmupTasks.push(
|
|
528
|
+
semanticCache.getLocalModel().then(() => console.log(` ✓ SemanticCache local model loaded`))
|
|
529
|
+
);
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
if (EMBEDDING_CONFIG.isRemote) {
|
|
533
|
+
warmupTasks.push(
|
|
534
|
+
generateEmbedding('warmup')
|
|
535
|
+
.then(() => console.log(` ✓ ${EMBEDDING_CONFIG.provider} API connection verified`))
|
|
536
|
+
.catch(err => console.log(` ⚠ ${EMBEDDING_CONFIG.provider} API: ${err.message}`))
|
|
537
|
+
);
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
if (initVocabulary && EMBEDDING_CONFIG.cache?.enabled) {
|
|
541
|
+
warmupTasks.push(
|
|
542
|
+
vocabulary.load()
|
|
543
|
+
.then(() => console.log(` ✓ Vocabulary loaded (${vocabulary.size()} terms)`))
|
|
544
|
+
);
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
await Promise.all(warmupTasks);
|
|
548
|
+
|
|
549
|
+
const elapsed = Math.round(performance.now() - warmupStart);
|
|
550
|
+
console.log(`Warmup complete in ${elapsed}ms\n`);
|
|
551
|
+
return true;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
export function isWarm() {
|
|
555
|
+
return EMBEDDING_CONFIG.provider === 'local' ? isLocalModelLoaded() : true;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
export function getModelInfo() {
|
|
559
|
+
return {
|
|
560
|
+
provider: EMBEDDING_CONFIG.provider,
|
|
561
|
+
model: EMBEDDING_CONFIG.model,
|
|
562
|
+
dimension: EMBEDDING_CONFIG.dimension,
|
|
563
|
+
hnswDimension: EMBEDDING_CONFIG.hnswDimension,
|
|
564
|
+
isRemote: EMBEDDING_CONFIG.isRemote,
|
|
565
|
+
isWarm: isWarm(),
|
|
566
|
+
cache: { enabled: EMBEDDING_CONFIG.cache?.enabled, ...getCacheStats() },
|
|
567
|
+
availableProviders: Object.entries(EMBEDDING_PROVIDERS)
|
|
568
|
+
.filter(([_, p]) => p.enabled)
|
|
569
|
+
.map(([name, p]) => ({ name, model: p.model, priority: p.priority })),
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
export async function unload() {
|
|
574
|
+
await unloadLocalModel();
|
|
575
|
+
console.log('Local model unloaded');
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
// =============================================================================
|
|
579
|
+
// WRAPPED CACHE EXPORTS (inject dependencies to avoid circular imports)
|
|
580
|
+
// =============================================================================
|
|
581
|
+
|
|
582
|
+
export function getCacheStats() {
|
|
583
|
+
return _getCacheStats(circuitBreaker.getState());
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
export async function addToVocabulary(term) {
|
|
587
|
+
return _addToVocabulary(term, embed);
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
export async function expandVocabulary(terms) {
|
|
591
|
+
return _expandVocabulary(terms, embed);
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
// Re-export cache functions that need no wrapping
|
|
595
|
+
export { getSemanticCacheStats, clearCache, getFrequentQueries, autoPersistFrequentQueries, registerAutoPersistOnExit };
|
|
596
|
+
|
|
597
|
+
// Named exports for internal generator functions (used by vocab-warmer)
|
|
598
|
+
export { generateEmbedding, generateEmbeddings };
|
|
599
|
+
|
|
600
|
+
// Local model runtime configuration (Phase 2 — parallel indexing)
|
|
601
|
+
// Pool lifecycle (initEmbeddingPool / shutdownEmbeddingPool) lives in
|
|
602
|
+
// core/indexing/indexer-pool.js per the DDD dependency matrix.
|
|
603
|
+
export {
|
|
604
|
+
configureLocalModelRuntime,
|
|
605
|
+
resetLocalModelRuntime,
|
|
606
|
+
};
|
|
607
|
+
|
|
608
|
+
// =============================================================================
|
|
609
|
+
// CLI INTERFACE
|
|
610
|
+
// =============================================================================
|
|
611
|
+
|
|
612
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
613
|
+
const args = process.argv.slice(2);
|
|
614
|
+
|
|
615
|
+
if (args.includes('--warmup') || args.includes('warmup')) {
|
|
616
|
+
await warmup({ initVocabulary: true });
|
|
617
|
+
|
|
618
|
+
console.log('--- Cache Performance Test ---');
|
|
619
|
+
const q1 = await getEmbedding('AuthService');
|
|
620
|
+
console.log(`Query 1 "AuthService": ${q1.latency_us}μs (${q1.source})`);
|
|
621
|
+
|
|
622
|
+
const q2 = await getEmbedding('AuthService');
|
|
623
|
+
console.log(`Query 2 "AuthService": ${q2.latency_us}μs (${q2.source})`);
|
|
624
|
+
|
|
625
|
+
const q3 = await getEmbedding('how does authentication work in this codebase');
|
|
626
|
+
console.log(`Query 3 "how does auth work": ${q3.latency_us}μs (${q3.source})`);
|
|
627
|
+
|
|
628
|
+
console.log('\nCache stats:', getCacheStats());
|
|
629
|
+
|
|
630
|
+
} else if (args.includes('--test') || args.includes('test')) {
|
|
631
|
+
console.log('Testing embedding service...\n');
|
|
632
|
+
console.log('Model info:', JSON.stringify(getModelInfo(), null, 2));
|
|
633
|
+
|
|
634
|
+
console.log('\nGenerating test embedding...');
|
|
635
|
+
const result = await getEmbedding('function calculateTotal(items) { return items.reduce((sum, i) => sum + i.price, 0); }');
|
|
636
|
+
console.log(` Embedding dimension: ${result.embedding.length}`);
|
|
637
|
+
console.log(` Source: ${result.source}`);
|
|
638
|
+
console.log(` Latency: ${result.latency_us}μs`);
|
|
639
|
+
|
|
640
|
+
console.log(`\nHNSW truncation: ${result.embedding.length}d → ${truncateForHNSW(result.embedding).length}d`);
|
|
641
|
+
|
|
642
|
+
} else if (args.includes('--stats')) {
|
|
643
|
+
await vocabulary.load();
|
|
644
|
+
console.log('Embedding Service Stats:');
|
|
645
|
+
console.log(JSON.stringify(getModelInfo(), null, 2));
|
|
646
|
+
|
|
647
|
+
} else if (args.includes('--expand')) {
|
|
648
|
+
const terms = args.slice(args.indexOf('--expand') + 1);
|
|
649
|
+
if (terms.length === 0) {
|
|
650
|
+
console.log('Usage: node embedding-service.js --expand term1 term2 ...');
|
|
651
|
+
} else {
|
|
652
|
+
await warmup({ initVocabulary: false });
|
|
653
|
+
const added = await expandVocabulary(terms);
|
|
654
|
+
console.log(`Added ${added} new terms to vocabulary`);
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
} else {
|
|
658
|
+
console.log(`
|
|
659
|
+
Embedding Service v2.2 (SOTA December 2025)
|
|
660
|
+
|
|
661
|
+
Usage:
|
|
662
|
+
node embedding-service.js warmup Preload model + initialize vocabulary
|
|
663
|
+
node embedding-service.js test Test embedding generation
|
|
664
|
+
node embedding-service.js --stats Show model and cache info
|
|
665
|
+
node embedding-service.js --expand term1 term2 Add terms to vocabulary
|
|
666
|
+
|
|
667
|
+
Active Provider: ${EMBEDDING_CONFIG.provider} (${EMBEDDING_CONFIG.model})
|
|
668
|
+
Dimensions: ${EMBEDDING_CONFIG.dimension}d full, ${EMBEDDING_CONFIG.hnswDimension}d HNSW
|
|
669
|
+
|
|
670
|
+
Available Providers:
|
|
671
|
+
${Object.entries(EMBEDDING_PROVIDERS)
|
|
672
|
+
.map(([name, p]) => ` ${p.enabled ? '✓' : '✗'} ${name}: ${p.model} (priority ${p.priority})`)
|
|
673
|
+
.join('\n')}
|
|
674
|
+
`);
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
// Deprecated alias for backward compatibility
|
|
679
|
+
const int8DotProduct = int8CosineSimilarity;
|
|
680
|
+
|
|
681
|
+
export default {
|
|
682
|
+
getEmbedding,
|
|
683
|
+
embed,
|
|
684
|
+
getEmbeddings,
|
|
685
|
+
truncateForHNSW,
|
|
686
|
+
floatToBinary,
|
|
687
|
+
floatToInt8,
|
|
688
|
+
normalizedFloatToInt8,
|
|
689
|
+
hammingDistance,
|
|
690
|
+
int8CosineSimilarity,
|
|
691
|
+
int8DotProduct,
|
|
692
|
+
int8BatchDotScores,
|
|
693
|
+
getBinaryEmbedding,
|
|
694
|
+
getInt8Embedding,
|
|
695
|
+
warmup,
|
|
696
|
+
isWarm,
|
|
697
|
+
getModelInfo,
|
|
698
|
+
unload,
|
|
699
|
+
getCacheStats,
|
|
700
|
+
clearCache,
|
|
701
|
+
addToVocabulary,
|
|
702
|
+
expandVocabulary,
|
|
703
|
+
getFrequentQueries,
|
|
704
|
+
generateEmbedding,
|
|
705
|
+
generateEmbeddings,
|
|
706
|
+
INDEXING_MAX_LENGTH,
|
|
707
|
+
QUERY_MAX_LENGTH,
|
|
708
|
+
callLocalModelBucketed,
|
|
709
|
+
TimeWindowRateLimiter,
|
|
710
|
+
looksLikeJson,
|
|
711
|
+
_providerCompressionSupport,
|
|
712
|
+
};
|