Example #1
0
 async def send_to_cai(
     self,
     request: DetectIntentRequest,
 ) -> Tuple[DetectIntentResponse, str]:
     text = request.query_input.text.text
     logger_console.warning({
         "message": f"CAI-DetectIntentRequest to CAI, text input: {text}",
         "content": text,
         "text": text,
         "tags": ["text"],
     })
     cai_response: DetectIntentResponse = await self.loops[
         request.session]["loop"].run_in_executor(
             None,
             self.client.services.sessions.detect_intent,
             request,
         )
     intent_name_cai = cai_response.query_result.intent.display_name
     logger_console.warning({
         "message":
         f"CAI-DetectIntentResponse from CAI, intent_name_cai: {intent_name_cai}",
         "content": intent_name_cai,
         "intent_name_cai": intent_name_cai,
         "tags": ["text"],
     })
     return cai_response, "cai_response"
Example #2
0
 def handle_if_intent_reached_number_triggers_max(
         response: session_pb2.DetectIntentResponse,
         nlu_client: Client) -> session_pb2.DetectIntentResponse:
     logger_console.warning(
         "Intent was triggered a maximum amount of times!")
     IntentMaxTriggerHandler.handle_if_intent_reached_number_triggers_max(
         response, nlu_client)
Example #3
0
 def quicksend_to_api(self, response: session_pb2.DetectIntentResponse,
                      message: Optional[intent_pb2.Intent.Message],
                      count: int) -> None:
     logger_console.warning({
         "message":
         "quicksend_to_api not written, please subclass and implement"
     })
Example #4
0
    async def send_to_qa(
        self,
        request: DetectIntentRequest,
    ) -> Tuple[DetectIntentResponse, str]:
        text = request.query_input.text.text
        qa_request = qa_pb2.GetAnswerRequest(
            session_id=request.session,
            text=session_pb2.TextInput(text=text, language_code=f"{QA_LANG}"),
            max_num_answers=QA_MAX_ANSWERS,
            threshold_reader=QA_THRESHOLD_READER,
            threshold_retriever=QA_THRESHOLD_RETRIEVER,
        )

        logger_console.warning({
            "message": f"QA-GetAnswerRequest to QA, text input: {text}",
            "content": text,
            "text": text,
            "tags": ["text"],
        })
        qa_response: DetectIntentResponse = await self.loops[
            request.session]["loop"].run_in_executor(
                None,
                self.qa_client_stub.GetAnswer,
                qa_request,
            )
        # intent_name_qa = qa_response.query_result.intent.display_name
        logger_console.warning({
            "message": "QA-DetectIntentResponse from QA",
            "tags": ["text"]
        })
        return qa_response, "qa_response"
Example #5
0
    def test_log(log_store):
        CONSOLE_TEXT = "console log"
        logger_console.addHandler(log_store)
        logger_console.debug(CONSOLE_TEXT)
        assert CONSOLE_TEXT in log_store.messages["debug"]
        logger_console.info(CONSOLE_TEXT)
        assert CONSOLE_TEXT in log_store.messages["info"]
        logger_console.warning(CONSOLE_TEXT)
        assert CONSOLE_TEXT in log_store.messages["warning"]
        logger_console.error(CONSOLE_TEXT)
        assert CONSOLE_TEXT in log_store.messages["error"]
        logger_console.critical(CONSOLE_TEXT)
        assert CONSOLE_TEXT in log_store.messages["critical"]

        CONSOLE_TEXT = "debug log"
        logger_debug.addHandler(log_store)
        logger_debug.debug(CONSOLE_TEXT)
        assert CONSOLE_TEXT in log_store.messages["debug"]
        logger_debug.info(CONSOLE_TEXT)
        assert CONSOLE_TEXT in log_store.messages["info"]
        logger_debug.warning(CONSOLE_TEXT)
        assert CONSOLE_TEXT in log_store.messages["warning"]
        logger_debug.error(CONSOLE_TEXT)
        assert CONSOLE_TEXT in log_store.messages["error"]
        logger_debug.critical(CONSOLE_TEXT)
        assert CONSOLE_TEXT in log_store.messages["critical"]

        CONSOLE_TEXT = "root log"
        logger_root.addHandler(log_store)
        logger_root.debug(CONSOLE_TEXT)
        assert CONSOLE_TEXT in log_store.messages["debug"]
        logger_root.info(CONSOLE_TEXT)
        assert CONSOLE_TEXT in log_store.messages["info"]
        logger_root.warning(CONSOLE_TEXT)
        assert CONSOLE_TEXT in log_store.messages["warning"]
        logger_root.error(CONSOLE_TEXT)
        assert CONSOLE_TEXT in log_store.messages["error"]
        logger_root.critical(CONSOLE_TEXT)
        assert CONSOLE_TEXT in log_store.messages["critical"]

        assert len(log_store.messages["critical"]) == 3
        log_store.reset()
        assert len(log_store.messages["critical"]) == 0

        CONSOLE_TEXT = "root log 2"
        logger.addHandler(log_store)
        logger.debug(CONSOLE_TEXT)
        assert CONSOLE_TEXT in log_store.messages["debug"]
        logger.info(CONSOLE_TEXT)
        assert CONSOLE_TEXT in log_store.messages["info"]
        logger.warning(CONSOLE_TEXT)
        assert CONSOLE_TEXT in log_store.messages["warning"]
        logger.error(CONSOLE_TEXT)
        assert CONSOLE_TEXT in log_store.messages["error"]
        logger.critical(CONSOLE_TEXT)
        assert CONSOLE_TEXT in log_store.messages["critical"]
