Skip to content

[Pipeline C] Form generation: generate endpoint, fill task, retrieval endpoints (#552) - #677

Open
abhishek-8081 wants to merge 1 commit into
fireform-core:development-approach-cfrom
abhishek-8081:issue-552-generate-endpoint
Open

[Pipeline C] Form generation: generate endpoint, fill task, retrieval endpoints (#552)#677
abhishek-8081 wants to merge 1 commit into
fireform-core:development-approach-cfrom
abhishek-8081:issue-552-generate-endpoint

Conversation

@abhishek-8081

Copy link
Copy Markdown
Collaborator

Part 2 of #552 (part 1 added the Form model + migration). This builds the full form
generation flow — generate, fill, and retrieve.

What it does

A user picks the ready templates on the readiness screen and submits them. This PR takes that
request, generates a filled PDF (and a JSON version) for each template by reading values
straight from the incident's contract, and lets the user poll for progress and download the
results. No LLM runs at this stage — filling is pure lookup and draw, so a batch finishes in
seconds.

Endpoints

  • POST /forms/generate — validates the incident, checks each requested template's
    readiness, and splits them into queued (ready) and skipped (not ready, with a reason).
    Creates a batch + one Form row per queued template, dispatches the fill task, and returns a
    BatchGenerateResponse. template_ids is required here; auto-selecting every ready template
    is Batch form generation - API Contracts #554.
  • GET /forms/batch/{batch_id} — batch status (counts + per-form status), derived on the
    fly from the Form rows (no Batch table, per the agreed scope).
  • GET /forms/{form_id} — the form record.
  • GET /forms/{form_id}/pdf — the generated PDF.
  • GET /forms/{form_id}/json — the agency-field-mapped JSON.

The fill task

For each form in the batch, independently:

  • Resolve every template field's value from the incident contract (reuses resolve() from
    extraction_readiness).
  • Draw the placed fields onto a ReportLab overlay at their layout coordinates, then merge that
    overlay onto the template PDF with pypdf.
  • Save the PDF under data/forms/generated/{form_id}.pdf, build the mapped JSON, and compute
    the field-mapping summary (reuses gaps_for()).

Each form is wrapped in its own try/except — if one form fails, it's marked failed and the
batch carries on, so a single bad form never sinks the whole job.

Reuse and structure

Reuses resolve() and gaps_for() from the readiness engine, and mirrors the extraction
service/worker/task split rather than the legacy fill path. Adds reportlab + Pillow.

Verification

  • 485 tests pass (454 baseline + 31 new). ruff clean.
  • Verified the coordinate drawing visually: values land on their boxes with the correct
    left/center/right alignment and no vertical flip (bottom-left origin, matching ReportLab).

Three API-surface calls — implemented this way, open to your thoughts

The contract doesn't fully spell these out, so I made a call on each. They're implemented and
working as described below — happy to change any if you'd prefer a different approach:

  1. GET /forms/{form_id}/pdf: a failed form returns 500 (PDF_GENERATION_FAILED); one not ready
    yet returns 202 with a retry hint.
  2. output_format is accepted but not honored yet — the fill always writes both PDF and JSON.
    Honoring pdf-only / json-only felt like Batch form generation - API Contracts #554 scope.
  3. BatchStatus reads "completed" even when some forms failed (the per-form statuses still show
    exactly which ones), matching the per-form isolation we agreed on.

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.

2 participants