使用 Python 让你的 Mycroft AI 语音助手技能栩栩如生

通过管理依赖项、调试、收集用户特定数据以及将所有内容整合到你的 Python 代码中,为你的 Mycroft 技能进行最后的润色。
146 位读者喜欢这篇文章。
Hands on a keyboard with a Python book

WOCinTech Chat。由 Opensource.com 修改。CC BY-SA 4.0

在本系列关于 Mycroft(一款开源、注重隐私的数字语音助手)的前两篇文章中,我介绍了语音助手的背景以及 Mycroft 的一些核心原则。在第 3 部分中,我开始概述 Python 代码,这些代码是为一个技能提供一些基本功能所必需的,该技能可以将物品添加到 OurGroceries(一款购物清单应用)中。在第 4 部分中,我讨论了不同类型的意图解析器(以及何时使用每种解析器),并扩展了 Python 代码,以便 Mycroft 在处理技能时可以提供听觉反馈。

在第五篇文章中,我将介绍构建此技能所需的其余部分。我将讨论项目依赖项、用于调试目的的日志输出、使用 Mycroft Web UI 设置值(例如用户名和密码),以及如何将此信息输入到你的 Python 代码中。

处理项目依赖项

在编写 Mycroft 技能时,项目依赖项通常有三个来源

  • 来自 PyPI 的 Python 包
  • 从存储库中提取的系统级包
  • 其他 Mycroft 技能

在 Mycroft 中处理依赖项有几种方法。你可以使用“requirements”文件,也可以使用 manifest.yml 文件。

由于 Mycroft 商店中的大多数技能都使用 requirement 文件,我将仅简单介绍一下 manifest.yml 文件。manifest.yml 文件非常简单明了。其中有一个 dependencies: 部分, 在此部分下有三个选项:python:system:skill:。在每个标题下,你应该指定所需依赖项的名称。一个示例文件可能如下所示

dependencies:
   # Pip dependencies on PyPI
   python:
     - requests
     - gensim

   system:
     # For simple packages, this is all that is necessary
     all: pianobar piano-dev

   # Require the installation of other skills before installing this skill
   skill:
     - my-other-skill

但是,由于大多数技能都使用 requirement 文件,因此我将在此项目中使用该选项,以便你可以将其用作其他你可能希望使用或创建的技能的示例。

在 Python 中,requirements.txt 文件非常常见,它 列出了项目所需的所有 Python 依赖项。此文件非常简单;它可以是包列表,也可以是带有特定版本的列表。我将使用一些我提交给 ourgroceries 项目的代码来指定最低版本。此项目的 requirements.txt 有三个选项

  • ourgroceries==1.3.5:指定包必须是 1.3.5 版本
  • ourgroceries>=1.3.5:指定包必须是 1.3.5 或更高版本
  • ourgroceries:允许任何版本的包

我的 requirements.txt 使用 ourgroceries>=1.3.5 以允许未来的更新。按照相同的逻辑,你的 requirements.txt 可以列出不同的包,而不是指定单个包。

我的 requirements.txt 文件的全部内容只有一行

ourgroceries>=1.3.5

你也可以选择使用 requirements.sh。这是一个 shell 脚本,可用于安装包、从 Git 下载模块或执行任意数量的操作。此文件在安装新技能时执行。Zork 技能有一个 requirements.sh 脚本的示例。但是,虽然你可以使用它,但如果你想将你的技能提交到商店,则会对 requirements.sh 进行相当严格的审查,以减轻安全问题。

调试你的技能

有几种方法可以调试你的技能。你可以使用 Mycroft 日志记录器,也可以使用标准的 Python 调试工具。这两种方法都在 Mycroft 命令行界面 (CLI) 中可用,这对于调试非常方便。

使用 Mycroft 日志记录器

要开始使用 Mycroft 日志记录器,你只需要导入 MycroftSkill 因为 logger 是基类的一部分。这意味着只要你在技能的类内部工作,logger 就可以使用。例如,以下代码演示了如何创建一个带有日志条目的非常基本的技能

from mycroft import MycroftSkill

class MyFakeSkill(MycroftSkill):
		def __init__(self):
    		self.log.info("Skill starting up")

def create_skill():
		return MyFakeSkill()

Logger 具有你可能期望的所有日志级别

  • debug: 提供最高级别的详细信息,但默认情况下记录
  • info: 在技能按预期运行时提供一般信息;它始终被记录
  • warning: 表示有些问题,但不是致命的
  • error: 致命问题;它们在 CLI 中以红色显示
  • exception: 类似于错误,但它们包含堆栈跟踪

除了在 CLI 中显示外,logger 还会写入 skills.log。文件的位置因你安装 Mycroft 的方式而异。常见的位置是 /var/log/mycroft/skills.log~/snap/mycroft/common/logs/skills.log/var/opt/mycroft/skills.log

有时你可能想在实例化的类之外使用 Mycroft 日志记录器。例如,如果你在类外部定义了一些全局函数,则可以专门导入 LOG

from mycroft import MycroftSkill
from mycroft.util import LOG