Example #6
0
def detect_intent(
    client: Client,
    response: session_pb2.DetectIntentResponse,
    text: str
) -> session_pb2.DetectIntentResponse:
    logger_console.info({"message": "detect intent triggered in bpi helpers", "tags": ["timing"]})
    request = get_detect_intent_request(text=text, session=get_session_from_response(response=response),)
    logger_console.info({"message": "detect intent returned in bpi helpers", "tags": ["timing"]})
    result = client.services.sessions.detect_intent(request)
    logger_console.warning(f"wrote {text}, received {result.query_result.fulfillment_messages}")
    return result
Example #7
0
 def trigger_function_not_implemented(
     self,
     response: session_pb2.DetectIntentResponse,
     message: intent_pb2.Intent.Message,
     trigger: str,
     found_triggers: Dict[str, List[str]],
 ) -> None:
     logger_console.warning({
         "message":
         f"no function for the trigger {trigger}, please subclass and implement",
         "trigger": trigger,
         "content": found_triggers[trigger],
     })
Example #8
0
 def serve(self) -> None:
     logger_console.info(f"attempting to start server on port {PORT}")
     self._setup_server()
     logger_console.warning({"message": f"Server started on port {PORT}", "content": PORT})
     logger_console.warning(
         {
             "message": f"using intent handlers list: {self.intent_handlers}",
             "content": self.intent_handlers,
         }
     )
     try:
         while True:
             time.sleep(10)
     except KeyboardInterrupt:
         logger_console.info("Keyboard interrupt, shutting down")
     logger_console.info({"message": "server shut down", "tags": ["timing"]})
Example #9
0
    def check_session_id(self, request: DetectIntentRequest) -> None:
        session_pop_timeout: int = SESSION_TIMEOUT_MINUTES * 60

        for session in self.loops.copy():
            if time.time() - self.loops[session][
                    "timestamp"] > session_pop_timeout:  # type: ignore
                logger_console.warning(f"Popping old session: {session}.")
                loop = self.loops.pop(session)
                loop["loop"].stop()
                loop["loop"].close()

        if request.session not in self.loops.keys():
            self.loops[request.session] = {
                "loop": asyncio.new_event_loop(),
                "timestamp": time.time(),
            }
            logger_console.warning(
                f"New session in bpi: {request.session}. {len(self.loops)} sessions currently stored."
            )
Example #10
0
    def DetectIntent(self, request: DetectIntentRequest,
                     context: grpc.ServicerContext) -> DetectIntentResponse:
        self.check_session_id(request)

        if len(request.query_input.text.text) > SENTENCE_TRUNCATION:
            logger_console.warning(
                f'The received text is too long, it will be truncated '
                f'to {SENTENCE_TRUNCATION} characters!')
        truncated_text: TextInput = TextInput(
            text=request.query_input.text.text[:SENTENCE_TRUNCATION])
        request.query_input.text.CopyFrom(truncated_text)

        response, response_name = self.handle_async(request)

        if response_name == "cai_response":
            # Process CAI response
            response = self.process_messages(response)
            response = self.process_intent_handler(response)
        return response
