def test_get_conversation_multi_client(self):
        config = BotConversationsConfiguration()
        mgr = ConversationManager(config)

        if os.path.exists("./storage/conversations"):
            shutil.rmtree("./storage/conversations")

        client = TestClient()
        client.add_conversation_store("./storage/conversations")

        mgr.initialise(client.storage_factory)
        mgr.configuration._multi_client = True

        client_context = client.create_client_context("user1")

        conversation = mgr.get_conversation(client_context)

        question1 = Question.create_from_text(client_context, "Hello There")
        question1.sentence(0).response = "Hi"
        conversation.record_dialog(question1)
        mgr.save_conversation(client_context)

        conversation = mgr.get_conversation(client_context)
        self.assertEqual(len(mgr.conversations), 1)

        if os.path.exists("./storage/conversations"):
            shutil.rmtree("./storage/conversations")
예제 #2
0
    def test_conversation_operations_multi_client_no_storage(self):
        config = BotConversationsConfiguration()
        config._multi_client = True
        mgr = ConversationManager(config)

        convo_dir = self.get_temp_dir() + os.sep + "storage" + os.sep + "conversations"

        if os.path.exists(convo_dir):
            shutil.rmtree(convo_dir)

        client = TestClient()
        #client.add_conversation_store(convo_dir)

        mgr.initialise(client.storage_factory)

        client_context = client.create_client_context("user1")

        conversation = mgr.get_conversation(client_context)

        question1 = Question.create_from_text(client_context, "Hello There")
        question1.sentence(0).response = "Hi"
        conversation.record_dialog(question1)
        mgr.save_conversation(client_context)

        question2 = Question.create_from_text(client_context, "Hello There Again")
        question2.sentence(0).response = "Hi Again"
        conversation.record_dialog(question2)
        mgr.save_conversation(client_context)

        question3 = Question.create_from_text(client_context, "Hello There Again Again")
        question3.sentence(0).response = "Hi Again Again"
        conversation.record_dialog(question3)
        mgr.save_conversation(client_context)

        conversation2 = mgr.get_conversation(client_context)
        self.assertIsNotNone(conversation2)

        self.assertEqual(len(mgr.conversations), 1)
        mgr.empty()
        self.assertEqual(len(mgr.conversations), 0)

        conversation = mgr.get_conversation(client_context)
        self.assertEqual(len(mgr.conversations), 1)

        if os.path.exists(convo_dir):
            shutil.rmtree(convo_dir)

        self.assertIsNotNone(conversation)
        self.assertEqual(len(conversation.questions), 0)
