Merge pull request #232 from ggozad/feat/page-generation-option
Control page image generation
This commit is contained in:
commit
d602ad48bb
10 changed files with 86803 additions and 5 deletions
|
|
@ -1,6 +1,14 @@
|
|||
# Changelog
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
|
||||
- **Page Image Generation Control**: New `generate_page_images` option in `ConversionOptions` to control PDF page image extraction
|
||||
- `generate_page_images: bool = True` - Enable/disable rendered page images (used by `visualize_chunk()`)
|
||||
- Works with both `docling-local` and `docling-serve` converters
|
||||
- For `docling-serve`, maps to `image_export_mode` API parameter (`embedded`/`placeholder`)
|
||||
- Note: `generate_picture_images` (embedded figures/diagrams) works with local converter but has limited support in docling-serve
|
||||
|
||||
## [0.26.2] - 2026-01-13
|
||||
|
||||
### Changed
|
||||
|
|
|
|||
|
|
@ -35,7 +35,8 @@ processing:
|
|||
|
||||
# Image settings
|
||||
images_scale: 2.0 # Image scale factor
|
||||
generate_picture_images: false # Include embedded images in output
|
||||
generate_page_images: true # Include rendered page images (for visualize_chunk)
|
||||
generate_picture_images: false # Include embedded figure/diagram images
|
||||
|
||||
# VLM picture description (optional)
|
||||
picture_description:
|
||||
|
|
@ -82,12 +83,16 @@ conversion_options:
|
|||
```yaml
|
||||
conversion_options:
|
||||
images_scale: 2.0 # Image resolution scale factor
|
||||
generate_picture_images: false # Include embedded images in output
|
||||
generate_page_images: true # Include rendered page images
|
||||
generate_picture_images: false # Include embedded figure/diagram images
|
||||
```
|
||||
|
||||
- **images_scale**: Scale factor for extracted images. Higher values = better quality but larger size. Typical range: 1.0-3.0.
|
||||
- **generate_page_images**: When `true` (default), rendered images of each PDF page are included in the document. Required for `visualize_chunk()` to show visual grounding. When `false`, page images are excluded to reduce document size.
|
||||
- **generate_picture_images**: When `true`, embedded images (figures, diagrams) are included as base64-encoded data in the document. When `false` (default), images are excluded to reduce chunk size and avoid context bloat.
|
||||
|
||||
**Note:** With `docling-serve`, `generate_picture_images` has limited support - picture image data may not be returned in the JSON response. Page images work correctly with both local and remote converters.
|
||||
|
||||
#### Picture Description (VLM)
|
||||
|
||||
Use a Vision Language Model (VLM) to automatically describe images in documents. Descriptions become searchable text, improving RAG retrieval for visual content.
|
||||
|
|
|
|||
|
|
@ -125,6 +125,7 @@ class ConversionOptions(BaseModel):
|
|||
|
||||
# Image options
|
||||
images_scale: float = 2.0
|
||||
generate_page_images: bool = True
|
||||
generate_picture_images: bool = False
|
||||
|
||||
# VLM picture description
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ class DoclingLocalConverter(DocumentConverter):
|
|||
do_ocr=opts.do_ocr,
|
||||
do_table_structure=opts.do_table_structure,
|
||||
images_scale=opts.images_scale,
|
||||
generate_page_images=True,
|
||||
generate_page_images=opts.generate_page_images,
|
||||
generate_picture_images=opts.generate_picture_images or pic_desc.enabled,
|
||||
table_structure_options=TableStructureOptions(
|
||||
do_cell_matching=opts.table_cell_matching,
|
||||
|
|
|
|||
|
|
@ -93,7 +93,10 @@ class DoclingServeConverter(DocumentConverter):
|
|||
"table_mode": opts.table_mode,
|
||||
"table_cell_matching": str(opts.table_cell_matching).lower(),
|
||||
"images_scale": str(opts.images_scale),
|
||||
"generate_picture_images": str(
|
||||
"image_export_mode": "embedded"
|
||||
if opts.generate_page_images
|
||||
else "placeholder",
|
||||
"include_images": str(
|
||||
opts.generate_picture_images or pic_desc.enabled
|
||||
).lower(),
|
||||
"do_picture_description": str(pic_desc.enabled).lower(),
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
|
|
@ -304,11 +304,15 @@ class TestDoclingLocalConverter:
|
|||
config.processing.conversion_options.do_ocr = False
|
||||
config.processing.conversion_options.table_mode = "fast"
|
||||
config.processing.conversion_options.images_scale = 3.0
|
||||
config.processing.conversion_options.generate_page_images = False
|
||||
converter = DoclingLocalConverter(config)
|
||||
|
||||
assert converter.config.processing.conversion_options.do_ocr is False
|
||||
assert converter.config.processing.conversion_options.table_mode == "fast"
|
||||
assert converter.config.processing.conversion_options.images_scale == 3.0
|
||||
assert (
|
||||
converter.config.processing.conversion_options.generate_page_images is False
|
||||
)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_convert_pdf_without_picture_images(self, config):
|
||||
|
|
@ -349,6 +353,44 @@ class TestDoclingLocalConverter:
|
|||
"Pictures should have image data when generate_picture_images=True"
|
||||
)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_convert_pdf_without_page_images(self, config):
|
||||
"""Test PDF conversion excludes page images when disabled."""
|
||||
pdf_path = Path("tests/data/doclaynet.pdf")
|
||||
if not pdf_path.exists():
|
||||
pytest.skip("doclaynet.pdf not found")
|
||||
|
||||
config.processing.conversion_options.generate_page_images = False
|
||||
converter = DoclingLocalConverter(config)
|
||||
|
||||
doc = await converter.convert_file(pdf_path)
|
||||
assert isinstance(doc, DoclingDocument)
|
||||
|
||||
# Check that pages don't have image data
|
||||
for page in doc.pages.values():
|
||||
assert page.image is None, (
|
||||
"Pages should not have image data when generate_page_images=False"
|
||||
)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_convert_pdf_with_page_images(self, config):
|
||||
"""Test PDF conversion includes page images when enabled."""
|
||||
pdf_path = Path("tests/data/doclaynet.pdf")
|
||||
if not pdf_path.exists():
|
||||
pytest.skip("doclaynet.pdf not found")
|
||||
|
||||
config.processing.conversion_options.generate_page_images = True
|
||||
converter = DoclingLocalConverter(config)
|
||||
|
||||
doc = await converter.convert_file(pdf_path)
|
||||
assert isinstance(doc, DoclingDocument)
|
||||
|
||||
# Check that pages have image data
|
||||
pages_with_images = [p for p in doc.pages.values() if p.image is not None]
|
||||
assert len(pages_with_images) > 0, (
|
||||
"Pages should have image data when generate_page_images=True"
|
||||
)
|
||||
|
||||
def test_get_vlm_api_url_with_ollama(self, config):
|
||||
"""Test VLM API URL construction for Ollama provider."""
|
||||
converter = DoclingLocalConverter(config)
|
||||
|
|
@ -542,6 +584,7 @@ class TestDoclingServeConverter:
|
|||
config.processing.conversion_options.table_cell_matching = False
|
||||
config.processing.conversion_options.do_table_structure = False
|
||||
config.processing.conversion_options.images_scale = 3.0
|
||||
config.processing.conversion_options.generate_picture_images = False
|
||||
converter = DoclingServeConverter(config)
|
||||
|
||||
doc_json = create_mock_docling_document("test")
|
||||
|
|
@ -567,6 +610,8 @@ class TestDoclingServeConverter:
|
|||
assert data["table_cell_matching"] == "false"
|
||||
assert data["do_table_structure"] == "false"
|
||||
assert data["images_scale"] == "3.0"
|
||||
assert data["include_images"] == "false"
|
||||
assert data["image_export_mode"] == "embedded"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_convert_text_connection_error(self, converter):
|
||||
|
|
@ -769,7 +814,7 @@ class TestDoclingServeConverterPictureDescription:
|
|||
data = call_kwargs["data"]
|
||||
|
||||
assert data["do_picture_description"] == "true"
|
||||
assert data["generate_picture_images"] == "true"
|
||||
assert data["include_images"] == "true"
|
||||
assert "picture_description_api" in data
|
||||
|
||||
api_config = json.loads(data["picture_description_api"])
|
||||
|
|
@ -884,3 +929,89 @@ class TestDoclingServeConverterIntegration:
|
|||
assert pictures_with_descriptions, (
|
||||
"At least one picture should have a VLM description"
|
||||
)
|
||||
|
||||
@pytest.mark.vcr()
|
||||
@pytest.mark.asyncio
|
||||
async def test_convert_pdf_without_page_images(self, config):
|
||||
"""Test PDF conversion excludes page images when disabled."""
|
||||
pdf_path = Path("tests/data/doclaynet.pdf")
|
||||
if not pdf_path.exists():
|
||||
pytest.skip("doclaynet.pdf not found")
|
||||
|
||||
config.processing.conversion_options.generate_page_images = False
|
||||
converter = DoclingServeConverter(config)
|
||||
|
||||
doc = await converter.convert_file(pdf_path)
|
||||
assert isinstance(doc, DoclingDocument)
|
||||
|
||||
# Check that pages don't have image data
|
||||
for page in doc.pages.values():
|
||||
assert page.image is None, (
|
||||
"Pages should not have image data when generate_page_images=False"
|
||||
)
|
||||
|
||||
@pytest.mark.vcr()
|
||||
@pytest.mark.asyncio
|
||||
async def test_convert_pdf_with_page_images(self, config):
|
||||
"""Test PDF conversion includes page images when enabled."""
|
||||
pdf_path = Path("tests/data/doclaynet.pdf")
|
||||
if not pdf_path.exists():
|
||||
pytest.skip("doclaynet.pdf not found")
|
||||
|
||||
config.processing.conversion_options.generate_page_images = True
|
||||
converter = DoclingServeConverter(config)
|
||||
|
||||
doc = await converter.convert_file(pdf_path)
|
||||
assert isinstance(doc, DoclingDocument)
|
||||
|
||||
# Check that pages have image data
|
||||
pages_with_images = [p for p in doc.pages.values() if p.image is not None]
|
||||
assert len(pages_with_images) > 0, (
|
||||
"Pages should have image data when generate_page_images=True"
|
||||
)
|
||||
|
||||
@pytest.mark.vcr()
|
||||
@pytest.mark.asyncio
|
||||
async def test_convert_pdf_without_picture_images(self, config):
|
||||
"""Test PDF conversion excludes picture images when disabled."""
|
||||
pdf_path = Path("tests/data/doclaynet.pdf")
|
||||
if not pdf_path.exists():
|
||||
pytest.skip("doclaynet.pdf not found")
|
||||
|
||||
config.processing.conversion_options.generate_picture_images = False
|
||||
converter = DoclingServeConverter(config)
|
||||
|
||||
doc = await converter.convert_file(pdf_path)
|
||||
assert isinstance(doc, DoclingDocument)
|
||||
|
||||
# Check that pictures don't have image data
|
||||
for picture in doc.pictures:
|
||||
assert picture.image is None, (
|
||||
"Pictures should not have image data when generate_picture_images=False"
|
||||
)
|
||||
|
||||
@pytest.mark.xfail(
|
||||
reason="docling-serve does not return picture image data in JSON response "
|
||||
"even with include_images=true. Page images work, but extracted picture/figure "
|
||||
"images are not included. This is a docling-serve limitation."
|
||||
)
|
||||
@pytest.mark.vcr()
|
||||
@pytest.mark.asyncio
|
||||
async def test_convert_pdf_with_picture_images(self, config):
|
||||
"""Test PDF conversion includes picture images when enabled."""
|
||||
pdf_path = Path("tests/data/doclaynet.pdf")
|
||||
if not pdf_path.exists():
|
||||
pytest.skip("doclaynet.pdf not found")
|
||||
|
||||
config.processing.conversion_options.generate_picture_images = True
|
||||
converter = DoclingServeConverter(config)
|
||||
|
||||
doc = await converter.convert_file(pdf_path)
|
||||
assert isinstance(doc, DoclingDocument)
|
||||
|
||||
# Check that at least some pictures have image data
|
||||
pictures_with_images = [p for p in doc.pictures if p.image is not None]
|
||||
if doc.pictures:
|
||||
assert len(pictures_with_images) > 0, (
|
||||
"Pictures should have image data when generate_picture_images=True"
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in a new issue