def no_conv_handler(self, infos_given: dict, message: str): response = "" if infos_given.get('intent') == 'annuler': self.current_conv = ConvAnnulation(self) return self.current_conv.response(infos_given, message) else: response = response + self.question_generator(message, infos_given) return response
def no_conv_handler(self, infos_given: dict, message: str): response = "" if infos_given.get('intent') == 'annuler': self.current_conv = ConvAnnulation(self) return self.current_conv.response(infos_given, message) if self.validation: return self.confirmation(message, infos_given) self.infos_given_to_infos(infos_given) if not check_for_relevant_infos(infos_given, self.relevant_keys): response = ConvSmallTalk(self, infos_given.get('intent')).response( infos_given, message) + "\n" response = response + self.response_generator() return response
class ConvArbre(AbstractConv): status_ongoing = "arbre" status_finished = None previous_question = None tree = None def __init__(self, handler, classe: str): self.status_conv = 0 self.set_from_config(classe) self.handler = handler self.status = self.status_ongoing self.current_conv = None def response(self, infos_in_message: dict, message: str): if not self.current_conv: response = self.no_conv_handler(infos_in_message, message) else: response = self.annulation_handler(infos_in_message, message) return response def annulation_handler( self, infos_in_message: dict, message: str): #facile pas d'autre convs que annulation response = self.current_conv.response(infos_in_message, message) if self.current_conv.status: return response else: return self.no_conv_handler(infos_in_message, message) def no_conv_handler(self, infos_given: dict, message: str): response = "" if infos_given.get('intent') == 'annuler': self.current_conv = ConvAnnulation(self) return self.current_conv.response(infos_given, message) else: response = response + self.question_generator(message, infos_given) return response def question_generator(self, message: str, infos_in_message: dict): if infos_in_message.get('intent') == 'oui' or infos_in_message.get( 'intent') == 'non': self.previous_question = self.tree.get(self.previous_question).get( infos_in_message.get('intent')) response = self.previous_question if self.previous_question in config.ending_questions.values(): response += '\n' + self.handler.question_generator() self.status = self.status_finished return response else: return self.previous_question def set_from_config(self, classe): if classe in config.possible_classes.keys(): self.tree = config.possible_classes[classe] self.previous_question = config.starting_question[classe]
def no_conv_handler(self, infos_in_message : dict, message : str): """ Méthode appelée si on a pas de conversations autre en cours, suivant l'etat courant genère la réponse appropriée. """ if infos_in_message.get('intent')=='annuler': self.current_conv = ConvAnnulation(self) response = self.current_conv.response(infos_in_message, message) return response if self.info_asked == 'train': self.info_asked = 'aller' possible_status = { 'info_gathering' : self.create_conv_and_answer, 'yes_no_question_asked' : self.yes_no_answer, 'confirmation_asked' : self.confirmation_answer, 'modify_travelers' : self.modify_travelers } if self.status_conv in possible_status.keys() : response = possible_status.get(self.status_conv)(infos_in_message, message) return response
class ConvVoyage(AbstractConv): """ Conversation pour gérer le voyage, plusieurs états possibles : - info_gathering : On manque d'infos sur le voyage donc on crée une conv train ou hotel - yes_no_question_asked : On vient de poser une question oui/non on appel donc yes_no_answer() - confirmation_asked : On a toute les infos on vient d'afficher le récap on attend appel conv_recap() - modify_travelers : Etat dans lequel on se place quand l'utilisateur demande a modifier un voyageur, on appel question_for_modify_travelers() """ status_ongoing = "voyage" status_finished = None current_conv = None hotel_asked = False sentences = None infos_needed = None def __init__(self, handler, classe : str): self.user = None self.traveler = None #ca va etre le voyageur self.set_from_config(classe) self.travelers = [] self.info_asked = classe self.voyage = {} self.complement = {} self.error = False self.status = self.status_ongoing self.handler = handler self.status_conv = 'info_gathering' def response(self, infos_in_message : dict, message : str): if self.current_conv and self.current_conv.status: response = self.current_conv.response(infos_in_message, message) else : response = self.no_conv_handler(infos_in_message, message) return response def no_conv_handler(self, infos_in_message : dict, message : str): """ Méthode appelée si on a pas de conversations autre en cours, suivant l'etat courant genère la réponse appropriée. """ if infos_in_message.get('intent')=='annuler': self.current_conv = ConvAnnulation(self) response = self.current_conv.response(infos_in_message, message) return response if self.info_asked == 'train': self.info_asked = 'aller' possible_status = { 'info_gathering' : self.create_conv_and_answer, 'yes_no_question_asked' : self.yes_no_answer, 'confirmation_asked' : self.confirmation_answer, 'modify_travelers' : self.modify_travelers } if self.status_conv in possible_status.keys() : response = possible_status.get(self.status_conv)(infos_in_message, message) return response def create_conv_and_answer(self, infos_in_message : dict, message : str): """ Permt de créer la conversation souhaitée (train ou hotel) ou degénérer la reponse appropriée """ possible_info_asked = { 'aller' : ConvTrain, 'retour' : ConvTrain, 'hotel' : ConvHotel, 'voyageur' : ConvNameInfo, 'voyageur_add' : ConvNameInfo, } if self.info_asked in possible_info_asked.keys(): self.current_conv = possible_info_asked[self.info_asked](self, '') response = self.current_conv.response(infos_in_message, message) elif self.info_asked == 'voyageurs' : self.status_conv = 'modify_travelers' response = self.question_for_modifying_traveler() elif self.info_asked == 'motif' : self.complement['motif'] = message if check_string(self.complement['motif']): if 'motif' in self.infos_needed : self.infos_needed.remove('motif') self.info_asked = None else : self.status_conv = 'info_gathering' response = self.question_generator() elif self.info_asked == 'commentaires' : if 'commentaires' in self.infos_needed : self.infos_needed.remove('commentaires') self.complement['commentaires'] = message self.info_asked = None response = self.question_generator() else : response = self.question_generator() return response def question_generator(self): """ Permet de poser la question correspondant aux infos manquante pour le voyage """ self.status_conv = 'yes_no_question_asked' questions = config.questions if not self.voyage.get('voyageurs') and 'voyageur_add' not in self.infos_needed: self.infos_needed.append('voyageur_add') if self.infos_needed: if self.is_hotel_needed() and 'hotel' not in self.infos_needed and 'hotel' not in self.voyage: self.infos_needed.insert(1, 'hotel') self.hotel_asked = True key = self.infos_needed[0] self.info_asked = key return questions[key] else : self.status_conv = 'confirmation_asked' return self.conv_recap() def conv_recap(self): """ Récapitulatif du voyage et check de cohérence """ response = "Récapitulatif de votre voyage : \n\n" response += string_recap(self.voyage) + '\n' items = self.voyage.keys() response += string_recap(self.complement) + '\n' itemsComplement = self.complement.keys() errors = check_coherent_voyage(self.voyage) if errors: response += errors[0] response += "\nVeuillez corriger vos informations : entrez le nom de l'item à modifier parmi (" response += string_list(items) + ", " + string_list(itemsComplement) + ")" self.error = True return response self.validation = True if 'hotel' in self.voyage.keys(): response += "Pour votre réservation, nous allons sélectionner un hotel parmi nos hotels partenaires. \n \n " response = response + "Si cela vous convient, entrez 'oui'\n" \ + "Sinon entrez le nom de l'item à modifer (" + string_list(items) + ", " + string_list(itemsComplement) + ")" return response def confirmation_answer(self, infos_in_message : dict, message : str): if infos_in_message.get('intent') == 'oui' and not self.error: return self.confirm_voyage() elif message.strip().lower() in self.voyage.keys() : self.info_asked = message.strip().lower() self.status_conv = 'info_gathering' self.error = False return self.create_conv_and_answer(infos_in_message, message) elif message.strip().lower() in self.complement.keys() : self.status_conv = 'info_gathering' self.info_asked = None self.infos_needed.append(message) self.error = False return self.create_conv_and_answer(infos_in_message, message) elif message == 'bololololo': return self.question_generator() else: return ConvSmallTalk(self, infos_in_message.get('intent')).response(infos_in_message, message) \ + '\n' +self.question_generator() def yes_no_answer(self, infos_in_message: dict, message: str): if infos_in_message.get('intent') == 'oui' or self.info_asked in ["motif", "commentaires"]: if self.info_asked == 'voyageur_solo': if 'voyageur' in self.infos_needed: self.infos_needed.remove('voyageur') if 'voyageur_add' in self.infos_needed: self.infos_needed.remove('voyageur_add') self.add_infos(self.handler.user) return self.create_conv_and_answer(infos_in_message, message) elif infos_in_message.get('intent') == 'non': if self.info_asked == 'voyageur': self.add_infos(self.handler.user) if self.info_asked in self.infos_needed: self.infos_needed.remove(self.info_asked) return self.question_generator() elif message == 'bololololo': return self.question_generator() else: return ConvSmallTalk(self, infos_in_message.get('intent')).response(infos_in_message, message) \ + '\n' + self.question_generator() """ Suivent toutes les fontcions d'aide pour cette conversation """ def modify_travelers(self, infos_in_message : dict, message : str): if message.isdigit() and int(message) <= len(self.voyage.get('voyageurs')) and int(message) > 0 : choice = int(message) self.voyage.get('voyageurs').remove(self.voyage.get('voyageurs')[choice - 1]) return self.question_for_modifying_traveler() elif message.lower().strip() == 'ajouter': self.info_asked = 'voyageur_add' self.infos_needed.append('voyageur_add') return self.create_conv_and_answer(infos_in_message, message) else : return self.question_generator() def question_for_modifying_traveler(self): if 'voyageurs' in self.voyage.keys(): i = 0 response = 'Pour enlever un voyageur entrez son numéro : \n' for traveler in self.voyage['voyageurs']: i += 1 response+= str(i) + ' : ' + traveler['prenom'] + ' ' + traveler['nom'] + ' (' +traveler['mail']+')' +'\n' response += "Pour ajouter d'autres voyageurs entrez 'ajouter', sinon entrez 'fin'" return response else : '' def add_infos(self, infos : dict): if self.info_asked == 'voyageur' or self.info_asked == 'voyageur_add' or self.info_asked == 'voyageur_solo': self.travelers.append(infos) self.voyage['voyageurs'] = self.travelers else : self.voyage[self.info_asked] = infos if self.info_asked in self.infos_needed and self.info_asked != 'voyageur_add': self.infos_needed.remove(self.info_asked) def confirm_voyage(self): if 'hotel' in self.voyage.keys() or 'aller' in self.voyage.keys() or 'retour' in self.voyage.keys(): response = 'Mail récapitulatif envoyé !' else : response = 'Réservation vide - Pas de mail envoyé' self.send_infos() self.status = None return response def is_hotel_needed(self): hotel_is_needed = False if self.hotel_asked : return False if self.voyage.get('aller'): if self.voyage.get('aller').get('arrivée') == 'Paris': hotel_is_needed = True if self.voyage.get('retour'): if self.voyage.get('retour').get('départ') == 'Paris': hotel_is_needed = True return hotel_is_needed def send_infos(self): f = FicheVoyage(self.handler.user) f.add_voyage(self.voyage, self.complement) if 'hotel' in self.voyage.keys() or 'aller' in self.voyage.keys() or 'retour' in self.voyage.keys(): print("Création des fiches voyage...") f.createFiche_Train() f.createFiche_Hotel() print("Fiches créées.") print("Envoi des fiches par mail...") f.sendFiche(self.voyage) print("Mails envoyés.") else : print("Réservation vide - Pas de mail envoyé") def set_from_config(self, classe): self.infos_needed = config.infos_needed
class ConvHotel(AbstractConv): ''' Classe pour gérer tous les aspects de la conversation liée à la réservation d'hôtel. Très similaire à la conversation de train ''' #status_conv : int #infos : {} status_ongoing = None status_finished = None ville = None relevant_keys = None current_conv = None infos_needed = None sentences = None def __init__(self, handler, classe): self.set_from_config(classe) self.status = self.status_ongoing self.info_asked = None self.validation = False self.handler = handler self.infos = {} self.add_infos_from_handler() def response(self, infos_in_message: dict, message: str): if not self.current_conv: response = self.no_conv_handler(infos_in_message, message) else: response = self.annulation_handler(infos_in_message, message) return response def annulation_handler( self, infos_in_message: dict, message: str): #facile pas d'autre convs que annulation response = self.current_conv.response(infos_in_message, message) if self.current_conv.status: return response else: return self.no_conv_handler(infos_in_message, message) def confirmation(self, message: str, infos_in_message: dict): #À revoir if message in config.dict_hotel.keys(): desired_hotel = config.dict_hotel[message] self.infos['hotel_wanted'] = desired_hotel self.status = self.status_finished self.handler.add_infos(self.infos) return self.handler.question_generator() if infos_in_message.get('intent') == 'oui': self.status = self.status_finished self.handler.add_infos(self.infos) return self.handler.question_generator() else: self.validation = False return self.no_conv_handler(infos_in_message, message) def add_date_arrival_or_departure(self, arrival_or_departure: str, datetime: dict): date = datetime.get('jour') self.infos[arrival_or_departure] = date if arrival_or_departure in self.infos_needed: self.infos_needed.remove(arrival_or_departure) if 'date_arrivee' and "date_depart" in self.infos.keys(): self.infos['nights'] = str( hotel_number_nights(self.infos.get('date_arrivee'), self.infos.get('date_depart'))) def add_city(self, city: str): self.infos['ville'] = city if 'ville' in self.infos_needed: self.infos_needed.remove('ville') def question_generator(self): response = '' questions = config.questions if self.infos_needed: for key in self.infos_needed: self.info_asked = key return questions[key] else: errors = check_coherent_hotel(self.infos) if errors: return errors[0] + '\n Veuillez corriger vos informations.' self.validation = True for key in config.dict_hotel.keys(): response += key + ' : ' + config.dict_hotel[key] + '\n' return response + self.sentences["favorite_hotel"] def response_generator(self): response = "Vous voulez un hôtel" if "date_arrivee" in self.infos.keys(): response += " du " + self.infos.get('date_arrivee') if "date_depart" in self.infos.keys(): response += " au " + self.infos.get('date_depart') if 'nights' in self.infos.keys(): response += '\n ce qui correspond à ' + self.infos.get( 'nights') + ' nuit(s)' if "ville" in self.infos.keys(): if self.infos.get( 'ville') != 'Paris' and 'ville' not in self.infos_needed: response = self.sentences['out_of_paris_hotel'] return response else: response += ' à ' + self.infos.get('ville') return response + '\n' + self.question_generator() def infos_given_to_infos(self, infos_given: dict): type_of_infos_given = infos_given.keys() for key in type_of_infos_given: if key in self.ville: self.add_city(infos_given.get(key)) if key == 'villes_inconnues': cities = infos_given.get('villes_inconnues') self.set_infos_for_unknown_cities(cities) elif key == "date_depart" or key == "date_arrivee": self.add_date_arrival_or_departure(key, infos_given.get(key)) elif key == "dates_inconnues": datetimes = infos_given.get('dates_inconnues') self.set_info_for_unknown_dates(datetimes) def set_infos_for_unknown_cities(self, unknown_cities: []): if len(unknown_cities) == 1: city = unknown_cities[0] self.add_city(city) def set_info_for_unknown_dates(self, unknown_dates: []): if len(unknown_dates) == 1: datetime = unknown_dates[0] if self.info_asked: # cas ou on a demandé un truc a l'interlocuteur self.add_date_arrival_or_departure(self.info_asked, datetime) else: # on suppose que si le bot recoit une date sans qu'on lui ait rien avoir demandé c'est la date d'arrivée if 'date_arrivee' in self.infos_needed: self.add_date_arrival_or_departure('date_arrivee', datetime) elif 'date_depart' in self.infos_needed: self.add_date_arrival_or_departure('date_depart', datetime) def no_conv_handler(self, infos_given: dict, message: str): response = "" if infos_given.get('intent') == 'annuler': self.current_conv = ConvAnnulation(self) return self.current_conv.response(infos_given, message) if self.validation: return self.confirmation(message, infos_given) self.infos_given_to_infos(infos_given) if not check_for_relevant_infos(infos_given, self.relevant_keys): response = ConvSmallTalk(self, infos_given.get('intent')).response( infos_given, message) + "\n" response = response + self.response_generator() return response def small_talk(self, infos_in_message: dict, message): """ Fonction qui permet d'inclure le small talk dans une conversation de réservation d'hôtel. """ response = ConvSmallTalk(self, infos_in_message.get('intent')).response( infos_in_message, message) return response def set_to_state(self, infos: dict): self.infos = infos for key in infos.keys(): if key in self.infos_needed: self.infos_needed.remove(key) def add_infos_from_handler(self): voyage = self.handler.voyage infos = {'ville': 'Paris'} if voyage.get('retour'): infos['date_depart'] = voyage.get('retour').get('jour') if voyage.get('aller'): infos['date_arrivee'] = voyage.get('aller').get('jour') if voyage.get('hotel'): infos = voyage.get('hotel') self.infos = infos self.set_to_state(infos) def set_from_config(self, classe: str): self.ville = config.ville self.relevant_keys = config.relevant_keys self.infos_needed = config.infos_needed self.status_ongoing = config.status_ongoing self.sentences = config.sentences
class ConvTrain(AbstractConv): ''' Classe pour gérer tous les aspects de la conversation liée à la réservation de train. ''' status_ongoing = "train" status_finished = None current_conv = None relevant_keys = [ "départ", 'arrivée', 'date_arrivee', 'date_depart', 'villes_inconnues', 'dates_inconnues' ] trains_wanted = None request = None sentences = None def __init__(self, handler, classe): self.status = self.status_ongoing self.annulation = False self.proposals = None self.infos_needed = ["départ", "arrivée", "jour", "heure"] self.set_from_config(classe) self.info_asked = None self.validation = False self.infos = {} self.handler = handler self.add_infos_from_handler() def response(self, infos_in_message: dict, message: str): if not self.current_conv: return self.no_conv_handler(infos_in_message, message) else: return self.annulation_handler(infos_in_message, message) def annulation_handler(self, infos_in_message: dict, message: str): response = self.current_conv.response(infos_in_message, message) if self.current_conv.status: return response else: return self.no_conv_handler(infos_in_message, message) def confirmation(self, message: str, infos_in_message: dict): """ Traite la réponse lorsqu'on est à l'étape de confirmation. """ if self.proposals: if message.isdigit() and int(message) <= len( self.proposals) and int(message) > 0: choice = int(message) train_chosen = self.proposals[choice - 1] self.infos['jour'] = train_chosen['departure_date'] self.infos['heure'] = train_chosen['departure_time'] self.status = self.status_finished self.handler.add_infos(self.infos) response = self.message_meteo( ) + self.handler.question_generator() return response else: self.validation = False return self.no_conv_handler(infos_in_message, message) else: if infos_in_message.get('intent') == 'oui': self.status = self.status_finished self.handler.add_infos(self.infos) response = self.message_meteo( ) + self.handler.question_generator() return response else: self.validation = False return self.no_conv_handler(infos_in_message, message) def add_location(self, arrival_or_departure: str, city: str): self.infos[arrival_or_departure] = city if arrival_or_departure in self.infos_needed: self.infos_needed.remove(arrival_or_departure) def message_meteo(self): meteo = api_meteo.get_weather_for_city_and_date( self.infos.get('arrivée'), self.infos.get('jour')) if meteo: response = "Météo à votre arrivée : \n" response += '- État du ciel : ' + meteo.get('text_meteo') + '\n' response += '- Température : ' + meteo.get( 'max_temp') + '°C' + '\n' response += '- Probabilité de pluie : ' + meteo.get( 'chance_of_rain') + '\n' else: response = '' return response def add_jour(self, jour: str): self.infos['jour'] = jour if 'jour' in self.infos_needed: self.infos_needed.remove('jour') def add_heure(self, heure: str): self.infos['heure'] = heure if 'heure' in self.infos_needed: self.infos_needed.remove('heure') def question_generator(self): if self.infos_needed: self.info_asked = self.infos_needed[0] return self.sentences[self.info_asked] else: errors = check_coherent_train(self.infos, self.handler.voyage) if errors: return errors[0] + '\nVeuillez corriger vos informations.' self.validation = True res = self.fetch_data_trains(self.infos) if self.proposals: return res + self.sentences['ask_train_number'] else: res += self.sentences['no_train_available'] return res def response_generator(self): response = "Vous voulez un train" if "départ" in self.infos.keys(): response += " de " + self.infos.get('départ') if "arrivée" in self.infos.keys(): response += " pour " + self.infos.get('arrivée') if "jour" in self.infos.keys(): response += ' le ' + self.infos.get('jour') if "heure" in self.infos.keys(): response += ' à ' + self.infos.get('heure') return response + '\n' + self.question_generator() def fetch_data_trains(self, infos): departure_or_arrival = 'departure' self.request = api_sncf.set_request(infos.get('départ'), infos.get('arrivée'), infos.get('jour'), infos.get('heure'), 'departure') data = api_sncf.get_possible_trips_from_request( self.request, departure_or_arrival) self.proposals = data return proposition_trains(data) def infos_given_to_infos(self, infos_given: dict): type_of_infos_given = infos_given.keys() for key in type_of_infos_given: if key == 'date_départ' or key == 'date_arrivée': self.add_date_time(infos_given.get(key)) if key == 'dates_inconnues': self.set_info_for_unknown_dates(infos_given.get(key)) elif key == "départ" or key == "arrivée": self.add_location(key, infos_given.get(key)) elif key == "villes_inconnues": cities = infos_given.get('villes_inconnues') self.set_info_for_unknown_cities(cities) def set_info_for_unknown_dates(self, unknwown_dates: []): if len(unknwown_dates) == 1: date = unknwown_dates[0] self.add_date_time(date) def set_info_for_unknown_cities(self, unknown_cities: []): if len(unknown_cities) == 1: city = unknown_cities[0] if self.info_asked: # cas ou on a demandé un truc a l'interlocuteur self.add_location(self.info_asked, city) else: # on suppose que si le bot recoit une ville sans qu'on lui ait rien avoir demandé c'est la ville d'arrivée if 'arrivée' in self.infos_needed: self.add_location('arrivée', city) elif 'départ' in self.infos_needed: self.add_location('départ', city) def no_conv_handler(self, infos_given: dict, message: str): response = '' if infos_given.get('intent') == 'annuler': self.current_conv = ConvAnnulation(self) return self.current_conv.response(infos_given, message) if self.validation: return self.confirmation(message, infos_given) self.infos_given_to_infos(infos_given) if not check_for_relevant_infos(infos_given, self.relevant_keys): response = ConvSmallTalk(self, infos_given.get('intent')).response( infos_given, message) + '\n' response += self.response_generator() return response def set_to_state(self, infos: dict): for key in infos.keys(): if key in self.infos_needed: self.infos_needed.remove(key) def add_infos_from_handler(self): """ Permet de récupérer les infos du voyages qui ont déjà été entrées pour ne pas le redemander """ voyage = self.handler.voyage infos = {} if self.handler.info_asked == 'aller': if voyage.get('retour'): infos['départ'] = voyage.get('retour').get('arrivée') infos['arrivée'] = voyage.get('retour').get('départ') if voyage.get('hotel'): infos['arrivée'] = voyage.get('hotel').get('ville') infos['jour'] = voyage.get('hotel').get('date_arrivee') if voyage.get('aller'): infos = voyage.get('aller') if self.handler.info_asked == 'retour': if voyage.get('aller'): infos['départ'] = voyage.get('aller').get('arrivée') infos['arrivée'] = voyage.get('aller').get('départ') if voyage.get('hotel'): infos['départ'] = voyage.get('hotel').get('date_arrivee') infos['jour'] = voyage.get('hotel').get('date_depart') if voyage.get('retour'): infos = voyage.get('retour') self.infos = infos self.set_to_state(infos) def add_date_time(self, date: dict): for key in date.keys(): if key == "jour": self.add_jour(date.get(key)) elif key == "heure": self.add_heure(date.get(key)) def set_from_config(self, classe): self.sentences = config.sentences_train