예제 #3
0
    def test_conversation_operations_no_conversation(self):
        config = BotConversationsConfiguration()
        mgr = ConversationManager(config)

        convo_dir = self.get_temp_dir() + os.sep + "storage" + os.sep + "conversations"

        if os.path.exists(convo_dir):
            shutil.rmtree(convo_dir)

        client = TestClient()
        client.add_conversation_store(convo_dir)

        mgr.initialise(client.storage_factory)

        client_context = client.create_client_context("user1")

        conversation = mgr.get_conversation(client_context)

        question1 = Question.create_from_text(client_context, "Hello There")
        question1.sentence(0).response = "Hi"
        conversation.record_dialog(question1)

        del mgr._conversations[client_context.userid]

        mgr.save_conversation(client_context)
    def test_remove_conversation_invalid_userid(self):
        config = BotConversationsConfiguration()
        mgr = ConversationManager(config)

        if os.path.exists("./storage/conversations"):
            shutil.rmtree("./storage/conversations")

        client = TestClient()
        client.add_conversation_store("./storage/conversations")

        mgr.initialise(client.storage_factory)

        client_context = client.create_client_context("user1")
        self.assertEqual(len(mgr.conversations), 0)
        conversation = mgr.get_conversation(client_context)

        question1 = Question.create_from_text(client_context, "Hello There")
        question1.sentence(0).response = "Hi"
        conversation.record_dialog(question1)
        mgr.save_conversation(client_context)
        self.assertTrue(
            os.path.exists("./storage/conversations/testclient_user1.conv"))

        client_context._userid = "user2"
        mgr.remove_conversation(client_context)
        self.assertTrue(
            os.path.exists("./storage/conversations/testclient_user1.conv"))
        self.assertFalse(
            os.path.exists("./storage/conversations/testclient_user2.conv"))

        if os.path.exists("./storage/conversations"):
            shutil.rmtree("./storage/conversations")
    def test_conversation_operations(self):
        config = BotConversationsConfiguration()
        mgr = ConversationManager(config)

        if os.path.exists("./storage/conversations"):
            shutil.rmtree("./storage/conversations")

        client = TestClient()
        client.add_conversation_store("./storage/conversations")

        mgr.initialise(client.storage_factory)

        client_context = client.create_client_context("user1")

        conversation = mgr.get_conversation(client_context)

        question1 = Question.create_from_text(client_context, "Hello There")
        question1.sentence(0).response = "Hi"
        conversation.record_dialog(question1)
        mgr.save_conversation(client_context)

        question2 = Question.create_from_text(client_context,
                                              "Hello There Again")
        question2.sentence(0).response = "Hi Again"
        conversation.record_dialog(question2)
        mgr.save_conversation(client_context)

        question3 = Question.create_from_text(client_context,
                                              "Hello There Again Again")
        question3.sentence(0).response = "Hi Again Again"
        conversation.record_dialog(question3)
        mgr.save_conversation(client_context)
        self.assertTrue(
            os.path.exists("./storage/conversations/testclient_user1.conv"))

        self.assertEqual(len(mgr.conversations), 1)
        mgr.empty()
        self.assertEqual(len(mgr.conversations), 0)

        conversation = mgr.get_conversation(client_context)
        self.assertEqual(len(mgr.conversations), 1)

        self.assertIsNotNone(conversation)
        self.assertEqual(len(conversation.questions), 3)

        if os.path.exists("./storage/conversations"):
            shutil.rmtree("./storage/conversations")
    def test_save_conversation_no_userid_data(self):
        config = BotConversationsConfiguration()
        mgr = ConversationManager(config)

        if os.path.exists("./storage/conversations"):
            shutil.rmtree("./storage/conversations")

        client = TestClient()
        client.add_conversation_store("./storage/conversations")

        mgr.initialise(client.storage_factory)

        client_context = client.create_client_context("user1")
        mgr.get_conversation(client_context)
        self.assertEqual(len(mgr.conversations), 1)

        mgr.save_conversation(client_context)
        self.assertFalse(
            os.path.exists("./storage/conversations/testclient_user1.conv"))
