def find_skill(self, param, author=None, skills=None):
        # type: (str, str, List[SkillEntry]) -> SkillEntry
        """Find skill by name or url"""
        if param.startswith('https://') or param.startswith('http://'):
            repo_id = SkillEntry.extract_repo_id(param)
            for skill in self.all_skills:
                if skill.id == repo_id:
                    return skill
            name = SkillEntry.extract_repo_name(param)
            skill_directory = SkillEntry.create_path(self.skills_dir, param)
            return SkillEntry(name, skill_directory, param, msm=self)
        else:
            skill_confs = {
                skill: skill.match(param, author)
                for skill in skills or self.all_skills
            }
            best_skill, score = max(skill_confs.items(), key=lambda x: x[1])
            LOG.info('Best match ({}): {} by {}'.format(
                round(score, 2), best_skill.name, best_skill.author))
            if score < 0.3:
                raise SkillNotFound(param)
            low_bound = (score * 0.7) if score != 1.0 else 1.0

            close_skills = [
                skill for skill, conf in skill_confs.items()
                if conf >= low_bound and skill != best_skill
            ]
            if close_skills:
                raise MultipleSkillMatches([best_skill] + close_skills)
            return best_skill
예제 #2
0
    def list(self):
        """
        Load a list of SkillEntry objects from both local and
        remote skills

        It is necessary to load both local and remote skills at
        the same time to correctly associate local skills with the name
        in the repo and remote skills with any custom path that they
        have been downloaded to
        """
        try:
            self.repo.update()
        except GitException as e:
            if not isdir(self.repo.path):
                raise
            LOG.warning('Failed to update repo: {}'.format(repr(e)))
        remote_skill_list = (
            SkillEntry(
                name, SkillEntry.create_path(self.skills_dir, url, name),
                url, sha if self.versioned else '', msm=self
            )
            for name, path, url, sha in self.repo.get_skill_data()
        )
        remote_skills = {
            skill.id: skill for skill in remote_skill_list
        }
        all_skills = []
        for skill_file in glob(join(self.skills_dir, '*', '__init__.py')):
            skill = SkillEntry.from_folder(dirname(skill_file), msm=self)
            if skill.id in remote_skills:
                skill.attach(remote_skills.pop(skill.id))
            all_skills.append(skill)
        all_skills += list(remote_skills.values())
        return all_skills
    def _get_remote_skills(self):
        """Build a dictionary of skills in mycroft-skills repo keyed by id"""
        remote_skills = []
        for name, _, url, sha in self.repo.get_skill_data():
            skill_dir = SkillEntry.create_path(self.skills_dir, url, name)
            sha = sha if self.versioned else ''
            remote_skills.append(
                SkillEntry(name, skill_dir, url, sha, msm=self))

        return {skill.id: skill for skill in remote_skills}