def my_global_funct():
		LOG.info("This is being logged outside the class")

class MyFakeSkill(MycroftSkill):
		def __init__(self):
    		self.log.info("Skill starting up")

def create_skill():
		return MyFakeSkill()

使用 Python 的调试工具

如果你想要更突出的东西,你可以使用内置的 Python print() 语句进行调试。我发现有时 Mycroft 日志记录器产生输出的速度很慢。在其他时候,我只是想要一些在视觉上能立即引起我注意的东西。在任何一种情况下,当我在 IDE 之外进行调试时,我都更喜欢使用 print() 语句。

以以下代码为例

if category_name is None:
    self.log.info("---------------> Adding %s to %s" % (item_to_add, list_name))
    print("-------------> Adding %s to %s" % (item_to_add, list_name))

这会在 mycroft-cli-client 中产生以下输出

~~~~ings:104 | Skill settings successfully saved to /opt/mycroft/skills/fallback-wolfram-alpha.mycroftai/settings.json
~~~~1 | mycroft.skills.mycroft_skill.mycroft_skill:handle_settings_change:272 | Updating settings for skill AlarmSkill
~~~~save_settings:104 | Skill settings successfully saved to /opt/mycroft/skills/mycroft-alarm.mycroftai/settings.json
 10:50:38.528 | INFO     | 51831 | ConfigurationSkill | Remote configuration updated
 10:50:43.862 | INFO     | 51831 | OurGroceriesSkill | ---------------> Adding hot dogs to my shopping
---------------> Adding hot dogs to my shopping
~~~~7.654 | INFO     | 51831 | mycroft.skills.skill_loader:reload:108 | ATTEMPTING TO RELOAD SKILL: ourgroceries-skill
~~~~831 | mycroft.skills.skill_loader:_execute_instance_shutdown:146 | Skill ourgroceries-skill shut down successfully

我发现,当文本滚动时,更容易在视觉上识别没有其他消息的统一标题的 print 语句。这纯粹是个人偏好,并不意味着对编程最佳实践的任何形式的建议。

从用户获取输入

既然你已经知道如何查看技能的输出,现在是时候从你的用户那里获取一些特定于环境的信息了。在许多情况下,你的技能需要一些用户信息才能正常运行。大多数时候,这是用户名和密码。通常,技能需要此信息才能正确初始化。

使用联网的 Mycroft 获取用户输入

如果你的 Mycroft 设备连接到互联网,你可以使用 Mycroft 的 Web UI 输入用户信息。登录 https://account.mycroft.ai 并导航到 skills 部分。正确配置技能后,你将看到类似这样的内容

Mycroft Web UI

opensource.com

在这里,你可以发现哪些设备安装了你的技能。在我的例子中,有两台设备:Arch Pi4Asus。还有输入文本框用于从用户获取信息。

如果你配置了 Mycroft 的设置文件,则会自动创建此界面。你有两种文件类型选择:你可以创建 settingsmeta.yamlsettingsmeta.json。我更喜欢 YAML 语法,所以这就是我用于此项目的内容。这是我为此技能的 settingsmeta.yaml

skillMetadata:
  sections:
  - name: OurGroceries Account
    fields:
    - type: label
      label: "Provide your OurGroceries username/password and then Connect with the button below."
    - name: user_name
      type: text
      label: username
      value: ''
    - name: password
      type: password
      label: Ourgroceries password
      value: ''
    - name: default_list
      type: text
      label: Default Shopping List
      value: ''

此文件的结构非常容易理解。每个文件都必须以 skillsMetadata 标题开头。接下来,有一个 sections 标题。每个新部分都由 - name: 表示,这是 YAML 语法中列表中的项目。上面,只有一个名为 OurGroceries Account 的部分,但你可以根据需要设置任意多个部分。

字段用于传递和存储信息。字段可以像标签一样简单,它可以向用户提供说明。然而,对于此技能来说,更有趣的是 textpassword 字段。文本字段允许用户查看他们正在键入的内容,并以纯文本形式显示。这适用于非敏感信息。密码字段并非专门用于密码,而是旨在隐藏敏感信息。在用户输入信息并单击 save 按钮后,Mycroft 会替换技能首次初始化时创建的 settings.json 文件。新文件包含用户在 Web UI 中输入的值。技能还将使用此文件来查找凭据和其他信息。如果你在使用技能中的正确值时遇到问题,请查看 settings.json 文件,以了解变量的正确命名以及值是否存储在 JSON 文件中。

使用离线 Mycroft 获取用户输入

正如你可能已经猜到的,在没有互联网连接的情况下,更难从最终用户那里接收信息。只有少数 选项。首先,你可以编写你的技能,使其在首次运行时提示用户输入技能所需的信息。然后,如果你希望使用内置设置解析器,你可以将其写入 settings.json,或者你可以将其写入你选择的文件,并且你的技能可以处理解析。请注意,如果你写入 settings.json,则如果 Mycroft 重新初始化你的技能,则此文件可能会被覆盖。

