MD Doc updates
This commit is contained in:
49
docs/API.md
49
docs/API.md
@@ -40,6 +40,7 @@ Reliance Digital, Vijay Sales, Tata CLiQ, Poorvika, Sangeetha, Vasanth & Co and
|
|||||||
| GET | [`/api/elec/products`](#get-apielecproducts) | Product list with filters |
|
| GET | [`/api/elec/products`](#get-apielecproducts) | Product list with filters |
|
||||||
| GET | [`/api/elec/products/{product_id}`](#get-apielecproductsproduct_id) | Full product detail |
|
| GET | [`/api/elec/products/{product_id}`](#get-apielecproductsproduct_id) | Full product detail |
|
||||||
| GET | [`/api/elec/products/{product_id}/price-history`](#get-apielecproductsproduct_idprice-history) | Price over time per platform |
|
| GET | [`/api/elec/products/{product_id}/price-history`](#get-apielecproductsproduct_idprice-history) | Price over time per platform |
|
||||||
|
| GET | [`/api/elec/products/{product_id}/recommendations`](#get-apielecproductsproduct_idrecommendations) | Similar or better-rated products to suggest, and other variants |
|
||||||
| GET | [`/api/elec/sites`](#get-apielecsites) | The retail platforms read |
|
| GET | [`/api/elec/sites`](#get-apielecsites) | The retail platforms read |
|
||||||
|
|
||||||
### `GET /api/health`
|
### `GET /api/health`
|
||||||
@@ -103,12 +104,15 @@ curl "http://31.97.228.132:8000/api/elec/products?category=mobiles&brand=samsung
|
|||||||
"best_price": "42999.00",
|
"best_price": "42999.00",
|
||||||
"best_price_site": "Reliance Digital",
|
"best_price_site": "Reliance Digital",
|
||||||
"platform_count": 5,
|
"platform_count": 5,
|
||||||
"image_url": "https://img-prd-pim.poorvika.com/product/Samsung-Galaxy-A56-5G-Awesome-Graphite-Main.png"
|
"image_url": "https://img-prd-pim.poorvika.com/product/Samsung-Galaxy-A56-5G-Awesome-Graphite-Main.png",
|
||||||
|
"rating": 4.5,
|
||||||
|
"rating_count": 1224
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
`total` is the full match count; use `limit`/`offset` to page. Some extra fields (`brand_slug`,
|
`total` is the full match count; use `limit`/`offset` to page. `rating` / `rating_count` are the same
|
||||||
|
overall rating as the product detail's `rating.value` / `rating.count` (`null` when no platform publishes one). Some extra fields (`brand_slug`,
|
||||||
`family`, `model`, `processor`, `sold_by_tn_retailer`, `updated_at`, ...) are also present.
|
`family`, `model`, `processor`, `sold_by_tn_retailer`, `updated_at`, ...) are also present.
|
||||||
|
|
||||||
### `GET /api/elec/products/{product_id}`
|
### `GET /api/elec/products/{product_id}`
|
||||||
@@ -160,6 +164,46 @@ curl http://31.97.228.132:8000/api/elec/products/551/price-history
|
|||||||
```
|
```
|
||||||
Oldest first, one row per observation per platform.
|
Oldest first, one row per observation per platform.
|
||||||
|
|
||||||
|
### `GET /api/elec/products/{product_id}/recommendations`
|
||||||
|
```bash
|
||||||
|
curl http://31.97.228.132:8000/api/elec/products/551/recommendations
|
||||||
|
```
|
||||||
|
| Parameter | Meaning |
|
||||||
|
|---|---|
|
||||||
|
| `type` | `similar` (default) or `better_rated` |
|
||||||
|
| `limit` | 1–12, default 6 |
|
||||||
|
| `tn_only` | `true` to suggest only products sold by a Tamil Nadu retailer |
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"product_id": 551, "type": "similar",
|
||||||
|
"items": [
|
||||||
|
{ "product_id": 560, "brand": "Samsung", "display_name": "Samsung Galaxy A37 (8GB RAM, 256GB)",
|
||||||
|
"ram_gb": 8.0, "storage_gb": 256.0, "image_url": "https://…", "best_price": "52999.00",
|
||||||
|
"best_price_site": "Croma", "rating": 4.7, "rating_count": 648,
|
||||||
|
"basis": "similar", "reason": "Similar specs · 4.7★ vs 4.5★" }
|
||||||
|
],
|
||||||
|
"other_variants": [
|
||||||
|
{ "product_id": 552, "display_name": "Samsung Galaxy A56 (8GB RAM, 128GB)",
|
||||||
|
"ram_gb": 8.0, "storage_gb": 128.0, "best_price": "38999.00" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Notes:
|
||||||
|
- Same category, in stock, never the product itself. Other RAM/storage variants of the same model are left
|
||||||
|
out of `items` and listed in `other_variants` instead. A laptop variant must also have the same processor
|
||||||
|
(other CPUs of one model line are separate products).
|
||||||
|
- **Price limit:** every item's best price is within ±30% (`similar`) or ±20% (`better_rated`) of this
|
||||||
|
product's. A product with no price of its own gets no limit.
|
||||||
|
- `similar` is ranked by `0.60 × spec similarity + 0.25 × rating + 0.15 × price closeness`. The rating is weighted by
|
||||||
|
how many people rated it, so 5.0★ from 3 ratings does not beat 4.4★ from 2,000.
|
||||||
|
- `basis` is `similar`, or `top_rated` when fewer than 3 similar products exist and the best-rated in the
|
||||||
|
category fill the list. `rating` is `null` when no platform publishes one.
|
||||||
|
- `better_rated` lists only products rated higher than this one (any rated product if this one has no
|
||||||
|
rating) by at least 5 people, best weighted rating first; ties go to the product whose reviews are more
|
||||||
|
positive. `basis` is `better_rated` and `reason` reads e.g. `"4.5★ vs 4.1★ · 2,300 ratings"`. Often
|
||||||
|
empty: few products have 5+ ratings yet.
|
||||||
|
- See [RECOMMENDATIONS.md](RECOMMENDATIONS.md) for the full design.
|
||||||
|
|
||||||
### `GET /api/elec/sites`
|
### `GET /api/elec/sites`
|
||||||
```bash
|
```bash
|
||||||
curl http://31.97.228.132:8000/api/elec/sites
|
curl http://31.97.228.132:8000/api/elec/sites
|
||||||
@@ -213,6 +257,7 @@ The same catalogue is an MCP server (Streamable HTTP transport) at
|
|||||||
| `search_products` | `query`, `category`, `brand`, `max_price`, `min_price`, `limit` (all optional, `limit` 1–100, default 20) | `total` and products: id, name, RAM/storage, best price and platform, platform count, image URL |
|
| `search_products` | `query`, `category`, `brand`, `max_price`, `min_price`, `limit` (all optional, `limit` 1–100, default 20) | `total` and products: id, name, RAM/storage, best price and platform, platform count, image URL |
|
||||||
| `get_product` | `product_id` | Offers per platform, specs, `image_urls`, rating, reviews |
|
| `get_product` | `product_id` | Offers per platform, specs, `image_urls`, rating, reviews |
|
||||||
| `price_history` | `product_id` | Every observed price per platform |
|
| `price_history` | `product_id` | Every observed price per platform |
|
||||||
|
| `recommend_products` | `product_id`, `kind` (`similar` or `better_rated`, default `similar`), `limit` (1–12, default 6) | Alternatives with a reason each, and the model's other variants |
|
||||||
|
|
||||||
Images are returned as **URLs** on the retailers' own image servers; nothing is re-hosted. Only part
|
Images are returned as **URLs** on the retailers' own image servers; nothing is re-hosted. Only part
|
||||||
of the catalogue has an image.
|
of the catalogue has an image.
|
||||||
|
|||||||
195
docs/RECOMMENDATIONS.md
Normal file
195
docs/RECOMMENDATIONS.md
Normal file
@@ -0,0 +1,195 @@
|
|||||||
|
# Recommendation System — Requirements
|
||||||
|
|
||||||
|
**Status: Phases 1 (Similar products) and 2 (Better rated alternatives) are built, with a hard price limit. Phase 3 is not started.** The decisions in §9 use the suggested defaults.
|
||||||
|
|
||||||
|
This document describes what we want from a product recommendation feature, where it will appear, and how it can work using the data the project already has. It is meant to be read before we decide what to build.
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| **Goal** | Show "You may also like" products under a product's Ratings & Reviews |
|
||||||
|
| **Where** | Product popup (`ProductModal`), plus a tool for AI assistants (MCP) |
|
||||||
|
| **Main building blocks** | Product embeddings (already stored), ratings, review sentiment, price |
|
||||||
|
| **New data needed?** | Not for Phases 1 and 2. Phase 3 needs customer accounts and tracking |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. What we want
|
||||||
|
|
||||||
|
When someone opens a product and reads its ratings and reviews, they should see a short list of **other products worth looking at**: products that are similar, well rated and priced about the same.
|
||||||
|
|
||||||
|
Example: someone looking at a 4.1★ phone at ₹18,000 sees three or four similar phones around the same price, including one rated 4.5★ by 2,300 buyers.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Where it shows up
|
||||||
|
|
||||||
|
| Place | What appears |
|
||||||
|
|---|---|
|
||||||
|
| **Product popup, directly below Ratings & Reviews** | A "Similar products" row of 4–6 small cards: image, name, best price, ★ rating, review count |
|
||||||
|
| **Same popup, second tab** | "Better rated alternatives": same category and price range, higher rating |
|
||||||
|
| **MCP (AI assistants)** | A new tool `recommend_products(product_id)` so the assistant can suggest alternatives |
|
||||||
|
| **Product cards on the Home page** | A small ★ rating badge with the rating count ✅ built |
|
||||||
|
|
||||||
|
Rough layout inside the product popup:
|
||||||
|
|
||||||
|
```
|
||||||
|
┌────────────────────────────────────────────┐
|
||||||
|
│ Ratings & Reviews │
|
||||||
|
│ 4.1 ★★★★☆ (1,240 ratings) │
|
||||||
|
│ … reviews … │
|
||||||
|
├────────────────────────────────────────────┤
|
||||||
|
│ You may also like │
|
||||||
|
│ [ Similar ] [ Better rated ] │
|
||||||
|
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
|
||||||
|
│ │ img │ │ img │ │ img │ │ img │ │
|
||||||
|
│ │ name │ │ name │ │ name │ │ name │ │
|
||||||
|
│ │ ₹ │ │ ₹ │ │ ₹ │ │ ₹ │ │
|
||||||
|
│ │ 4.5★ │ │ 4.3★ │ │ 4.2★ │ │ 4.0★ │ │
|
||||||
|
│ └──────┘ └──────┘ └──────┘ └──────┘ │
|
||||||
|
└────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
Clicking a card opens that product's popup.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. How it works
|
||||||
|
|
||||||
|
We build this in three phases. Each phase works on its own.
|
||||||
|
|
||||||
|
### Phase 1: Similar products (uses data we already have) ✅ Built
|
||||||
|
|
||||||
|
Every product already has an **embedding**, a list of numbers that captures what the product is (name, brand, specs). Products with close embeddings are similar. The database already has a fast index for this; nothing uses it yet.
|
||||||
|
|
||||||
|
Steps:
|
||||||
|
1. Find the ~30 products closest to this one (same category, in stock).
|
||||||
|
2. Give each one a score:
|
||||||
|
|
||||||
|
`score = 0.60 × similarity + 0.25 × rating quality + 0.15 × price closeness`
|
||||||
|
|
||||||
|
3. Show the top 6.
|
||||||
|
|
||||||
|
**Rating quality** uses a weighted average, so a product with 5★ from 3 reviews does not beat one with 4.4★ from 2,000 reviews.
|
||||||
|
|
||||||
|
### Phase 2: Better rated alternatives (uses ratings and reviews) ✅ Built
|
||||||
|
|
||||||
|
1. Same category, price within ±20%.
|
||||||
|
2. Keep only products with a **higher** weighted rating and **at least 5 ratings**.
|
||||||
|
3. If two are close, prefer the one with more positive and fewer negative reviews. Review sentiment is already stored.
|
||||||
|
4. Show the reason on the card, for example: *"4.5★ vs 4.1★ · 2,300 reviews"*.
|
||||||
|
|
||||||
|
If the product has no rating of its own, any product rated by at least 5 people counts as better rated.
|
||||||
|
|
||||||
|
The minimum was lowered from 20 to 5 ratings so the tab is not mostly empty.
|
||||||
|
|
||||||
|
> **Today's data:** only 14 of the 57 catalogue products have a rating, and 6 have 5 or more. With the
|
||||||
|
> minimum at 5, 27 of the 48 priced products get at least one better-rated suggestion (up from 10 at 20).
|
||||||
|
> It fills in further as the review backfill collects more ratings.
|
||||||
|
|
||||||
|
### Phase 3: Personalised (future)
|
||||||
|
|
||||||
|
"Customers who viewed this also viewed…" needs to know who looked at what. The project has **no customer accounts and no view or click tracking** today, so this phase only makes sense if we add those later. It is listed here for completeness and is **not in scope now**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Rules
|
||||||
|
|
||||||
|
- Never recommend the product itself.
|
||||||
|
- Don't fill the list with variants of the same model (other RAM or storage). Either leave them out or show them on a separate "Other variants" line. *(Decided: separate line, see §9.)* For **laptops**, a variant must also have the **same processor**: one model line such as "HP 15" spans many CPUs, and those are different laptops that can be suggested. A laptop that doesn't state its processor has no variants.
|
||||||
|
- Only show products that are **in stock** and have a **known price**.
|
||||||
|
- A product is "better rated" only if it has **at least 5 ratings**.
|
||||||
|
- Show at most **6** products. If there are fewer than 3 good matches, fill the rest with the top-rated products in the same category.
|
||||||
|
- **Hard price limit:** only suggest products whose best price is within **±30%** of this product's (Similar) or **±20%** (Better rated). If this product has no price, there is no limit.
|
||||||
|
- Respect the filters the user already has on, such as sold by TN retailers only (`tn_only`) or site.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Data we have vs. data we need
|
||||||
|
|
||||||
|
| Signal | Available today? | Where it lives |
|
||||||
|
|---|---|---|
|
||||||
|
| Product embeddings (similarity) | ✅ Yes | `elec.product.embedding` |
|
||||||
|
| Category, brand, specs | ✅ Yes | `elec.product`, `canonical_specs` |
|
||||||
|
| Price and stock | ✅ Yes | `elec.source_listing`, `v_best_price` |
|
||||||
|
| Rating, rating count, star breakdown | ✅ Yes | `elec.source_listing` |
|
||||||
|
| Review sentiment (positive/neutral/negative) | ✅ Yes | `elec.listing_review.sentiment` |
|
||||||
|
| Customer views, clicks, purchases | ❌ No | Needed only for Phase 3 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Proposed API (to build later)
|
||||||
|
|
||||||
|
```
|
||||||
|
GET /api/elec/products/{product_id}/recommendations?type=similar&limit=6
|
||||||
|
GET /api/elec/products/{product_id}/recommendations?type=better_rated&limit=6
|
||||||
|
```
|
||||||
|
|
||||||
|
Response (example):
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"product_id": 123,
|
||||||
|
"type": "similar",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"product_id": 456,
|
||||||
|
"name": "Brand X Phone 8GB/128GB",
|
||||||
|
"image": "https://…",
|
||||||
|
"best_price": 17499,
|
||||||
|
"rating": 4.5,
|
||||||
|
"review_count": 2300,
|
||||||
|
"reason": "Similar specs · 4.5★ vs 4.1★"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Recommendations get their **own endpoint** instead of being added to the product details response. That keeps the popup fast: details load first and recommendations follow.
|
||||||
|
|
||||||
|
The MCP tool `recommend_products` would call the same function.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Speed and quality
|
||||||
|
|
||||||
|
- **Speed:** under 300 ms per request. The vector index already exists.
|
||||||
|
- **Caching:** store results per product and refresh them after each crawler run.
|
||||||
|
- **Quality check:** before release, review recommendations for about 20 products across categories by hand. Once tracking exists, measure how often people click them.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Out of scope (for now)
|
||||||
|
|
||||||
|
- Customer accounts, login for shoppers, view or click tracking
|
||||||
|
- Training machine-learning models
|
||||||
|
- Recommendations written by the LLM
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. Decisions needed
|
||||||
|
|
||||||
|
| # | Question | Decision |
|
||||||
|
|---|---|---|
|
||||||
|
| 1 | Show other variants (RAM/storage) as recommendations, or on a separate line? | Separate "Other variants" line ✅ built |
|
||||||
|
| 2 | Weights for similarity / rating / price | 0.60 / 0.25 / 0.15, tune after testing ✅ built |
|
||||||
|
| 3 | Recommend accessories across categories (phone → case, charger)? | Not now. It needs a manual category mapping |
|
||||||
|
| 4 | Show ★ ratings on Home page cards too? | Yes, small badge ✅ built |
|
||||||
|
| 5 | Do we plan to add customer accounts (needed for Phase 3)? | Decide later |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. Where the code lives
|
||||||
|
|
||||||
|
Phases 1 and 2 are in these files.
|
||||||
|
|
||||||
|
| Area | File | Change |
|
||||||
|
|---|---|---|
|
||||||
|
| Scoring | `backend/app/electronics/recommend.py` | Score formula, weighted rating, top-rated fill, better-rated rules, price bands |
|
||||||
|
| Database query | `backend/app/electronics/db/repository.py` | `similar_products`, `rated_products`, `review_sentiment_counts`, `other_variants` (pgvector) |
|
||||||
|
| API | `backend/app/api/routers/elec.py` | New `/recommendations` endpoint |
|
||||||
|
| MCP | `backend/app/mcp_server.py` | New `recommend_products` tool |
|
||||||
|
| Frontend | `frontend/src/components/ProductModal.jsx` | "You may also like" section with Similar / Better rated tabs under `RatingsAndReviews` |
|
||||||
|
| Frontend API | `frontend/src/api/client.js` | Call the new endpoint |
|
||||||
|
| Rating badge | `frontend/src/components/ProductCard.jsx`, `GET /api/elec/products` | ★ rating and count on Home page cards |
|
||||||
|
| Docs | `docs/API.md` | Document the endpoint |
|
||||||
|
| Tests | `backend/tests/test_elec_recommend.py` | Scoring rules and API behaviour |
|
||||||
Reference in New Issue
Block a user