2 min read

Proposals that sound like you, with retrieval

How BidCraft grounds every Upwork proposal in the freelancer's own past work, using Mistral embeddings, pgvector in Supabase and a streaming FastAPI endpoint.

  • RAG
  • pgvector
  • FastAPI

Generic AI proposals lose. Clients read dozens of them, and the ones that read like a template get skipped. A good bid proves you can do the job by pointing to work you have already done. BidCraft, the proposal generator I built the backend for, does that automatically for every new job post.

Start with the evidence

Each freelancer adds reference projects. The backend embeds them with Mistral and stores the vectors in Supabase Postgres using pgvector. Keeping the vectors next to the rest of the data meant one database, one set of credentials and ordinary SQL for everything else.

When a job post comes in, the API embeds it and ranks the freelancer’s past work by cosine distance. The top matches become the evidence the proposal is built around.

Scope retrieval like it is a permission check

Similarity search is scoped to the user and to the selected profile. That is not an optimisation, it is correctness. A freelancer with a “web development” profile and a “data engineering” profile should never get one profile’s projects in the other’s bids, and nobody should ever see another user’s work. The filter belongs in the query itself, not in the code after it.

Assemble the prompt from parts the user controls

The retrieved projects are combined with stored memory (facts about the freelancer worth repeating) and the user’s own editable prompts. Making prompts editable was one of the best decisions on the project. Freelancers know their voice better than any default, and they can tune it without waiting on a developer.

Stream it

Bids are streamed token by token from a FastAPI endpoint. Total generation time is the same, but watching the proposal appear makes the wait feel far shorter, and the user can start reading straight away.

Screening questions are different. Those answers come back as structured output, so the frontend can place each answer next to its question without parsing free text.

Make revisions cheap

Nobody sends a first draft. Bids are versioned, users can ask for revisions, and the history reads like a chat. Keeping every version means a user can go back to the one they liked instead of trying to regenerate it.

Ship it small

The backend is packaged for AWS Lambda with Mangum, which suits bursty traffic: lots of activity when someone is applying for jobs, nothing for hours in between.

The takeaway

Most of the quality in a RAG product comes from what you retrieve and how you scope it, not from the model call at the end. Get the evidence right, let the user own the voice, and stream the result.

More detail is on the BidCraft project page.

Case studyBidCraftStreams tailored Upwork proposals grounded in a freelancer's own past projects, retrieved by vector similarity in Postgres.
Home/
Work/work
About/about
Notes/notes
Contact/contact
HaxMindAI systems
AI Sales Call AnalysisAutomation
FPL FarmsWeb platforms
VYVA Voice CompanionVoice agents
BidCraftAI systems
Call AI AutomationVoice agents
Automated CV / LinkedIn Profile GeneratorAutomation
Restaurant Voice-Ordering BackendVoice agents
UIT University WebsiteWeb platforms
Copy email addressmhassamzahid@gmail.com
Download CVPDF
Open GitHub@mhassamzahid
Ask about HassamQuick answers
Toggle light / dark themeTheme