Skip to main content

The Verification Pipeline

Penquify’s verification system ensures that generated photos contain the correct document data. The key design principle: the extraction model never sees ground truth values.
1

Generate photo

Gemini generates a photorealistic image from the clean document + variation config.
2

Blind extraction

A separate Gemini 2.5 Flash call receives the generated photo and a list of field names. It extracts values with confidence scores. It does NOT know the expected values.
3

Programmatic comparison

Extracted values are compared against the source schema in Python code. No model is involved. Values are normalized (strip whitespace, lowercase, remove $, commas, dots).
4

Classify results

Each field gets a status:
  • match — extracted value matches ground truth
  • mismatch — extracted value differs (image gen error)
  • illegible — model can’t read it (confidence below 0.5)
  • not_visible — field not in frame (cropped, occluded)
5

Retry on mismatch

Mismatches indicate the image generator rendered text incorrectly. Penquify retries up to N times, emphasizing the wrong fields in the prompt.
Only mismatch triggers retries. illegible and not_visible are expected outcomes of intentional variation effects (blur, crop, stains) and are documented in the occlusion manifest.

Extraction Prompt

The extraction model receives:
  • The generated photo
  • A JSON list of field names to look for
For each field, it returns:
  • value — what it read (or null)
  • confidence — 0.0 to 1.0
  • reasonnull, "blurry", "cropped", "occluded", or "not_in_frame"

Comparison Logic

Comparison is pure Python — no model involved:

Verification Result

Verified Generation

The generate_verified_photo() function combines generation + verification + retry:
  1. Generate photo
  2. Verify against schema
  3. If mismatches exist and retries remain, regenerate with emphasis on wrong fields
  4. Return result with verified: true/false, attempt count, verification details, and occlusion manifest