Beispiel #1
0
def get_dialogue_intents(dialogue: Dict,
                         exclude_none: bool = True) -> Set[str]:
    """Returns the intents in a dialogue.

    Parameters
    ----------
    dialogue
        Nested dictionary containing dialogue and annotations.
    exclude_none
        If True, the `NONE` intent is not included in the intents set.

    Returns
    -------
    intents
        A set of intents contained in the dialogue.
    """

    intents = set()
    for turn in dialogue_iterator(dialogue, user=True, system=False):
        for frame in turn['frames']:
            intent = frame['state']['active_intent']
            if exclude_none:
                if intent == 'NONE':
                    continue
                else:
                    intents.add(intent)
            else:
                intents.add(intent)
    return intents
def _get_entity_slots(
        split: Literal['train', 'test',
                       'dev']) -> Dict[str, Dict[str, Set[str]]]:
    """Find the slots that are always specified by the system when a call to a "search" intent
    is made (referred to as "entity" slots).

    Parameters
    ----------
    split
        The data split for which the entity slots are to be determined

    Returns
    -------
    entity_slots_map
        A mapping of the form::

            {
            'service_name':
                         {'intent_1': {'slot_name',...}
            ...
            }

    """
    # select only dialogues where the system speaks about an entity following a search call
    filtered_dialogues = filter_by_intent_type(split,
                                               transactional=True,
                                               search=True)
    search_only = filter_by_intent_type(split,
                                        transactional=False,
                                        search=True)
    for file_id, dial_ids in search_only.items():
        if file_id in filtered_dialogues:
            filtered_dialogues[file_id].update(dial_ids)
        else:
            filtered_dialogues[file_id] = dial_ids

    # iterate through selected dialogues to find slots that are always specified after a
    # call to a given intent ("entity slot").
    entity_slots_map = defaultdict(lambda: collections.defaultdict(set))
    search_intents = set(get_intents_by_type()['search'])
    for file in filtered_dialogues.keys():
        for fp, dial in file_iterator(file,
                                      return_only=filtered_dialogues[file]):
            for turn in dialogue_iterator(dial, user=False, system=True):
                if 'service_call' in (frame := turn['frames'][0]):
                    service = frame['service']
                    intent = frame['service_call']['method']
                    service_results = frame['service_results']
                    if intent in search_intents and service_results:
                        mentioned_slots = {
                            entry['slot']
                            for entry in frame['slots']
                        }
                        if intent in entity_slots_map[service]:
                            entity_slots_map[service][intent] = \
                                entity_slots_map[service][intent].intersection(mentioned_slots)
                        else:
                            entity_slots_map[service][intent] = mentioned_slots
Beispiel #3
0
def has_requestables(dialogue: dict) -> bool:
    """Returns `True` if the user requests information
    from the system and false otherwise.
    """

    for turn in dialogue_iterator(dialogue, user=True, system=False):
        for frame in turn['frames']:
            if frame['state']['requested_slots']:
                return True
    return False
def get_dialogues_by_type(
        intents_mapping: dict) -> Dict[str, Dict[str, List[str]]]:
    """Returns a mapping from dialogue type (transactional intent only, search intent only,
    mixed intent) to dialogue IDs.

    Returns
    -------
    dialogues_by_type:
        A mapping of the form::

            {
            'transactional: ['dialogue_id',...],
            'search': ['dialogue_id',...],
            'mixed_intent': ['dialogue_id',...]
            }
    """

    dialogues_by_type = collections.defaultdict(
        lambda: collections.defaultdict(list))

    for split in _SPLIT_NAMES:
        for _, dial in split_iterator(split):
            dialogue_id = dial['dialogue_id']
            transactional, search = False, False
            for turn in dialogue_iterator(dial, user=True, system=False):
                for frame in turn['frames']:
                    active_intent = frame['state']['active_intent']
                    if active_intent != 'NONE':
                        if active_intent in intents_mapping['transactional']:
                            transactional = True
                        else:
                            search = True
                if transactional and search:
                    break
            if transactional and not search:
                dialogues_by_type[split]['transactional'].append(dialogue_id)
            elif search and not transactional:
                dialogues_by_type[split]['search'].append(dialogue_id)
            else:
                dialogues_by_type[split]['mixed_intent'].append(dialogue_id)

        for intent_type in dialogues_by_type:
            dialogues_by_type[split][intent_type].sort(key=dial_sort_key)

    return dialogues_by_type
def test_get_entity_slots_map(n_dialogues, split, trials):

    expected_output = get_entity_slots_map()
    for _ in range(trials):
        for dial in random_sampler(split, n_dialogues):
            # output of sampler is (filename, dial)
            dial_id = dial[1]['dialogue_id']
            mixed_intent = dial_id in metadata.MIXED_INTENT_DIALOGUES
            search = dial_id in metadata.SEARCH_DIALOGUES
            if mixed_intent or search:
                for turn in dialogue_iterator(dial, user=False, system=True):
                    frame = turn['frames'][0]
                    intent = frame['service_call']['method']
                    if ('service_call' in frame) and (intent in metadata.SEARCH_INTENTS):
                        if 'service_results' in frame:
                            expected = expected_output[frame['service']][intent]
                            actual = set(slot_dict['slot'] for slot_dict in frame['slots'])
                            assert not expected - actual
def _get_requestables(dialogue: dict) -> Set[str]:
    """Get requestable slots in a given dialogue.

    Parameters
    ----------
    dialogue
        A nested dictionary representation of the dialogue in SGD format.

    Returns
    -------
    requestables
        Set of slots which appear in the ``['state']['requested_slots']`` of all user frames.
    """

    requestables = set()
    for turn in dialogue_iterator(dialogue, user=True, system=False):
        for frame in turn['frames']:
            if reqs := frame['state']['requested_slots']:
                requestables.update(reqs)