vectra 0.12.2 → 0.14.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 +1 -1
- package/README.md +92 -100
- package/bin/vectra.js +3 -0
- package/lib/BrowserWebFetcher.d.ts +75 -0
- package/lib/BrowserWebFetcher.d.ts.map +1 -0
- package/lib/BrowserWebFetcher.js +290 -0
- package/lib/BrowserWebFetcher.js.map +1 -0
- package/lib/FileFetcher.d.ts +5 -0
- package/lib/FileFetcher.d.ts.map +1 -0
- package/lib/FileFetcher.js +89 -0
- package/lib/FileFetcher.js.map +1 -0
- package/lib/FileFetcher.spec.d.ts +2 -0
- package/lib/FileFetcher.spec.d.ts.map +1 -0
- package/lib/FileFetcher.spec.js +244 -0
- package/lib/FileFetcher.spec.js.map +1 -0
- package/lib/FolderWatcher.d.ts +91 -0
- package/lib/FolderWatcher.d.ts.map +1 -0
- package/lib/FolderWatcher.js +304 -0
- package/lib/FolderWatcher.js.map +1 -0
- package/lib/FolderWatcher.spec.d.ts +2 -0
- package/lib/FolderWatcher.spec.d.ts.map +1 -0
- package/lib/FolderWatcher.spec.js +308 -0
- package/lib/FolderWatcher.spec.js.map +1 -0
- package/lib/GPT3Tokenizer.d.ts +9 -0
- package/lib/GPT3Tokenizer.spec.d.ts +2 -0
- package/lib/GPT3Tokenizer.spec.d.ts.map +1 -0
- package/lib/GPT3Tokenizer.spec.js +45 -0
- package/lib/GPT3Tokenizer.spec.js.map +1 -0
- package/lib/ItemSelector.d.ts +41 -0
- package/lib/ItemSelector.d.ts.map +1 -0
- package/lib/ItemSelector.js +179 -0
- package/lib/ItemSelector.js.map +1 -0
- package/lib/ItemSelector.spec.d.ts +2 -0
- package/lib/ItemSelector.spec.d.ts.map +1 -0
- package/lib/ItemSelector.spec.js +204 -0
- package/lib/ItemSelector.spec.js.map +1 -0
- package/lib/LocalDocument.d.ts +54 -0
- package/lib/LocalDocument.d.ts.map +1 -1
- package/lib/LocalDocument.js +116 -0
- package/lib/LocalDocument.js.map +1 -0
- package/lib/LocalDocument.spec.d.ts +2 -0
- package/lib/LocalDocument.spec.d.ts.map +1 -0
- package/lib/LocalDocument.spec.js +214 -0
- package/lib/LocalDocument.spec.js.map +1 -0
- package/lib/LocalDocumentIndex.d.ts +152 -0
- package/lib/LocalDocumentIndex.d.ts.map +1 -1
- package/lib/LocalDocumentIndex.js +420 -0
- package/lib/LocalDocumentIndex.js.map +1 -0
- package/lib/LocalDocumentIndex.spec.d.ts +2 -0
- package/lib/LocalDocumentIndex.spec.d.ts.map +1 -0
- package/lib/LocalDocumentIndex.spec.js +494 -0
- package/lib/LocalDocumentIndex.spec.js.map +1 -0
- package/lib/LocalDocumentResult.d.ts +66 -0
- package/lib/LocalDocumentResult.d.ts.map +1 -1
- package/lib/LocalDocumentResult.js +376 -0
- package/lib/LocalDocumentResult.js.map +1 -0
- package/lib/LocalDocumentResult.spec.d.ts +2 -0
- package/lib/LocalDocumentResult.spec.d.ts.map +1 -0
- package/lib/LocalDocumentResult.spec.js +373 -0
- package/lib/LocalDocumentResult.spec.js.map +1 -0
- package/lib/LocalEmbeddings.d.ts +59 -0
- package/lib/LocalEmbeddings.d.ts.map +1 -0
- package/lib/LocalEmbeddings.js +101 -0
- package/lib/LocalEmbeddings.js.map +1 -0
- package/lib/LocalEmbeddings.spec.d.ts +2 -0
- package/lib/LocalEmbeddings.spec.d.ts.map +1 -0
- package/lib/LocalEmbeddings.spec.js +155 -0
- package/lib/LocalEmbeddings.spec.js.map +1 -0
- package/lib/LocalIndex.d.ts +159 -0
- package/lib/LocalIndex.d.ts.map +1 -1
- package/lib/LocalIndex.js +519 -0
- package/lib/LocalIndex.js.map +1 -0
- package/lib/LocalIndex.spec.d.ts +2 -0
- package/lib/LocalIndex.spec.js +611 -9
- package/lib/LocalIndex.spec.js.map +1 -1
- package/lib/OpenAIEmbeddings.d.ts +124 -0
- package/lib/OpenAIEmbeddings.d.ts.map +1 -0
- package/lib/OpenAIEmbeddings.js +166 -0
- package/lib/OpenAIEmbeddings.js.map +1 -0
- package/lib/OpenAIEmbeddings.spec.d.ts +2 -0
- package/lib/OpenAIEmbeddings.spec.d.ts.map +1 -0
- package/lib/OpenAIEmbeddings.spec.js +298 -0
- package/lib/OpenAIEmbeddings.spec.js.map +1 -0
- package/lib/TextSplitter.d.ts +21 -0
- package/lib/TextSplitter.d.ts.map +1 -1
- package/lib/TextSplitter.js +500 -0
- package/lib/TextSplitter.js.map +1 -0
- package/lib/TextSplitter.spec.d.ts +2 -0
- package/lib/TextSplitter.spec.d.ts.map +1 -0
- package/lib/TextSplitter.spec.js +337 -0
- package/lib/TextSplitter.spec.js.map +1 -0
- package/lib/TransformersEmbeddings.d.ts +121 -0
- package/lib/TransformersEmbeddings.d.ts.map +1 -0
- package/lib/TransformersEmbeddings.js +176 -0
- package/lib/TransformersEmbeddings.js.map +1 -0
- package/lib/TransformersEmbeddings.spec.d.ts +2 -0
- package/lib/TransformersEmbeddings.spec.d.ts.map +1 -0
- package/lib/TransformersEmbeddings.spec.js +198 -0
- package/lib/TransformersEmbeddings.spec.js.map +1 -0
- package/lib/TransformersTokenizer.d.ts +33 -0
- package/lib/TransformersTokenizer.d.ts.map +1 -0
- package/lib/TransformersTokenizer.js +44 -0
- package/lib/TransformersTokenizer.js.map +1 -0
- package/lib/TransformersTokenizer.spec.d.ts +2 -0
- package/lib/TransformersTokenizer.spec.d.ts.map +1 -0
- package/lib/TransformersTokenizer.spec.js +112 -0
- package/lib/TransformersTokenizer.spec.js.map +1 -0
- package/lib/WebFetcher.d.ts +14 -0
- package/lib/WebFetcher.d.ts.map +1 -0
- package/lib/WebFetcher.js +238 -0
- package/lib/WebFetcher.js.map +1 -0
- package/lib/WebFetcher.spec.d.ts +2 -0
- package/lib/WebFetcher.spec.d.ts.map +1 -0
- package/lib/WebFetcher.spec.js +263 -0
- package/lib/WebFetcher.spec.js.map +1 -0
- package/lib/browser.d.ts +30 -0
- package/lib/browser.d.ts.map +1 -0
- package/lib/browser.js +52 -0
- package/lib/browser.js.map +1 -0
- package/lib/codecs/IndexCodec.d.ts +37 -0
- package/lib/codecs/IndexCodec.d.ts.map +1 -0
- package/lib/codecs/IndexCodec.js +3 -0
- package/lib/codecs/IndexCodec.js.map +1 -0
- package/lib/codecs/JsonCodec.d.ts +19 -0
- package/lib/codecs/JsonCodec.d.ts.map +1 -0
- package/lib/codecs/JsonCodec.js +35 -0
- package/lib/codecs/JsonCodec.js.map +1 -0
- package/lib/codecs/JsonCodec.spec.d.ts +2 -0
- package/lib/codecs/JsonCodec.spec.d.ts.map +1 -0
- package/lib/codecs/JsonCodec.spec.js +66 -0
- package/lib/codecs/JsonCodec.spec.js.map +1 -0
- package/lib/codecs/LocalIndex.protobuf.spec.d.ts +2 -0
- package/lib/codecs/LocalIndex.protobuf.spec.d.ts.map +1 -0
- package/lib/codecs/LocalIndex.protobuf.spec.js +108 -0
- package/lib/codecs/LocalIndex.protobuf.spec.js.map +1 -0
- package/lib/codecs/ProtobufCodec.d.ts +20 -0
- package/lib/codecs/ProtobufCodec.d.ts.map +1 -0
- package/lib/codecs/ProtobufCodec.js +225 -0
- package/lib/codecs/ProtobufCodec.js.map +1 -0
- package/lib/codecs/ProtobufCodec.spec.d.ts +2 -0
- package/lib/codecs/ProtobufCodec.spec.d.ts.map +1 -0
- package/lib/codecs/ProtobufCodec.spec.js +155 -0
- package/lib/codecs/ProtobufCodec.spec.js.map +1 -0
- package/lib/codecs/index.d.ts +5 -0
- package/lib/codecs/index.d.ts.map +1 -0
- package/lib/codecs/index.js +21 -0
- package/lib/codecs/index.js.map +1 -0
- package/lib/codecs/migrateIndex.d.ts +24 -0
- package/lib/codecs/migrateIndex.d.ts.map +1 -0
- package/lib/codecs/migrateIndex.js +119 -0
- package/lib/codecs/migrateIndex.js.map +1 -0
- package/lib/codecs/migrateIndex.spec.d.ts +2 -0
- package/lib/codecs/migrateIndex.spec.d.ts.map +1 -0
- package/lib/codecs/migrateIndex.spec.js +151 -0
- package/lib/codecs/migrateIndex.spec.js.map +1 -0
- package/lib/codecs/schemas/index.proto +34 -0
- package/lib/index.d.ts +20 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +36 -0
- package/lib/index.js.map +1 -0
- package/lib/internals/Colorize.d.ts +14 -0
- package/lib/internals/Colorize.d.ts.map +1 -0
- package/lib/internals/Colorize.js +69 -0
- package/lib/internals/Colorize.js.map +1 -0
- package/lib/internals/index.d.ts +3 -0
- package/lib/internals/index.d.ts.map +1 -0
- package/lib/internals/index.js +19 -0
- package/lib/internals/index.js.map +1 -0
- package/lib/internals/types.d.ts +43 -0
- package/lib/internals/types.d.ts.map +1 -0
- package/lib/internals/types.js +3 -0
- package/lib/internals/types.js.map +1 -0
- package/lib/server/IndexManager.d.ts +78 -0
- package/lib/server/IndexManager.d.ts.map +1 -0
- package/lib/server/IndexManager.js +259 -0
- package/lib/server/IndexManager.js.map +1 -0
- package/lib/server/VectraServer.d.ts +40 -0
- package/lib/server/VectraServer.d.ts.map +1 -0
- package/lib/server/VectraServer.js +151 -0
- package/lib/server/VectraServer.js.map +1 -0
- package/lib/server/VectraServer.spec.d.ts +2 -0
- package/lib/server/VectraServer.spec.d.ts.map +1 -0
- package/lib/server/VectraServer.spec.js +322 -0
- package/lib/server/VectraServer.spec.js.map +1 -0
- package/lib/server/handlers/documentHandlers.d.ts +15 -0
- package/lib/server/handlers/documentHandlers.d.ts.map +1 -0
- package/lib/server/handlers/documentHandlers.js +95 -0
- package/lib/server/handlers/documentHandlers.js.map +1 -0
- package/lib/server/handlers/helpers.d.ts +23 -0
- package/lib/server/handlers/helpers.d.ts.map +1 -0
- package/lib/server/handlers/helpers.js +138 -0
- package/lib/server/handlers/helpers.js.map +1 -0
- package/lib/server/handlers/index.d.ts +8 -0
- package/lib/server/handlers/index.d.ts.map +1 -0
- package/lib/server/handlers/index.js +22 -0
- package/lib/server/handlers/index.js.map +1 -0
- package/lib/server/handlers/indexHandlers.d.ts +14 -0
- package/lib/server/handlers/indexHandlers.d.ts.map +1 -0
- package/lib/server/handlers/indexHandlers.js +85 -0
- package/lib/server/handlers/indexHandlers.js.map +1 -0
- package/lib/server/handlers/itemHandlers.d.ts +34 -0
- package/lib/server/handlers/itemHandlers.d.ts.map +1 -0
- package/lib/server/handlers/itemHandlers.js +166 -0
- package/lib/server/handlers/itemHandlers.js.map +1 -0
- package/lib/server/handlers/lifecycleHandlers.d.ts +11 -0
- package/lib/server/handlers/lifecycleHandlers.d.ts.map +1 -0
- package/lib/server/handlers/lifecycleHandlers.js +31 -0
- package/lib/server/handlers/lifecycleHandlers.js.map +1 -0
- package/lib/server/handlers/queryHandlers.d.ts +27 -0
- package/lib/server/handlers/queryHandlers.d.ts.map +1 -0
- package/lib/server/handlers/queryHandlers.js +135 -0
- package/lib/server/handlers/queryHandlers.js.map +1 -0
- package/lib/server/handlers/statsHandlers.d.ts +17 -0
- package/lib/server/handlers/statsHandlers.d.ts.map +1 -0
- package/lib/server/handlers/statsHandlers.js +81 -0
- package/lib/server/handlers/statsHandlers.js.map +1 -0
- package/lib/server/index.d.ts +4 -0
- package/lib/server/index.d.ts.map +1 -0
- package/lib/server/index.js +23 -0
- package/lib/server/index.js.map +1 -0
- package/lib/storage/FileStorage.d.ts +92 -0
- package/lib/storage/FileStorage.d.ts.map +1 -0
- package/lib/storage/FileStorage.js +3 -0
- package/lib/storage/FileStorage.js.map +1 -0
- package/lib/storage/FileStorageUtilities.d.ts +36 -0
- package/lib/storage/FileStorageUtilities.d.ts.map +1 -0
- package/lib/storage/FileStorageUtilities.js +91 -0
- package/lib/storage/FileStorageUtilities.js.map +1 -0
- package/lib/storage/FileStorageUtilities.spec.d.ts +2 -0
- package/lib/storage/FileStorageUtilities.spec.d.ts.map +1 -0
- package/lib/storage/FileStorageUtilities.spec.js +98 -0
- package/lib/storage/FileStorageUtilities.spec.js.map +1 -0
- package/lib/storage/FileType.d.ts +29 -0
- package/lib/storage/FileType.d.ts.map +1 -0
- package/lib/storage/FileType.js +38 -0
- package/lib/storage/FileType.js.map +1 -0
- package/lib/storage/IndexedDBStorage.d.ts +47 -0
- package/lib/storage/IndexedDBStorage.d.ts.map +1 -0
- package/lib/storage/IndexedDBStorage.js +347 -0
- package/lib/storage/IndexedDBStorage.js.map +1 -0
- package/lib/storage/LocalFileStorage.browser.d.ts +19 -0
- package/lib/storage/LocalFileStorage.browser.d.ts.map +1 -0
- package/lib/storage/LocalFileStorage.browser.js +43 -0
- package/lib/storage/LocalFileStorage.browser.js.map +1 -0
- package/lib/storage/LocalFileStorage.d.ts +23 -0
- package/lib/storage/LocalFileStorage.d.ts.map +1 -0
- package/lib/storage/LocalFileStorage.js +152 -0
- package/lib/storage/LocalFileStorage.js.map +1 -0
- package/lib/storage/LocalFileStorage.spec.d.ts +2 -0
- package/lib/storage/LocalFileStorage.spec.d.ts.map +1 -0
- package/lib/storage/LocalFileStorage.spec.js +249 -0
- package/lib/storage/LocalFileStorage.spec.js.map +1 -0
- package/lib/storage/VirtualFileStorage.d.ts +18 -0
- package/lib/storage/VirtualFileStorage.d.ts.map +1 -0
- package/lib/storage/VirtualFileStorage.js +178 -0
- package/lib/storage/VirtualFileStorage.js.map +1 -0
- package/lib/storage/VirtualFileStorage.spec.d.ts +2 -0
- package/lib/storage/VirtualFileStorage.spec.d.ts.map +1 -0
- package/lib/storage/VirtualFileStorage.spec.js +302 -0
- package/lib/storage/VirtualFileStorage.spec.js.map +1 -0
- package/lib/storage/index.d.ts +6 -0
- package/lib/storage/index.d.ts.map +1 -0
- package/lib/storage/index.js +22 -0
- package/lib/storage/index.js.map +1 -0
- package/lib/templates/templates/csharp/README.md +48 -0
- package/lib/templates/templates/csharp/VectraClient.cs +234 -0
- package/lib/templates/templates/go/README.md +71 -0
- package/lib/templates/templates/go/vectra_client.go +322 -0
- package/lib/templates/templates/java/README.md +81 -0
- package/lib/templates/templates/java/VectraClient.java +232 -0
- package/lib/templates/templates/python/README.md +37 -0
- package/lib/templates/templates/python/vectra_client.py +279 -0
- package/lib/templates/templates/rust/Cargo.toml +14 -0
- package/lib/templates/templates/rust/README.md +39 -0
- package/lib/templates/templates/rust/build.rs +4 -0
- package/lib/templates/templates/rust/lib.rs +284 -0
- package/lib/templates/templates/typescript/README.md +96 -0
- package/lib/templates/templates/typescript/VectraClient.ts +374 -0
- package/lib/templates/typescript/VectraClient.d.ts +114 -0
- package/lib/templates/typescript/VectraClient.d.ts.map +1 -0
- package/lib/templates/typescript/VectraClient.js +328 -0
- package/lib/templates/typescript/VectraClient.js.map +1 -0
- package/lib/types.d.ts +153 -0
- package/lib/types.d.ts.map +1 -0
- package/lib/types.js +3 -0
- package/lib/types.js.map +1 -0
- package/lib/utils/index.d.ts +2 -0
- package/lib/utils/index.d.ts.map +1 -0
- package/lib/utils/index.js +18 -0
- package/lib/utils/index.js.map +1 -0
- package/lib/utils/pathUtils.d.ts +40 -0
- package/lib/utils/pathUtils.d.ts.map +1 -0
- package/lib/utils/pathUtils.js +98 -0
- package/lib/utils/pathUtils.js.map +1 -0
- package/lib/vectra-cli.d.ts +2 -0
- package/lib/vectra-cli.d.ts.map +1 -1
- package/lib/vectra-cli.generate.spec.d.ts +2 -0
- package/lib/vectra-cli.generate.spec.d.ts.map +1 -0
- package/lib/vectra-cli.generate.spec.js +112 -0
- package/lib/vectra-cli.generate.spec.js.map +1 -0
- package/lib/vectra-cli.js +760 -0
- package/lib/vectra-cli.js.map +1 -0
- package/lib/vectra-cli.spec.d.ts +1 -0
- package/lib/vectra-cli.spec.d.ts.map +1 -0
- package/lib/vectra-cli.spec.js +2 -0
- package/lib/vectra-cli.spec.js.map +1 -0
- package/package.json +91 -16
- package/proto/vectra_service.proto +276 -0
- package/src/BrowserWebFetcher.ts +345 -0
- package/src/FileFetcher.spec.ts +234 -0
- package/src/FileFetcher.ts +37 -25
- package/src/FolderWatcher.spec.ts +288 -0
- package/src/FolderWatcher.ts +304 -0
- package/src/GPT3Tokenizer.spec.ts +50 -0
- package/src/ItemSelector.spec.ts +252 -0
- package/src/ItemSelector.ts +163 -150
- package/src/LocalDocument.spec.ts +211 -0
- package/src/LocalDocument.ts +88 -94
- package/src/LocalDocumentIndex.spec.ts +481 -0
- package/src/LocalDocumentIndex.ts +39 -40
- package/src/LocalDocumentResult.spec.ts +373 -0
- package/src/LocalDocumentResult.ts +489 -319
- package/src/LocalEmbeddings.spec.ts +138 -0
- package/src/LocalEmbeddings.ts +120 -0
- package/src/LocalIndex.spec.ts +808 -66
- package/src/LocalIndex.ts +479 -429
- package/src/OpenAIEmbeddings.spec.ts +354 -0
- package/src/OpenAIEmbeddings.ts +26 -27
- package/src/TextSplitter.spec.ts +342 -0
- package/src/TextSplitter.ts +517 -532
- package/src/TransformersEmbeddings.spec.ts +188 -0
- package/src/TransformersEmbeddings.ts +232 -0
- package/src/TransformersTokenizer.spec.ts +143 -0
- package/src/TransformersTokenizer.ts +45 -0
- package/src/WebFetcher.spec.ts +288 -0
- package/src/WebFetcher.ts +184 -186
- package/src/browser.ts +69 -0
- package/src/codecs/IndexCodec.ts +40 -0
- package/src/codecs/JsonCodec.spec.ts +70 -0
- package/src/codecs/JsonCodec.ts +37 -0
- package/src/codecs/LocalIndex.protobuf.spec.ts +115 -0
- package/src/codecs/ProtobufCodec.spec.ts +166 -0
- package/src/codecs/ProtobufCodec.ts +193 -0
- package/src/codecs/index.ts +4 -0
- package/src/codecs/migrateIndex.spec.ts +176 -0
- package/src/codecs/migrateIndex.ts +125 -0
- package/src/codecs/schemas/index.proto +34 -0
- package/src/index.ts +9 -1
- package/src/internals/Colorize.ts +19 -16
- package/src/server/IndexManager.ts +243 -0
- package/src/server/VectraServer.spec.ts +303 -0
- package/src/server/VectraServer.ts +156 -0
- package/src/server/handlers/documentHandlers.ts +59 -0
- package/src/server/handlers/helpers.ts +93 -0
- package/src/server/handlers/index.ts +7 -0
- package/src/server/handlers/indexHandlers.ts +44 -0
- package/src/server/handlers/itemHandlers.ts +140 -0
- package/src/server/handlers/lifecycleHandlers.ts +26 -0
- package/src/server/handlers/queryHandlers.ts +96 -0
- package/src/server/handlers/statsHandlers.ts +38 -0
- package/src/server/index.ts +3 -0
- package/src/storage/FileStorage.ts +105 -0
- package/src/storage/FileStorageUtilities.spec.ts +106 -0
- package/src/storage/FileStorageUtilities.ts +77 -0
- package/src/storage/FileType.ts +61 -0
- package/src/storage/IndexedDBStorage.ts +365 -0
- package/src/storage/LocalFileStorage.browser.ts +52 -0
- package/src/storage/LocalFileStorage.spec.ts +292 -0
- package/src/storage/LocalFileStorage.ts +98 -0
- package/src/storage/VirtualFileStorage.spec.ts +307 -0
- package/src/storage/VirtualFileStorage.ts +169 -0
- package/src/storage/index.ts +5 -0
- package/src/templates/csharp/README.md +48 -0
- package/src/templates/csharp/VectraClient.cs +234 -0
- package/src/templates/go/README.md +71 -0
- package/src/templates/go/vectra_client.go +322 -0
- package/src/templates/java/README.md +81 -0
- package/src/templates/java/VectraClient.java +232 -0
- package/src/templates/python/README.md +37 -0
- package/src/templates/python/vectra_client.py +279 -0
- package/src/templates/rust/Cargo.toml +14 -0
- package/src/templates/rust/README.md +39 -0
- package/src/templates/rust/build.rs +4 -0
- package/src/templates/rust/lib.rs +284 -0
- package/src/templates/typescript/README.md +96 -0
- package/src/templates/typescript/VectraClient.ts +374 -0
- package/src/types.ts +131 -123
- package/src/utils/index.ts +1 -0
- package/src/utils/pathUtils.ts +106 -0
- package/src/vectra-cli.generate.spec.ts +72 -0
- package/src/vectra-cli.spec.ts +0 -0
- package/src/vectra-cli.ts +687 -246
|
@@ -1,358 +1,528 @@
|
|
|
1
1
|
import { LocalDocument } from "./LocalDocument";
|
|
2
2
|
import { LocalDocumentIndex } from "./LocalDocumentIndex";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
QueryResult,
|
|
5
|
+
DocumentChunkMetadata,
|
|
6
|
+
Tokenizer,
|
|
7
|
+
DocumentTextSection,
|
|
8
|
+
} from "./types";
|
|
4
9
|
|
|
5
10
|
/**
|
|
6
11
|
* Represents a search result for a document stored on disk.
|
|
7
12
|
*/
|
|
8
13
|
export class LocalDocumentResult extends LocalDocument {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
14
|
+
private readonly _chunks: QueryResult<DocumentChunkMetadata>[];
|
|
15
|
+
private readonly _tokenizer: Tokenizer;
|
|
16
|
+
private readonly _score: number;
|
|
17
|
+
|
|
18
|
+
public static readonly CONNECTOR = "\n\n...\n\n";
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @private
|
|
22
|
+
* Internal constructor for `LocalDocumentResult` instances.
|
|
23
|
+
*/
|
|
24
|
+
public constructor(
|
|
25
|
+
index: LocalDocumentIndex,
|
|
26
|
+
id: string,
|
|
27
|
+
uri: string,
|
|
28
|
+
chunks: QueryResult<DocumentChunkMetadata>[],
|
|
29
|
+
tokenizer: Tokenizer
|
|
30
|
+
) {
|
|
31
|
+
super(index, id, uri);
|
|
32
|
+
this._chunks = chunks;
|
|
33
|
+
this._tokenizer = tokenizer;
|
|
34
|
+
|
|
35
|
+
// Average score across chunks
|
|
36
|
+
let score = 0;
|
|
37
|
+
this._chunks.forEach((chunk) => (score += chunk.score));
|
|
38
|
+
this._score = this._chunks.length > 0 ? score / this._chunks.length : 0;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Returns the chunks of the document that matched the query.
|
|
43
|
+
*/
|
|
44
|
+
public get chunks(): QueryResult<DocumentChunkMetadata>[] {
|
|
45
|
+
return this._chunks;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Returns the average score of the document result.
|
|
50
|
+
*/
|
|
51
|
+
public get score(): number {
|
|
52
|
+
return this._score;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Helper: robust check for BM25-marked chunks.
|
|
57
|
+
*/
|
|
58
|
+
protected isBm25Chunk(chunk: QueryResult<DocumentChunkMetadata>): boolean {
|
|
59
|
+
const val = chunk.item.metadata?.isBm25 as any;
|
|
60
|
+
return val === true || val === "true" || val === 1 || val === "1";
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* A small, testable packer that mimics the old `renderAllSections()` behavior
|
|
65
|
+
* but exposes the internal flush logic so all branches are coverable.
|
|
66
|
+
*/
|
|
67
|
+
protected createAllSectionsPacker() {
|
|
68
|
+
const sections: DocumentTextSection[] = [];
|
|
69
|
+
|
|
70
|
+
let currentTokens: number[] = [];
|
|
71
|
+
let currentScores: number[] = [];
|
|
72
|
+
let currentIsBm25AllTrue = true;
|
|
73
|
+
|
|
74
|
+
const flush = () => {
|
|
75
|
+
// Branch 1: empty flush
|
|
76
|
+
if (currentTokens.length === 0) return;
|
|
77
|
+
|
|
78
|
+
// Branch 2: avgScore fallback when scores are missing
|
|
79
|
+
const avgScore =
|
|
80
|
+
currentScores.length > 0
|
|
81
|
+
? currentScores.reduce((a, b) => a + b, 0) / currentScores.length
|
|
82
|
+
: 0;
|
|
83
|
+
|
|
84
|
+
// Branch 3: isBm25 depends on "all bm25" and "has scores"
|
|
85
|
+
const isBm25 =
|
|
86
|
+
currentIsBm25AllTrue && currentScores.length > 0 ? true : false;
|
|
87
|
+
|
|
88
|
+
sections.push({
|
|
89
|
+
text: this._tokenizer.decode(currentTokens),
|
|
90
|
+
tokenCount: currentTokens.length,
|
|
91
|
+
score: avgScore,
|
|
92
|
+
isBm25,
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
currentTokens = [];
|
|
96
|
+
currentScores = [];
|
|
97
|
+
currentIsBm25AllTrue = true;
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const pushChunkTokens = (
|
|
101
|
+
tokens: number[],
|
|
102
|
+
score: number,
|
|
103
|
+
isBm25Chunk: boolean
|
|
104
|
+
) => {
|
|
105
|
+
currentTokens.push(...tokens);
|
|
106
|
+
currentScores.push(score);
|
|
107
|
+
currentIsBm25AllTrue = currentIsBm25AllTrue && isBm25Chunk;
|
|
108
|
+
};
|
|
12
109
|
|
|
13
110
|
/**
|
|
14
|
-
*
|
|
15
|
-
*
|
|
111
|
+
* Test-only escape hatch: force internal state to cover otherwise-invariant branches.
|
|
112
|
+
* Not used by production code.
|
|
16
113
|
*/
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
114
|
+
const __testSetState = (state: {
|
|
115
|
+
currentTokens?: number[];
|
|
116
|
+
currentScores?: number[];
|
|
117
|
+
currentIsBm25AllTrue?: boolean;
|
|
118
|
+
}) => {
|
|
119
|
+
if (state.currentTokens) currentTokens = state.currentTokens.slice();
|
|
120
|
+
if (state.currentScores) currentScores = state.currentScores.slice();
|
|
121
|
+
if (typeof state.currentIsBm25AllTrue === "boolean") {
|
|
122
|
+
currentIsBm25AllTrue = state.currentIsBm25AllTrue;
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
const getSections = () => sections;
|
|
127
|
+
|
|
128
|
+
return { flush, pushChunkTokens, getSections, __testSetState };
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Renders all of the results chunks as spans of text (sections.)
|
|
133
|
+
* @remarks
|
|
134
|
+
* - Chunks are sorted by document order.
|
|
135
|
+
* - Multiple small chunks are packed into a single section up to maxTokens.
|
|
136
|
+
* - Oversized chunks are split into multiple sections, each carrying the chunk's score.
|
|
137
|
+
* - When multiple chunks are packed, section score is the arithmetic mean of packed chunks' scores.
|
|
138
|
+
*/
|
|
139
|
+
public async renderAllSections(
|
|
140
|
+
maxTokens: number
|
|
141
|
+
): Promise<DocumentTextSection[]> {
|
|
142
|
+
const docText = await this.loadText();
|
|
143
|
+
|
|
144
|
+
// Sort by document order
|
|
145
|
+
const sorted = this._chunks
|
|
146
|
+
.slice()
|
|
147
|
+
.sort(
|
|
148
|
+
(a, b) =>
|
|
149
|
+
Number(a.item.metadata.startPos) - Number(b.item.metadata.startPos)
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
const packer = this.createAllSectionsPacker();
|
|
153
|
+
|
|
154
|
+
// We'll keep a local "current length" mirror, to avoid re-encoding just to compute lengths.
|
|
155
|
+
let currentLen = 0;
|
|
156
|
+
|
|
157
|
+
const flushAndReset = () => {
|
|
158
|
+
packer.flush();
|
|
159
|
+
currentLen = 0;
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
for (const chunk of sorted) {
|
|
163
|
+
const startPos = Number(chunk.item.metadata.startPos);
|
|
164
|
+
const endPos = Number(chunk.item.metadata.endPos);
|
|
165
|
+
const chunkText = docText.substring(startPos, endPos + 1);
|
|
166
|
+
const tokens = this._tokenizer.encode(chunkText);
|
|
167
|
+
|
|
168
|
+
// Oversized chunk: split
|
|
169
|
+
if (tokens.length > maxTokens) {
|
|
170
|
+
// flush pending packed group
|
|
171
|
+
flushAndReset();
|
|
172
|
+
|
|
173
|
+
let offset = 0;
|
|
174
|
+
while (offset < tokens.length) {
|
|
175
|
+
const part = tokens.slice(offset, offset + maxTokens);
|
|
176
|
+
|
|
177
|
+
// Each split part is its own section (force packer state then flush)
|
|
178
|
+
(packer as any).__testSetState({
|
|
179
|
+
currentTokens: part,
|
|
180
|
+
currentScores: [chunk.score],
|
|
181
|
+
currentIsBm25AllTrue: this.isBm25Chunk(chunk),
|
|
182
|
+
});
|
|
183
|
+
packer.flush();
|
|
184
|
+
offset += part.length;
|
|
185
|
+
}
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Pack if it fits
|
|
190
|
+
if (currentLen + tokens.length <= maxTokens) {
|
|
191
|
+
packer.pushChunkTokens(tokens, chunk.score, this.isBm25Chunk(chunk));
|
|
192
|
+
currentLen += tokens.length;
|
|
193
|
+
} else {
|
|
194
|
+
// overflow: flush, then start new group
|
|
195
|
+
flushAndReset();
|
|
196
|
+
packer.pushChunkTokens(tokens, chunk.score, this.isBm25Chunk(chunk));
|
|
197
|
+
currentLen = tokens.length;
|
|
198
|
+
}
|
|
26
199
|
}
|
|
27
200
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
201
|
+
// final flush
|
|
202
|
+
packer.flush();
|
|
203
|
+
return packer.getSections();
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Testable helper: build a single fallback section from the top-scoring chunk,
|
|
208
|
+
* truncated to exactly maxTokens tokens.
|
|
209
|
+
*/
|
|
210
|
+
protected buildFallbackTopChunkSection(
|
|
211
|
+
docText: string,
|
|
212
|
+
chunks: QueryResult<DocumentChunkMetadata>[],
|
|
213
|
+
isBm25: boolean,
|
|
214
|
+
maxTokens: number
|
|
215
|
+
): DocumentTextSection[] {
|
|
216
|
+
if (chunks.length === 0) return [];
|
|
217
|
+
|
|
218
|
+
const topChunk = chunks.reduce(
|
|
219
|
+
(prev, curr) => (curr.score > prev.score ? curr : prev),
|
|
220
|
+
chunks[0]
|
|
221
|
+
);
|
|
222
|
+
|
|
223
|
+
const start = Number(topChunk.item.metadata.startPos);
|
|
224
|
+
const end = Number(topChunk.item.metadata.endPos);
|
|
225
|
+
const chunkText = docText.substring(start, end + 1);
|
|
226
|
+
const chunkTokens = this._tokenizer.encode(chunkText);
|
|
227
|
+
|
|
228
|
+
const truncatedTokens = chunkTokens.slice(0, maxTokens);
|
|
229
|
+
|
|
230
|
+
return [
|
|
231
|
+
{
|
|
232
|
+
text: this._tokenizer.decode(truncatedTokens),
|
|
233
|
+
tokenCount: maxTokens,
|
|
234
|
+
score: topChunk.score,
|
|
235
|
+
isBm25,
|
|
236
|
+
},
|
|
237
|
+
];
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Internal helper: builds sections for either semantic or BM25 chunk lists using a heatmap.
|
|
242
|
+
*/
|
|
243
|
+
protected buildSectionsFor(
|
|
244
|
+
docText: string,
|
|
245
|
+
chunks: QueryResult<DocumentChunkMetadata>[],
|
|
246
|
+
isBm25: boolean,
|
|
247
|
+
maxTokens: number,
|
|
248
|
+
maxSections: number,
|
|
249
|
+
overlappingChunks: boolean
|
|
250
|
+
): DocumentTextSection[] {
|
|
251
|
+
if (chunks.length === 0) return [];
|
|
252
|
+
|
|
253
|
+
const connector = LocalDocumentResult.CONNECTOR;
|
|
254
|
+
const connectorTokens = this._tokenizer.encode(connector);
|
|
255
|
+
|
|
256
|
+
// Build heatmap: map each character position to accumulated score
|
|
257
|
+
const heatmap = new Map<number, number>();
|
|
258
|
+
for (const chunk of chunks) {
|
|
259
|
+
const start = Number(chunk.item.metadata.startPos);
|
|
260
|
+
const end = Number(chunk.item.metadata.endPos);
|
|
261
|
+
for (let pos = start; pos <= end; pos++) {
|
|
262
|
+
heatmap.set(pos, (heatmap.get(pos) || 0) + chunk.score);
|
|
263
|
+
}
|
|
33
264
|
}
|
|
34
265
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
return this._score;
|
|
266
|
+
interface Peak {
|
|
267
|
+
position: number;
|
|
268
|
+
score: number;
|
|
269
|
+
chunks: QueryResult<DocumentChunkMetadata>[];
|
|
40
270
|
}
|
|
41
271
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
for (let i = 0; i < this._chunks.length; i++) {
|
|
56
|
-
const chunk = this._chunks[i];
|
|
57
|
-
const startPos = chunk.item.metadata.startPos;
|
|
58
|
-
const endPos = chunk.item.metadata.endPos;
|
|
59
|
-
const chunkText = text.substring(startPos, endPos + 1);
|
|
60
|
-
const tokens = this._tokenizer.encode(chunkText);
|
|
61
|
-
let offset = 0;
|
|
62
|
-
while (offset < tokens.length) {
|
|
63
|
-
const chunkLength = Math.min(maxTokens, tokens.length - offset);
|
|
64
|
-
chunks.push({
|
|
65
|
-
text: this._tokenizer.decode(tokens.slice(offset, offset + chunkLength)),
|
|
66
|
-
startPos: startPos + offset,
|
|
67
|
-
endPos: startPos + offset + chunkLength - 1,
|
|
68
|
-
score: chunk.score,
|
|
69
|
-
tokenCount: chunkLength,
|
|
70
|
-
isBm25: false
|
|
71
|
-
});
|
|
72
|
-
offset += chunkLength;
|
|
73
|
-
}
|
|
272
|
+
const peaks: Peak[] = [];
|
|
273
|
+
const sortedPositions = Array.from(heatmap.keys()).sort((a, b) => a - b);
|
|
274
|
+
|
|
275
|
+
let currentPeak: Peak | null = null;
|
|
276
|
+
const PEAK_THRESHOLD = 0.1;
|
|
277
|
+
|
|
278
|
+
for (const pos of sortedPositions) {
|
|
279
|
+
const score = heatmap.get(pos)!;
|
|
280
|
+
|
|
281
|
+
if (score < PEAK_THRESHOLD) {
|
|
282
|
+
if (currentPeak) {
|
|
283
|
+
peaks.push(currentPeak);
|
|
284
|
+
currentPeak = null;
|
|
74
285
|
}
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
75
288
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
const chunk = sorted[i];
|
|
83
|
-
let section = sections[sections.length - 1];
|
|
84
|
-
if (!section || section.tokenCount + chunk.tokenCount > maxTokens) {
|
|
85
|
-
section = {
|
|
86
|
-
chunks: [],
|
|
87
|
-
score: 0,
|
|
88
|
-
tokenCount: 0
|
|
89
|
-
};
|
|
90
|
-
sections.push(section);
|
|
91
|
-
}
|
|
92
|
-
section.chunks.push(chunk);
|
|
93
|
-
section.score += chunk.score;
|
|
94
|
-
section.tokenCount += chunk.tokenCount;
|
|
289
|
+
if (!currentPeak) {
|
|
290
|
+
currentPeak = { position: pos, score, chunks: [] };
|
|
291
|
+
} else {
|
|
292
|
+
if (score > currentPeak.score) {
|
|
293
|
+
currentPeak.position = pos;
|
|
294
|
+
currentPeak.score = score;
|
|
95
295
|
}
|
|
96
|
-
|
|
97
|
-
// Normalize section scores
|
|
98
|
-
sections.forEach(section => section.score /= section.chunks.length);
|
|
99
|
-
|
|
100
|
-
// Return final rendered sections
|
|
101
|
-
return sections.map(section => {
|
|
102
|
-
let text = '';
|
|
103
|
-
section.chunks.forEach(chunk => text += chunk.text);
|
|
104
|
-
return {
|
|
105
|
-
text: text,
|
|
106
|
-
tokenCount: section.tokenCount,
|
|
107
|
-
score: section.score,
|
|
108
|
-
isBm25: false,
|
|
109
|
-
};
|
|
110
|
-
});
|
|
296
|
+
}
|
|
111
297
|
}
|
|
298
|
+
if (currentPeak) peaks.push(currentPeak);
|
|
112
299
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
const text = await this.loadText();
|
|
125
|
-
|
|
126
|
-
// First check to see if the entire document is shorter than maxTokens
|
|
127
|
-
const length = await this.getLength();
|
|
128
|
-
if (length <= maxTokens) {
|
|
129
|
-
return [{
|
|
130
|
-
text,
|
|
131
|
-
tokenCount: length,
|
|
132
|
-
score: 1.0,
|
|
133
|
-
isBm25: false,
|
|
134
|
-
}];
|
|
135
|
-
}
|
|
300
|
+
// No-peaks fallback: create one at center of top chunk
|
|
301
|
+
if (peaks.length === 0) {
|
|
302
|
+
const topChunk = chunks.reduce(
|
|
303
|
+
(prev, curr) => (curr.score > prev.score ? curr : prev),
|
|
304
|
+
chunks[0]
|
|
305
|
+
);
|
|
306
|
+
const start = Number(topChunk.item.metadata.startPos);
|
|
307
|
+
const end = Number(topChunk.item.metadata.endPos);
|
|
308
|
+
const center = Math.floor((start + end) / 2);
|
|
309
|
+
peaks.push({ position: center, score: topChunk.score, chunks: [] });
|
|
310
|
+
}
|
|
136
311
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
startPos,
|
|
152
|
-
endPos,
|
|
153
|
-
score: chunk.score,
|
|
154
|
-
tokenCount: this._tokenizer.encode(chunkText).length,
|
|
155
|
-
isBm25: Boolean(chunk.item.metadata.isBm25),
|
|
156
|
-
};
|
|
157
|
-
}).filter(chunk => chunk.tokenCount <= maxTokens).sort((a, b) => a.startPos - b.startPos);
|
|
158
|
-
|
|
159
|
-
// Check for no chunks
|
|
160
|
-
if (chunks.length === 0) {
|
|
161
|
-
// Take the top chunk and return a subset of its text
|
|
162
|
-
const topChunk = this._chunks[0];
|
|
163
|
-
const startPos = topChunk.item.metadata.startPos;
|
|
164
|
-
const endPos = topChunk.item.metadata.endPos;
|
|
165
|
-
const chunkText = text.substring(startPos, endPos + 1);
|
|
166
|
-
const tokens = this._tokenizer.encode(chunkText);
|
|
167
|
-
return [{
|
|
168
|
-
text: this._tokenizer.decode(tokens.slice(0, maxTokens)),
|
|
169
|
-
tokenCount: maxTokens,
|
|
170
|
-
score: topChunk.score,
|
|
171
|
-
isBm25: false,
|
|
172
|
-
}];
|
|
312
|
+
// Associate chunks to nearest peak
|
|
313
|
+
for (const chunk of chunks) {
|
|
314
|
+
const start = Number(chunk.item.metadata.startPos);
|
|
315
|
+
const end = Number(chunk.item.metadata.endPos);
|
|
316
|
+
const center = Math.floor((start + end) / 2);
|
|
317
|
+
|
|
318
|
+
let closestPeak = peaks[0];
|
|
319
|
+
let minDist = Math.abs(center - closestPeak.position);
|
|
320
|
+
|
|
321
|
+
for (const peak of peaks) {
|
|
322
|
+
const dist = Math.abs(center - peak.position);
|
|
323
|
+
if (dist < minDist) {
|
|
324
|
+
minDist = dist;
|
|
325
|
+
closestPeak = peak;
|
|
173
326
|
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
closestPeak.chunks.push(chunk);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// Sort peaks by score desc
|
|
333
|
+
peaks.sort((a, b) => b.score - a.score);
|
|
334
|
+
const topPeaks = peaks.slice(0, maxSections);
|
|
335
|
+
|
|
336
|
+
const sections: DocumentTextSection[] = [];
|
|
337
|
+
|
|
338
|
+
for (const peak of topPeaks) {
|
|
339
|
+
const sortedChunks = peak.chunks.slice().sort((a, b) => {
|
|
340
|
+
const aCenter = Math.floor(
|
|
341
|
+
(Number(a.item.metadata.startPos) + Number(a.item.metadata.endPos)) / 2
|
|
342
|
+
);
|
|
343
|
+
const bCenter = Math.floor(
|
|
344
|
+
(Number(b.item.metadata.startPos) + Number(b.item.metadata.endPos)) / 2
|
|
345
|
+
);
|
|
346
|
+
return (
|
|
347
|
+
Math.abs(aCenter - peak.position) - Math.abs(bCenter - peak.position)
|
|
348
|
+
);
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
const selected: QueryResult<DocumentChunkMetadata>[] = [];
|
|
352
|
+
let currentTokenCount = 0;
|
|
353
|
+
|
|
354
|
+
for (const chunk of sortedChunks) {
|
|
355
|
+
const start = Number(chunk.item.metadata.startPos);
|
|
356
|
+
const end = Number(chunk.item.metadata.endPos);
|
|
357
|
+
const chunkText = docText.substring(start, end + 1);
|
|
358
|
+
const chunkTokens = this._tokenizer.encode(chunkText);
|
|
174
359
|
|
|
175
|
-
//
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
section.score += chunk.score;
|
|
191
|
-
section.tokenCount += chunk.tokenCount;
|
|
192
|
-
}
|
|
360
|
+
// Whole-chunk preference, skip oversize
|
|
361
|
+
if (chunkTokens.length > maxTokens) continue;
|
|
362
|
+
|
|
363
|
+
let tokensNeeded = chunkTokens.length;
|
|
364
|
+
|
|
365
|
+
if (selected.length > 0 && overlappingChunks) {
|
|
366
|
+
const isAdjacent = selected.some((s) => {
|
|
367
|
+
const sEnd = Number(s.item.metadata.endPos);
|
|
368
|
+
const sStart = Number(s.item.metadata.startPos);
|
|
369
|
+
return sEnd + 1 === start || end + 1 === sStart;
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
if (!isAdjacent) {
|
|
373
|
+
tokensNeeded += connectorTokens.length;
|
|
374
|
+
}
|
|
193
375
|
}
|
|
194
376
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
const chunk = chunks[i];
|
|
199
|
-
let section = bm25Sections[bm25Sections.length - 1];
|
|
200
|
-
if (chunk.isBm25) {
|
|
201
|
-
if (!section || section.tokenCount + chunk.tokenCount > maxTokens) {
|
|
202
|
-
section = {
|
|
203
|
-
chunks: [],
|
|
204
|
-
score: 0,
|
|
205
|
-
tokenCount: 0
|
|
206
|
-
};
|
|
207
|
-
bm25Sections.push(section);
|
|
208
|
-
}
|
|
209
|
-
section.chunks.push(chunk);
|
|
210
|
-
section.score += chunk.score;
|
|
211
|
-
section.tokenCount += chunk.tokenCount;
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
// Normalize section scores
|
|
215
|
-
sections.forEach(section => section.score /= section.chunks.length);
|
|
216
|
-
bm25Sections.forEach(section => section.score /= section.chunks.length);
|
|
217
|
-
|
|
218
|
-
// Sort sections by score and limit to maxSections
|
|
219
|
-
sections.sort((a, b) => b.score - a.score);
|
|
220
|
-
bm25Sections.sort((a, b) => b.score - a.score);
|
|
221
|
-
if (sections.length > maxSections) {
|
|
222
|
-
sections.splice(maxSections, sections.length - maxSections);
|
|
377
|
+
if (currentTokenCount + tokensNeeded <= maxTokens) {
|
|
378
|
+
selected.push(chunk);
|
|
379
|
+
currentTokenCount += tokensNeeded;
|
|
223
380
|
}
|
|
224
|
-
|
|
225
|
-
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// If nothing selected, fall back (required by contract)
|
|
384
|
+
if (selected.length === 0) {
|
|
385
|
+
return this.buildFallbackTopChunkSection(
|
|
386
|
+
docText,
|
|
387
|
+
chunks,
|
|
388
|
+
isBm25,
|
|
389
|
+
maxTokens
|
|
390
|
+
);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// Assemble selected in document order with connectors
|
|
394
|
+
const ordered = selected
|
|
395
|
+
.slice()
|
|
396
|
+
.sort(
|
|
397
|
+
(a, b) =>
|
|
398
|
+
Number(a.item.metadata.startPos) - Number(b.item.metadata.startPos)
|
|
399
|
+
);
|
|
400
|
+
|
|
401
|
+
let sectionText = "";
|
|
402
|
+
let sectionTokens: number[] = [];
|
|
403
|
+
|
|
404
|
+
for (let i = 0; i < ordered.length; i++) {
|
|
405
|
+
const curr = ordered[i];
|
|
406
|
+
const start = Number(curr.item.metadata.startPos);
|
|
407
|
+
const end = Number(curr.item.metadata.endPos);
|
|
408
|
+
const chunkText = docText.substring(start, end + 1);
|
|
409
|
+
|
|
410
|
+
if (i > 0 && overlappingChunks) {
|
|
411
|
+
const prev = ordered[i - 1];
|
|
412
|
+
const prevEnd = Number(prev.item.metadata.endPos);
|
|
413
|
+
if (prevEnd + 1 < start) {
|
|
414
|
+
sectionText += connector;
|
|
415
|
+
sectionTokens.push(...connectorTokens);
|
|
416
|
+
}
|
|
226
417
|
}
|
|
227
418
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
const beforeTex = text.substring(0, section.chunks[0].startPos);
|
|
270
|
-
const beforeTokens = this.encodeBeforeText(beforeTex, Math.ceil(budget/2));
|
|
271
|
-
const beforeBudget = sectionEnd < text.length - 1 ? Math.min(beforeTokens.length, Math.ceil(budget/2)) : Math.min(beforeTokens.length, budget);
|
|
272
|
-
const chunk: SectionChunk = {
|
|
273
|
-
text: this._tokenizer.decode(beforeTokens.slice(-beforeBudget)),
|
|
274
|
-
startPos: sectionStart - beforeBudget,
|
|
275
|
-
endPos: sectionStart - 1,
|
|
276
|
-
score: 0,
|
|
277
|
-
tokenCount: beforeBudget,
|
|
278
|
-
isBm25: false,
|
|
279
|
-
};
|
|
280
|
-
section.chunks.unshift(chunk);
|
|
281
|
-
section.tokenCount += chunk.tokenCount;
|
|
282
|
-
budget -= chunk.tokenCount;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
if (sectionEnd < text.length - 1) {
|
|
286
|
-
const afterText = text.substring(sectionEnd + 1);
|
|
287
|
-
const afterTokens = this.encodeAfterText(afterText, budget);
|
|
288
|
-
const afterBudget = Math.min(afterTokens.length, budget);
|
|
289
|
-
const chunk: SectionChunk = {
|
|
290
|
-
text: this._tokenizer.decode(afterTokens.slice(0, afterBudget)),
|
|
291
|
-
startPos: sectionEnd + 1,
|
|
292
|
-
endPos: sectionEnd + afterBudget,
|
|
293
|
-
score: 0,
|
|
294
|
-
tokenCount: afterBudget,
|
|
295
|
-
isBm25: false,
|
|
296
|
-
};
|
|
297
|
-
section.chunks.push(chunk);
|
|
298
|
-
section.tokenCount += chunk.tokenCount;
|
|
299
|
-
budget -= chunk.tokenCount;
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
});
|
|
419
|
+
sectionText += chunkText;
|
|
420
|
+
sectionTokens.push(...this._tokenizer.encode(chunkText));
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// Optional expansion if budget remains
|
|
424
|
+
if (overlappingChunks) {
|
|
425
|
+
const budgetRemain = maxTokens - sectionTokens.length;
|
|
426
|
+
if (budgetRemain > 40) {
|
|
427
|
+
const firstStart = Math.min(
|
|
428
|
+
...selected.map((c) => Number(c.item.metadata.startPos))
|
|
429
|
+
);
|
|
430
|
+
const lastEnd = Math.max(
|
|
431
|
+
...selected.map((c) => Number(c.item.metadata.endPos))
|
|
432
|
+
);
|
|
433
|
+
|
|
434
|
+
const beforeRegion = docText.slice(0, firstStart);
|
|
435
|
+
const afterRegion = docText.slice(lastEnd + 1);
|
|
436
|
+
|
|
437
|
+
const beforeToksAll = this._tokenizer.encode(beforeRegion);
|
|
438
|
+
const afterToksAll = this._tokenizer.encode(afterRegion);
|
|
439
|
+
|
|
440
|
+
const beforeBudget = Math.min(
|
|
441
|
+
Math.ceil(budgetRemain / 2),
|
|
442
|
+
beforeToksAll.length
|
|
443
|
+
);
|
|
444
|
+
const afterBudget = Math.min(
|
|
445
|
+
budgetRemain - beforeBudget,
|
|
446
|
+
afterToksAll.length
|
|
447
|
+
);
|
|
448
|
+
|
|
449
|
+
const beforeTail = beforeToksAll.slice(
|
|
450
|
+
beforeToksAll.length - beforeBudget
|
|
451
|
+
);
|
|
452
|
+
const afterHead = afterToksAll.slice(0, afterBudget);
|
|
453
|
+
|
|
454
|
+
sectionText =
|
|
455
|
+
this._tokenizer.decode(beforeTail) +
|
|
456
|
+
sectionText +
|
|
457
|
+
this._tokenizer.decode(afterHead);
|
|
458
|
+
|
|
459
|
+
sectionTokens = [...beforeTail, ...sectionTokens, ...afterHead];
|
|
303
460
|
}
|
|
461
|
+
}
|
|
304
462
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
});
|
|
315
|
-
const bm25DocTextSections = bm25Sections.map(section => {
|
|
316
|
-
let text = '';
|
|
317
|
-
section.chunks.forEach(chunk => text += chunk.text);
|
|
318
|
-
return {
|
|
319
|
-
text: text,
|
|
320
|
-
tokenCount: section.tokenCount,
|
|
321
|
-
score: section.score,
|
|
322
|
-
isBm25: true,
|
|
323
|
-
};
|
|
324
|
-
});
|
|
325
|
-
|
|
326
|
-
// Return final rendered sections
|
|
327
|
-
return [...semanticDocTextSections, ...bm25DocTextSections];
|
|
463
|
+
const avgScore =
|
|
464
|
+
selected.reduce((sum, c) => sum + c.score, 0) / selected.length;
|
|
465
|
+
|
|
466
|
+
sections.push({
|
|
467
|
+
text: sectionText,
|
|
468
|
+
tokenCount: sectionTokens.length,
|
|
469
|
+
score: avgScore,
|
|
470
|
+
isBm25,
|
|
471
|
+
});
|
|
328
472
|
}
|
|
329
473
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
return this._tokenizer.encode(substr);
|
|
474
|
+
// If maxSections=0 (or slice emptied), this is reachable:
|
|
475
|
+
if (sections.length === 0) {
|
|
476
|
+
return this.buildFallbackTopChunkSection(docText, chunks, isBm25, maxTokens);
|
|
334
477
|
}
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
478
|
+
|
|
479
|
+
return sections;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
/**
|
|
483
|
+
* Renders the top spans of text (sections) of the document based on the query result.
|
|
484
|
+
*/
|
|
485
|
+
public async renderSections(
|
|
486
|
+
maxTokens: number,
|
|
487
|
+
maxSections: number,
|
|
488
|
+
overlappingChunks = true
|
|
489
|
+
): Promise<DocumentTextSection[]> {
|
|
490
|
+
const length = await this.getLength();
|
|
491
|
+
if (length <= maxTokens) {
|
|
492
|
+
const text = await this.loadText();
|
|
493
|
+
return [
|
|
494
|
+
{
|
|
495
|
+
text,
|
|
496
|
+
tokenCount: length,
|
|
497
|
+
score: 1.0,
|
|
498
|
+
isBm25: false,
|
|
499
|
+
},
|
|
500
|
+
];
|
|
340
501
|
}
|
|
341
502
|
|
|
342
|
-
|
|
503
|
+
const docText = await this.loadText();
|
|
504
|
+
|
|
505
|
+
const semanticChunks = this._chunks.filter((c) => !this.isBm25Chunk(c));
|
|
506
|
+
const bm25Chunks = this._chunks.filter((c) => this.isBm25Chunk(c));
|
|
343
507
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
508
|
+
const semSections = this.buildSectionsFor(
|
|
509
|
+
docText,
|
|
510
|
+
semanticChunks,
|
|
511
|
+
false,
|
|
512
|
+
maxTokens,
|
|
513
|
+
maxSections,
|
|
514
|
+
overlappingChunks
|
|
515
|
+
).slice(0, maxSections);
|
|
352
516
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
517
|
+
const bmSections = this.buildSectionsFor(
|
|
518
|
+
docText,
|
|
519
|
+
bm25Chunks,
|
|
520
|
+
true,
|
|
521
|
+
maxTokens,
|
|
522
|
+
maxSections,
|
|
523
|
+
overlappingChunks
|
|
524
|
+
).slice(0, maxSections);
|
|
358
525
|
|
|
526
|
+
return [...semSections, ...bmSections];
|
|
527
|
+
}
|
|
528
|
+
}
|