另一种方法是在 settings.json 或与项目一起存储的另一个文件中使用静态值。这有一些明显的安全隐患,但如果你的存储库是安全的,这是一个可行的选择。

第三个也是最后一个选项是允许用户直接编辑文件。这可以通过网络文件系统 (NFS) 或 Samba 文件共享协议来完成,或者你可以简单地授予安全 shell (SSH) 用户的适当权限,该用户可以使用任何 Unix 编辑器进行更改。

由于此项目需要访问互联网,因此我将不探讨这些选项。如果你有疑问,可以随时在 Mattermost 上与社区互动。

从你的技能访问设置

如果链中的其他部分正常工作(即,用户通过 Web UI 更新了他们的设置,并且 Mycroft 基于这些设置更新了 settings.json),则使用用户提供的设置很容易理解。

正如我在第三篇文章(我在其中讨论了 __init__initialize 方法)中提到的,不可能使用 __init__(self) 方法从 settings.json 中检索值。因此,你必须使用另一种方法来处理设置。在我的例子中,我创建了一个适当命名的 _create_initial_grocery_connection 方法

def _create_initial_grocery_connection(self):
    """
    This gets the username/password from the config file and gets the session cookie
    for any interactions
    :return: None
    """
    self.username = self.settings.get('user_name')
    self.password = self.settings.get('password')
    self.ourgroceries_object = OurGroceries(self.username, self.password)
    asyncio.run(self.ourgroceries_object.login())

正如你所看到的,你可以通过使用 self.settings.get()settings.json 中提取信息。唯一需要注意的是,你传入的值必须settingsmeta.yaml 中的名称匹配。在这种情况下,因为我没有在此方法之外使用用户名或密码,所以我可以选择不将这些变量作为类范围的一部分(即,我可以将它们称为 password 而不是 self.password)。这是因为我正在将 ourgroceries_object 设置为类范围,并且它包含技能的其余部分运行所需的所有信息。

总结

语音助手正在扩展到一个数百万美元(如果不是数十亿美元)的业务,一些分析师认为,未来几年,大多数家庭将拥有一台(或多台)。鉴于苹果、谷歌、Facebook 等公司因侵犯隐私而频频登上新闻头条,更不用说不断报告的数据泄露事件,因此拥有一个开源、注重隐私的替代方案来取代大型公司非常重要。Mycroft 将你的隐私放在首位,其规模虽小但敬业的贡献者团队正在语音助手最常见的应用场景中取得进展。

本系列深入探讨了技能开发的细节,讨论了在开始之前仔细思考并制定良好大纲的重要性。了解你在大方向上的目标有助于你组织代码。将任务分解为各个部分也是你策略的关键部分。有时,最好在 Mycroft 技能环境之外编写一些片段或重要部分,以确保你的代码能够按预期工作。这不是必需的,但对于刚接触技能开发的人来说,可能是一个很好的起点。

本系列还探讨了意图解析器以及如何理解何时使用每种解析器。PadatiousAdapt 解析器各有优缺点。

  • Padatious 意图依赖于短语以及这些短语中的实体来理解用户想要完成什么,它们通常是 Mycroft 技能的默认用法。
  • 另一方面,Adapt 使用正则表达式来实现类似的目标。当你需要 Mycroft 具有上下文感知能力时,Adapt 是唯一的选择。它也非常擅长解析复杂的语句。但是,在使用正则表达式时,你需要格外小心,否则最终可能会得到意想不到的结果。

我还介绍了处理项目的基础知识。这是复杂技能开发中的重要一步,以确保技能具有所有正常工作所需的依赖项。确保最大的可移植性对于技能至关重要,而依赖项解析是其中的关键部分,因为你的技能在依赖项未满足的情况下可能无法正常工作。

最后,我解释了如何从用户那里获取技能特定的设置,无论设备是否连接到互联网。你选择哪种方法实际上取决于你的用例。

虽然我的目的不是提供 Mycroft 技能开发的百科全书,但通过学习本系列,你应该为开发大多数你想创建的技能打下非常坚实的基础。我希望本系列中的具体示例将向你展示如何处理你在技能开发期间可能想要完成的大多数任务。我没有逐行讲解整个技能,但如果你想进一步探索,代码托管在 GitLab 上。欢迎提出评论和问题。作为一名刚起步的 Mycroft 开发人员,我仍然在不断学习和成长,所以请在 TwitterMycroft Mattermost 实例上联系我,让我们一起学习!

接下来阅读
User profile image.
Steve 是一位敬业的 IT 专业人士和 Linux 倡导者。在加入红帽之前,他曾在金融、汽车和电影行业工作多年。Steve 目前在红帽公司担任解决方案和技术实践部门的架构师。他拥有从 RHCA(DevOps 领域)到 Ansible,再到容器化应用程序等各种认证。

1 条评论

我迫不及待地想制作自己的 Mycroft 技能。谢谢你的文章!

知识共享许可协议本作品根据知识共享署名-相同方式共享 4.0 国际许可协议获得许可。
© 2025 open-source.net.cn. All rights reserved.