Skip to content

Add Word document generation Colab notebook (uses the docx processor plugin) - #884

Open
mvansegbroeck wants to merge 2 commits into
mainfrom
add-word-document-tutorial
Open

Add Word document generation Colab notebook (uses the docx processor plugin)#884
mvansegbroeck wants to merge 2 commits into
mainfrom
add-word-document-tutorial

Conversation

@mvansegbroeck

Copy link
Copy Markdown
Contributor

What

Adds docs/colab_notebooks/8-generating-word-documents.ipynb — a standalone Colab
notebook that turns generated rows into real .docx files: headings, a front-matter
metadata table, numbered sections with bullets, a key-data table, page footer, and Word
core properties.

Single file. No docs/notebook_source/ counterpart.

Why

Data Designer produces rows; document pipelines consume .docx. Teams building
enterprise RAG ingestion, document classifiers, or DLP tooling need document corpora
they are structurally not allowed to obtain — the real policy library lives in a
customer's SharePoint.

Generating them keeps the ground truth attached: the sampler controls that produced each
document are already columns in the dataset, so the corpus is labelled by construction
rather than by an annotation pass.

This notebook will be referenced from an upcoming dev note.

Usage

Open the badge at the top of the notebook, or run locally. The pipeline is:

sampler(doc_id, company, department, doc_type, classification)
  -> llm-structured(document: WordDocument)
  -> render to .docx

The load-bearing idea is that one Pydantic model does two jobs — it is the
output_format of the LLM column and the input contract of the renderer:

class WordDocument(BaseModel):
    title: str = Field(description="Document title.")
    subtitle: str = Field(description="One-line subtitle, e.g. the scope or the owning function.")
    summary: str = Field(description="A single paragraph executive summary, 40-80 words.")
    sections: list[DocSection] = Field(description="Four to six sections that make up the body.")
    key_data: DocTable = Field(description="A table carrying the document's structured facts ...")

Because both ends share one definition, "the model produced something the renderer can't
handle" becomes a Pydantic validation error on the column — which Data Designer already
retries — instead of a parsing failure downstream. There is no markdown parsing anywhere
in the notebook.

How

Placement. Follows the 7-nemotron-personas.ipynb pattern: a self-contained Colab
notebook with the Open in Colab badge and the standard install / NVIDIA_API_KEY setup
cells (marked nemo_colab_inject, matching generate_colab_notebooks.py), rather than a
numbered entry in the docs/notebook_source tutorial series.

