|
from annotation.src.utils import get_valid_name_city,extract_before_parenthesis,extract_numbers_from_filenames |
|
from tools.flights.apis import Flights |
|
from tools.accommodations.apis import Accommodations |
|
from tools.restaurants.apis import Restaurants |
|
from tools.googleDistanceMatrix.apis import GoogleDistanceMatrix |
|
from tools.attractions.apis import Attractions |
|
import math |
|
import json |
|
import re |
|
import numpy as np |
|
import os |
|
import sys |
|
from tqdm import tqdm |
|
import argparse |
|
|
|
sys.path.append(os.path.abspath(os.path.join(os.getcwd(), ".."))) |
|
os.chdir(os.path.dirname(os.path.abspath(__file__))) |
|
|
|
|
|
flight = Flights() |
|
accommodation = Accommodations() |
|
restaurants = Restaurants() |
|
googleDistanceMatrix = GoogleDistanceMatrix() |
|
attractions = Attractions() |
|
|
|
|
|
def load_line_json_data(filename): |
|
data = [] |
|
with open(filename, 'r', encoding='utf-8') as f: |
|
for line in f.read().strip().split('\n'): |
|
unit = json.loads(line) |
|
data.append(unit) |
|
return data |
|
|
|
|
|
def convert_bool_values(item): |
|
if isinstance(item, dict): |
|
|
|
return {key: convert_bool_values(value) for key, value in item.items()} |
|
elif isinstance(item, list): |
|
|
|
return [convert_bool_values(value) for value in item] |
|
elif isinstance(item, tuple): |
|
|
|
return tuple(convert_bool_values(value) for value in item) |
|
elif isinstance(item, np.bool_): |
|
|
|
return bool(item) |
|
else: |
|
|
|
return item |
|
|
|
|
|
|
|
|
|
def extract_from_to(text: str): |
|
""" |
|
Extracts 'A' and 'B' from the format "from A to B" in the given text, with B ending at a comma or the end of the string. |
|
|
|
Args: |
|
- text (str): The input string. |
|
|
|
Returns: |
|
- tuple: A tuple containing 'A' and 'B'. If no match is found, returns (None, None). |
|
""" |
|
pattern = r"from\s+(.+?)\s+to\s+([^,]+)(?=[,\s]|$)" |
|
matches = re.search(pattern, text) |
|
return matches.groups() if matches else (None, None) |
|
|
|
|
|
def get_total_cost(question, tested_data): |
|
total_cost = 0 |
|
for i in range(min(question['days'],len(tested_data))): |
|
unit = tested_data[i] |
|
|
|
if unit['transportation'] and unit['transportation'] != '-': |
|
value = unit['transportation'] |
|
org_city, dest_city = extract_from_to(value) |
|
if org_city == None or dest_city == None: |
|
org_city, dest_city = extract_from_to(unit['current_city']) |
|
|
|
if org_city == None or dest_city == None: |
|
pass |
|
else: |
|
if 'flight number' in value.lower(): |
|
res = flight.data[flight.data['Flight Number'] == value.split('Flight Number: ')[1].split(',')[0]] |
|
if len(res) > 0: |
|
total_cost += res['Price'].values[0] * question['people_number'] |
|
|
|
elif 'self-driving' in value.lower() or 'taxi' in value.lower(): |
|
if 'self-driving' in value.lower(): |
|
|
|
cost = googleDistanceMatrix.run_for_evaluation(org_city,dest_city,'self-driving')['cost'] |
|
total_cost += cost * math.ceil(question['people_number'] * 1.0 / 5) |
|
else: |
|
cost = googleDistanceMatrix.run_for_evaluation(org_city,dest_city,'taxi')['cost'] |
|
total_cost += cost * math.ceil(question['people_number'] * 1.0 / 4) |
|
|
|
|
|
if unit['breakfast'] and unit['breakfast'] != '-': |
|
name, city = get_valid_name_city(unit['breakfast']) |
|
res = restaurants.data[(restaurants.data['Name'].astype(str).str.contains(re.escape(name))) & (restaurants.data['City'] == city)] |
|
if len(res) > 0: |
|
total_cost += res['Average Cost'].values[0] * question['people_number'] |
|
|
|
|
|
|
|
if unit['lunch'] and unit['lunch'] != '-': |
|
name, city = get_valid_name_city(unit['lunch']) |
|
res = restaurants.data[(restaurants.data['Name'].astype(str).str.contains(re.escape(name))) & (restaurants.data['City'] == city)] |
|
if len(res) > 0: |
|
total_cost += res['Average Cost'].values[0] * question['people_number'] |
|
|
|
|
|
if unit['dinner'] and unit['dinner'] != '-': |
|
name, city = get_valid_name_city(unit['dinner']) |
|
res = restaurants.data[(restaurants.data['Name'].astype(str).str.contains(re.escape(name))) & (restaurants.data['City'] == city)] |
|
if len(res) > 0: |
|
total_cost += res['Average Cost'].values[0] * question['people_number'] |
|
|
|
|
|
if unit['accommodation'] and unit['accommodation'] != '-': |
|
name, city = get_valid_name_city(unit['accommodation']) |
|
res = accommodation.data[(accommodation.data['NAME'].astype(str).str.contains(re.escape(name))) & (accommodation.data['city'] == city)] |
|
if len(res) > 0: |
|
total_cost += res['price'].values[0] * math.ceil(question['people_number'] * 1.0 / res['maximum occupancy'].values[0]) |
|
|
|
return total_cost |
|
|
|
|
|
def is_valid_room_rule(question, tested_data): |
|
|
|
if question['local_constraint']['house rule'] is None: |
|
return None,None |
|
|
|
for i in range(min(question['days'],len(tested_data))): |
|
unit = tested_data[i] |
|
if unit['accommodation'] and unit['accommodation'] != '-': |
|
name, city = get_valid_name_city(unit['accommodation']) |
|
res = accommodation.data[(accommodation.data['NAME'].astype(str).str.contains(re.escape(name))) & (accommodation.data['city'] == city)] |
|
if len(res) > 0: |
|
if question['local_constraint']['house rule'] == 'smoking' and 'No smoking' in str(res['house_rules'].values[0]): |
|
return False, f"The house rule should be {question['local_constraint']['house rule']}." |
|
if question['local_constraint']['house rule'] == 'parties' and 'No parties' in str(res['house_rules'].values[0]): |
|
return False, f"The house rule should be {question['local_constraint']['house rule']}." |
|
if question['local_constraint']['house rule'] == 'children under 10' and 'No children under 10' in str(res['house_rules'].values[0]): |
|
return False, f"The house rule should be {question['local_constraint']['house rule']}." |
|
if question['local_constraint']['house rule'] == 'visitors' and 'No visitors' in str(res['house_rules'].values[0]): |
|
return False, f"The house rule should be {question['local_constraint']['house rule']}." |
|
if question['local_constraint']['house rule'] == 'pets' and 'No pets' in str(res['house_rules'].values[0]): |
|
return False, f"The house rule should be {question['local_constraint']['house rule']}." |
|
|
|
|
|
return True, None |
|
|
|
|
|
|
|
def is_valid_cuisine(question, tested_data): |
|
cuisine_set = set() |
|
if question['local_constraint']['cuisine']: |
|
for i in range(min(question['days'],len(tested_data))): |
|
unit = tested_data[i] |
|
|
|
if unit['breakfast'] and unit['breakfast'] != '-': |
|
name, city = get_valid_name_city(unit['breakfast']) |
|
if city == question['org']: |
|
continue |
|
res = restaurants.data[(restaurants.data['Name'].astype(str).str.contains(re.escape(name))) & (restaurants.data['City'] == city)] |
|
if len(res) > 0: |
|
for cuisine in question['local_constraint']['cuisine']: |
|
if cuisine in res.iloc[0]['Cuisines']: |
|
cuisine_set.add(cuisine) |
|
|
|
if unit['lunch'] and unit['lunch'] != '-': |
|
name, city = get_valid_name_city(unit['lunch']) |
|
if city == question['org']: |
|
continue |
|
res = restaurants.data[(restaurants.data['Name'].astype(str).str.contains(re.escape(name))) & (restaurants.data['City'] == city)] |
|
if len(res) > 0: |
|
for cuisine in question['local_constraint']['cuisine']: |
|
if cuisine in res.iloc[0]['Cuisines']: |
|
cuisine_set.add(cuisine) |
|
|
|
if unit['dinner'] and unit['dinner'] != '-': |
|
name, city = get_valid_name_city(unit['dinner']) |
|
if city == question['org']: |
|
continue |
|
res = restaurants.data[(restaurants.data['Name'].astype(str).str.contains(re.escape(name))) & (restaurants.data['City'] == city)] |
|
if len(res) > 0: |
|
for cuisine in question['local_constraint']['cuisine']: |
|
if cuisine in res.iloc[0]['Cuisines']: |
|
cuisine_set.add(cuisine) |
|
|
|
if len(cuisine_set) == len(question['local_constraint']['cuisine']): |
|
return True, None |
|
else: |
|
|
|
for cuisine in question['local_constraint']['cuisine']: |
|
if cuisine not in cuisine_set: |
|
return False, f"The cuisine {cuisine} is not satisfied." |
|
|
|
else: |
|
return None,None |
|
|
|
|
|
def is_valid_transportation(question, tested_data): |
|
if question['local_constraint']['transportation'] is None: |
|
return None,None |
|
for i in range(min(question['days'],len(tested_data))): |
|
unit = tested_data[i] |
|
if unit['transportation'] and unit['transportation'] != '-': |
|
value = unit['transportation'] |
|
if question['local_constraint']['transportation'] == 'no flight' and 'Flight' in value: |
|
return False, f"The transportation should not be {question['local_constraint']['transportation']}." |
|
elif question['local_constraint']['transportation'] == 'no self-driving' and 'Self-driving' in value: |
|
return False, f"The transportation should not be {question['local_constraint']['transportation']}." |
|
|
|
return True, None |
|
|
|
|
|
def is_valid_room_type(question, tested_data): |
|
if question['local_constraint']['room type'] is None: |
|
return None,None |
|
for i in range(min(question['days'],len(tested_data))): |
|
unit = tested_data[i] |
|
if unit['accommodation'] and unit['accommodation'] != '-': |
|
name, city = get_valid_name_city(unit['accommodation']) |
|
res = accommodation.data[(accommodation.data['NAME'].astype(str).str.contains(re.escape(name))) & (accommodation.data['city'] == city)] |
|
if len(res) > 0: |
|
if question['local_constraint']['room type'] == 'not shared room' and res['room type'].values[0] == 'Shared room': |
|
return False, f"The room type should be {question['local_constraint']['room type']}." |
|
|
|
elif question['local_constraint']['room type'] == 'shared room' and res['room type'].values[0] != 'Shared room': |
|
return False, f"The room type should be {question['local_constraint']['room type']}." |
|
|
|
elif question['local_constraint']['room type'] == 'private room' and res['room type'].values[0] != 'Private room': |
|
return False, f"The room type should be {question['local_constraint']['room type']}." |
|
|
|
elif question['local_constraint']['room type'] == 'entire room' and res['room type'].values[0] != 'Entire home/apt': |
|
return False, f"The room type should be {question['local_constraint']['room type']}." |
|
|
|
return True, None |
|
|
|
|
|
def evaluation(query_data, tested_data): |
|
return_info = {} |
|
return_info['valid_cuisine'] = is_valid_cuisine(query_data, tested_data) |
|
return_info['valid_room_rule'] = is_valid_room_rule(query_data, tested_data) |
|
return_info['valid_transportation'] = is_valid_transportation(query_data, tested_data) |
|
return_info['valid_room_type'] = is_valid_room_type(query_data, tested_data) |
|
return_info['valid_cost'] = (bool(get_total_cost(query_data, tested_data) <= query_data['budget']), None) |
|
return return_info |
|
|
|
def boolean_evaluation(query_data, tested_data): |
|
return_info = {} |
|
return_info['valid_cuisine'] = is_valid_cuisine(query_data, tested_data) |
|
return_info['valid_room_rule'] = is_valid_room_rule(query_data, tested_data) |
|
return_info['valid_transportation'] = is_valid_transportation(query_data, tested_data) |
|
return_info['valid_room_type'] = is_valid_room_type(query_data, tested_data) |
|
return_info['valid_cost'] = (bool(get_total_cost(query_data, tested_data) <= query_data['budget']), None) |
|
for key in return_info: |
|
if return_info[key][0] == False: |
|
print(key) |
|
return False |
|
return True |
|
|
|
|