Example #11
0
    def handle_async(
        self,
        request: DetectIntentRequest,
    ) -> Tuple[DetectIntentResponse, str]:
        tasks: List[Coroutine] = [self.send_to_cai(request)]
        if QA_ACTIVE:
            tasks.append(self.send_to_qa(request))

        while len(tasks):
            logger_console.warning(
                f"Starting async loop with {len(tasks)} tasks of type: {type(tasks)}"
            )
            try:
                finished, tasks = self.loops[
                    request.session]["loop"].run_until_complete(
                        asyncio.wait(tasks,
                                     return_when=asyncio.FIRST_COMPLETED
                                     )  # type: ignore
                    )
            except Exception:
                logger_console.exception("Task returned an exception!")
                return DetectIntentResponse(), "exception"

            # Allow the cai_response to return early if it finishes first
            for task in finished:
                result = task.result()
                if result[1] == "cai_response":
                    cai_response = result[0]
                    intent_name_cai = cai_response.query_result.intent.display_name
                    if intent_name_cai != "Default Fallback Intent" or not QA_ACTIVE:
                        logger_console.warning(
                            "CAI response good, returning early")
                        return cai_response, "cai_response"
                # If the QA response finishes first, save it for later
                else:
                    assert result[
                        1] == "qa_response", "Somehow a different response snuck in!"
                    qa_response = result[0]

        qa_confidence = qa_response.query_result.query_result.intent_detection_confidence
        logger_console.warning(
            f"QA confidence is {qa_confidence}, cutoff is {QA_THRESHOLD_READER}"
        )
        messages = qa_response.query_result.query_result.fulfillment_messages
        if messages:
            return qa_response.query_result, "qa_response"
        logger_console.warning(
            "No response from QA, passing back Default Fallback.")
        return cai_response, "cai_response"
Example #12
0
def trigger_intent(
    client: Client,
    session: str,
    intent_name: str,
    language: str = "de-DE",
    additional_contexts: Optional[List[context_pb2.Context]] = None,
) -> session_pb2.DetectIntentResponse:
    """
    Trigger a specific intent in the NLU backend without intent matching.

    Args:
        client: nlu client
        session: full session to perform the trigger in ('parent/<PROJECT_ID>/agent/sessions/<SESSION_ID>')
        intent_name: intent that you want to trigger
        language: language of the project
        additional_contexts: if you want to add additional contexts to the session

    Returns:
        session_pb2.DetectIntentResponse
    """
    if not additional_contexts:
        additional_contexts = []

    logger_console.warning({"message": "triggering specific intent", "intent_name": intent_name})
    trigger_context = create_context_struct(
        context=f"{session}/contexts/exact_intent",
        parameters=create_parameter_dict({"intent_name": intent_name}),
        lifespan_count=1,
    )
    request = get_detect_intent_request(
        text=f"Triggering Specific Intent: {intent_name}",
        session=session,
        language=language,
        query_params=session_pb2.QueryParameters(contexts=[trigger_context, *additional_contexts]),
    )
    result = client.services.sessions.detect_intent(request)
    logger_console.warning(f"triggered {intent_name}")
    return result
Example #13
0
    def DetectIntent(
            self, request: session_pb2.DetectIntentRequest,
            context: grpc.ServicerContext) -> session_pb2.DetectIntentResponse:
        try:
            if len(request.query_input.text.text) > SENTENCE_TRUNCATION:
                logger_console.warning(
                    f'The received text is too long, it will be truncated '
                    f'to {SENTENCE_TRUNCATION} characters!')
            truncated_text: TextInput = TextInput(
                text=request.query_input.text.text[:SENTENCE_TRUNCATION])
            request.query_input.text.CopyFrom(truncated_text)
            text = request.query_input.text.text
        except Exception as e:
            logger_console.exception(
                f"An issue was encountered in BPI:\n"
                f"\tSeems like the request query_input data was not properly formatted\n"
                f"\tDetails: {e}")
            text = "error"
        logger_console.warning({
            "message": f"CAI-DetectIntentRequest to CAI, text input: {text}",
            "content": text,
            "text": text,
            "tags": ["text"],
        })
        cai_response = self.perform_detect_intent(request)
        intent_name = cai_response.query_result.intent.display_name
        logger_console.warning({
            "message":
            f"CAI-DetectIntentResponse from CAI, intent_name: {intent_name}",
            "content":
            intent_name,
            "intent_name":
            intent_name,
            "session_id":
            get_session_from_response(cai_response),
            "tags": ["text"],
        })

        cai_response = self.process_messages(cai_response)
        return self.process_intent_handler(cai_response)
