Cbphcr's picture
Init repo
dfe35ce verified
# -*- coding: utf-8 -*-
import os
import sys
import pandas as pd
project_root_path = os.path.dirname(
os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
)
if project_root_path not in sys.path:
sys.path.append(project_root_path)
import json
from chinatravel.environment.world_env import WorldEnv
from chinatravel.evaluation.utils import Attractions
from chinatravel.symbol_verification.preference import evaluate_preference_py
env = WorldEnv()
attractions = Attractions()
goto = env.transportation.goto
city_dict = {
"北京": "beijing",
"上海": "shanghai",
"南京": "nanjing",
"苏州": "suzhou",
"杭州": "hangzhou",
"深圳": "shenzhen",
"成都": "chengdu",
"武汉": "wuhan",
"广州": "guangzhou",
"重庆": "chongqing",
}
def calc_time_delta(st_time, ed_time):
st_h, st_m = int(st_time.split(":")[0]), int(st_time.split(":")[1])
ed_h, ed_m = int(ed_time.split(":")[0]), int(ed_time.split(":")[1])
return (ed_m - st_m) + (ed_h - st_h) * 60
def convenient_transport(plan_json):
plan = plan_json["itinerary"]
time_cost = 0
transport_count = 0
for plan_of_day in plan:
for activity in plan_of_day["activities"]:
if "transports" in activity:
transport_count += 1
for transport in activity["transports"]:
time_cost += calc_time_delta(
transport["start_time"], transport["end_time"]
)
average_time_cost = time_cost / transport_count
return average_time_cost
def convenient_restaurant(plan_json):
plan = plan_json["itinerary"]
restaurant_count = 0
time_cost = 0
for plan_of_day in plan:
for activity in plan_of_day["activities"]:
if activity["type"] in ["breakfast", "lunch", "dinner"]:
restaurant_count += 1
for transport in activity["transports"]:
time_cost += calc_time_delta(
transport["start_time"], transport["end_time"]
)
if restaurant_count == 0:
return -1
average_time_cost = time_cost / restaurant_count
return average_time_cost
def near_poi(plan_json, poi_list):
poi_count = len(poi_list)
if poi_count == 0:
return -1
plan = plan_json["itinerary"]
if len(plan) == 1:
return -1
city = plan_json["target_city"]
accommodation_name = ""
for plan_of_day in plan:
for activity in plan_of_day["activities"]:
if activity["type"] == "accommodation":
accommodation_name = activity["position"]
break
dist_cost = 0
for poi in poi_list:
# print("city", city, "accommodation_name", accommodation_name, "poi", poi)
dist_cost += goto(
city, accommodation_name, poi, start_time="00:00", transport_type="walk"
)[0]["distance"]
average_dist_cost = dist_cost / poi_count
return average_dist_cost
def less_walk(plan_json):
plan = plan_json["itinerary"]
walk_distance = 0
activity_count = 0
for plan_of_day in plan:
for activity in plan_of_day["activities"]:
if "transports" in activity:
for transport in activity["transports"]:
if transport["mode"] == "walk":
walk_distance += transport["distance"]
activity_count += 1
# average_walk_distance = walk_distance / activity_count
return walk_distance
def meal_cost_ratio(plan_json):
plan = plan_json["itinerary"]
meal_cost = 0
for plan_of_day in plan:
for activity in plan_of_day["activities"]:
if activity["type"] in ["breakfast", "lunch", "dinner"]:
meal_cost += activity["cost"]
return meal_cost / total_cost(plan_json)
def accommodation_cost_ratio(plan_json):
plan = plan_json["itinerary"]
accommodation_cost = 0
for plan_of_day in plan:
for activity in plan_of_day["activities"]:
if activity["type"] == "accommodation":
accommodation_cost += activity["cost"]
return accommodation_cost / total_cost(plan_json)
def attraction_cost_ratio(plan_json):
plan = plan_json["itinerary"]
attraction_cost = 0
for plan_of_day in plan:
for activity in plan_of_day["activities"]:
if activity["type"] == "attraction":
attraction_cost += activity["cost"]
return attraction_cost / total_cost(plan_json)
def total_cost(plan_json):
plan = plan_json["itinerary"]
_total_cost = 0
for plan_of_day in plan:
for activity in plan_of_day["activities"]:
_total_cost += activity["cost"]
for transport in activity["transports"]:
_total_cost += transport["cost"]
return _total_cost
def attraction_satisfaction(plan_json):
plan = plan_json["itinerary"]
city = plan_json["target_city"]
recommend_time_list = []
actual_time_list = []
# datapath=os.path.dirname(__file__) + "/eval_annotation/attractions/{}/attractions_tag.csv".format(city_dict[city])
# ood_attractions_dataframe = pd.read_csv(datapath)
# datapath=os.path.dirname(__file__) + "/eval_annotation/attractions/{}/attractions_tag.csv".format(city_dict[city])
# ood_attractions_dataframe = pd.read_csv(datapath)
for plan_of_day in plan:
for activity in plan_of_day["activities"]:
if activity["type"] == "attraction":
attraction_name = activity["position"]
attrction_info = attractions.select(
city, key="name", func=lambda x: x == attraction_name
).iloc[0]
# attrction_info = ood_attractions_dataframe[ood_attractions_dataframe["name"] == attraction_name].iloc[0]
recommend_time = (attrction_info["recommendmintime"]) * 60
actual_time = calc_time_delta(
activity["start_time"], activity["end_time"]
)
recommend_time_list.append(recommend_time)
actual_time_list.append(actual_time)
if len(recommend_time_list) == 0:
return -1
# marco = sum(recommend_time_list) / sum(actual_time_list)
micro = sum(
[
recommend_time_list[i] / actual_time_list[i]
for i in range(len(recommend_time_list))
]
) / len(recommend_time_list)
return micro
def attraction_count(plan_json):
plan = plan_json["itinerary"]
day_num = len(plan)
attraction_count = 0
for plan_of_day in plan:
for activity in plan_of_day["activities"]:
if activity["type"] == "attraction":
attraction_count += 1
average_attraction_count = attraction_count / day_num
return average_attraction_count
def indoor_attraction_ratio(plan_json):
plan = plan_json["itinerary"]
attraction_count = 0
indoor_attraction_count = 0
for plan_of_day in plan:
for activity in plan_of_day["activities"]:
if activity["type"] == "attraction":
attraction_count += 1
attraction_name = activity["position"]
city = plan_json["target_city"]
attraction_info = attractions.select(
city, key="name", func=lambda x: x == attraction_name
).iloc[0]
if attraction_info["indoor"] == 1:
indoor_attraction_count += 1
if attraction_count == 0:
return -1
return indoor_attraction_count / attraction_count
def popular_attraction_ratio(plan_json):
plan = plan_json["itinerary"]
attraction_count = 0
popular_score_sum = 0
for plan_of_day in plan:
for activity in plan_of_day["activities"]:
if activity["type"] == "attraction":
attraction_count += 1
attraction_name = activity["position"]
city = plan_json["target_city"]
attraction_info = attractions.select(
city, key="name", func=lambda x: x == attraction_name
).iloc[0]
popular_score_sum += attraction_info["popularity"]
if attraction_count == 0:
return -1
return popular_score_sum / attraction_count
func_list = [
convenient_transport,
convenient_restaurant,
near_poi,
less_walk,
meal_cost_ratio,
accommodation_cost_ratio,
attraction_cost_ratio,
total_cost,
attraction_satisfaction,
attraction_count,
indoor_attraction_ratio,
popular_attraction_ratio,
]
def _evaluate_preference(symbolic_input, plan_json):
result = {}
poi_list_str = ""
preference_list = symbolic_input["preference_en"]
for preference in preference_list:
if "close to" in preference:
poi_list_str = preference.split("{")[1].split("}")[0]
break
poi_list = poi_list_str.replace(",", ",").split(",")
poi_list = (
[poi.strip().strip("'").strip('"') for poi in poi_list]
if poi_list_str != ""
else []
)
for func in func_list:
if func == near_poi:
result[func.__name__] = func(plan_json, poi_list)
else:
result[func.__name__] = func(plan_json)
return result
def evaluate_preference(query_index, query_data, result_data, commonsense_pass):
result = []
for i in range(len(query_index)):
if query_index[i] not in commonsense_pass:
result.append(
{"data_id": query_index[i]} | {func.__name__: -1 for func in func_list}
)
continue
symbolic_input = query_data[query_index[i]]
plan_json = result_data[query_index[i]]
# print("symbolic_input", symbolic_input, "plan_json", plan_json)
result.append(
{"data_id": query_index[i]}
| _evaluate_preference(symbolic_input, plan_json)
)
result_df = pd.DataFrame(result)
return result_df
def evaluate_preference_v2(query_index, query_data, result_data, pass_id):
result = []
for i in range(len(query_index)):
if query_index[i] not in pass_id:
result.append(
{"data_id": query_index[i], "concept": -1}
)
continue
evaluate_preference_py
symbolic_input = query_data[query_index[i]]
plan_json = result_data[query_index[i]]
# print("symbolic_input", symbolic_input, "plan_json", plan_json)
if isinstance(symbolic_input["preference_py"], list):
pre_py = symbolic_input["preference_py"][0]
else:
pre_py = symbolic_input["preference_py"]
index = pre_py.find("\n")
concept = pre_py[:index]
op = concept.split(" ")[0]
op_concept = concept.split(" ")[1]
code = pre_py[index + 1 :]
res = evaluate_preference_py([(op, op_concept, code)], plan_json)[0]
result.append(
{"data_id": query_index[i], "concept": res}
)
result_df = pd.DataFrame(result)
return result_df
def test():
test_json_txt = """
{"people_number":1,"start_city":"深圳","target_city":"南京","itinerary":[{"day":1,"activities":[{"start_time":"06:27","end_time":"15:15","start":"深圳北站","end":"南京南站","TrainID":"D376","type":"train","transports":[],"cost":694.1,"tickets":1},{"position":"中山陵景区","type":"attraction","transports":[{"start":"南京南站","end":"南京南站-地铁站","mode":"walk","start_time":"15:15","end_time":"15:18","cost":0,"distance":0.29},{"start":"南京南站-地铁站","end":"钟灵街-地铁站","mode":"metro","start_time":"15:18","end_time":"15:38","cost":4,"distance":10.21,"tickets":1},{"start":"钟灵街-地铁站","end":"中山陵景区","mode":"walk","start_time":"15:38","end_time":"16:07","cost":0,"distance":2.47}],"cost":0,"start_time":"16:07","end_time":"17:00"},{"position":"朱氏梅花糕","type":"dinner","transports":[{"start":"中山陵景区","end":"钟灵街-地铁站","mode":"walk","start_time":"17:00","end_time":"17:29","cost":0,"distance":2.47},{"start":"钟灵街-地铁站","end":"云南路-地铁站","mode":"metro","start_time":"17:29","end_time":"17:47","cost":4,"distance":9.22,"tickets":1},{"start":"云南路-地铁站","end":"朱氏梅花糕","mode":"walk","start_time":"17:47","end_time":"17:52","cost":0,"distance":0.5}],"cost":6,"start_time":"17:52","end_time":"19:22"},{"position":"行政院","type":"attraction","transports":[{"start":"朱氏梅花糕","end":"云南路-地铁站","mode":"walk","start_time":"19:22","end_time":"19:27","cost":0,"distance":0.5},{"start":"云南路-地铁站","end":"九华山-地铁站","mode":"metro","start_time":"19:27","end_time":"19:32","cost":2,"distance":2.96,"tickets":1},{"start":"九华山-地铁站","end":"行政院","mode":"walk","start_time":"19:32","end_time":"19:39","cost":0,"distance":0.62}],"cost":0,"start_time":"19:39","end_time":"21:09"},{"position":"南京玄武饭店","type":"accommodation","room_type":1,"transports":[{"start":"行政院","end":"九华山-地铁站","mode":"walk","start_time":"21:09","end_time":"21:16","cost":0,"distance":0.62},{"start":"九华山-地铁站","end":"玄武门-地铁站","mode":"metro","start_time":"21:16","end_time":"21:20","cost":2,"distance":2.5,"tickets":1},{"start":"玄武门-地铁站","end":"南京玄武饭店","mode":"walk","start_time":"21:20","end_time":"21:21","cost":0,"distance":0.1}],"cost":556.0,"start_time":"21:21","end_time":"24:00","rooms":1}]},{"day":2,"activities":[{"position":"南京玄武饭店","type":"breakfast","transports":[],"cost":0,"start_time":"08:00","end_time":"08:30"},{"position":"雨花门","type":"attraction","transports":[{"start":"南京玄武饭店","end":"玄武门-地铁站","mode":"walk","start_time":"08:30","end_time":"08:31","cost":0,"distance":0.1},{"start":"玄武门-地铁站","end":"武定门-地铁站","mode":"metro","start_time":"08:31","end_time":"08:43","cost":3,"distance":6.32,"tickets":1},{"start":"武定门-地铁站","end":"雨花门","mode":"walk","start_time":"08:43","end_time":"08:48","cost":0,"distance":0.42}],"cost":0,"start_time":"08:48","end_time":"10:18"},{"position":"江心洲大桥","type":"attraction","transports":[{"start":"雨花门","end":"武定门-地铁站","mode":"walk","start_time":"10:18","end_time":"10:23","cost":0,"distance":0.42},{"start":"武定门-地铁站","end":"雨山路-地铁 站","mode":"metro","start_time":"10:23","end_time":"10:57","cost":5,"distance":17.3,"tickets":1},{"start":"雨山路-地铁站","end":"江心洲大桥","mode":"walk","start_time":"10:57","end_time":"11:31","cost":0,"distance":2.86}],"cost":0,"start_time":"11:31","end_time":"13:01"},{"position":"胡小石纪念馆","type":"attraction","transports":[{"start":"江心洲大桥","end":"雨山路-地铁站","mode":"walk","start_time":"13:01","end_time":"13:35","cost":0,"distance":2.86},{"start":"雨山路-地铁站","end":"文德路-地铁站","mode":"metro","start_time":"13:35","end_time":"13:38","cost":2,"distance":1.8,"tickets":1},{"start":"文德路-地铁站","end":"胡小石纪念馆","mode":"walk","start_time":"13:38","end_time":"13:45","cost":0,"distance":0.61}],"cost":0,"start_time":"13:45","end_time":"15:15"},{"start_time":"17:00","end_time":"14:52","start":"南京站","end":"深圳站","TrainID":"K36","type":"train","transports":[{"start":"胡小石纪念馆","end":"文德路-地铁站","mode":"walk","start_time":"15:15","end_time":"15:22","cost":0,"distance":0.61},{"start":"文德路-地铁站","end":"南京站-地铁站","mode":"metro","start_time":"15:22","end_time":"15:54","cost":5,"distance":16.42,"tickets":1},{"start":"南京站-地铁站","end":"南京站","mode":"walk","start_time":"15:54","end_time":"15:56","cost":0,"distance":0.25}],"cost":462.73,"tickets":1}]}]}
"""
test_symbolic_input = {"preference_en": ["close to {中山陵景区,行政院}"]}
plan_json = json.loads(test_json_txt)
result = _evaluate_preference(test_symbolic_input, plan_json)
print(result)
if __name__ == "__main__":
test()