Skip to content
goutham.dechineni

Freelance project

Job Fraud Detector

Problem
Fake job postings look like real ones and cost applicants money and personal data; a job seeker has no quick way to check a posting before applying.
Approach
A posting is checked against a crowd-reported blacklist, scored by a fast text classifier that shows which words drove its verdict, then reviewed by Gemini with a strict output schema; Gemini can overrule the classifier only when it is more than 70% confident.
Result
A FastAPI web app that checks a URL or pasted text, keeps a history of checks in Postgres, and drafts an ATS-friendly resume for postings that look legitimate.
My role
Freelance AI engineer (2024–2025). Built the system end to end for a client: backend, classifier, LLM integration and UI.
Stack
  • Python
  • FastAPI
  • BeautifulSoup
  • scikit-learn
  • Gemini
  • Pydantic structured output
  • PostgreSQL
  • SQLAlchemy + Alembic
  • python-docx / WeasyPrint

01

Architecture

  1. Job URL or text: the user pastes a link to a posting or the posting's text.
  2. Crowd blacklist: the posting is first checked against postings other users have reported as fraudulent, the cheapest check of all.
  3. Scraper: for a URL, the posting's text is fetched from the page; pasted text skips this step.
  4. SGD classifier: a CountVectorizer bag of words feeds a linear classifier trained with SGD. It is fast, and its top-weighted words are shown as the explanation for its verdict.
  5. Gemini verifier: Gemini reviews the posting and must answer in a fixed Pydantic schema that includes its verdict and its confidence, so the reply can be checked and used by the code rather than parsed out of free text.
  6. Verdict: the classifier's call stands unless Gemini disagrees with more than 70% confidence; only then does the LLM override it.
  7. ATS resume: for postings judged legitimate, the app can generate an ATS-friendly resume for that job.
  8. Postgres keeps the history of every check.

02

Key decisions

  • The LLM overrides the classifier only above 70% confidence

    The classifier is fast and predictable, but it only sees word counts; Gemini can catch context it misses. Letting Gemini overrule only when it is confident keeps a hesitant LLM from flipping a sound verdict. The cost is that the 70% threshold is a fixed choice, and an LLM's own confidence is not well calibrated.

  • A simple linear text model with visible top words

    CountVectorizer with an SGD-trained linear classifier is cheap to train and run, and shows exactly which words pushed a posting towards fraud, which a user can check. The cost is that it ignores word order and context, which is why the LLM review sits behind it.

  • Schema-checked LLM output

    Requiring a Pydantic schema means a malformed or off-topic reply fails validation instead of silently changing the verdict. The cost is extra failure handling: a reply that does not validate is a separate case the code has to handle.

03

Results

  • Checks a posting by URL or pasted text through four layers: blacklist, scraper, classifier and LLM review.
  • Every verdict comes with an explanation: the classifier's top words, plus Gemini's structured assessment.
  • Keeps a history of checks in Postgres, and drafts an ATS-friendly resume for postings judged legitimate.

04

What I'd do next

  • Measure how often Gemini overrides the classifier and whether those overrides are right, to set the 70% threshold from data.
  • Replace the bag-of-words model with a small fine-tuned transformer and compare both on a held-out set.
  • Add moderation to the crowd blacklist so a single false report cannot mark a real posting as fraud.