Example #14
0
 def handle_default_exit(
         response: session_pb2.DetectIntentResponse,
         nlu_client: Client) -> session_pb2.DetectIntentResponse:
     logger_console.warning("Default exit was triggered!")
     return response
Example #15
0
 def handle_default_fallback(
     response: session_pb2.DetectIntentResponse
 ) -> session_pb2.DetectIntentResponse:
     logger_console.warning("Default fallback was triggered!")
     return response
Example #16
0
    def test_level_manipulation(log_store):
        CONSOLE_TEXT = "console log"
        logger_console.addHandler(log_store)
        logger_console.debug(CONSOLE_TEXT)
        assert CONSOLE_TEXT in log_store.messages["debug"]

        logger_console.setLevel(logging.INFO)
        log_store.reset()
        assert len(log_store.messages["debug"]) == 0

        logger_console.debug(CONSOLE_TEXT)
        assert CONSOLE_TEXT not in log_store.messages["debug"]
        logger_console.info(CONSOLE_TEXT)
        assert CONSOLE_TEXT in log_store.messages["info"]

        logger_console.setLevel(logging.WARN)
        log_store.reset()
        assert len(log_store.messages["info"]) == 0

        logger_console.debug(CONSOLE_TEXT)
        assert CONSOLE_TEXT not in log_store.messages["debug"]
        logger_console.info(CONSOLE_TEXT)
        assert CONSOLE_TEXT not in log_store.messages["info"]
        logger_console.warning(CONSOLE_TEXT)
        assert CONSOLE_TEXT in log_store.messages["warning"]

        logger_console.setLevel(logging.ERROR)
        log_store.reset()
        assert len(log_store.messages["warning"]) == 0

        logger_console.debug(CONSOLE_TEXT)
        assert CONSOLE_TEXT not in log_store.messages["debug"]
        logger_console.info(CONSOLE_TEXT)
        assert CONSOLE_TEXT not in log_store.messages["info"]
        logger_console.warning(CONSOLE_TEXT)
        assert CONSOLE_TEXT not in log_store.messages["warning"]
        logger_console.error(CONSOLE_TEXT)
        assert CONSOLE_TEXT in log_store.messages["error"]

        logger_console.setLevel(logging.CRITICAL)
        log_store.reset()
        assert len(log_store.messages["error"]) == 0

        logger_console.debug(CONSOLE_TEXT)
        assert CONSOLE_TEXT not in log_store.messages["debug"]
        logger_console.info(CONSOLE_TEXT)
        assert CONSOLE_TEXT not in log_store.messages["info"]
        logger_console.warning(CONSOLE_TEXT)
        assert CONSOLE_TEXT not in log_store.messages["warning"]
        logger_console.error(CONSOLE_TEXT)
        assert CONSOLE_TEXT not in log_store.messages["error"]
        logger_console.critical(CONSOLE_TEXT)
        assert CONSOLE_TEXT in log_store.messages["critical"]

        logger_console.setLevel(logging.CRITICAL + 1)
        log_store.reset()
        assert len(log_store.messages["error"]) == 0

        logger_console.debug(CONSOLE_TEXT)
        assert CONSOLE_TEXT not in log_store.messages["debug"]
        logger_console.info(CONSOLE_TEXT)
        assert CONSOLE_TEXT not in log_store.messages["info"]
        logger_console.warning(CONSOLE_TEXT)
        assert CONSOLE_TEXT not in log_store.messages["warning"]
        logger_console.error(CONSOLE_TEXT)
        assert CONSOLE_TEXT not in log_store.messages["error"]
        logger_console.critical(CONSOLE_TEXT)
        assert CONSOLE_TEXT not in log_store.messages["critical"]