← AI Engineering / Case study 02
AI Sales Assistant.
The form that fills itself in. Clients type or simply talk, AI fills in the answers, and every answer shapes the next question. Behind it, the team gets an AI brief, and after the meeting a tailored offer is one click away from the client.
- Role
- Solo build: product, UX, backend, AI, deployment
- Built for
- Small businesses that need details before they can quote
- Year
- 2026
- Status
- Live on Vercel, in real use
Project presentation · use ← → or swipe
The problem
Long forms scare clients away, and short ones leave the business chasing details by email. Many clients don't even know what they need yet. So I built a form that feels like a conversation, and the whole path behind it: from the first answer to a sent offer.
How it works
- The client fills in a smart form. Every answer decides the next question: a restaurant gets questions about takeaway and reservations, a shop about products and shipping, someone just starting out gets a shorter, friendlier path. 6 business types and 37 steps, but each client sees only 15–25.
- Or simply says what they need. Clients can type or talk in their own words. AI fills in the matching answers and the form skips everything it already knows.
- The team gets an AI brief. Each lead is validated and saved first, then AI writes a short summary with the questions to ask at the meeting.
- They meet and talk it through. In a private back office (Google sign-in), the team adds meeting notes and prices.
- AI drafts the offer. A RAG offer writer finds the services that fit, writes a tailored offer and turns it into a PDF. Texts, photos, colours and fonts can be finished by hand.
- One click to send. AI writes a personal email, code builds the designed layout, and the client gets a private link to their offer.
Smart, but never guessing
The AI writes, but code decides what's true. Every guardrail that matters is checked in Python, not just asked for in a prompt.
Read more
Only what the client said. The fill-in model is built at runtime from the form's own questions (a Pydantic model used as a structured output), so the AI can only pick options that exist. Every answer also needs a quote, and code drops any answer whose quote isn't in the client's text.
Never invents a price. An early test made up two prices. Now every amount must appear in the team's own notes or edits; otherwise the offer says "Price to confirm".
Budgets are always asked. "Maybe 100 euro" once turned into a price range, so money was removed from what the AI may fill in.
A pipeline, not an agent. The offer writer is a fixed sequence (read the lead, retrieve, write, check, render), so the AI can never skip the price check.
Under the hood
- Branching engine. Questions are data, each with a condition on earlier answers. One small engine finds the next question and remembers the path, so Back always goes back the same way.
- Structured outputs. A Pydantic model is built from the form's own questions while the app runs, so the AI can only choose answers that exist. Each answer needs a quote, and code checks the quote is really in the client's text.
- Selective RAG. The agency knowledge lives in one Markdown file, embedded and stored in Pinecone. Only the services are searched per client; the team, results and offer style are always included.
- Few-shot style memory. When the team rewrites AI text, the before and after are saved. The latest five go into the prompt as examples, so the AI learns the brand voice over time, without fine-tuning.
- A fixed pipeline, not an agent. The offer is always made in the same steps: find the services, write, check, design, PDF. The check only keeps prices the team wrote themselves; anything else becomes "Price to confirm".
- Brand style kept out of the AI. Each offer has its own colours and fonts, checked in code and turned into CSS. The AI never touches them, and the preview and the PDF always match.
More technical details
Save first, AI after. Pydantic checks each lead, it is saved straight away, and the AI brief is added later by a background task, so the client never waits and no lead is lost.
Google Drive instead of a database. The server copies a client's files to a temporary workspace, then saves back only what changed.
Google sign-in, built by hand. OAuth 2.0 without a library: a random check value against fake logins, a signed cookie that ends when Google's login ends, only the email permission, and a list of allowed team emails as a second lock.
Private offer links. Each client gets a secret link that search engines can't find and that can be switched off at any time.
Photos with AI vision. The AI sees small thumbnails to decide which photo goes where; code removes unknown or repeated picks.
How I built it
Built with Claude Code as my pair programmer, plus a custom Claude Code skill (/wrap-up) that logs every technical decision as I go. I made the product, architecture and model decisions.
Difficulties solved
- A sync that deleted a photo: an empty temporary desk looked like "the user deleted these files". Deletes are now explicit, never inferred.
- Two clocks: the session cookie renewed on every click, Google's sign-in didn't. Both now stop together, with a warning 5 minutes before.
- Serverless limits: no Chrome and a small upload cap. The PDF is the browser's print of the offer page, and photos are shrunk in the browser, so saves went from ~20 s to ~7 s.
- Files served by accident: found by probing the live site; now only a whitelist of files is public.
- My own design assumption: a confirmation screen felt like re-reading, so I removed it after testing.
Evaluation
Models were chosen by tests, not by feel. The same 8 test clients (English and Dutch, people just starting out, and a prompt-injection attempt) ran through two models. The smaller one guessed shop questions for a salon; gpt-4.1-mini got them right with no invented budgets or timing. A client who says "I have nothing yet" skips about 6 questions.