| name | notebooklm-pdf-to-ppt |
| description | Convert image-based NotebookLM slide PDF/PPTX exports into editable PowerPoint decks with OCR reconstruction, per-page local/model background cleanup routing, and blocking QA. Use when the user wants flattened PDF/PPT slide images rebuilt as editable PPTX with clean backgrounds and editable text, separate from NotebookLM content generation. |
| metadata | {"version":"0.1.14"} |
NotebookLM PDF To PPT
Use this skill for the editable reconstruction problem: converting flattened NotebookLM slide exports, PDFs, or image-based PPTX files into editable PowerPoint decks.
This skill is separate from notebooklm-course-studio:
notebooklm-course-studio owns NotebookLM content workflow: source import, content generation, artifact revision, and export.
notebooklm-pdf-to-ppt owns post-export reconstruction: parse pages, clean backgrounds, rebuild editable PPTX, and diagnose fidelity problems.
Do not use this skill to ask NotebookLM to generate course content, podcasts, study guides, or new slide artifacts. Use it only after a PDF/PPTX/image export already exists or when the user explicitly asks for editable reconstruction.
Current Status
This skill is under active development. The default path is now a small, inspectable PDF-to-editable-PPTX tool rather than the older multi-model fusion stack. It can run representative-page experiments, but it is not yet a reliable 90%+ full-deck converter.
Known current conclusions:
- PaddleOCR is the only OCR engine in the default main flow. Representative tests showed the removed secondary OCR path did not change final text, geometry, or PPTX output; it only added rejected candidates and maintenance noise.
- Preferred PaddleOCR models are the official PP-OCRv6 small models:
PP-OCRv6_small_det for text detection and PP-OCRv6_small_rec for text recognition. If the installed PaddleOCR runtime does not register v6 small models, fall back to official PP-OCRv5_mobile_det and PP-OCRv5_mobile_rec. Keep official model names exactly as published by PaddleOCR; do not rename or alias local model identifiers.
- Do not use a secondary OCR fallback for top-band heading repair in the default flow. Wrong section numerals are worse than missing numerals; handle heading numbering only when PaddleOCR or another reliable evidence source provides it.
- When OCR splits a short CJK tail onto the next row inside the same visual text container, merge it into one editable text box and preserve the original visible row break. Do not leave the tail as an independent text object, and do not force a single long CJK line that PowerPoint may fail to wrap.
- Font fitting is conservative for body text: do not enlarge body text during render-fit, do not switch body Latin text to serif fonts just because a width score looks better, and reject low-confidence font-fit candidates instead of committing bad typography to layout JSON.
- CJK body font-fit must preserve readability. Do not shrink CJK body text below a conservative floor merely to match rendered width; let the final fit-to-box cap handle overflow.
- PPTX renderer differences are secondary. When structure, text, coordinates, or grouping are wrong, the root cause is the layout/fusion layer, not the PPTX renderer.
- Visual section-prefix repair must clean the entire prefix cell, not only the detected horizontal strokes. If OCR misses a top-band prefix such as
一、, the recovered editable text and the background text-removal mask must cover the numeral plus punctuation area together.
- Title OCR repairs are allowed only for narrow, evidence-preserving fixes such as duplicated characters inside known section-title terms (
重重点 -> 重点). Preserve the original bbox and style fields, and record the repair in layout_repairs; do not use this as a broad content rewrite layer.
- Local-clean must flag high-risk pages instead of silently treating them as successful. If text removal uses diffusion/inpaint on textured, illustrated, dark, or large non-uniform regions, write
localCleanRisk=review into QA so the page can be routed to model-clean.
Operating Principle
The user should interact by chat. Internally, run scripts and models as needed, but present the result as output paths and concise diagnoses.
Always separate the two failure domains:
- OCR / parsing / fusion owns text content, reading order, grouping, coordinates, font size, color, style evidence, and whether text should be editable.
- PPTX rebuild owns unit conversion, font substitution, text-box margins, line spacing, paragraph spacing, and renderer-specific output.
Do not let one layer compensate for the other. If OCR is wrong, fix OCR/parsing/fusion. If layout JSON is right but PPTX output is wrong, fix the renderer.
Core reconstruction principles
OCR returns only text, boxes, and confidence. Everything else — color, font
size, weight, family, and what counts as a paragraph — is reconstructed by
this skill. Most fidelity bugs come from reconstructing via a fixed assumption
instead of measuring. Follow these three principles for any new rule:
-
Reconstruct by measuring, not by assuming — and stay polarity-agnostic.
Recover color and size from the actual pixels of the text region, never from
a baked-in assumption like "dark text on a light background" or "font size =
bbox height × constant". Light text on a dark background is normal. The shared
probe scripts/style_probe.py separates foreground from background by
luminance distance and is the single source for color, ink height, and ink
density; route new style recovery through it rather than re-deriving pixels.
-
Base decisions on stable geometry, not on derived values. Bounding-box
height and position are stable; a font size estimated from ink varies between
sibling lines (ascenders/descenders). Paragraph/grouping decisions must key
off bbox geometry, not the estimated font size.
-
Every recovered size must fit its box; segment by structure. OCR boxes are
tight to one ink line, so any recovered font size must be reconciled with the
box (shrink-to-fit) or it overflows and overlaps. A sentence is ONE flowing
segment (let word-wrap reflow it; do not freeze OCR's visual row breaks with
hard newlines), but a glossary/table row is NOT a paragraph — distinguish a
table row (a short, cross-column translation pair on the same y) from stacked
sentence lines (same column, different y) and never vertically merge the former.
These reconstructions interact (enlarging size causes overflow; ink-based size
causes sibling-line divergence), so each new rule needs a safety check and must
be validated on rendered output, not just on the layout JSON. OCR has a hard
ceiling (mis-read phonetics, very thin numerals); do not try to fix engine-level
recognition errors in post-processing — diagnose, state the limit, and stop.
Default Workflow
Use scripts/run_simple.py as the default entrypoint for normal PDF-to-PPTX conversion tests. It launches scripts/pdf_to_ppt_simple.py through a stable wrapper because direct script startup can stall on this local macOS Python environment.
Default command shape (use python3; python may be absent). --background
defaults to auto (per-page routing, see below), so a bare run already picks
the right cleanup per page:
PYTHONDONTWRITEBYTECODE=1 python3 scripts/run_simple.py \
--pdf /path/to/source.pdf \
--pages 1,2 \
--output-dir /path/to/output \
--ocr auto \
--background auto
To force one mode for the whole deck, pass --background local-clean or
--background model-clean. Do not choose local-clean from screenshot
appearance alone. Run OCR plus --background auto first and let the recorded
text geometry and cleanup QA prove that local cleanup is safe; force
local-clean only for an explicitly requested diagnostic experiment or after
the auto router has already selected it. For illustrated,
textured, image-heavy, speech-bubble, diagram, or mixed pages, the default
quality strategy is AI/model background cleanup, not local Python fill.
For model-clean, the default provider in Codex is codex-image: the agent
should use Codex's built-in image capability to edit the original slide image
directly. This means: first load the local source slide PNG into the conversation
with view_image, then call the built-in image_gen tool in edit mode against
that visible image. Do not treat the lack of an image_path parameter on
image_gen as permission to switch backends. view_image is only the
load/inspection step; image_gen is the edit operation. Third-party image
backends are not the Codex default. Use them only when the user explicitly
selects one, or when a pre-authorized third-party fallback is configured and the
Codex source-image edit is unavailable, fails, or fails QA.
The script cannot call Codex's built-in image tool by itself, so it writes a
codex_image_request package for every page that needs model cleanup. A
codex-image run finishes request discovery for all selected pages, writes one
manifest, returns exit code 2 with reason=codex_image_edits_pending, and
does not build a misleading PPTX from unfinished backgrounds. In an
interactive Codex session,
execute each request by opening source_image with view_image, then using
the built-in image_gen tool to edit that visible image. If the current Codex
image tool cannot use the visible source image as the edit target, stop and
report the limitation; do not substitute a prompt-only image generation result.
If the user has not pre-authorized a third-party image-edit fallback, ask before
switching providers. Any fallback must also edit the original source image; never
use prompt-only text-to-image generation as a clean background.
When the edited clean backgrounds have been saved to each request's
expected_output, run scripts/apply_codex_image_edits.py --work-dir <work_dir>
to validate the images, update layout JSON, and rebuild the PPTX.
For fully automated CLI/API runs, explicitly select a real image-edit API
backend and model supported by that environment:
PYTHONDONTWRITEBYTECODE=1 python3 scripts/run_simple.py \
--pdf /path/to/source.pdf --pages 1,2 --output-dir /path/to/output \
--ocr auto --background model-clean \
--model-provider openai-image --model-clean-model <image-edit-model> \
--model-clean-fallback fail
This default path is intentionally simple:
- Render selected PDF pages into PNGs. Cached with provenance: a render is reused only when source PDF identity, page, and DPI still match its sidecar metadata.
- OCR text lines and coordinates with PaddleOCR worker by default (
.venv-paddleocr). Raw OCR is saved immediately to 02_ocr/raw_paddle_cache.json and reused only when the source, renders, DPI, page set, OCR worker, and style probe still match. Use --no-ocr-cache for an intentional refresh. By default (--ocr-batch-size 0) one worker handles all selected pages so the model loads once; set a smaller batch size such as 3 or 1 only when a machine hits OCR memory limits.
- Recover style (color/size/weight) per region via
scripts/style_probe.py, group/segment text, fit each text size to its box, then clean the background. With --background auto each page is routed to local-clean or model-clean automatically. model-clean is cached: an existing cleaned background for a page+model is reused (no re-billing).
- Always strip the NotebookLM watermark from the cleaned background (
strip_watermark_from_background), then rebuild a PPTX with the clean background and editable text boxes.
- The maintained flow writes the editable PPTX plus layout and QA JSON. It does not render PPTX images.
Background modes:
auto (default, recommended): per-page routing. text_background_is_uniform
measures the luminance spread of the background AROUND each text box; pages
whose text sits on a uniform/light background go to local-clean (fast, no
model call), pages with textured/dark/illustrated text backgrounds go to
model-clean. Solves the all-or-nothing trade-off: a mostly-white deck mostly
uses local-clean (e.g. a 15-page deck dropped from ~15 min to ~4 min) while
still model-cleaning the few hard pages. Bias is safe — when unsure it picks
model-clean. This does not mean Python cleanup is the default for complex
pages; complex pages should route to AI/model cleanup. If a page initially
routes to local-clean but the local-clean QA marks localCleanRisk=review,
auto must escalate that page to model-clean. The router is three-state and
fail-closed: missing OCR/source text, unreadable source images, or pages that
mix four or more complex text-carrier surfaces with bottom-edge content become
manual-review, which blocks PPTX delivery until explicitly resolved. Pages
with suspicious OCR fragments route directly to model-clean and remain
review-required instead of first attempting local cleanup. Route the complete
selected batch before any cleanup; if one page is manual-review, stop the
whole batch preflight before creating local edits or model requests.
original: keep the original page image as background and overlay editable text.
local-clean: fast deterministic background cleanup by covering text regions with sampled neighboring colors; no model call, but not automatically safe. Safe-cover rule: it only covers a region that has a surviving editable text replacement (_has_replacement); a region OCR'd into the mask but dropped from final texts (e.g. a big decorative number) is left in the background so it is never erased-without-replacement. Can still leave faint pale blocks where text sits on a textured/illustrated background.
model-clean: high-quality background cleanup through an image-editing backend. In Codex chat, default to codex-image: load the original page image with view_image, edit that visible source image with built-in image_gen, and reject regenerated similar scenes. For unattended CLI/API runs, use openai-image or gemini-native explicitly.
Follow references/editable-ppt-workflow.md for the broader staged process and references/editable-ppt-rules.md for quality rules.
Use references/development-roadmap.md for the current development direction and promotion criteria. When an experiment regresses visually, stop and diagnose the responsible layer before trying another prompt or model.
Practical execution order:
-
Input and scope
- Accept a PDF, flattened PPTX, or slide image set.
- Create a work directory under the user's project output folder.
- Record source path, selected pages, model names, and output paths.
-
Representative pages first
- Do not start with a full deck.
- Pick pages by visual type, not by convenient consecutive page numbers. Cover: cover/title; dense: the page with the most body text; structure: table/grid/multi-column; interaction: dialogue/bubbles; illustration: text embedded in artwork; oversized text: phonics, alphabet, decorative glyphs or giant numerals; ending: summary/closing page when its layout differs.
- Select one page from each type that actually occurs, then deduplicate. A small deck may need 3-4 representatives; a visually diverse deck may need 5-7.
- Include oversized-glyph/phonics pages even when OCR reports little text; low OCR count is exactly why they require visual coverage.
-
Render source pages
- Render pages to PNG.
- Keep the original image pixel coordinate space as the layout coordinate system.
-
OCR before rebuild
- Run OCR before background cleanup or PPTX rebuild.
- Extract text, confidence, bbox, estimated font size, font family policy, color, and mask boxes.
- Keep the layout JSON as the source of truth for rebuild.
-
OCR / visual accuracy gate
- Verify text content, grouping, x/y/width/height, font size, and color before rebuild.
- If these fields are wrong, stop and fix OCR/parsing first.
- Merge adjacent same-baseline OCR fragments into one editable line when they share font policy and vertical overlap.
- Same-baseline OCR fragments may have overlapping boxes because OCR over-expands glyph regions. If the second fragment still advances in reading direction and shares style/vertical overlap, treat the negative gap as bbox overlap and merge it in OCR normalization.
- Filter footer/watermark brand text from editable text and text masks.
- For strict textbook/source-faithful work, create a case-local JSON inventory such as
{"pages":{"3":["Expected heading","Key term"]}} and pass --expected-text-json /path/to/inventory.json. Missing expected strings are a hard QA blocker (expected_text_missing, exit code 4); the gate diagnoses but never invents text.
- Review
suspiciousTextFragments in QA. It flags low-confidence and malformed short OCR tokens without silently deleting them. Accept or correct them using source evidence before delivery.
- Do not make a final local/model cleanup decision during screenshot-only planning. Without OCR text boxes and the auto-routing feature record, report the route as provisional and run the batch preflight before cleanup.
- Apply renderer-calibrated OCR font-size estimates before PPTX generation.
- Classify text role (
title, body, label) before font and size normalization.
- Use style-appropriate fonts only from the approved pool or explicit playful classroom fallbacks.
- Do not call a secondary OCR engine as a top-band OCR repair in the default flow. In representative tests it added rejected candidates but did not improve final text, geometry, or PPTX output.
- Missing section numerals should not be guessed. Add or repair section numbers only from reliable primary OCR evidence or a future dedicated numbering module.
- When primary OCR splits a top heading into adjacent fragments, merge those fragments by x-order into one heading before typography and rebuild. Record this deterministic repair in
layout_repairs.
- When OCR splits a continuous paragraph into multiple visible rows inside the same visual region, column, card, bubble, or panel, rebuild it as one editable paragraph while preserving the original visible row breaks. Record
paragraphGroup, textSource=ocr_paragraph_group, and lineBreakSource=ocr_visible_rows.
- When OCR splits a CJK sentence into a normal line plus a very short continuation tail, such as
...什么工 + 作?, merge them into one editable text box before paragraph grouping. Preserve the visible row break (lineBreakSource=ocr_visible_rows) because PowerPoint may not wrap continuous CJK text reliably.
- Paragraph grouping must be column/region aware, not only global reading-order based. Interleaved text from another column must not prevent same-region continuation lines from being grouped.
- Do not merge titles, table cells, glossary/list rows, Q/A pairs, or separate cards just because they are visually near each other. Group only rows with compatible font policy, size, alignment, and local geometry.
- Derive
font_bold from original-slide visual evidence, such as title role and tight ink-density in the OCR text region. The PPTX renderer must only execute the recorded style fields; it must not invent bold or regular weight during rendering.
- For repeated same-column lists, glossaries, or table-like rows, normalize sibling font size and font weight from group-level evidence. Record
fontSizeSource, fontSizeLocked, typographyGroup, textBoxHeightScale, and lineSpacing in layout JSON before PPTX rendering.
- Run font render-fit after typography grouping. Choose
font_family only from the approved pool by comparing rendered candidate width and ink density against the original OCR region. Record fontFit, fontFamilySource, and any size compensation in layout JSON.
- Body text render-fit is a shrink/validation pass, not a style generator. For non-title text, only shrink or keep the measured size; do not scale up.
- CJK body render-fit must use a higher minimum scale than Latin body text. Avoid shrinking continuous Chinese sentences into unreadable small text just to satisfy width fitting.
- For Latin body text, prefer the actual default/fallback sans-serif family. Do not switch body text to
Times New Roman; reserve serif fitting for explicit title or clearly serif source evidence.
- If a font-fit candidate still has poor width match or high score after testing, keep the existing font/size and let the later fit-to-box cap handle overflow.
- Do not aggressively font-fit Chinese or mixed Chinese/Latin glossary/list groups. For these groups, preserve the approved CJK default font and group typography unless repeated evidence proves a better candidate. Font fitting is safer for titles and homogeneous Latin text.
-
Background cleanup
- Editable replacement text requires old text to be removed from the background.
- Default to AI/model cleanup for complex visual backgrounds. Use local cleanup only for flat/simple pages or as an explicitly accepted diagnostic fallback.
- Use
model-clean when text is embedded in illustrations, photos, textured backgrounds, cards, bubbles, diagrams, or other non-uniform visual regions.
- In
auto mode, local-clean is only accepted after its own QA. If local-clean records localCleanRisk=review, immediately escalate the page to model-clean; do not silently keep the risky local-clean background as final.
- In Codex chat, prefer
--model-provider codex-image for complex pages. Treat the generated codex_image_request as a handoff for the Codex built-in image tool: open the listed source_image with view_image, then use built-in image_gen to edit that visible source image, then save the result to expected_output.
view_image is not background editing. It only makes the local slide PNG visible for inspection and as the source-image context. The actual edit must be performed by built-in image_gen against that visible source image.
- When a run produces Codex image requests, use
03_model_cleaned/codex_image_edit_manifest.json or .md as the execution checklist. Each listed source_image must be edited directly and saved to expected_output.
- Request discovery is all-at-once: one missing edited background must not stop later pages from receiving request packages. Treat exit code
2 as an expected handoff state, not as conversion completion.
- After Codex edited backgrounds exist, run
scripts/apply_codex_image_edits.py --work-dir <work_dir>. This script validates geometry, runs visual-diff QA outside text masks, writes layout.codex_applied.json, and builds editable_text_overlay.codex_applied.pptx.
- For
model-clean, prompt the model to edit the original image directly and remove only the OCR-listed text. Do not describe or reinterpret the scene.
- Codex image cleanup is valid only when the original slide PNG is made visible with
view_image and used as the edit target for built-in image_gen. If only prompt-to-image generation is available, stop and report that the backend cannot perform source-image editing.
- Never accept a similar regenerated background as
clean_background. The result must be a text-removed edit of the original source image.
- For OpenAI-compatible image models, use an image-edit endpoint with
multipart/form-data; do not use text-to-image generation endpoints for background repair because they can regenerate a different scene.
- If Codex source-image editing is unavailable, fails, or the edited image fails QA, first report the failure reason. Use third-party image-edit fallback only when the user has pre-authorized it or explicitly selects it after the failure report.
- Third-party image providers are opt-in/fallback backends. Do not silently use external services when running inside Codex if the user asked for Codex's built-in image capability. Any fallback must be source-image editing, never prompt-only generation.
- If a model-clean background changes composition, size, or text container positions, diagnose it as a background/OCR alignment issue before judging PPTX rendering.
- If a model-clean background preserves aspect ratio and composition but returns a different pixel size, normalize it back to the original input canvas and record the geometry QA. Do not treat this as a coordinate failure.
- After model-clean normalization, run visual-diff QA outside OCR text-mask regions. Text regions are expected to change; non-text regions such as containers, icons, illustrations, cards, panels, and composition should remain stable.
- Cached model backgrounds must be trusted only if they came from source-image editing and passed non-text-region visual QA. Do not reuse prompt-generated or visually drifted backgrounds as if they were valid clean backgrounds.
- In representative batch runs, one model-clean failure must not hide the rest of the diagnostic signal. Record
model_clean_error and mark background QA as fail. Only use local-clean fallback when the user explicitly requests --model-clean-fallback local-clean.
- Preserve non-text containers, speech bubbles, cards, panels, icons, illustrations, charts, and composition.
-
PPTX rebuild
- Use
clean_background when available.
- Add editable text/shapes/images from layout JSON.
- Rebuild deterministically.
- Do not shrink, move, or rewrite OCR fields during rendering. If the OCR coordinates or font size are wrong, fix OCR/parsing rather than moving text in the renderer.
- Text-box height and line spacing must come from layout metrics, not a renderer-wide constant. The renderer executes
textBoxHeightScale and lineSpacing without additional fitting.
- The renderer must not silently replace fitted fonts. If a fitted font is unavailable, diagnose the font environment or rerun font fitting; do not hide substitution inside PPTX generation.
-
Output QA
- Inspect the generated PPTX and diagnostic JSON.
- Compare the PPTX against the original page when an external viewer is available.
- Attribute differences to OCR/parsing/fusion or renderer before changing anything.
- Do not deliver while
missingExpectedText > 0, modelCleanPending > 0, visualFail > 0, or any page still has an unresolved needsReview reason. The main flow exits with unresolved_qa_review instead of building a candidate PPTX, and apply_codex_image_edits.py enforces the same gate after model edits. Cached model backgrounds must be rechecked by visual diff; reused alone is not a visual pass.
- A missing model-clean background always blocks rebuild.
--allow-missing is retained only as a deprecated compatibility flag and must never authorize rebuilding with original old-text backgrounds.
-
Only then consider full-deck
- Promote to wider page batches only after representative pages pass review.
Readiness Check
Before a new reconstruction run on a fresh machine or after major script changes, run:
python scripts/check_readiness.py
This is a read-only check. It verifies local files, required Python modules, core binaries such as Poppler, PaddleOCR runtime availability/startup, and model-related environment variables. Add --ocr-smoke-image /path/to/page.png when you need a real one-page PaddleOCR smoke test before a full run. It does not install dependencies or call external model APIs.
Script Map
Core scripts:
scripts/check_readiness.py: read-only local readiness and dependency check, including PaddleOCR startup and optional one-page OCR smoke.
scripts/run_simple.py: stable launcher for the simple flow.
scripts/pdf_to_ppt_simple.py: default PDF -> render -> PaddleOCR -> clean background -> python-pptx flow. Key post-processing rules live here: paragraph grouping, safe background cleanup, watermark stripping, typography grouping, conservative font fitting, and PPTX rebuild.
scripts/ocr_paddle_worker.py: PaddleOCR batch worker called by the simple flow. Uses official PP-OCRv6_small_det and PP-OCRv6_small_rec by default, and sizes text from measured ink height through style_probe.
scripts/style_probe.py: shared polarity-agnostic style probe (analyze_text_region): foreground/background separation -> true text color, ink height, ink width, ink density. Single source for color/size recovery; used by both ocr_paddle_worker.py and pdf_to_ppt_simple.py.
scripts/repair_background_with_image_model.py: optional image-model background text removal for --background model-clean; codex-image writes a Codex image-tool request package, while API backends call external image-edit endpoints.
scripts/apply_codex_image_edits.py: closes the Codex image-tool handoff loop. After edited backgrounds are saved to expected_output, it validates them, rewrites layout/QA, and rebuilds the PPTX.
scripts/publish_check.py: local pre-publish validation for README, metadata, required files, and script syntax.
scripts/smoke_test.py: local smoke test for script syntax and lightweight package checks.
Old prototype, secondary OCR, mask-edit, renderer comparison, and multi-model fusion scripts are intentionally not part of the maintained skill package. Reintroduce any of them only behind a clear main-flow need and a representative visual regression test.
Fonts
Use references/fonts.md as the practical font guide and references/codia-google-fonts-list.json as the machine-readable font catalog.
Default font policy:
- Chinese:
Noto Sans SC.
- Latin:
Inter.
- Approved fallbacks:
Source Han Sans CN / 思源黑体 CN, Arial, Times New Roman.
- Classroom/playful title fallback when visually appropriate:
Comic Sans MS, Chalkboard SE, Marker Felt, ZCOOL KuaiLe.
Do not freely match arbitrary fonts. If font mismatch causes line-spacing or size drift, diagnose it as style/font evidence or renderer mapping, not as a reason to move OCR boxes.
PaddleOCR Policy
PaddleOCR may be used as the primary OCR engine for the simple default flow when it is available and stable on the machine.
Current policy:
- Use PP-OCRv6 small by default:
PP-OCRv6_small_det + PP-OCRv6_small_rec.
- Keep PaddleOCR official model names exactly as-is in code, docs, logs, and outputs. Do not invent local aliases for model names.
- Use PaddleOCR to compare and improve text recognition and bbox quality.
- Call PaddleOCR through
scripts/ocr_paddle_worker.py, not by importing PaddleOCR inside the main script.
- If PaddleOCR is unavailable or fails, report the readiness/runtime problem instead of silently falling back to a weaker OCR path.
- Do not dump every PaddleOCR result into the final PPTX layout.
- Filter low-confidence fragments, logo text, decorative background text, and short signage.
- Treat OCR as the source for text and bbox evidence; detailed typography is still estimated unless a separate style probe is explicitly added.
Renderer Policy
Use the renderer that best supports the current experiment:
- python-pptx: preferred default for the simple flow because it is easy to inspect and patch.
- PPTXGenJS: preferred for fast deterministic generation from layout JSON.
- PowerPoint/Keynote: final human visual validation when available.
If a PPTX looks wrong, first inspect the layout JSON. Renderer changes cannot fix wrong text grouping, wrong title structure, wrong coordinates, or decorative OCR leakage.
Boundaries
- MUST remove the NotebookLM export watermark from every generated background,
no matter how the background was produced (model-clean OR local-clean) — the
source is a NotebookLM export and the bottom-right "NotebookLM" mark must never
survive into the deck.
strip_watermark_from_background runs after every
background-clean path and fills the mark with the sampled local background so it
blends in; it searches only the very bottom strip (below any corner QR code) so
QR codes and real content are preserved. Do not bypass or gate this off.
- Do not promise full element decomposition.
- Do not run full decks while representative pages still fail.
- Do not treat a model-generated clean background as valid without visual QA.
- Do not let one model-clean page failure abort representative-page diagnostics unless the user explicitly asks for fail-fast behavior.
- Do not keep old background text behind editable replacement text.
- Do not hardcode a single test deck's wording, page structure, or visual style into general rules.
- Do not store project-specific reconstruction rules in global memory.
Outputs
For every representative run, return clickable paths for:
- work directory;
- layout JSON;
- PPTX;
- diagnostics or QA reports when produced.
Keep the user-facing summary blunt: what improved, what got worse, and which layer owns the remaining problem.