def expect_slots_and_choose_state_for_selecting_train(turn: RzdTurn): """Второй этап. Заполнение слотов для выбора поезда.""" print(f"usr_object: {turn.user_object}") # Достаем все возможные слоты из объекта trains = turn.user_object.get("trains", None) car_type = turn.user_object.get("car_type", None) seat_type = turn.user_object.get("seat_type", None) print(f"car_type: {car_type}") print(f"seat_type: {seat_type}") if car_type and (seat_type or car_type not in ['econom', 'sleeping']): filtered_trains = filter_trains_by_rzd_car_type( trains, car_type_to_rzd_type(car_type)) if not filtered_trains: turn.response_text = f'К сожалению нет поездов с {car_type_to_human_str(car_type, form=2)} вагонами ' \ f'на указанное время.\n' \ f'Давайте выберем вагон другого типа?' turn.suggests.extend(get_human_readable_existing_car_types(trains)) turn.user_object["car_type"] = None turn.stage = "expect_car_type" else: selected_train = filtered_trains[0] turn.user_object["selected_train"] = selected_train response_str = f'Покупаем билет на поезд {selected_train["number"]} ' \ f'{selected_train["from"]} {selected_train["to"]} на {selected_train["time_start"]} ' \ f'местного времени, ' if car_type in ['econom', 'sleeping']: response_str += f'{seat_type_to_human_str(seat_type, form=1)} место в ' \ f'{car_type_to_human_str(car_type, form=3)} вагоне. ' else: response_str += f'{car_type_to_human_str(car_type)} вагон. ' response_str += f'\nЦена {selected_train["cost"]} руб.\nВсе правильно?' turn.response_text = response_str turn.stage = 'expect_after_selecting_train_slots_filled' turn.suggests.extend(['Да', 'Нет']) # Заполнили вторую часть if not car_type: extracted_prices = extract_min_max_prices_for_car_types(trains) prices_information_str = extracted_prices_to_information_str( extracted_prices) turn.response_text = f'{prices_information_str}\nКакой хотите тип вагона?' turn.stage = 'expect_car_type' turn.suggests.extend(get_human_readable_existing_car_types(trains)) elif car_type in ['econom', 'sleeping'] and not seat_type: # Для плацкартного и купейного вагона уточняем тип места turn.response_text = 'Верхнее или нижнее место?' turn.stage = 'expect_seat_type' turn.suggests.extend(['Верхнее', 'Нижнее']) print(f"next stage is: {turn.stage}") return turn
def expect_departure_time_tag(turn: RzdTurn): print("expect_departure_time_tag handler") print(f"intents: {turn.intents}") forms = turn.forms['time_tags'] time_tags = forms.keys() source_trains = turn.user_object['trains'] filtered_trains = filter_trains_by_time_tags(source_trains, time_tags) print(f"Filtered trains by time tags: {filtered_trains}") if len(filtered_trains) == 0: extracted_prices = extract_min_max_prices_for_car_types(source_trains) prices_information_str = extracted_prices_to_information_str( extracted_prices) # Если на нужное время дня нет билетов то говорим об этом и предлагаем соазу выбирать тип вагона и места turn.response_text = f'К сожалению, на выбранное время дня нет билетов. ' \ f'Давайте выберем место в найденных билетах?\n\n{prices_information_str}' turn.stage = 'expect_all_train_data' rzd_car_types = get_human_readable_existing_car_types(source_trains) if rzd_car_types: turn.suggests.extend( create_suggestions_for_car_types(rzd_car_types)) else: turn.suggests.extend( ['Верхнее место в плацкарте', 'Нижнее место в купе']) else: extracted_prices = extract_min_max_prices_for_car_types( filtered_trains) prices_information_str = extracted_prices_to_information_str( extracted_prices) # Теперь в юзерстейте лежат отфильтрованные по времени билеты turn.user_object['trains'] = filtered_trains # Переходим к выбору типа вагона и мест turn.response_text = f'{prices_information_str}\nКакое место хотите?' turn.stage = 'expect_all_train_data' rzd_car_types = get_human_readable_existing_car_types(filtered_trains) if rzd_car_types: turn.suggests.extend( create_suggestions_for_car_types(rzd_car_types)) else: turn.suggests.extend( ['Верхнее место в плацкарте', 'Нижнее место в купе'])
def expect_departure_time(turn: RzdTurn): print("expect_departure_time handler") # Должен быть заполнен интент slots_filing и слот when forms = turn.forms['slots_filling'] when_text = forms.get('when', None) near_text = forms.get("near", None) if not (when_text or near_text): # Во время дозаполнения слота времени мы не получили данный слот. Переспрашиваем ещё раз turn.response_text = 'Назовите дату, на которую хотите посмотреть билет' # Оставляем тот же стейт turn.stage = 'expect_departure_time' turn.suggests.extend(['Завтра', 'Сегодня', 'Ближайшая']) elif when_text: # Получили недостающий слот со временем. Заполняем данные turn.user_object['when_text'] = date2ru(convert_date_to_abs(when_text)) turn = check_slots_and_chose_state(turn) print(f"turn.response_text: {turn.response_text}") else: turn.user_object['near_text'] = near_text # На всякий случай сохраняем в поле when_text сегодняшнюю дату turn.user_object['when_text'] = date2ru(convert_date_to_abs('сегодня')) turn = check_slots_and_chose_state(turn) print(f"turn.response_text: {turn.response_text}")
def expect_car_type(turn: RzdTurn): # Уточняем тип вагона print("expect_car_type handler") # Должен быть заполнен интент selecting_train и слот car_type forms = turn.forms.get('selecting_train', None) or turn.forms.get( 'car_type_slot_filling', None) car_type = forms.get('car_type', None) trains = turn.user_object.get("trains", None) prices_information_str = "" if trains: extracted_prices = extract_min_max_prices_for_car_types(trains) prices_information_str = extracted_prices_to_information_str( extracted_prices) if not car_type: # Переспрашиваем тип вагона turn.response_text = f'{prices_information_str}Какой хотите тип вагона?' # Оставляем тот же стейт turn.stage = 'expect_car_type' if trains: turn.suggests.extend(get_human_readable_existing_car_types(trains)) else: turn.suggests.extend(['Плацкартный', 'Купейный', 'СВ', 'Сидячий']) elif trains and not car_type_to_human_str(car_type).capitalize( ) in get_human_readable_existing_car_types(trains): # Гооворим, что вагона заданного типа нет turn.response_text = f'К сожалению нет поездов с {car_type_to_human_str(car_type, form=2)} вагонами ' \ f'на указанное время! ' \ f'Выберем другой тип вагона?\n\n{prices_information_str}' # Оставляем тот же стейт turn.stage = 'expect_car_type' turn.suggests.extend(get_human_readable_existing_car_types(trains)) else: # Получили недостающий слот со временем. Заполняем данные turn.user_object['car_type'] = car_type turn = expect_slots_and_choose_state_for_selecting_train(turn) print(f"turn.response_text: {turn.response_text}")
def check_slots_and_chose_state(turn: RzdTurn): """Проверяем что заполнены все слоты. Если что-то не заполнено то выбираем какой заполнить.""" print(turn.ctx.user_object) # Достаем все возможные слоты из объекта from_text = turn.ctx.user_object.get("from_text", None) to_text = turn.ctx.user_object.get("to_text", None) when_text = turn.ctx.user_object.get("when_text", None) if from_text and to_text and when_text: turn.response_text = f'Ищу билеты {from_text} {to_text} {when_text}. Все правильно?' turn.stage = 'expect_after_slots_filled' # На данном этапе полностью получены все слоты elif from_text and to_text: turn.response_text = f'Когда поедем {from_text} {to_text}?' turn.stage = 'expect_departure_time' turn.suggests.extend(['Завтра', 'Сегодня']) elif from_text and when_text: turn.response_text = f'Куда поедем {from_text} {when_text}?' turn.stage = 'expect_destination_place' turn.suggests.extend(['Петербург', 'Казань']) elif to_text and when_text: turn.response_text = f'Откуда поедем {to_text} {when_text}?' turn.stage = 'expect_departure_place' turn.suggests.extend(['Москва', 'Петербург']) else: turn.response_text = f'Давайте попробуем заново. Откуда и куда вы хотите билет?' turn.stage = 'expect_departure_place' turn.suggests.extend(['Москва', 'Петербург']) print(f"next stage is: {turn.stage}") return turn
def expect_departure_time(turn: RzdTurn): print("expect_departure_time handler") # Должен быть заполнен интент slots_filing и слот when forms = turn.forms['slots_filing'] when_text = forms.get('when', None) if not when_text: # Во время дозаполнения слота времени мы не получили данный слот. Переспрашиваем ещё раз turn.response_text = 'Назовите дату, на которую хотите посмотреть билет' # Оставляем тот же стейт turn.stage = 'expect_departure_time' turn.suggests.extend(['Завтра', 'Сегодня']) else: # Получили недостающий слот со временем. Заполняем данные turn.ctx.user_object['when_text'] = when_text
def suburb_purchase_details(turn: RzdTurn): sub = SuburbContext.from_dict(turn.user_object.get('suburb') or {}) if turn.intents.get('both_sides'): sub.bidirectional = True if turn.intents.get('one_side'): sub.bidirectional = False turn.response_text = f'Покупаю билет от станции {sub.from_norm} до станции {sub.to_norm}, ' if sub.bidirectional: turn.response_text += 'в обе стороны, ' cost_text = with_number("рубль", sub.cost * (sub.bidirectional + 1)) turn.response_text += f' с вашей карты {turn.bank_card} спишется {cost_text}. ' turn.response_text += 'Вы подтверждаете покупку?' turn.suggests.append('Да') turn.suggests.append( 'В одну сторону' if sub.bidirectional else 'В обе стороны') turn.stage = 'suburb_confirm_sell_final' turn.user_object['suburb'] = sub.to_dict()
def expect_destination_place(turn: RzdTurn): # Уточняем место назначения print("expect_destination_place handler") # Должен быть заполнен интент slots_filing и слот to forms = turn.forms['slots_filing'] to_text = forms.get('to', None) if not to_text: # Во время дозаполнения слота места назначения мы не получили данный слот. Переспрашиваем ещё раз turn.response_text = 'Назовите конечный пункт куда вы держите путь' # Оставляем тот же стейт turn.stage = 'expect_destination_place' turn.suggests.extend(['Москва', 'Петербург']) else: # Получили недостающий слот со временем. Заполняем данные turn.ctx.user_object['to_text'] = to_text
def expect_departure_place(turn: RzdTurn): # Уточняем место отправления print("expect_departure_place handler") # Должен быть заполнен интент slots_filing и слот from forms = turn.forms['slots_filing'] from_text = forms.get('from', None) if not from_text: # Во время дозаполнения слота места отправления мы не получили данный слот. Переспрашиваем ещё раз turn.response_text = 'Назовите, откуда вы собираетесь выезжать' # Оставляем тот же стейт turn.stage = 'expect_departure_place' turn.suggests.extend(['Москва', 'Петербург']) else: # Получили недостающий слот со временем. Заполняем данные turn.ctx.user_object['from_text'] = from_text
def greeting_handler(turn: RzdTurn): # Очищаем некоторые данные о пользователе, например, заполненные слоты из предыдущей сессии user_slots_to_delete = [ "from_text", "to_text", "when_text", "car_type", "seat_type", "quantity" ] for slot_name in user_slots_to_delete: if slot_name in turn.user_object: del turn.user_object[slot_name] turn.response_text = 'Привет! Это навык РЖД. Здесь вы можете найти и заказать билеты на поезд. ' \ 'Чтобы выйти из навыка, скажите "Хватит".' turn.suggests.append('Помощь') turn.suggests.append('билет москва - ярославль') turn.suggests.append('электрички от беговой до сколково') for slot in TRANSIENT_SLOTS: if slot in turn.user_object: del turn.user_object[slot]
def expect_seat_type(turn: RzdTurn): # Уточняем тип места print("expect_seat_type handler") forms = turn.forms.get('selecting_train', None) or turn.forms.get( 'seat_type_slot_filling', None) seat_type = forms.get('seat_type', None) car_type = turn.user_object.get('car_type', None) if car_type == 'first_class' or car_type == 'seating': turn.user_object['seat_type'] = 'нет' elif not seat_type: # Для плацкартного и купейного вагона уточняем тип места turn.response_text = 'Верхнее или нижнее место?' turn.stage = 'expect_seat_type' turn.suggests.extend(['Верхнее', 'Нижнее']) else: # Получили недостающий слот со временем. Заполняем данные turn.user_object['seat_type'] = seat_type turn = expect_slots_and_choose_state_for_selecting_train(turn) print(f"turn.response_text: {turn.response_text}")
def expect_departure_place(turn: RzdTurn): # Уточняем место отправления print("expect_departure_place handler") # Должен быть заполнен интент slots_filing и слот from forms = turn.forms['slots_filling'] from_text = forms.get('from', None) or forms.get( 'place', None) or forms.get('to', None) if not from_text: # Во время дозаполнения слота места отправления мы не получили данный слот. Переспрашиваем ещё раз turn.response_text = 'Назовите, откуда вы собираетесь выезжать' # Оставляем тот же стейт turn.stage = 'expect_departure_place' turn.suggests.extend(['Москва', 'Петербург']) else: # Получили недостающий слот с местом отправления. Заполняем данные from_text = convert_geo_to_normalized_city(from_text) turn.user_object['from_text'] = from_text turn.user_object['from_id'] = suggest_first_station(from_text) turn = check_slots_and_chose_state(turn) print(f"turn.response_text: {turn.response_text}")
def expect_destination_place(turn: RzdTurn): # Уточняем место назначения print("expect_destination_place handler") # Должен быть заполнен интент slots_filing и слот to forms = turn.forms['slots_filling'] to_text = forms.get('to', None) or forms.get('place', None) or forms.get( 'from', None) if not to_text: # Во время дозаполнения слота места назначения мы не получили данный слот. Переспрашиваем ещё раз turn.response_text = 'Назовите конечный пункт куда вы держите путь' # Оставляем тот же стейт turn.stage = 'expect_destination_place' turn.suggests.extend(['Москва', 'Петербург']) else: # Получили недостающий слот с местом назначения. Заполняем данные to_text = convert_geo_to_normalized_city(to_text) turn.user_object['to_text'] = to_text turn.user_object['to_id'] = suggest_first_station(to_text) turn = check_slots_and_chose_state(turn) print(f"turn.response_text: {turn.response_text}")
def expect_after_selecting_train_slots_filled(turn: RzdTurn): print("expect_after_selecting_train_slots_filled handler") print(f"intents: {turn.intents}") # TODO разобраться и поправить с учетом адреса картинки if 'yes' in turn.intents: selected_train = turn.user_object["selected_train"] cost = selected_train["cost"] from_location = selected_train["from"] to_location = selected_train["to"] url = f'https://rzd-skill.herokuapp.com/qr/?f={from_location}&t={to_location}' text = f'Отлично! Вы купили билет на поезд. С вашей карты будет списано {cost} руб.' turn.response = Response( image=BigImage( image_id='213044/4e2dacacedfb7029f89e', button_text='Скачать билет', button_url=url, description=text, ), text='', # voice='*', rich_text=text, ) else: turn.response_text = f'К сожалению, я ничего не нашла. Давайте попробуем заново'
def fallback(turn: RzdTurn): turn.response_text = 'Простите, я вас не понимаю.' turn.suggests.append('Помощь') turn.suggests.append('билет москва - ярославль') turn.suggests.append('электрички от беговой до сколково')
def help_handler(turn: RzdTurn): # todo: make help dependent on turn.text and maybe some context turn.response_text = 'Это навык РЖД. Здесь вы можете найти и заказать билеты на поезд.' \ 'Чтобы выйти из навыка, скажите "Хватит".' turn.suggests.append('Хватит')
def fallback(turn: RzdTurn): turn.response_text = 'Простите, я вас не понимаю.' turn.suggests.append('Помощь')
def check_slots_and_chose_state(turn: RzdTurn): """Проверяем что заполнены все слоты. Если что-то не заполнено то выбираем какой заполнить.""" # Достаем все возможные слоты из объекта from_text = turn.user_object.get("from_text", None) to_text = turn.user_object.get("to_text", None) when_text = turn.user_object.get("when_text", None) near_text = turn.user_object.get("near_text", None) print(f"check_slots_and_chose_state from_text: {from_text}") print(f"check_slots_and_chose_state to_text: {to_text}") print(f"check_slots_and_chose_state when_text: {when_text}") print(f"check_slots_and_chose_state near_text: {near_text}") response_text = "" if from_text and to_text and (when_text or near_text): if near_text: audio = get_audio() timer = audio["medium"] turn.response_text = f'Ищу ближайшие билеты по маршруту {from_text} - {to_text}. {timer} ' \ f'Показать, что нашлось?' else: turn.response_text = f'Ищу билеты по маршруту {from_text} - {to_text} {when_text}. Все правильно?' next_stage = 'expect_after_slots_filled' from_id = turn.user_object.get('from_id', None) to_id = turn.user_object.get('to_id', None) date_to = turn.user_object.get('when_text', None) params, cookies = init_find_route(from_id, to_id, date_to) turn.user_object['find_route_params'] = params turn.user_object['find_route_cookies'] = cookies # На данном этапе полностью получены все слоты turn.suggests.extend(['Да', 'Нет']) elif from_text and to_text and not (when_text or near_text): turn.response_text = f'Когда поедем по маршруту {from_text} - {to_text}?' next_stage = 'expect_departure_time' turn.suggests.extend(['Завтра', 'Сегодня']) elif to_text and not from_text: turn.response_text = f'Откуда поедем до {inflect_case(to_text, "gent")}?' next_stage = 'expect_departure_place' turn.suggests.extend(['Москва', 'Петербург']) elif from_text and not to_text: turn.response_text = f'Куда поедем из {inflect_case(from_text, "gent")}?' next_stage = 'expect_destination_place' turn.suggests.extend(['Москва', 'Петербург']) else: response_text = f'Давайте попробуем заново. Откуда и куда вы хотите билет?' # Либо пользователь скажет фразу целиком, либо как минимум станцию отправления # Тут косяк с тем, что получается он говорит станцию назначения (косяк из-за грамматики) next_stage = 'expect_departure_place' # тут был None turn.suggests.extend(['Москва', 'Петербург']) # Если в ответе уже было сообщение (сообщение об ошибке), то текущий ответ просто добавляем # следующей строкой, иначе - заменяем if turn.response_text: turn.response_text += f'\n{response_text}' else: turn.response_text = response_text if next_stage: print(f"Next stage: {next_stage}") turn.stage = next_stage return turn
def greeting_handler(turn: RzdTurn): turn.response_text = 'Привет! Это навык РЖД. Здесь вы можете найти и заказать билеты на поиск.' \ 'Чтобы выйти из навыка, скажите "Хватит".' turn.suggests.append('Помощь')
def suburb_route(turn: RzdTurn, force=False): form = turn.forms.get('suburb_route') or turn.forms.get( 'suburb_route_rx') or turn.forms.get('suburb_ellipsis') # найди электрички от сколково до беговой turns to # {'suburb': 'электрички', 'from': 'беговой', 's9602218': 'сколково', 's9601666': 'беговой', 'to': 'сколково'}} sub = SuburbContext.from_dict(turn.user_object.get('suburb') or {}) suburb_stage = (turn.stage or '').startswith('suburb') if not form: if suburb_stage: turn.response_text = 'Я не поняла вас. Пожалуйста, попробуйте переформулировать.' return if not suburb_stage \ and not form.get('suburb') \ and ('intercity_route' in turn.forms or (turn.stage or '').startswith('expect') and 'slots_filling' in turn.forms) \ and not force: # we give higher priority to intercity_route if we are out of suburb-specific context return text2slots = defaultdict(set) for k, v in form.items(): if not isinstance(v, dict): # skip yandex intents text2slots[v].add(k) if 'suburb_route_rx' in turn.forms and 'suburb_route' not in turn.forms and 'suburb_ellipsis' not in turn.forms: ft, fn = extract_slot_with_code('from', form, text2slots) tt, tn = extract_slot_with_code('to', form, text2slots) else: # yandex fills these slots in a really weird way ft, fn = form.get('from'), None tt, tn = form.get('to'), None if ft or tt: # on new search, we don't want to keep bidirectionality sub.bidirectional = False center = None center_code = sub.from_code or sub.to_code or turn.last_yandex_code or 'c213' if center_code: c = turn.world.code2obj.get(center_code) if c and c.get('latitude'): center = c['latitude'], c['longitude'] # matching stations or cities from Yandex queries if ft and not fn: fn = (turn.world.match(ft, center=center) or [None])[0] logger.debug('matched {} to {} '.format( ft, fn and turn.world.code2obj[fn]['title'])) if tt and not tn: tn = (turn.world.match(tt, center=center) or [None])[0] logger.debug('matched {} to {} '.format( tt, tn and turn.world.code2obj[tn]['title'])) logger.debug(f'{ft} ({fn}) -> {tt} ({tn})') if fn: sub.from_text = ft sub.from_code = fn if tn: sub.to_text = tt sub.to_code = tn anchor = None if sub.from_code: anchor = turn.world.code2obj[sub.from_code] elif sub.to_code: anchor = turn.world.code2obj[sub.to_code] if anchor: now = local_now(lat=anchor['latitude'], lon=anchor['longitude']) else: now = datetime.now(tz=timezone('Europe/Moscow')) date = None if form.get('when'): date = convert_date_to_abs(form['when']) if not date and sub.date_txt: date = datetime.fromisoformat(sub.date_txt) if not date: date = now sub.date_txt = date.isoformat() logger.debug('now is {}, search date is {}'.format(now, date)) if sub.from_code and sub.to_code and sub.from_code == sub.to_code: turn.response_text = f'Кажется точки отправления и назначения совпадают: {sub.from_text}. Попробуйте ещё раз.' turn.user_object['suburb'] = sub.to_dict() turn.suggests.append('электрички от тушино до красногорска') return if sub.from_code and sub.to_code: if form.get('back'): logger.debug('turning the route backwards!') sub.from_code, sub.to_code = sub.to_code, sub.from_code sub.from_text, sub.to_text = sub.to_text, sub.from_text result = turn.rasp_api.suburban_trains_between( code_from=sub.from_code, code_to=sub.to_code, date=str(date)[:10], ) if not result: turn.response_text = f'Не удалось получить маршрут электричек от {sub.from_text} до {sub.to_text}.' \ f' Поискать междугородные поезда? ' turn.suggests.append('да') turn.stage = 'suggest_intercity_route_from_suburban' turn.user_object['suburb'] = sub.to_dict() return segments = result['segments'] search = result['search'] sub.from_norm = search['from']['title'] sub.to_norm = search['to']['title'] if segments and os.getenv('USE_CPPK_PRICES'): cost = get_cppk_cost(from_text=sub.from_text, to_text=sub.to_text, date=None, return_price=True) else: cost = None dur_text = None dur_minute = None durs = [r.get('duration') for r in segments if r.get('duration')] if durs: min_dur = int(min(durs) / 60) max_dur = int(max(durs) / 60) logger.debug(f'durations: min {min_dur} max {max_dur}') if max_dur / min_dur < 1.1: dur_text = f'{human_duration(max_dur)}' elif min_dur < 60 and max_dur < 60: dur_text = f'от {min_dur} до {human_duration(max_dur)}' else: dur_text = f'от {human_duration(min_dur)} до {human_duration(max_dur)}' dur_minute = min_dur if not cost: # approximate cost by duration cost = int(max(14.0, -10 + 2.25 * dur_minute)) turn.response_text = phrase_results( name_from=sub.from_norm, name_to=sub.to_norm, results=result, only_next=(str(date)[:10] == str(now)[:10]), from_meta=turn.world.code2obj.get(sub.from_code), date=date, now=now, dur_text=dur_text, ) if cost and segments: sub.cost = cost turn.response_text += f' Стоимость {with_number("рубль", cost)} в одну сторону. Желаете купить билет?' turn.stage = 'suburb_confirm_sell' turn.suggests.append('Да') turn.suggests.append('Туда и обратно') elif not segments: turn.response_text += ' Поискать междугородные поезда?' turn.suggests.append('да') turn.stage = 'suggest_intercity_route_from_suburban' else: turn.stage = 'suburb_no_price' turn.suggests.append('А обратно?') turn.suggests.append('А завтра?') elif not tn: turn.response_text = 'Куда вы хотите поехать' + (f' от станции {ft}' if ft else '') + '?' turn.stage = 'suburb_get_to' elif not fn: turn.response_text = 'Откуда вы хотите поехать' + (f' до станции {tt}' if tt else '') + '?' turn.stage = 'suburb_get_from' else: turn.response_text = 'Это какая-то невозможная ветка диалога' turn.user_object['suburb'] = sub.to_dict()
def expect_after_slots_filled(turn: RzdTurn): print("expect_after_slots_filled handler") print(f"intents: {turn.intents}") if 'yes' in turn.intents: # Дождались положительного ответа от пользователя после формирования полного запроса # Достаем результат trains = get_trains(turn) turn.user_object['trains'] = trains print("Trains received after API request") for train in trains: print(train) # Атрибуцируем тег времени для trains, time_tags = time_tag_attribution(trains) print(f"Trains with time tags:\n{trains}") print(trains) # Проверяем, если нет поездов if not trains: turn.response_text = f'К сожалению на выбранную дату нет поедов!' turn.user_object["when_text"] = None turn = check_slots_and_chose_state(turn) # Случай одного поезда elif len(trains) == 1: form_car_type = turn.forms.get('car_type', None) form_seat_type = turn.forms.get('seat_type', None) train_car_type = trains[0]['seat_type'] turn.user_object['car_type'] = train_car_type turn.stage = 'expect_seat_type' # if train_car_type in ['Сидячий', 'СВ', 'Люкс']: # turn.user_object['seat_type'] = 'нет' # else: # turn.stage = 'expect_seat_type' # Случай нескольких поездов else: n_trains = len(trains) when_text = turn.user_object.get("when_text", None) turn.response_text = f'Найдено {with_number("поезд", n_trains)} на {when_text}.\n' min_cost, max_cost = get_min_max_costs(trains) min_time, max_time = get_min_and_max_departure_time(trains) if min_cost == max_cost: turn.response_text += f'Все белеты стоимостью {min_cost} руб.\n' else: turn.response_text += f"Билеты стоимостью от {min_cost} до {max_cost} руб.\n" if min_time == max_time: turn.response_text += f"Все поезда уходят в одно время {min_time}.\n" else: turn.response_text += f"Поезда ходят с {min_time} до {max_time}.\n" tag_names = [TIME_MAPPING[tag] for tag in time_tags] suggestion_tag_names = [ SUGGESTION_TIME_MAPPING[tag] for tag in time_tags ] time_tags_str = ", ".join(tag_names) # Есть более одного выбора времени if len(time_tags) > 1: turn.response_text += f'\nЕсть поезда на {time_tags_str}. Когда желаете отправиться?' turn.stage = 'expect_departure_time_tag' turn.suggests.extend(suggestion_tag_names) else: # Проверяем, что тегов больше одног # Не даем выбрать время, потому что выбора нет extracted_prices = extract_min_max_prices_for_car_types(trains) prices_information_str = extracted_prices_to_information_str( extracted_prices) turn.response_text += f'\nКакое место хотите?\n\n{prices_information_str}' turn.stage = 'expect_all_train_data' turn.suggests.extend([ 'Верхнее место в плацкартном вагоне', 'Нижнее место в купе' ]) else: turn.response_text = f'К сожалению, я ничего не нашла. Давайте попробуем заново'