bushra.muham@gmail.com818-693-0961
← AI for Architects
06

AI Product Binder Generator

A custom LLM tool for interior architecture

Format
Custom AI Tool
Tools
Python · Anthropic Claude API · PyMuPDF · ReportLab
Course
AI for Architects — ELVTR
Overview

Interior architects assemble product selections binders: client-facing PDFs that collect every specified product in a project — vanities, fixtures, tile, furniture — with a page of curated details per product. Building one by hand means opening every manufacturer cut-sheet PDF and product webpage, retyping dimensions, materials, finishes, and care notes into a layout, and keeping a table of contents in sync. It is slow, repetitive work.

This tool automates the whole pipeline. It takes the schedule an architect already has — an Excel export with KEY · DESCRIPTION · PATH columns pointing at each product’s spec sheet or webpage — and produces a finished binder. The intelligence in the middle is Claude, called through the Anthropic API: raw text and images scraped from each source are sent to the model, which returns clean, structured product data. The design is modeled on a real DFH Architects deliverable for a Pacific Palisades rebuild, including the firm’s convention of grouping several schedule keys onto one page when a single document covers them.

API Design

Forced Tool-Use

The extraction schema is declared as a tool and the model is compelled to call it, so every response is valid, schema-conforming JSON — no “return JSON only” prompt, no markdown fences, no parsing failures.

Efficiency

Prompt Caching

The long domain system prompt is identical for every product, so it carries a cache breakpoint. The first product writes the cache; every product after reads it at ~10% of the cost.

Multimodal

Vision Input

Product photos and dimensioned drawings extracted from each source are downscaled, encoded, and sent as image blocks alongside the text, grounding the extraction in what the product actually looks like.

Architecture

How the Pipeline Fits Together

Schedule rows are grouped by shared source; each unique source is extracted, structured by Claude, then rendered into the binder. Two front-ends — a CLI and a notebook form — feed the same pipeline.

excel_reader.py

Schedule intake

Reads the schedule with case-insensitive header matching; groups rows sharing one PATH into a single product; also writes schedules created in the notebook.

extraction/

Source extraction

PDF extractor (PyMuPDF text + embedded images with icon filtering), web extractor (requests + BeautifulSoup with keyword and size heuristics for product photos), and a source router for dispatch and path resolution.

ai_client.py

Claude API wrapper

Domain system prompt, forced tool-use JSON schema, prompt caching, multimodal image blocks, and layered error handling.

pdf_builder.py

Binder renderer

ReportLab renderer: cover, two-pass table of contents with accurate page numbers, product pages with key badges, and red error blocks for failed products.

pipeline.py

Shared pipeline

End-to-end pipeline used by both front-ends, with unique output naming: project__company__timestamp.

main.py / notebook

Two front-ends

A CLI for batch runs, and a point-and-click Jupyter notebook form (ipywidgets + native file picker) for non-technical users.

AI Integration

The Anthropic API, Deliberately

Rather than hoping for clean JSON in free text, the extraction schema is a tool and tool_choice forces the model to call it. The result is read straight from tool_use.input as a Python dict — no regex, no JSON repair.

System instructions (excerpt)
ROLE:
You are an architectural interior product binder assistant working for an
interior architecture firm. You receive raw product information extracted from
manufacturer spec sheets (PDF cut sheets) or product webpages, and you extract
the information a designer needs when assembling a product selections binder.

YOU WILL BE GIVEN:
- One or more product KEYS from the project’s finish/fixture schedule (e.g.
  U-36). Several keys may share one spec sheet when a single document covers
  multiple scheduled items (a vanity cabinet, its countertop, and its sink).
- Short schedule descriptions written by the design team.
- The raw text extracted from the source. This text can be noisy: navigation
  menus, legal boilerplate, unrelated products. Focus only on the product(s)
  matching the keys and descriptions.
- Optionally, images extracted from the source.

RULES:
- Do not invent information. Only report what is present in the text or clearly
  visible in the provided images.
- If a field is missing from the source, return an empty string. Never guess.
- Keep every field concise and professional — a technical reference binder,
  not marketing copy.
Forced tool-use call
response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1500,
    system=[{"type": "text", "text": SYSTEM_PROMPT,
             "cache_control": {"type": "ephemeral"}}],   # prompt caching
    tools=[EXTRACT_PRODUCT_INFO_TOOL],           # 10-field JSON schema
    tool_choice={"type": "tool", "name": "extract_product_info"},  # forced
    messages=[{"role": "user", "content": content_blocks}],  # text + images
)
info = ProductInfo(**next(b for b in response.content
                          if b.type == "tool_use").input)
