Skip to content

How It Works

Daniel Boles edited this page Nov 6, 2026 · 1 revision

How It Works

SlideBridge divides a hard problem into five small ones and puts a file between each pair. A deck is read for its words, rendered for its appearance, reconciled so that the words follow a sensible order, assembled into a Word table pack, and audited, and because every stage reads and writes plain files under one work folder, any stage can be run again alone without repeating the others.

Architecture

flowchart LR
    P["deck.pptx"] --> E["extract<br/>python-pptx"]
    P --> R["render<br/>LibreOffice to PDF,<br/>PyMuPDF to PNG"]
    E --> J["work/json/deck.json"]
    R --> I["work/pdf and<br/>work/images/deck/slide_001.png"]
    J --> C["reconcile<br/>reading order, fragments,<br/>confidence, warnings"]
    I --> C
    C --> M["work/reconciled/manifest.json"]
    M --> B["build-docx<br/>python-docx"]
    I --> B
    M --> A["audit<br/>slides.csv, warnings.csv,<br/>run_report.json"]
    B --> D["output/review_pack.docx"]
    D --> L["align<br/>with an edited DOCX"]
    L --> D2["aligned.docx"]
Loading

The manifest is the hinge. It is a pydantic model, RunManifest, serialized to JSON and checked against a JSON Schema by slidebridge validate, and it carries one SlideRecord per slide with its text blocks, table count, notes, confidence, warnings, and the path of its image.

The main parts

Package Role
extract Opens the deck, classifies each shape (title, body, footer, table, picture, group, other), detects the slide title by a three-tier fallback, and pulls tables and speaker notes
render Converts the deck to PDF with headless LibreOffice, with two attempts and a two-second wait, then renders one PNG per page with PyMuPDF and validates the result
reconcile Puts text blocks in reading order, merges short fragments, scores confidence, and attaches warning flags
build Writes the DOCX: styles and margins, a heading, a metadata line, the image, an optional warning block, and the four-column table for each slide
audit Writes slides.csv, warnings.csv, and run_report.json from the manifest
align Reads a review pack and an edited document, splits the edited text into segments, and matches each original row to a segment
orchestration The run pipeline, one function per command, and the retry helper
models, config, constants Typed records, the YAML configuration, and the named numeric constants
gui A Tkinter window over the same orchestration

The decisions inside the stages

Three small algorithms carry most of the behavior, and each is a heuristic with its numbers written down in constants.py.

Title detection tries a native title placeholder first, then a text block that the shape classifier marked as a title, then the first non-empty block, truncated at 120 characters, and records which tier answered in title_source. A slide on which all three fail gets the source fallback, which later costs it confidence.

Reading order puts the title first and footers last. The remaining blocks are sorted by their top edge and grouped into rows: a block belongs to the current row when its top is within 457,200 EMU, half an inch, of the row's first block, and rows are then read left to right. Tables are atomic. Body blocks shorter than 20 characters merge into the block that follows them.

Confidence starts at 1.0 and loses a fixed penalty for each of these conditions: no detected title (0.10), no text on a slide that has shapes (0.35), eight or more blocks under 15 characters (0.10), a grouped shape (0.15), and more than five shapes with fewer than 50 characters of text (0.20). The score is floored at 0, and a slide below 0.60 receives the flag confidence_below_threshold. The other flags are no_detected_title, image_without_text, grouped_shapes_present, table_detected, notes_present_not_extracted, and possible_missing_chart_labels.

One slide, followed through

Slide 3 of the sample deck carries a title placeholder reading "Deck A slide 3", a body placeholder with two paragraphs, and a 2 by 2 table whose cells read r0c0, r0c1, r1c0, and r1c1. Its path through the pipeline can be checked in the output files of the run described on Getting Started.

  1. extract classifies three shapes as title, body, and table, takes the title from the placeholder (title_source is placeholder), and records a table count of 1.
  2. render produces work/images/sample/slide_003.png from page 3 of the PDF, and the stage passes only because the PDF has 17 pages for 17 slides and no image has zero bytes.
  3. reconcile orders the blocks title, body, table, applies no penalty, and so leaves the confidence at 1.0, and adds the flag table_detected because the table count is above zero.
  4. build-docx writes the heading, the metadata line, the picture, and a table with three rows: 1 | Deck A slide 3 | | title, then 2 | First point on slide 3 of deck A / Second point on slide 3 | | body, then 3 | r0c0 | r0c1 / r1c0 | r1c1 | | table. The third column is empty and the fourth names the role.
  5. audit adds one row to slides.csv (title, confidence 1.0, warning count 1, 95 characters of raw text) and one row to warnings.csv for table_detected.

How align matches

align tries five strategies for each original row, in this order: an exact match after normalization, a containment match where the original lies inside a longer edited segment, a fuzzy match on a single segment with a score of at least 78, a window of up to three adjacent segments with a score of at least 74, and finally nothing. The result is labeled Unchanged, Grammar, Clarity, Rewritten, Merged, Split, or Not Found, according to the score and the relative lengths. The matching depends on how the edited text is first cut into segments, and that step has two reproducible faults, which Evidence describes.

Clone this wiki locally