JustscrAPIng's picture
Update app.py
6e9abcf verified
import gradio as gr
from setfit import SetFitModel
from sentence_transformers import SentenceTransformer, util
import re
import numpy as np
import traceback
# --- 1. SETUP & LOAD MODELS ---
print("Loading Models...")
try:
# A. Load your Custom Trained Food Model (Bilingual)
food_model = SetFitModel.from_pretrained("filter-search-model_v2")
# B. Load Multilingual Vector Model (The "Bilingual Brain")
# We use this instead of 'all-MiniLM-L6-v2' so it understands Vietnamese inputs
vector_model = SentenceTransformer("JustscrAPIng/cultour-base-model-v2")
print("Models Loaded Successfully!")
except Exception as e:
print(f"Error loading models: {e}")
# --- 2. DEFINE DICTIONARIES ---
tag_definitions_en = {
"religion": {
'none': 'secular non-religious atheism no religion',
'taoist': 'taoist taoism yin yang dao',
'chinese_folk': 'chinese folk religion ancestor worship shenism',
'buddhist': 'buddhist temple buddhism monk zen lotus',
'christian': 'christian church jesus catholic protestant cross bible',
'hinduism': 'hindu temple hinduism shiva vishnu',
'vietnamese_folk': 'vietnamese folk religion mother goddess dao mau thanh mau',
'khmer': 'khmer religion theravada buddhism cambodian style',
'muslim': 'muslim islam mosque halal allah'
},
"arch_style": {
'french': 'french colonial architecture indochina villa balcony yellow walls shutters',
'modernism': 'modern architecture modernism brutalist concrete glass sleek minimal high-rise',
'east asian': 'east asian oriental wooden structure curved roof',
'contemporary': 'contemporary design new recent 21st century current',
'baroque': 'baroque architecture ornate dramatic detailed grandiose european',
'rococo': 'rococo style decorative pastel intricate playful',
'vietnamese': 'traditional vietnamese architecture wooden red tile roof',
'chinese': 'chinese architecture dragon courtyard feng shui',
'romanesque': 'romanesque arches thick walls sturdy rounded',
'gothic': 'gothic architecture pointed arches stained glass spires cathedral',
'renaissance': 'renaissance symmetry domes columns classical proportion',
'neo-romanesque': 'neo-romanesque revival 19th century style',
'indochine': 'indochine style fusion french colonial and vietnamese tropical',
'neo-baroque': 'neo-baroque revival grand opera house style',
'hindu': 'hindu architecture cham style champa towers sandstone',
'art deco': 'art deco retro geometric stylized 1920s 1930s',
'khmer': 'khmer architecture angkor wat style stone temple prasat',
'islamic': 'islamic architecture domes minarets geometric patterns',
'flamboyant': 'flamboyant gothic flame-like intricate stone tracery',
'beaux arts': 'beaux arts style monumental classical grand french school',
'art nouveau': 'art nouveau organic lines flowery decorative curved'
},
"building_type": {
'marketplace': 'marketplace market bazaar shopping buy food groceries ben thanh',
'community_centre': 'community center public gathering cultural house hall',
'courthouse': 'courthouse law legal judge justice government',
'hospital': 'hospital clinic doctor medical emergency healthcare',
'mortuary': 'mortuary funeral home dead burial services',
'place_of_worship': 'place of worship temple church pagoda shrine mosque pray spiritual',
'institution': 'institution school university college education academy library',
'tomb': 'tomb grave mausoleum cemetery burial site',
'heritage': 'heritage site historical building landmark monument preservation',
'zoo': 'zoo animals botanical garden nature park',
'museum': 'museum exhibition history art gallery display',
'commercial': 'commercial building shop store mall office business trade',
'government': 'government building administrative town hall committee',
'residential': 'residential house home villa apartment living',
'library': 'library books reading study archive',
'fountain': 'fountain water feature square plaza',
'theatre': 'theatre opera house performance stage cinema arts',
'pagoda': 'pagoda tiered tower buddhist temple asian',
'park': 'park green space garden nature relax trees',
'reservoir': 'reservoir water lake dam utility',
'restaurant': 'restaurant place to eat food dining hungry lunch dinner eatery',
'cafe': 'cafe coffee shop drink sip tea chill work',
},
"food_type": {
'vietnamese': '', 'international': '', 'asian': '', 'korean': '', 'grill': '',
'argentinian': '', 'japanese': '', 'lebanese': '', 'chinese': '', 'local food': '',
'pizza': '', 'mediterranean': '', 'thai': '', 'italian': '', 'hue style': '',
'indian': '', 'french': '', 'barbecue': '', 'banh cuon': '', 'nướng (grill)': '',
'sushi': '', 'beef bowl': '', 'noodles': '', 'curry': '', 'burger': '', 'seafood': '',
'american': '', 'pasta': '', 'thai hotpot': '', 'grilled fish': '', 'steamed fish': '',
'stir-fried vegetables': '', 'hotpot': '', 'sandwich': '', 'ice cream': '', 'crepe': '',
'coffee': '', 'fine dining': '', 'diner': '', 'steakhouse': '', 'mexican': '', 'wings': ''
}
}
tag_definitions_vi = {
"religion": {
'none': 'không tôn giáo vô thần thế tục',
'taoist': 'đạo giáo lão giáo âm dương',
'chinese_folk': 'tín ngưỡng dân gian trung hoa thờ cúng tổ tiên',
'buddhist': 'phật giáo chùa sư đạo phật nơi thờ tự người theo đạo phật hoa sen sư thầy thiền',
'christian': 'công giáo tin lành nhà thờ chúa giêsu thánh giá kinh thánh',
'hinduism': 'ấn độ giáo đền thần shiva vishnu',
'vietnamese_folk': 'tín ngưỡng dân gian việt nam đạo mẫu hầu đồng thánh mẫu',
'khmer': 'phật giáo nam tông khmer chùa tháp',
'muslim': 'hồi giáo thánh đường halal allah'
},
"arch_style": {
'french': 'kiến trúc pháp thuộc địa đông dương biệt thự tường vàng cửa chớp',
'modernism': 'kiến trúc hiện đại bê tông kính tối giản cao tầng tòa nhà kính',
'east asian': 'kiến trúc đông á á đông gỗ mái cong',
'contemporary': 'kiến trúc đương đại thiết kế mới thế kỷ 21',
'baroque': 'kiến trúc baroque lộng lẫy chi tiết cầu kỳ châu âu',
'rococo': 'phong cách rococo trang trí pastel tinh xảo',
'vietnamese': 'kiến trúc truyền thống việt nam nhà gỗ mái ngói đỏ nhà rường',
'chinese': 'kiến trúc trung hoa rồng sân trong phong thủy',
'romanesque': 'kiến trúc romanesque vòm tròn tường dày',
'gothic': 'kiến trúc gothic vòm nhọn kính màu tháp chuông nhà thờ',
'renaissance': 'phục hưng mái vòm cột đối xứng cổ điển',
'neo-romanesque': 'tân romanesque thế kỷ 19',
'indochine': 'phong cách đông dương kết hợp pháp và việt nhiệt đới',
'neo-baroque': 'tân baroque nhà hát lớn',
'hindu': 'kiến trúc chăm pa tháp chăm gạch nung',
'art deco': 'art deco hình học cách điệu thập niên 1920',
'khmer': 'kiến trúc khmer angkor wat đền đá',
'islamic': 'kiến trúc hồi giáo mái vòm tháp',
'flamboyant': 'gothic rực cháy đá chạm khắc tinh xảo',
'beaux arts': 'beaux arts hoành tráng cổ điển pháp',
'art nouveau': 'tân nghệ thuật đường cong họa tiết hoa'
},
"building_type": {
'marketplace': 'chợ bến thành mua sắm thực phẩm đồ khô',
'community_centre': 'trung tâm cộng đồng nhà văn hóa hội trường',
'courthouse': 'tòa án pháp luật xét xử',
'hospital': 'bệnh viện phòng khám bác sĩ cấp cứu y tế',
'mortuary': 'nhà tang lễ mai táng',
'place_of_worship': 'nơi thờ tự chùa đền nhà thờ thánh đường miếu',
'institution': 'trường học đại học thư viện giáo dục',
'tomb': 'lăng mộ nghĩa trang',
'heritage': 'di sản di tích lịch sử bảo tồn',
'zoo': 'sở thú thảo cầm viên vườn bách thảo',
'museum': 'bảo tàng triển lãm lịch sử nghệ thuật',
'commercial': 'tòa nhà thương mại cửa hàng trung tâm mua sắm văn phòng',
'government': 'cơ quan nhà nước ủy ban hành chính',
'residential': 'nhà ở chung cư biệt thự căn hộ',
'library': 'thư viện đọc sách tài liệu',
'fountain': 'đài phun nước quảng trường',
'theatre': 'nhà hát rạp chiếu phim sân khấu nghệ thuật',
'pagoda': 'chùa tháp phật giáo',
'park': 'công viên cây xanh vườn hoa',
'reservoir': 'hồ chứa nước đập thủy điện',
'restaurant': 'nhà hàng quán ăn tiệm cơm ăn uống',
'cafe': 'quán cà phê trà sữa làm việc',
}
}
# --- 3. AUTO-MERGE DICTIONARIES ---
print("Merging dictionaries...")
combined_definitions = {}
for category in ["religion", "arch_style", "building_type"]:
combined_definitions[category] = {}
for tag in tag_definitions_en[category]:
en_desc = tag_definitions_en[category][tag]
vi_desc = ""
if category in tag_definitions_vi:
vi_desc = tag_definitions_vi[category].get(tag, "")
combined_desc = f"{en_desc} {vi_desc}".strip()
combined_definitions[category][tag] = combined_desc
# --- 4. PRE-COMPUTE VECTORS ---
print("Pre-computing vectors...")
encoded_db = {}
for category in combined_definitions:
tags_map = combined_definitions[category]
encoded_db[category] = {
'embeddings': vector_model.encode(list(tags_map.values()), convert_to_tensor=True),
'names': list(tags_map.keys())
}
print("Ready.")
# --- 5. EXTRACTION LOGIC (Strict & Patched) ---
def extract_tags(user_text):
try:
detected_data = {}
text_lower = user_text.lower()
# --- A. MANUAL OVERRIDES (Safety Net) ---
# 1. Food
if 'bún chả' in text_lower:
detected_data['food_type'] = ['vietnamese', 'local food']
elif 'bánh mì' in text_lower and 'pate' in text_lower:
detected_data['food_type'] = ['sandwich', 'vietnamese']
elif 'bánh mì' in text_lower:
detected_data['food_type'] = ['vietnamese']
# 2. Religion
if 'đạo phật' in text_lower or 'chùa' in text_lower:
detected_data['religion'] = ['buddhist']
elif 'nhà thờ' in text_lower or 'công giáo' in text_lower:
detected_data['religion'] = ['christian']
# 3. Architecture
if 'kính' in text_lower and 'cao tầng' in text_lower:
detected_data['arch_style'] = ['modernism']
elif 'gỗ' in text_lower and 'truyền thống' in text_lower:
detected_data['arch_style'] = ['vietnamese']
# --- B. AGE EXTRACTION ---
match = re.search(r'\b(1[7-9]|20)\d{2}s?\b', user_text)
detected_data['age'] = match.group(0).rstrip('s') if match else None
# --- C. VECTOR SEARCH (Strict) ---
user_embedding = vector_model.encode(user_text, convert_to_tensor=True)
base_threshold = 0.29
for category in ["religion", "arch_style", "building_type"]:
if category in detected_data: continue # Skip overrides
db_data = encoded_db[category]
scores = util.cos_sim(user_embedding, db_data['embeddings'])[0]
candidates = []
for idx, score in enumerate(scores):
if score > base_threshold:
candidates.append((db_data['names'][idx], score.item()))
candidates.sort(key=lambda x: x[1], reverse=True)
# STRICT LIMIT: Keep only top 2 to reduce noise
candidates = candidates[:2]
if candidates:
best_score = candidates[0][1]
relative_cutoff = best_score * 0.90
final_tags = [t[0] for t in candidates if t[1] >= relative_cutoff]
detected_data[category] = final_tags
else:
detected_data[category] = None
# --- D. SMART FOOD LOGIC (Your Old Strict Method) ---
if 'food_type' not in detected_data:
food_triggers = ['restaurant', 'cafe', 'street_food', 'marketplace']
buildings = detected_data.get('building_type') or []
is_food_venue = any(b in food_triggers for b in buildings)
prediction_array = food_model.predict([user_text])
prediction_clean = prediction_array.tolist()
# 1. Validation List (From your old code)
valid_food_keys = list(tag_definitions_en['food_type'].keys())
# 2. Strict Filter
filtered_food = [tag for tag in prediction_clean if tag in valid_food_keys]
# 3. Assign
if is_food_venue and filtered_food:
detected_data['food_type'] = filtered_food
else:
detected_data['food_type'] = None
return detected_data
except Exception as e:
return {"error": str(e), "traceback": traceback.format_exc()}
# --- 6. LAUNCH API ---
iface = gr.Interface(
fn=extract_tags,
inputs=gr.Textbox(label="User Search", placeholder="e.g. I want a french villa"),
outputs=gr.JSON(label="Extracted Tags"),
title="Cultour AI API (Bilingual)",
description="Supports English and Vietnamese. Send queries to /api/predict"
)
iface.launch()