예제 #7
0
class Bot(object):
    def __init__(self, config, client):

        assert (config is not None)
        assert (client is not None)

        self._configuration = config
        self._client = client

        self._brain_factory = BrainFactory(self)

        self._question_depth = 0
        self._question_start_time = None

        self._spell_checker = None
        self.initiate_spellchecker()

        self._sentence_splitter = None
        self.initiate_sentence_splitter()

        self._sentence_joiner = None
        self.initiate_sentence_joiner()

        self._from_translator = None
        self._to_translator = None
        self.initiate_translator()

        self._sentiment_analyser = None
        self._sentiment_scores = None
        self.initiate_sentiment_analyser()

        self._conversation_mgr = ConversationManager(config.conversations)
        self._conversation_mgr.initialise(self._client.storage_factory)

    def ylogger_type(self):
        return "bot"

    @property
    def id(self):
        return self._configuration.section_name

    @property
    def client(self):
        return self._client

    @property
    def configuration(self):
        return self._configuration

    @property
    def brain_factory(self):
        return self._brain_factory

    @property
    def spell_checker(self):
        return self._spell_checker

    def initiate_spellchecker(self):
        if self.configuration is not None:
            if self.configuration.spelling is not None:
                self._spell_checker = SpellingChecker.initiate_spellchecker(
                    self.configuration.spelling, self.client.storage_factory)

    @property
    def sentence_splitter(self):
        return self._sentence_splitter

    def initiate_sentence_splitter(self):
        if self.configuration is not None:
            if self.configuration.splitter is not None:
                self._sentence_splitter = SentenceSplitter.initiate_sentence_splitter(
                    self.configuration.splitter)

    @property
    def sentence_joiner(self):
        return self._sentence_joiner

    def initiate_sentence_joiner(self):
        if self.configuration is not None:
            if self.configuration.joiner is not None:
                self._sentence_joiner = SentenceJoiner.initiate_sentence_joiner(
                    self.configuration.joiner)

    @property
    def from_translator(self):
        return self._from_translator

    @property
    def to_translator(self):
        return self._to_translator

    def initiate_translator(self):
        if self.configuration is not None:

            if self.configuration.from_translator is not None:
                self._from_translator = BaseTranslator.initiate_translator(
                    self.configuration.from_translator)

            if self.configuration.to_translator is not None:
                self._to_translator = BaseTranslator.initiate_translator(
                    self.configuration.to_translator)

    @property
    def sentiment_analyser(self):
        return self._sentiment_analyser

    @property
    def sentiment_scores(self):
        return self._sentiment_scores

    def initiate_sentiment_analyser(self):
        if self.configuration is not None:
            if self.configuration.sentiment_analyser is not None:
                self._sentiment_analyser, self._sentiment_scores = BaseSentimentAnalyser.initiate_sentiment_analyser(
                    self.configuration.sentiment_analyser)

    @property
    def brain(self):
        return self._brain_factory.select_brain()

    @property
    def conversations(self):
        return self._conversation_mgr

    @property
    def default_response(self):
        if self.configuration is not None:
            return self.configuration.default_response
        return BotConfiguration.DEFAULT_RESPONSE

    @property
    def default_response_srai(self):
        if self.configuration is not None:
            return self.configuration.default_response_srai
        return None

    @property
    def exit_response(self):
        if self.configuration is not None:
            return self.configuration.exit_response
        return BotConfiguration.DEFAULT_EXIT_RESPONSE

    @property
    def exit_response_srai(self):
        if self.configuration is not None:
            return self.configuration.exit_response_srai
        return BotConfiguration.DEFAULT_EXIT_RESPONSE_SRAI

    @property
    def initial_question(self):
        if self.configuration is not None:
            return self.configuration.initial_question
        return BotConfiguration.DEFAULT_INITIAL_QUESTION

    @property
    def initial_question_srai(self):
        if self.configuration is not None:
            return self.configuration.initial_question_srai
        return BotConfiguration.DEFAULT_INITIAL_QUESTION_SRAI

    @property
    def override_properties(self):
        if self.configuration is not None:
            return self.configuration.override_properties
        return False

    def get_version_string(self, client_context):

        assert (client_context is not None)

        if client_context.brain.properties.has_property("version"):
            # The old version of returning the version string, did not distinquish
            # between App and Grammar version
            return "%s, v%s, initiated %s" % (
                client_context.brain.properties.property("name"),
                client_context.brain.properties.property("version"),
                client_context.brain.properties.property("birthdate"))
        else:
            # This version now does
            return "%s, App: v%s Grammar v%s, initiated %s" % (
                client_context.brain.properties.property("name"),
                client_context.brain.properties.property("app_version"),
                client_context.brain.properties.property("grammar_version"),
                client_context.brain.properties.property("birthdate"))

    def has_conversation(self, client_context):

        assert (self._conversation_mgr is not None)

        return self._conversation_mgr.has_conversation(client_context)

    def get_conversation(self, client_context):

        assert (self._conversation_mgr is not None)

        return self._conversation_mgr.get_conversation(client_context)

    def save_conversation(self, client_context):

        assert (self._conversation_mgr is not None)

        self._conversation_mgr.save_conversation(client_context)

    def check_spelling_before(self, client_context, each_sentence):
        if self.spell_checker is not None:
            self.spell_checker.check_spelling_before(client_context,
                                                     each_sentence)

    def check_spelling_and_retry(self, client_context, each_sentence):
        if self.spell_checker is not None:
            return self.spell_checker.check_spelling_and_retry(
                client_context, each_sentence)
        return None

    def get_default_response(self, client_context):

        assert (client_context is not None)

        if self.default_response_srai is not None:
            sentence = Sentence(client_context.brain.tokenizer,
                                self.default_response_srai)
            default_response = client_context.brain.ask_question(
                client_context, sentence)
            if default_response is None or not default_response:
                default_response = self.default_response
            return default_response
        else:
            return self.default_response

    def get_initial_question(self, client_context):

        assert (client_context is not None)

        if self.initial_question_srai is not None:
            sentence = Sentence(client_context.brain.tokenizer,
                                self.initial_question_srai)
            initial_question = client_context.brain.ask_question(
                client_context, sentence)
            if initial_question is None or not initial_question:
                initial_question = self.initial_question
            return initial_question
        else:
            return self.initial_question

    def get_exit_response(self, client_context):

        assert (client_context is not None)

        if self.exit_response_srai is not None:
            sentence = Sentence(client_context.brain.tokenizer,
                                self.exit_response_srai)
            exit_response = client_context.brain.ask_question(
                client_context, sentence)
            if exit_response is None or not exit_response:
                exit_response = self.exit_response

            return exit_response

        else:
            return self.exit_response

    def pre_process_text(self, client_context, text, srai):

        assert (client_context is not None)
        assert (client_context.brain is not None)

        if srai is False:
            pre_processed = client_context.brain.pre_process_question(
                client_context, text)
            YLogger.debug(client_context, "Pre Processed (%s): %s",
                          client_context.userid, pre_processed)

        else:
            pre_processed = text

        if pre_processed is None or pre_processed == "":

            assert (self.configuration is not None)

            pre_processed = self.configuration.empty_string

        return pre_processed

    def get_question(self, client_context, pre_processed, srai):
        if srai is False:
            return Question.create_from_text(client_context,
                                             pre_processed,
                                             srai=srai)
        else:
            return Question.create_from_text(client_context,
                                             pre_processed,
                                             split=False,
                                             srai=srai)

    def combine_answers(self, answers, srai):

        assert (answers is not None)
        assert (self._sentence_joiner is not None)

        return self._sentence_joiner.combine_answers(answers, srai)

    def post_process_response(self, client_context, response, srai):
        if srai is False:

            assert (client_context is not None)

            answer = client_context.brain.post_process_response(
                client_context, response).strip()
            if not answer:
                answer = self.get_default_response(client_context)

        else:
            answer = response

        return answer

    def log_answer(self, client_context, text, answer, responselogger):
        YLogger.debug(client_context, "Processed Response (%s): %s",
                      client_context.userid, answer)

        if responselogger is not None:
            responselogger.log_response(text, answer)

    def ask_question(self,
                     client_context,
                     text,
                     srai=False,
                     responselogger=None):

        assert (client_context is not None)

        if srai is False:
            client_context.bot = self
            client_context.brain = client_context.bot.brain

        assert (client_context.bot is not None)
        assert (client_context.brain is not None)

        client_context.mark_question_start(text)

        pre_processed = self.pre_process_text(client_context, text, srai)

        question = self.get_question(client_context, pre_processed, srai)

        conversation = self.get_conversation(client_context)
        if len(conversation.questions) == 0:
            if self.client.trigger_manager is not None:
                self.client.trigger_manager.trigger(
                    SystemTriggers.CONVERSATION_START, client_context)

        assert (conversation is not None)

        conversation.record_dialog(question)

        answers = self.process_sentences(client_context, question, srai,
                                         responselogger)

        client_context.reset_question()

        if srai is True:
            conversation.pop_dialog()

        self.save_conversation(client_context)

        conversation.save_sentiment()

        if self.client.trigger_manager is not None and srai is False:
            self.client.trigger_manager.trigger(SystemTriggers.QUESTION_ASKED,
                                                client_context)

        return self.combine_answers(answers, srai)

    def process_sentences(self, client_context, question, srai,
                          responselogger):
        answers = []
        sentence_no = 0
        for sentence in question.sentences:
            question.set_current_sentence_no(sentence_no)
            answer = self.process_sentence(client_context, sentence, srai,
                                           responselogger)
            answers.append(answer)
            sentence_no += 1

        return answers

    def process_sentence(self, client_context, sentence, srai, responselogger):

        assert (client_context is not None)
        assert (client_context.brain is not None)

        client_context.check_max_recursion()
        client_context.check_max_timeout()

        if srai is False:
            self.check_spelling_before(client_context, sentence)

        response = client_context.brain.ask_question(client_context, sentence,
                                                     srai)

        if response is None and srai is False:
            response = self.check_spelling_and_retry(client_context, sentence)

        if response is not None:
            return self.handle_response(client_context, sentence, response,
                                        srai, responselogger)
        else:
            return self.handle_none_response(client_context, sentence,
                                             responselogger)

    def handle_response(self, client_context, sentence, response, srai,
                        responselogger):

        assert (sentence is not None)

        YLogger.debug(client_context, "Raw Response (%s): %s",
                      client_context.userid, response)
        sentence.response = response

        sentence.calculate_sentinment_score(client_context)

        answer = self.post_process_response(client_context, response, srai)
        self.log_answer(client_context, sentence.text, answer, responselogger)

        return answer

    def handle_none_response(self, client_context, sentence, responselogger):

        assert (sentence is not None)

        sentence.response = self.get_default_response(client_context)

        sentence.calculate_sentinment_score(client_context)

        if responselogger is not None:
            responselogger.log_unknown_response(sentence)

        return sentence.response
