qdrant-loader 1.0.2__tar.gz → 1.0.3__tar.gz
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.
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/PKG-INFO +9 -3
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/pyproject.toml +12 -3
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/__init__.py +8 -1
- qdrant_loader-1.0.3/src/qdrant_loader/cli/__main__.py +6 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/cli/cli.py +33 -4
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/cli/commands/__init__.py +15 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/cli/commands/config.py +3 -1
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/cli/commands/config_cmd.py +3 -1
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/cli/commands/ingest_cmd.py +3 -1
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/cli/commands/init_cmd.py +1 -1
- qdrant_loader-1.0.3/src/qdrant_loader/cli/commands/jobs_cmd.py +256 -0
- qdrant_loader-1.0.3/src/qdrant_loader/cli/commands/serve_cmd.py +242 -0
- qdrant_loader-1.0.3/src/qdrant_loader/cli/commands/webhook_cmd.py +76 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/cli/logging_utils.py +1 -1
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/config/__init__.py +35 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/config/global_config.py +6 -0
- qdrant_loader-1.0.3/src/qdrant_loader/config/workers.py +202 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/config/workspace.py +1 -1
- qdrant_loader-1.0.3/src/qdrant_loader/connectors/base.py +107 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/connectors/jira/cloud_connector.py +1 -1
- qdrant_loader-1.0.3/src/qdrant_loader/connectors/jira/config.py +316 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/connectors/jira/connector.py +135 -68
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/connectors/jira/data_center_connector.py +1 -1
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/connectors/jira/mappers.py +40 -3
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/connectors/jira/models.py +2 -1
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/markdown/section_splitter.py +14 -8
- qdrant_loader-1.0.3/src/qdrant_loader/core/chunking/strategy/markdown/splitters/row_kv_excel.py +213 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/embedding/embedding_service.py +15 -1
- qdrant_loader-1.0.3/src/qdrant_loader/core/file_conversion/clean_xlsx_converter.py +164 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/file_conversion/file_converter.py +15 -6
- qdrant_loader-1.0.3/src/qdrant_loader/core/file_conversion/sub_table_detector.py +110 -0
- qdrant_loader-1.0.3/src/qdrant_loader/core/file_conversion/xlsx_markdown_format.py +23 -0
- qdrant_loader-1.0.3/src/qdrant_loader/core/pipeline/document_pipeline.py +179 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/pipeline/factory.py +1 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/pipeline/orchestrator.py +275 -39
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/pipeline/source_processor.py +73 -3
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/pipeline/workers/embedding_worker.py +16 -5
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/pipeline/workers/upsert_worker.py +6 -1
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/project_manager.py +19 -4
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/qdrant_manager.py +158 -16
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/state/document_state_manager.py +1 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/state/models.py +21 -4
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/state/state_change_detector.py +80 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/state/state_manager.py +127 -1
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/state/transitions.py +27 -3
- qdrant_loader-1.0.3/src/qdrant_loader/core/worker/__init__.py +30 -0
- qdrant_loader-1.0.3/src/qdrant_loader/core/worker/handlers.py +198 -0
- qdrant_loader-1.0.3/src/qdrant_loader/core/worker/job_types.py +29 -0
- qdrant_loader-1.0.3/src/qdrant_loader/core/worker/pool.py +256 -0
- qdrant_loader-1.0.3/src/qdrant_loader/core/worker/queue.py +355 -0
- qdrant_loader-1.0.3/src/qdrant_loader/core/worker/scheduler.py +181 -0
- qdrant_loader-1.0.3/src/qdrant_loader/webhooks/__init__.py +5 -0
- qdrant_loader-1.0.3/src/qdrant_loader/webhooks/auth.py +240 -0
- qdrant_loader-1.0.3/src/qdrant_loader/webhooks/event_processor.py +216 -0
- qdrant_loader-1.0.3/src/qdrant_loader/webhooks/handlers.py +182 -0
- qdrant_loader-1.0.3/src/qdrant_loader/webhooks/queue_backend.py +165 -0
- qdrant_loader-1.0.3/src/qdrant_loader/webhooks/server.py +341 -0
- qdrant_loader-1.0.3/src/qdrant_loader/webhooks/single_event_handler.py +67 -0
- qdrant_loader-1.0.3/src/qdrant_loader/webhooks/worker.py +69 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader.egg-info/PKG-INFO +9 -3
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader.egg-info/SOURCES.txt +24 -1
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader.egg-info/requires.txt +13 -2
- qdrant_loader-1.0.2/src/qdrant_loader/connectors/base.py +0 -48
- qdrant_loader-1.0.2/src/qdrant_loader/connectors/jira/config.py +0 -151
- qdrant_loader-1.0.2/src/qdrant_loader/core/pipeline/document_pipeline.py +0 -94
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/README.md +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/setup.cfg +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/cli/__init__.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/cli/async_utils.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/cli/asyncio.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/cli/commands/ingest.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/cli/commands/init.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/cli/commands/project/__init__.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/cli/commands/project/list_cmd.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/cli/commands/project/status_cmd.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/cli/commands/project/validate_cmd.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/cli/commands/setup_cmd.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/cli/config_loader.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/cli/path_utils.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/cli/project_commands.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/cli/update_check.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/cli/version.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/config/base.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/config/chunking.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/config/embedding.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/config/error_formatter.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/config/models.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/config/parser.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/config/qdrant.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/config/source_config.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/config/sources.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/config/state.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/config/types.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/config/validator.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/config.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/connectors/__init__.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/connectors/attachments.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/connectors/confluence/__init__.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/connectors/confluence/auth.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/connectors/confluence/config.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/connectors/confluence/connector.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/connectors/confluence/mappers.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/connectors/confluence/pagination.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/connectors/exceptions.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/connectors/factory.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/connectors/git/__init__.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/connectors/git/adapter.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/connectors/git/config.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/connectors/git/connector.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/connectors/git/file_processor.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/connectors/git/metadata_extractor.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/connectors/git/operations.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/connectors/http.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/connectors/jira/__init__.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/connectors/jira/auth.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/connectors/localfile/__init__.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/connectors/localfile/config.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/connectors/localfile/connector.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/connectors/localfile/file_processor.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/connectors/localfile/metadata_extractor.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/connectors/publicdocs/__init__.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/connectors/publicdocs/config.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/connectors/publicdocs/connector.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/connectors/publicdocs/crawler.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/connectors/publicdocs/http.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/connectors/publicdocs/parsers.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/connectors/registry.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/connectors/shared/__init__.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/connectors/shared/attachments/__init__.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/connectors/shared/attachments/metadata.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/connectors/shared/attachments/reader.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/connectors/shared/http/__init__.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/connectors/shared/http/client.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/connectors/shared/http/errors.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/connectors/shared/http/policy.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/connectors/shared/http/rate_limit.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/__init__.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/async_ingestion_pipeline.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/attachment_downloader.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/__init__.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/chunking_service.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/progress_tracker.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/__init__.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/base/__init__.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/base/chunk_processor.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/base/document_parser.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/base/metadata_extractor.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/base/section_splitter.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/base_strategy.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/code/__init__.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/code/code_chunk_processor.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/code/code_document_parser.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/code/code_metadata_extractor.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/code/code_section_splitter.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/code/metadata/__init__.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/code/metadata/complexity.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/code/metadata/dependencies.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/code/metadata/documentation.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/code/metadata/entities.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/code/metadata/language_specific.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/code/metadata/maintainability.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/code/metadata/patterns.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/code/metadata/performance.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/code/metadata/security.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/code/metadata/testing.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/code/parser/__init__.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/code/parser/common.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/code/parser/python_ast.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/code/parser/tree_sitter.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/code/processor/__init__.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/code/processor/analysis.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/code/processor/quality.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/code/processor/utils.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/code_strategy.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/default/__init__.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/default/text_chunk_processor.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/default/text_document_parser.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/default/text_metadata_extractor.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/default/text_section_splitter.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/default_strategy.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/html/__init__.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/html/html_chunk_processor.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/html/html_document_parser.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/html/html_metadata_extractor.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/html/html_section_splitter.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/html_strategy.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/json/__init__.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/json/json_chunk_processor.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/json/json_document_parser.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/json/json_metadata_extractor.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/json/json_section_splitter.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/json_strategy.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/markdown/__init__.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/markdown/chunk_processor.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/markdown/document_parser.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/markdown/markdown_strategy.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/markdown/metadata_extractor.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/markdown/splitters/__init__.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/markdown/splitters/base.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/markdown/splitters/excel.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/markdown/splitters/fallback.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/chunking/strategy/markdown/splitters/standard.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/document.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/embedding/__init__.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/embedding_service.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/file_conversion/__init__.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/file_conversion/conversion_config.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/file_conversion/exceptions.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/file_conversion/file_detector.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/init_collection.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/monitoring/__init__.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/monitoring/batch_summary.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/monitoring/ingestion_metrics.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/monitoring/processing_stats.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/monitoring/prometheus_metrics.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/monitoring/resource_monitor.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/pipeline/__init__.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/pipeline/config.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/pipeline/resource_manager.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/pipeline/source_filter.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/pipeline/workers/__init__.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/pipeline/workers/base_worker.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/pipeline/workers/chunking_worker.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/state/__init__.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/state/exceptions.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/state/queries.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/state/session.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/state/utils.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/text_processing/semantic_analyzer.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/text_processing/text_processor.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/core/text_processing/topic_modeler.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/main.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/utils/__init__.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/utils/logging.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/utils/sensitive.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader/utils/version_check.py +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader.egg-info/dependency_links.txt +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader.egg-info/entry_points.txt +0 -0
- {qdrant_loader-1.0.2 → qdrant_loader-1.0.3}/src/qdrant_loader.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: qdrant-loader
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.3
|
|
4
4
|
Summary: A tool for collecting and vectorizing technical content from multiple sources and storing it in a QDrant vector database.
|
|
5
5
|
Author-email: Martin Papy <martin.papy@cbtw.tech>
|
|
6
6
|
License-Expression: GPL-3.0
|
|
@@ -37,7 +37,7 @@ Requires-Dist: pydantic-settings>=2.0.0
|
|
|
37
37
|
Requires-Dist: structlog>=23.0.0
|
|
38
38
|
Requires-Dist: httpx>=0.24.0
|
|
39
39
|
Requires-Dist: openai>=1.0.0
|
|
40
|
-
Requires-Dist: qdrant-loader-core[openai]==1.0.
|
|
40
|
+
Requires-Dist: qdrant-loader-core[openai]==1.0.3
|
|
41
41
|
Requires-Dist: qdrant-client>=1.10.0
|
|
42
42
|
Requires-Dist: PyYAML>=6.0.0
|
|
43
43
|
Requires-Dist: beautifulsoup4>=4.12.0
|
|
@@ -48,7 +48,7 @@ Requires-Dist: langchain-core>=0.3.0
|
|
|
48
48
|
Requires-Dist: langchain-community>=0.0.38
|
|
49
49
|
Requires-Dist: langchain-text-splitters>=0.3.9
|
|
50
50
|
Requires-Dist: numpy<2.0.0,>=1.26.0
|
|
51
|
-
Requires-Dist: GitPython>=3.1.
|
|
51
|
+
Requires-Dist: GitPython>=3.1.50
|
|
52
52
|
Requires-Dist: atlassian-python-api>=3.41.0
|
|
53
53
|
Requires-Dist: tqdm>=4.66.0
|
|
54
54
|
Requires-Dist: SQLAlchemy>=2.0.0
|
|
@@ -65,10 +65,16 @@ Requires-Dist: psutil>=5.9.0
|
|
|
65
65
|
Requires-Dist: tree-sitter-languages>=1.10.0
|
|
66
66
|
Requires-Dist: tree-sitter<0.21
|
|
67
67
|
Requires-Dist: markitdown[all]>=0.1.3
|
|
68
|
+
Requires-Dist: networkx>=3.0.0
|
|
68
69
|
Requires-Dist: rich>=13.0.0
|
|
69
70
|
Requires-Dist: questionary>=2.0.0
|
|
70
71
|
Requires-Dist: packaging>=21.0
|
|
71
72
|
Requires-Dist: prometheus-client<1.0.0,>=0.19.0
|
|
73
|
+
Provides-Extra: server
|
|
74
|
+
Requires-Dist: fastapi>=0.104.0; extra == "server"
|
|
75
|
+
Requires-Dist: uvicorn[standard]>=0.24.0; sys_platform != "win32" and extra == "server"
|
|
76
|
+
Requires-Dist: uvicorn>=0.24.0; sys_platform == "win32" and extra == "server"
|
|
77
|
+
Requires-Dist: PyJWT[crypto]>=2.8.0; extra == "server"
|
|
72
78
|
|
|
73
79
|
# QDrant Loader
|
|
74
80
|
|
|
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
|
|
|
7
7
|
|
|
8
8
|
[project]
|
|
9
9
|
name = "qdrant-loader"
|
|
10
|
-
version = "1.0.
|
|
10
|
+
version = "1.0.3"
|
|
11
11
|
description = "A tool for collecting and vectorizing technical content from multiple sources and storing it in a QDrant vector database."
|
|
12
12
|
readme = "README.md"
|
|
13
13
|
requires-python = ">=3.12"
|
|
@@ -35,7 +35,7 @@ dependencies = [
|
|
|
35
35
|
"structlog>=23.0.0",
|
|
36
36
|
"httpx>=0.24.0",
|
|
37
37
|
"openai>=1.0.0",
|
|
38
|
-
"qdrant-loader-core[openai]==1.0.
|
|
38
|
+
"qdrant-loader-core[openai]==1.0.3",
|
|
39
39
|
"qdrant-client>=1.10.0",
|
|
40
40
|
"PyYAML>=6.0.0",
|
|
41
41
|
"beautifulsoup4>=4.12.0",
|
|
@@ -46,7 +46,7 @@ dependencies = [
|
|
|
46
46
|
"langchain-community>=0.0.38",
|
|
47
47
|
"langchain-text-splitters>=0.3.9",
|
|
48
48
|
"numpy>=1.26.0,<2.0.0",
|
|
49
|
-
"GitPython>=3.1.
|
|
49
|
+
"GitPython>=3.1.50",
|
|
50
50
|
"atlassian-python-api>=3.41.0",
|
|
51
51
|
"tqdm>=4.66.0",
|
|
52
52
|
"SQLAlchemy>=2.0.0",
|
|
@@ -63,6 +63,7 @@ dependencies = [
|
|
|
63
63
|
"tree-sitter-languages>=1.10.0",
|
|
64
64
|
"tree-sitter<0.21",
|
|
65
65
|
"markitdown[all]>=0.1.3",
|
|
66
|
+
"networkx>=3.0.0",
|
|
66
67
|
"rich>=13.0.0",
|
|
67
68
|
"questionary>=2.0.0",
|
|
68
69
|
"packaging>=21.0",
|
|
@@ -87,6 +88,14 @@ classifiers = [
|
|
|
87
88
|
"Typing :: Typed",
|
|
88
89
|
]
|
|
89
90
|
|
|
91
|
+
[project.optional-dependencies]
|
|
92
|
+
server = [
|
|
93
|
+
"fastapi>=0.104.0",
|
|
94
|
+
"uvicorn[standard]>=0.24.0 ; sys_platform != 'win32'",
|
|
95
|
+
"uvicorn>=0.24.0 ; sys_platform == 'win32'",
|
|
96
|
+
"PyJWT[crypto]>=2.8.0",
|
|
97
|
+
]
|
|
98
|
+
|
|
90
99
|
[project.urls]
|
|
91
100
|
Homepage = "https://qdrant-loader.net"
|
|
92
101
|
Documentation = "https://qdrant-loader.net/docs/packages/qdrant-loader/README.html"
|
|
@@ -43,7 +43,14 @@ def __getattr__(name):
|
|
|
43
43
|
|
|
44
44
|
return QdrantManager
|
|
45
45
|
else:
|
|
46
|
-
|
|
46
|
+
try:
|
|
47
|
+
import importlib
|
|
48
|
+
|
|
49
|
+
return importlib.import_module(f"{__name__}.{name}")
|
|
50
|
+
except ImportError as err:
|
|
51
|
+
raise AttributeError(
|
|
52
|
+
f"module '{__name__}' has no attribute '{name}'"
|
|
53
|
+
) from err
|
|
47
54
|
|
|
48
55
|
|
|
49
56
|
__all__ = [
|
|
@@ -11,6 +11,8 @@ from click.utils import echo
|
|
|
11
11
|
|
|
12
12
|
# async_command is needed at module level for @async_command decorator on commands.
|
|
13
13
|
from qdrant_loader.cli.asyncio import async_command # noqa: F401
|
|
14
|
+
from qdrant_loader.cli.commands.jobs_cmd import jobs_cmd
|
|
15
|
+
from qdrant_loader.cli.commands.serve_cmd import serve_cmd as serve_command
|
|
14
16
|
from qdrant_loader.utils.sensitive import sanitize_exception_message
|
|
15
17
|
|
|
16
18
|
# Heavy modules are lazy-imported to keep CLI startup fast.
|
|
@@ -77,7 +79,9 @@ def _setup_logging(log_level: str, workspace_config=None) -> None:
|
|
|
77
79
|
|
|
78
80
|
log_format = "console"
|
|
79
81
|
log_file = (
|
|
80
|
-
str(workspace_config.logs_path
|
|
82
|
+
str(workspace_config.logs_path / "cli.log")
|
|
83
|
+
if workspace_config
|
|
84
|
+
else "qdrant-loader.log"
|
|
81
85
|
)
|
|
82
86
|
LoggingConfig.setup(level=log_level, format=log_format, file=log_file)
|
|
83
87
|
# update module-global logger
|
|
@@ -96,9 +100,13 @@ def _check_for_updates() -> None:
|
|
|
96
100
|
pass
|
|
97
101
|
|
|
98
102
|
|
|
99
|
-
def _setup_workspace(workspace_path
|
|
100
|
-
|
|
101
|
-
|
|
103
|
+
def _setup_workspace(workspace_path):
|
|
104
|
+
try:
|
|
105
|
+
return _setup_workspace_impl(workspace_path)
|
|
106
|
+
except ValueError as e:
|
|
107
|
+
raise ClickException(str(e)) from e
|
|
108
|
+
except Exception as e: # pragma: no cover - handled by CLI tests
|
|
109
|
+
raise ClickException(f"Failed to setup workspace: {str(e)!s}") from e
|
|
102
110
|
|
|
103
111
|
|
|
104
112
|
@group(name="qdrant-loader")
|
|
@@ -120,6 +128,10 @@ def cli(log_level: str = "INFO") -> None:
|
|
|
120
128
|
_check_for_updates()
|
|
121
129
|
|
|
122
130
|
|
|
131
|
+
cli.add_command(serve_command)
|
|
132
|
+
cli.add_command(jobs_cmd)
|
|
133
|
+
|
|
134
|
+
|
|
123
135
|
def _create_database_directory(path: Path) -> bool:
|
|
124
136
|
"""Create database directory with user confirmation.
|
|
125
137
|
|
|
@@ -400,6 +412,23 @@ async def ingest(
|
|
|
400
412
|
)
|
|
401
413
|
|
|
402
414
|
|
|
415
|
+
async def _start_webhook_server(
|
|
416
|
+
workspace: Path | None,
|
|
417
|
+
config: Path | None,
|
|
418
|
+
env: Path | None,
|
|
419
|
+
host: str,
|
|
420
|
+
port: int,
|
|
421
|
+
log_level: str,
|
|
422
|
+
) -> None:
|
|
423
|
+
"""Start webhook server for receiving connector events and triggering ingestion.
|
|
424
|
+
|
|
425
|
+
Internal function called by the future `serve` command. Not exposed as a user CLI command in v1.1.
|
|
426
|
+
"""
|
|
427
|
+
from qdrant_loader.cli.commands.webhook_cmd import run_webhook_command
|
|
428
|
+
|
|
429
|
+
await run_webhook_command(workspace, config, env, host, port, log_level)
|
|
430
|
+
|
|
431
|
+
|
|
403
432
|
@cli.command()
|
|
404
433
|
@option(
|
|
405
434
|
"--output-dir",
|
|
@@ -10,10 +10,25 @@ def __getattr__(name: str):
|
|
|
10
10
|
from .ingest import run_pipeline_ingestion
|
|
11
11
|
|
|
12
12
|
return run_pipeline_ingestion
|
|
13
|
+
if name == "serve_cmd":
|
|
14
|
+
from .serve_cmd import serve_cmd
|
|
15
|
+
|
|
16
|
+
return serve_cmd
|
|
17
|
+
if name == "jobs_cmd":
|
|
18
|
+
from .jobs_cmd import jobs_cmd
|
|
19
|
+
|
|
20
|
+
return jobs_cmd
|
|
21
|
+
if name == "run_webhook_command":
|
|
22
|
+
from .webhook_cmd import run_webhook_command
|
|
23
|
+
|
|
24
|
+
return run_webhook_command
|
|
13
25
|
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
14
26
|
|
|
15
27
|
|
|
16
28
|
__all__ = [
|
|
17
29
|
"run_init",
|
|
18
30
|
"run_pipeline_ingestion",
|
|
31
|
+
"serve_cmd",
|
|
32
|
+
"jobs_cmd",
|
|
33
|
+
"run_webhook_command",
|
|
19
34
|
]
|
|
@@ -40,7 +40,9 @@ def run_show_config(
|
|
|
40
40
|
|
|
41
41
|
# Setup/reconfigure logging once with workspace support
|
|
42
42
|
log_file = (
|
|
43
|
-
str(workspace_config.logs_path
|
|
43
|
+
str(workspace_config.logs_path / "config.log")
|
|
44
|
+
if workspace_config
|
|
45
|
+
else "qdrant-loader.log"
|
|
44
46
|
)
|
|
45
47
|
if getattr(LoggingConfig, "reconfigure", None): # Core supports reconfigure
|
|
46
48
|
if getattr(LoggingConfig, "_initialized", False): # type: ignore[attr-defined]
|
|
@@ -18,7 +18,9 @@ def run_config_command(
|
|
|
18
18
|
# Maintain test expectation: log via workspace-logger as before
|
|
19
19
|
workspace_config = _setup_workspace_impl(workspace) if workspace else None
|
|
20
20
|
log_file = (
|
|
21
|
-
str(workspace_config.logs_path
|
|
21
|
+
str(workspace_config.logs_path / "config.log")
|
|
22
|
+
if workspace_config
|
|
23
|
+
else "qdrant-loader.log"
|
|
22
24
|
)
|
|
23
25
|
if getattr(LoggingConfig, "reconfigure", None): # type: ignore[attr-defined]
|
|
24
26
|
if getattr(LoggingConfig, "_initialized", False): # type: ignore[attr-defined]
|
|
@@ -52,7 +52,9 @@ async def run_ingest_command(
|
|
|
52
52
|
|
|
53
53
|
# Setup/reconfigure logging with workspace support
|
|
54
54
|
log_file = (
|
|
55
|
-
str(workspace_config.logs_path
|
|
55
|
+
str(workspace_config.logs_path / "ingest.log")
|
|
56
|
+
if workspace_config
|
|
57
|
+
else "qdrant-loader.log"
|
|
56
58
|
)
|
|
57
59
|
if getattr(LoggingConfig, "reconfigure", None): # type: ignore[attr-defined]
|
|
58
60
|
if getattr(LoggingConfig, "_initialized", False): # type: ignore[attr-defined]
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
"""
|
|
2
|
+
qdrant-loader jobs admin CLI commands.
|
|
3
|
+
|
|
4
|
+
Subcommands: list [--status], retry <id>, trigger --source-type --source --mode, cancel <id>.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import asyncio
|
|
10
|
+
import json
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
import click
|
|
14
|
+
from click.exceptions import ClickException
|
|
15
|
+
from click.types import Choice
|
|
16
|
+
from click.types import Path as ClickPath
|
|
17
|
+
|
|
18
|
+
from qdrant_loader.core.worker.job_types import JobType
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _init_queue(workspace: Path | None, config: Path | None, env: Path | None):
|
|
22
|
+
"""Load config, build StateManager. Returns state_manager."""
|
|
23
|
+
from qdrant_loader.cli.config_loader import (
|
|
24
|
+
load_config_with_workspace,
|
|
25
|
+
setup_workspace,
|
|
26
|
+
)
|
|
27
|
+
from qdrant_loader.config import get_global_config
|
|
28
|
+
from qdrant_loader.config.workspace import validate_workspace_flags
|
|
29
|
+
from qdrant_loader.core.state.state_manager import StateManager
|
|
30
|
+
|
|
31
|
+
# Validate mutually exclusive flags early
|
|
32
|
+
try:
|
|
33
|
+
validate_workspace_flags(workspace, config, env)
|
|
34
|
+
except ValueError as e:
|
|
35
|
+
raise ClickException(str(e))
|
|
36
|
+
|
|
37
|
+
if workspace:
|
|
38
|
+
ws_config = setup_workspace(workspace)
|
|
39
|
+
load_config_with_workspace(workspace_config=ws_config, skip_validation=True)
|
|
40
|
+
else:
|
|
41
|
+
resolved_config = config
|
|
42
|
+
if resolved_config is None:
|
|
43
|
+
default_config = Path("config.yaml")
|
|
44
|
+
resolved_config = default_config if default_config.exists() else None
|
|
45
|
+
if resolved_config is None:
|
|
46
|
+
raise ClickException("No config found. Use --workspace or --config.")
|
|
47
|
+
load_config_with_workspace(
|
|
48
|
+
workspace_config=None,
|
|
49
|
+
config_path=resolved_config,
|
|
50
|
+
env_path=env,
|
|
51
|
+
skip_validation=True,
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
global_config = get_global_config()
|
|
55
|
+
state_manager = StateManager(global_config.state_management)
|
|
56
|
+
return state_manager
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
async def _run_with_queue(workspace, config, env, coro_factory):
|
|
60
|
+
"""Initialize queue, run coro_factory(queue), dispose state manager."""
|
|
61
|
+
state_manager = _init_queue(workspace, config, env)
|
|
62
|
+
await state_manager.initialize()
|
|
63
|
+
queue_instance = None
|
|
64
|
+
try:
|
|
65
|
+
from qdrant_loader.core.worker.queue import SQLiteJobQueue
|
|
66
|
+
|
|
67
|
+
queue_instance = SQLiteJobQueue(state_manager.session_factory)
|
|
68
|
+
return await coro_factory(queue_instance)
|
|
69
|
+
finally:
|
|
70
|
+
await state_manager.dispose()
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
# ────────────────────────────────────────────────
|
|
74
|
+
# Click group
|
|
75
|
+
# ────────────────────────────────────────────────
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
@click.group("jobs")
|
|
79
|
+
def jobs_cmd():
|
|
80
|
+
"""Inspect and manage background ingestion jobs."""
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _common_options(fn):
|
|
84
|
+
"""Decorator that adds --workspace, --config, --env options."""
|
|
85
|
+
fn = click.option(
|
|
86
|
+
"--workspace",
|
|
87
|
+
type=ClickPath(path_type=Path),
|
|
88
|
+
default=None,
|
|
89
|
+
help="Workspace directory.",
|
|
90
|
+
)(fn)
|
|
91
|
+
fn = click.option(
|
|
92
|
+
"--config",
|
|
93
|
+
"config_path",
|
|
94
|
+
type=ClickPath(path_type=Path),
|
|
95
|
+
default=None,
|
|
96
|
+
help="Path to config.yaml.",
|
|
97
|
+
)(fn)
|
|
98
|
+
fn = click.option(
|
|
99
|
+
"--env",
|
|
100
|
+
"env_path",
|
|
101
|
+
type=ClickPath(path_type=Path),
|
|
102
|
+
default=None,
|
|
103
|
+
help="Path to .env file.",
|
|
104
|
+
)(fn)
|
|
105
|
+
return fn
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
# ────────────────────────────────────────────────
|
|
109
|
+
# jobs list
|
|
110
|
+
# ────────────────────────────────────────────────
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
@jobs_cmd.command("list")
|
|
114
|
+
@click.option(
|
|
115
|
+
"--status",
|
|
116
|
+
type=Choice(
|
|
117
|
+
["pending", "running", "done", "failed", "cancelled"], case_sensitive=False
|
|
118
|
+
),
|
|
119
|
+
default=None,
|
|
120
|
+
help="Filter by job status.",
|
|
121
|
+
)
|
|
122
|
+
@click.option(
|
|
123
|
+
"--limit",
|
|
124
|
+
type=click.IntRange(min=1, max=1000),
|
|
125
|
+
default=50,
|
|
126
|
+
show_default=True,
|
|
127
|
+
help="Max rows to return.",
|
|
128
|
+
)
|
|
129
|
+
@click.option("--json", "output_json", is_flag=True, help="Output as JSON.")
|
|
130
|
+
@_common_options
|
|
131
|
+
def jobs_list(status, limit, output_json, workspace, config_path, env_path):
|
|
132
|
+
"""List jobs, optionally filtered by status."""
|
|
133
|
+
|
|
134
|
+
async def _list(queue):
|
|
135
|
+
jobs = await queue.list(status=status, limit=limit)
|
|
136
|
+
if output_json:
|
|
137
|
+
rows = []
|
|
138
|
+
for j in jobs:
|
|
139
|
+
rows.append(
|
|
140
|
+
{
|
|
141
|
+
"id": j.id,
|
|
142
|
+
"type": j.type,
|
|
143
|
+
"status": j.status,
|
|
144
|
+
"attempts": j.attempts,
|
|
145
|
+
"enqueued_at": (
|
|
146
|
+
j.enqueued_at.isoformat() if j.enqueued_at else None
|
|
147
|
+
),
|
|
148
|
+
"started_at": (
|
|
149
|
+
j.started_at.isoformat() if j.started_at else None
|
|
150
|
+
),
|
|
151
|
+
"finished_at": (
|
|
152
|
+
j.finished_at.isoformat() if j.finished_at else None
|
|
153
|
+
),
|
|
154
|
+
"last_error": j.last_error,
|
|
155
|
+
"payload": json.loads(j.payload_json) if j.payload_json else {},
|
|
156
|
+
}
|
|
157
|
+
)
|
|
158
|
+
click.echo(json.dumps(rows, indent=2))
|
|
159
|
+
else:
|
|
160
|
+
if not jobs:
|
|
161
|
+
click.echo("No jobs found.")
|
|
162
|
+
return
|
|
163
|
+
header = f"{'ID':>6} {'STATUS':<10} {'TYPE':<20} {'ATTEMPTS':>8} {'ENQUEUED_AT':<27} LAST_ERROR"
|
|
164
|
+
click.echo(header)
|
|
165
|
+
click.echo("-" * len(header))
|
|
166
|
+
for j in jobs:
|
|
167
|
+
enq = j.enqueued_at.isoformat() if j.enqueued_at else ""
|
|
168
|
+
err = (j.last_error or "")[:40]
|
|
169
|
+
click.echo(
|
|
170
|
+
f"{j.id:>6} {j.status:<10} {j.type:<20} {j.attempts:>8} {enq:<27} {err}"
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
asyncio.run(_run_with_queue(workspace, config_path, env_path, _list))
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
# ────────────────────────────────────────────────
|
|
177
|
+
# jobs retry
|
|
178
|
+
# ────────────────────────────────────────────────
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
@jobs_cmd.command("retry")
|
|
182
|
+
@click.argument("job_id", type=int)
|
|
183
|
+
@_common_options
|
|
184
|
+
def jobs_retry(job_id, workspace, config_path, env_path):
|
|
185
|
+
"""Reset a failed or done job back to pending."""
|
|
186
|
+
|
|
187
|
+
async def _retry(queue):
|
|
188
|
+
ok = await queue.reset_to_pending(job_id)
|
|
189
|
+
if ok:
|
|
190
|
+
click.echo(f"Job {job_id} reset to pending.")
|
|
191
|
+
else:
|
|
192
|
+
raise ClickException(
|
|
193
|
+
f"Job {job_id} not found or is not in failed/done state."
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
asyncio.run(_run_with_queue(workspace, config_path, env_path, _retry))
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
# ────────────────────────────────────────────────
|
|
200
|
+
# jobs trigger
|
|
201
|
+
# ────────────────────────────────────────────────
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
@jobs_cmd.command("trigger")
|
|
205
|
+
@click.option(
|
|
206
|
+
"--source-type", required=True, help="Source type (e.g. git, confluence)."
|
|
207
|
+
)
|
|
208
|
+
@click.option("--source", required=True, help="Source name as configured.")
|
|
209
|
+
@click.option(
|
|
210
|
+
"--mode",
|
|
211
|
+
type=Choice(["bulk", "incremental"], case_sensitive=False),
|
|
212
|
+
required=True,
|
|
213
|
+
help="Ingestion mode.",
|
|
214
|
+
)
|
|
215
|
+
@click.option("--project", "project_id", required=True, help="Project ID.")
|
|
216
|
+
@_common_options
|
|
217
|
+
def jobs_trigger(
|
|
218
|
+
source_type, source, mode, project_id, workspace, config_path, env_path
|
|
219
|
+
):
|
|
220
|
+
"""Enqueue a new ingestion job immediately."""
|
|
221
|
+
|
|
222
|
+
async def _trigger(queue):
|
|
223
|
+
job_type = (
|
|
224
|
+
JobType.BULK_INGEST if mode.lower() == "bulk" else JobType.INCREMENTAL_PULL
|
|
225
|
+
)
|
|
226
|
+
payload = {
|
|
227
|
+
"project_id": project_id,
|
|
228
|
+
"source_type": source_type,
|
|
229
|
+
"source": source,
|
|
230
|
+
"source_lock": f"{project_id}:{source_type}:{source}",
|
|
231
|
+
}
|
|
232
|
+
job = await queue.enqueue(job_type, payload)
|
|
233
|
+
click.echo(f"Enqueued job {job.id} (type={job_type}, status={job.status}).")
|
|
234
|
+
|
|
235
|
+
asyncio.run(_run_with_queue(workspace, config_path, env_path, _trigger))
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
# ────────────────────────────────────────────────
|
|
239
|
+
# jobs cancel
|
|
240
|
+
# ────────────────────────────────────────────────
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
@jobs_cmd.command("cancel")
|
|
244
|
+
@click.argument("job_id", type=int)
|
|
245
|
+
@_common_options
|
|
246
|
+
def jobs_cancel(job_id, workspace, config_path, env_path):
|
|
247
|
+
"""Cancel a pending job."""
|
|
248
|
+
|
|
249
|
+
async def _cancel(queue):
|
|
250
|
+
ok = await queue.cancel(job_id)
|
|
251
|
+
if ok:
|
|
252
|
+
click.echo(f"Job {job_id} cancelled.")
|
|
253
|
+
else:
|
|
254
|
+
raise ClickException(f"Job {job_id} not found or is not in pending state.")
|
|
255
|
+
|
|
256
|
+
asyncio.run(_run_with_queue(workspace, config_path, env_path, _cancel))
|