Example #1
0
def interpret_schematic(
    interpreter,
    speaker,
    d,
    repeat_dict=None
) -> List[Tuple[List[Block], Optional[str], List[Tuple[str, str]]]]:
    """Return a list of 3-tuples, each with values:
    - the schematic blocks, list[(xyz, idm)]
    - a SchematicNode memid, or None
    - a list of (pred, val) tags
    """
    # hack, fixme in grammar/standardize.  sometimes the repeat is a sibling of action
    if repeat_dict is not None:
        repeat = cast(int, get_repeat_num(repeat_dict))
    else:
        repeat = cast(int, get_repeat_num(d))
    assert type(repeat) == int, "bad repeat={}".format(repeat)

    triples = d.get("triples", [{
        "pred_text": "has_shape",
        "obj_text": "cube"
    }])
    shapes = get_properties_from_triples(triples, "has_shape")
    if any(shapes):
        blocks, tags = interpret_shape_schematic(interpreter, speaker, d)
        return [(blocks, None, tags)] * repeat
    else:
        return [interpret_named_schematic(interpreter, speaker, d)] * repeat
Example #2
0
    def handle_spawn(self, speaker, d) -> Tuple[Optional[str], Any]:
        """This function reads the dictionary, resolves the missing details using memory
        and handles a 'spawn' command by either replying back or 
        pushing a Spawn task to the task stack. 

        Args:
            speaker: speaker_id or name.
            d: the complete action dictionary
        """
        # FIXME! use filters appropriately, don't search by hand
        spawn_triples = d.get("reference_object", {}).get("filters", {}).get("triples", [])
        if not spawn_triples:
            raise ErrorWithResponse("I don't understand what you want me to spawn.")
        names = [t.get("obj_text") for t in spawn_triples if t.get("pred_text", "") == "has_name"]
        if not any(names):
            raise ErrorWithResponse("I don't understand what you want me to spawn.")
        # if multiple possible has_name triples, just pick the first:
        object_name = names[0]
        schematic = self.memory.get_mob_schematic_by_name(object_name)
        if not schematic:
            raise ErrorWithResponse("I don't know how to spawn: %r." % (object_name))

        object_idm = list(schematic.blocks.values())[0]
        location_d = d.get("location", SPEAKERLOOK)
        mems = self.subinterpret["reference_locations"](self, speaker, location_d)
        steps, reldir = interpret_relative_direction(self, location_d)
        pos, _ = self.subinterpret["specify_locations"](self, speaker, mems, steps, reldir)
        repeat_times = get_repeat_num(d)
        for i in range(repeat_times):
            task_data = {"object_idm": object_idm, "pos": pos, "action_dict": d}
            self.append_new_task(self.task_objects["spawn"], task_data)
        self.finished = True
        return None, None
Example #3
0
    def handle_fill(self, speaker, d) -> Tuple[Optional[str], Any]:
        """This function reads the dictionary, resolves the missing details using memory
        and perception and handles a 'fill' command by either pushing a dialogue object
        or pushing a Fill task to the task stack. 

        Args:
            speaker: speaker_id or name.
            d: the complete action dictionary
        """
        r = d.get("reference_object")
        self.finished = True
        if not r.get("filters"):
            r["filters"] = {"location", SPEAKERLOOK}

        # Get the reference location
        location_d = r["filters"].get("location", SPEAKERLOOK)
        mems = self.subinterpret["reference_locations"](self, speaker, location_d)
        steps, reldir = interpret_relative_direction(self, location_d)
        location, _ = self.subinterpret["specify_locations"](self, speaker, mems, steps, reldir)

        # Get nearby holes
        holes: List[Hole] = heuristic_perception.get_all_nearby_holes(self.agent, location)
        candidates: List[Tuple[XYZ, Hole]] = [
            (to_block_pos(np.mean(hole[0], axis=0)), hole) for hole in holes
        ]

        # Choose the best ones to fill
        repeat = get_repeat_num(d)
        holes = filter_by_sublocation(self, speaker, candidates, r, limit=repeat, loose=True)
        if holes is None:
            self.dialogue_stack.append_new(
                Say, "I don't understand what holes you want me to fill."
            )
            return None, None
        for hole in holes:
            _, hole_info = hole
            poss, hole_idm = hole_info
            # FIXME use filters properly...
            triples = d.get("triples", [])
            block_types = [
                t.get("obj_text") for t in triples if t.get("pred_text", "") == "has_block_type"
            ]
            try:
                fill_idm = get_block_type(block_types[0])
            except:
                fill_idm = hole_idm
            task_data = {"action_dict": d, "schematic": poss, "block_idm": fill_idm}
            self.append_new_task(self.task_objects["fill"], task_data)
        if len(holes) > 1:
            self.dialogue_stack.append_new(Say, "Ok. I'll fill up the holes.")
        else:
            self.dialogue_stack.append_new(Say, "Ok. I'll fill that hole up.")
        self.finished = True
        return None, None
