This is a submission for the Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle.
What I Built
Freelancing has a tax nobody invoices. Before a client pays you a rupee, you read their brief twice, google the company, dig through your old projects for something that fits, guess at the scope, and then write the proposal. That can eat a whole evening. Sometimes you lose the bid anyway.
FreelanceCanvas is my attempt to shrink that evening. You paste a client brief (or drop in a PDF) and it gives you back:
- a quick snapshot of the client
- the past projects of yours that fit the job best
- a full proposal written by Gemma, running on my own machine
- a three-milestone schedule with a price estimate
- a short risk list
- an audio script you can listen to later
Code
TejasRawool186
/
FreelanceCanvas
Autonomous AI Workstation for Solo Developers, Consultants & Freelancers
FreelanceCanvas 🎨💼
Visual Collaborative AI Workstation for Solo Developers, Consultants & Freelancers
"Brainstorm visually. Research faster. Close clients while you touch grass."
🌟 Overview
FreelanceCanvas is an interactive, visual-first whiteboard and autonomous AI workspace tailored for freelancers, solo developers, and technical consultants. Combining playful neo-brutalist collaborative canvas boards with local vector RAG and AI synthesis, it automates the most time-consuming, unbillable freelance chores:
- Visual Brainstorming & Whiteboarding: Interactive draggable sticky notes, phase workflows, and real-time team collaboration canvas.
- RFP & Brief Ingestion: Drops in client PDFs, Upwork project descriptions, or discovery call transcripts.
- Client Reconnaissance: Autonomous background search (SerpApi) on the client's company, tech stack, and market footprint.
- Portfolio & Skills Matching: Local vector RAG (Qdrant) searching your personal past projects, case studies, and rate cards.
- Scope & Proposal Synthesis: Local LLM reasoning (Gemma via Ollama) generating a complete proposal, Work Breakdown Structure (WBS), milestone…
To run it:
cp .env.example .env
pip install -r requirements.txt
cd frontend && npm install && cd ..
python scripts/seed_profile.py
python scripts/run_all.py
Then open http://localhost:5173. You also need Ollama running with a Gemma model pulled.
How I Built It
The flow is simple enough to draw in text:
brief or PDF -> client lookup -> portfolio search -> Gemma -> proposal, milestones, risks -> audio script
| Part | What I used |
|---|---|
| Frontend | React, TypeScript, Vite |
| Backend | FastAPI, async SQLAlchemy, SQLite |
| Model | Gemma (gemma3:1b by default) through Ollama |
| Portfolio search | Qdrant in local mode |
| Client lookup | SerpApi (optional) |
| Audio | ElevenLabs (optional) |
When you submit a brief, FastAPI saves it and hands the real work to a background task, so the UI never freezes while the model thinks. That task looks up the client, searches my portfolio for similar past work, stitches everything into one prompt, and sends it to Ollama. The call itself is tiny:
payload = {
"model": settings.OLLAMA_MODEL,
"prompt": prompt,
"system": system,
"stream": False,
}
resp = await client.post(f"{settings.OLLAMA_BASE_URL}/api/generate", json=payload)
Because the prompt includes the matched case studies, the proposal talks about work I have actually done instead of producing the usual "we are a passionate team" filler.
One thing I care about: the app should never die because a key is missing. No SerpApi key? You get a basic client profile. No ElevenLabs key? You get the audio script as a text file. Ollama down or too slow? You get a structured proposal template instead of an error screen. It's not glamorous, but it means the whole loop runs on a laptop with no internet.
What Isn't Finished
I'd rather say this up front than have you find it in the code.
- Portfolio matching uses lightweight hashed vectors right now, not real embeddings. Swapping in
nomic-embed-textthrough Ollama is the next thing I want to do. - Milestones, prices and risks come from a fixed three-phase template. I don't trust a 1B model with numbers yet, so Gemma writes the proposal text and the template handles the money.
- Login is local only. There are no real multi-user accounts.
- Canvas notes live in the browser and disappear on refresh.
Why Open Models Matter Here
Client briefs are often under NDA. Sending one to a hosted API feels wrong to me, and running Gemma locally means the proposal text never leaves my machine.
Cost matters too. A freelancer sends a lot of bids and wins a few. If every bid costs API money, the lost ones sting. With a local model, a lost bid costs electricity.
And it's swappable. Changing OLLAMA_MODEL in the .env file gives you a different model without touching any code. A bigger Gemma, or something else, is one line away.
Who Would Pay
Solo developers, consultants and tiny agencies who write proposals every week. I plan to turn this into a subscription product at [PRICE] a month, with the local model as the private default.
What I Learned
Small models write decent prose and unreliable numbers. I spent more time deciding what the model should not do than what it should. Letting it write the narrative while a template owns the pricing made the output far more consistent. The next step is asking Gemma for milestones as JSON and validating it before anything reaches the screen.
Prize Categories
Gemma: the proposal engine runs on gemma3:1b through Ollama, and the demo shows it at [TIMESTAMP].
If you freelance, I'm curious which part of a proposal eats your time: the research, the scoping, or the writing? Tell me in the comments. Issues and PRs are welcome on GitHub.
Top comments (0)