예제 #8
0
class Bot(object):
    def __init__(self, config, client):

        assert (config is not None)
        assert (client is not None)

        self._configuration = config
        self._client = client

        self._brain_factory = BrainFactory(self)

        self._question_depth = 0
        self._question_start_time = None

        self._spell_checker = None
        self.initiate_spellchecker()

        self._sentence_splitter = None
        self.initiate_sentence_splitter()

        self._sentence_joiner = None
        self.initiate_sentence_joiner()

        self._from_translator = None
        self._to_translator = None
        self.initiate_translator()

        self._sentiment_analyser = None
        self._sentiment_scores = None
        self.initiate_sentiment_analyser()

        self._conversation_mgr = ConversationManager(config.conversations)
        self._conversation_mgr.initialise(self._client.storage_factory)

        self._utterance = None

        self._is_error = False
        self._srai_count = 0

    def ylogger_type(self):
        return "bot"

    @property
    def id(self):
        return self._configuration.section_name

    @property
    def client(self):
        return self._client

    @property
    def configuration(self):
        return self._configuration

    @property
    def brain_factory(self):
        return self._brain_factory

    @property
    def spell_checker(self):
        return self._spell_checker

    def initiate_spellchecker(self):
        if self.configuration.spelling is not None:
            self._spell_checker = SpellingChecker.initiate_spellchecker(
                self.configuration.spelling, self.client.storage_factory)

    @property
    def sentence_splitter(self):
        return self._sentence_splitter

    def initiate_sentence_splitter(self):
        if self.configuration.splitter is not None:
            self._sentence_splitter = SentenceSplitter.initiate_sentence_splitter(
                self.configuration.splitter)
            if self._sentence_splitter is not None:
                if self.brain.properties.has_property(
                        "splitter_split_chars") is True:
                    self._sentence_splitter.set_configuration_split_chars(
                        self.brain.properties.property("splitter_split_chars"))
                if self.brain.properties.has_property(
                        "punctuation_chars") is True:
                    self._sentence_splitter.set_configuration_punctuation_chars(
                        self.brain.properties.property("punctuation_chars"))

    @property
    def sentence_joiner(self):
        return self._sentence_joiner

    def initiate_sentence_joiner(self):
        if self.configuration.joiner is not None:
            self._sentence_joiner = SentenceJoiner.initiate_sentence_joiner(
                self.configuration.joiner)
            if self._sentence_joiner is not None:
                if self.brain.properties.has_property(
                        "joiner_join_chars") is True:
                    self._sentence_joiner.set_configuration_join_chars(
                        self.brain.properties.property("joiner_join_chars"))
                if self.brain.properties.has_property(
                        "joiner_terminator") is True:
                    self._sentence_joiner.set_configuration_terminator(
                        self.brain.properties.property("joiner_terminator"))

    @property
    def from_translator(self):
        return self._from_translator

    @property
    def to_translator(self):
        return self._to_translator

    def initiate_translator(self):
        if self.configuration.from_translator is not None:
            self._from_translator = BaseTranslator.initiate_translator(
                self.configuration.from_translator)

        if self.configuration.to_translator is not None:
            self._to_translator = BaseTranslator.initiate_translator(
                self.configuration.to_translator)

    @property
    def sentiment_analyser(self):
        return self._sentiment_analyser

    @property
    def sentiment_scores(self):
        return self._sentiment_scores

    def initiate_sentiment_analyser(self):
        if self.configuration.sentiment_analyser is not None:
            self._sentiment_analyser, self._sentiment_scores = BaseSentimentAnalyser.initiate_sentiment_analyser(
                self.configuration.sentiment_analyser)

    @property
    def brain(self):
        return self._brain_factory.select_brain()

    @property
    def conversations(self):
        return self._conversation_mgr

    @property
    def default_response(self):
        return self.configuration.default_response

    @property
    def default_response_srai(self):
        return self.configuration.default_response_srai

    @property
    def exit_response(self):
        return self.configuration.exit_response

    @property
    def exit_response_srai(self):
        return self.configuration.exit_response_srai

    @property
    def exception_response(self):
        return self.configuration.exception_response

    @property
    def initial_question(self):
        return self.configuration.initial_question

    @property
    def initial_question_srai(self):
        return self.configuration.initial_question_srai

    @property
    def override_properties(self):
        return self.configuration.override_properties

    @property
    def utterance(self):
        return self._utterance

    def get_version_string(self, client_context):

        assert (client_context is not None)

        if client_context.brain.properties.has_property("version"):
            # The old version of returning the version string, did not distinquish
            # between App and Grammar version
            return "%s, v%s, initiated %s " % (
                client_context.brain.properties.property("name"),
                client_context.brain.properties.property("version"),
                client_context.brain.properties.property("birthdate"))
        else:
            # This version now does
            return "%s, App: v%s Grammar v%s, initiated %s " % (
                client_context.brain.properties.property("name"),
                client_context.brain.properties.property("app_version"),
                client_context.brain.properties.property("grammar_version"),
                client_context.brain.properties.property("birthdate"))

    def has_conversation(self, client_context):

        assert (self._conversation_mgr is not None)

        return self._conversation_mgr.has_conversation(client_context)

    def conversation(self, client_context):
        return self.get_conversation(client_context)

    def get_conversation(self, client_context):

        assert (self._conversation_mgr is not None)

        return self._conversation_mgr.get_conversation(client_context)

    def save_conversation(self, client_context):

        assert (self._conversation_mgr is not None)

        self._conversation_mgr.save_conversation(client_context)

    def check_spelling_before(self, client_context, each_sentence):
        if self.spell_checker is not None:
            self.spell_checker.check_spelling_before(client_context,
                                                     each_sentence)

    def check_spelling_and_retry(self, client_context, each_sentence):
        if self.spell_checker is not None:
            return self.spell_checker.check_spelling_and_retry(
                client_context, each_sentence)
        return None

    def get_default_response(self, client_context):

        assert (client_context is not None)

        if self.default_response_srai is not None and self.default_response_srai != '':
            sentence = Sentence(client_context.brain.tokenizer,
                                self.default_response_srai)
            default_response = client_context.brain.ask_question(
                client_context, sentence, default_srai=True)
            if default_response is None:
                default_response = client_context.brain.properties.property(
                    "default-response")
                if default_response is None:
                    default_response = self.default_response
            return default_response
        else:
            default_response = client_context.brain.properties.property(
                "default-response")
            if default_response is None:
                default_response = self.default_response
            return default_response

    def get_exception_response(self, client_context):

        assert (client_context is not None)

        exception_response = client_context.brain.properties.property(
            "exception-response")
        if exception_response is None:
            exception_response = self.exception_response
        return exception_response

    def get_initial_question(self, client_context):

        assert (client_context is not None)

        if self.initial_question_srai is not None:
            sentence = Sentence(client_context.brain.tokenizer,
                                self.initial_question_srai)
            initial_question = client_context.brain.ask_question(
                client_context, sentence)
            if initial_question is None or not initial_question:
                initial_question = self.initial_question
            return initial_question
        else:
            return self.initial_question

    def get_exit_response(self, client_context):

        assert (client_context is not None)

        if self.exit_response_srai is not None:
            sentence = Sentence(client_context.brain.tokenizer,
                                self.exit_response_srai)
            exit_response = client_context.brain.ask_question(
                client_context, sentence)
            if exit_response is None or not exit_response:
                exit_response = self.exit_response

            return exit_response

        else:
            return self.exit_response

    def pre_process_text(self, client_context, text, srai):

        assert (client_context is not None)
        assert (client_context.brain is not None)

        if srai is False:
            pre_processed = client_context.brain.pre_process_question(
                client_context, text)
            YLogger.debug(client_context, "Pre Processed (%s): %s",
                          client_context.userid, pre_processed)

        else:
            pre_processed = text

        if pre_processed is None or pre_processed == "":

            assert (self.configuration is not None)

            pre_processed = self.configuration.empty_string

        return pre_processed

    def get_question(self, client_context, pre_processed, srai):
        if srai is False:
            return Question.create_from_text(client_context,
                                             pre_processed,
                                             srai=srai)
        else:
            return Question.create_from_text(client_context,
                                             pre_processed,
                                             split=False,
                                             srai=srai)

    def combine_answers(self, answers, srai):

        assert (answers is not None)
        assert (self._sentence_joiner is not None)

        return self._sentence_joiner.combine_answers(answers, srai)

    def post_process_response(self, client_context, response, srai):
        if srai is False:

            assert (client_context is not None)

            answer = client_context.brain.post_process_response(
                client_context, response).strip()
            if not answer:
                answer = self.get_default_response(client_context)

        else:
            answer = response

        return answer

    def log_answer(self, client_context, text, answer, responselogger, srai):
        YLogger.debug(client_context, "Processed Response (%s) [srai:%s] : %s",
                      client_context.userid, srai, answer)

        if responselogger is not None:
            responselogger.log_response(text, answer)

    def ask_question(self,
                     client_context,
                     text,
                     srai=False,
                     responselogger=None):

        assert (client_context is not None)

        if srai is False:
            client_context.bot = self
            client_context.brain = client_context.bot.brain
            self._is_error = False
        else:
            if self._is_error is True:
                return ''

        assert (client_context.bot is not None)
        assert (client_context.brain is not None)

        client_context.mark_question_start(text, srai)

        pre_processed = self.pre_process_text(client_context, text, srai)

        question = self.get_question(client_context, pre_processed, srai)

        conversation = self.get_conversation(client_context)
        if len(conversation.questions) == 0:
            if self.client.trigger_manager is not None:
                self.client.trigger_manager.trigger(
                    SystemTriggers.CONVERSATION_START, client_context)

        assert (conversation is not None)

        if srai is False:
            conversation.exception = None
            if client_context.server_mode is True:
                self.conversations.load_learnf_with_userid(client_context)
                client_context.brain.rdf.apply_updates()
            if client_context.deleteVariable is True:
                conversation.clear_data_property()
            self.conversations.remove_internal_data(client_context)

        conversation.record_dialog(question)

        try:
            answers = self.process_sentences(client_context, question, srai,
                                             responselogger)
        except LimitOverException as excep:
            if self._is_error is False:
                self._is_error = True
                conversation.exception = str(excep)
                YLogger.exception(client_context, "Limit-Over Exception",
                                  excep)
                base = conversation.internal_base
                conversation.add_internal_data(base, 'exception',
                                               conversation.exception)
                conversation.add_internal_variables(base, 'after_variables')
            if srai is True:
                conversation.pop_dialog()
                raise
        except Exception as excep:
            if self._is_error is False:
                self._is_error = True
                conversation.exception = str(excep)
                YLogger.exception(client_context, "Exception", excep)
                base = conversation.internal_base
                conversation.add_internal_data(base, 'exception',
                                               conversation.exception)
                conversation.add_internal_variables(base, 'after_variables')
            if srai is True:
                conversation.pop_dialog()
                raise

        if self._is_error is True:
            question.exception = conversation.exception
            answer = self.get_exception_response(client_context)
            sentence = question.current_sentence()
            sentence.response = answer
            answers = [answer]

        client_context.reset_question()

        if srai is True:
            conversation.pop_dialog()

        conversation.save_sentiment()

        if srai is False:
            self.conversations.set_internal_data(client_context)
            self.save_conversation(client_context)
            if client_context.server_mode is True:
                self.conversations.remove_conversation(client_context)
                self.conversations.remove_learnf_with_userid(client_context)

        if self.client.trigger_manager is not None and srai is False:
            self.client.trigger_manager.trigger(SystemTriggers.QUESTION_ASKED,
                                                client_context)

        return self.combine_answers(answers, srai)

    def process_sentences(self, client_context, question, srai,
                          responselogger):
        self._utterances = None
        utterances = []
        answers = []
        sentence_no = 0
        for sentence in question.sentences:
            YLogger.debug(client_context, "Sentence-Words %s", sentence.words)
            question.set_current_sentence_no(sentence_no)
            utterance = client_context.brain.tokenizer.words_to_texts(
                sentence.words)
            if utterance == '':
                answer = ''
            else:
                answer = self.process_sentence(client_context, sentence, srai,
                                               responselogger)
            utterances.append(utterance)
            answers.append(answer)
            if self._is_error is True:
                break
            sentence_no += 1

        self._utterance = self.combine_answers(utterances, False)
        return answers

    def process_sentence(self, client_context, sentence, srai, responselogger):

        assert (client_context is not None)
        assert (client_context.brain is not None)

        try:
            client_context.check_max_recursion()
            client_context.check_max_timeout()
        except LimitOverException:
            raise

        if srai is False:
            self.check_spelling_before(client_context, sentence)
            self._srai_count = 0
        else:
            self._srai_count += 1
            if self._srai_count > client_context.bot.configuration.max_search_srai:
                raise LimitOverException(
                    "Max search srai [%d] exceeded: [%s]" %
                    (client_context.bot.configuration.max_search_srai,
                     client_context.brain.tokenizer.words_to_texts(
                         sentence.words)))

        response = client_context.brain.ask_question(client_context, sentence,
                                                     srai)

        if response is None and srai is False:
            response = self.check_spelling_and_retry(client_context, sentence)

        if response is not None:
            return self.handle_response(client_context, sentence, response,
                                        srai, responselogger)
        else:
            return self.handle_none_response(client_context, sentence,
                                             responselogger)

    def handle_response(self, client_context, sentence, response, srai,
                        responselogger):

        assert (sentence is not None)

        YLogger.debug(client_context, "Raw Response (%s): %s",
                      client_context.userid, response)
        sentence.response = response

        sentence.calculate_sentinment_score(client_context)

        answer = self.post_process_response(client_context, response, srai)
        self.log_answer(client_context, sentence.text(), answer,
                        responselogger, srai)

        return answer

    def handle_none_response(self, client_context, sentence, responselogger):

        assert (sentence is not None)

        sentence.response = self.get_default_response(client_context)

        sentence.calculate_sentinment_score(client_context)

        if responselogger is not None:
            responselogger.log_unknown_response(sentence)

        return sentence.response