Example #4
0
        def new_tasks():
            attrs = {}
            schematic_d = d.get("schematic", {"has_size": 2})
            # set the attributes of the hole to be dug.
            for dim, default in [("depth", 1), ("length", 1), ("width", 1)]:
                key = "has_{}".format(dim)
                if key in schematic_d:
                    attrs[dim] = word_to_num(schematic_d[key])
                elif "has_size" in schematic_d:
                    attrs[dim] = interpret_size(self, schematic_d["has_size"])
                else:
                    attrs[dim] = default
            # minecraft world is [z, x, y]
            padding = (attrs["depth"] + 4, attrs["length"] + 4, attrs["width"] + 4)
            print("attrs", attrs)
            print("padding", padding)

            location_d = d.get("location", SPEAKERLOOK)
            repeat_num = get_repeat_num(d)
            repeat_dir = get_repeat_dir(d)
            print("loc d in dig", location_d, "repeat", repeat_num, repeat_dir)
            mems = self.subinterpret["reference_locations"](self, speaker, location_d)
            steps, reldir = interpret_relative_direction(self, location_d)
            origin, offsets = self.subinterpret["specify_locations"](
                self,
                speaker,
                mems,
                steps,
                reldir,
                repeat_num=repeat_num,
                repeat_dir=repeat_dir,
                padding=padding,
            )
            print("origin from dig", origin, "offsets", offsets)

            # add dig tasks in a loop
            tasks_todo = []
            for offset in offsets:
                og = np.array(origin) + offset
                t = self.task_objects["dig"](self.agent, {"origin": og, "action_dict": d, **attrs})
                print("append task:", t, og, d, attrs)
                tasks_todo.append(t)
            return list(reversed(tasks_todo))
