kreuzberg 4.0.0.pre.rc.29 → 4.0.0.rc1
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.
- checksums.yaml +4 -4
- data/.gitignore +0 -6
- data/.rubocop.yaml +534 -1
- data/Gemfile +2 -1
- data/Gemfile.lock +28 -116
- data/README.md +269 -629
- data/Rakefile +0 -9
- data/Steepfile +4 -8
- data/examples/async_patterns.rb +58 -1
- data/ext/kreuzberg_rb/extconf.rb +5 -35
- data/ext/kreuzberg_rb/native/Cargo.toml +16 -55
- data/ext/kreuzberg_rb/native/build.rs +14 -12
- data/ext/kreuzberg_rb/native/include/ieeefp.h +1 -1
- data/ext/kreuzberg_rb/native/include/msvc_compat/strings.h +1 -1
- data/ext/kreuzberg_rb/native/include/strings.h +2 -2
- data/ext/kreuzberg_rb/native/include/unistd.h +1 -1
- data/ext/kreuzberg_rb/native/src/lib.rs +34 -897
- data/extconf.rb +6 -38
- data/kreuzberg.gemspec +20 -114
- data/lib/kreuzberg/api_proxy.rb +18 -2
- data/lib/kreuzberg/cache_api.rb +0 -22
- data/lib/kreuzberg/cli.rb +10 -2
- data/lib/kreuzberg/cli_proxy.rb +10 -0
- data/lib/kreuzberg/config.rb +22 -274
- data/lib/kreuzberg/errors.rb +7 -73
- data/lib/kreuzberg/extraction_api.rb +8 -237
- data/lib/kreuzberg/mcp_proxy.rb +11 -2
- data/lib/kreuzberg/ocr_backend_protocol.rb +73 -0
- data/lib/kreuzberg/post_processor_protocol.rb +71 -0
- data/lib/kreuzberg/result.rb +33 -151
- data/lib/kreuzberg/setup_lib_path.rb +2 -22
- data/lib/kreuzberg/validator_protocol.rb +73 -0
- data/lib/kreuzberg/version.rb +1 -1
- data/lib/kreuzberg.rb +13 -27
- data/pkg/kreuzberg-4.0.0.rc1.gem +0 -0
- data/sig/kreuzberg.rbs +12 -105
- data/spec/binding/cache_spec.rb +22 -22
- data/spec/binding/cli_proxy_spec.rb +4 -2
- data/spec/binding/cli_spec.rb +11 -12
- data/spec/binding/config_spec.rb +0 -74
- data/spec/binding/config_validation_spec.rb +6 -100
- data/spec/binding/error_handling_spec.rb +97 -283
- data/spec/binding/plugins/ocr_backend_spec.rb +8 -8
- data/spec/binding/plugins/postprocessor_spec.rb +11 -11
- data/spec/binding/plugins/validator_spec.rb +13 -12
- data/spec/examples.txt +104 -0
- data/spec/fixtures/config.toml +1 -0
- data/spec/fixtures/config.yaml +1 -0
- data/spec/fixtures/invalid_config.toml +1 -0
- data/spec/smoke/package_spec.rb +3 -2
- data/spec/spec_helper.rb +3 -1
- data/vendor/kreuzberg/Cargo.toml +67 -192
- data/vendor/kreuzberg/README.md +9 -97
- data/vendor/kreuzberg/build.rs +194 -516
- data/vendor/kreuzberg/src/api/handlers.rs +9 -130
- data/vendor/kreuzberg/src/api/mod.rs +3 -18
- data/vendor/kreuzberg/src/api/server.rs +71 -236
- data/vendor/kreuzberg/src/api/types.rs +7 -43
- data/vendor/kreuzberg/src/bin/profile_extract.rs +455 -0
- data/vendor/kreuzberg/src/cache/mod.rs +3 -27
- data/vendor/kreuzberg/src/chunking/mod.rs +79 -1705
- data/vendor/kreuzberg/src/core/batch_mode.rs +0 -60
- data/vendor/kreuzberg/src/core/config.rs +23 -905
- data/vendor/kreuzberg/src/core/extractor.rs +106 -403
- data/vendor/kreuzberg/src/core/io.rs +2 -4
- data/vendor/kreuzberg/src/core/mime.rs +12 -2
- data/vendor/kreuzberg/src/core/mod.rs +3 -22
- data/vendor/kreuzberg/src/core/pipeline.rs +78 -395
- data/vendor/kreuzberg/src/embeddings.rs +21 -169
- data/vendor/kreuzberg/src/error.rs +2 -2
- data/vendor/kreuzberg/src/extraction/archive.rs +31 -36
- data/vendor/kreuzberg/src/extraction/docx.rs +1 -365
- data/vendor/kreuzberg/src/extraction/email.rs +11 -12
- data/vendor/kreuzberg/src/extraction/excel.rs +129 -138
- data/vendor/kreuzberg/src/extraction/html.rs +170 -1447
- data/vendor/kreuzberg/src/extraction/image.rs +14 -138
- data/vendor/kreuzberg/src/extraction/libreoffice.rs +3 -13
- data/vendor/kreuzberg/src/extraction/mod.rs +5 -21
- data/vendor/kreuzberg/src/extraction/office_metadata/mod.rs +0 -2
- data/vendor/kreuzberg/src/extraction/pandoc/batch.rs +275 -0
- data/vendor/kreuzberg/src/extraction/pandoc/mime_types.rs +178 -0
- data/vendor/kreuzberg/src/extraction/pandoc/mod.rs +491 -0
- data/vendor/kreuzberg/src/extraction/pandoc/server.rs +496 -0
- data/vendor/kreuzberg/src/extraction/pandoc/subprocess.rs +1188 -0
- data/vendor/kreuzberg/src/extraction/pandoc/version.rs +162 -0
- data/vendor/kreuzberg/src/extraction/pptx.rs +94 -196
- data/vendor/kreuzberg/src/extraction/structured.rs +4 -5
- data/vendor/kreuzberg/src/extraction/table.rs +1 -2
- data/vendor/kreuzberg/src/extraction/text.rs +10 -18
- data/vendor/kreuzberg/src/extractors/archive.rs +0 -22
- data/vendor/kreuzberg/src/extractors/docx.rs +148 -69
- data/vendor/kreuzberg/src/extractors/email.rs +9 -37
- data/vendor/kreuzberg/src/extractors/excel.rs +40 -81
- data/vendor/kreuzberg/src/extractors/html.rs +173 -182
- data/vendor/kreuzberg/src/extractors/image.rs +8 -32
- data/vendor/kreuzberg/src/extractors/mod.rs +10 -171
- data/vendor/kreuzberg/src/extractors/pandoc.rs +201 -0
- data/vendor/kreuzberg/src/extractors/pdf.rs +64 -329
- data/vendor/kreuzberg/src/extractors/pptx.rs +34 -79
- data/vendor/kreuzberg/src/extractors/structured.rs +0 -16
- data/vendor/kreuzberg/src/extractors/text.rs +7 -30
- data/vendor/kreuzberg/src/extractors/xml.rs +8 -27
- data/vendor/kreuzberg/src/keywords/processor.rs +1 -9
- data/vendor/kreuzberg/src/keywords/rake.rs +1 -0
- data/vendor/kreuzberg/src/language_detection/mod.rs +51 -94
- data/vendor/kreuzberg/src/lib.rs +5 -17
- data/vendor/kreuzberg/src/mcp/mod.rs +1 -4
- data/vendor/kreuzberg/src/mcp/server.rs +21 -145
- data/vendor/kreuzberg/src/ocr/mod.rs +0 -2
- data/vendor/kreuzberg/src/ocr/processor.rs +8 -19
- data/vendor/kreuzberg/src/ocr/tesseract_backend.rs +0 -2
- data/vendor/kreuzberg/src/pdf/error.rs +1 -93
- data/vendor/kreuzberg/src/pdf/metadata.rs +100 -263
- data/vendor/kreuzberg/src/pdf/mod.rs +2 -33
- data/vendor/kreuzberg/src/pdf/rendering.rs +12 -12
- data/vendor/kreuzberg/src/pdf/table.rs +64 -61
- data/vendor/kreuzberg/src/pdf/text.rs +24 -416
- data/vendor/kreuzberg/src/plugins/extractor.rs +8 -40
- data/vendor/kreuzberg/src/plugins/mod.rs +0 -3
- data/vendor/kreuzberg/src/plugins/ocr.rs +14 -22
- data/vendor/kreuzberg/src/plugins/processor.rs +1 -10
- data/vendor/kreuzberg/src/plugins/registry.rs +0 -15
- data/vendor/kreuzberg/src/plugins/validator.rs +8 -20
- data/vendor/kreuzberg/src/stopwords/mod.rs +2 -2
- data/vendor/kreuzberg/src/text/mod.rs +0 -8
- data/vendor/kreuzberg/src/text/quality.rs +15 -28
- data/vendor/kreuzberg/src/text/string_utils.rs +10 -22
- data/vendor/kreuzberg/src/text/token_reduction/core.rs +50 -86
- data/vendor/kreuzberg/src/text/token_reduction/filters.rs +16 -37
- data/vendor/kreuzberg/src/text/token_reduction/simd_text.rs +1 -2
- data/vendor/kreuzberg/src/types.rs +67 -907
- data/vendor/kreuzberg/src/utils/mod.rs +0 -14
- data/vendor/kreuzberg/src/utils/quality.rs +3 -12
- data/vendor/kreuzberg/tests/api_tests.rs +0 -506
- data/vendor/kreuzberg/tests/archive_integration.rs +0 -2
- data/vendor/kreuzberg/tests/batch_orchestration.rs +12 -57
- data/vendor/kreuzberg/tests/batch_processing.rs +8 -32
- data/vendor/kreuzberg/tests/chunking_offset_demo.rs +92 -0
- data/vendor/kreuzberg/tests/concurrency_stress.rs +8 -40
- data/vendor/kreuzberg/tests/config_features.rs +1 -33
- data/vendor/kreuzberg/tests/config_loading_tests.rs +39 -16
- data/vendor/kreuzberg/tests/core_integration.rs +9 -35
- data/vendor/kreuzberg/tests/csv_integration.rs +81 -71
- data/vendor/kreuzberg/tests/docx_metadata_extraction_test.rs +25 -23
- data/vendor/kreuzberg/tests/email_integration.rs +1 -3
- data/vendor/kreuzberg/tests/error_handling.rs +34 -43
- data/vendor/kreuzberg/tests/format_integration.rs +1 -7
- data/vendor/kreuzberg/tests/helpers/mod.rs +0 -60
- data/vendor/kreuzberg/tests/image_integration.rs +0 -2
- data/vendor/kreuzberg/tests/mime_detection.rs +16 -17
- data/vendor/kreuzberg/tests/ocr_configuration.rs +0 -4
- data/vendor/kreuzberg/tests/ocr_errors.rs +0 -22
- data/vendor/kreuzberg/tests/ocr_quality.rs +0 -2
- data/vendor/kreuzberg/tests/pandoc_integration.rs +503 -0
- data/vendor/kreuzberg/tests/pdf_integration.rs +0 -2
- data/vendor/kreuzberg/tests/pipeline_integration.rs +2 -36
- data/vendor/kreuzberg/tests/plugin_ocr_backend_test.rs +0 -5
- data/vendor/kreuzberg/tests/plugin_postprocessor_test.rs +1 -17
- data/vendor/kreuzberg/tests/plugin_system.rs +0 -6
- data/vendor/kreuzberg/tests/registry_integration_tests.rs +22 -2
- data/vendor/kreuzberg/tests/security_validation.rs +1 -13
- data/vendor/kreuzberg/tests/test_fastembed.rs +23 -45
- metadata +25 -171
- data/.rubocop.yml +0 -543
- data/ext/kreuzberg_rb/native/.cargo/config.toml +0 -23
- data/ext/kreuzberg_rb/native/Cargo.lock +0 -7619
- data/lib/kreuzberg/error_context.rb +0 -136
- data/lib/kreuzberg/types.rb +0 -170
- data/lib/libpdfium.so +0 -0
- data/spec/binding/async_operations_spec.rb +0 -473
- data/spec/binding/batch_operations_spec.rb +0 -595
- data/spec/binding/batch_spec.rb +0 -359
- data/spec/binding/config_result_spec.rb +0 -377
- data/spec/binding/embeddings_spec.rb +0 -816
- data/spec/binding/error_recovery_spec.rb +0 -488
- data/spec/binding/font_config_spec.rb +0 -220
- data/spec/binding/images_spec.rb +0 -738
- data/spec/binding/keywords_extraction_spec.rb +0 -600
- data/spec/binding/metadata_types_spec.rb +0 -1228
- data/spec/binding/pages_extraction_spec.rb +0 -471
- data/spec/binding/tables_spec.rb +0 -641
- data/spec/unit/config/chunking_config_spec.rb +0 -213
- data/spec/unit/config/embedding_config_spec.rb +0 -343
- data/spec/unit/config/extraction_config_spec.rb +0 -438
- data/spec/unit/config/font_config_spec.rb +0 -285
- data/spec/unit/config/hierarchy_config_spec.rb +0 -314
- data/spec/unit/config/image_extraction_config_spec.rb +0 -209
- data/spec/unit/config/image_preprocessing_config_spec.rb +0 -249
- data/spec/unit/config/keyword_config_spec.rb +0 -229
- data/spec/unit/config/language_detection_config_spec.rb +0 -258
- data/spec/unit/config/ocr_config_spec.rb +0 -171
- data/spec/unit/config/page_config_spec.rb +0 -221
- data/spec/unit/config/pdf_config_spec.rb +0 -267
- data/spec/unit/config/postprocessor_config_spec.rb +0 -290
- data/spec/unit/config/tesseract_config_spec.rb +0 -181
- data/spec/unit/config/token_reduction_config_spec.rb +0 -251
- data/test/metadata_types_test.rb +0 -959
- data/vendor/Cargo.toml +0 -61
- data/vendor/kreuzberg/examples/bench_fixes.rs +0 -71
- data/vendor/kreuzberg/examples/test_pdfium_fork.rs +0 -62
- data/vendor/kreuzberg/src/chunking/processor.rs +0 -219
- data/vendor/kreuzberg/src/core/batch_optimizations.rs +0 -385
- data/vendor/kreuzberg/src/core/config_validation.rs +0 -949
- data/vendor/kreuzberg/src/core/formats.rs +0 -235
- data/vendor/kreuzberg/src/core/server_config.rs +0 -1220
- data/vendor/kreuzberg/src/extraction/capacity.rs +0 -263
- data/vendor/kreuzberg/src/extraction/markdown.rs +0 -216
- data/vendor/kreuzberg/src/extraction/office_metadata/odt_properties.rs +0 -284
- data/vendor/kreuzberg/src/extractors/bibtex.rs +0 -470
- data/vendor/kreuzberg/src/extractors/docbook.rs +0 -504
- data/vendor/kreuzberg/src/extractors/epub.rs +0 -696
- data/vendor/kreuzberg/src/extractors/fictionbook.rs +0 -492
- data/vendor/kreuzberg/src/extractors/jats.rs +0 -1054
- data/vendor/kreuzberg/src/extractors/jupyter.rs +0 -368
- data/vendor/kreuzberg/src/extractors/latex.rs +0 -653
- data/vendor/kreuzberg/src/extractors/markdown.rs +0 -701
- data/vendor/kreuzberg/src/extractors/odt.rs +0 -628
- data/vendor/kreuzberg/src/extractors/opml.rs +0 -635
- data/vendor/kreuzberg/src/extractors/orgmode.rs +0 -529
- data/vendor/kreuzberg/src/extractors/rst.rs +0 -577
- data/vendor/kreuzberg/src/extractors/rtf.rs +0 -809
- data/vendor/kreuzberg/src/extractors/security.rs +0 -484
- data/vendor/kreuzberg/src/extractors/security_tests.rs +0 -367
- data/vendor/kreuzberg/src/extractors/typst.rs +0 -651
- data/vendor/kreuzberg/src/language_detection/processor.rs +0 -218
- data/vendor/kreuzberg/src/ocr/language_registry.rs +0 -520
- data/vendor/kreuzberg/src/panic_context.rs +0 -154
- data/vendor/kreuzberg/src/pdf/bindings.rs +0 -306
- data/vendor/kreuzberg/src/pdf/bundled.rs +0 -408
- data/vendor/kreuzberg/src/pdf/fonts.rs +0 -358
- data/vendor/kreuzberg/src/pdf/hierarchy.rs +0 -903
- data/vendor/kreuzberg/src/text/quality_processor.rs +0 -231
- data/vendor/kreuzberg/src/text/utf8_validation.rs +0 -193
- data/vendor/kreuzberg/src/utils/pool.rs +0 -503
- data/vendor/kreuzberg/src/utils/pool_sizing.rs +0 -364
- data/vendor/kreuzberg/src/utils/string_pool.rs +0 -761
- data/vendor/kreuzberg/tests/api_embed.rs +0 -360
- data/vendor/kreuzberg/tests/api_extract_multipart.rs +0 -52
- data/vendor/kreuzberg/tests/api_large_pdf_extraction.rs +0 -471
- data/vendor/kreuzberg/tests/api_large_pdf_extraction_diagnostics.rs +0 -289
- data/vendor/kreuzberg/tests/batch_pooling_benchmark.rs +0 -154
- data/vendor/kreuzberg/tests/bibtex_parity_test.rs +0 -421
- data/vendor/kreuzberg/tests/config_integration_test.rs +0 -753
- data/vendor/kreuzberg/tests/data/hierarchy_ground_truth.json +0 -294
- data/vendor/kreuzberg/tests/docbook_extractor_tests.rs +0 -500
- data/vendor/kreuzberg/tests/docx_vs_pandoc_comparison.rs +0 -370
- data/vendor/kreuzberg/tests/epub_native_extractor_tests.rs +0 -275
- data/vendor/kreuzberg/tests/fictionbook_extractor_tests.rs +0 -228
- data/vendor/kreuzberg/tests/html_table_test.rs +0 -551
- data/vendor/kreuzberg/tests/instrumentation_test.rs +0 -139
- data/vendor/kreuzberg/tests/jats_extractor_tests.rs +0 -639
- data/vendor/kreuzberg/tests/jupyter_extractor_tests.rs +0 -704
- data/vendor/kreuzberg/tests/latex_extractor_tests.rs +0 -496
- data/vendor/kreuzberg/tests/markdown_extractor_tests.rs +0 -490
- data/vendor/kreuzberg/tests/ocr_language_registry.rs +0 -191
- data/vendor/kreuzberg/tests/odt_extractor_tests.rs +0 -674
- data/vendor/kreuzberg/tests/opml_extractor_tests.rs +0 -616
- data/vendor/kreuzberg/tests/orgmode_extractor_tests.rs +0 -822
- data/vendor/kreuzberg/tests/page_markers.rs +0 -297
- data/vendor/kreuzberg/tests/pdf_hierarchy_detection.rs +0 -301
- data/vendor/kreuzberg/tests/pdf_hierarchy_quality.rs +0 -589
- data/vendor/kreuzberg/tests/pdf_ocr_triggering.rs +0 -301
- data/vendor/kreuzberg/tests/pdf_text_merging.rs +0 -475
- data/vendor/kreuzberg/tests/pdfium_linking.rs +0 -340
- data/vendor/kreuzberg/tests/rst_extractor_tests.rs +0 -694
- data/vendor/kreuzberg/tests/rtf_extractor_tests.rs +0 -775
- data/vendor/kreuzberg/tests/typst_behavioral_tests.rs +0 -1260
- data/vendor/kreuzberg/tests/typst_extractor_tests.rs +0 -648
- data/vendor/kreuzberg-ffi/Cargo.toml +0 -67
- data/vendor/kreuzberg-ffi/README.md +0 -851
- data/vendor/kreuzberg-ffi/benches/result_view_benchmark.rs +0 -227
- data/vendor/kreuzberg-ffi/build.rs +0 -168
- data/vendor/kreuzberg-ffi/cbindgen.toml +0 -37
- data/vendor/kreuzberg-ffi/kreuzberg-ffi.pc.in +0 -12
- data/vendor/kreuzberg-ffi/kreuzberg.h +0 -3012
- data/vendor/kreuzberg-ffi/src/batch_streaming.rs +0 -588
- data/vendor/kreuzberg-ffi/src/config.rs +0 -1341
- data/vendor/kreuzberg-ffi/src/error.rs +0 -901
- data/vendor/kreuzberg-ffi/src/extraction.rs +0 -555
- data/vendor/kreuzberg-ffi/src/helpers.rs +0 -879
- data/vendor/kreuzberg-ffi/src/lib.rs +0 -977
- data/vendor/kreuzberg-ffi/src/memory.rs +0 -493
- data/vendor/kreuzberg-ffi/src/mime.rs +0 -329
- data/vendor/kreuzberg-ffi/src/panic_shield.rs +0 -265
- data/vendor/kreuzberg-ffi/src/plugins/document_extractor.rs +0 -442
- data/vendor/kreuzberg-ffi/src/plugins/mod.rs +0 -14
- data/vendor/kreuzberg-ffi/src/plugins/ocr_backend.rs +0 -628
- data/vendor/kreuzberg-ffi/src/plugins/post_processor.rs +0 -438
- data/vendor/kreuzberg-ffi/src/plugins/validator.rs +0 -329
- data/vendor/kreuzberg-ffi/src/result.rs +0 -510
- data/vendor/kreuzberg-ffi/src/result_pool.rs +0 -639
- data/vendor/kreuzberg-ffi/src/result_view.rs +0 -773
- data/vendor/kreuzberg-ffi/src/string_intern.rs +0 -568
- data/vendor/kreuzberg-ffi/src/types.rs +0 -363
- data/vendor/kreuzberg-ffi/src/util.rs +0 -210
- data/vendor/kreuzberg-ffi/src/validation.rs +0 -848
- data/vendor/kreuzberg-ffi/tests.disabled/README.md +0 -48
- data/vendor/kreuzberg-ffi/tests.disabled/config_loading_tests.rs +0 -299
- data/vendor/kreuzberg-ffi/tests.disabled/config_tests.rs +0 -346
- data/vendor/kreuzberg-ffi/tests.disabled/extractor_tests.rs +0 -232
- data/vendor/kreuzberg-ffi/tests.disabled/plugin_registration_tests.rs +0 -470
- data/vendor/kreuzberg-tesseract/.commitlintrc.json +0 -13
- data/vendor/kreuzberg-tesseract/.crate-ignore +0 -2
- data/vendor/kreuzberg-tesseract/Cargo.lock +0 -2933
- data/vendor/kreuzberg-tesseract/Cargo.toml +0 -57
- data/vendor/kreuzberg-tesseract/LICENSE +0 -22
- data/vendor/kreuzberg-tesseract/README.md +0 -399
- data/vendor/kreuzberg-tesseract/build.rs +0 -1127
- data/vendor/kreuzberg-tesseract/patches/README.md +0 -71
- data/vendor/kreuzberg-tesseract/patches/tesseract.diff +0 -199
- data/vendor/kreuzberg-tesseract/src/api.rs +0 -1371
- data/vendor/kreuzberg-tesseract/src/choice_iterator.rs +0 -77
- data/vendor/kreuzberg-tesseract/src/enums.rs +0 -297
- data/vendor/kreuzberg-tesseract/src/error.rs +0 -81
- data/vendor/kreuzberg-tesseract/src/lib.rs +0 -145
- data/vendor/kreuzberg-tesseract/src/monitor.rs +0 -57
- data/vendor/kreuzberg-tesseract/src/mutable_iterator.rs +0 -197
- data/vendor/kreuzberg-tesseract/src/page_iterator.rs +0 -253
- data/vendor/kreuzberg-tesseract/src/result_iterator.rs +0 -286
- data/vendor/kreuzberg-tesseract/src/result_renderer.rs +0 -183
- data/vendor/kreuzberg-tesseract/tests/integration_test.rs +0 -211
|
@@ -1,816 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
RSpec.describe 'Embeddings Vector Generation' do
|
|
4
|
-
describe 'vector generation correctness' do
|
|
5
|
-
it 'generates embedding vectors with correct dimensions' do
|
|
6
|
-
config = Kreuzberg::Config::Extraction.new(
|
|
7
|
-
chunking: Kreuzberg::Config::Chunking.new(
|
|
8
|
-
enabled: true,
|
|
9
|
-
max_chars: 500,
|
|
10
|
-
embedding: Kreuzberg::Config::Embedding.new(
|
|
11
|
-
model: { type: :preset, name: 'balanced' },
|
|
12
|
-
normalize: true,
|
|
13
|
-
batch_size: 32
|
|
14
|
-
)
|
|
15
|
-
)
|
|
16
|
-
)
|
|
17
|
-
|
|
18
|
-
text = 'Machine learning transforms technology. Artificial intelligence enables automation and prediction across industries.'
|
|
19
|
-
result = Kreuzberg.extract_bytes_sync(data: text, mime_type: 'text/plain', config: config)
|
|
20
|
-
|
|
21
|
-
expect(result).not_to be_nil
|
|
22
|
-
expect(result.chunks).not_to be_nil
|
|
23
|
-
unless result.chunks.empty?
|
|
24
|
-
first_chunk = result.chunks.first
|
|
25
|
-
expect(first_chunk.embedding).not_to be_nil if first_chunk.embedding
|
|
26
|
-
if first_chunk.embedding.is_a?(Array) && !first_chunk.embedding.empty?
|
|
27
|
-
dimension = first_chunk.embedding.length
|
|
28
|
-
expect(dimension).to be_in([384, 512, 768, 1024])
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
it 'produces numeric embedding vectors' do
|
|
34
|
-
config = Kreuzberg::Config::Extraction.new(
|
|
35
|
-
chunking: Kreuzberg::Config::Chunking.new(
|
|
36
|
-
enabled: true,
|
|
37
|
-
embedding: Kreuzberg::Config::Embedding.new(
|
|
38
|
-
model: { type: :preset, name: 'balanced' },
|
|
39
|
-
normalize: true
|
|
40
|
-
)
|
|
41
|
-
)
|
|
42
|
-
)
|
|
43
|
-
|
|
44
|
-
text = 'Deep learning neural networks enable complex pattern recognition.'
|
|
45
|
-
result = Kreuzberg.extract_bytes_sync(data: text, mime_type: 'text/plain', config: config)
|
|
46
|
-
|
|
47
|
-
expect(result).not_to be_nil
|
|
48
|
-
if result.chunks && !result.chunks.empty? && result.chunks.first.embedding
|
|
49
|
-
embedding = result.chunks.first.embedding
|
|
50
|
-
expect(embedding).to be_a(Array)
|
|
51
|
-
expect(embedding).to all(be_a(Numeric))
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
it 'generates consistent vectors for same input' do
|
|
56
|
-
config = Kreuzberg::Config::Extraction.new(
|
|
57
|
-
chunking: Kreuzberg::Config::Chunking.new(
|
|
58
|
-
enabled: true,
|
|
59
|
-
embedding: Kreuzberg::Config::Embedding.new(
|
|
60
|
-
model: { type: :preset, name: 'balanced' }
|
|
61
|
-
)
|
|
62
|
-
)
|
|
63
|
-
)
|
|
64
|
-
|
|
65
|
-
text = 'Artificial intelligence transforms technology development.'
|
|
66
|
-
result1 = Kreuzberg.extract_bytes_sync(data: text, mime_type: 'text/plain', config: config)
|
|
67
|
-
result2 = Kreuzberg.extract_bytes_sync(data: text, mime_type: 'text/plain', config: config)
|
|
68
|
-
|
|
69
|
-
expect(result1).not_to be_nil
|
|
70
|
-
expect(result2).not_to be_nil
|
|
71
|
-
|
|
72
|
-
if result1.chunks && result2.chunks && !result1.chunks.empty? && !result2.chunks.empty? && result1.chunks.first.embedding && result2.chunks.first.embedding
|
|
73
|
-
expect(result1.chunks.first.embedding).to eq(result2.chunks.first.embedding)
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
describe 'embedding dimension verification' do
|
|
79
|
-
it 'validates embedding vector length consistency within batch' do
|
|
80
|
-
config = Kreuzberg::Config::Extraction.new(
|
|
81
|
-
chunking: Kreuzberg::Config::Chunking.new(
|
|
82
|
-
enabled: true,
|
|
83
|
-
max_chars: 300,
|
|
84
|
-
embedding: Kreuzberg::Config::Embedding.new(
|
|
85
|
-
model: { type: :preset, name: 'balanced' },
|
|
86
|
-
batch_size: 8
|
|
87
|
-
)
|
|
88
|
-
)
|
|
89
|
-
)
|
|
90
|
-
|
|
91
|
-
text = 'Machine learning techniques evolve continuously. Neural networks improve performance. Data science enables insights.'
|
|
92
|
-
result = Kreuzberg.extract_bytes_sync(data: text, mime_type: 'text/plain', config: config)
|
|
93
|
-
|
|
94
|
-
expect(result).not_to be_nil
|
|
95
|
-
if result.chunks && result.chunks.length > 1
|
|
96
|
-
embedding_dims = result.chunks
|
|
97
|
-
.select { |chunk| chunk.embedding.is_a?(Array) }
|
|
98
|
-
.map { |chunk| chunk.embedding.length }
|
|
99
|
-
.uniq
|
|
100
|
-
|
|
101
|
-
# All embeddings should have consistent dimensions
|
|
102
|
-
expect(embedding_dims.length).to eq(1)
|
|
103
|
-
end
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
it 'respects configured batch size for embeddings' do
|
|
107
|
-
batch_sizes = [8, 16, 32]
|
|
108
|
-
|
|
109
|
-
batch_sizes.each do |batch_size|
|
|
110
|
-
config = Kreuzberg::Config::Extraction.new(
|
|
111
|
-
chunking: Kreuzberg::Config::Chunking.new(
|
|
112
|
-
enabled: true,
|
|
113
|
-
max_chars: 200,
|
|
114
|
-
embedding: Kreuzberg::Config::Embedding.new(
|
|
115
|
-
model: { type: :preset, name: 'balanced' },
|
|
116
|
-
batch_size: batch_size
|
|
117
|
-
)
|
|
118
|
-
)
|
|
119
|
-
)
|
|
120
|
-
|
|
121
|
-
text = 'Technology transforms industries. Machine learning advances AI. Neural networks improve models. Data analysis drives decisions.'
|
|
122
|
-
result = Kreuzberg.extract_bytes_sync(data: text, mime_type: 'text/plain', config: config)
|
|
123
|
-
|
|
124
|
-
expect(result).not_to be_nil
|
|
125
|
-
expect(result.chunks).not_to be_nil
|
|
126
|
-
end
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
it 'confirms embedding dimensions match model specification' do
|
|
130
|
-
config = Kreuzberg::Config::Extraction.new(
|
|
131
|
-
chunking: Kreuzberg::Config::Chunking.new(
|
|
132
|
-
enabled: true,
|
|
133
|
-
embedding: Kreuzberg::Config::Embedding.new(
|
|
134
|
-
model: { type: :preset, name: 'balanced' },
|
|
135
|
-
normalize: true
|
|
136
|
-
)
|
|
137
|
-
)
|
|
138
|
-
)
|
|
139
|
-
|
|
140
|
-
text = 'Embeddings capture semantic meaning in vector space representations.'
|
|
141
|
-
result = Kreuzberg.extract_bytes_sync(data: text, mime_type: 'text/plain', config: config)
|
|
142
|
-
|
|
143
|
-
if result.chunks && !result.chunks.empty? && result.chunks.first.embedding
|
|
144
|
-
embedding = result.chunks.first.embedding
|
|
145
|
-
dimension = embedding.length
|
|
146
|
-
# Verify dimension is positive
|
|
147
|
-
expect(dimension).to be > 0
|
|
148
|
-
# Verify dimension is in expected range for balanced model
|
|
149
|
-
expect(dimension).to be_within(1024).of(512)
|
|
150
|
-
end
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
it 'handles empty chunk gracefully' do
|
|
154
|
-
config = Kreuzberg::Config::Extraction.new(
|
|
155
|
-
chunking: Kreuzberg::Config::Chunking.new(
|
|
156
|
-
enabled: true,
|
|
157
|
-
embedding: Kreuzberg::Config::Embedding.new(
|
|
158
|
-
model: { type: :preset, name: 'balanced' }
|
|
159
|
-
)
|
|
160
|
-
)
|
|
161
|
-
)
|
|
162
|
-
|
|
163
|
-
text = 'a'
|
|
164
|
-
result = Kreuzberg.extract_bytes_sync(data: text, mime_type: 'text/plain', config: config)
|
|
165
|
-
|
|
166
|
-
expect(result).not_to be_nil
|
|
167
|
-
end
|
|
168
|
-
end
|
|
169
|
-
|
|
170
|
-
describe 'performance with batch operations' do
|
|
171
|
-
it 'processes multiple chunks efficiently' do
|
|
172
|
-
config = Kreuzberg::Config::Extraction.new(
|
|
173
|
-
chunking: Kreuzberg::Config::Chunking.new(
|
|
174
|
-
enabled: true,
|
|
175
|
-
max_chars: 250,
|
|
176
|
-
embedding: Kreuzberg::Config::Embedding.new(
|
|
177
|
-
model: { type: :preset, name: 'balanced' },
|
|
178
|
-
batch_size: 16
|
|
179
|
-
)
|
|
180
|
-
)
|
|
181
|
-
)
|
|
182
|
-
|
|
183
|
-
text = 'Machine learning transforms industries. Neural networks enable deep learning. ' \
|
|
184
|
-
'Artificial intelligence drives automation. Data science enables insights. ' \
|
|
185
|
-
'Computer vision processes images. Natural language processing understands text. ' \
|
|
186
|
-
'Reinforcement learning optimizes decisions. Transfer learning improves efficiency.'
|
|
187
|
-
|
|
188
|
-
start_time = Time.now
|
|
189
|
-
result = Kreuzberg.extract_bytes_sync(data: text, mime_type: 'text/plain', config: config)
|
|
190
|
-
elapsed = Time.now - start_time
|
|
191
|
-
|
|
192
|
-
expect(result).not_to be_nil
|
|
193
|
-
expect(elapsed).to be < 30.0
|
|
194
|
-
expect(result.chunks.length).to be > 0
|
|
195
|
-
end
|
|
196
|
-
|
|
197
|
-
it 'maintains consistent embedding quality across batch sizes' do
|
|
198
|
-
text = 'Deep learning networks process data efficiently through parallel computation architecture.'
|
|
199
|
-
|
|
200
|
-
results = []
|
|
201
|
-
[8, 16, 32].each do |batch_size|
|
|
202
|
-
config = Kreuzberg::Config::Extraction.new(
|
|
203
|
-
chunking: Kreuzberg::Config::Chunking.new(
|
|
204
|
-
enabled: true,
|
|
205
|
-
embedding: Kreuzberg::Config::Embedding.new(
|
|
206
|
-
model: { type: :preset, name: 'balanced' },
|
|
207
|
-
batch_size: batch_size
|
|
208
|
-
)
|
|
209
|
-
)
|
|
210
|
-
)
|
|
211
|
-
|
|
212
|
-
result = Kreuzberg.extract_bytes_sync(data: text, mime_type: 'text/plain', config: config)
|
|
213
|
-
results << result if result
|
|
214
|
-
end
|
|
215
|
-
|
|
216
|
-
expect(results.length).to be > 0
|
|
217
|
-
results.each do |result|
|
|
218
|
-
expect(result).not_to be_nil
|
|
219
|
-
expect(result.chunks).to be_a(Array)
|
|
220
|
-
end
|
|
221
|
-
end
|
|
222
|
-
|
|
223
|
-
it 'handles large text with many chunks' do
|
|
224
|
-
config = Kreuzberg::Config::Extraction.new(
|
|
225
|
-
chunking: Kreuzberg::Config::Chunking.new(
|
|
226
|
-
enabled: true,
|
|
227
|
-
max_chars: 300,
|
|
228
|
-
embedding: Kreuzberg::Config::Embedding.new(
|
|
229
|
-
model: { type: :preset, name: 'balanced' },
|
|
230
|
-
batch_size: 32
|
|
231
|
-
)
|
|
232
|
-
)
|
|
233
|
-
)
|
|
234
|
-
|
|
235
|
-
text = ('Machine learning and artificial intelligence are transforming technology. ' * 10)
|
|
236
|
-
result = Kreuzberg.extract_bytes_sync(data: text, mime_type: 'text/plain', config: config)
|
|
237
|
-
|
|
238
|
-
expect(result).not_to be_nil
|
|
239
|
-
expect(result.chunks.length).to be >= 1
|
|
240
|
-
expect(result.chunk_count).to eq(result.chunks.length)
|
|
241
|
-
end
|
|
242
|
-
end
|
|
243
|
-
|
|
244
|
-
describe 'format-specific embedding handling' do
|
|
245
|
-
it 'generates embeddings from plain text' do
|
|
246
|
-
config = Kreuzberg::Config::Extraction.new(
|
|
247
|
-
chunking: Kreuzberg::Config::Chunking.new(
|
|
248
|
-
enabled: true,
|
|
249
|
-
embedding: Kreuzberg::Config::Embedding.new(
|
|
250
|
-
model: { type: :preset, name: 'balanced' }
|
|
251
|
-
)
|
|
252
|
-
)
|
|
253
|
-
)
|
|
254
|
-
|
|
255
|
-
text = 'Machine learning enables advanced data analysis and predictions.'
|
|
256
|
-
result = Kreuzberg.extract_bytes_sync(data: text, mime_type: 'text/plain', config: config)
|
|
257
|
-
|
|
258
|
-
expect(result).not_to be_nil
|
|
259
|
-
expect(result.mime_type).to include('text')
|
|
260
|
-
expect(result.chunks).not_to be_nil
|
|
261
|
-
end
|
|
262
|
-
|
|
263
|
-
it 'handles extraction without embeddings when disabled' do
|
|
264
|
-
config = Kreuzberg::Config::Extraction.new(
|
|
265
|
-
chunking: Kreuzberg::Config::Chunking.new(
|
|
266
|
-
enabled: true,
|
|
267
|
-
embedding: nil
|
|
268
|
-
)
|
|
269
|
-
)
|
|
270
|
-
|
|
271
|
-
text = 'Data science transforms business decisions with insights.'
|
|
272
|
-
result = Kreuzberg.extract_bytes_sync(data: text, mime_type: 'text/plain', config: config)
|
|
273
|
-
|
|
274
|
-
expect(result).not_to be_nil
|
|
275
|
-
expect(result.chunks).not_to be_nil
|
|
276
|
-
end
|
|
277
|
-
|
|
278
|
-
it 'respects extraction config for embeddings' do
|
|
279
|
-
config = Kreuzberg::Config::Extraction.new(
|
|
280
|
-
chunking: Kreuzberg::Config::Chunking.new(
|
|
281
|
-
enabled: true,
|
|
282
|
-
max_chars: 400,
|
|
283
|
-
embedding: Kreuzberg::Config::Embedding.new(
|
|
284
|
-
model: { type: :preset, name: 'balanced' },
|
|
285
|
-
normalize: true,
|
|
286
|
-
batch_size: 16
|
|
287
|
-
)
|
|
288
|
-
)
|
|
289
|
-
)
|
|
290
|
-
|
|
291
|
-
text = 'Artificial intelligence enables automation across industries.'
|
|
292
|
-
result = Kreuzberg.extract_bytes_sync(data: text, mime_type: 'text/plain', config: config)
|
|
293
|
-
|
|
294
|
-
expect(result).not_to be_nil
|
|
295
|
-
expect(result.chunks).to be_a(Array)
|
|
296
|
-
end
|
|
297
|
-
end
|
|
298
|
-
|
|
299
|
-
describe 'similarity score validation' do
|
|
300
|
-
it 'generates vectors suitable for cosine similarity' do
|
|
301
|
-
config = Kreuzberg::Config::Extraction.new(
|
|
302
|
-
chunking: Kreuzberg::Config::Chunking.new(
|
|
303
|
-
enabled: true,
|
|
304
|
-
embedding: Kreuzberg::Config::Embedding.new(
|
|
305
|
-
model: { type: :preset, name: 'balanced' },
|
|
306
|
-
normalize: true
|
|
307
|
-
)
|
|
308
|
-
)
|
|
309
|
-
)
|
|
310
|
-
|
|
311
|
-
text = 'Machine learning enables pattern recognition. Artificial intelligence drives innovation.'
|
|
312
|
-
result = Kreuzberg.extract_bytes_sync(data: text, mime_type: 'text/plain', config: config)
|
|
313
|
-
|
|
314
|
-
if result.chunks && result.chunks.length >= 2
|
|
315
|
-
embeddings = result.chunks.select { |c| c.embedding.is_a?(Array) }.map(&:embedding)
|
|
316
|
-
|
|
317
|
-
if embeddings.length >= 2
|
|
318
|
-
vec1 = embeddings[0]
|
|
319
|
-
vec2 = embeddings[1]
|
|
320
|
-
|
|
321
|
-
dot_product = vec1.zip(vec2).sum { |a, b| a * b }
|
|
322
|
-
norm1 = Math.sqrt(vec1.sum { |x| x * x })
|
|
323
|
-
norm2 = Math.sqrt(vec2.sum { |x| x * x })
|
|
324
|
-
similarity = dot_product / (norm1 * norm2) if norm1 > 0 && norm2 > 0
|
|
325
|
-
|
|
326
|
-
if similarity
|
|
327
|
-
expect(similarity).to be >= -1.0
|
|
328
|
-
expect(similarity).to be <= 1.0
|
|
329
|
-
end
|
|
330
|
-
end
|
|
331
|
-
end
|
|
332
|
-
end
|
|
333
|
-
|
|
334
|
-
it 'normalized embeddings have unit or near-unit magnitude' do
|
|
335
|
-
config = Kreuzberg::Config::Extraction.new(
|
|
336
|
-
chunking: Kreuzberg::Config::Chunking.new(
|
|
337
|
-
enabled: true,
|
|
338
|
-
embedding: Kreuzberg::Config::Embedding.new(
|
|
339
|
-
model: { type: :preset, name: 'balanced' },
|
|
340
|
-
normalize: true
|
|
341
|
-
)
|
|
342
|
-
)
|
|
343
|
-
)
|
|
344
|
-
|
|
345
|
-
text = 'Embeddings capture semantic information in vector space.'
|
|
346
|
-
result = Kreuzberg.extract_bytes_sync(data: text, mime_type: 'text/plain', config: config)
|
|
347
|
-
|
|
348
|
-
if result.chunks && !result.chunks.empty? && result.chunks.first.embedding
|
|
349
|
-
embedding = result.chunks.first.embedding
|
|
350
|
-
magnitude = Math.sqrt(embedding.sum { |x| x * x })
|
|
351
|
-
|
|
352
|
-
expect(magnitude).to be > 0.0
|
|
353
|
-
end
|
|
354
|
-
end
|
|
355
|
-
|
|
356
|
-
it 'computes reasonable similarity between related texts' do
|
|
357
|
-
config = Kreuzberg::Config::Extraction.new(
|
|
358
|
-
chunking: Kreuzberg::Config::Chunking.new(
|
|
359
|
-
enabled: true,
|
|
360
|
-
embedding: Kreuzberg::Config::Embedding.new(
|
|
361
|
-
model: { type: :preset, name: 'balanced' },
|
|
362
|
-
normalize: true
|
|
363
|
-
)
|
|
364
|
-
)
|
|
365
|
-
)
|
|
366
|
-
|
|
367
|
-
text1 = 'Machine learning enables data analysis'
|
|
368
|
-
text2 = 'Artificial intelligence enables learning'
|
|
369
|
-
|
|
370
|
-
result1 = Kreuzberg.extract_bytes_sync(data: text1, mime_type: 'text/plain', config: config)
|
|
371
|
-
result2 = Kreuzberg.extract_bytes_sync(data: text2, mime_type: 'text/plain', config: config)
|
|
372
|
-
|
|
373
|
-
if result1.chunks && result2.chunks && !result1.chunks.empty? && !result2.chunks.empty?
|
|
374
|
-
emb1 = result1.chunks.first.embedding
|
|
375
|
-
emb2 = result2.chunks.first.embedding
|
|
376
|
-
|
|
377
|
-
if emb1.is_a?(Array) && emb2.is_a?(Array)
|
|
378
|
-
dot_product = emb1.zip(emb2).sum { |a, b| a * b }
|
|
379
|
-
norm1 = Math.sqrt(emb1.sum { |x| x * x })
|
|
380
|
-
norm2 = Math.sqrt(emb2.sum { |x| x * x })
|
|
381
|
-
similarity = dot_product / (norm1 * norm2) if norm1 > 0 && norm2 > 0
|
|
382
|
-
|
|
383
|
-
expect(similarity).not_to be_nil if similarity
|
|
384
|
-
# Cosine similarity must be in valid range [-1, 1]
|
|
385
|
-
expect(similarity).to be >= -1.0 if similarity
|
|
386
|
-
expect(similarity).to be <= 1.0 if similarity
|
|
387
|
-
# Related texts should have positive similarity
|
|
388
|
-
expect(similarity).to be > 0 if similarity
|
|
389
|
-
end
|
|
390
|
-
end
|
|
391
|
-
end
|
|
392
|
-
end
|
|
393
|
-
|
|
394
|
-
describe 'normalization correctness' do
|
|
395
|
-
it 'respects normalization configuration' do
|
|
396
|
-
config_normalized = Kreuzberg::Config::Extraction.new(
|
|
397
|
-
chunking: Kreuzberg::Config::Chunking.new(
|
|
398
|
-
enabled: true,
|
|
399
|
-
embedding: Kreuzberg::Config::Embedding.new(
|
|
400
|
-
model: { type: :preset, name: 'balanced' },
|
|
401
|
-
normalize: true
|
|
402
|
-
)
|
|
403
|
-
)
|
|
404
|
-
)
|
|
405
|
-
|
|
406
|
-
text = 'Normalization ensures consistent vector magnitudes.'
|
|
407
|
-
result = Kreuzberg.extract_bytes_sync(data: text, mime_type: 'text/plain', config: config_normalized)
|
|
408
|
-
|
|
409
|
-
expect(result).not_to be_nil
|
|
410
|
-
expect(result.chunks).not_to be_nil
|
|
411
|
-
end
|
|
412
|
-
|
|
413
|
-
it 'handles embedding with custom normalization settings' do
|
|
414
|
-
normalize_options = [true, false]
|
|
415
|
-
|
|
416
|
-
normalize_options.each do |should_normalize|
|
|
417
|
-
config = Kreuzberg::Config::Extraction.new(
|
|
418
|
-
chunking: Kreuzberg::Config::Chunking.new(
|
|
419
|
-
enabled: true,
|
|
420
|
-
embedding: Kreuzberg::Config::Embedding.new(
|
|
421
|
-
model: { type: :preset, name: 'balanced' },
|
|
422
|
-
normalize: should_normalize
|
|
423
|
-
)
|
|
424
|
-
)
|
|
425
|
-
)
|
|
426
|
-
|
|
427
|
-
text = 'Embeddings can be normalized or unnormalized depending on use case.'
|
|
428
|
-
result = Kreuzberg.extract_bytes_sync(data: text, mime_type: 'text/plain', config: config)
|
|
429
|
-
|
|
430
|
-
expect(result).not_to be_nil
|
|
431
|
-
expect(result.chunks).to be_a(Array)
|
|
432
|
-
end
|
|
433
|
-
end
|
|
434
|
-
|
|
435
|
-
it 'validates embedding values within expected range' do
|
|
436
|
-
config = Kreuzberg::Config::Extraction.new(
|
|
437
|
-
chunking: Kreuzberg::Config::Chunking.new(
|
|
438
|
-
enabled: true,
|
|
439
|
-
embedding: Kreuzberg::Config::Embedding.new(
|
|
440
|
-
model: { type: :preset, name: 'balanced' },
|
|
441
|
-
normalize: true
|
|
442
|
-
)
|
|
443
|
-
)
|
|
444
|
-
)
|
|
445
|
-
|
|
446
|
-
text = 'Normalized embeddings typically have values between -1 and 1.'
|
|
447
|
-
result = Kreuzberg.extract_bytes_sync(data: text, mime_type: 'text/plain', config: config)
|
|
448
|
-
|
|
449
|
-
if result.chunks && !result.chunks.empty? && result.chunks.first.embedding
|
|
450
|
-
embedding = result.chunks.first.embedding
|
|
451
|
-
expect(embedding).to all(be >= -2.0)
|
|
452
|
-
expect(embedding).to all(be <= 2.0)
|
|
453
|
-
end
|
|
454
|
-
end
|
|
455
|
-
|
|
456
|
-
it 'ensures numerical stability in embeddings' do
|
|
457
|
-
config = Kreuzberg::Config::Extraction.new(
|
|
458
|
-
chunking: Kreuzberg::Config::Chunking.new(
|
|
459
|
-
enabled: true,
|
|
460
|
-
embedding: Kreuzberg::Config::Embedding.new(
|
|
461
|
-
model: { type: :preset, name: 'balanced' },
|
|
462
|
-
normalize: true
|
|
463
|
-
)
|
|
464
|
-
)
|
|
465
|
-
)
|
|
466
|
-
|
|
467
|
-
text = 'Numerical stability prevents overflow and underflow in floating point computation.'
|
|
468
|
-
result = Kreuzberg.extract_bytes_sync(data: text, mime_type: 'text/plain', config: config)
|
|
469
|
-
|
|
470
|
-
if result.chunks && !result.chunks.empty? && result.chunks.first.embedding
|
|
471
|
-
embedding = result.chunks.first.embedding
|
|
472
|
-
expect(embedding).to all(be_finite)
|
|
473
|
-
end
|
|
474
|
-
end
|
|
475
|
-
end
|
|
476
|
-
|
|
477
|
-
describe 'embedding configuration validation' do
|
|
478
|
-
it 'creates Embedding config with default values' do
|
|
479
|
-
embedding = Kreuzberg::Config::Embedding.new
|
|
480
|
-
|
|
481
|
-
expect(embedding.model).to be_a(Hash)
|
|
482
|
-
expect(embedding.normalize).to be true
|
|
483
|
-
expect(embedding.batch_size).to eq(32)
|
|
484
|
-
expect(embedding.show_download_progress).to be false
|
|
485
|
-
expect(embedding.cache_dir).to be_nil
|
|
486
|
-
end
|
|
487
|
-
|
|
488
|
-
it 'creates Embedding config with custom values' do
|
|
489
|
-
embedding = Kreuzberg::Config::Embedding.new(
|
|
490
|
-
model: { type: :preset, name: 'large' },
|
|
491
|
-
normalize: false,
|
|
492
|
-
batch_size: 64,
|
|
493
|
-
show_download_progress: true,
|
|
494
|
-
cache_dir: '/tmp/embeddings'
|
|
495
|
-
)
|
|
496
|
-
|
|
497
|
-
expect(embedding.model[:type]).to eq(:preset)
|
|
498
|
-
expect(embedding.model[:name]).to eq('large')
|
|
499
|
-
expect(embedding.normalize).to be false
|
|
500
|
-
expect(embedding.batch_size).to eq(64)
|
|
501
|
-
expect(embedding.show_download_progress).to be true
|
|
502
|
-
expect(embedding.cache_dir).to eq('/tmp/embeddings')
|
|
503
|
-
end
|
|
504
|
-
|
|
505
|
-
it 'converts Embedding config to hash' do
|
|
506
|
-
embedding = Kreuzberg::Config::Embedding.new(
|
|
507
|
-
model: { type: :preset, name: 'balanced' },
|
|
508
|
-
normalize: true,
|
|
509
|
-
batch_size: 16
|
|
510
|
-
)
|
|
511
|
-
|
|
512
|
-
hash = embedding.to_h
|
|
513
|
-
|
|
514
|
-
expect(hash).to be_a(Hash)
|
|
515
|
-
expect(hash[:model]).to be_a(Hash)
|
|
516
|
-
expect(hash[:normalize]).to be true
|
|
517
|
-
expect(hash[:batch_size]).to eq(16)
|
|
518
|
-
end
|
|
519
|
-
|
|
520
|
-
it 'compacts nil values in embedding hash' do
|
|
521
|
-
embedding = Kreuzberg::Config::Embedding.new(
|
|
522
|
-
model: { type: :preset, name: 'balanced' },
|
|
523
|
-
batch_size: 32
|
|
524
|
-
)
|
|
525
|
-
|
|
526
|
-
hash = embedding.to_h
|
|
527
|
-
|
|
528
|
-
expect(hash).not_to have_key(:cache_dir)
|
|
529
|
-
expect(hash).not_to have_key(:show_download_progress) unless hash[:show_download_progress] == false
|
|
530
|
-
end
|
|
531
|
-
|
|
532
|
-
it 'accepts hash model specification' do
|
|
533
|
-
embedding = Kreuzberg::Config::Embedding.new(
|
|
534
|
-
model: { type: :preset, name: 'balanced', dimension: 384 }
|
|
535
|
-
)
|
|
536
|
-
|
|
537
|
-
expect(embedding.model).to be_a(Hash)
|
|
538
|
-
expect(embedding.model[:type]).to eq(:preset)
|
|
539
|
-
expect(embedding.model[:name]).to eq('balanced')
|
|
540
|
-
end
|
|
541
|
-
|
|
542
|
-
it 'converts numeric batch_size to integer' do
|
|
543
|
-
embedding = Kreuzberg::Config::Embedding.new(batch_size: '64')
|
|
544
|
-
|
|
545
|
-
expect(embedding.batch_size).to eq(64)
|
|
546
|
-
expect(embedding.batch_size).to be_a(Integer)
|
|
547
|
-
end
|
|
548
|
-
end
|
|
549
|
-
|
|
550
|
-
describe 'edge cases and error handling' do
|
|
551
|
-
it 'handles very short text with embeddings' do
|
|
552
|
-
config = Kreuzberg::Config::Extraction.new(
|
|
553
|
-
chunking: Kreuzberg::Config::Chunking.new(
|
|
554
|
-
enabled: true,
|
|
555
|
-
embedding: Kreuzberg::Config::Embedding.new(
|
|
556
|
-
model: { type: :preset, name: 'balanced' }
|
|
557
|
-
)
|
|
558
|
-
)
|
|
559
|
-
)
|
|
560
|
-
|
|
561
|
-
text = 'AI'
|
|
562
|
-
result = Kreuzberg.extract_bytes_sync(data: text, mime_type: 'text/plain', config: config)
|
|
563
|
-
|
|
564
|
-
expect(result).not_to be_nil
|
|
565
|
-
expect(result.chunks).not_to be_nil
|
|
566
|
-
end
|
|
567
|
-
|
|
568
|
-
it 'handles text with special characters in embeddings' do
|
|
569
|
-
config = Kreuzberg::Config::Extraction.new(
|
|
570
|
-
chunking: Kreuzberg::Config::Chunking.new(
|
|
571
|
-
enabled: true,
|
|
572
|
-
embedding: Kreuzberg::Config::Embedding.new(
|
|
573
|
-
model: { type: :preset, name: 'balanced' }
|
|
574
|
-
)
|
|
575
|
-
)
|
|
576
|
-
)
|
|
577
|
-
|
|
578
|
-
text = 'Machine learning & AI. Data science -> insights. Deep learning @ scale.'
|
|
579
|
-
result = Kreuzberg.extract_bytes_sync(data: text, mime_type: 'text/plain', config: config)
|
|
580
|
-
|
|
581
|
-
expect(result).not_to be_nil
|
|
582
|
-
expect(result.chunks).not_to be_nil
|
|
583
|
-
end
|
|
584
|
-
|
|
585
|
-
it 'handles unicode text in embeddings' do
|
|
586
|
-
config = Kreuzberg::Config::Extraction.new(
|
|
587
|
-
chunking: Kreuzberg::Config::Chunking.new(
|
|
588
|
-
enabled: true,
|
|
589
|
-
embedding: Kreuzberg::Config::Embedding.new(
|
|
590
|
-
model: { type: :preset, name: 'balanced' }
|
|
591
|
-
)
|
|
592
|
-
)
|
|
593
|
-
)
|
|
594
|
-
|
|
595
|
-
text = 'Machine learning transforms technology. Aprendizaje automático transforma.'
|
|
596
|
-
result = Kreuzberg.extract_bytes_sync(data: text, mime_type: 'text/plain', config: config)
|
|
597
|
-
|
|
598
|
-
expect(result).not_to be_nil
|
|
599
|
-
end
|
|
600
|
-
|
|
601
|
-
it 'handles repeated text in embeddings' do
|
|
602
|
-
config = Kreuzberg::Config::Extraction.new(
|
|
603
|
-
chunking: Kreuzberg::Config::Chunking.new(
|
|
604
|
-
enabled: true,
|
|
605
|
-
embedding: Kreuzberg::Config::Embedding.new(
|
|
606
|
-
model: { type: :preset, name: 'balanced' }
|
|
607
|
-
)
|
|
608
|
-
)
|
|
609
|
-
)
|
|
610
|
-
|
|
611
|
-
text = 'machine machine machine learning learning learning'
|
|
612
|
-
result = Kreuzberg.extract_bytes_sync(data: text, mime_type: 'text/plain', config: config)
|
|
613
|
-
|
|
614
|
-
expect(result).not_to be_nil
|
|
615
|
-
end
|
|
616
|
-
|
|
617
|
-
it 'handles empty embedding result gracefully' do
|
|
618
|
-
config = Kreuzberg::Config::Extraction.new(
|
|
619
|
-
chunking: Kreuzberg::Config::Chunking.new(
|
|
620
|
-
enabled: false
|
|
621
|
-
)
|
|
622
|
-
)
|
|
623
|
-
|
|
624
|
-
text = 'This text will not be chunked.'
|
|
625
|
-
result = Kreuzberg.extract_bytes_sync(data: text, mime_type: 'text/plain', config: config)
|
|
626
|
-
|
|
627
|
-
expect(result).not_to be_nil
|
|
628
|
-
expect(result.chunks).to be_a(Array)
|
|
629
|
-
end
|
|
630
|
-
end
|
|
631
|
-
|
|
632
|
-
describe 'Chunking with Embedding integration' do
|
|
633
|
-
it 'integrates embedding with chunking configuration' do
|
|
634
|
-
chunking = Kreuzberg::Config::Chunking.new(
|
|
635
|
-
max_chars: 500,
|
|
636
|
-
max_overlap: 100,
|
|
637
|
-
embedding: Kreuzberg::Config::Embedding.new(
|
|
638
|
-
model: { type: :preset, name: 'balanced' },
|
|
639
|
-
normalize: true
|
|
640
|
-
)
|
|
641
|
-
)
|
|
642
|
-
|
|
643
|
-
expect(chunking.embedding).to be_a(Kreuzberg::Config::Embedding)
|
|
644
|
-
expect(chunking.embedding.normalize).to be true
|
|
645
|
-
end
|
|
646
|
-
|
|
647
|
-
it 'accepts embedding config in Chunking' do
|
|
648
|
-
embedding = Kreuzberg::Config::Embedding.new(batch_size: 16)
|
|
649
|
-
chunking = Kreuzberg::Config::Chunking.new(embedding: embedding)
|
|
650
|
-
|
|
651
|
-
expect(chunking.embedding).to be_a(Kreuzberg::Config::Embedding)
|
|
652
|
-
expect(chunking.embedding.batch_size).to eq(16)
|
|
653
|
-
end
|
|
654
|
-
|
|
655
|
-
it 'accepts embedding config as hash in Chunking' do
|
|
656
|
-
chunking = Kreuzberg::Config::Chunking.new(
|
|
657
|
-
embedding: { batch_size: 32, normalize: false }
|
|
658
|
-
)
|
|
659
|
-
|
|
660
|
-
expect(chunking.embedding).to be_a(Kreuzberg::Config::Embedding)
|
|
661
|
-
expect(chunking.embedding.batch_size).to eq(32)
|
|
662
|
-
expect(chunking.embedding.normalize).to be false
|
|
663
|
-
end
|
|
664
|
-
|
|
665
|
-
it 'converts chunking with embedding to hash' do
|
|
666
|
-
chunking = Kreuzberg::Config::Chunking.new(
|
|
667
|
-
max_chars: 600,
|
|
668
|
-
embedding: Kreuzberg::Config::Embedding.new(batch_size: 24)
|
|
669
|
-
)
|
|
670
|
-
|
|
671
|
-
hash = chunking.to_h
|
|
672
|
-
|
|
673
|
-
expect(hash).to be_a(Hash)
|
|
674
|
-
expect(hash[:embedding]).to be_a(Hash)
|
|
675
|
-
expect(hash[:embedding][:batch_size]).to eq(24)
|
|
676
|
-
end
|
|
677
|
-
|
|
678
|
-
it 'handles nil embedding in chunking' do
|
|
679
|
-
chunking = Kreuzberg::Config::Chunking.new(
|
|
680
|
-
max_chars: 500,
|
|
681
|
-
embedding: nil
|
|
682
|
-
)
|
|
683
|
-
|
|
684
|
-
expect(chunking.embedding).to be_nil
|
|
685
|
-
hash = chunking.to_h
|
|
686
|
-
expect(hash[:embedding]).to be_nil
|
|
687
|
-
end
|
|
688
|
-
end
|
|
689
|
-
|
|
690
|
-
describe 'mathematical properties and error handling' do
|
|
691
|
-
it 'validates embedding vector values are valid floats' do
|
|
692
|
-
config = Kreuzberg::Config::Extraction.new(
|
|
693
|
-
chunking: Kreuzberg::Config::Chunking.new(
|
|
694
|
-
enabled: true,
|
|
695
|
-
embedding: Kreuzberg::Config::Embedding.new(
|
|
696
|
-
model: { type: :preset, name: 'balanced' },
|
|
697
|
-
normalize: true
|
|
698
|
-
)
|
|
699
|
-
)
|
|
700
|
-
)
|
|
701
|
-
|
|
702
|
-
text = 'Validating floating-point properties of embedding values.'
|
|
703
|
-
result = Kreuzberg.extract_bytes_sync(data: text, mime_type: 'text/plain', config: config)
|
|
704
|
-
|
|
705
|
-
if result.chunks && !result.chunks.empty? && result.chunks.first.embedding
|
|
706
|
-
embedding = result.chunks.first.embedding
|
|
707
|
-
expect(embedding).to all(be_a(Float))
|
|
708
|
-
expect(embedding).to all(be_finite)
|
|
709
|
-
end
|
|
710
|
-
end
|
|
711
|
-
|
|
712
|
-
it 'ensures no dead embeddings (all-zero vectors)' do
|
|
713
|
-
config = Kreuzberg::Config::Extraction.new(
|
|
714
|
-
chunking: Kreuzberg::Config::Chunking.new(
|
|
715
|
-
enabled: true,
|
|
716
|
-
embedding: Kreuzberg::Config::Embedding.new(
|
|
717
|
-
model: { type: :preset, name: 'balanced' },
|
|
718
|
-
normalize: true
|
|
719
|
-
)
|
|
720
|
-
)
|
|
721
|
-
)
|
|
722
|
-
|
|
723
|
-
text = 'Testing for dead embeddings and zero vectors.'
|
|
724
|
-
result = Kreuzberg.extract_bytes_sync(data: text, mime_type: 'text/plain', config: config)
|
|
725
|
-
|
|
726
|
-
if result.chunks && !result.chunks.empty? && result.chunks.first.embedding
|
|
727
|
-
embedding = result.chunks.first.embedding
|
|
728
|
-
magnitude = embedding.sum(&:abs)
|
|
729
|
-
expect(magnitude).to be > 0.1
|
|
730
|
-
end
|
|
731
|
-
end
|
|
732
|
-
|
|
733
|
-
it 'validates identical vectors have similarity 1.0' do
|
|
734
|
-
config = Kreuzberg::Config::Extraction.new(
|
|
735
|
-
chunking: Kreuzberg::Config::Chunking.new(
|
|
736
|
-
enabled: true,
|
|
737
|
-
embedding: Kreuzberg::Config::Embedding.new(
|
|
738
|
-
model: { type: :preset, name: 'balanced' },
|
|
739
|
-
normalize: true
|
|
740
|
-
)
|
|
741
|
-
)
|
|
742
|
-
)
|
|
743
|
-
|
|
744
|
-
text = 'Testing identical vector similarity.'
|
|
745
|
-
result = Kreuzberg.extract_bytes_sync(data: text, mime_type: 'text/plain', config: config)
|
|
746
|
-
|
|
747
|
-
if result.chunks && !result.chunks.empty? && result.chunks.first.embedding
|
|
748
|
-
embedding = result.chunks.first.embedding
|
|
749
|
-
# Vector with itself should have similarity 1.0
|
|
750
|
-
dot_product = embedding.zip(embedding).sum { |a, b| a * b }
|
|
751
|
-
norm_sq = embedding.sum { |x| x * x }
|
|
752
|
-
similarity = dot_product / norm_sq if norm_sq > 0
|
|
753
|
-
|
|
754
|
-
expect(similarity).to be_close_to(1.0, 0.0001) if similarity
|
|
755
|
-
end
|
|
756
|
-
end
|
|
757
|
-
|
|
758
|
-
it 'validates embedding consistency across multiple runs' do
|
|
759
|
-
config = Kreuzberg::Config::Extraction.new(
|
|
760
|
-
chunking: Kreuzberg::Config::Chunking.new(
|
|
761
|
-
enabled: true,
|
|
762
|
-
embedding: Kreuzberg::Config::Embedding.new(
|
|
763
|
-
model: { type: :preset, name: 'balanced' },
|
|
764
|
-
normalize: true
|
|
765
|
-
)
|
|
766
|
-
)
|
|
767
|
-
)
|
|
768
|
-
|
|
769
|
-
text = 'Testing deterministic embedding generation.'
|
|
770
|
-
|
|
771
|
-
result1 = Kreuzberg.extract_bytes_sync(data: text, mime_type: 'text/plain', config: config)
|
|
772
|
-
result2 = Kreuzberg.extract_bytes_sync(data: text, mime_type: 'text/plain', config: config)
|
|
773
|
-
|
|
774
|
-
if result1.chunks && result2.chunks && !result1.chunks.empty? && !result2.chunks.empty?
|
|
775
|
-
emb1 = result1.chunks.first.embedding
|
|
776
|
-
emb2 = result2.chunks.first.embedding
|
|
777
|
-
|
|
778
|
-
expect(emb1).to eq(emb2) if emb1.is_a?(Array) && emb2.is_a?(Array)
|
|
779
|
-
end
|
|
780
|
-
end
|
|
781
|
-
|
|
782
|
-
it 'handles dimension consistency across batch operations' do
|
|
783
|
-
config = Kreuzberg::Config::Extraction.new(
|
|
784
|
-
chunking: Kreuzberg::Config::Chunking.new(
|
|
785
|
-
enabled: true,
|
|
786
|
-
max_chars: 150,
|
|
787
|
-
embedding: Kreuzberg::Config::Embedding.new(
|
|
788
|
-
model: { type: :preset, name: 'balanced' },
|
|
789
|
-
batch_size: 4
|
|
790
|
-
)
|
|
791
|
-
)
|
|
792
|
-
)
|
|
793
|
-
|
|
794
|
-
texts = [
|
|
795
|
-
'First document about machine learning.',
|
|
796
|
-
'Second document about neural networks.',
|
|
797
|
-
'Third document about deep learning.'
|
|
798
|
-
]
|
|
799
|
-
|
|
800
|
-
dimensions = []
|
|
801
|
-
|
|
802
|
-
texts.each do |text|
|
|
803
|
-
result = Kreuzberg.extract_bytes_sync(data: text, mime_type: 'text/plain', config: config)
|
|
804
|
-
|
|
805
|
-
next unless result.chunks
|
|
806
|
-
|
|
807
|
-
result.chunks.each do |chunk|
|
|
808
|
-
dimensions << chunk.embedding.length if chunk.embedding.is_a?(Array)
|
|
809
|
-
end
|
|
810
|
-
end
|
|
811
|
-
|
|
812
|
-
# All dimensions should be consistent
|
|
813
|
-
expect(dimensions.uniq.length).to be <= 1 if dimensions.any?
|
|
814
|
-
end
|
|
815
|
-
end
|
|
816
|
-
end
|