Workbook context & screenshots¶
Workbook context¶
result.workbook_context extracts bounded first rows and columns for every
sheet, without assuming a header row. It also exposes comments, merged cells,
frozen panes, hidden columns, and sheet visibility using openpyxl; Excel is
not launched.
ctx = result.workbook_context
for sheet in ctx["sheets"]:
print(sheet["name"], sheet["dimensions"], sheet["preview_range"])
print(" frozen:", sheet["freeze_panes"], "hidden:", sheet["hidden_columns"])
for comment in sheet["comments"]:
print(f" {comment['cell']} ({comment['author']}): {comment['text']}")
The mapping is keyed filename, sheets, stats and warnings; per-sheet
context lives under sheets.
This context has two consumers. The HTML report renders it in the Sheets
tab, and document_workbook() sends it to the model
so the AI overview describes the file a reader opens — its titles, labels,
comments and hidden columns — rather than only the graph its formulas make.
Pass include_context=False to keep cell contents off the wire.
Screenshots¶
Generate and embed high-resolution sheet screenshots using LibreOffice Calc:
screenshots = result.save_screenshots("screenshots/")
result.save_html("out.html", screenshots=screenshots)
Each sheet is rendered whole, onto a single image, and the result is keyed by sheet name — which is what lets the Sheets tab show every sheet's image beside its comments, frozen panes and first cells:
result.save_screenshots("screenshots/")
# {'Sales': [PosixPath('screenshots/demo-Sales.png')],
# 'Summary': [PosixPath('screenshots/demo-Summary.png')], ...}
Pass per_sheet=False for the flat list[Path] of print pages instead, laid
out by the workbook's own page setup; the report then shows them in a separate
Visual preview tab, since no page can be tied to a sheet. That flat list is
also what you get back when the renderer does not produce exactly one page per
sheet — an older LibreOffice ignores the single-page option — because a
screenshot filed under the wrong sheet is worse than one filed under none.
Requires LibreOffice and Poppler's pdftoppm. Both are located on PATH or in
their standard install directory, so the Windows and macOS installers work
without any PATH setup:
LibreOffice runs headless with a throwaway user profile, so rendering works even while LibreOffice is open on the desktop, and never touches your own settings.
Screenshots are for readers first
The PNGs are embedded in the report for a human to look at, and the AI
overview never receives one: it is given the same facts in text form, read
deterministically from the file by openpyxl. So the overview describes the
sheets as they look even when no renderer is installed at all, and no vision
model is needed.
Letting a model look at them¶
What survives that text extraction is what openpyxl can name. Colour
conventions — blue inputs against black formulas — conditional formatting,
charts and the shape of a layout do not, and one call sends the picture itself
to a multimodal model:
seen = result.describe_screenshots(shots, base_url=..., model="<a vision model>")
result.save_html("out.html", screenshots=shots, screenshot_docs=seen)
The description appears under the image it describes, badged read from the screenshot so it is never mistaken for a claim about the lineage — and so it can be read against the picture it sits under, which is the only check there is. It is opt-in for a reason: a picture of a sheet shows every row on it. See Describing the screenshots and Data handling.