Two consequences, both intentional:

  • It is not executed by make test-run-tutorials, which globs docs/notebook_source/*.py.
    A full document at max_tokens=8192 per record is not something to run on every CI pass.
  • It adds no dependency to the notebooks group. python-docx is installed by the
    notebook's own Colab setup cell, the same way notebook 4 handles pillow and datasets.

Numbering. 8- rather than 7-, since 7-nemotron-personas.ipynb already occupies
that slot in colab_notebooks/.

Content notes. The notebook covers two things worth calling out explicitly, because
both are easy to get wrong:

  • Field(description=...) strings are prompt text, not documentation — Data Designer
    serializes the JSON Schema into the prompt inside <response_schema> tags.
  • Table rows are normalized to the header width. Structured outputs constrain the shape
    of the JSON, not the arithmetic inside it, so a model asked for three columns
    occasionally returns a row with two cells. Padding is cheaper than a retry.

It closes by pointing at
data-designer-docx
for the production shape, where rendering moves inside the pipeline as a processor.

Validation

The notebook body was executed end to end against a stub OpenAI-compatible model server
(Colab-injected cells stripped, as a local run would): 4 documents written — 1 from
preview(), 3 from create() — and read back through python-docx to confirm headings,
tables, footer, and core properties.

It has not been run against a live model in this branch; the generation path is identical
to the plugin's, which is covered by tests in the Plugins repo.

git status on this branch shows exactly one added file.

🤖 Generated with Claude Code

Adds docs/colab_notebooks/8-generating-word-documents.ipynb, a standalone
notebook showing how to turn generated rows into real .docx files: one Pydantic
model serving as both the LLM output_format and the renderer's input contract,
sampler controls that label the corpus by construction, and python-docx
rendering of headings, tables, footers, and Word core properties.

Follows the 7-nemotron-personas pattern: a self-contained Colab notebook with an
Open in Colab badge and the standard install/API-key setup cells, rather than a
numbered entry in the docs/notebook_source tutorial series. It is referenced
from an upcoming dev note.

Because it is not part of docs/notebook_source, it is not executed by
make test-run-tutorials and adds no dependency to the notebooks group;
python-docx is installed by the notebook's own Colab setup cell.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: mvansegbroeck <mvansegbroeck@gmail.com>
@mvansegbroeck
mvansegbroeck requested a review from a team as a code owner August 21, 2026 19:30
@github-actions

Copy link
Copy Markdown
Contributor

Fern preview: https://nvidia-preview-pr-884.docs.buildwithfern.com/nemo/datadesigner

Fern previews include the docs-website version archive with PR changes synced into latest. Notebook tutorials are rendered without execution outputs in previews.

@greptile-apps

greptile-apps Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds a standalone Colab notebook demonstrating generation of structured Word documents through the data-designer-docx processor plugin.

  • Installs and verifies the external processor plugin.
  • Defines sampled metadata and structured LLM document generation.
  • Renders generated rows to .docx files and demonstrates reading one back.

Confidence Score: 4/5

The PR is not yet safe to merge because the previously reported local-execution path still terminates at the Colab-only import.

The notebook continues to import google.colab before entering the API-key fallback, so users following its advertised local Jupyter instructions encounter ModuleNotFoundError instead of reaching document generation.

Files Needing Attention: docs/colab_notebooks/8-generating-word-documents.ipynb

Important Files Changed

Filename Overview
docs/colab_notebooks/8-generating-word-documents.ipynb Adds the complete Colab workflow for configuring, generating, rendering, and inspecting synthetic Word documents.

Reviews (2): Last reviewed commit: "docs: use the docx processor plugin in t..." | Re-trigger Greptile

"import getpass\n",
"import os\n",
"\n",
"from google.colab import userdata\n",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Colab import breaks local execution

When this notebook is run in a local Jupyter environment, the unguarded google.colab import raises ModuleNotFoundError before the API-key fallback runs, preventing the advertised local execution path from reaching generation.

Prompt To Fix With AI
This is a comment left during a code review.
Path: docs/colab_notebooks/8-generating-word-documents.ipynb
Line: 79

Comment:
**Colab import breaks local execution**

When this notebook is run in a local Jupyter environment, the unguarded `google.colab` import raises `ModuleNotFoundError` before the API-key fallback runs, preventing the advertised local execution path from reaching generation.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Replaces the self-contained renderer with the data-designer-docx plugin, so the
notebook demonstrates the production shape rather than an inline loop over the
finished dataframe.

The notebook now installs the plugin, verifies Data Designer discovered it
through its entry point, and adds a single DocxProcessorConfig processor. The
WordDocument schema is imported from the plugin instead of being redefined,
since the schema is the contract between the LLM and the renderer and the two
halves belong in the same package.

Rendering happens inside the pipeline: files stream out per batch, and the
document path is written back into the dataset automatically.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: mvansegbroeck <mvansegbroeck@gmail.com>
@mvansegbroeck mvansegbroeck changed the title Add Word document generation Colab notebook Add Word document generation Colab notebook (uses the docx processor plugin) Aug 21, 2026
@mvansegbroeck

Copy link
Copy Markdown
Contributor Author

Updated in 35f580e — the notebook now uses the data-designer-docx plugin rather than defining its own renderer inline.

The first revision was the self-contained version: it defined WordDocument and a render_document function in cells and looped over the finished dataframe, mentioning the plugin only in a closing note. That is the wrong artifact to point a dev note at when the dev note argues for the plugin.

What changed

Before Now
Schema redefined in a cell imported from the plugin
Renderer ~90 lines of python-docx in cells none — the processor does it
Wiring loop over dataset.iterrows() one add_processor(DocxProcessorConfig(...))
Install data-designer, python-docx data-designer, data-designer-docx

It also gained a plugin-discovery check, which is the thing people actually get stuck on:

from data_designer.plugins.plugin import PluginType
from data_designer.plugins.registry import PluginRegistry

print("processor plugins:", PluginRegistry().get_plugin_names(PluginType.PROCESSOR))
# -> processor plugins: ['docx']

Net effect: 32 cells down to 22, and rendering now happens inside the pipeline — files stream out per batch and docx_path lands in the dataset automatically.

⚠️ Merge ordering

This PR now depends on NVIDIA-NeMo/DataDesignerPlugins#83 and should not merge before it.

data-designer-docx is not on PyPI, so the setup cell installs from the plugins repository:

!pip install -U data-designer \
  "data-designer-docx @ git+https://github.com/NVIDIA-NeMo/DataDesignerPlugins.git#subdirectory=plugins/data-designer-docx"

That URL targets main with no branch ref, so it is durable — but it only resolves once #83 lands. The cell carries a comment noting it collapses to !pip install -U data-designer data-designer-docx once the plugin is released.

Validation

Executed end to end with the Colab-injected cells stripped, against a stub model server, with the plugin installed from #83's branch:

processor plugins: ['docx']
✅ 11 .docx written
   artifacts/policy-documents-plugin/documents/word-documents/POL-25B13D2C-Remote-Work-Policy.docx
   ...

Still one file, still 8-, still no docs/notebook_source/ counterpart — so make test-run-tutorials does not execute it and no dependency is added to the notebooks group.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant