sammy786 commited on
Commit
283d2fb
·
1 Parent(s): e2999d0

backend: airline/chain-direct offers in flight+hotel HTTP scoring

Browse files
Files changed (1) hide show
  1. app/main.py +25 -8
app/main.py CHANGED
@@ -188,6 +188,13 @@ class FlightSellersRequest(BaseModel):
188
  held_cards: Optional[List[str]] = None
189
  persona: Optional[List[str]] = None
190
  city: Optional[str] = None
 
 
 
 
 
 
 
191
  include_comparison: Optional[bool] = False # app scores on-device by default
192
 
193
 
@@ -224,6 +231,9 @@ class HotelSellersRequest(BaseModel):
224
  adults: Optional[int] = 2
225
  held_cards: Optional[List[str]] = None
226
  persona: Optional[List[str]] = None
 
 
 
227
  include_comparison: Optional[bool] = False
228
 
229
 
@@ -498,7 +508,7 @@ def flights_search(req: FlightSearchRequest, request: Request = None):
498
  _limit(request, "flt", rate=30) # 30/min per IP per worker
499
  import flights_provider
500
  import flight_sellers
501
- from channels import compare_channels
502
  from availability import normalize_city
503
 
504
  held = req.held_cards or demo_data.DEMO_WALLET
@@ -564,7 +574,9 @@ def flights_search(req: FlightSearchRequest, request: Request = None):
564
  for f in flights:
