Spaces:
Sleeping
Sleeping
from typing import Dict, List | |
from fastapi import FastAPI, APIRouter, HTTPException, Request, Response # type: ignore | |
from fastapi.responses import JSONResponse, RedirectResponse, HTMLResponse # type: ignore | |
from datetime import datetime, timedelta | |
from fastapi.templating import Jinja2Templates | |
from app.dialogflow.services.dialog_service import dialog_service | |
from utils.format_data_dialog import format_time, get_weekday_name | |
from common.external.external_api import api | |
from app.dialogflow.services.origin_codes import origin_codes | |
from common.response.respone_dialogflow import DialogFlowResponseAPI | |
router = APIRouter() | |
templates = Jinja2Templates(directory="templates") | |
async def confirm(request: Request): | |
body = await request.json() | |
session_info = body.get("sessionInfo", {}) | |
parameters = session_info.get("parameters", {}) if isinstance(session_info.get("parameters"), dict) else {} | |
raw_date = parameters.get("date") | |
departure_city = parameters.get("departure_city") | |
destination_city = parameters.get("destination_city") | |
origin_office = parameters.get("origin_office") | |
dest_office = parameters.get("dest_office") | |
raw_ticket_number = parameters.get("ticket_number") | |
ticket_number = int(raw_ticket_number) if raw_ticket_number else 1 | |
date = dialog_service.to_datetime_from_Dialogflow(raw_date) | |
date, week_day = get_weekday_name(date) | |
text = [f"""Ngày: {date} {week_day}\nSố vé: {ticket_number}"""] | |
temp = "" | |
if origin_office and dest_office: | |
temp = f"""Điểm đi: {origin_office}\nĐiểm đến: {dest_office}\n""" | |
elif origin_office and departure_city: | |
temp = f"""Điểm đi: {origin_office}\nĐiểm đến: {departure_city}\n""" | |
elif dest_office and departure_city: | |
temp = f"""Điểm đi: {departure_city}\nĐiểm đến: {dest_office}\n""" | |
elif departure_city and destination_city: | |
temp = f"""Điểm đi: {departure_city}\nĐiểm đến: {destination_city}\n""" | |
text[0] = temp + text[0] | |
payload = { | |
"richContent": [ | |
[ | |
{ | |
"type": "chips", | |
"options": [ | |
{"text": "Tìm chuyến xe"}, | |
{"text": "Không, cảm ơn"} | |
] | |
} | |
] | |
] | |
} | |
return DialogFlowResponseAPI(text=text, payload=payload) | |
async def route(request: Request): | |
body = await request.json() | |
raw_departure_city, raw_destination_city, raw_ticket_number , raw_date, _ = dialog_service.get_param_from_dialogflow(body) | |
ticket_count = int(raw_ticket_number) if raw_ticket_number else 1 | |
if raw_date is None: | |
from_time, to_time = dialog_service.process_dates_to_timestamp() | |
date = datetime.today().date().strftime('%m-%d-%Y') | |
else: | |
date = raw_date.strftime('%m-%d-%Y') | |
from_time, to_time = dialog_service.process_dates_to_timestamp(raw_date) | |
departure_code = origin_codes.get(raw_departure_city) | |
destination_code = origin_codes.get(raw_destination_city) | |
route_dep_to_des = await dialog_service.search_route_ids_from_province(departure_code,destination_code) | |
route_des_to_dep = await dialog_service.search_route_ids_from_province(destination_code,departure_code) | |
routes_ids = list(set(route_dep_to_des + route_des_to_dep)) | |
payload = { | |
"from_time": from_time, | |
"to_time": to_time, | |
"route_ids": routes_ids, | |
"ticket_count": 1, | |
"sort_by": ["price", "departure_time"] | |
} | |
try: | |
respone = await api.post("/search/trips", payload=payload) | |
data = respone["data"]["items"] | |
total = respone["data"]["total"] | |
if total > 0: | |
price = data[0]["price"] | |
list_raw_departure_times = sorted(list(set([ trip["raw_departure_time"] for trip in data]))) | |
list_raw_seat_type = list(set([ trip["seat_type_name"] for trip in data])) | |
seat_type_trip_string = "**" + "** | **".join(map(str, list_raw_seat_type)) + "**" | |
schedule_time_trip = "**" + "** | **".join(map(str, list_raw_departure_times)) + "**" | |
duration = data[0]["duration"] | |
link = f'https://stag.futabus.vn/dat-ve?from={departure_code}&fromTime={date}&isReturn=false&ticketCount={ticket_count}&to={destination_code}&toTime=' | |
text = [f"Tuyến xe **{raw_departure_city}** - **{raw_destination_city}**\n \ | |
Loại xe: {seat_type_trip_string} \n \ | |
Thời gian hành trình: {duration} giờ \n \ | |
Giá vé: **{price}** VND"] | |
payload = { | |
"richContent": [ | |
[ | |
{ | |
"type": "chips", | |
"options": [ | |
{"text": "Tìm chuyến xe"}, | |
{"text": "Xem lịch trình khác"}, | |
{"text": "Không, cảm ơn"} | |
] | |
} | |
] | |
] | |
} | |
return DialogFlowResponseAPI(text=text, payload=payload) | |
text = [f"Hệ thống không tìm thấy tuyến xe **{raw_departure_city}** - **{raw_destination_city}**.\n Quý khách vui lòng thử lại với lộ trình khác hoặc liên hệ Trung tâm tổng đài 1900 6067 để được hỗ trợ."] | |
payload = { | |
"richContent": [ | |
[ | |
{ | |
"type": "chips", | |
"options": [ | |
{"text": "Xem lịch trình khác"}, | |
{"text": "Không, cảm ơn"} | |
] | |
} | |
] | |
] | |
} | |
return DialogFlowResponseAPI(text=text, payload=payload) | |
# return DialogFlowResponeAPI(text=['Hello']) | |
except Exception as e: | |
return DialogFlowResponseAPI(text=["Hệ thống xảy ra lỗi. Quý khách vui lòng thử lại sau hoặc liên hệ Trung tâm tổng đài 1900 6067 để được hỗ trợ."]) | |
async def price(request: Request): | |
body = await request.json() | |
raw_departure_city, raw_destination_city, _, raw_date, _ = dialog_service.get_param_from_dialogflow(body) | |
if raw_date is None: | |
from_time, to_time = dialog_service.process_dates_to_timestamp() | |
from_time, to_time = dialog_service.process_dates_to_timestamp(raw_date) | |
departure_code = origin_codes.get(raw_departure_city) | |
destination_code = origin_codes.get(raw_destination_city) | |
route_dep_to_des = await dialog_service.search_route_ids_from_province(departure_code,destination_code) | |
route_des_to_dep = await dialog_service.search_route_ids_from_province(destination_code,departure_code) | |
routes_ids = list(set(route_dep_to_des + route_des_to_dep)) | |
payload = { | |
"from_time": from_time, | |
"to_time": to_time, | |
"route_ids": routes_ids, | |
"ticket_count": 1, | |
"sort_by": ["price", "departure_time"] | |
} | |
try: | |
respone = await api.post("/search/trips", payload=payload) | |
total = respone["data"]["total"] | |
if total > 0: | |
price = respone["data"]["items"][0]["price"] | |
text = [f"Tuyến xe **{raw_departure_city}** - **{raw_destination_city}**\n" | |
f"Giá vé: **{price}** VND.\n \ | |
Bạn có muốn đặt vé không?" | |
] | |
payload = { | |
"richContent": [ | |
[ | |
{ | |
"type": "chips", | |
"options": [ | |
{"text": "Có, tôi muốn đặt vé"}, | |
{"text": "Xem giá vé tuyến xe khác"}, | |
{"text": "Không, cảm ơn"} | |
] | |
} | |
] | |
] | |
} | |
return DialogFlowResponseAPI(text=text, payload=payload) | |
text = [f"Hệ thống không tìm thấy tuyến xe **{raw_departure_city}** - **{raw_destination_city}**.\n Quý khách vui lòng thử lại với lộ trình khác hoặc liên hệ Trung tâm tổng đài 1900 6067 để được hỗ trợ."] | |
payload={ | |
"richContent": [ | |
[ | |
{ | |
"type": "chips", | |
"options": [ | |
{"text": "Xem giá vé lịch trình khác"}, | |
{"text": "Không, cảm ơn"} | |
] | |
} | |
] | |
] | |
} | |
return DialogFlowResponseAPI(text=text, payload=payload) | |
except: | |
return DialogFlowResponseAPI(text=["Hệ thống xảy ra lỗi. Quý khách vui lòng thử lại sau hoặc liên hệ Trung tâm tổng đài 1900 6067 để được hỗ trợ."]) | |
async def booking_trip(request: Request) -> Response: | |
body = await request.json() | |
raw_departure_city, raw_destination_city, raw_ticket_number, raw_date, raw_time_of_day = dialog_service.get_param_from_dialogflow(body) | |
date = raw_date.strftime('%m-%d-%Y') | |
from_time, to_time = dialog_service.process_dates_to_timestamp(raw_date) | |
ticket_count = int(raw_ticket_number) if raw_ticket_number else 1 | |
departure_code = origin_codes.get(raw_departure_city) | |
destination_code = origin_codes.get(raw_destination_city) | |
route_dep_to_des = await dialog_service.search_route_ids_from_province(departure_code,destination_code) | |
route_des_to_dep = await dialog_service.search_route_ids_from_province(destination_code,departure_code) | |
routes_ids = list(set(route_dep_to_des + route_des_to_dep)) | |
try: | |
data = await dialog_service.search_trip(from_time, to_time, routes_ids, ticket_count) | |
total = len(data) | |
if total > 0: | |
trips = [] | |
routes_name = [] | |
for trip in data: | |
if ticket_count <= trip["empty_seat_quantity"]: | |
route = f"{trip['route']['origin_hub_name']} => {trip['route']['dest_hub_name']}" | |
if trip["route"] and route not in routes_name: | |
routes_name.append(f"{trip['route']['origin_hub_name']} => {trip['route']['dest_hub_name']}") | |
trips.append({ | |
"route_name": f"{trip['route']['origin_hub_name']} => {trip['route']['dest_hub_name']}", | |
"route_id": trip["route_id"], | |
"id": trip["id"], | |
"departure_date": trip["raw_departure_date"], | |
"departure_time": trip["raw_departure_time"], | |
"kind": trip["seat_type_name"], | |
"way_id": trip["way_id"] | |
}) | |
text = ["Quý khách vui lòng lựa chọn chuyến xe\n" + "\n".join(f"{i+1}. {name}" for i, name in enumerate(routes_name))] | |
payload={ | |
"richContent": [ | |
[ | |
{ | |
"type": "chips", | |
"options": [ | |
{"text": name} for name in (routes_name) | |
] | |
} | |
] | |
] | |
} | |
parameters = { | |
"trip_list": trips, | |
"routes_name": routes_name | |
} | |
return DialogFlowResponseAPI(text=text, payload=payload,parameters=parameters) | |
text = [f"Hệ thống không tìm thấy tuyến xe **{raw_departure_city}** - **{raw_destination_city}**.\n Quý khách vui lòng thử lại với lộ trình khác hoặc liên hệ Trung tâm tổng đài 1900 6067 để được hỗ trợ."] | |
payload={ | |
"richContent": [ | |
[ | |
{ | |
"type": "chips", | |
"options": [ | |
{"text": "Xem tuyến xe khác"}, | |
{"text": "Không, cảm ơn"} | |
] | |
} | |
] | |
] | |
} | |
return DialogFlowResponseAPI(text=text, payload=payload) | |
except Exception as e: | |
print(e) | |
return JSONResponse( | |
{ | |
"fulfillment_response": { | |
"messages": [ | |
{ | |
"text": { | |
"text": ["Hệ thống xảy ra lỗi. Quý khách vui lòng thử lại sau hoặc liên hệ Trung tâm tổng đài 1900 6067 để được hỗ trợ."] | |
} | |
} | |
] | |
}, | |
} | |
) | |
async def is_valid_select_trip(request: Request) -> Response: | |
body = await request.json() | |
raw_input = body.get("text", "") | |
session_info = body.get("sessionInfo", {}) | |
parameters = session_info.get("parameters") | |
routes_name = parameters.get("routes_name") | |
if raw_input: | |
raw_input = raw_input.strip() | |
if raw_input in routes_name: | |
trip_list: List[Dict[str, any]] = parameters.get("trip_list") | |
for trip in trip_list: | |
if trip["route_name"] == raw_input: | |
route_id = int(trip["route_id"]) | |
kind = trip["kind"] | |
way_id = trip["way_id"] | |
break | |
parameters = { | |
"is_valid_trip": True, | |
"route_name": raw_input, | |
"kind": kind, | |
"route_id": route_id, | |
"way_id": way_id, | |
} | |
else: | |
parameters = { | |
"is_valid_trip": False, | |
} | |
return DialogFlowResponseAPI(parameters=parameters) | |
async def time_trip(request: Request) -> Response: | |
try: | |
body = await request.json() | |
session_info = body.get("sessionInfo", {}) | |
parameters = session_info.get("parameters") | |
trip_list: List[Dict[str, any]] = parameters.get("trip_list", []) | |
raw_route_id = parameters.get("route_id", None) | |
route_name = parameters.get("route_name", "") | |
route_id = int(raw_route_id) if raw_route_id else None | |
time_list = [] | |
for trip in trip_list: | |
if (trip["route_id"]) == route_id: | |
time_list.append({"time": trip["departure_time"], "id": trip["id"]}) | |
parameters = { | |
"time_list": time_list | |
} | |
text = [f"Quý khách lựa chọn thời gian chuyến {route_name}\n" + " | ".join([item["time"] for item in time_list])] | |
payload={ | |
"richContent": [ | |
[ | |
{ | |
"type": "chips", | |
"options": [ | |
{"text": time["time"]} for time in (time_list) | |
] | |
} | |
] | |
] | |
} | |
return DialogFlowResponseAPI(text=text, payload=payload ,parameters=parameters) | |
except Exception as e: | |
print(e) | |
return DialogFlowResponseAPI(text=["Hệ thống xảy ra lỗi. Quý khách vui lòng thử lại sau hoặc liên hệ Trung tâm tổng đài 1900 6067 để được hỗ trợ."]) | |
async def is_valid_select_time(request: Request) -> Response: | |
try: | |
body = await request.json() | |
session_info = body.get("sessionInfo", {}) | |
parameters = session_info.get("parameters") | |
raw_departure_city, raw_destination_city, raw_ticket_number, raw_date, raw_time_of_day = dialog_service.get_param_from_dialogflow(body) | |
date = raw_date.strftime('%m-%d-%Y') | |
from_time, to_time = dialog_service.process_dates_to_timestamp(raw_date) | |
ticket_count = int(raw_ticket_number) if raw_ticket_number else 1 | |
departure_code = origin_codes.get(raw_departure_city) | |
destination_code = origin_codes.get(raw_destination_city) | |
route_dep_to_des = await dialog_service.search_route_ids_from_province(departure_code,destination_code) | |
route_des_to_dep = await dialog_service.search_route_ids_from_province(destination_code,departure_code) | |
routes_ids = list(set(route_dep_to_des + route_des_to_dep)) | |
time_list: List[Dict[str, any]] = parameters.get("time_list", []) | |
time_select = parameters.get("time-select", None) | |
route_name = parameters.get("route_name", None) | |
if time_select is not None: | |
time_select = format_time(time_select) | |
for time in time_list: | |
if time_select == time["time"]: | |
id = int(time["id"]) | |
trip = await dialog_service.search_trip_by_id(id, from_time, to_time, routes_ids, ticket_count) | |
departure_date = trip["raw_departure_date"] | |
parameters = { | |
"is_valid_time": True, | |
"departure_time": time_select, | |
"departure_date": departure_date, | |
"trip": trip, | |
} | |
text = [f' Quý khách chọn chuyến {time_select} | {route_name}'] | |
return DialogFlowResponseAPI(text=text, parameters=parameters) | |
parameters = { | |
"is_valid_time": False | |
} | |
text = [] | |
return DialogFlowResponseAPI(text=text, parameters=parameters) | |
except Exception as e: | |
print(e) | |
return DialogFlowResponseAPI(text=["Hệ thống xảy ra lỗi. Quý khách vui lòng thử lại sau hoặc liên hệ Trung tâm tổng đài 1900 6067 để được hỗ trợ."]) | |
async def seats_trip(request: Request) -> Response: | |
try: | |
body = await request.json() | |
session_info = body.get("sessionInfo", {}) | |
parameters = session_info.get("parameters") | |
trip = parameters.get("trip", None) | |
route_id: int = parameters.get("route_id", None) | |
route_id = int(route_id) if route_id else None | |
departure_date: str = parameters.get("departure_date", None) | |
departure_time: str = parameters.get("departure_time", None) | |
kind: str = parameters.get("kind", None) | |
trip_id = int(trip["id"]) if trip else None | |
seats = await dialog_service.seats_trip(route_id, trip_id, departure_date, departure_time, kind) | |
seats_empty = [ seat for seat in seats if seat["bookStatus"] == 0 ] | |
seats_empty.sort(key=lambda x: x["chair"]) | |
text=["Vui lòng chọn ghế"] | |
payload={ | |
"richContent": [ | |
[ | |
{ | |
"type": "chips", | |
"options": [ | |
{"text": seat["chair"]} for seat in (seats_empty) | |
] | |
} | |
] | |
] | |
} | |
parameters = { | |
"seat_list": seats | |
} | |
return DialogFlowResponseAPI(text=text, payload=payload, parameters=parameters) | |
except Exception as e: | |
print(e) | |
return DialogFlowResponseAPI(text=["Hệ thống xảy ra lỗi. Quý khách vui lòng thử lại sau hoặc liên hệ Trung tâm tổng đài 1900 6067 để được hỗ trợ."]) | |
async def is_valid_select_seat(request: Request) -> Response: | |
try: | |
body = await request.json() | |
session_info = body.get("sessionInfo", {}) | |
parameters = session_info.get("parameters") | |
trip = parameters.get("trip", None) | |
route_id: int = parameters.get("route_id", None) | |
route_id = int(route_id) if route_id else None | |
departure_date: str = parameters.get("departure_date", None) | |
departure_time: str = parameters.get("departure_time", None) | |
kind: str = parameters.get("kind", None) | |
seat: str = parameters.get("seat", None) | |
trip_id = int(trip["id"]) if trip else None | |
is_valid = await dialog_service.is_valid_select_seat(seat, route_id, trip_id, departure_date, departure_time, kind) | |
if is_valid: | |
parameters = { | |
"is_valid_seat": True, | |
"seat": seat | |
} | |
text = [f"Quý khách chọn ghế {seat}"] | |
else: | |
parameters = { | |
"is_valid_seat": False, | |
"seat": None | |
} | |
text = [f"Ghế {seat} đã được đặt. Quý khách vui lòng chọn ghế khác"] | |
return DialogFlowResponseAPI(text=text, parameters=parameters) | |
except Exception as e: | |
return DialogFlowResponseAPI(text=["Hệ thống xảy ra lỗi. Quý khách vui lòng thử lại sau hoặc liên hệ Trung tâm tổng đài 1900 6067 để được hỗ trợ."]) | |
async def pickup(request: Request) -> Response: | |
body = await request.json() | |
session_info = body.get("sessionInfo", {}) | |
parameters = session_info.get("parameters") | |
trip: dict[str, any] = parameters.get("trip", None) | |
route_id: int = trip["route_id"] | |
route_id = int(route_id) if route_id else None | |
way_id: int = trip["way_id"] | |
way_id = int(way_id) if way_id else None | |
pickup_list = await dialog_service.pickup_list(route_id, way_id) | |
text=["Quý khách vui lòng chọn điểm đón"] | |
payload={ | |
"richContent": [ | |
[ | |
{ | |
"type": "chips", | |
"options": [ | |
{"text": pickup["name"]} for pickup in (pickup_list) | |
] | |
} | |
] | |
] | |
} | |
parameters = { | |
"pickup_list": pickup_list | |
} | |
return DialogFlowResponseAPI(text=text, payload=payload, parameters=parameters) | |
async def is_valid_select_pickup(request: Request) -> Response: | |
body = await request.json() | |
session_info = body.get("sessionInfo", {}) | |
parameters = session_info.get("parameters") | |
trip = parameters.get("trip", None) | |
route_id: int = trip["route_id"] | |
route_id = int(route_id) if route_id else None | |
way_id: int = trip["way_id"] | |
way_id = int(way_id) if way_id else None | |
raw_input = (body.get("text","")) | |
pickup = raw_input.strip() | |
is_valid = await dialog_service.is_valid_pickup(pickup, route_id, way_id) | |
if is_valid: | |
parameters = { | |
"is_valid_pickup": True, | |
"pick_up": pickup | |
} | |
text = [f"Quý khách chọn điểm đón {pickup}"] | |
else: | |
parameters = { | |
"is_valid_pickup": False, | |
} | |
text = [f"Điểm đón không hợp lệ. Quý khách vui lòng chọn điểm đón khác"] | |
return DialogFlowResponseAPI(text=text, parameters=parameters) | |
async def dropoff(request: Request) -> Response: | |
body = await request.json() | |
session_info = body.get("sessionInfo", {}) | |
parameters = session_info.get("parameters") | |
trip = parameters.get("trip", None) | |
route_id: int = trip["route_id"] | |
route_id = int(route_id) if route_id else None | |
way_id: int = trip["way_id"] | |
way_id = int(way_id) if way_id else None | |
dropoff_list = await dialog_service.dropoff_list(route_id, way_id) | |
text=["Quý khách vui lòng chọn điểm trả khách"] | |
payload={ | |
"richContent": [ | |
[ | |
{ | |
"type": "chips", | |
"options": [ | |
{"text": dropoff["name"]} for dropoff in (dropoff_list) | |
] | |
} | |
] | |
] | |
} | |
parameters = { | |
"dropoff_list": dropoff_list | |
} | |
return DialogFlowResponseAPI(text=text, payload=payload, parameters=parameters) | |
async def is_valid_select_dropoff(request: Request) -> Response: | |
body = await request.json() | |
session_info = body.get("sessionInfo", {}) | |
parameters = session_info.get("parameters") | |
trip = parameters.get("trip", None) | |
route_id: int = trip["route_id"] | |
route_id = int(route_id) if route_id else None | |
way_id: int = trip["way_id"] | |
way_id = int(way_id) if way_id else None | |
raw_input = (body.get("text","")) | |
dropoff = raw_input.strip() | |
is_valid = await dialog_service.is_valid_dropoff(dropoff, route_id, way_id) | |
if is_valid: | |
parameters = { | |
"is_valid_dropoff": True, | |
"drop_off": dropoff | |
} | |
text = [f"Quý khách chọn điểm trả khách {dropoff}"] | |
else: | |
parameters = { | |
"is_valid_dropoff": False, | |
} | |
text = [f"Điểm trả khách không hợp lệ. Quý khách vui lòng chọn điểm trả khách khác"] | |
return DialogFlowResponseAPI(text=text, parameters=parameters) | |
async def response_ticket_info(request: Request) -> Response: | |
body = await request.json() | |
session_info = body.get("sessionInfo", {}) | |
parameters = session_info.get("parameters") | |
user_name = parameters.get("user_name", None) | |
phone_number = parameters.get("phone_number", None) | |
email = parameters.get("email", None) | |
seat = parameters.get("seat", None) | |
pickup = parameters.get("pick_up", None) | |
dropoff = parameters.get("drop_off", None) | |
trip = parameters.get("trip", None) | |
route_name = trip["route"]["name"] | |
time = trip["raw_departure_time"] | |
date = trip["raw_departure_date"] | |
price = trip["price"] | |
price = int(price) if price else None | |
text = [ | |
f" \ | |
**Thông tin hành khách**\ | |
\n\ | |
Họ và tên {user_name} \ | |
Số điện thoại {phone_number} \ | |
Email {email} \ | |
\n\ | |
**Thông tin lượt đi** \ | |
\n\ | |
Tuyến xe {route_name} \ | |
Thời gian xuất bến {time} {date} \ | |
Số ghế {seat} \ | |
Điểm lên xe {pickup} \ | |
Điểm trả khách {dropoff} \ | |
Tổng tiền lượt đi {price} VND \ | |
" | |
] | |
payload={ | |
"richContent": [ | |
[ | |
{ | |
"type": "chips", | |
"options": [ | |
{"text": "Đặt vé"}, | |
{"text": "Không, cảm ơn"} | |
] | |
} | |
] | |
] | |
} | |
return DialogFlowResponseAPI(text=text, payload=payload) | |
def home(): | |
return "Hello World!" | |
async def index(request: Request): | |
return templates.TemplateResponse("index.html", {"request": request, "title": "Dawi Chatbot"}) |