Example #5
0
        def new_tasks():
            repeat = get_repeat_num(d)
            tasks_to_do = []
            # only go around the x has "around"; FIXME allow other kinds of dances
            location_d = d.get("location")
            if location_d is not None:
                rd = location_d.get("relative_direction")
                if rd is not None and (
                    rd == "AROUND" or rd == "CLOCKWISE" or rd == "ANTICLOCKWISE"
                ):
                    ref_obj = None
                    location_reference_object = location_d.get("reference_object")
                    if location_reference_object:
                        objmems = self.subinterpret["reference_objects"](
                            self, speaker, location_reference_object
                        )
                        if len(objmems) == 0:
                            raise ErrorWithResponse("I don't understand where you want me to go.")
                        ref_obj = objmems[0]
                    for i in range(repeat):
                        refmove = dance.RefObjMovement(
                            self.agent,
                            ref_object=ref_obj,
                            relative_direction=location_d["relative_direction"],
                        )
                        t = self.task_objects["dance"](self.agent, {"movement": refmove})
                        tasks_to_do.append(t)
                    return list(reversed(tasks_to_do))

            dance_type = d.get("dance_type", {"dance_type_name": "dance"})
            # FIXME holdover from old dict format
            if type(dance_type) is str:
                dance_type = dance_type = {"dance_type_name": "dance"}
            if dance_type.get("point"):
                target = self.subinterpret["point_target"](self, speaker, dance_type["point"])
                for i in range(repeat):
                    t = self.task_objects["point"](self.agent, {"target": target})
                    tasks_to_do.append(t)
            # MC bot does not control body turn separate from head
            elif dance_type.get("look_turn") or dance_type.get("body_turn"):
                lt = dance_type.get("look_turn") or dance_type.get("body_turn")
                f = self.subinterpret["facing"](self, speaker, lt)
                for i in range(repeat):
                    t = self.task_objects["dancemove"](self.agent, f)
                    tasks_to_do.append(t)
            else:
                if location_d is None:
                    dance_location = None
                else:
                    mems = self.subinterpret["reference_locations"](self, speaker, location_d)
                    steps, reldir = interpret_relative_direction(self, location_d)
                    dance_location, _ = self.subinterpret["specify_locations"](
                        self, speaker, mems, steps, reldir
                    )
                # TODO use name!
                if dance_type.get("dance_type_span") is not None:
                    dance_name = dance_type["dance_type_span"]
                    if dance_name == "dance":
                        dance_name = "ornamental_dance"
                    dance_memids = self.memory._db_read(
                        "SELECT DISTINCT(Dances.uuid) FROM Dances INNER JOIN Triples on Dances.uuid=Triples.subj WHERE Triples.obj_text=?",
                        dance_name,
                    )
                else:
                    dance_memids = self.memory._db_read(
                        "SELECT DISTINCT(Dances.uuid) FROM Dances INNER JOIN Triples on Dances.uuid=Triples.subj WHERE Triples.obj_text=?",
                        "ornamental_dance",
                    )
                dance_memid = random.choice(dance_memids)[0]
                dance_fn = self.memory.dances[dance_memid]
                for i in range(repeat):
                    dance_obj = dance.Movement(
                        agent=self.agent, move_fn=dance_fn, dance_location=dance_location
                    )
                    t = self.task_objects["dance"](self.agent, {"movement": dance_obj})
                    tasks_to_do.append(t)
            return list(reversed(tasks_to_do))
Example #6
0
    def handle_build(self, speaker, d) -> Tuple[Optional[str], Any]:
        """This function reads the dictionary, resolves the missing details using memory
        and perception and handles a 'build' command by either pushing a dialogue object
        or pushing a Build task to the task stack. 

        Args:
            speaker: speaker_id or name.
            d: the complete action dictionary
        """
        # Get the segment to build
        if "reference_object" in d:
            # handle copy
            repeat = get_repeat_num(d)
            objs = self.subinterpret["reference_objects"](
                self,
                speaker,
                d["reference_object"],
                limit=repeat,
                extra_tags=["_voxel_object"],
                loose_speakerlook=True,
            )
            if len(objs) == 0:
                raise ErrorWithResponse("I don't understand what you want me to build")
            tagss = [
                [(p, v) for (_, p, v) in self.memory.get_triples(subj=obj.memid)] for obj in objs
            ]
            interprets = [
                [list(obj.blocks.items()), obj.memid, tags] for (obj, tags) in zip(objs, tagss)
            ]
        else:  # a schematic
            if d.get("repeat") is not None:
                repeat_dict = d
            else:
                repeat_dict = None
            interprets = interpret_schematic(
                self, speaker, d.get("schematic", {}), repeat_dict=repeat_dict
            )

        # Get the locations to build
        location_d = d.get("location", SPEAKERLOOK)
        mems = self.subinterpret["reference_locations"](self, speaker, location_d)
        steps, reldir = interpret_relative_direction(self, location_d)
        origin, offsets = self.subinterpret["specify_locations"](
            self,
            speaker,
            mems,
            steps,
            reldir,
            repeat_dir=get_repeat_dir(location_d),
            objects=interprets,
            enable_geoscorer=True,
        )
        interprets_with_offsets = [
            (blocks, mem, tags, off) for (blocks, mem, tags), off in zip(interprets, offsets)
        ]

        tasks_todo = []
        for schematic, schematic_memid, tags, offset in interprets_with_offsets:
            og = np.array(origin) + offset
            task_data = {
                "blocks_list": schematic,
                "origin": og,
                "schematic_memid": schematic_memid,
                "schematic_tags": tags,
                "action_dict": d,
            }

            tasks_todo.append(task_data)

        for task_data in reversed(tasks_todo):
            self.append_new_task(self.task_objects["build"], task_data)
        logging.info("Added {} Build tasks to stack".format(len(tasks_todo)))
        self.finished = True
        return None, None
