Docling-serve cassettes

This commit is contained in:
Yiorgis Gozadinos 2025-12-26 18:59:46 +02:00
parent c3a3b4a5b4
commit 0da8ba97c4
No known key found for this signature in database
5 changed files with 22031 additions and 38 deletions

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,100 @@
interactions:
- request:
body: "--4379b32700c5b8d95062406eb16d4651\r\nContent-Disposition: form-data; name=\"to_formats\"\r\n\r\njson\r\n--4379b32700c5b8d95062406eb16d4651\r\nContent-Disposition:
form-data; name=\"do_ocr\"\r\n\r\ntrue\r\n--4379b32700c5b8d95062406eb16d4651\r\nContent-Disposition: form-data; name=\"force_ocr\"\r\n\r\nfalse\r\n--4379b32700c5b8d95062406eb16d4651\r\nContent-Disposition:
form-data; name=\"do_table_structure\"\r\n\r\ntrue\r\n--4379b32700c5b8d95062406eb16d4651\r\nContent-Disposition: form-data;
name=\"table_mode\"\r\n\r\naccurate\r\n--4379b32700c5b8d95062406eb16d4651\r\nContent-Disposition: form-data; name=\"table_cell_matching\"\r\n\r\ntrue\r\n--4379b32700c5b8d95062406eb16d4651\r\nContent-Disposition:
form-data; name=\"images_scale\"\r\n\r\n2.0\r\n--4379b32700c5b8d95062406eb16d4651\r\nContent-Disposition: form-data;
name=\"generate_picture_images\"\r\n\r\nfalse\r\n--4379b32700c5b8d95062406eb16d4651\r\nContent-Disposition: form-data;
name=\"files\"; filename=\"tmpeojgnbxt.md\"\r\nContent-Type: text/markdown\r\n\r\n```python\ndef test():\n return
42\n```\r\n--4379b32700c5b8d95062406eb16d4651--\r\n"
headers:
accept:
- '*/*'
accept-encoding:
- gzip, deflate, zstd
connection:
- keep-alive
content-length:
- '1011'
content-type:
- multipart/form-data; boundary=4379b32700c5b8d95062406eb16d4651
host:
- localhost:5001
method: POST
uri: http://localhost:5001/v1/convert/file
response:
headers:
content-length:
- '1114'
content-type:
- application/json
parsed_body:
document:
doctags_content: null
filename: tmpeojgnbxt.md
html_content: null
json_content:
body:
children:
- $ref: '#/texts/0'
content_layer: body
label: unspecified
meta: null
name: _root_
parent: null
self_ref: '#/body'
form_items: []
furniture:
children: []
content_layer: furniture
label: unspecified
meta: null
name: _root_
parent: null
self_ref: '#/furniture'
groups: []
key_value_items: []
name: tmpeojgnbxt
origin:
binary_hash: 9008975733065065710
filename: tmpeojgnbxt.md
mimetype: text/markdown
uri: null
pages: {}
pictures: []
schema_name: DoclingDocument
tables: []
texts:
- captions: []
children: []
code_language: unknown
content_layer: body
footnotes: []
formatting: null
hyperlink: null
image: null
label: code
meta: null
orig: |-
def test():
return 42
parent:
$ref: '#/body'
prov: []
references: []
self_ref: '#/texts/0'
text: |-
def test():
return 42
version: 1.8.0
md_content: null
text_content: null
errors: []
processing_time: 0.0017275830000471615
status: success
timings: {}
status:
code: 200
message: OK
version: 1

View file

@ -0,0 +1,103 @@
interactions:
- request:
body: "--798e57b119ed24827326455c645311ae\r\nContent-Disposition: form-data; name=\"to_formats\"\r\n\r\njson\r\n--798e57b119ed24827326455c645311ae\r\nContent-Disposition:
form-data; name=\"do_ocr\"\r\n\r\ntrue\r\n--798e57b119ed24827326455c645311ae\r\nContent-Disposition: form-data; name=\"force_ocr\"\r\n\r\nfalse\r\n--798e57b119ed24827326455c645311ae\r\nContent-Disposition:
form-data; name=\"do_table_structure\"\r\n\r\ntrue\r\n--798e57b119ed24827326455c645311ae\r\nContent-Disposition: form-data;
name=\"table_mode\"\r\n\r\naccurate\r\n--798e57b119ed24827326455c645311ae\r\nContent-Disposition: form-data; name=\"table_cell_matching\"\r\n\r\ntrue\r\n--798e57b119ed24827326455c645311ae\r\nContent-Disposition:
form-data; name=\"images_scale\"\r\n\r\n2.0\r\n--798e57b119ed24827326455c645311ae\r\nContent-Disposition: form-data;
name=\"generate_picture_images\"\r\n\r\nfalse\r\n--798e57b119ed24827326455c645311ae\r\nContent-Disposition: form-data;
name=\"files\"; filename=\"content.md\"\r\nContent-Type: text/markdown\r\n\r\n# Test Document\n\nThis is a test.\r\n--798e57b119ed24827326455c645311ae--\r\n"
headers:
accept:
- '*/*'
accept-encoding:
- gzip, deflate, zstd
connection:
- keep-alive
content-length:
- '1000'
content-type:
- multipart/form-data; boundary=798e57b119ed24827326455c645311ae
host:
- localhost:5001
method: POST
uri: http://localhost:5001/v1/convert/file
response:
headers:
content-length:
- '1225'
content-type:
- application/json
parsed_body:
document:
doctags_content: null
filename: content.md
html_content: null
json_content:
body:
children:
- $ref: '#/texts/0'
- $ref: '#/texts/1'
content_layer: body
label: unspecified
meta: null
name: _root_
parent: null
self_ref: '#/body'
form_items: []
furniture:
children: []
content_layer: furniture
label: unspecified
meta: null
name: _root_
parent: null
self_ref: '#/furniture'
groups: []
key_value_items: []
name: content
origin:
binary_hash: 18149311266811077188
filename: content.md
mimetype: text/markdown
uri: null
pages: {}
pictures: []
schema_name: DoclingDocument
tables: []
texts:
- children: []
content_layer: body
formatting: null
hyperlink: null
label: title
meta: null
orig: Test Document
parent:
$ref: '#/body'
prov: []
self_ref: '#/texts/0'
text: Test Document
- children: []
content_layer: body
formatting: null
hyperlink: null
label: text
meta: null
orig: This is a test.
parent:
$ref: '#/body'
prov: []
self_ref: '#/texts/1'
text: This is a test.
version: 1.8.0
md_content: null
text_content: null
errors: []
processing_time: 0.002875374999803171
status: success
timings: {}
status:
code: 200
message: OK
version: 1

View file

@ -1,3 +1,4 @@
from pathlib import Path
from unittest.mock import AsyncMock, Mock, patch from unittest.mock import AsyncMock, Mock, patch
import pytest import pytest
@ -11,6 +12,11 @@ from haiku.rag.config import AppConfig, Config
from haiku.rag.converters import get_converter from haiku.rag.converters import get_converter
@pytest.fixture(scope="module")
def vcr_cassette_dir():
return str(Path(__file__).parent / "cassettes" / "test_chunker")
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_local_chunker(qa_corpus: Dataset): async def test_local_chunker(qa_corpus: Dataset):
"""Test DoclingLocalChunker with real document.""" """Test DoclingLocalChunker with real document."""
@ -479,28 +485,11 @@ This is content.
assert meta1.page_numbers == [1, 2] assert meta1.page_numbers == [1, 2]
def is_docling_serve_available(base_url: str = "http://localhost:5001") -> bool: @pytest.mark.vcr()
"""Check if docling-serve is running and accessible."""
import requests
try:
response = requests.get(f"{base_url}/health", timeout=2)
return response.status_code == 200
except Exception:
return False
@pytest.mark.skipif(
not is_docling_serve_available(),
reason="docling-serve not available at http://localhost:5001",
)
@pytest.mark.integration
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_local_and_serve_chunkers_produce_same_output(): async def test_local_and_serve_chunkers_produce_same_output():
"""Test that local and serve chunkers produce identical output for the same document. """Test that local and serve chunkers produce identical output for the same document.
This integration test requires docling-serve to be running on localhost:5001.
Note: Labels are resolved from the DoclingDocument since docling-serve API Note: Labels are resolved from the DoclingDocument since docling-serve API
only returns ref strings, not labels. See: only returns ref strings, not labels. See:
https://github.com/docling-project/docling-serve/issues/448 https://github.com/docling-project/docling-serve/issues/448

View file

@ -6,7 +6,6 @@ from unittest.mock import AsyncMock, Mock, patch
import httpx import httpx
import pytest import pytest
import requests
from docling_core.types.doc.document import DoclingDocument from docling_core.types.doc.document import DoclingDocument
from haiku.rag.config import AppConfig from haiku.rag.config import AppConfig
@ -16,13 +15,9 @@ from haiku.rag.converters.docling_serve import DoclingServeConverter
from haiku.rag.converters.text_utils import TextFileHandler from haiku.rag.converters.text_utils import TextFileHandler
def is_docling_serve_available(base_url: str = "http://localhost:5001") -> bool: @pytest.fixture(scope="module")
"""Check if docling-serve is running and accessible.""" def vcr_cassette_dir():
try: return str(Path(__file__).parent / "cassettes" / "test_converters")
response = requests.get(f"{base_url}/health", timeout=2)
return response.status_code == 200
except Exception:
return False
def create_mock_docling_document_json(name: str = "test") -> dict: def create_mock_docling_document_json(name: str = "test") -> dict:
@ -560,13 +555,8 @@ class TestDoclingServeConverter:
assert "files" in call_kwargs assert "files" in call_kwargs
@pytest.mark.integration
@pytest.mark.skipif(
not is_docling_serve_available(),
reason="docling-serve not available at http://localhost:5001",
)
class TestDoclingServeConverterIntegration: class TestDoclingServeConverterIntegration:
"""Integration tests with real docling-serve (requires service running).""" """Integration tests with real docling-serve recorded via VCR."""
@pytest.fixture @pytest.fixture
def config(self): def config(self):
@ -580,22 +570,23 @@ class TestDoclingServeConverterIntegration:
"""Create converter for integration tests.""" """Create converter for integration tests."""
return DoclingServeConverter(config) return DoclingServeConverter(config)
@pytest.mark.vcr()
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_convert_text_real_service(self, converter): async def test_convert_text_real_service(self, converter):
"""Test text conversion with real docling-serve (integration).""" """Test text conversion with real docling-serve."""
doc = await converter.convert_text("# Test Document\n\nThis is a test.") doc = await converter.convert_text("# Test Document\n\nThis is a test.")
assert isinstance(doc, DoclingDocument) assert isinstance(doc, DoclingDocument)
assert doc.version == "1.8.0"
@pytest.mark.vcr()
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_convert_code_file_real_service(self, converter): async def test_convert_code_file_real_service(self, converter):
"""Test code file conversion with real docling-serve (integration).""" """Test code file conversion with real docling-serve."""
code = "def test():\n return 42" code = "def test():\n return 42"
with tempfile.NamedTemporaryFile(mode="w", suffix=".py") as f: with tempfile.NamedTemporaryFile(mode="w", suffix=".py", delete=False) as f:
f.write(code) f.write(code)
f.flush()
temp_path = Path(f.name) temp_path = Path(f.name)
doc = await converter.convert_file(temp_path) doc = await converter.convert_file(temp_path)
temp_path.unlink()
assert isinstance(doc, DoclingDocument) assert isinstance(doc, DoclingDocument)
result = doc.export_to_markdown() result = doc.export_to_markdown()