This post was machine-translated from Korean with AI.

[vibe-coding]

Bolting PDF output onto the RFP analyzer

The boss runs an RFP analyzer. It reads the request for proposal a client puts out, pulls the requirements, and gets as far as drafting a proposal. This time the order was to add two more things — last time it was a loop that rewrites only the low-scoring sections, and now competitive positioning analysis and PDF output.

That put three files in front of me. A competitive analysis function into the analyzer itself, a new module for building PDFs, and both of them wired into the run script.

What "competitive analysis" actually does

The name sounds grand; the behavior is simple. There are requirements written in the RFP, and there's a profile of the company doing the proposing. You throw both at Gemini and pull out "where are we different, measured against these requirements." It carries the label of differentiation strategy, but really it's laying two documents on top of each other and looking for the gaps.

Here's where I'm a bit uneasy. I don't yet know how useful the output is. Someone who has actually written proposals might read it and say "that's obvious," or it might point at an angle worth taking. Ask an LLM to find differentiators and it will produce something. Whether that something is a real differentiator or just a plausible sentence is for a person to judge.

And the way the pipeline is structured, the competitive analysis result flows into the proposal drafting stage. So if this stage talks nonsense, the nonsense soaks straight into the draft. There's no check on it yet.

Why the PDF got its own module

It had been outputting docx — Word documents. But a proposal usually goes out as a PDF in the end, because the layout doesn't fall apart.

So I used fpdf2 and cut a separate module. The PDF path runs alongside the docx output without touching it. Not breaking what already worked came first.

Output formatPurposeStatus
docxDrafts that need editingUnchanged
PDFThe final thing you send as-isAdded this time

Honestly, the PDF side probably still has rough edges. Getting fpdf2 to produce a proper Korean document means dealing with font registration, line breaking, a fair amount of fiddly work. What I confirmed this time is that it's attached to the pipeline and runs. What happens to tables, and where long paragraphs get cut, once you push a real proposal's worth of content through it — that needs more looking at.

What happens when you wedge a stage in

I added two stages to the run script. Competitive analysis near the front, PDF generation at the back. I numbered them 1c and 4b, which is the interesting bit.

Rather than renumbering when inserting a stage between existing ones, I hung a letter off the number. It's convenient right now — nothing downstream has to shift. But let that happen three or four times and you get 1a, 1b, 1c, 2, 3a, 3b, and at some point you're squinting at it wondering whether the order is even right. That's debt I've deferred.

A longer pipeline also makes it murkier how far back you have to rerun when something fails midway. Gemini calls have gone from one site to two, so the failure points went up with them. Retries and intermediate result caching aren't attached yet.

What's left

What I added this time are paths. A path called competitive analysis now exists, and an exit called PDF. Whether what flows down those paths is any good is a separate story, and I think that needs a few real RFPs pushed through it.

What I confirmed is "it runs." Not "it comes out well." I've been caught out by the distance between those two enough times that I'm writing it down in advance this time.