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.services import api from app.utils.constants import code_province from app.types.Respone import DialogFlowResponseAPI router = APIRouter() templates = Jinja2Templates(directory="app/templates") def to_datetime_from_Dialogflow(time: dict): date_time = datetime(int(time["year"]), int(time["month"]), int(time["day"])) return date_time # Xử lý fromTime và toTime def process_dates_to_timestamp(from_time: datetime = None, to_time: datetime = None): print(from_time) if to_time is None and from_time is not None: to_time = from_time.replace(hour=23, minute=59, second=59) if from_time is None: today = datetime.today().date() from_time = datetime.combine(today, datetime.min.time()) to_time = datetime.combine(today, datetime.max.time()) - timedelta(microseconds=1) return int(from_time.timestamp()) * 1000 , int(to_time.timestamp()) * 1000 def get_param_from_dialogflow(body: any): session_info = body.get("sessionInfo", {}) parameters = session_info.get("parameters") raw_date = parameters.get("date") if raw_date is not None: raw_date = to_datetime_from_Dialogflow(raw_date) raw_departure_city = parameters.get("departure_city") raw_destination_city = parameters.get("destination_city") raw_ticket_number = parameters.get("ticket_number") raw_time_of_day = parameters.get("time_of_day") return raw_departure_city, raw_destination_city, raw_ticket_number, raw_date, raw_time_of_day async def search_route_ids_from_province(departure_code: str, destination_code: str): response = await api.get(f'/metadata/office/routes?DestCode={destination_code}&OriginCode={departure_code}') route_ids = [] if isinstance(response, list): # Kiểm tra nếu data là danh sách route_ids = [route.get("routeId", -1) for route in response] return route_ids @router.post('/routes') async def route(request: Request): body = await request.json() raw_departure_city, raw_destination_city, raw_ticket_number , raw_date, _ = 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 = process_dates_to_timestamp() date = datetime.today().date().strftime('%m-%d-%Y') else: date = raw_date.strftime('%m-%d-%Y') from_time, to_time = process_dates_to_timestamp(raw_date) departure_code = code_province.get(raw_departure_city) destination_code = code_province.get(raw_destination_city) route_dep_to_des = await search_route_ids_from_province(departure_code,destination_code) route_des_to_dep = await 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]))) schedule_time_trip = "**" + "** | **".join(map(str, list_raw_departure_times)) + "**" link = f'https://stag.futabus.vn/dat-ve?from={departure_code}&fromTime={date}&isReturn=false&ticketCount={ticket_count}&to={destination_code}&toTime=' text = [f"Lộ trình **{raw_departure_city}** - **{raw_destination_city}**: **{total}** tuyến xe.\n \ Thời gian các tuyến xe khởi hành: {schedule_time_trip}\n \ Giá vé: **{price}** VND.\n \ Quý khách vui lòng truy cập vào [**tại đây**]({link}) để xem chi tiết lịch trình."] payload = { "richContent": [ [ { "type": "chips", "options": [ {"text": "Đặt vé"}, {"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 nào phù hợp với lộ trình **{raw_departure_city}** - **{raw_destination_city}** của quý khách.\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ợ."]) @router.post('/price') async def price(request: Request): body = await request.json() raw_departure_city, raw_destination_city, _, raw_date, _ = get_param_from_dialogflow(body) if raw_date is None: from_time, to_time = process_dates_to_timestamp() from_time, to_time = process_dates_to_timestamp(raw_date) departure_code = code_province.get(raw_departure_city) destination_code = code_province.get(raw_destination_city) route_dep_to_des = await search_route_ids_from_province(departure_code,destination_code) route_des_to_dep = await 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"Lộ trình **{raw_departure_city}** - **{raw_destination_city}**\n" f"Giá vé: **{price}** VND.\nBạ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é 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 nào phù hợp với lộ trình **{raw_departure_city}** - **{raw_destination_city}** của quý khách.\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ợ."]) @router.post('/trip/booking') 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 = get_param_from_dialogflow(body) date = raw_date.strftime('%m-%d-%Y') from_time, to_time = process_dates_to_timestamp(raw_date) ticket_count = int(raw_ticket_number) if raw_ticket_number else 1 departure_code = code_province.get(raw_departure_city) destination_code = code_province.get(raw_destination_city) route_dep_to_des = await search_route_ids_from_province(departure_code,destination_code) route_des_to_dep = await 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": ticket_count, "sort_by": ["price", "departure_time"] } try: respone = await api.post("/search/trips", payload=payload) if respone.get('status') == 200: data = respone["data"]["items"] total = respone["data"]["total"] if total > 0: price = respone["data"]["items"][0]["price"] list_raw_departure_times = sorted(list(set([ trip["raw_departure_time"] for trip in data]))) schedule_time_trip = "**" + "** | **".join(map(str, list_raw_departure_times)) + "**" link = f'https://stag.futabus.vn/dat-ve?from={departure_code}&fromTime={date}&isReturn=false&ticketCount={ticket_count}&to={destination_code}&toTime=' text= [f"Lộ trình **{raw_departure_city}** - **{raw_destination_city}**: **{total}** tuyến xe.\n" f"Thời gian các tuyến xe khởi hành: {schedule_time_trip}\n" f"Giá vé: **{price}** VND.\n" f"Quý khách vui lòng truy cập vào [**tại đây**]({link}) để tiến hành đặt vé."] return DialogFlowResponseAPI(text=text) text = [f"Hệ thống không tìm thấy tuyến xe nào phù hợp với lộ trình **{raw_departure_city}** - **{raw_destination_city}** của quý khách.\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) 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ợ."] } } ] }, } ) @router.get("/") def home(): return "Hello World!" @router.get('/chatbot', response_class=HTMLResponse) async def index(request: Request): return templates.TemplateResponse("index.html", {"request": request, "title": "Dawi Chatbot"})