sammy786 commited on
Commit
169454a
·
1 Parent(s): 888df51

coverage: airports search + merchant resolver +718, Titan caps, GRT + Surat Diamond offers

Browse files
app/airports.py ADDED
@@ -0,0 +1,188 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Comprehensive airport search + resolution for the Flights composer.
3
+
4
+ Replaces the ~87-entry hardcoded CITY_IATA map with the full IATA airport
5
+ dataset (7,884 airports, every Indian one). The From/To inputs become a
6
+ type-to-search box that calls search(); flight search calls resolve() to turn
7
+ any typed city or code into the IATA(s) Google Flights speaks; geo classifies a
8
+ route by the airports' COUNTRY, so any route resolves domestic/international -
9
+ not just the ~90 cities that used to be enumerated.
10
+
11
+ Data ships as airports_data.json (generated from the `airportsdata` package) so
12
+ the Space has no runtime dependency on the package.
13
+ """
14
+ import json, os, re, functools, unicodedata
15
+ from typing import List, Dict, Optional
16
+
17
+ _HERE = os.path.dirname(os.path.abspath(__file__))
18
+ with open(os.path.join(_HERE, "airports_data.json")) as _f:
19
+ _RAW = json.load(_f)
20
+
21
+ # rows: [iata, city, name, country, subd]
22
+ _ROWS = _RAW["airports"]
23
+ METROS: Dict[str, str] = _RAW["metros"]
24
+ _PRIMARY = set(_RAW.get("primary", []))
25
+ _ALIASES: Dict[str, str] = {k.lower(): v for k, v in _RAW["aliases"].items()}
26
+
27
+ def _strip(s: str) -> str:
28
+ return "".join(c for c in unicodedata.normalize("NFKD", s or "") if not unicodedata.combining(c))
29
+
30
+ def _norm(s: str) -> str:
31
+ return _strip(re.sub(r"\s+", " ", (s or "").strip().lower()))
32
+
33
+
34
+ # The airport dataset carries several Indian cities under their OLD names
35
+ # (Calicut, Mysore, Mangalore, Pondicherry, Allahabad...). Show the CURRENT name
36
+ # people type, and keep the old/colloquial name searchable so BOTH resolve - a
37
+ # search for "Kozhikode" and one for "Calicut" must both find CCJ.
38
+ _CITY_FIX = {
39
+ "CCJ": "Kozhikode", "MYQ": "Mysuru", "IXE": "Mangaluru", "PNY": "Puducherry",
40
+ "VTZ": "Visakhapatnam", "IXD": "Prayagraj", "IXG": "Belagavi",
41
+ "TCR": "Thoothukudi", "RJA": "Rajahmundry",
42
+ }
43
+ _ALT = {
44
+ "CCJ": "calicut", "MYQ": "mysore", "IXE": "mangalore", "PNY": "pondicherry pondy",
45
+ "VTZ": "vizag vishakhapatnam", "IXD": "allahabad", "IXG": "belgaum",
46
+ "TCR": "tuticorin", "BOM": "bombay", "BLR": "bangalore", "CCU": "calcutta",
47
+ "MAA": "madras", "COK": "cochin ernakulam", "TRV": "trivandrum", "BDQ": "baroda",
48
+ "VNS": "benares banaras", "PNQ": "poona", "IXJ": "jammu", "GAU": "guwahati",
49
+ }
50
+
51
+ BY_IATA: Dict[str, Dict] = {}
52
+ _BY_CITY: Dict[str, list] = {}
53
+ for _iata, _city, _name, _country, _subd in _ROWS:
54
+ _cty = _CITY_FIX.get(_iata, _city or _name)
55
+ rec = {"iata": _iata, "city": _cty, "name": _name, "country": _country, "subd": _subd}
56
+ rec["_c"] = _norm(_cty)
57
+ rec["_n"] = _norm(_name + " " + _ALT.get(_iata, ""))
58
+ rec["_i"] = _iata.lower()
59
+ BY_IATA[_iata] = rec
60
+ _BY_CITY.setdefault((_cty or "").lower(), []).append(rec)
61
+
62
+
63
+
64
+ def is_international(iata_or_country: Optional[str]) -> Optional[bool]:
65
+ """True if the airport (or the metro's first airport) is outside India.
66
+ None if unknown. Country-based, so EVERY airport classifies correctly."""
67
+ if not iata_or_country:
68
+ return None
69
+ s = iata_or_country.strip().upper()
70
+ if s == "IN":
71
+ return False
72
+ if len(s) == 2: # a country code
73
+ return True
74
+ first = s.split(",")[0]
75
+ rec = BY_IATA.get(first)
76
+ if not rec:
77
+ return None
78
+ return rec["country"] != "IN"
79
+
80
+
81
+ def label(rec: Dict) -> str:
82
+ """Human label for a picker row: 'Kochi (COK) - India'."""
83
+ city = rec["city"]
84
+ tail = rec["subd"] if rec["country"] == "IN" and rec["subd"] and rec["subd"].lower() != city.lower() else _country_name(rec["country"])
85
+ return f"{city} ({rec['iata']})" + (f" - {tail}" if tail else "")
86
+
87
+
88
+ _COUNTRY = {"IN": "India", "AE": "UAE", "US": "USA", "GB": "UK", "SG": "Singapore",
89
+ "TH": "Thailand", "QA": "Qatar", "SA": "Saudi Arabia", "MY": "Malaysia",
90
+ "LK": "Sri Lanka", "NP": "Nepal", "MV": "Maldives", "ID": "Indonesia"}
91
+ def _country_name(cc: str) -> str:
92
+ return _COUNTRY.get(cc, cc)
93
+
94
+
95
+ def _score(rec: Dict, q: str) -> int:
96
+ """Higher = better match for query q (already normalised). Importance boosts
97
+ apply ONLY when the query actually matches, so India airports never leak
98
+ into an unrelated search."""
99
+ iata = rec["_i"]; city = rec["_c"]; name = rec["_n"]
100
+ base = 0
101
+ if q == iata: base += 1000
102
+ if city == q: base += 600
103
+ elif city.startswith(q): base += 400
104
+ elif q in city: base += 220
105
+ if q in name: base += 130
106
+ elif iata.startswith(q): base += 90
107
+ if base == 0:
108
+ return 0
109
+ # importance (no pax data in the set): this is an India-first app, then real
110
+ # intl gateways. Applied only on a genuine match so it breaks ties, never invents them.
111
+ if rec["country"] == "IN": base += 500
112
+ if rec["iata"] in _PRIMARY: base += 350
113
+ if rec["iata"] in METROS: base += 150 # metro-anchor: LHR over LGW, JFK over LGA
114
+ if "international" in name: base += 40
115
+ return base
116
+
117
+
118
+ @functools.lru_cache(maxsize=4096)
119
+ def search(q: str, limit: int = 8) -> tuple:
120
+ """Autocomplete: match on IATA / city / name. Returns a tuple of dicts
121
+ (cached; convert to list at the boundary)."""
122
+ q0 = _norm(q)
123
+ if not q0:
124
+ return tuple()
125
+ q = _norm(_ALIASES.get(q0, q0))
126
+ hits = []
127
+ for rec in BY_IATA.values():
128
+ sc = _score(rec, q)
129
+ if sc > 0:
130
+ hits.append((sc, rec))
131
+ # An alias must never make matching WORSE: if it redirected to a spelling the
132
+ # dataset lacks, fall back to scoring the raw query.
133
+ if not hits and q != q0:
134
+ for rec in BY_IATA.values():
135
+ sc = _score(rec, q0)
136
+ if sc > 0:
137
+ hits.append((sc, rec))
138
+ hits.sort(key=lambda x: (-x[0], x[1]["city"]))
139
+ out = []
140
+ seen = set()
141
+ for _, rec in hits[: limit * 3]:
142
+ key = (rec["city"], rec["country"])
143
+ if rec["iata"] in seen:
144
+ continue
145
+ seen.add(rec["iata"])
146
+ out.append({**rec, "label": label(rec), "intl": rec["country"] != "IN"})
147
+ if len(out) >= limit:
148
+ break
149
+ return tuple(out)
150
+
151
+
152
+ def resolve(text: str) -> Optional[str]:
153
+ """Turn a typed city / IATA / alias into the IATA(s) the flight API speaks.
154
+ Returns a metro comma-list where relevant ('Mumbai' -> 'BOM,NMI'), or None."""
155
+ if not text:
156
+ return None
157
+ t = text.strip()
158
+ # already an IATA (single or metro comma list) - only when typed in caps, so a
159
+ # mixed-case city like "Goa" is read as the city, not the code GOA (Genova).
160
+ if t == t.upper() and re.fullmatch(r"[A-Z]{3}(,[A-Z]{3})*", t):
161
+ return METROS.get(t.split(",")[0], t)
162
+ n = _norm(t)
163
+ n = _norm(_ALIASES.get(n, n))
164
+ # exact city -> prefer the highest-scored airport, apply metro grouping
165
+ res = search(n, limit=1)
166
+ if not res:
167
+ return None
168
+ iata = res[0]["iata"]
169
+ return METROS.get(iata, iata)
170
+
171
+
172
+ def cities_for_hotels(q: str, limit: int = 8) -> list:
173
+ """City suggestions for the hotels/dining city box (dedup by city name)."""
174
+ q = _norm(q)
175
+ if not q:
176
+ return []
177
+ q = _norm(_ALIASES.get(q, q))
178
+ seen, out = set(), []
179
+ for rec in sorted(BY_IATA.values(), key=lambda r: (r["country"] != "IN", r["city"])):
180
+ c = (rec["city"] or "").lower()
181
+ if c and (c.startswith(q) or q in c) and c not in seen:
182
+ seen.add(c)
183
+ out.append({"city": rec["city"], "country": rec["country"],
184
+ "label": f"{rec['city']} - {_country_name(rec['country'])}",
185
+ "intl": rec["country"] != "IN"})
186
+ if len(out) >= limit:
187
+ break
188
+ return out
app/airports_data.json ADDED
The diff for this file is too large to render. See raw diff
 
app/card_catalogue.py CHANGED
@@ -1769,7 +1769,11 @@ CATALOGUE += [
1769
  segment="mid", reward_unit="cashback", point_value_inr=1, base_rate=1.5,
1770
  category_rates={},
1771
  caps={},
1772
- brand_caps=[{"brands": ["tanishq"], "cap": 8333}, {"brands": ["caratlane"], "cap": 3333}, {"brands": ["titan"], "cap": 3333}],
 
 
 
 
1773
  excluded_categories=["fuel", "wallet_load", "rent", "utilities"],
1774
  brand_bonuses={"tanishq": 3, "caratlane": 5, "mia": 5, "zoya": 5, "titan": 7.5, "fastrack": 7.5, "helios": 7.5, "titan_eyeplus": 7.5, "taneira": 7.5, "sonata": 7.5},
1775
  upi_eligible=True,
 
1769
  segment="mid", reward_unit="cashback", point_value_inr=1, base_rate=1.5,
1770
  category_rates={},
1771
  caps={},
1772
+ # Shared quarterly caps (≈ monthly): Tanishq ₹25k/qtr → 8,333/mo; the 5%
1773
+ # jewellery trio (Mia/CaratLane/Zoya) share ₹10k/qtr → 3,333/mo; the 7.5%
1774
+ # Titan-world brands share ₹10k/qtr → 3,333/mo. Every bonused brand must
1775
+ # sit in a cap group or it earns its accelerated rate UNCAPPED.
1776
+ brand_caps=[{"brands": ["tanishq"], "cap": 8333}, {"brands": ["mia", "caratlane", "zoya"], "cap": 3333}, {"brands": ["titan", "fastrack", "helios", "titan_eyeplus", "taneira", "sonata"], "cap": 3333}],
1777
  excluded_categories=["fuel", "wallet_load", "rent", "utilities"],
1778
  brand_bonuses={"tanishq": 3, "caratlane": 5, "mia": 5, "zoya": 5, "titan": 7.5, "fastrack": 7.5, "helios": 7.5, "titan_eyeplus": 7.5, "taneira": 7.5, "sonata": 7.5},
1779
  upi_eligible=True,
app/geo.py CHANGED
@@ -11,6 +11,7 @@ Mirrored on-device in app/src/data/geo.ts.
11
  """
12
 
13
  from typing import Optional
 
14
 
15
  # Major Indian airports (domestic when the destination is one of these).
16
  INDIA_IATA = {
@@ -96,6 +97,16 @@ def iata_is_international(code: Optional[str]) -> Optional[bool]:
96
  continue
97
  if not (len(c) == 3 and c.isalpha()):
98
  return None
 
 
 
 
 
 
 
 
 
 
99
  all_india = False
100
  return False if all_india else True
101
 
 
11
  """
12
 
13
  from typing import Optional
14
+ import airports as _ap # comprehensive 7,884-airport dataset (country-based fallback)
15
 
16
  # Major Indian airports (domestic when the destination is one of these).
17
  INDIA_IATA = {
 
97
  continue
98
  if not (len(c) == 3 and c.isalpha()):
99
  return None
100
+ # Consult the full airport dataset before falling back to the heuristic:
101
+ # a real Indian airport MISSING from INDIA_IATA must classify domestic,
102
+ # not international. country=IN -> domestic; a known foreign airport ->
103
+ # international; only a code absent from all 7,884 stays "international,
104
+ # not unknown" (the Indian set is finite; the world's airports are not).
105
+ rec = _ap.BY_IATA.get(c)
106
+ if rec is not None:
107
+ if rec["country"] == "IN":
108
+ continue
109
+ return True
110
  all_india = False
111
  return False if all_india else True
112
 
app/main.py CHANGED
@@ -307,6 +307,26 @@ def cards():
307
  return {"cards": [_card_public(c) for c in all_cards()]}
308
 
309
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
310
  @app.get("/offers")
311
  def offers():
312
  """All currently-active offers (dated). Fed by the ingestion connectors."""
@@ -470,14 +490,20 @@ def flights_search(req: FlightSearchRequest, request: Request = None):
470
  city = normalize_city(req.city)
471
  import geo
472
  # BOTH endpoints: a return leg into India is still an international trip.
473
- intl = geo.route_is_international(req.src, req.dst) # international route? offers gate on it
 
 
 
 
 
 
474
 
475
  # SerpApi's Google Flights results carry a booking token, which is what
476
  # unlocks per-platform prices later via /flights/sellers. Prefer it when a
477
  # key is configured; otherwise keep the Travelpayouts cached-fare path,
478
  # which has no token and therefore no per-platform comparison.
479
  flights, source = flight_sellers.search_flights(
480
- req.src, req.dst, req.date,
481
  adults=req.adults or 1,
482
  children=req.children or 0,
483
  infants=req.infants or 0,
@@ -498,7 +524,7 @@ def flights_search(req: FlightSearchRequest, request: Request = None):
498
  plain_search = (req.cabin or "economy") == "economy" and not (req.children or req.infants)
499
  if not flights and plain_search:
500
  flights = flights_provider.search_flights(
501
- req.src, req.dst, req.date,
502
  adults=req.adults or 1, nonstop=req.nonstop or (req.stops == "nonstop"),
503
  airlines=req.airlines, max_price=req.max_price,
504
  window_days=req.window_days if req.window_days is not None else 3,
 
307
  return {"cards": [_card_public(c) for c in all_cards()]}
308
 
309
 
310
+ @app.get("/airports/search")
311
+ def airports_search(q: str = "", limit: int = 8, request: Request = None):
312
+ """Type-to-search autocomplete over the full 7,884-airport dataset (every
313
+ Indian airport + international). Powers the Flights From/To box. Public +
314
+ rate-limited; no PII, no app key."""
315
+ if request is not None:
316
+ _limit(request, "aps", rate=120)
317
+ import airports
318
+ return {"query": q, "results": list(airports.search(q, min(int(limit or 8), 15)))}
319
+
320
+
321
+ @app.get("/cities/search")
322
+ def cities_search(q: str = "", limit: int = 8, request: Request = None):
323
+ """City autocomplete for the Hotels/Dining city box (searches by city name)."""
324
+ if request is not None:
325
+ _limit(request, "cts", rate=120)
326
+ import airports
327
+ return {"query": q, "results": airports.cities_for_hotels(q, min(int(limit or 8), 15))}
328
+
329
+
330
  @app.get("/offers")
331
  def offers():
332
  """All currently-active offers (dated). Fed by the ingestion connectors."""
 
490
  city = normalize_city(req.city)
491
  import geo
492
  # BOTH endpoints: a return leg into India is still an international trip.
493
+ # Resolve a typed city OR an IATA to the code(s) the flight API speaks: the new
494
+ # searchable From/To sends a picked IATA, but free text ("Kochi", "Goa") also
495
+ # works now via the full airport dataset. Passthrough when already a code.
496
+ import airports as _apx
497
+ src_q = _apx.resolve(req.src) or req.src
498
+ dst_q = _apx.resolve(req.dst) or req.dst
499
+ intl = geo.route_is_international(src_q, dst_q) # international route? offers gate on it
500
 
501
  # SerpApi's Google Flights results carry a booking token, which is what
502
  # unlocks per-platform prices later via /flights/sellers. Prefer it when a
503
  # key is configured; otherwise keep the Travelpayouts cached-fare path,
504
  # which has no token and therefore no per-platform comparison.
505
  flights, source = flight_sellers.search_flights(
506
+ src_q, dst_q, req.date,
507
  adults=req.adults or 1,
508
  children=req.children or 0,
509
  infants=req.infants or 0,
 
524
  plain_search = (req.cabin or "economy") == "economy" and not (req.children or req.infants)
525
  if not flights and plain_search:
526
  flights = flights_provider.search_flights(
527
+ src_q, dst_q, req.date,
528
  adults=req.adults or 1, nonstop=req.nonstop or (req.stops == "nonstop"),
529
  airlines=req.airlines, max_price=req.max_price,
530
  window_days=req.window_days if req.window_days is not None else 3,
app/merchants.py CHANGED
@@ -1364,6 +1364,751 @@ MERCHANT_MAP: Dict[str, Tuple[str, Optional[str]]] = {
1364
  # matrix caught it, 2026-07-29).
1365
  }
1366
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1367
  # Retailers / merchants preferred over product words so "iPhone at Croma"
1368
  # resolves to Croma, not iPhone.
1369
  STORE_KEYWORDS = {
 
1364
  # matrix caught it, 2026-07-29).
1365
  }
1366
 
1367
+ # ---------------------------------------------------------------------------
1368
+ # Wider merchant coverage (added 2026-08-08): 719 brand keywords across
1369
+ # every category, folded in from the market sweep. Existing hand-tuned keys
1370
+ # always win (setdefault below), so this only ADDS reach - any store a user
1371
+ # names now resolves to the right category (and a brand key where we have
1372
+ # one) instead of falling through to "general".
1373
+ # ---------------------------------------------------------------------------
1374
+ _PROPOSED_2026_08: Dict[str, Tuple[str, Optional[str]]] = {
1375
+ # --- dining ---
1376
+ "7th heaven": ("dining", "seventh_heaven"),
1377
+ "adigas": ("dining", "adigas"),
1378
+ "amex dining": ("dining", "amex_dining"),
1379
+ "ammi's": ("dining", "ammis_biryani"),
1380
+ "ammis biryani": ("dining", "ammis_biryani"),
1381
+ "anjappar": ("dining", "anjappar"),
1382
+ "barista": ("dining", "barista"),
1383
+ "baskin robbins": ("dining", "baskin_robbins"),
1384
+ "bbk": ("dining", "biryani_by_kilo"),
1385
+ "belgian waffle": ("dining", "belgian_waffle"),
1386
+ "biggies burger": ("dining", "biggies_burger"),
1387
+ "biryani by kilo": ("dining", "biryani_by_kilo"),
1388
+ "burger singh": ("dining", "burger_singh"),
1389
+ "cafe delhi heights": ("dining", "cafe_delhi_heights"),
1390
+ "california pizza kitchen": ("dining", "cpk"),
1391
+ "carl's jr": ("dining", "carls_jr"),
1392
+ "carls jr": ("dining", "carls_jr"),
1393
+ "chai point": ("dining", "chai_point"),
1394
+ "chai sutta bar": ("dining", "chai_sutta_bar"),
1395
+ "charcoal eats": ("dining", "charcoal_eats"),
1396
+ "chinese wok": ("dining", "chinese_wok"),
1397
+ "chowman": ("dining", "chowman"),
1398
+ "costa": ("dining", "costa_coffee"),
1399
+ "costa coffee": ("dining", "costa_coffee"),
1400
+ "cpk": ("dining", "cpk"),
1401
+ "cream stone": ("dining", "cream_stone"),
1402
+ "culinary treats": ("dining", "culinary_treats"),
1403
+ "cult eatfit": ("dining", "eatfit"),
1404
+ "dindigul": ("dining", "thalappakatti"),
1405
+ "dining delights": ("dining", "dining_delights"),
1406
+ "drunken monkey": ("dining", "drunken_monkey"),
1407
+ "dunkin": ("dining", "dunkin"),
1408
+ "dunkin donuts": ("dining", "dunkin"),
1409
+ "eatfit": ("dining", "eatfit"),
1410
+ "effingut": ("dining", "effingut"),
1411
+ "empire restaurant": ("dining", "empire_restaurant"),
1412
+ "firangi bake": ("dining", "firangi_bake"),
1413
+ "flavours of india": ("dining", "amex_dining"),
1414
+ "fresh menu": ("dining", "freshmenu"),
1415
+ "freshmenu": ("dining", "freshmenu"),
1416
+ "frozen bottle": ("dining", "frozen_bottle"),
1417
+ "giani": ("dining", "giani"),
1418
+ "giani's": ("dining", "giani"),
1419
+ "goila": ("dining", "goila_butter_chicken"),
1420
+ "goli": ("dining", "goli_vada_pav"),
1421
+ "goli vada pav": ("dining", "goli_vada_pav"),
1422
+ "good bowl": ("dining", "the_good_bowl"),
1423
+ "good food trail": ("dining", "good_food_trail"),
1424
+ "hard rock cafe": ("dining", "hard_rock_cafe"),
1425
+ "honest restaurant": ("dining", "honest"),
1426
+ "hoppipola": ("dining", "hoppipola"),
1427
+ "hotel empire": ("dining", "empire_restaurant"),
1428
+ "ibaco": ("dining", "ibaco"),
1429
+ "irish house": ("dining", "irish_house"),
1430
+ "johnny rockets": ("dining", "johnny_rockets"),
1431
+ "jumbo king": ("dining", "jumboking"),
1432
+ "jumboking": ("dining", "jumboking"),
1433
+ "junior kuppanna": ("dining", "junior_kuppanna"),
1434
+ "kailash parbat": ("dining", "kailash_parbat"),
1435
+ "karachi bakery": ("dining", "karachi_bakery"),
1436
+ "kathi junction": ("dining", "kathi_junction"),
1437
+ "keventers": ("dining", "keventers"),
1438
+ "kotak dining": ("dining", "kotak_dining"),
1439
+ "krispy kreme": ("dining", "krispy_kreme"),
1440
+ "mad over donuts": ("dining", "mad_over_donuts"),
1441
+ "maharaja bhog": ("dining", "maharaja_bhog"),
1442
+ "mba chai wala": ("dining", "mba_chai_wala"),
1443
+ "meghana foods": ("dining", "meghana_foods"),
1444
+ "mio amore": ("dining", "mio_amore"),
1445
+ "monginis": ("dining", "monginis"),
1446
+ "moti mahal": ("dining", "moti_mahal"),
1447
+ "mtr restaurant": ("dining", "mtr_restaurant"),
1448
+ "murugan idli": ("dining", "murugan_idli"),
1449
+ "nando's": ("dining", "nandos"),
1450
+ "nandos": ("dining", "nandos"),
1451
+ "natural ice cream": ("dining", "naturals"),
1452
+ "naturals ice cream": ("dining", "naturals"),
1453
+ "nic ice cream": ("dining", "nic"),
1454
+ "nirula's": ("dining", "nirulas"),
1455
+ "nirulas": ("dining", "nirulas"),
1456
+ "oh calcutta": ("dining", "oh_calcutta"),
1457
+ "olive bar": ("dining", "olive_group"),
1458
+ "olive bistro": ("dining", "olive_group"),
1459
+ "pf changs": ("dining", "pf_changs"),
1460
+ "pind balluchi": ("dining", "pind_balluchi"),
1461
+ "pirates of grill": ("dining", "pirates_of_grill"),
1462
+ "ponnusamy": ("dining", "ponnusamy"),
1463
+ "popeyes": ("dining", "popeyes"),
1464
+ "punjab grill": ("dining", "punjab_grill"),
1465
+ "rajdhani": ("dining", "rajdhani_thali"),
1466
+ "rolls mania": ("dining", "rolls_mania"),
1467
+ "sangeetha veg": ("dining", "sangeetha"),
1468
+ "sankalp": ("dining", "sankalp"),
1469
+ "sbow": ("dining", "sodabottleopenerwala"),
1470
+ "sigree": ("dining", "sigree"),
1471
+ "smoke house deli": ("dining", "smoke_house_deli"),
1472
+ "smoor": ("dining", "smoor"),
1473
+ "sodabottleopenerwala": ("dining", "sodabottleopenerwala"),
1474
+ "subko": ("dining", "subko"),
1475
+ "taco bell": ("dining", "taco_bell"),
1476
+ "tacobell": ("dining", "taco_bell"),
1477
+ "tea trails": ("dining", "tea_trails"),
1478
+ "thalappakatti": ("dining", "thalappakatti"),
1479
+ "thick shake factory": ("dining", "thickshake_factory"),
1480
+ "thickshake": ("dining", "thickshake_factory"),
1481
+ "tim hortons": ("dining", "tim_hortons"),
1482
+ "toit": ("dining", "toit"),
1483
+ "truffles": ("dining", "truffles"),
1484
+ "vasudev adiga": ("dining", "adigas"),
1485
+ "warmoven": ("dining", "warmoven"),
1486
+ "wat a burger": ("dining", "wat_a_burger"),
1487
+ "wat-a-burger": ("dining", "wat_a_burger"),
1488
+ "wendy's": ("dining", "wendys"),
1489
+ "wendys": ("dining", "wendys"),
1490
+ "wok express": ("dining", "wok_express"),
1491
+ "wokexpress": ("dining", "wok_express"),
1492
+ "wow! china": ("dining", "wow_china"),
1493
+ "yellow chilli": ("dining", "yellow_chilli"),
1494
+ # --- groceries ---
1495
+ "7 eleven": ("groceries", "seven_eleven"),
1496
+ "7-eleven": ("groceries", "seven_eleven"),
1497
+ "akshayakalpa": ("groceries", "akshayakalpa"),
1498
+ "apna bazaar": ("groceries", "apna_bazar"),
1499
+ "apna bazar": ("groceries", "apna_bazar"),
1500
+ "balaji grand bazar": ("groceries", "balaji_grand_bazar"),
1501
+ "best price": ("groceries", "best_price"),
1502
+ "bgb": ("groceries", "balaji_grand_bazar"),
1503
+ "city mall": ("groceries", "citymall"),
1504
+ "citymall": ("groceries", "citymall"),
1505
+ "dealshare": ("groceries", "dealshare"),
1506
+ "deep rooted": ("groceries", "deep_rooted"),
1507
+ "deeprooted": ("groceries", "deep_rooted"),
1508
+ "doodhvale": ("groceries", "doodhvale"),
1509
+ "flipkart wholesale": ("groceries", "best_price"),
1510
+ "food stories": ("groceries", "food_stories"),
1511
+ "foodstories": ("groceries", "food_stories"),
1512
+ "gourmet garden": ("groceries", "verify-first"),
1513
+ "grace supermarket": ("groceries", "grace_supermarket"),
1514
+ "kisan konnect": ("groceries", "kisankonnect"),
1515
+ "kisankonnect": ("groceries", "kisankonnect"),
1516
+ "kovai pazhamudir nilayam": ("groceries", "kpn_fresh"),
1517
+ "kpn fresh": ("groceries", "kpn_fresh"),
1518
+ "le marche": ("groceries", "le_marche"),
1519
+ "lemarche": ("groceries", "le_marche"),
1520
+ "magsons": ("groceries", "magsons"),
1521
+ "magsons supercenter": ("groceries", "magsons"),
1522
+ "margin free": ("groceries", "margin_free_market"),
1523
+ "meatigo": ("groceries", "meatigo"),
1524
+ "mk ahmed": ("groceries", "mk_retail"),
1525
+ "mk retail": ("groceries", "mk_retail"),
1526
+ "modern bazaar": ("groceries", "modern_bazaar"),
1527
+ "mother dairy safal": ("groceries", "safal"),
1528
+ "nesto": ("groceries", "nesto"),
1529
+ "nesto hypermarket": ("groceries", "nesto"),
1530
+ "osia": ("groceries", "osia_hypermart"),
1531
+ "osia hypermart": ("groceries", "osia_hypermart"),
1532
+ "osiamart": ("groceries", "osia_hypermart"),
1533
+ "pazhamudir": ("groceries", "kpn_fresh"),
1534
+ "pothys": ("groceries", "pothys_hyper"),
1535
+ "pothys hyper": ("groceries", "pothys_hyper"),
1536
+ "prasuma": ("groceries", "meatigo"),
1537
+ "q-mart": ("groceries", "q_mart"),
1538
+ "qmart": ("groceries", "q_mart"),
1539
+ "safal": ("groceries", "safal"),
1540
+ "sahakari bhandar": ("groceries", "sahakari_bhandar"),
1541
+ "seven eleven": ("groceries", "seven_eleven"),
1542
+ "sid's farm": ("groceries", "sids_farm"),
1543
+ "sids farm": ("groceries", "sids_farm"),
1544
+ "spar": ("groceries", "spar_india"),
1545
+ "spar hypermarket": ("groceries", "spar_india"),
1546
+ "spar india": ("groceries", "spar_india"),
1547
+ "triveni supermarket": ("groceries", "triveni_supermarkets"),
1548
+ "v-mart": ("groceries", "v_mart"),
1549
+ "vijetha": ("groceries", "vijetha"),
1550
+ "vijetha supermarket": ("groceries", "vijetha"),
1551
+ "vmart": ("groceries", "v_mart"),
1552
+ "zappfresh": ("groceries", "zappfresh"),
1553
+ # --- electronics ---
1554
+ "adishwar": ("electronics", "adishwar"),
1555
+ "adishwar india": ("electronics", "adishwar"),
1556
+ "amazfit": ("electronics", "amazfit"),
1557
+ "apple premium reseller": ("electronics", "india_istore"),
1558
+ "atomberg": ("electronics", "atomberg"),
1559
+ "b new": ("electronics", "b_new_mobiles"),
1560
+ "benq": ("electronics", "benq"),
1561
+ "bismi": ("electronics", "bismi"),
1562
+ "bismi appliances": ("electronics", "bismi"),
1563
+ "bnew mobiles": ("electronics", "b_new_mobiles"),
1564
+ "brother printers": ("electronics", "brother"),
1565
+ "butterfly": ("electronics", "butterfly"),
1566
+ "butterfly gandhimathi": ("electronics", "butterfly"),
1567
+ "canon": ("electronics", "canon"),
1568
+ "canon store": ("electronics", "canon"),
1569
+ "capital electronics": ("electronics", "capital_electronics"),
1570
+ "celekt": ("electronics", "celekt"),
1571
+ "cell point": ("electronics", "cellpoint"),
1572
+ "cellpoint": ("electronics", "cellpoint"),
1573
+ "crompton": ("electronics", "crompton"),
1574
+ "crompton greaves": ("electronics", "crompton"),
1575
+ "dji": ("electronics", "dji"),
1576
+ "ecotank": ("electronics", "epson"),
1577
+ "electronicsmartindia": ("electronics", "electronics_mart"),
1578
+ "elica": ("electronics", "elica"),
1579
+ "emil": ("electronics", "electronics_mart"),
1580
+ "epson": ("electronics", "epson"),
1581
+ "faber": ("electronics", "faber"),
1582
+ "faber chimney": ("electronics", "faber"),
1583
+ "fire-boltt": ("electronics", "fire_boltt"),
1584
+ "fireboltt": ("electronics", "fire_boltt"),
1585
+ "fujifilm": ("electronics", "fujifilm"),
1586
+ "future world": ("electronics", "futureworld"),
1587
+ "futureworld": ("electronics", "futureworld"),
1588
+ "g-mart": ("electronics", "nandilath_gmart"),
1589
+ "garmin": ("electronics", "garmin"),
1590
+ "glen": ("electronics", "glen"),
1591
+ "gmart": ("electronics", "nandilath_gmart"),
1592
+ "gopro": ("electronics", "gopro"),
1593
+ "happi mobiles": ("electronics", "happi_mobiles"),
1594
+ "happimobiles": ("electronics", "happi_mobiles"),
1595
+ "harman audio": ("electronics", "harman_audio"),
1596
+ "harman kardon": ("electronics", "harman_audio"),
1597
+ "hihonor": ("electronics", "honor"),
1598
+ "hmd": ("electronics", "hmd_nokia"),
1599
+ "honor": ("electronics", "honor"),
1600
+ "htech": ("electronics", "honor"),
1601
+ "imagine online": ("electronics", "imagine_apple"),
1602
+ "in.canon": ("electronics", "canon"),
1603
+ "indiaistore": ("electronics", "india_istore"),
1604
+ "infinix": ("electronics", "infinix"),
1605
+ "insta360": ("electronics", "insta360"),
1606
+ "instax": ("electronics", "fujifilm"),
1607
+ "iplanet": ("electronics", "iplanet"),
1608
+ "iqoo store": ("electronics", "iqoo"),
1609
+ "itel": ("electronics", "itel"),
1610
+ "kenstar": ("electronics", "kenstar"),
1611
+ "lava": ("electronics", "lava"),
1612
+ "lava mobiles": ("electronics", "lava"),
1613
+ "livpure": ("electronics", "livpure"),
1614
+ "logitech": ("electronics", "logitech"),
1615
+ "logitech g": ("electronics", "logitech"),
1616
+ "luminous": ("electronics", "luminous"),
1617
+ "luminous inverter": ("electronics", "luminous"),
1618
+ "mahajan electronics": ("electronics", "mahajan_electronics"),
1619
+ "maple store": ("electronics", "maple_apple"),
1620
+ "marshall": ("electronics", "marshall"),
1621
+ "mivi": ("electronics", "mivi"),
1622
+ "morphy richards": ("electronics", "morphy_richards"),
1623
+ "msi": ("electronics", "msi"),
1624
+ "myg": ("electronics", "myg"),
1625
+ "myg digital": ("electronics", "myg"),
1626
+ "myg india": ("electronics", "myg"),
1627
+ "nandilath": ("electronics", "nandilath_gmart"),
1628
+ "nikon": ("electronics", "nikon"),
1629
+ "nikon store": ("electronics", "nikon"),
1630
+ "nokia mobile": ("electronics", "hmd_nokia"),
1631
+ "nokia phones": ("electronics", "hmd_nokia"),
1632
+ "orient": ("electronics", "orient_electric"),
1633
+ "orient electric": ("electronics", "orient_electric"),
1634
+ "oxygen digital": ("electronics", "oxygen_digital"),
1635
+ "oxygen the digital shop": ("electronics", "oxygen_digital"),
1636
+ "pigeon": ("electronics", "pigeon"),
1637
+ "pittappillil": ("electronics", "pittappillil"),
1638
+ "placewell": ("electronics", "placewell"),
1639
+ "poojara": ("electronics", "poojara"),
1640
+ "poojara telecom": ("electronics", "poojara"),
1641
+ "portronics": ("electronics", "portronics"),
1642
+ "preethi": ("electronics", "preethi"),
1643
+ "prestige": ("electronics", "ttk_prestige"),
1644
+ "prestige xclusive": ("electronics", "ttk_prestige"),
1645
+ "ptron": ("electronics", "ptron"),
1646
+ "qrs": ("electronics", "qrs"),
1647
+ "qrs retail": ("electronics", "qrs"),
1648
+ "rathna fan house": ("electronics", "rathna_fan_house"),
1649
+ "razer": ("electronics", "razer"),
1650
+ "sales emporium": ("electronics", "sales_emporium"),
1651
+ "sales india": ("electronics", "sales_india"),
1652
+ "salesindia": ("electronics", "sales_india"),
1653
+ "sargam": ("electronics", "sargam"),
1654
+ "sargam electronics": ("electronics", "sargam"),
1655
+ "sennheiser": ("electronics", "sennheiser"),
1656
+ "siemens appliances": ("electronics", "siemens_home"),
1657
+ "siemens home": ("electronics", "siemens_home"),
1658
+ "skullcandy": ("electronics", "skullcandy"),
1659
+ "sonos": ("electronics", "sonos"),
1660
+ "stovekraft": ("electronics", "pigeon"),
1661
+ "supreme mobiles": ("electronics", "supreme_mobiles"),
1662
+ "suprememobiles": ("electronics", "supreme_mobiles"),
1663
+ "symphony": ("electronics", "symphony"),
1664
+ "symphony cooler": ("electronics", "symphony"),
1665
+ "tecno": ("electronics", "tecno"),
1666
+ "top 10 mobiles": ("electronics", "top10_mobiles"),
1667
+ "top10 mobile": ("electronics", "top10_mobiles"),
1668
+ "ttk prestige": ("electronics", "ttk_prestige"),
1669
+ "unicorn": ("electronics", "unicorn_apple"),
1670
+ "unilet": ("electronics", "unilet"),
1671
+ "unilet stores": ("electronics", "unilet"),
1672
+ "v-guard": ("electronics", "v_guard"),
1673
+ "value plus": ("electronics", "value_plus"),
1674
+ "valueplusretail": ("electronics", "value_plus"),
1675
+ "vasanth": ("electronics", "vasanth_and_co"),
1676
+ "vasanth & co": ("electronics", "vasanth_and_co"),
1677
+ "vasanthandco": ("electronics", "vasanth_and_co"),
1678
+ "vguard": ("electronics", "v_guard"),
1679
+ "voltbek": ("electronics", "voltas_beko"),
1680
+ "vu televisions": ("electronics", "vu"),
1681
+ "vu tv": ("electronics", "vu"),
1682
+ "zebronics": ("electronics", "zebronics"),
1683
+ # --- travel_hotels ---
1684
+ "aman-i-khas": ("travel_hotels", "aman"),
1685
+ "amanbagh": ("travel_hotels", "aman"),
1686
+ "amritara": ("travel_hotels", "amritara"),
1687
+ "anantara": ("travel_hotels", "minor_hotels"),
1688
+ "avani": ("travel_hotels", "minor_hotels"),
1689
+ "beacon hotels": ("travel_hotels", "the_fern"),
1690
+ "best western": ("travel_hotels", "best_western"),
1691
+ "biznotel": ("travel_hotels", "pride_hotels"),
1692
+ "bloom boutique": ("travel_hotels", "bloom_hotels"),
1693
+ "bloom hub": ("travel_hotels", "bloom_hotels"),
1694
+ "bloomrooms": ("travel_hotels", "bloom_hotels"),
1695
+ "cgh earth": ("travel_hotels", "cgh_earth"),
1696
+ "citadines": ("travel_hotels", "ascott"),
1697
+ "clarion hotel": ("travel_hotels", "choice_hotels"),
1698
+ "clarks hotels": ("travel_hotels", "clarks_hotels"),
1699
+ "clarks inn": ("travel_hotels", "clarks_hotels"),
1700
+ "coconut lagoon": ("travel_hotels", "cgh_earth"),
1701
+ "comfort inn": ("travel_hotels", "choice_hotels"),
1702
+ "cozzet": ("travel_hotels", "cygnett"),
1703
+ "cygnett inn": ("travel_hotels", "cygnett"),
1704
+ "cygnett park": ("travel_hotels", "cygnett"),
1705
+ "days inn": ("travel_hotels", "wyndham"),
1706
+ "deltin royale": ("travel_hotels", "deltin"),
1707
+ "deltin suites": ("travel_hotels", "deltin"),
1708
+ "effotel": ("travel_hotels", "sayaji"),
1709
+ "ekostay": ("travel_hotels", "ekostay"),
1710
+ "enrise by sayaji": ("travel_hotels", "sayaji"),
1711
+ "evolve back": ("travel_hotels", "evolve_back"),
1712
+ "expedia": ("travel_hotels", "expedia"),
1713
+ "fateh prakash": ("travel_hotels", "hrh_hotels"),
1714
+ "fern residency": ("travel_hotels", "the_fern"),
1715
+ "four seasons bengaluru": ("travel_hotels", "four_seasons"),
1716
+ "four seasons mumbai": ("travel_hotels", "four_seasons"),
1717
+ "go stops": ("travel_hotels", "gostops"),
1718
+ "golden tulip": ("travel_hotels", "golden_tulip"),
1719
+ "gostops": ("travel_hotels", "gostops"),
1720
+ "grand by grt": ("travel_hotels", "grt_hotels"),
1721
+ "grt grand": ("travel_hotels", "grt_hotels"),
1722
+ "grt hotels": ("travel_hotels", "grt_hotels"),
1723
+ "hotels.com": ("travel_hotels", "expedia"),
1724
+ "howard johnson": ("travel_hotels", "wyndham"),
1725
+ "hrh hotels": ("travel_hotels", "hrh_hotels"),
1726
+ "isprava": ("travel_hotels", "lohono"),
1727
+ "itdc hotels": ("travel_hotels", "itdc_ashok"),
1728
+ "jaypee greens": ("travel_hotels", "jaypee_hotels"),
1729
+ "jaypee palace": ("travel_hotels", "jaypee_hotels"),
1730
+ "jaypee vasant": ("travel_hotels", "jaypee_hotels"),
1731
+ "justa hotels": ("travel_hotels", "justa_hotels"),
1732
+ "justa resorts": ("travel_hotels", "justa_hotels"),
1733
+ "kamat hotels": ("travel_hotels", "the_orchid"),
1734
+ "karma lakelands": ("travel_hotels", "karma_group"),
1735
+ "karma resorts": ("travel_hotels", "karma_group"),
1736
+ "karma royal": ("travel_hotels", "karma_group"),
1737
+ "kempinski": ("travel_hotels", "kempinski"),
1738
+ "lalit suri": ("travel_hotels", "the_lalit"),
1739
+ "lohono stays": ("travel_hotels", "lohono"),
1740
+ "mayfair hotels": ("travel_hotels", "mayfair_hotels"),
1741
+ "mayfair lagoon": ("travel_hotels", "mayfair_hotels"),
1742
+ "moustache escapes": ("travel_hotels", "moustache"),
1743
+ "moustache hostel": ("travel_hotels", "moustache"),
1744
+ "neemrana": ("travel_hotels", "neemrana"),
1745
+ "neemrana fort palace": ("travel_hotels", "neemrana"),
1746
+ "nh collection": ("travel_hotels", "minor_hotels"),
1747
+ "oaks hotels": ("travel_hotels", "minor_hotels"),
1748
+ "oakwood": ("travel_hotels", "ascott"),
1749
+ "orange county resorts": ("travel_hotels", "evolve_back"),
1750
+ "orchid hotel": ("travel_hotels", "the_orchid"),
1751
+ "postcard goa": ("travel_hotels", "postcard_hotel"),
1752
+ "postcard hotel": ("travel_hotels", "postcard_hotel"),
1753
+ "pride hotel": ("travel_hotels", "pride_hotels"),
1754
+ "pride plaza": ("travel_hotels", "pride_hotels"),
1755
+ "quality inn": ("travel_hotels", "choice_hotels"),
1756
+ "ramada": ("travel_hotels", "wyndham"),
1757
+ "ramee grand": ("travel_hotels", "ramee"),
1758
+ "ramee guestline": ("travel_hotels", "ramee"),
1759
+ "regenta": ("travel_hotels", "royal_orchid"),
1760
+ "roseate house": ("travel_hotels", "roseate"),
1761
+ "royal orchid": ("travel_hotels", "royal_orchid"),
1762
+ "royal tulip": ("travel_hotels", "golden_tulip"),
1763
+ "saffron stays": ("travel_hotels", "saffronstays"),
1764
+ "saffronstays": ("travel_hotels", "saffronstays"),
1765
+ "sayaji hotel": ("travel_hotels", "sayaji"),
1766
+ "shangri-la bengaluru": ("travel_hotels", "shangri_la"),
1767
+ "shangri-la eros": ("travel_hotels", "shangri_la"),
1768
+ "shiv niwas": ("travel_hotels", "hrh_hotels"),
1769
+ "somerset": ("travel_hotels", "ascott"),
1770
+ "spice village": ("travel_hotels", "cgh_earth"),
1771
+ "stayvista": ("travel_hotels", "stayvista"),
1772
+ "sure hotel": ("travel_hotels", "best_western"),
1773
+ "the ashok": ("travel_hotels", "itdc_ashok"),
1774
+ "the deltin": ("travel_hotels", "deltin"),
1775
+ "the fern": ("travel_hotels", "the_fern"),
1776
+ "the hosteller": ("travel_hotels", "the_hosteller"),
1777
+ "the lalit": ("travel_hotels", "the_lalit"),
1778
+ "the park hotels": ("travel_hotels", "the_park"),
1779
+ "the roseate": ("travel_hotels", "roseate"),
1780
+ "trip com hotels": ("travel_hotels", "trip_com"),
1781
+ "tulip inn": ("travel_hotels", "golden_tulip"),
1782
+ "vista rooms": ("travel_hotels", "stayvista"),
1783
+ "vits hotels": ("travel_hotels", "the_orchid"),
1784
+ "wyndham grand": ("travel_hotels", "wyndham"),
1785
+ "zo trips": ("travel_hotels", "zostel"),
1786
+ "zone by the park": ("travel_hotels", "the_park"),
1787
+ "zostel": ("travel_hotels", "zostel"),
1788
+ "zostel plus": ("travel_hotels", "zostel"),
1789
+ # --- utilities ---
1790
+ "best mumbai electricity": ("utilities", "best_electricity"),
1791
+ "best undertaking": ("utilities", "best_electricity"),
1792
+ "brpl": ("utilities", "bses"),
1793
+ "bypl": ("utilities", "bses"),
1794
+ "cable tv gujarat": ("utilities", "gtpl"),
1795
+ "delhi electricity": ("utilities", "bses"),
1796
+ "den cable": ("utilities", "den_networks"),
1797
+ "den networks": ("utilities", "den_networks"),
1798
+ "gtpl": ("utilities", "gtpl"),
1799
+ "gtpl broadband": ("utilities", "gtpl"),
1800
+ "maharashtra electricity": ("utilities", "msedcl"),
1801
+ "mumbai power bill": ("utilities", "adani_electricity"),
1802
+ "tikona": ("utilities", "tikona"),
1803
+ "tpddl": ("utilities", "tata_power"),
1804
+ "wireless broadband": ("utilities", "tikona"),
1805
+ # --- insurance ---
1806
+ "acko": ("insurance", "acko"),
1807
+ "bike insurance": ("insurance", "acko"),
1808
+ "car insurance": ("insurance", "acko"),
1809
+ "digit insurance": ("insurance", "digit_insurance"),
1810
+ "godigit": ("insurance", "digit_insurance"),
1811
+ "insurance advisor": ("insurance", "turtlemint"),
1812
+ "insurance comparison": ("insurance", "insurancedekho"),
1813
+ "insurancedekho": ("insurance", "insurancedekho"),
1814
+ "turtlemint": ("insurance", "turtlemint"),
1815
+ # --- education ---
1816
+ "aakash byjus": ("education", "aakash"),
1817
+ "aakash institute": ("education", "aakash"),
1818
+ "allen coaching fees": ("education", "allen"),
1819
+ "allen kota": ("education", "allen"),
1820
+ "byjus": ("education", "byjus"),
1821
+ "certification course": ("education", "simplilearn"),
1822
+ "coursera plus india": ("education", "coursera"),
1823
+ "cuemath": ("education", "cuemath"),
1824
+ "great learning": ("education", "great_learning"),
1825
+ "math classes online": ("education", "cuemath"),
1826
+ "medical coaching fees": ("education", "aakash"),
1827
+ "mygreatlearning": ("education", "great_learning"),
1828
+ "neet jee coaching": ("education", "allen"),
1829
+ "online degree": ("education", "upgrad"),
1830
+ "pg certificate": ("education", "great_learning"),
1831
+ "simplilearn": ("education", "simplilearn"),
1832
+ "think and learn": ("education", "byjus"),
1833
+ "upskilling": ("education", "upgrad"),
1834
+ # --- rent ---
1835
+ "apartment dues": ("rent", "nobrokerhood"),
1836
+ "redgirraffe": ("rent", "redgirraffe"),
1837
+ "rent via credit card": ("rent", "redgirraffe"),
1838
+ "rentpay": ("rent", "redgirraffe"),
1839
+ "society maintenance": ("rent", "nobrokerhood"),
1840
+ # --- entertainment ---
1841
+ "adlabs imagica": ("entertainment", "imagicaa"),
1842
+ "adventure island": ("entertainment", "adventure_island"),
1843
+ "ags cinemas": ("entertainment", "ags_cinemas"),
1844
+ "aha": ("entertainment", "aha_ott"),
1845
+ "aha video": ("entertainment", "aha_ott"),
1846
+ "alt balaji": ("entertainment", "altt"),
1847
+ "altt": ("entertainment", "altt"),
1848
+ "amaazia": ("entertainment", "amaazia"),
1849
+ "amazon music": ("entertainment", "amazon_music"),
1850
+ "apple music": ("entertainment", "apple_music"),
1851
+ "apple tv plus": ("entertainment", "apple_tv_plus"),
1852
+ "apple tv+": ("entertainment", "apple_tv_plus"),
1853
+ "aquatica": ("entertainment", "aquatica"),
1854
+ "audible": ("entertainment", "audible"),
1855
+ "chaupal": ("entertainment", "chaupal"),
1856
+ "city pride": ("entertainment", "city_pride"),
1857
+ "connplex": ("entertainment", "connplex"),
1858
+ "crunchyroll": ("entertainment", "crunchyroll"),
1859
+ "delite cinema": ("entertainment", "delite_cinemas"),
1860
+ "della adventure": ("entertainment", "della_adventure"),
1861
+ "discovery plus": ("entertainment", "discovery_plus"),
1862
+ "discovery+": ("entertainment", "discovery_plus"),
1863
+ "e-square": ("entertainment", "esquare_cinemas"),
1864
+ "escape": ("entertainment", "spi_cinemas"),
1865
+ "esquare": ("entertainment", "esquare_cinemas"),
1866
+ "etv win": ("entertainment", "etv_win"),
1867
+ "explara": ("entertainment", "explara"),
1868
+ "fun cinemas": ("entertainment", "cinepolis"),
1869
+ "fun city": ("entertainment", "fun_city"),
1870
+ "gaana": ("entertainment", "gaana"),
1871
+ "glitz cinemas": ("entertainment", "glitz_cinemas"),
1872
+ "gold cinema": ("entertainment", "gold_cinema"),
1873
+ "imagica": ("entertainment", "imagicaa"),
1874
+ "imagicaa": ("entertainment", "imagicaa"),
1875
+ "iskate": ("entertainment", "iskate"),
1876
+ "jiosaavn": ("entertainment", "jiosaavn"),
1877
+ "kidzania": ("entertainment", "kidzania"),
1878
+ "kuku fm": ("entertainment", "kuku_fm"),
1879
+ "m2k": ("entertainment", "m2k_cinemas"),
1880
+ "manoramamax": ("entertainment", "manorama_max"),
1881
+ "meraevents": ("entertainment", "meraevents"),
1882
+ "mgm dizzee": ("entertainment", "mgm_dizzee"),
1883
+ "mx player": ("entertainment", "mx_player"),
1884
+ "nicco park": ("entertainment", "nicco_park"),
1885
+ "ottplay": ("entertainment", "ottplay"),
1886
+ "palazzo": ("entertainment", "spi_cinemas"),
1887
+ "pocket fm": ("entertainment", "pocket_fm"),
1888
+ "prasads imax": ("entertainment", "prasads"),
1889
+ "prasads multiplex": ("entertainment", "prasads"),
1890
+ "ramoji": ("entertainment", "ramoji_film_city"),
1891
+ "saavn": ("entertainment", "jiosaavn"),
1892
+ "sandhya 70mm": ("entertainment", "sandhya_70mm"),
1893
+ "sathyam": ("entertainment", "spi_cinemas"),
1894
+ "shott": ("entertainment", "shott"),
1895
+ "skillbox": ("entertainment", "skillbox"),
1896
+ "smaaash": ("entertainment", "smaaash"),
1897
+ "snow world": ("entertainment", "snow_world"),
1898
+ "spi cinemas": ("entertainment", "spi_cinemas"),
1899
+ "srs cinemas": ("entertainment", "srs_cinemas"),
1900
+ "stage app": ("entertainment", "stage_ott"),
1901
+ "stage ott": ("entertainment", "stage_ott"),
1902
+ "sun nxt": ("entertainment", "sun_nxt"),
1903
+ "sunnxt": ("entertainment", "sun_nxt"),
1904
+ "timezone": ("entertainment", "timezone"),
1905
+ "townscript": ("entertainment", "townscript"),
1906
+ "vgp marine kingdom": ("entertainment", "vgp_universal"),
1907
+ "vgp universal kingdom": ("entertainment", "vgp_universal"),
1908
+ "wet n joy": ("entertainment", "wetnjoy"),
1909
+ "wetnjoy": ("entertainment", "wetnjoy"),
1910
+ "wonderla": ("entertainment", "wonderla"),
1911
+ "worlds of wonder": ("entertainment", "worlds_of_wonder"),
1912
+ "wow noida": ("entertainment", "worlds_of_wonder"),
1913
+ "xstream play": ("entertainment", "xstream_play"),
1914
+ # --- apparel ---
1915
+ "1 india family mart": ("apparel", "one_india_family_mart"),
1916
+ "1-india family mart": ("apparel", "one_india_family_mart"),
1917
+ "allen solly": ("apparel", "allen_solly"),
1918
+ "american eagle": ("apparel", "american_eagle"),
1919
+ "american tourister": ("apparel", "american_tourister"),
1920
+ "arrow apparel": ("apparel", "arrow_fashion"),
1921
+ "arrow shirts": ("apparel", "arrow_fashion"),
1922
+ "biba": ("apparel", "biba"),
1923
+ "c krishniah chetty": ("apparel", "ckc_jewellers"),
1924
+ "campus activewear": ("apparel", "campus_shoes"),
1925
+ "campus shoes": ("apparel", "campus_shoes"),
1926
+ "celio": ("apparel", "celio"),
1927
+ "central department store": ("apparel", "central_mall"),
1928
+ "central mall": ("apparel", "central_mall"),
1929
+ "city kart": ("apparel", "city_kart"),
1930
+ "citykart": ("apparel", "city_kart"),
1931
+ "ckc jewellers": ("apparel", "ckc_jewellers"),
1932
+ "clarks": ("apparel", "clarks"),
1933
+ "clarks shoes": ("apparel", "clarks"),
1934
+ "crocs": ("apparel", "crocs"),
1935
+ "ethos watch boutique": ("apparel", "ethos_watches"),
1936
+ "ethos watches": ("apparel", "ethos_watches"),
1937
+ "fab india": ("apparel", "fabindia"),
1938
+ "fabindia": ("apparel", "fabindia"),
1939
+ "flying machine": ("apparel", "flying_machine"),
1940
+ "forever new": ("apparel", "forever_new"),
1941
+ "gant": ("apparel", "gant"),
1942
+ "gap india": ("apparel", "gap"),
1943
+ "gap store": ("apparel", "gap"),
1944
+ "gkb opticals": ("apparel", "gkb_opticals"),
1945
+ "grt": ("apparel", "grt_jewellers"),
1946
+ "grt jewellers": ("apparel", "grt_jewellers"),
1947
+ "helios watches": ("apparel", "helios_watches"),
1948
+ "jack & jones": ("apparel", "jack_jones"),
1949
+ "jack and jones": ("apparel", "jack_jones"),
1950
+ "joy alukkas": ("apparel", "joyalukkas"),
1951
+ "joyalukkas": ("apparel", "joyalukkas"),
1952
+ "kalki fashion": ("apparel", "kalki_fashion"),
1953
+ "khazana jewellery": ("apparel", "khazana_jewellery"),
1954
+ "levi's": ("apparel", "levis"),
1955
+ "levis": ("apparel", "levis"),
1956
+ "libas": ("apparel", "libas"),
1957
+ "liberty shoes": ("apparel", "liberty_shoes"),
1958
+ "louis philippe": ("apparel", "louis_philippe"),
1959
+ "mango clothing": ("apparel", "mango_fashion"),
1960
+ "mango fashion": ("apparel", "mango_fashion"),
1961
+ "manyavar": ("apparel", "manyavar"),
1962
+ "mia by tanishq": ("apparel", "mia_by_tanishq"),
1963
+ "mochi shoes": ("apparel", "mochi_shoes"),
1964
+ "mohey": ("apparel", "manyavar"),
1965
+ "only clothing": ("apparel", "only_fashion"),
1966
+ "only fashion": ("apparel", "only_fashion"),
1967
+ "orra": ("apparel", "orra"),
1968
+ "orra jewellery": ("apparel", "orra"),
1969
+ "p n gadgil": ("apparel", "png_jewellers"),
1970
+ "pc jeweller": ("apparel", "pc_jeweller"),
1971
+ "peter england": ("apparel", "peter_england"),
1972
+ "png jewellers": ("apparel", "png_jewellers"),
1973
+ "red tape shoes": ("apparel", "red_tape"),
1974
+ "redtape": ("apparel", "red_tape"),
1975
+ "regal shoes": ("apparel", "regal_shoes"),
1976
+ "reliance jewels": ("apparel", "reliance_jewels"),
1977
+ "safari bags": ("apparel", "safari_bags"),
1978
+ "safari luggage": ("apparel", "safari_bags"),
1979
+ "samsonite": ("apparel", "samsonite"),
1980
+ "senco": ("apparel", "senco_gold"),
1981
+ "senco gold": ("apparel", "senco_gold"),
1982
+ "skechers": ("apparel", "skechers"),
1983
+ "skybags": ("apparel", "skybags"),
1984
+ "specsmakers": ("apparel", "specsmakers"),
1985
+ "style union": ("apparel", "style_union"),
1986
+ "titan eye plus": ("apparel", "titan_eyeplus"),
1987
+ "titan eye+": ("apparel", "titan_eyeplus"),
1988
+ "titan eyeplus": ("apparel", "titan_eyeplus"),
1989
+ "u.s. polo assn": ("apparel", "us_polo"),
1990
+ "under armour": ("apparel", "under_armour"),
1991
+ "underarmour": ("apparel", "under_armour"),
1992
+ "us polo": ("apparel", "us_polo"),
1993
+ "uspa": ("apparel", "us_polo"),
1994
+ "van heusen": ("apparel", "van_heusen"),
1995
+ "vbj jewellers": ("apparel", "vummidi"),
1996
+ "vero moda": ("apparel", "vero_moda"),
1997
+ "vip bags": ("apparel", "vip_bags"),
1998
+ "vip luggage": ("apparel", "vip_bags"),
1999
+ "vision express": ("apparel", "vision_express"),
2000
+ "vummidi bangaru": ("apparel", "vummidi"),
2001
+ "w for woman": ("apparel", "w_for_woman"),
2002
+ "waman hari pethe": ("apparel", "whp_jewellers"),
2003
+ "whp jewellers": ("apparel", "whp_jewellers"),
2004
+ "wildcraft": ("apparel", "wildcraft"),
2005
+ "woodland india": ("apparel", "woodland"),
2006
+ "woodland shoes": ("apparel", "woodland"),
2007
+ "zudio": ("apparel", "zudio"),
2008
+ # --- pharmacy ---
2009
+ "aarogyam": ("pharmacy", "thyrocare"),
2010
+ "agilus": ("pharmacy", "agilus_diagnostics"),
2011
+ "anytime fitness": ("pharmacy", "anytime_fitness"),
2012
+ "aster pharmacy": ("pharmacy", "aster_pharmacy"),
2013
+ "clove dental": ("pharmacy", "clove_dental"),
2014
+ "cultpass": ("pharmacy", "cultfit"),
2015
+ "dava india": ("pharmacy", "davaindia"),
2016
+ "davaindia": ("pharmacy", "davaindia"),
2017
+ "dawaa dost": ("pharmacy", "dawaa_dost"),
2018
+ "dawaadost": ("pharmacy", "dawaa_dost"),
2019
+ "dr agarwal eye": ("pharmacy", "dr_agarwals"),
2020
+ "dr agarwals": ("pharmacy", "dr_agarwals"),
2021
+ "dr lal pathlabs": ("pharmacy", "dr_lal_pathlabs"),
2022
+ "fitness first": ("pharmacy", "fitness_first"),
2023
+ "frank ross": ("pharmacy", "frank_ross"),
2024
+ "frankross pharmacy": ("pharmacy", "frank_ross"),
2025
+ "gold's gym": ("pharmacy", "golds_gym"),
2026
+ "golds gym": ("pharmacy", "golds_gym"),
2027
+ "guardian pharmacy": ("pharmacy", "guardian_pharmacy"),
2028
+ "healthians": ("pharmacy", "healthians"),
2029
+ "healthkart": ("pharmacy", "healthkart"),
2030
+ "kaya clinic": ("pharmacy", "kaya_clinic"),
2031
+ "kaya skin": ("pharmacy", "kaya_clinic"),
2032
+ "lal path labs": ("pharmacy", "dr_lal_pathlabs"),
2033
+ "lalpathlabs": ("pharmacy", "dr_lal_pathlabs"),
2034
+ "lucid diagnostics": ("pharmacy", "lucid_diagnostics"),
2035
+ "lucid medical": ("pharmacy", "lucid_diagnostics"),
2036
+ "med 247": ("pharmacy", "med247"),
2037
+ "med247": ("pharmacy", "med247"),
2038
+ "medibuddy": ("pharmacy", "medibuddy"),
2039
+ "muscleblaze": ("pharmacy", "muscleblaze"),
2040
+ "neuberg": ("pharmacy", "neuberg_diagnostics"),
2041
+ "noble pharmacy": ("pharmacy", "noble_plus"),
2042
+ "noble plus": ("pharmacy", "noble_plus"),
2043
+ "nutrabay": ("pharmacy", "nutrabay"),
2044
+ "o2 spa": ("pharmacy", "o2_spa"),
2045
+ "orange health": ("pharmacy", "orange_health"),
2046
+ "orange health labs": ("pharmacy", "orange_health"),
2047
+ "pathkind": ("pharmacy", "pathkind_labs"),
2048
+ "sabka dentist": ("pharmacy", "sabka_dentist"),
2049
+ "snap fitness": ("pharmacy", "snap_fitness"),
2050
+ "srl diagnostics": ("pharmacy", "agilus_diagnostics"),
2051
+ "suburban diagnostics": ("pharmacy", "suburban_diagnostics"),
2052
+ "suraksha diagnostic": ("pharmacy", "suraksha_diagnostics"),
2053
+ "suraksha diagnostics": ("pharmacy", "suraksha_diagnostics"),
2054
+ "thyrocare": ("pharmacy", "thyrocare"),
2055
+ "truemeds": ("pharmacy", "truemeds"),
2056
+ "vasan eye care": ("pharmacy", "vasan_eye_care"),
2057
+ "vijaya diagnostic": ("pharmacy", "vijaya_diagnostics"),
2058
+ "vijaya diagnostics": ("pharmacy", "vijaya_diagnostics"),
2059
+ "vlcc": ("pharmacy", "vlcc"),
2060
+ "wellbeing nutrition": ("pharmacy", "wellbeing_nutrition"),
2061
+ "zeno health": ("pharmacy", "zeno_health"),
2062
+ "zeno pharmacy": ("pharmacy", "zeno_health"),
2063
+ # --- transport ---
2064
+ "airport transfer": ("transport", "savaari"),
2065
+ "aqua line": ("transport", "mumbai_metro"),
2066
+ "ather grid": ("transport", "ather_grid"),
2067
+ "bangalore metro card": ("transport", "namma_metro"),
2068
+ "bike rental": ("transport", "royal_brothers"),
2069
+ "bmrcl": ("transport", "namma_metro"),
2070
+ "car rental": ("transport", "zoomcar"),
2071
+ "car subscription": ("transport", "revv"),
2072
+ "chargezone": ("transport", "chargezone"),
2073
+ "chennai metro": ("transport", "chennai_metro"),
2074
+ "cityflo": ("transport", "cityflo"),
2075
+ "cmrl": ("transport", "chennai_metro"),
2076
+ "delhi metro": ("transport", "delhi_metro"),
2077
+ "dmrc": ("transport", "delhi_metro"),
2078
+ "electric scooter charging": ("transport", "ather_grid"),
2079
+ "ev charging": ("transport", "ather_grid"),
2080
+ "ev charging app": ("transport", "tata_power_ez_charge"),
2081
+ "ev charging stations": ("transport", "statiq"),
2082
+ "ev fast charging": ("transport", "chargezone"),
2083
+ "ez charge": ("transport", "tata_power_ez_charge"),
2084
+ "gozo": ("transport", "gozo_cabs"),
2085
+ "gozocabs": ("transport", "gozo_cabs"),
2086
+ "metro card recharge": ("transport", "delhi_metro"),
2087
+ "mmrc": ("transport", "mumbai_metro"),
2088
+ "mumbai bus commute": ("transport", "cityflo"),
2089
+ "mumbai metro": ("transport", "mumbai_metro"),
2090
+ "mumbai1": ("transport", "mumbai_metro"),
2091
+ "namma metro": ("transport", "namma_metro"),
2092
+ "ncmc": ("transport", "delhi_metro"),
2093
+ "outstation cab": ("transport", "savaari"),
2094
+ "outstation taxi": ("transport", "gozo_cabs"),
2095
+ "revv": ("transport", "revv"),
2096
+ "royal brothers": ("transport", "royal_brothers"),
2097
+ "savaari": ("transport", "savaari"),
2098
+ "scooter rental": ("transport", "royal_brothers"),
2099
+ "self drive": ("transport", "zoomcar"),
2100
+ "singara chennai card": ("transport", "chennai_metro"),
2101
+ "statiq": ("transport", "statiq"),
2102
+ "tata power ev": ("transport", "tata_power_ez_charge"),
2103
+ "zoomcar": ("transport", "zoomcar"),
2104
+ }
2105
+ for _k, _v in _PROPOSED_2026_08.items():
2106
+ MERCHANT_MAP.setdefault(_k, _v)
2107
+
2108
+ # Surat Diamond — carries a live ICICI 20% offer (2026-08-08 ICICI feed harvest).
2109
+ MERCHANT_MAP.setdefault("surat diamond", ("apparel", "surat_diamond"))
2110
+
2111
+
2112
  # Retailers / merchants preferred over product words so "iPhone at Croma"
2113
  # resolves to Croma, not iPhone.
2114
  STORE_KEYWORDS = {
app/offers_data/curated_offers.json CHANGED
The diff for this file is too large to render. See raw diff