Esempio n. 1
0
    def parse(
        self,
        text: Text,
        time: Optional[datetime.datetime] = None,
        only_output_properties: bool = True,
    ) -> Dict[Text, Any]:
        """Parse the input text, classify it and return pipeline result.

        The pipeline result usually contains intent and entities."""

        if not text:
            # Not all components are able to handle empty strings. So we need
            # to prevent that... This default return will not contain all
            # output attributes of all components, but in the end, no one
            # should pass an empty string in the first place.
            output = self.default_output_attributes()
            output["text"] = ""
            return output

        message = Message(text, self.default_output_attributes(), time=time)

        for component in self.pipeline:
            component.process(message, **self.context)

        output = self.default_output_attributes()
        output.update(message.as_dict(only_output_properties=only_output_properties))
        return output
Esempio n. 2
0
 def process(self, message: Message, **kwargs: Any) -> None:
     """
     This is where we care about adding to the message, as this
     is where we can see it. Take each attribute in `properties_to_add`
     and add it to the output
     """
     print(message)
     print(message.as_dict())
     for prop in self.properties_to_add:
         print(prop)
         prop_val = message.get(prop)
         message.set(prop, prop_val, add_to_output=True)
Esempio n. 3
0
class IncrementalInterpreter(Interpreter):
    """Use a trained pipeline of components to parse text messages.

        This is for explicitly listed incremental components"""
    @staticmethod
    def load(model_dir: Text,
             component_builder: Optional[ComponentBuilder] = None,
             skip_validation: bool = False) -> 'IncrementalInterpreter':
        """Create an interpreter based on a persisted model.

        Args:
            skip_validation: If set to `True`, tries to check that all
                required packages for the components are installed
                before loading them.
            model_dir: The path of the model to load
            component_builder: The :class:`ComponentBuilder` to use.

        Returns:
            An interpreter that uses the loaded model.
        """

        model_metadata = Metadata.load(model_dir)
        IncrementalInterpreter.ensure_model_compatibility(model_metadata)
        return IncrementalInterpreter.create(model_metadata, component_builder,
                                             skip_validation)

    @staticmethod
    def create(model_metadata: Metadata,
               component_builder: Optional[ComponentBuilder] = None,
               skip_validation: bool = False) -> 'IncrementalInterpreter':
        """Load stored model and components defined by the provided metadata."""

        context = {}

        if component_builder is None:
            # If no builder is passed, every interpreter creation will result
            # in a new builder. hence, no components are reused.
            component_builder = components.ComponentBuilder()

        pipeline = []

        # Before instantiating the component classes,
        # lets check if all required packages are available
        if not skip_validation:
            components.validate_requirements(model_metadata.component_classes)

        for i in range(model_metadata.number_of_components):
            component_meta = model_metadata.for_component(i)
            component = component_builder.load_component(
                component_meta, model_metadata.model_dir, model_metadata,
                **context)
            try:
                updates = component.provide_context()
                if updates:
                    context.update(updates)
                pipeline.append(component)
            except components.MissingArgumentError as e:
                raise Exception("Failed to initialize component '{}'. "
                                "{}".format(component.name, e))
        return IncrementalInterpreter(pipeline, context, model_metadata)

    def __init__(self, pipeline, context, model_metadata=None):

        super().__init__(pipeline, context, model_metadata)
        # self.message is initialized in init, and get modified with each parse
        # call until it is eventually cleared when new_utterance is called
        # TODO: assert that every compoenent in the pipeline is incremental
        self.message = Message(text="")

    # Call this function when creating up a new utterance
    # this will tell the incremental components to clear their
    # internal states and start clean.
    def new_utterance(self):
        """ Tells the component that a new utterance is about to begin

        This clears a components internal state and resets the Message """

        for component in self.pipeline:
            component.new_utterance()
        self.message = Message(text="")

    def parse(self, text, time=None, only_output_properties=True):
        """ Parse the input text, classify it and return pipeline result.

        This should only be called for command line evaluation of an
        incremental component, otherwise, use parse_incremental.

        Text is split into word-level increments and subsequently calls
        parse_incremental for each word to evaluate incremental components. """
        self.new_utterance()
        # split the text into words, and pass them through as
        # "add" incremental units to parse_incremental
        for word in text.split():
            iu = (word, "add")
            self.parse_incremental(iu, time)
        output = self.default_output_attributes()
        output.update(
            self.message.as_dict(
                only_output_properties=only_output_properties))
        return output

    def parse_incremental(self, iu, time=None, only_output_properties=True):
        """ Parse the incremental unit through the pipeline of trained
        incremental components.

        new_utterance should be called before each new query.

        Arg:
            iu: Incremental Unit. This can be anything as long as the
                pipeline can handle it. The default for sium and restart-
                incremental embeddings is a tuple of format (word, operation),
                Where operation is either "add" or "revoke" """
        if not iu:
            # Not all components are able to handle empty strings. So we need
            # to prevent that... This default return will not contain all
            # output attributes of all components, but in the end, no one
            # should pass an empty string in the first place.
            output = self.default_output_attributes()
            output["text"] = ""
            return output

        # Initialize our iu_list if this is the first
        # call to it.
        if (self.message.get('iu_list') is None):
            self.message.set('iu_list', list())

        # add our IU
        self.message.get('iu_list').append(iu)

        # Call each component's process() function. Recall that
        # incremental components should expect multiple calls to
        # process() per utterance, one per IU.
        for component in self.pipeline:
            component.process(self.message, **self.context)

        output = self.default_output_attributes()
        output.update(
            self.message.as_dict(
                only_output_properties=only_output_properties))
        return output