Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions haystack/components/converters/pptx.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@

with LazyImport("Run 'pip install python-pptx'") as pptx_import:
from pptx import Presentation
from pptx.oxml.text import CT_RegularTextRun, CT_TextField
from pptx.shapes.autoshape import Shape
from pptx.shapes.base import BaseShape
from pptx.shapes.graphfrm import GraphicFrame
from pptx.shapes.group import GroupShape
from pptx.table import Table
from pptx.text.text import _Paragraph
from pptx.text.text import _Paragraph, _Run


logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -137,7 +138,13 @@ def _process_paragraph(self, paragraph: "_Paragraph") -> str:
if self.link_format == "none":
return paragraph.text
parts = []
for run in paragraph.runs:
for child in paragraph._p.iterchildren():
if isinstance(child, CT_TextField):
parts.append(child.text)
continue
if not isinstance(child, CT_RegularTextRun):
continue
run = _Run(child, paragraph)
if run.hyperlink and run.hyperlink.address:
if self.link_format == "markdown":
parts.append(f"[{run.text}]({run.hyperlink.address})")
Expand Down
7 changes: 7 additions & 0 deletions releasenotes/notes/pptx-field-text-30f1b392c307906b.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
fixes:
- |
``PPTXToDocument`` now keeps the text of a field, such as a slide number or a date,
when ``link_format`` is ``"markdown"`` or ``"plain"``. These formats read only the
runs of a paragraph, so the text of a field between runs was dropped, for example
the ``3`` in ``Slide 3``. The default ``link_format="none"`` already kept field text.
36 changes: 36 additions & 0 deletions test/components/converters/test_pptx_to_document.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,16 @@
#
# SPDX-License-Identifier: Apache-2.0

import io
import logging
import os
from pathlib import Path

import pytest
from pptx import Presentation
from pptx.oxml import parse_xml
from pptx.oxml.ns import nsdecls
from pptx.util import Inches

from haystack.components.converters.pptx import PPTXToDocument
from haystack.dataclasses import ByteStream
Expand Down Expand Up @@ -124,6 +129,37 @@ def test_no_link_extraction(self, test_files_path):
assert "https://example.com" not in content
assert "Example" in content

@pytest.mark.parametrize(
"link_format,expected",
[
("none", "Slide 3 of the deck"),
("markdown", "Slide 3 of [the deck](https://example.com)"),
("plain", "Slide 3 of the deck (https://example.com)"),
],
)
def test_run_keeps_field_text_with_every_link_format(self, link_format, expected):
# A slide-number field (`a:fld`) sits between the runs of the paragraph
presentation = Presentation()
slide = presentation.slides.add_slide(presentation.slide_layouts[6])
paragraph = slide.shapes.add_textbox(Inches(1), Inches(1), Inches(5), Inches(1)).text_frame.paragraphs[0]
paragraph.add_run().text = "Slide "
paragraph._p.append(
parse_xml(
f'<a:fld {nsdecls("a")} id="{{B6F15528-21DE-4FAA-801E-634DDDAF4B2B}}" type="slidenum">'
"<a:t>3</a:t></a:fld>"
)
)
paragraph.add_run().text = " of "
link = paragraph.add_run()
link.text = "the deck"
link.hyperlink.address = "https://example.com"
buffer = io.BytesIO()
presentation.save(buffer)

documents = PPTXToDocument(link_format=link_format).run(sources=[ByteStream(buffer.getvalue())])["documents"]

assert documents[0].content == expected

def test_run_reads_nested_groups_and_table_with_links(self, test_files_path):
# The slide includes nested text groups, a grouped table, and an empty decorative shape.
converter = PPTXToDocument(link_format="markdown")
Expand Down
Loading