Skip to content

Latest commit

 

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 

Repository files navigation

360 Ghar — AI Property Search Assistant

India's AI & VR-Powered Real Estate Platform — Software Developer Intern Assignment


Live Demo

Open index.html in any browser. No build step required.


Setup

  1. Clone or download the repo
  2. Open index.html in Chrome (for voice search support)
  3. (Optional) Add your OpenRouter API key on line ~220 of the HTML: const API_KEY = 'sk-or-...'

Without a key: The app uses a smart local parser + heuristic match reasons. All UI features work fully. With a key: LLM query parsing and AI-generated property summaries are live.


Tech Stack

  • Framework: React 18 (via CDN, no bundler needed — pure portable HTML)
  • LLM API: OpenRouter — model meta-llama/llama-3.1-8b-instruct:free
  • Fonts: Playfair Display + DM Sans (Google Fonts)
  • No backend, no dependencies to install

Features Built

1. Natural Language Search

User types a plain-English query. The app sends it to an LLM which returns structured JSON filters (bhk, maxPrice, location, sunlight, school, metro, etc.). These drive filtering and ranking of property cards. Parsed filters are displayed as colour-coded tags.

2. Property Cards UI

10 mock properties with realistic Gurgaon sectors, prices, specs. Each card shows:

  • BHK type, area, sector, price, floor, facing direction
  • 360° VR badge + match % score badge
  • Match reason badge — heuristically generated from parsed filters (e.g. "Great natural light · Near DPS")

3. AI-Generated Property Summary (live LLM call)

Clicking a card opens a modal with a live generateMatchReason() call to OpenRouter. The prompt instructs the model to reference the user's original query and explain why this specific property matches. Result streams into a styled "AI Match Analysis" box.

4. Bonus Feature: Two bonus features shipped

Voice Input — Browser Speech Recognition API (works in Chrome/Edge). Mic button in the search bar; transcribed text fills the search field and auto-triggers search. Language set to en-IN for Indian accent accuracy.

Similar Properties Rail — Horizontal scrollable rail inside the property modal showing same-BHK properties. Acts as a "keep browsing" nudge without leaving the flow.

AI Follow-up Question — When the LLM detects genuine ambiguity (e.g. "Sector 50 or 57?"), it returns a followUpQuestion which surfaces as a dismissable banner above results.


Architecture Notes

index.html
  └── React App (single-file, no bundler)
       ├── PROPERTIES[]       — 10 mock JSON objects with Gurgaon data
       ├── callLLM()          — OpenRouter fetch wrapper
       ├── parseQuery()       — LLM → structured filters JSON
       ├── generateMatchReason() — LLM → property summary text
       ├── localParse()       — regex fallback when no API key
       ├── filterProperties() — filter + sort by matchScore
       └── Components
            ├── App            — state, search orchestration
            ├── PropertyCard   — grid card with match reason
            ├── PropertyModal  — detail view + AI summary + similar rail
            ├── FilterTag      — parsed filter pills
            └── SkeletonCard   — loading state

State is kept in React useState — no Redux, no context, no overkill. Modal opens on card click, closes on overlay click or ✕.


Prompt Design Notes

Query Parsing Prompt

The system prompt instructs the LLM to return only valid JSON — no preamble, no markdown fences. This was the most critical constraint: early tests with Mistral-7B returned explanatory text before the JSON, which broke JSON.parse(). Solution: explicit "Return ONLY valid JSON" instruction + text.replace(/\``json|```/g, '')` sanitisation as a safety net.

The JSON schema is spelled out field-by-field with types and examples inline (maxPrice: 80 or null (number in lakhs)). This reduces unit confusion — models often output "80 lakhs" as a string rather than 80 as a number without the explicit type hint.

Price normalisation is handled in the prompt itself: convert crores: 1Cr=100L. This way the filter logic always works in a single unit (lakhs).

What didn't work:

  • Asking the model to infer match scores — too slow and too inconsistent. Moved scoring to a simple heuristic on the frontend.
  • Using a single prompt for both parsing + summary — the outputs conflicted. Separated into two focused prompts.

Property Summary Prompt

Instructed to be "a knowledgeable friend, not a salesperson" and to stay under 55 words. Giving a word limit dramatically improved quality — without it, models pad to fill space. Injecting the user's original query string directly means the model references their actual words, not generic platitudes.

Model Choice: meta-llama/llama-3.1-8b-instruct:free

Fast, free, and instruction-following. For structured JSON output it performs reliably with tight prompts. Gemma-3-27B is stronger but slower on the free tier. For a prototype where latency matters for demo UX, Llama 3.1 8B wins.


Evaluation Criteria Notes

Criterion Approach
Vibe Coding Playfair Display serif + DM Sans sans, dark header, teal accent system, card hover lift, skeleton loading — feels intentional
AI Integration Two separate LLM calls with task-focused prompts; local fallback ensures demo always works
Code Quality Flat component tree, clear separation of data/logic/UI, no prop drilling beyond 2 levels
Product Thinking Match reason badge surfaces why, not just what; AI summary references the user's own words
Bonus Feature Voice input (real value on mobile) + similar properties rail + follow-up question

About

No description, website, or topics provided.

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages