#2674·agentscope

[Bug]: PPTParser silently drops text and images inside grouped shapes

Author: iluv7Created Sep 17, 2026Updated Sep 17, 2026

Prerequisites

  • I searched existing issues, pull requests, and discussions and did not find this bug reported.
  • This is a bug, not a usage question.

Background / Description

PPTParser._parse_slide walks slide.shapes, which only iterates the direct children of the slide's spTree (src/agentscope/rag/_parser/_ppt.py:263). A GroupShape has no has_text_frame and no has_table, so the loop skips it entirely — text frames, tables, and pictures nested inside the group are never visited.

Grouped shapes are extremely common in real decks (templates group text boxes routinely), so this is a silent content loss: the parse succeeds, the text inside the group simply never reaches the index. Pictures inside groups are also dropped even with include_image=True.

Steps to Reproduce

From a repository checkout, save the following as reproduce_ppt_group.py and run PYTHONPATH=src python reproduce_ppt_group.py. It builds a deck in memory; no files, network, or credentials are needed.

python
import asyncio
import base64
import io

from pptx import Presentation
from pptx.util import Inches

from agentscope.rag import PPTParser

# 1x1 transparent PNG
PNG_1X1 = base64.b64decode(
    "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR4nGNgYGBgAAAABQAB"
    "h6FO1AAAAABJRU5ErkJggg=="
)


async def main():
    prs = Presentation()
    slide = prs.slides.add_slide(prs.slide_layouts[6])

    slide.shapes.add_textbox(Inches(1), Inches(1), Inches(4), Inches(1)).text_frame.text = (
        "UNGROUPED TEXT"
    )

    group = slide.shapes.add_group_shape()
    group.shapes.add_textbox(Inches(1), Inches(2), Inches(4), Inches(1)).text_frame.text = (
        "GROUPED TEXT"
    )
    group.shapes.add_picture(io.BytesIO(PNG_1X1), Inches(1), Inches(3), Inches(1), Inches(1))

    buffer = io.BytesIO()
    prs.save(buffer)

    sections = await PPTParser(include_image=True).parse(buffer.getvalue(), "grouped.pptx")
    text = "\n".join(
        s.content.text for s in sections if hasattr(s.content, "text")
    )
    images = sum(1 for s in sections if not hasattr(s.content, "text"))
    print("extracted text:", repr(text))
    print("image sections:", images)


asyncio.run(main())

Actual Output

extracted text: '<slide index=1>\nUNGROUPED TEXT\n</slide>'
image sections: 0

GROUPED TEXT is missing from the extracted text, and the picture inside the group produces no image section.

Expected Output

extracted text: '<slide index=1>\nUNGROUPED TEXT\nGROUPED TEXT\n</slide>'
image sections: 1

Environment

  • AgentScope: 2.0.8, reproduced on main @ 0727cbf9
  • Python: 3.13.3
  • python-pptx: 1.0.2

Root Cause / Proposed Fix

_parse_slide iterates only the top-level shapes and never descends into GroupShape children (grpSp element). The fix is to walk shapes recursively: when a shape exposes .shapes (a GroupShape), apply the same text-frame / table / picture dispatch to its children in document order, so grouped text, grouped tables, and grouped pictures are extracted exactly like top-level ones. This mirrors the "sweep descendants" fix family as in #2662, and needs a regression test with an in-memory grouped deck (text + image) like the reproduction above.

Source: agentscope-ai/agentscope