azure-doc-intelligence-haystack 1.0.0__tar.gz → 1.2.0__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.
- azure_doc_intelligence_haystack-1.2.0/CHANGELOG.md +36 -0
- azure_doc_intelligence_haystack-1.0.0/LICENSE → azure_doc_intelligence_haystack-1.2.0/LICENSE.txt +1 -1
- {azure_doc_intelligence_haystack-1.0.0 → azure_doc_intelligence_haystack-1.2.0}/PKG-INFO +7 -3
- {azure_doc_intelligence_haystack-1.0.0 → azure_doc_intelligence_haystack-1.2.0}/README.md +3 -0
- azure_doc_intelligence_haystack-1.2.0/pydoc/config_docusaurus.yml +13 -0
- {azure_doc_intelligence_haystack-1.0.0 → azure_doc_intelligence_haystack-1.2.0}/pyproject.toml +9 -5
- {azure_doc_intelligence_haystack-1.0.0 → azure_doc_intelligence_haystack-1.2.0}/src/haystack_integrations/components/converters/azure_doc_intelligence/converter.py +11 -7
- {azure_doc_intelligence_haystack-1.0.0 → azure_doc_intelligence_haystack-1.2.0}/tests/test_azure_document_intelligence_converter.py +199 -10
- azure_doc_intelligence_haystack-1.0.0/pydoc/config_docusaurus.yml +0 -28
- azure_doc_intelligence_haystack-1.0.0/src/haystack_integrations/components/__init__.py +0 -3
- azure_doc_intelligence_haystack-1.0.0/src/haystack_integrations/components/converters/__init__.py +0 -3
- azure_doc_intelligence_haystack-1.0.0/tests/__init__.py +0 -3
- {azure_doc_intelligence_haystack-1.0.0 → azure_doc_intelligence_haystack-1.2.0}/.gitignore +0 -0
- {azure_doc_intelligence_haystack-1.0.0 → azure_doc_intelligence_haystack-1.2.0}/src/haystack_integrations/components/converters/azure_doc_intelligence/__init__.py +0 -0
- {azure_doc_intelligence_haystack-1.0.0 → azure_doc_intelligence_haystack-1.2.0}/src/haystack_integrations/components/converters/py.typed +0 -0
- {azure_doc_intelligence_haystack-1.0.0/src/haystack_integrations → azure_doc_intelligence_haystack-1.2.0/tests}/__init__.py +0 -0
- {azure_doc_intelligence_haystack-1.0.0 → azure_doc_intelligence_haystack-1.2.0}/tests/test_files/docx/sample.docx +0 -0
- {azure_doc_intelligence_haystack-1.0.0 → azure_doc_intelligence_haystack-1.2.0}/tests/test_files/images/sample_text.jpg +0 -0
- {azure_doc_intelligence_haystack-1.0.0 → azure_doc_intelligence_haystack-1.2.0}/tests/test_files/pdf/sample_pdf_1.pdf +0 -0
- {azure_doc_intelligence_haystack-1.0.0 → azure_doc_intelligence_haystack-1.2.0}/tests/test_files/pdf/sample_pdf_2.pdf +0 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [integrations/azure_doc_intelligence-v1.1.0] - 2026-08-17
|
|
4
|
+
|
|
5
|
+
### 🐛 Bug Fixes
|
|
6
|
+
|
|
7
|
+
- Fix new issues raised by ruff 0.16.0 (#3670)
|
|
8
|
+
- Standardize license files (#3771)
|
|
9
|
+
- Azure Document Intelligence - fix default model (#3769)
|
|
10
|
+
|
|
11
|
+
### 📚 Documentation
|
|
12
|
+
|
|
13
|
+
- Simplify pydoc configs (#2855)
|
|
14
|
+
|
|
15
|
+
### 🧪 Testing
|
|
16
|
+
|
|
17
|
+
- Test compatible integrations with python 3.14; update pyproject (#3001)
|
|
18
|
+
- Track test coverage for all integrations (#3065)
|
|
19
|
+
- AzureDocumentIntelligenceConverter - add tests (#3205)
|
|
20
|
+
|
|
21
|
+
### 🧹 Chores
|
|
22
|
+
|
|
23
|
+
- Remove unused allow-direct-references (#2866)
|
|
24
|
+
- Enable ANN ruff ruleset for azure_doc_intelligence integration (#2981)
|
|
25
|
+
- Enforce ruff docstring rules (D102/D103/D205/D209/D213/D417/D419) in first 10 integrations (#3008)
|
|
26
|
+
- Improve consistency of integrations folder structure (#3430)
|
|
27
|
+
- Re-standardize READMEs (#3768)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
## [integrations/azure_doc_intelligence-v1.0.0] - 2026-01-19
|
|
31
|
+
|
|
32
|
+
### 🚀 Features
|
|
33
|
+
|
|
34
|
+
- Add azure-doc-intelligence integration (#2717)
|
|
35
|
+
|
|
36
|
+
<!-- generated by git-cliff -->
|
azure_doc_intelligence_haystack-1.0.0/LICENSE → azure_doc_intelligence_haystack-1.2.0/LICENSE.txt
RENAMED
|
@@ -186,7 +186,7 @@
|
|
|
186
186
|
same "printed page" as the copyright notice for easier
|
|
187
187
|
identification within third-party archives.
|
|
188
188
|
|
|
189
|
-
Copyright 2023 deepset GmbH
|
|
189
|
+
Copyright 2023-present deepset GmbH
|
|
190
190
|
|
|
191
191
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
192
|
you may not use this file except in compliance with the License.
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: azure-doc-intelligence-haystack
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.2.0
|
|
4
4
|
Summary: Haystack integration for Azure Document Intelligence
|
|
5
5
|
Project-URL: Documentation, https://github.com/deepset-ai/haystack-core-integrations/tree/main/integrations/azure_doc_intelligence#readme
|
|
6
6
|
Project-URL: Issues, https://github.com/deepset-ai/haystack-core-integrations/issues
|
|
7
7
|
Project-URL: Source, https://github.com/deepset-ai/haystack-core-integrations/tree/main/integrations/azure_doc_intelligence
|
|
8
8
|
Author-email: deepset GmbH <info@deepset.ai>
|
|
9
9
|
License-Expression: Apache-2.0
|
|
10
|
-
License-File: LICENSE
|
|
10
|
+
License-File: LICENSE.txt
|
|
11
11
|
Keywords: Azure,Document Converter,Document Intelligence,Haystack,OCR,PDF
|
|
12
12
|
Classifier: Development Status :: 4 - Beta
|
|
13
13
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
@@ -16,6 +16,7 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
16
16
|
Classifier: Programming Language :: Python :: 3.11
|
|
17
17
|
Classifier: Programming Language :: Python :: 3.12
|
|
18
18
|
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
19
20
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
20
21
|
Requires-Python: >=3.10
|
|
21
22
|
Requires-Dist: azure-ai-documentintelligence>=1.0.0
|
|
@@ -27,6 +28,7 @@ Description-Content-Type: text/markdown
|
|
|
27
28
|
[](https://pypi.org/project/azure-doc-intelligence-haystack)
|
|
28
29
|
[](https://pypi.org/project/azure-doc-intelligence-haystack)
|
|
29
30
|
|
|
31
|
+
- [Integration page](https://haystack.deepset.ai/integrations/azure-doc-intelligence)
|
|
30
32
|
- [Changelog](https://github.com/deepset-ai/haystack-core-integrations/blob/main/integrations/azure_doc_intelligence/CHANGELOG.md)
|
|
31
33
|
|
|
32
34
|
---
|
|
@@ -34,3 +36,5 @@ Description-Content-Type: text/markdown
|
|
|
34
36
|
## Contributing
|
|
35
37
|
|
|
36
38
|
Refer to the general [Contribution Guidelines](https://github.com/deepset-ai/haystack-core-integrations/blob/main/CONTRIBUTING.md).
|
|
39
|
+
|
|
40
|
+
To run integration tests locally, you need to export the `AZURE_DI_ENDPOINT` and `AZURE_DI_API_KEY` environment variables.
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
[](https://pypi.org/project/azure-doc-intelligence-haystack)
|
|
4
4
|
[](https://pypi.org/project/azure-doc-intelligence-haystack)
|
|
5
5
|
|
|
6
|
+
- [Integration page](https://haystack.deepset.ai/integrations/azure-doc-intelligence)
|
|
6
7
|
- [Changelog](https://github.com/deepset-ai/haystack-core-integrations/blob/main/integrations/azure_doc_intelligence/CHANGELOG.md)
|
|
7
8
|
|
|
8
9
|
---
|
|
@@ -10,3 +11,5 @@
|
|
|
10
11
|
## Contributing
|
|
11
12
|
|
|
12
13
|
Refer to the general [Contribution Guidelines](https://github.com/deepset-ai/haystack-core-integrations/blob/main/CONTRIBUTING.md).
|
|
14
|
+
|
|
15
|
+
To run integration tests locally, you need to export the `AZURE_DI_ENDPOINT` and `AZURE_DI_API_KEY` environment variables.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
loaders:
|
|
2
|
+
- modules:
|
|
3
|
+
- haystack_integrations.components.converters.azure_doc_intelligence.converter
|
|
4
|
+
search_path: [../src]
|
|
5
|
+
processors:
|
|
6
|
+
- type: filter
|
|
7
|
+
documented_only: true
|
|
8
|
+
skip_empty_modules: true
|
|
9
|
+
renderer:
|
|
10
|
+
description: Azure Document Intelligence integration for Haystack
|
|
11
|
+
id: integrations-azure_doc_intelligence
|
|
12
|
+
filename: azure_doc_intelligence.md
|
|
13
|
+
title: Azure Document Intelligence
|
{azure_doc_intelligence_haystack-1.0.0 → azure_doc_intelligence_haystack-1.2.0}/pyproject.toml
RENAMED
|
@@ -28,6 +28,7 @@ classifiers = [
|
|
|
28
28
|
"Programming Language :: Python :: 3.11",
|
|
29
29
|
"Programming Language :: Python :: 3.12",
|
|
30
30
|
"Programming Language :: Python :: 3.13",
|
|
31
|
+
"Programming Language :: Python :: 3.14",
|
|
31
32
|
"Programming Language :: Python :: Implementation :: CPython",
|
|
32
33
|
]
|
|
33
34
|
dependencies = [
|
|
@@ -56,7 +57,7 @@ installer = "uv"
|
|
|
56
57
|
dependencies = ["haystack-pydoc-tools", "ruff"]
|
|
57
58
|
|
|
58
59
|
[tool.hatch.envs.default.scripts]
|
|
59
|
-
docs = ["pydoc
|
|
60
|
+
docs = ["haystack-pydoc pydoc/config_docusaurus.yml"]
|
|
60
61
|
fmt = "ruff check --fix {args}; ruff format {args}"
|
|
61
62
|
fmt-check = "ruff check {args} && ruff format --check {args}"
|
|
62
63
|
|
|
@@ -74,7 +75,8 @@ dependencies = [
|
|
|
74
75
|
unit = 'pytest -m "not integration" {args:tests}'
|
|
75
76
|
integration = 'pytest -m "integration" {args:tests}'
|
|
76
77
|
all = 'pytest {args:tests}'
|
|
77
|
-
cov-retry = 'pytest --cov=haystack_integrations --reruns 3 --reruns-delay 30 -x {args:tests}'
|
|
78
|
+
unit-cov-retry = 'pytest --cov=haystack_integrations --reruns 3 --reruns-delay 30 -x -m "not integration" {args:tests}'
|
|
79
|
+
integration-cov-append-retry = 'pytest --cov=haystack_integrations --cov-append --reruns 3 --reruns-delay 30 -x -m "integration" {args:tests}'
|
|
78
80
|
types = "mypy -p haystack_integrations.components.converters.azure_doc_intelligence {args}"
|
|
79
81
|
|
|
80
82
|
[tool.mypy]
|
|
@@ -83,8 +85,6 @@ non_interactive = true
|
|
|
83
85
|
check_untyped_defs = true
|
|
84
86
|
disallow_incomplete_defs = true
|
|
85
87
|
|
|
86
|
-
[tool.hatch.metadata]
|
|
87
|
-
allow-direct-references = true
|
|
88
88
|
|
|
89
89
|
[tool.ruff]
|
|
90
90
|
line-length = 120
|
|
@@ -92,6 +92,7 @@ line-length = 120
|
|
|
92
92
|
[tool.ruff.lint]
|
|
93
93
|
select = [
|
|
94
94
|
"A",
|
|
95
|
+
"ANN",
|
|
95
96
|
"ARG",
|
|
96
97
|
"B",
|
|
97
98
|
"C",
|
|
@@ -117,6 +118,7 @@ select = [
|
|
|
117
118
|
"YTT",
|
|
118
119
|
]
|
|
119
120
|
ignore = [
|
|
121
|
+
"ANN401", # Allow Any - used legitimately for dynamic types and SDK boundaries
|
|
120
122
|
# Allow non-abstract empty methods in abstract base classes
|
|
121
123
|
"B027",
|
|
122
124
|
# Allow function calls in argument defaults (common Haystack pattern for Secret.from_env_var)
|
|
@@ -133,6 +135,7 @@ ignore = [
|
|
|
133
135
|
"PLR0912",
|
|
134
136
|
"PLR0913",
|
|
135
137
|
"PLR0915",
|
|
138
|
+
"PLR0917",
|
|
136
139
|
]
|
|
137
140
|
unfixable = [
|
|
138
141
|
# Don't touch unused imports
|
|
@@ -147,11 +150,12 @@ ban-relative-imports = "parents"
|
|
|
147
150
|
|
|
148
151
|
[tool.ruff.lint.per-file-ignores]
|
|
149
152
|
# Tests can use magic values, assertions, and relative imports
|
|
150
|
-
"tests/**/*" = ["PLR2004", "S101", "TID252"]
|
|
153
|
+
"tests/**/*" = ["PLR2004", "S101", "TID252", "D", "ANN"]
|
|
151
154
|
|
|
152
155
|
[tool.coverage.run]
|
|
153
156
|
source = ["haystack_integrations"]
|
|
154
157
|
branch = true
|
|
158
|
+
relative_files = true
|
|
155
159
|
parallel = false
|
|
156
160
|
|
|
157
161
|
[tool.coverage.report]
|
|
@@ -65,9 +65,9 @@ class AzureDocumentIntelligenceConverter:
|
|
|
65
65
|
endpoint: str,
|
|
66
66
|
*,
|
|
67
67
|
api_key: Secret = Secret.from_env_var("AZURE_DI_API_KEY"),
|
|
68
|
-
model_id: str = "prebuilt-
|
|
68
|
+
model_id: str = "prebuilt-layout",
|
|
69
69
|
store_full_path: bool = False,
|
|
70
|
-
):
|
|
70
|
+
) -> None:
|
|
71
71
|
"""
|
|
72
72
|
Creates an AzureDocumentIntelligenceConverter component.
|
|
73
73
|
|
|
@@ -79,9 +79,8 @@ class AzureDocumentIntelligenceConverter:
|
|
|
79
79
|
to load from AZURE_DI_API_KEY environment variable.
|
|
80
80
|
:param model_id:
|
|
81
81
|
Azure model to use for analysis. Options:
|
|
82
|
-
- "prebuilt-
|
|
82
|
+
- "prebuilt-layout": Layout analysis with table and structure detection (default)
|
|
83
83
|
- "prebuilt-read": Fast OCR for text extraction
|
|
84
|
-
- "prebuilt-layout": Enhanced layout analysis with better table/structure detection
|
|
85
84
|
- Custom model IDs from your Azure resource
|
|
86
85
|
:param store_full_path:
|
|
87
86
|
If True, stores complete file path in metadata.
|
|
@@ -93,7 +92,7 @@ class AzureDocumentIntelligenceConverter:
|
|
|
93
92
|
self.store_full_path = store_full_path
|
|
94
93
|
self.client: DocumentIntelligenceClient | None = None
|
|
95
94
|
|
|
96
|
-
def warm_up(self):
|
|
95
|
+
def warm_up(self) -> None:
|
|
97
96
|
"""
|
|
98
97
|
Initializes the Azure Document Intelligence client.
|
|
99
98
|
"""
|
|
@@ -102,6 +101,12 @@ class AzureDocumentIntelligenceConverter:
|
|
|
102
101
|
endpoint=self.endpoint, credential=AzureKeyCredential(self.api_key.resolve_value() or "")
|
|
103
102
|
)
|
|
104
103
|
|
|
104
|
+
def close(self) -> None:
|
|
105
|
+
"""Close the Azure Document Intelligence client."""
|
|
106
|
+
if self.client is not None:
|
|
107
|
+
self.client.close()
|
|
108
|
+
self.client = None
|
|
109
|
+
|
|
105
110
|
@component.output_types(documents=list[Document], raw_azure_response=list[dict])
|
|
106
111
|
def run(
|
|
107
112
|
self,
|
|
@@ -125,8 +130,7 @@ class AzureDocumentIntelligenceConverter:
|
|
|
125
130
|
- `documents`: List of created Documents
|
|
126
131
|
- `raw_azure_response`: List of raw Azure responses used to create the Documents
|
|
127
132
|
"""
|
|
128
|
-
|
|
129
|
-
self.warm_up()
|
|
133
|
+
self.warm_up()
|
|
130
134
|
|
|
131
135
|
documents = []
|
|
132
136
|
azure_responses = []
|
|
@@ -4,14 +4,35 @@
|
|
|
4
4
|
|
|
5
5
|
import os
|
|
6
6
|
from pathlib import Path
|
|
7
|
+
from unittest.mock import MagicMock, patch
|
|
7
8
|
|
|
8
9
|
import pytest
|
|
10
|
+
from haystack.dataclasses import ByteStream
|
|
9
11
|
from haystack.utils import Secret
|
|
10
12
|
|
|
11
13
|
from haystack_integrations.components.converters.azure_doc_intelligence import AzureDocumentIntelligenceConverter
|
|
12
14
|
|
|
13
15
|
|
|
14
|
-
|
|
16
|
+
def make_mock_analyze_result(content="# Title\n\nBody", pages=("p1",), as_dict_value=None):
|
|
17
|
+
result = MagicMock()
|
|
18
|
+
result.content = content
|
|
19
|
+
result.pages = list(pages) if pages is not None else None
|
|
20
|
+
result.as_dict.return_value = as_dict_value if as_dict_value is not None else {"content": content}
|
|
21
|
+
return result
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@pytest.fixture
|
|
25
|
+
def warmed_converter():
|
|
26
|
+
converter = AzureDocumentIntelligenceConverter(
|
|
27
|
+
endpoint="https://test.cognitiveservices.azure.com/",
|
|
28
|
+
api_key=Secret.from_token("test_api_key"),
|
|
29
|
+
)
|
|
30
|
+
converter.client = MagicMock()
|
|
31
|
+
converter.client.begin_analyze_document.return_value.result.return_value = make_mock_analyze_result()
|
|
32
|
+
return converter
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class TestAzureDocumentIntelligenceConverterInitSerde:
|
|
15
36
|
def test_init_default(self):
|
|
16
37
|
"""Test basic initialization with defaults"""
|
|
17
38
|
converter = AzureDocumentIntelligenceConverter(
|
|
@@ -20,28 +41,30 @@ class TestAzureDocumentIntelligenceConverter:
|
|
|
20
41
|
)
|
|
21
42
|
|
|
22
43
|
assert converter.endpoint == "https://test.cognitiveservices.azure.com/"
|
|
23
|
-
assert converter.model_id == "prebuilt-
|
|
44
|
+
assert converter.model_id == "prebuilt-layout"
|
|
24
45
|
assert converter.store_full_path is False
|
|
46
|
+
assert converter.client is None
|
|
25
47
|
|
|
26
48
|
def test_init_custom_params(self):
|
|
27
49
|
"""Test initialization with custom parameters"""
|
|
28
50
|
converter = AzureDocumentIntelligenceConverter(
|
|
29
51
|
endpoint="https://test.cognitiveservices.azure.com/",
|
|
30
52
|
api_key=Secret.from_token("test_api_key"),
|
|
31
|
-
model_id="prebuilt-
|
|
53
|
+
model_id="prebuilt-read",
|
|
32
54
|
store_full_path=True,
|
|
33
55
|
)
|
|
34
56
|
|
|
35
57
|
assert converter.endpoint == "https://test.cognitiveservices.azure.com/"
|
|
36
|
-
assert converter.model_id == "prebuilt-
|
|
58
|
+
assert converter.model_id == "prebuilt-read"
|
|
37
59
|
assert converter.store_full_path is True
|
|
60
|
+
assert converter.client is None
|
|
38
61
|
|
|
39
62
|
def test_to_dict(self):
|
|
40
63
|
"""Test serialization with Secret handling"""
|
|
41
64
|
converter = AzureDocumentIntelligenceConverter(
|
|
42
65
|
endpoint="https://test.cognitiveservices.azure.com/",
|
|
43
66
|
api_key=Secret.from_env_var("AZURE_DI_API_KEY"),
|
|
44
|
-
model_id="prebuilt-
|
|
67
|
+
model_id="prebuilt-read",
|
|
45
68
|
store_full_path=True,
|
|
46
69
|
)
|
|
47
70
|
|
|
@@ -56,7 +79,7 @@ class TestAzureDocumentIntelligenceConverter:
|
|
|
56
79
|
"init_parameters": {
|
|
57
80
|
"api_key": {"type": "env_var", "env_vars": ["AZURE_DI_API_KEY"], "strict": True},
|
|
58
81
|
"endpoint": "https://test.cognitiveservices.azure.com/",
|
|
59
|
-
"model_id": "prebuilt-
|
|
82
|
+
"model_id": "prebuilt-read",
|
|
60
83
|
"store_full_path": True,
|
|
61
84
|
},
|
|
62
85
|
}
|
|
@@ -71,7 +94,7 @@ class TestAzureDocumentIntelligenceConverter:
|
|
|
71
94
|
data = converter.to_dict()
|
|
72
95
|
|
|
73
96
|
assert data["init_parameters"]["endpoint"] == "https://test.cognitiveservices.azure.com/"
|
|
74
|
-
assert data["init_parameters"]["model_id"] == "prebuilt-
|
|
97
|
+
assert data["init_parameters"]["model_id"] == "prebuilt-layout"
|
|
75
98
|
assert data["init_parameters"]["store_full_path"] is False
|
|
76
99
|
|
|
77
100
|
def test_from_dict(self):
|
|
@@ -85,7 +108,7 @@ class TestAzureDocumentIntelligenceConverter:
|
|
|
85
108
|
"init_parameters": {
|
|
86
109
|
"api_key": {"type": "env_var", "env_vars": ["AZURE_DI_API_KEY"], "strict": True},
|
|
87
110
|
"endpoint": "https://test.cognitiveservices.azure.com/",
|
|
88
|
-
"model_id": "prebuilt-
|
|
111
|
+
"model_id": "prebuilt-read",
|
|
89
112
|
"store_full_path": False,
|
|
90
113
|
},
|
|
91
114
|
}
|
|
@@ -93,8 +116,174 @@ class TestAzureDocumentIntelligenceConverter:
|
|
|
93
116
|
converter = AzureDocumentIntelligenceConverter.from_dict(data)
|
|
94
117
|
|
|
95
118
|
assert converter.endpoint == "https://test.cognitiveservices.azure.com/"
|
|
96
|
-
assert converter.model_id == "prebuilt-
|
|
119
|
+
assert converter.model_id == "prebuilt-read"
|
|
97
120
|
assert converter.store_full_path is False
|
|
121
|
+
assert converter.client is None
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
class TestComponentLifecycle:
|
|
125
|
+
def test_key_resolved_at_warm_up_not_init(self, monkeypatch):
|
|
126
|
+
monkeypatch.delenv("MISSING_AZURE_DI_API_KEY", raising=False)
|
|
127
|
+
converter = AzureDocumentIntelligenceConverter(
|
|
128
|
+
endpoint="https://test.cognitiveservices.azure.com/",
|
|
129
|
+
api_key=Secret.from_env_var("MISSING_AZURE_DI_API_KEY"),
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
assert converter.client is None
|
|
133
|
+
with pytest.raises(ValueError, match="MISSING_AZURE_DI_API_KEY"):
|
|
134
|
+
converter.warm_up()
|
|
135
|
+
|
|
136
|
+
def test_sync_lifecycle(self):
|
|
137
|
+
converter = AzureDocumentIntelligenceConverter(
|
|
138
|
+
endpoint="https://test.cognitiveservices.azure.com/",
|
|
139
|
+
api_key=Secret.from_token("test_api_key"),
|
|
140
|
+
)
|
|
141
|
+
with patch(
|
|
142
|
+
"haystack_integrations.components.converters.azure_doc_intelligence.converter.DocumentIntelligenceClient"
|
|
143
|
+
) as mock_client_cls:
|
|
144
|
+
client = mock_client_cls.return_value
|
|
145
|
+
converter.warm_up()
|
|
146
|
+
assert converter.client is client
|
|
147
|
+
converter.close()
|
|
148
|
+
client.close.assert_called_once_with()
|
|
149
|
+
assert converter.client is None
|
|
150
|
+
converter.warm_up()
|
|
151
|
+
assert mock_client_cls.call_count == 2
|
|
152
|
+
|
|
153
|
+
def test_warm_up_is_idempotent(self):
|
|
154
|
+
converter = AzureDocumentIntelligenceConverter(
|
|
155
|
+
endpoint="https://test.cognitiveservices.azure.com/",
|
|
156
|
+
api_key=Secret.from_token("test_api_key"),
|
|
157
|
+
)
|
|
158
|
+
with patch(
|
|
159
|
+
"haystack_integrations.components.converters.azure_doc_intelligence.converter.DocumentIntelligenceClient"
|
|
160
|
+
) as mock_client_cls:
|
|
161
|
+
converter.warm_up()
|
|
162
|
+
converter.warm_up()
|
|
163
|
+
|
|
164
|
+
mock_client_cls.assert_called_once()
|
|
165
|
+
|
|
166
|
+
def test_close_is_safe_without_warm_up(self):
|
|
167
|
+
converter = AzureDocumentIntelligenceConverter(
|
|
168
|
+
endpoint="https://test.cognitiveservices.azure.com/",
|
|
169
|
+
api_key=Secret.from_token("test_api_key"),
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
converter.close()
|
|
173
|
+
|
|
174
|
+
assert converter.client is None
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
class TestAzureDocumentIntelligenceConverterRun:
|
|
178
|
+
def test_run_calls_warm_up(self):
|
|
179
|
+
converter = AzureDocumentIntelligenceConverter(
|
|
180
|
+
endpoint="https://test.cognitiveservices.azure.com/",
|
|
181
|
+
api_key=Secret.from_token("test_api_key"),
|
|
182
|
+
)
|
|
183
|
+
with patch(
|
|
184
|
+
"haystack_integrations.components.converters.azure_doc_intelligence.converter.DocumentIntelligenceClient"
|
|
185
|
+
) as mock_client_cls:
|
|
186
|
+
mock_client_cls.return_value.begin_analyze_document.return_value.result.return_value = (
|
|
187
|
+
make_mock_analyze_result()
|
|
188
|
+
)
|
|
189
|
+
result = converter.run(sources=[ByteStream.from_string("data")])
|
|
190
|
+
|
|
191
|
+
assert converter.client is mock_client_cls.return_value
|
|
192
|
+
assert len(result["documents"]) == 1
|
|
193
|
+
|
|
194
|
+
def test_run_returns_document_with_markdown_content_and_meta(self, warmed_converter):
|
|
195
|
+
warmed_converter.client.begin_analyze_document.return_value.result.return_value = make_mock_analyze_result(
|
|
196
|
+
content="# Heading\n\nHello", pages=("p1", "p2", "p3")
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
result = warmed_converter.run(sources=[ByteStream.from_string("data")])
|
|
200
|
+
|
|
201
|
+
assert len(result["documents"]) == 1
|
|
202
|
+
doc = result["documents"][0]
|
|
203
|
+
assert doc.content == "# Heading\n\nHello"
|
|
204
|
+
assert doc.meta["model_id"] == "prebuilt-layout"
|
|
205
|
+
assert doc.meta["page_count"] == 3
|
|
206
|
+
|
|
207
|
+
def test_run_returns_raw_azure_response(self, warmed_converter):
|
|
208
|
+
raw_dict = {"content": "text", "pages": [{"page_number": 1}]}
|
|
209
|
+
warmed_converter.client.begin_analyze_document.return_value.result.return_value = make_mock_analyze_result(
|
|
210
|
+
content="text", as_dict_value=raw_dict
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
result = warmed_converter.run(sources=[ByteStream.from_string("data")])
|
|
214
|
+
|
|
215
|
+
assert result["raw_azure_response"] == [raw_dict]
|
|
216
|
+
|
|
217
|
+
def test_run_with_multiple_sources(self, warmed_converter):
|
|
218
|
+
sources = [ByteStream.from_string("one"), ByteStream.from_string("two")]
|
|
219
|
+
|
|
220
|
+
result = warmed_converter.run(sources=sources)
|
|
221
|
+
|
|
222
|
+
assert len(result["documents"]) == 2
|
|
223
|
+
assert len(result["raw_azure_response"]) == 2
|
|
224
|
+
|
|
225
|
+
@pytest.mark.parametrize("store_full_path", [True, False])
|
|
226
|
+
def test_run_respects_store_full_path(self, store_full_path):
|
|
227
|
+
pdf_path = Path(__file__).parent / "test_files" / "pdf" / "sample_pdf_1.pdf"
|
|
228
|
+
converter = AzureDocumentIntelligenceConverter(
|
|
229
|
+
endpoint="https://test.cognitiveservices.azure.com/",
|
|
230
|
+
api_key=Secret.from_token("test_api_key"),
|
|
231
|
+
store_full_path=store_full_path,
|
|
232
|
+
)
|
|
233
|
+
converter.client = MagicMock()
|
|
234
|
+
converter.client.begin_analyze_document.return_value.result.return_value = make_mock_analyze_result()
|
|
235
|
+
|
|
236
|
+
result = converter.run(sources=[str(pdf_path)])
|
|
237
|
+
|
|
238
|
+
expected_path = str(pdf_path) if store_full_path else "sample_pdf_1.pdf"
|
|
239
|
+
assert result["documents"][0].meta["file_path"] == expected_path
|
|
240
|
+
|
|
241
|
+
def test_run_applies_single_meta_dict_to_all_documents(self, warmed_converter):
|
|
242
|
+
sources = [ByteStream.from_string("one"), ByteStream.from_string("two")]
|
|
243
|
+
|
|
244
|
+
result = warmed_converter.run(sources=sources, meta={"shared": "value"})
|
|
245
|
+
|
|
246
|
+
assert all(doc.meta["shared"] == "value" for doc in result["documents"])
|
|
247
|
+
|
|
248
|
+
def test_run_applies_meta_list_pairwise(self, warmed_converter):
|
|
249
|
+
sources = [ByteStream.from_string("a"), ByteStream.from_string("b")]
|
|
250
|
+
|
|
251
|
+
result = warmed_converter.run(sources=sources, meta=[{"index": 0}, {"index": 1}])
|
|
252
|
+
|
|
253
|
+
assert result["documents"][0].meta["index"] == 0
|
|
254
|
+
assert result["documents"][1].meta["index"] == 1
|
|
255
|
+
|
|
256
|
+
def test_run_skips_unreadable_source(self, warmed_converter):
|
|
257
|
+
result = warmed_converter.run(sources=["/nonexistent/missing.pdf"])
|
|
258
|
+
|
|
259
|
+
assert result["documents"] == []
|
|
260
|
+
assert result["raw_azure_response"] == []
|
|
261
|
+
|
|
262
|
+
def test_run_skips_source_when_azure_analysis_fails(self, warmed_converter):
|
|
263
|
+
warmed_converter.client.begin_analyze_document.side_effect = RuntimeError("Azure failure")
|
|
264
|
+
|
|
265
|
+
result = warmed_converter.run(sources=[ByteStream.from_string("data")])
|
|
266
|
+
|
|
267
|
+
assert result["documents"] == []
|
|
268
|
+
assert result["raw_azure_response"] == []
|
|
269
|
+
|
|
270
|
+
def test_run_uses_empty_string_when_result_content_is_none(self, warmed_converter):
|
|
271
|
+
warmed_converter.client.begin_analyze_document.return_value.result.return_value = make_mock_analyze_result(
|
|
272
|
+
content=None
|
|
273
|
+
)
|
|
274
|
+
|
|
275
|
+
result = warmed_converter.run(sources=[ByteStream.from_string("data")])
|
|
276
|
+
|
|
277
|
+
assert result["documents"][0].content == ""
|
|
278
|
+
|
|
279
|
+
def test_run_sets_page_count_zero_when_result_has_no_pages(self, warmed_converter):
|
|
280
|
+
warmed_converter.client.begin_analyze_document.return_value.result.return_value = make_mock_analyze_result(
|
|
281
|
+
pages=None
|
|
282
|
+
)
|
|
283
|
+
|
|
284
|
+
result = warmed_converter.run(sources=[ByteStream.from_string("data")])
|
|
285
|
+
|
|
286
|
+
assert result["documents"][0].meta["page_count"] == 0
|
|
98
287
|
|
|
99
288
|
|
|
100
289
|
@pytest.mark.integration
|
|
@@ -117,7 +306,7 @@ class TestAzureDocumentIntelligenceConverterIntegration:
|
|
|
117
306
|
assert "documents" in results
|
|
118
307
|
assert len(results["documents"]) == 1
|
|
119
308
|
assert len(results["documents"][0].content) > 0
|
|
120
|
-
assert results["documents"][0].meta["model_id"] == "prebuilt-
|
|
309
|
+
assert results["documents"][0].meta["model_id"] == "prebuilt-layout"
|
|
121
310
|
|
|
122
311
|
@pytest.mark.skipif(not os.environ.get("AZURE_DI_ENDPOINT"), reason="Azure endpoint not available")
|
|
123
312
|
@pytest.mark.skipif(not os.environ.get("AZURE_DI_API_KEY"), reason="Azure credentials not available")
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
loaders:
|
|
2
|
-
- ignore_when_discovered:
|
|
3
|
-
- __init__
|
|
4
|
-
modules:
|
|
5
|
-
- haystack_integrations.components.converters.azure_doc_intelligence.converter
|
|
6
|
-
search_path:
|
|
7
|
-
- ../src
|
|
8
|
-
type: haystack_pydoc_tools.loaders.CustomPythonLoader
|
|
9
|
-
processors:
|
|
10
|
-
- do_not_filter_modules: false
|
|
11
|
-
documented_only: true
|
|
12
|
-
expression: null
|
|
13
|
-
skip_empty_modules: true
|
|
14
|
-
type: filter
|
|
15
|
-
- type: smart
|
|
16
|
-
- type: crossref
|
|
17
|
-
renderer:
|
|
18
|
-
description: Azure Document Intelligence integration for Haystack
|
|
19
|
-
id: integrations-azure_doc_intelligence
|
|
20
|
-
markdown:
|
|
21
|
-
add_member_class_prefix: false
|
|
22
|
-
add_method_class_prefix: true
|
|
23
|
-
classdef_code_block: false
|
|
24
|
-
descriptive_class_title: false
|
|
25
|
-
descriptive_module_title: true
|
|
26
|
-
filename: azure_doc_intelligence.md
|
|
27
|
-
title: Azure Document Intelligence
|
|
28
|
-
type: haystack_pydoc_tools.renderers.DocusaurusRenderer
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|