Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
|
@@ -116,14 +116,14 @@ KEYWORD_OVERRIDE = {
|
|
| 116 |
"goodbye": ["ู
ุน ุงูุณูุงู
ุฉ","ู
ุน ุงูุณูุงู
ู","ุจุงู","ูุฏุงุนุง","bye","goodbye","ุชุตุจุญ ุนูู ุฎูุฑ",
|
| 117 |
"ูู ุงู
ุงู ุงููู","ุงููู ูุณูู
ู","ุณูุงู
ุชู"],
|
| 118 |
"greeting":["ุงูุณูุงู
ุนูููู
","ูุนูููู
ุงูุณูุงู
","ุงููุง","ุฃููุง","ููุง","ููู","ู
ุฑุญุจุง","ู
ุฑุญุจุงู",
|
| 119 |
-
"ุตุจุงุญ ุงูุฎูุฑ","ู
ุณุงุก ุงูุฎูุฑ","ูุงู","hi","hello","ุตุจุงุญ","ู
ุณุงุก"],
|
| 120 |
"thanks": ["ุดูุฑุง","ุดูุฑุงู","ุชุณูู
","ูุณูู
ู","ู
ู
ููู","ู
ุดููุฑ","thanks","thank","ุงูู ุดูุฑ"],
|
| 121 |
}
|
| 122 |
CATEGORY_KEYWORDS = {
|
| 123 |
-
"restaurant":["ู
ุทุนู
","ุงูู","ูุฌุจุงุช","ู
ุดููุงุช","ูุจุงุจ","ุดุงูุฑู
ุง","ูุฑูุจ","ุณูุฏูุชุด","ุณูุฏูุชุดุงุช","ุจุฑุฌุฑ","ุณู
ู","ูุฑุงูุฏ","ู
ุทุงุนู
","ููู","ุทุนู
ูุฉ"],
|
| 124 |
-
"pharmacy": ["ุตูุฏููู","ุตูุฏููุฉ","ุฏูุง","ุงุฏููู","ุฏูุงุก","ุตูุฏูู","ุฏูุชูุฑ","ุนูุงุฌ"],
|
| 125 |
-
"cafe": ["ูุงููู","ูููู","ูููู","ูููุฉ","ูุงููุชูุฑูุง","ูุงููุฉ","ูููู"],
|
| 126 |
-
"supermarket":["ุณูุจุฑู
ุงุฑูุช","ู
ุงุฑูุช","ุจูุงูู","ูุงูุจุฑ","ุจูุงูุฉ","ุณูุจุฑ ู
ุงุฑูุช","ุณูุจุฑู
ุงุฑูุงุช","ุฌุฑูุณุฑู"],
|
| 127 |
"housing": ["ุดูู","ุดูุฉ","ุงูุฌุงุฑ","ุฅูุฌุงุฑ","ููุฏู","ููุณุชู","ุณูู","ุณูู"],
|
| 128 |
}
|
| 129 |
_CAT_MAP = {
|
|
@@ -420,15 +420,63 @@ def rebuild_embeddings(df: pd.DataFrame, force: bool = False):
|
|
| 420 |
"""HELPER FUNCTIONS"""
|
| 421 |
|
| 422 |
def normalize_category(cat):
|
| 423 |
-
|
|
|
|
|
|
|
| 424 |
cat_s = str(cat).strip()
|
| 425 |
-
if cat_s in ("restaurant","pharmacy","cafe","supermarket","housing"):
|
| 426 |
-
return cat_s
|
| 427 |
c = clean_text(cat_s)
|
| 428 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 429 |
for ar, en in _CAT_MAP.items():
|
| 430 |
-
if ar in c or c in ar:
|
| 431 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 432 |
|
| 433 |
def apply_keyword_override(text):
|
| 434 |
t = norm(text); tw = set(t.split())
|
|
@@ -621,11 +669,12 @@ def apply_filters(df, category=None, sub_category=None, location=None,
|
|
| 621 |
|
| 622 |
# โโ category โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 623 |
if category:
|
| 624 |
-
|
| 625 |
-
f_cat = f[f["
|
| 626 |
-
if
|
| 627 |
-
|
| 628 |
-
# ูู ู
|
|
|
|
| 629 |
|
| 630 |
# โโ sub_category โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 631 |
if sub_category:
|
|
@@ -771,6 +820,15 @@ def rank(df, query, user_lat=None, user_lon=None, intent=None):
|
|
| 771 |
axis=1
|
| 772 |
)
|
| 773 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 774 |
return df.sort_values("final_score", ascending=False).reset_index(drop=True)
|
| 775 |
|
| 776 |
def search_places(query, top_k_final=5, category=None, sub_category=None,
|
|
@@ -834,17 +892,8 @@ def search_places(query, top_k_final=5, category=None, sub_category=None,
|
|
| 834 |
strict_location=bool(location),
|
| 835 |
)
|
| 836 |
|
| 837 |
-
#
|
| 838 |
-
|
| 839 |
-
filtered = apply_filters(
|
| 840 |
-
all_cands,
|
| 841 |
-
sub_category=sub_category,
|
| 842 |
-
price_range=price_range,
|
| 843 |
-
open_now_only=open_now_only,
|
| 844 |
-
min_rating=min_rating,
|
| 845 |
-
strict_location=False,
|
| 846 |
-
)
|
| 847 |
-
|
| 848 |
if filtered.empty:
|
| 849 |
return pd.DataFrame()
|
| 850 |
|
|
@@ -1710,10 +1759,9 @@ def chat(text: str, session, user_lat=None, user_lon=None):
|
|
| 1710 |
|
| 1711 |
# โโ proximity query: ูู ู
ููุด lat/lon โโโโโโโโโโโโโโโโโโโโโโโโ
|
| 1712 |
t_low = norm(text)
|
| 1713 |
-
|
| 1714 |
-
|
| 1715 |
-
|
| 1716 |
-
"ูุนูู ุงูู location ู
ู ุงูุชุทุจูู ุฃู ูููู ุฃูุช ูู ุฃููู ู
ูุทูุฉุ")
|
| 1717 |
result.update(reply=reply, intent="missing_info",
|
| 1718 |
best_place=None, all_results=[])
|
| 1719 |
session.add(text, reply, "missing_info", ents, None, [])
|
|
@@ -1887,7 +1935,7 @@ SEARCH_INTENTS.add("show_menu")
|
|
| 1887 |
_MENU_TRIGGERS = {"ู
ููู","menu","ุงููุงุฆู
ู","ูุงูู
ุฉ","ูุงุฆู
ุฉ","ุงูุงููุงุช","ุงููุงุช","ุนุฑูุถู","ุนุฑุถ ุงูู
ุทุนู
"}
|
| 1888 |
_ITEM_TRIGGERS = {
|
| 1889 |
# ุฃููุงุช ุฑุฆูุณูุฉ
|
| 1890 |
-
"ุจูุชุฒุง","ุจุฑุฌุฑ","ูุฑูุจ","ุดุงูุฑู
ุง","ุจุฑูุณุช","ุณูุดู","ุฑุงูุด",
|
| 1891 |
"ุณุงูุฏูุชุด","ุณูุฏูุชุด","ุจุณุทุฑู
ู","ูุจุฏู","ูุจุฏุฉ","ุญูุงูุดู",
|
| 1892 |
"ุทุนู
ูู","ุทุนู
ูุฉ","ููู","ูุดุฑู","ู
ูุฑููู","ูุงุฒุงููุง",
|
| 1893 |
# ูุญูู
ูุฏุฌุงุฌ ูุณู
ู
|
|
@@ -2092,6 +2140,80 @@ def search_places_by_item(item_query: str) -> list[dict]:
|
|
| 2092 |
log.info(f"๐ search_by_item fuzzy โ {len(places)} results")
|
| 2093 |
return places
|
| 2094 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2095 |
def get_place_menu(place_id: str) -> list[dict]:
|
| 2096 |
"""
|
| 2097 |
Calls GET /api/mobile/places/<place_id>/menu
|
|
@@ -2222,7 +2344,8 @@ def handle_search_by_item(text: str, session, user_lat=None, user_lon=None) -> d
|
|
| 2222 |
Handles search_by_item intent end-to-end.
|
| 2223 |
1. Extract item_query
|
| 2224 |
2. Call backend API
|
| 2225 |
-
3.
|
|
|
|
| 2226 |
"""
|
| 2227 |
item_query = extract_item_query(text)
|
| 2228 |
item_query = clean_item_query(item_query)
|
|
@@ -2234,7 +2357,21 @@ def handle_search_by_item(text: str, session, user_lat=None, user_lon=None) -> d
|
|
| 2234 |
"place_cards": [],
|
| 2235 |
"best_place": None,
|
| 2236 |
}
|
|
|
|
| 2237 |
places = search_places_by_item(item_query)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2238 |
result = format_item_search_response(places, item_query, user_lat, user_lon)
|
| 2239 |
session.add(text, result["reply"], "search_by_item", {"item": item_query},
|
| 2240 |
result.get("best_place"), places)
|
|
@@ -2598,4 +2735,4 @@ def reload_data(x_secret: Optional[str] = Header(default=None)):
|
|
| 2598 |
def reset_session(session_id: str):
|
| 2599 |
SESSIONS.pop(session_id, None)
|
| 2600 |
log.info(f"๐๏ธ Session {session_id} reset")
|
| 2601 |
-
return {"status": "reset", "session_id": session_id}
|
|
|
|
| 116 |
"goodbye": ["ู
ุน ุงูุณูุงู
ุฉ","ู
ุน ุงูุณูุงู
ู","ุจุงู","ูุฏุงุนุง","bye","goodbye","ุชุตุจุญ ุนูู ุฎูุฑ",
|
| 117 |
"ูู ุงู
ุงู ุงููู","ุงููู ูุณูู
ู","ุณูุงู
ุชู"],
|
| 118 |
"greeting":["ุงูุณูุงู
ุนูููู
","ูุนูููู
ุงูุณูุงู
","ุงููุง","ุฃููุง","ููุง","ููู","ู
ุฑุญุจุง","ู
ุฑุญุจุงู",
|
| 119 |
+
"ุตุจุงุญ ุงูุฎูุฑ","ู
ุณุงุก ุงูุฎูุฑ","ูุงู","hi","hello","ุงุฒูู","ุงุฎุจุงุฑู","ุนุงู
ู ุงูู","ุตุจุงุญ","ู
ุณุงุก"],
|
| 120 |
"thanks": ["ุดูุฑุง","ุดูุฑุงู","ุชุณูู
","ูุณูู
ู","ู
ู
ููู","ู
ุดููุฑ","thanks","thank","ุงูู ุดูุฑ"],
|
| 121 |
}
|
| 122 |
CATEGORY_KEYWORDS = {
|
| 123 |
+
"restaurant":["ู
ุทุนู
","ุงูู","ุฃูู","ูุฌุจุงุช","ู
ุดููุงุช","ูุจุงุจ","ุดุงูุฑู
ุง","ูุฑูุจ","ุณูุฏูุชุด","ุณูุฏูุชุดุงุช","ุจุฑุฌุฑ","ุณู
ู","ูุฑุงูุฏ","ู
ุทุงุนู
","ููู","ุทุนู
ูุฉ","restaurant","restaurants","food","meal","burger","pizza","shawarma","crepe","grill","grills"],
|
| 124 |
+
"pharmacy": ["ุตูุฏููู","ุตูุฏููุฉ","ุฏูุง","ุงุฏููู","ุฏูุงุก","ุตูุฏูู","ุฏูุชูุฑ","ุนูุงุฌ","pharmacy","drugstore","medicine"],
|
| 125 |
+
"cafe": ["ูุงููู","ูููู","ูููู","ูููุฉ","ูุงููุชูุฑูุง","ูุงููุฉ","ูููู","cafe","coffee","coffee shop"],
|
| 126 |
+
"supermarket":["ุณูุจุฑู
ุงุฑูุช","ู
ุงุฑูุช","ุจูุงูู","ูุงูุจุฑ","ุจูุงูุฉ","ุณูุจุฑ ู
ุงุฑูุช","ุณูุจุฑู
ุงุฑูุงุช","ุฌุฑูุณุฑู","supermarket","market","grocery","hypermarket"],
|
| 127 |
"housing": ["ุดูู","ุดูุฉ","ุงูุฌุงุฑ","ุฅูุฌุงุฑ","ููุฏู","ููุณุชู","ุณูู","ุณูู"],
|
| 128 |
}
|
| 129 |
_CAT_MAP = {
|
|
|
|
| 420 |
"""HELPER FUNCTIONS"""
|
| 421 |
|
| 422 |
def normalize_category(cat):
|
| 423 |
+
"""Normalize DB/API categories to the app canonical categories."""
|
| 424 |
+
if not cat:
|
| 425 |
+
return cat
|
| 426 |
cat_s = str(cat).strip()
|
|
|
|
|
|
|
| 427 |
c = clean_text(cat_s)
|
| 428 |
+
|
| 429 |
+
# exact canonical values
|
| 430 |
+
if c in ("restaurant", "pharmacy", "cafe", "supermarket", "housing"):
|
| 431 |
+
return c
|
| 432 |
+
|
| 433 |
+
# English / mixed API categories
|
| 434 |
+
if "pharmacy" in c or "ุตูุฏูู" in c or "ุตูุฏูู" in c:
|
| 435 |
+
return "pharmacy"
|
| 436 |
+
if "supermarket" in c or "market" in c or "ู
ุงุฑูุช" in c or "ุจูุงู" in c or "ูุงูุจุฑ" in c:
|
| 437 |
+
return "supermarket"
|
| 438 |
+
if "housing" in c or "hotel" in c or "hostel" in c or "ุดูู" in c or "ุณูู" in c or "ููุฏู" in c:
|
| 439 |
+
return "housing"
|
| 440 |
+
# Restaurant & Cafรฉ: ูู ู
ุทููุจ restaurant ููุนุฏู ุจุงูู contains ูู ุงูููุชุฑุ ููู normalized ุงูุฃุณุงุณู restaurant
|
| 441 |
+
if "restaurant" in c or "ู
ุทุนู
" in c or "ู
ุทุงุนู
" in c:
|
| 442 |
+
return "restaurant"
|
| 443 |
+
if "cafe" in c or "coffee" in c or "ูุงููู" in c or "ูููู" in c or "ูููู" in c or "ูููุฉ" in c:
|
| 444 |
+
return "cafe"
|
| 445 |
+
|
| 446 |
+
if c in _CAT_MAP:
|
| 447 |
+
return _CAT_MAP[c]
|
| 448 |
for ar, en in _CAT_MAP.items():
|
| 449 |
+
if ar in c or c in ar:
|
| 450 |
+
return en
|
| 451 |
+
return c
|
| 452 |
+
|
| 453 |
+
|
| 454 |
+
def _category_match_value(raw_category: str, target_category: str) -> bool:
|
| 455 |
+
"""Strict category match without allowing unrelated fallback."""
|
| 456 |
+
if not target_category:
|
| 457 |
+
return True
|
| 458 |
+
target = normalize_category(target_category)
|
| 459 |
+
raw = clean_text(raw_category)
|
| 460 |
+
|
| 461 |
+
if target == "restaurant":
|
| 462 |
+
return ("restaurant" in raw or "ู
ุทุนู
" in raw or "ู
ุทุงุนู
" in raw) and "pharmacy" not in raw and "ุตูุฏูู" not in raw
|
| 463 |
+
if target == "cafe":
|
| 464 |
+
return "cafe" in raw or "coffee" in raw or "ูุงููู" in raw or "ูููู" in raw or "ูููู" in raw or "ูููุฉ" in raw
|
| 465 |
+
if target == "pharmacy":
|
| 466 |
+
return "pharmacy" in raw or "ุตูุฏูู" in raw or "ุตูุฏูู" in raw
|
| 467 |
+
if target == "supermarket":
|
| 468 |
+
return "supermarket" in raw or "market" in raw or "ู
ุงุฑูุช" in raw or "ุจูุงู" in raw or "ูุงูุจุฑ" in raw
|
| 469 |
+
if target == "housing":
|
| 470 |
+
return "housing" in raw or "hotel" in raw or "hostel" in raw or "ุดูู" in raw or "ุณูู" in raw or "ููุฏู" in raw
|
| 471 |
+
return target in raw
|
| 472 |
+
|
| 473 |
+
|
| 474 |
+
def _is_proximity_query(text: str) -> bool:
|
| 475 |
+
t = norm(text)
|
| 476 |
+
return any(w in t for w in [
|
| 477 |
+
"ุงูุฑุจ", "ุฃูุฑุจ", "ุงูุงูุฑุจ", "ุงูุฃูุฑุจ", "ูุฑูุจ", "ูุฑูุจู", "ูุฑูุจุฉ",
|
| 478 |
+
"ุฌูุจู", "ุญูุงููุง", "ุญููู", "near", "nearest", "nearby", "close"
|
| 479 |
+
])
|
| 480 |
|
| 481 |
def apply_keyword_override(text):
|
| 482 |
t = norm(text); tw = set(t.split())
|
|
|
|
| 669 |
|
| 670 |
# โโ category โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 671 |
if category:
|
| 672 |
+
target_cat = normalize_category(category)
|
| 673 |
+
f_cat = f[f["category"].astype(str).apply(lambda x: _category_match_value(x, target_cat))]
|
| 674 |
+
if f_cat.empty and "category_clean" in f.columns:
|
| 675 |
+
f_cat = f[f["category_clean"].astype(str).apply(lambda x: _category_match_value(x, target_cat))]
|
| 676 |
+
# strict: ูู ุงูู
ุณุชุฎุฏู
ุทูุจ category ู
ุนููุฉ ู
ู
ููุน ูุจุฏูููุง ุจู category ุชุงููุฉ
|
| 677 |
+
f = f_cat
|
| 678 |
|
| 679 |
# โโ sub_category โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 680 |
if sub_category:
|
|
|
|
| 820 |
axis=1
|
| 821 |
)
|
| 822 |
|
| 823 |
+
if is_proximity and has_loc and "distance_km" in df.columns:
|
| 824 |
+
# ูู ุทูุจ "ุฃูุฑุจ" ูู
ุนุงูุง location: ุงูู
ุณุงูุฉ ูู ุงูุญูููู
ุงูุฃูู
|
| 825 |
+
df = df.sort_values(
|
| 826 |
+
by=["distance_km", "rating_norm"],
|
| 827 |
+
ascending=[True, False],
|
| 828 |
+
na_position="last",
|
| 829 |
+
).reset_index(drop=True)
|
| 830 |
+
return df
|
| 831 |
+
|
| 832 |
return df.sort_values("final_score", ascending=False).reset_index(drop=True)
|
| 833 |
|
| 834 |
def search_places(query, top_k_final=5, category=None, sub_category=None,
|
|
|
|
| 892 |
strict_location=bool(location),
|
| 893 |
)
|
| 894 |
|
| 895 |
+
# ู
ูู
: ู
ู
ููุน ููุบู category ูู ุงูู
ุณุชุฎุฏู
ุทูุจ nearest_* ุฃู category ูุงุถุญุฉ
|
| 896 |
+
# ูุฃู ุฏู ูุงู ุจูุฑุฌุน restaurant ูู ุณุคุงู nearest_pharmacy ู
ุซูุงู.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 897 |
if filtered.empty:
|
| 898 |
return pd.DataFrame()
|
| 899 |
|
|
|
|
| 1759 |
|
| 1760 |
# โโ proximity query: ูู ู
ููุด lat/lon โโโโโโโโโโโโโโโโโโโโโโโโ
|
| 1761 |
t_low = norm(text)
|
| 1762 |
+
if _is_proximity_query(text) and not (user_lat and user_lon):
|
| 1763 |
+
reply = ("๐ ุนุดุงู ุฃุญุฏุฏ ุงูุฃูุฑุจ ู
ุญุชุงุฌ ุชุณู
ุญูู ุจุงูููููุดู.\n"
|
| 1764 |
+
"ุฃู ูููู ุงูู
ูุทูุฉ ุงููู ุฃูุช ูููุง.")
|
|
|
|
| 1765 |
result.update(reply=reply, intent="missing_info",
|
| 1766 |
best_place=None, all_results=[])
|
| 1767 |
session.add(text, reply, "missing_info", ents, None, [])
|
|
|
|
| 1935 |
_MENU_TRIGGERS = {"ู
ููู","menu","ุงููุงุฆู
ู","ูุงูู
ุฉ","ูุงุฆู
ุฉ","ุงูุงููุงุช","ุงููุงุช","ุนุฑูุถู","ุนุฑุถ ุงูู
ุทุนู
"}
|
| 1936 |
_ITEM_TRIGGERS = {
|
| 1937 |
# ุฃููุงุช ุฑุฆูุณูุฉ
|
| 1938 |
+
"ุจูุชุฒุง","ุจุฑุฌุฑ","ูุฑูุจ","ุดุงูุฑู
ุง","ุจุฑูุณุช","ุณูุดู","ุฑุงูุด","pizza","burger","crepe","shawarma","broast","sushi","ranch",
|
| 1939 |
"ุณุงูุฏูุชุด","ุณูุฏูุชุด","ุจุณุทุฑู
ู","ูุจุฏู","ูุจุฏุฉ","ุญูุงูุดู",
|
| 1940 |
"ุทุนู
ูู","ุทุนู
ูุฉ","ููู","ูุดุฑู","ู
ูุฑููู","ูุงุฒุงููุง",
|
| 1941 |
# ูุญูู
ูุฏุฌุงุฌ ูุณู
ู
|
|
|
|
| 2140 |
log.info(f"๐ search_by_item fuzzy โ {len(places)} results")
|
| 2141 |
return places
|
| 2142 |
|
| 2143 |
+
|
| 2144 |
+
def filter_item_results_strict(places: list, item_query: str) -> list:
|
| 2145 |
+
"""
|
| 2146 |
+
ููุชุฑ ููู ููุชุงุฆุฌ search_by_item:
|
| 2147 |
+
- ูู ุงูุณุคุงู ุนู ุฃูู: restaurants ููุท.
|
| 2148 |
+
- ูู ุงูุณุคุงู ุนู ู
ุดุฑูุจ: cafe ุฃู restaurant ููุท.
|
| 2149 |
+
- ูุงุฒู
ุงูุตูู ููุณู ูููู ุธุงูุฑ ูู matched_items / sub_category / description / name.
|
| 2150 |
+
"""
|
| 2151 |
+
if not places:
|
| 2152 |
+
return []
|
| 2153 |
+
|
| 2154 |
+
q = clean_text(item_query)
|
| 2155 |
+
|
| 2156 |
+
food_keywords = {
|
| 2157 |
+
"ุดุงูุฑู
ุง", "ุจุฑุฌุฑ", "ุจูุชุฒุง", "ูุฑูุจ", "ู
ุดููุงุช", "ูุฑุงุฎ",
|
| 2158 |
+
"ุฏุฌุงุฌ", "ูุจุงุจ", "ููุชู", "ููุชุฉ", "ุณู
ู", "ุณุงูุฏูุชุด",
|
| 2159 |
+
"ุณูุฏูุชุด", "ุญูุงูุดู", "ูุดุฑู", "ู
ูุฑููู", "ู
ูุฑููุฉ",
|
| 2160 |
+
"ูุฌุจู", "ูุฌุจุฉ", "ุงูู", "ุฃูู", "burger", "pizza",
|
| 2161 |
+
"shawarma", "crepe", "chicken", "grill", "grills"
|
| 2162 |
+
}
|
| 2163 |
+
|
| 2164 |
+
drink_keywords = {
|
| 2165 |
+
"ูููุฉ", "ูููู", "ูููู", "ุนุตูุฑ", "ู
ุดุฑูุจ", "ู
ุดุฑูุจุงุช",
|
| 2166 |
+
"ูุงุชูู", "ุงุณุจุฑูุณู", "ูุณูุงููู", "ุณู
ูุฐู",
|
| 2167 |
+
"coffee", "juice", "latte", "espresso", "smoothie"
|
| 2168 |
+
}
|
| 2169 |
+
|
| 2170 |
+
is_food = any(clean_text(w) in q for w in food_keywords)
|
| 2171 |
+
is_drink = any(clean_text(w) in q for w in drink_keywords)
|
| 2172 |
+
|
| 2173 |
+
query_words = [w for w in q.split() if len(w) > 2]
|
| 2174 |
+
filtered = []
|
| 2175 |
+
|
| 2176 |
+
for p in places:
|
| 2177 |
+
raw_category = str(p.get("category", ""))
|
| 2178 |
+
category = normalize_category(raw_category)
|
| 2179 |
+
|
| 2180 |
+
text_blob = clean_text(
|
| 2181 |
+
f"{p.get('name','')} "
|
| 2182 |
+
f"{p.get('name_ar','')} "
|
| 2183 |
+
f"{p.get('name_en','')} "
|
| 2184 |
+
f"{p.get('category','')} "
|
| 2185 |
+
f"{p.get('sub_category','')} "
|
| 2186 |
+
f"{p.get('description','')} "
|
| 2187 |
+
f"{p.get('matched_item','')} "
|
| 2188 |
+
f"{p.get('matched_items','')} "
|
| 2189 |
+
f"{p.get('menu_items','')} "
|
| 2190 |
+
f"{p.get('tags','')}"
|
| 2191 |
+
)
|
| 2192 |
+
|
| 2193 |
+
if is_food and category != "restaurant" and not _category_match_value(raw_category, "restaurant"):
|
| 2194 |
+
continue
|
| 2195 |
+
|
| 2196 |
+
if is_drink and not (
|
| 2197 |
+
category in ("cafe", "restaurant") or
|
| 2198 |
+
_category_match_value(raw_category, "cafe") or
|
| 2199 |
+
_category_match_value(raw_category, "restaurant")
|
| 2200 |
+
):
|
| 2201 |
+
continue
|
| 2202 |
+
|
| 2203 |
+
if query_words and not any(w in text_blob for w in query_words):
|
| 2204 |
+
continue
|
| 2205 |
+
|
| 2206 |
+
filtered.append(p)
|
| 2207 |
+
|
| 2208 |
+
# dedup
|
| 2209 |
+
seen, unique = set(), []
|
| 2210 |
+
for p in filtered:
|
| 2211 |
+
pid = str(p.get("place_id") or p.get("id") or p.get("name") or "")
|
| 2212 |
+
if pid and pid not in seen:
|
| 2213 |
+
seen.add(pid)
|
| 2214 |
+
unique.append(p)
|
| 2215 |
+
return unique
|
| 2216 |
+
|
| 2217 |
def get_place_menu(place_id: str) -> list[dict]:
|
| 2218 |
"""
|
| 2219 |
Calls GET /api/mobile/places/<place_id>/menu
|
|
|
|
| 2344 |
Handles search_by_item intent end-to-end.
|
| 2345 |
1. Extract item_query
|
| 2346 |
2. Call backend API
|
| 2347 |
+
3. Strictly filter wrong categories/items
|
| 2348 |
+
4. Return formatted response
|
| 2349 |
"""
|
| 2350 |
item_query = extract_item_query(text)
|
| 2351 |
item_query = clean_item_query(item_query)
|
|
|
|
| 2357 |
"place_cards": [],
|
| 2358 |
"best_place": None,
|
| 2359 |
}
|
| 2360 |
+
|
| 2361 |
places = search_places_by_item(item_query)
|
| 2362 |
+
places = filter_item_results_strict(places, item_query)
|
| 2363 |
+
|
| 2364 |
+
if not places:
|
| 2365 |
+
result = {
|
| 2366 |
+
"reply": f"ู
ุด ูุงูู ุฃู
ุงูู ุจุชูุฏู
{item_query} ุญุงูููุง ๐",
|
| 2367 |
+
"intent": "search_by_item",
|
| 2368 |
+
"ui_type": CFG.UI_TEXT_ONLY,
|
| 2369 |
+
"place_cards": [],
|
| 2370 |
+
"best_place": None,
|
| 2371 |
+
}
|
| 2372 |
+
session.add(text, result["reply"], "search_by_item", {"item": item_query}, None, [])
|
| 2373 |
+
return result
|
| 2374 |
+
|
| 2375 |
result = format_item_search_response(places, item_query, user_lat, user_lon)
|
| 2376 |
session.add(text, result["reply"], "search_by_item", {"item": item_query},
|
| 2377 |
result.get("best_place"), places)
|
|
|
|
| 2735 |
def reset_session(session_id: str):
|
| 2736 |
SESSIONS.pop(session_id, None)
|
| 2737 |
log.info(f"๐๏ธ Session {session_id} reset")
|
| 2738 |
+
return {"status": "reset", "session_id": session_id}
|