565
  cmp = compare_channels(
566
  held, "travel_flights", float(f["fare_inr"]),
567
- brand_key=None, merchant=None, rail="card",
 
 
568
  persona=persona, city=city, international=intl,
569
  # The party this search is for. Without it the server always scored
570
  # 1 passenger one-way while the app scored the real party, so the two
@@ -616,7 +628,7 @@ def flights_sellers(req: FlightSellersRequest, request: Request = None):
616
  if request is not None:
617
  _limit(request, "fls", rate=20) # 20/min per IP per worker
618
  import flight_sellers
619
- from channels import compare_channels
620
  from availability import normalize_city
621
  import geo
622
 
@@ -633,7 +645,9 @@ def flights_sellers(req: FlightSellersRequest, request: Request = None):
633
  base = min(data["channel_prices"].values()) if data["channel_prices"] else 0.0
634
  cmp = compare_channels(
635
  held, "travel_flights", float(base),
636
- brand_key=None, merchant=None, rail="card",
 
 
637
  persona=req.persona or demo_data.DEMO_PERSONA,
638
  city=normalize_city(req.city),
639
  international=geo.route_is_international(req.src, req.dst),
@@ -691,7 +705,7 @@ def hotels_search(req: HotelSearchRequest, request: Request = None):
691
  if request is not None:
692
  _limit(request, "htl", rate=30)
693
  import hotels_provider
694
- from channels import compare_channels
695
  from availability import normalize_city
696
 
697
  held = req.held_cards or demo_data.DEMO_WALLET
@@ -717,7 +731,8 @@ def hotels_search(req: HotelSearchRequest, request: Request = None):
717
  for h in hotels:
718
  cmp = compare_channels(
719
  held, "travel_hotels", float(h["price_inr"]),
720
- brand_key=None, merchant=None, rail="card",
 
721
  persona=persona, city=city, international=intl,
722
  ) if want_cmp else None
723
  results.append({"hotel": h, "channel_comparison": cmp})
@@ -749,7 +764,7 @@ def hotels_sellers(req: HotelSellersRequest, request: Request = None):
749
  if request is not None:
750
  _limit(request, "hts", rate=20)
751
  import hotel_sellers
752
- from channels import compare_channels
753
  from availability import normalize_city
754
  import geo
755
 
@@ -763,7 +778,9 @@ def hotels_sellers(req: HotelSellersRequest, request: Request = None):
763
  base = min(data["channel_prices"].values())
764
  cmp = compare_channels(
765
  held, "travel_hotels", float(base),
766
- brand_key=None, merchant=None, rail="card",
 
 
767
  persona=req.persona or demo_data.DEMO_PERSONA,
768
  city=normalize_city(req.city) or req.city,
769
  international=geo.city_is_international(req.city),
 
188
  held_cards: Optional[List[str]] = None
189
  persona: Optional[List[str]] = None
190
  city: Optional[str] = None
191
+ # The picked flight's airline, so the DIRECT channel scores that airline's
192
+ # own offers (Air India's flat Rs3,000 Axis discount, etc.) - the on-device
193
+ # app passes this via airlineBrandKey; without it the endpoint's optional
194
+ # comparison scored the airline website with no airline and missed those
195
+ # deals (2026-08-11 international app-vs-endpoint test). Optional: an older
196
+ # client that omits it gets exactly the prior behaviour.
197
+ airline: Optional[str] = None
198
  include_comparison: Optional[bool] = False # app scores on-device by default
199
 
200
 
 
231
  adults: Optional[int] = 2
232
  held_cards: Optional[List[str]] = None
233
  persona: Optional[List[str]] = None
234
+ # The picked property's name, so the DIRECT channel scores that chain's own
235
+ # offers (Marriott/IHG etc.) - mirror of the app's hotelBrandKey. Optional.
236
+ property_name: Optional[str] = None
237
  include_comparison: Optional[bool] = False
238
 
239
 
 
508
  _limit(request, "flt", rate=30) # 30/min per IP per worker
509
  import flights_provider
510
  import flight_sellers
511
+ from channels import compare_channels, airline_brand_key
512
  from availability import normalize_city
513
 
514
  held = req.held_cards or demo_data.DEMO_WALLET
 
574
  for f in flights:
575
  cmp = compare_channels(
576
  held, "travel_flights", float(f["fare_inr"]),
577
+ # This flight's own airline, so "Airline website" scores that
578
+ # carrier's offers. Mirror of the app's per-row airlineBrandKey.
579
+ brand_key=airline_brand_key(f.get("airline")), merchant=None, rail="card",
580
  persona=persona, city=city, international=intl,
581
  # The party this search is for. Without it the server always scored
582
  # 1 passenger one-way while the app scored the real party, so the two
 
628
  if request is not None:
629
  _limit(request, "fls", rate=20) # 20/min per IP per worker
630
  import flight_sellers
631
+ from channels import compare_channels, airline_brand_key
632
  from availability import normalize_city
633
  import geo
634
 
 
645
  base = min(data["channel_prices"].values()) if data["channel_prices"] else 0.0
646
  cmp = compare_channels(
647
  held, "travel_flights", float(base),
648
+ # The picked flight's airline (sent by the client), so the direct
649
+ # channel scores that carrier's offers - matches the app.
650
+ brand_key=airline_brand_key(req.airline), merchant=None, rail="card",
651
  persona=req.persona or demo_data.DEMO_PERSONA,
652
  city=normalize_city(req.city),
653
  international=geo.route_is_international(req.src, req.dst),
 
705
  if request is not None:
706
  _limit(request, "htl", rate=30)
707
  import hotels_provider
708
+ from channels import compare_channels, hotel_brand_key
709
  from availability import normalize_city
710
 
711
  held = req.held_cards or demo_data.DEMO_WALLET
 
731
  for h in hotels:
732
  cmp = compare_channels(
733
  held, "travel_hotels", float(h["price_inr"]),
734
+ # This property's chain, so "Hotel directly" scores its own offers.
735
+ brand_key=hotel_brand_key(h.get("name")), merchant=None, rail="card",
736
  persona=persona, city=city, international=intl,
737
  ) if want_cmp else None
738
  results.append({"hotel": h, "channel_comparison": cmp})
 
764
  if request is not None:
765
  _limit(request, "hts", rate=20)
766
  import hotel_sellers
767
+ from channels import compare_channels, hotel_brand_key
768
  from availability import normalize_city
769
  import geo
770
 
 
778
  base = min(data["channel_prices"].values())
779
  cmp = compare_channels(
780
  held, "travel_hotels", float(base),
781
+ # The picked property's chain (sent by the client), so the direct
782
+ # channel scores its own offers - matches the app.
783
+ brand_key=hotel_brand_key(req.property_name), merchant=None, rail="card",
784
  persona=req.persona or demo_data.DEMO_PERSONA,
785
  city=normalize_city(req.city) or req.city,
786
  international=geo.city_is_international(req.city),