Example #7
0
        def new_tasks():
            repeat = get_repeat_num(d)
            tasks_to_do = []
            # only go around the x has "around"; FIXME allow other kinds of dances
            location_d = d.get("location")
            if location_d is not None:
                rd = location_d.get("relative_direction")
                if rd is not None and (rd == "AROUND" or rd == "CLOCKWISE"
                                       or rd == "ANTICLOCKWISE"):
                    ref_obj = None
                    location_reference_object = location_d.get(
                        "reference_object")
                    if location_reference_object:
                        objmems = self.subinterpret["reference_objects"](
                            self, speaker, location_reference_object)
                        if len(objmems) == 0:
                            raise ErrorWithResponse(
                                "I don't understand where you want me to go.")
                        ref_obj = objmems[0]
                    for i in range(repeat):
                        refmove = dance.RefObjMovement(
                            self.agent,
                            ref_object=ref_obj,
                            relative_direction=location_d[
                                "relative_direction"],
                        )
                        t = self.task_objects["dance"](self.agent, {
                            "movement": refmove
                        })
                        tasks_to_do.append(t)
                    return list(reversed(tasks_to_do))

            dance_type = d.get("dance_type", {"dance_type_name": "dance"})
            if dance_type.get("point"):
                target = self.subinterpret["point_target"](self, speaker,
                                                           dance_type["point"])
                for i in range(repeat):
                    t = self.task_objects["point"](self.agent, {
                        "target": target
                    })
                    tasks_to_do.append(t)
            elif dance_type.get("look_turn") or dance_type.get("body_turn"):
                lt = dance_type.get("look_turn")
                if lt:
                    f = self.subinterpret["facing"](self,
                                                    speaker,
                                                    lt,
                                                    head_or_body="head")
                    T = self.task_objects["look"]
                else:
                    bt = dance_type.get("body_turn")
                    f = self.subinterpret["facing"](self,
                                                    speaker,
                                                    bt,
                                                    head_or_body="body")
                    T = self.task_objects["turn"]
                for i in range(repeat):
                    tasks_to_do.append(T(self.agent, f))
            elif dance_type["dance_type_name"] == "wave":
                new_task = self.task_objects["dance"](self.agent, {
                    "movement_type": "wave"
                })
                tasks_to_do.append(new_task)
            else:
                # FIXME ! merge dances, refactor.  search by name in sql
                raise ErrorWithResponse(
                    "I don't know how to do that dance yet!")
            return list(reversed(tasks_to_do))
