Documentation

Build on the analysis.

HomeLens AI is one Next.js app. The website, the demo and the analysis endpoint ship together, with no separate backend.

Overview

The app ships Rithik’s anonymized artifacts as static JSON and runs a TypeScript port of his masking rules, complaint-phrase dictionary and TF–IDF logistic-regression model inside a route handler. A parity test checks the port against the Python model’s outputs.

POST /api/analyze

Scores one review. Send JSON with a text string of 3–5,000 characters. Anything else returns 400.

# request
curl -s -X POST https://homelensai.vercel.app/api/analyze \
  -H 'content-type: application/json' \
  -d '{"text":"They never showed up and overcharged me."}'

Response

The actual response for the first demo example, trimmed. management_attention is true when the review risk meets the operating threshold; it is null when the model is unavailable and only dictionary signals remain.

{
  "model": {
    "name": "TF–IDF Logistic Regression",
    "threshold": 0.585,
    "available": true,
    "is_primary": false,
    "note": "Scored with the TF–IDF Logistic Regression model shipped in artifacts/ (the notebook's DistilBERT is not bundled with the web app)."
  },
  "risk_probability": 0.9629,
  "operating_threshold": 0.585,
  "management_attention": true,
  "primary_aspect": "Pricing / Billing",
  "detected_aspects": [
    "Pricing / Billing",
    "Timeliness",
    "Workmanship"
  ],
  "evidence": {
    "index": 0,
    "sentence": "The technician was three hours late, charged more than the quote, and the repair failed again two days later.",
    "aspect": "Pricing / Billing",
    "matched_phrases": {
      "Workmanship": [
        "repair failed"
      ],
      "Timeliness": [
        "hours late"
      ],
      "Pricing / Billing": [
        "charged more"
      ]
    },
    "risk_probability": 0.9629,
    "has_dictionary_match": true
  },
  "recommended_action": "Review estimate accuracy, change-order approvals, and fee disclosure.",
  "…": "sentences[], weights, matched_phrases, masking_applied, disclaimer"
}

Risk tiers

Provider tiers are relative to this corpus. They rank providers; they are not probabilities of any outcome.

Stable        Score below 50  (126 providers)
Watch         Score 50–75  (75 providers)
Elevated      Score 75–90  (47 providers)
High concern  Score 90 and above  (6 providers)

Data files

Generated by scripts/export_frontend_data.py from artifacts/ and app/risk_logic.py. Never edit them by hand; CI fails if they are stale.

frontend/data/providers.json   anonymized provider scores, tiers, yearly history
frontend/data/aspects.json     8 aspects: lift, frequency, keywords, actions
frontend/data/overview.json    KPIs, tier counts, service groups, model metrics
frontend/data/facts.json       validated notebook facts (corpus size, splits)
frontend/data/risk_config.json masking rules and phrase dictionary
frontend/data/tfidf_model.json TF–IDF vocabulary, IDF and coefficients

Run locally

cd frontend
npm install
npm run dev        # http://localhost:3000
npm run build && npm start

Optional environment variables: NEXT_PUBLIC_CONTACT_EMAIL, NEXT_PUBLIC_REPO_URL, NEXT_PUBLIC_SITE_URL. None are required.

Testing

npm test           # 14 parity tests vs data/golden.json (Python outputs)
npm run typecheck

Refresh the data after rebuilding artifacts: python scripts/build_artifacts.py && python scripts/export_frontend_data.py.

Responsible-use notes are on the Responsible AI page.

Try the endpoint in the browser.