Comebck Pakistan — Cohort 1 · Product Challenge
Make a more informed decision before spending Upwork Connects.
UpTally is a Chrome extension for Upwork freelancers. It reads the job page a freelancer is actively viewing, evaluates the opportunity for Connects ROI, and presents an Apply, Apply with Caution, or Skip recommendation. For opportunities that are not skipped, it also prepares a tailored proposal draft for the freelancer to review, edit, and submit manually.
Built by Squad Potohar for the Comebck Pakistan Cohort 1 Product Challenge.
- The problem
- Product flow
- Features
- Architecture
- Repository layout
- Install the extension
- Run the backend locally
- API reference
- Privacy and responsible use
- Research and product documentation
- Limitations and roadmap
- Team
- Contributing
- License
Upwork Connects have a real cost. Freelancers can spend them on jobs that are already crowded, stale, poorly scoped, underpriced, or associated with weak client signals. Manually qualifying each post and writing a relevant proposal also takes time away from better opportunities.
Our research repeatedly surfaced three needs: know whether a job is worth the Connects before applying, move while a client and post are active, and write a specific proposal without generic AI copy. UpTally is decision support for that moment. It does not guarantee an outcome, replace professional judgement, or submit work on a freelancer’s behalf.
flowchart LR
A["Open an Upwork job"] --> B["Set up profile once"]
B --> C["Select Analyze this job"]
C --> D["Read visible page text"]
D --> E["1. Extract facts"]
E --> F["2. Evaluate Connects ROI"]
F --> G{"Recommendation"}
G -->|"Skip"| H["Show score and reasoning"]
G -->|"Apply / Caution"| I["3. Generate proposal"]
I --> J["Review, edit, and submit manually"]
The server runs a three-stage Gemini pipeline. Extraction uses only facts explicit in the text. Evaluation produces the decision, 0–100 score, confidence, strengths, risks, and reasoning. Proposal generation is called only when the decision is not Skip.
- In-page extension UI on supported Upwork job, Find Work, and job-search routes.
- One-time freelancer profile, stored locally with
chrome.storage.local. Name, experience level, and at least one skill are required; portfolio links and bio are optional. - User-initiated analysis: the extension reads visible
document.body.innerTextonly after the freelancer chooses Analyze this job. Short or unloaded pages are stopped before an API request. - SPA-aware navigation: a mutation observer resynchronizes the widget as Upwork’s route or selected job changes.
- Structured job extraction: title, description, budget, experience level, skills, payment verification, proposal range/count, posting time, hire rate, total spend, and client country when present.
- Connects ROI assessment: decision, score, confidence, pros, cons, and concise personalized reasoning. The evaluation framework considers freshness, competition, client quality, budget realism, scope clarity, and the freelancer profile.
- Conditional proposal drafting: a personalized proposal and fit explanation are generated only for non-skip decisions.
- Human-in-control workflow: UpTally never applies or submits proposals. The freelancer retains final review and action.
- Resilient handling: JSON-only model prompts, backend parsing/recovery, loading states, escaped UI output, and actionable error states.
flowchart TB
subgraph Browser["Chrome / Upwork tab"]
CS["content.js\nWidget, profile and page text"]
BG["background.js\nMessage validation and request bridge"]
STORE["chrome.storage.local\nFreelancer profile"]
CS <--> STORE
CS -->|"ANALYZE_FULL_JOB"| BG
end
BG -->|"POST /api/analyze"| API
subgraph Backend["FastAPI backend"]
API["main.py"] --> EX["Extraction"]
EX --> EV["Evaluation"]
EV --> PR["Proposal if not Skip"]
EX & EV & PR --> GEM["Google Gemini API"]
end
API -->|"Structured result"| BG
BG --> CS
The Manifest V3 service worker accepts messages only from an Upwork page. The Gemini key remains on the backend; it is never embedded in the extension.
cohort-1-squad-potohar/
├── UpTally_Connects Budget Optimizer/
│ ├── extension/
│ │ ├── manifest.json # Manifest V3 configuration
│ │ ├── content.js # UI, profile and results
│ │ ├── background.js # Service worker / backend bridge
│ │ └── icon/ # Extension assets
│ └── backend/
│ ├── main.py # FastAPI endpoint and pipeline
│ ├── models.py # Request model and scoring framework
│ ├── prompts.py # Three Gemini prompts
│ ├── services.py # Gemini integration
│ ├── utils.py # Input and JSON handling
│ └── requirements.txt
├── extension-prototype/ # Earlier prototype
├── Research/findings-and-insights.md
├── srs.md # Product requirements and direction
├── LICENSE
└── README.md
| Layer | Technology |
|---|---|
| Browser extension | JavaScript, Chrome Extensions Manifest V3, content script, service worker, Chrome local storage |
| Backend | Python, FastAPI, Uvicorn, Pydantic |
| AI | Google Gemini via google-generativeai (gemini-3.1-flash-lite) |
| Configuration | python-dotenv and a backend .env file |
| Production service | Render-hosted FastAPI endpoint, configured in the extension |
- Chrome or another Chromium browser with extension developer mode
- An Upwork account and an accessible job page
- The deployed analysis service, or a local backend configured in
extension/background.js
-
Clone this repository.
git clone https://github.com/Comebck-Pakistan/cohort-1-squad-potohar.git cd cohort-1-squad-potohar -
Open
chrome://extensions. -
Enable Developer mode.
-
Select Load unpacked.
-
Open an Upwork job or supported Find Work/search route, select a job, and use the UpTally widget.
- Enter name, experience level, and skills; add portfolio URLs and a bio if helpful.
- Open the job details to assess.
- Select Analyze this job.
- Review the recommendation and extracted metadata.
- Edit any returned proposal so it accurately represents you.
- Submit manually on Upwork only if you decide to proceed.
The extension currently targets its deployed Render URL in background.js. For local development, replace that URL with your local server URL and add the required local host permission in the manifest. Keep local endpoint changes and API keys out of commits.
cd "UpTally_Connects Budget Optimizer/backend"
python -m venv .venvActivate the virtual environment:
# Windows PowerShell
.\.venv\Scripts\Activate.ps1# macOS / Linux
source .venv/bin/activateInstall dependencies, then create backend/.env:
pip install -r requirements.txtGEMINI_API_KEY=your_google_ai_api_keyStart the server:
uvicorn main:app --reload --host 127.0.0.1 --port 8000Verify it:
curl http://127.0.0.1:8000/{"status":"awake"}After editing extension files or its manifest, use Reload on chrome://extensions and refresh the Upwork tab.
Returns the service health state:
{"status":"awake"}Runs extraction, evaluation, and—unless the evaluation is Skip—proposal generation.
{
"pageText": "Visible text from the currently opened Upwork job page",
"profile": {
"name": "Ayesha Khan",
"experienceLevel": "Intermediate, 4 years",
"skills": ["React", "Python"],
"portfolio": ["https://example.com"],
"bio": "Frontend developer focused on product interfaces."
}
}Successful responses return:
{
"success": true,
"data": {
"profile": {},
"extraction": {},
"evaluation": {},
"proposal": {},
"proposalError": null
}
}For a Skip decision, proposal is null. A proposal-generation error does not discard a completed extraction or evaluation.
- The extension operates on the job page the user has actively opened; it does not implement background crawling, bulk collection, or automatic applications.
- Analysis starts only after the user selects Analyze this job.
- The profile stays in browser-local Chrome storage. When analysis is requested, the visible page text and profile are sent to the configured backend, which calls Gemini.
- Keep
GEMINI_API_KEYinbackend/.env. The repository ignores.env; never commit it. - Results are assistance, not a guarantee of job quality, client intent, hiring outcome, or platform-policy compliance.
Use UpTally responsibly and in accordance with Upwork’s applicable terms and policies. The freelancer remains responsible for every proposal and action taken.
- Research findings and insights: outreach, interviews, polls, Reddit feedback, and competitor observations.
- Software Requirements Specification: problem framing, personas, requirements, decision-engine direction, and future phases.
- Prototype README: the earlier product and technical iteration.
The SRS captures the intended evolution of the product. The implementation in UpTally_Connects Budget Optimizer/ is the source of truth for the current release and setup.
- Supported routes are limited to the Upwork paths detected by the content script.
- UpTally relies on visible page text, so layout changes, incomplete loading, or missing information can reduce extraction quality.
- Evaluation is model-generated and should be reviewed critically; it is not a guaranteed forecast.
- There is no automated test suite in this repository at present.
- The current release does not include automatic submission, outcome tracking, account sync, or bulk job processing.
The SRS identifies possible future work: a more deterministic decision engine, richer scoring signals, outcome logging, recalibration from observed outcomes, additional freelance platforms, and team capabilities. These are roadmap items, not claims about the current release.
Squad Potohar
| Member | GitHub |
|---|---|
| Muhammad Rafay | @itsrafay03 |
| Azhar Soomro | @Azharaliii |
| Anas Khan | @anasAnonymous |
| Muhammad Eesa Qamar | @Eesa-cyber |
| Zaid Haris Saigal | @Zaidharissheikh |
Use a short-lived branch and pull request for each change:
git checkout main
git pull origin main
git checkout -b your-name/short-description
# make and verify your change
git add .
git commit -m "Briefly describe the change"
git push -u origin your-name/short-descriptionExplain the user-facing impact in the pull request, request a squadmate’s review, and merge after approval. Never commit secrets, .env files, virtual environments, or generated caches.
Licensed under the MIT License. Copyright © 2026 Comebck Pakistan.