Example #8
0
        def new_tasks():
            repeat = get_repeat_num(d)
            tasks_to_do = []
            # only go around the x has "around"; FIXME allow other kinds of dances
            location_d = d.get("location")
            if location_d is not None:
                rd = location_d.get("relative_direction")
                if rd is not None and (rd == "AROUND" or rd == "CLOCKWISE"
                                       or rd == "ANTICLOCKWISE"):
                    ref_obj = None
                    location_reference_object = location_d.get(
                        "reference_object")
                    if location_reference_object:
                        objmems = self.subinterpret["reference_objects"](
                            self, speaker, location_reference_object)
                        if len(objmems) == 0:
                            raise ErrorWithResponse(
                                "I don't understand where you want me to go.")
                        ref_obj = objmems[0]
                    for i in range(repeat):
                        refmove = dance.RefObjMovement(
                            self.agent,
                            ref_object=ref_obj,
                            relative_direction=location_d[
                                "relative_direction"],
                        )
                        t = self.task_objects["dance"](self.agent, {
                            "movement": refmove
                        })
                        tasks_to_do.append(t)
                    return maybe_task_list_to_control_block(
                        tasks_to_do, self.agent)

            dance_type = d.get("dance_type", {})
            if dance_type.get("point"):
                target = self.subinterpret["point_target"](self, speaker,
                                                           dance_type["point"])
                for i in range(repeat):
                    t = self.task_objects["point"](self.agent, {
                        "target": target
                    })
                    tasks_to_do.append(t)
            # MC bot does not control body turn separate from head
            elif dance_type.get("look_turn") or dance_type.get("body_turn"):
                lt = dance_type.get("look_turn") or dance_type.get("body_turn")
                f = self.subinterpret["facing"](self, speaker, lt)
                for i in range(repeat):
                    t = self.task_objects["dancemove"](self.agent, f)
                    tasks_to_do.append(t)
            else:
                if location_d is None:
                    dance_location = None
                else:
                    mems = self.subinterpret["reference_locations"](self,
                                                                    speaker,
                                                                    location_d)
                    steps, reldir = interpret_relative_direction(
                        self, location_d)
                    dance_location, _ = self.subinterpret["specify_locations"](
                        self, speaker, mems, steps, reldir)
                filters_d = dance_type.get("filters", {})
                filters_d["memory_type"] = "DANCES"
                F = self.subinterpret["filters"](self, speaker,
                                                 dance_type.get("filters", {}))
                dance_memids, _ = F()
                # TODO correct selector in filters
                dance_memid = random.choice(dance_memids)
                dance_mem = self.memory.get_mem_by_id(dance_memid)
                for i in range(repeat):
                    dance_obj = dance.Movement(agent=self.agent,
                                               move_fn=dance_mem.dance_fn,
                                               dance_location=dance_location)
                    t = self.task_objects["dance"](self.agent, {
                        "movement": dance_obj
                    })
                    tasks_to_do.append(t)
            return maybe_task_list_to_control_block(tasks_to_do, self.agent)
Example #9
0
    def handle_fill(self, speaker, d) -> Tuple[Any, Optional[str], Any]:
        """This function reads the dictionary, resolves the missing details using memory
        and perception and handles a 'fill' command by either pushing a dialogue object
        or pushing a Fill task to the task stack. 

        Args:
            speaker: speaker_id or name.
            d: the complete action dictionary
        """
        tasks = []
        r = d.get("reference_object")
        if not r.get("filters"):
            r["filters"] = {"location", SPEAKERLOOK}

        # Get the reference location
        location_d = r["filters"].get("location", SPEAKERLOOK)
        mems = self.subinterpret["reference_locations"](self, speaker,
                                                        location_d)
        steps, reldir = interpret_relative_direction(self, location_d)
        location, _ = self.subinterpret["specify_locations"](self, speaker,
                                                             mems, steps,
                                                             reldir)

        # Get nearby holes
        holes: List[Hole] = heuristic_perception.get_all_nearby_holes(
            self.agent, location)
        candidates: List[Tuple[XYZ, Hole]] = [
            (to_block_pos(np.mean(hole[0], axis=0)), hole) for hole in holes
        ]

        # Choose the best ones to fill
        repeat = get_repeat_num(d)
        holes = filter_by_sublocation(self,
                                      speaker,
                                      candidates,
                                      r,
                                      limit=repeat,
                                      loose=True)
        if holes is None:
            self.dialogue_stack.append_new(
                Say, "I don't understand what holes you want me to fill.")
            return None, None, None
        tasks = []
        for hole in holes:
            _, hole_info = hole
            poss, hole_idm = hole_info
            schematic, tags = interpret_fill_schematic(self, speaker,
                                                       d.get("schematic", {}),
                                                       poss, hole_idm)
            origin = np.min([xyz for (xyz, bid) in schematic], axis=0)
            task_data = {
                "blocks_list": schematic,
                "force": True,
                "origin": origin,
                "verbose": False,
                "embed": True,
                "fill_message": True,
                "schematic_tags": tags,
            }

            tasks.append(self.task_objects["build"](self.agent, task_data))

        if len(holes) > 1:
            self.dialogue_stack.append_new(Say, "Ok. I'll fill up the holes.")
        else:
            self.dialogue_stack.append_new(Say, "Ok. I'll fill that hole up.")

        return maybe_task_list_to_control_block(tasks, self.agent), None, None