Why This Matters

Forcing structured output through the tool-use API eliminates an entire class of parsing failures that plague “return JSON only” prompts. Combined with prompt caching on the static system prompt and multimodal image blocks, the integration is production-shaped rather than a minimal single call.

Testing

Four Input Classes, All Run Live

The tool ships with four committed example schedules, each stressing a different kind of input — every transcript is unedited terminal output from a live API run.

Test 01 · PDF + grouping

Multi-key spec sheets

Five schedule rows collapse to three product groups; three vanity keys (cabinet, countertop, sink) share one page and one API call. 3 of 3 succeeded.

Test 02 · Web scraping

Live webpages mixed with PDFs

Correct extraction from ~10,000 characters of noisy page text; a rate-limited image degraded gracefully with a warning rather than a failure. 4 of 4 succeeded.

Test 03 · Error resilience

Broken inputs

A missing file and a dead URL each fail per-product: the run completes with exit code 0 and the failed keys render as red error blocks inside the binder instead of crashing the batch.

Test 04 · AI-failure path

Rejected API key

A 401 authentication error is caught as a per-product error — the binder still builds, with the reason documented on the page.

Prompt

Product keys: U-36, U-37, U-03 Schedule descriptions: VANITY CABINET · COUNTERTOP · MARBLE TOP · BATHROOM SINK · UNDERMOUNT · CERAMIC BASIN Extracted source text: MARLOW 60-in Double Vanity Suite — Model MV-6022, Calderhouse Bath. The MARLOW vanity suite combines a 60-inch solid-birch cabinet, a honed Carrara marble countertop, and two undermount ceramic basins… [+ 1 image block from the PDF]

Response

product_name: Marlow 60-in Double Vanity Suite — Cabinet (Model MV-6022) manufacturer: Calderhouse Bath dimensions: 60 in W × 22 in D × 34 in H materials: Solid birch face frame and doors; plywood box construction finishes: Dove White, Storm Grey, or Natural Birch; Polished Nickel or Matte Black hardware certifications: CARB Phase 2 compliant casework installation_notes: Secure cabinet to wall studs using included mounting cleats. Rough-in drain at 21 in AFF. important_specs: · Model: MV-6022 · Two soft-close doors; six dovetailed drawers · Sold as a coordinated set with countertop and basins (U-37, U-03)

Captured verbatim from the saved interaction log: the model respected the “do not invent” rule — every field traces to the source — and used the schedule keys to select the cabinet as the page’s primary subject while cross-referencing its sibling keys.

Prompt caching was measured from the API usage data across two consecutive extraction calls on a cold cache. The first call wrote the 1,048-token system prompt to the cache; the second read all 1,048 tokens back at roughly a tenth of the normal rate. Across a real binder of 30–50 products, the per-product cost of the domain prompt drops by about 90%.

Results

The Generated Binder

Cover page — project and prepared-by pulled from the run
Auto-generated TOC — grouped keys U-36/U-37/U-03 all resolve to page 3
Grouped product page — three key badges, extracted image, AI-structured fields
Page built from a live webpage source — photo filtered by the image heuristics
A failed product documented as a red error block; the run is unaffected
Single-key page from a PDF cut sheet — image placed before text so both share the page
A Front-End for Non-Technical Users

Because the intended users are designers, not developers, the tool also ships a Jupyter notebook: a form with a native file picker, an Add-row button building a live product table, and a Generate button that writes both the schedule and the binder with unique, collision-free names. Both front-ends call the same pipeline.

Reflection

Reliability Is the Hard Part

01

Structure beats prompting

Forcing output through the tool-use API removed an entire class of JSON-parsing failures. The schema, not a politely-worded instruction, is what guarantees a usable result every time.

02

Caching changes the economics

A verbose, careful system prompt would normally be a per-call cost liability. Prompt caching turned it into a one-time expense — the measured 90% drop makes a rich domain prompt essentially free at binder scale.

03

The real world is messy

Treating every product as an isolated failure domain meant dead links, locked files, rate-limited image hosts, and even a revoked API key all degrade into a documented error block rather than a crashed batch.

04

The AI is one box in the diagram

The model call was working early; making the tool usable by the people who actually assemble binders — the notebook form, native file picker, self-explanatory output naming — was most of the engineering.