ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Mycroft Core 技能开发 API 全景指南:从 MycroftSkill 基类到 util 工具库

Mycroft Core 技能开发 API 全景指南:从 MycroftSkill 基类到 util 工具库
  • 人工智能
  • 语音
  • 交互助手
  • 智能硬件

【免费下载链接】mycroft-core

Mycroft Core, the Mycroft Artificial Intelligence platform.

项目地址:https://gitcode.com/gh_mirrors/my/mycroft-core
点击查看免费下载

本篇技术指南以 Mycroft Core 官方 API 文档 doc/source/mycroft.rst 为骨架,系统梳理开发 Mycroft 技能(Skill)所需的全部核心 Python API:技能基类MycroftSkill与四类通用技能抽象(CommonIoT / CommonPlay / CommonQuery / Fallback)、意图注册与上下文装饰器、音频控制、文件系统沙箱,以及util下的日志、播放、解析、格式化与时间工具。读完本文,你将能够对照源码定位每个 API 的真实实现,并直接用它编写、调试与本地化自己的 Mycroft 技能。

一、文档定位:一份面向技能开发者的公开 API 索引

doc/source/mycroft.rst是 Mycroft Core 使用 Sphinx 自动生成 API 参考的入口页面,它按功能域将整个mycroft包拆成两大板块:

  • mycroft.skills:技能开发的最核心命名空间,涵盖技能基类、通用技能抽象类、音频服务与意图/上下文装饰器;
  • mycroft.audio/mycroft.filesystem/mycroft.util(含 log、parse、format、time):支撑技能运行的基础设施模块。

该文档大量使用.. autoclass::与.. autofunction::指令,即 API 文档内容直接取自源码 docstring。因此本文在解读 API 的同时,会逐一给出对应的源码文件位置,让你可以「从文档跳转到实现」。

二、mycroft.skills:技能系统的六大核心类

文档开篇列出六个通过autoclass导出的类,它们全部可以从顶层mycroft包或mycroft.skills子包导入。顶层包 mycroft/init.py 的__all__中导出了MycroftSkill、FallbackSkill、intent_handler、intent_file_handler、adds_context、removes_context、AdaptIntent等,确认了文档与导出的一致性。

1. MycroftSkill:所有技能的共同基类

MycroftSkill定义于 mycroft/skills/mycroft_skill/mycroft_skill.py,构造签名与核心成员如下:

class MycroftSkill: def __init__(self, name=None, bus=None, use_settings=True):
  • name:技能名,缺省取类名self.__class__.__name__;
  • bus:可选的 messagebus WebSocket 客户端连接;
  • use_settings:设为False可完全关闭技能设置(settings)机制。

实例化后自动建立的成员包括:

成员含义
self.root_dir技能根目录绝对路径,由模块文件位置推断(如/opt/mycroft/skills/my-skill.me/)
self.guiSkillGUI对象,用于驱动 Mark 1 / Mark 2 等设备的 GUI 显示
self.config_core全局配置Configuration.get()的字典快照
self.settings/self.settings_write_path技能私有设置及写回路径
self.settings_change_callback设置变更回调,技能可赋值以响应远端设置更新
self.dialog_renderer对话渲染器,由init_dialog()装载dialog/<lang>或locale/<lang>目录

技能开发中最高频的方法集中在同一文件内:

  • speak(utterance, expect_response=False, wait=False, meta=None)(L1216):通过bus.emit(Message("speak", ...))发出 TTS 请求;expect_response=True会让 Mycroft 说完立即进入聆听状态,wait=True则阻塞直到播报结束(内部调用wait_while_speaking())。源码同时会通过enclosure.register(self.name)把技能注册为活跃技能。
  • speak_dialog(key, data=None, ...)(L1243):从locale/<lang>/<key>.dialog对话文件中随机取一句渲染后说出;若 dialog 目录缺失会回退为直接speak(key)并打出警告。
  • register_intent(intent_parser, handler)(L989):注册 Adapt 意图。IntentBuilder会被自动build();若传入的是以.intent结尾的字符串则转交register_intent_file;其余类型必须是adapt.intent.Intent实例。
  • register_intent_file(intent_file, handler)(L1018):注册 Padatious 意图文件。docstring 中给出了标准写法,例如food.order.intent:
Order some {food}. Order some {food} from {place}. I'm hungry. Grab some {food} from {place}.

也支持用括号表达可选/变体,如(Order | Grab) some {food} (from {place} | ),并可配合register_entity_file()补充{food}、{place}的候选值。

  • get_response(dialog='', data=None, validator=None, on_fail=None, num_retries=-1)(L446):向用户提问并等待回答。validator是def validator(utterance) -> bool形式的校验函数;on_fail可以是对话 key 或返回提示语的函数;num_retries=-1表示无限重试(用户可随时说 "cancel" 或超时中止)。配套的ask_yesno(prompt, data=None)会自动处理 "yeah / sure" 等肯定变体,返回'yes'/'no'/ 其他原话或None(L547-L565)。
  • schedule_event/schedule_repeating_event/cancel_scheduled_event等:基于EventSchedulerInterface的定时任务接口。
  • set_context(context, word='', origin='')/remove_context(context):直接操纵 Adapt 上下文管理器。

2. FallbackSkill:兜底技能

FallbackSkill同样由顶层包导出,实现在 mycroft/skills/fallback_skill.py,核心 API 为:

  • register_fallback(handler, priority):注册兜底处理器。当常规意图全部匹配失败时,按优先级从高到低依次尝试兜底技能,适合实现「帮我查一下」「随机播放」这类无固定意图的请求;
  • remove_fallback(handler_to_del)/remove_instance_handlers():注销处理器,常用于技能shutdown()阶段。

3. CommonIoTSkill:物联网统一接入抽象

实现在 mycroft/skills/common_iot_skill.py,文档以:show-inheritance:标注其继承关系。它把「动作(Action)+ 事物(Thing)+ 属性(Attribute)」抽象为IoTRequest,技能开发者需要实现:

  • supported_request_version() -> IoTRequestVersion:声明支持的协议版本;
  • get_entities() -> [str]/get_scenes() -> [str]:向系统注册可用的实体与场景;
  • can_handle(request) -> bool:判断本技能是否能处理某请求;
  • run_request(request, callback_data) -> None:真正执行设备控制逻辑。

请求会通过消息总线分发(内部_handle_trigger/_run_request),并自动为请求附加跟踪上下文。

4. CommonPlaySkill:通用媒体播放抽象

实现在 mycroft/skills/common_play_skill.py,用于让不同音频技能(如 Mopidy、VLC 后端)响应「播放某首歌/某个电台」这类跨技能请求。核心回调:

  • CPS_match_query_phrase(phrase):返回(media_type, confidence, callback_data)三元组,confidence是 0~1 的匹配置信度,系统会取所有技能中置信度最高者;
  • CPS_start(phrase, data):开始播放;
  • CPS_play(*args, **kwargs):继续播放(如从暂停恢复);
  • CPS_send_status(...)/CPS_send_tracklist(tracklist):向 GUI 推送播放状态与播放列表;
  • stop():停止并清理播放状态。

其底层通过mycroft.audio.service.play/queue/stop等总线消息与音频子系统协作,__calc_confidence负责按匹配层级计算置信度。

5. CommonQuerySkill:通用问答抽象

实现在 mycroft/skills/common_query_skill.py,用于「谁唱了这首歌」「现在几点了」这类问答型请求的聚合。开发者实现:

  • CQS_match_query_phrase(phrase):返回(confidence, answer_data);
  • CQS_action(phrase, data):执行后续动作(如朗读答案、打开页面)。

系统通过__handle_question_query汇总各技能的置信度后择优选答,remove_noise()会先剥离疑问句中的无意义词汇(如 "please tell me")。

6. AudioService:技能侧音频控制

实现在 mycroft/skills/audioservice.py,是技能向音频子系统发指令的客户端门面。它接收一个bus连接,所有方法都通过消息总线与mycroft.audio服务通信:

方法总线消息说明
queue(tracks)mycroft.audio.service.queue将曲目加入播放队列,tracks可为 uri 字符串或(uri, mime)元组
play(tracks, utterance, repeat)mycroft.audio.service.play开始播放,repeat=True循环
stop()/next()/prev()mycroft.audio.service.stop/next/prev停止、切歌、回退
pause()/resume()mycroft.audio.service.pause/resume暂停 / 恢复
seek(seconds)seek_forward/seek_backward快进/快退,负数自动转为回退
track_info()track_info+track_info_reply同步等待当前曲目信息,超时 1 秒返回{}
available_backends()list_backends查询可用音频后端
is_playing(属性)基于track_info()播放中返回True

注意ensure_uri()的路径处理:普通路径会被自动补全为file://绝对 URI;已含://的字符串原样保留;(uri, mime)元组同样被处理;非法类型抛ValueError。

三、四个装饰器:意图与上下文的关键入口

文档列出的四个autofunction装饰器中,意图相关两个实现在 mycroft/skills/mycroft_skill/decorators.py,上下文相关两个实现在 mycroft/skills/context.py,全部由顶层mycroft包再导出。

1.intent_handler(intent_parser)

@intent_handler(IntentBuilder('WeatherIntent') .require('WeatherKeyword') .optionally('Location')) def handle_weather(self, message): ...

实现要点(decorators.py L18-L29):装饰器并不立即注册意图,而是把intent_parser追加到函数的func.intents列表中;技能加载时MycroftSkill._register_decorated()会遍历这些列表统一调用register_intent完成注册。因此一个处理函数可以叠加多个@intent_handler。

2.intent_file_handler(intent_file)

@intent_file_handler('food.order.intent') def handle_order(self, message): ...

与intent_handler机制相同,只是把文件路径存入func.intent_files,最终由register_intent_file注册。需要说明的是,源码 docstring 明确标注该装饰器deprecated:现在直接用intent_handler('food.order.intent')传入.intent文件路径即可获得同等效果(register_intent内部会自动识别.intent后缀并转交文件注册)。

3.adds_context(context, words='')

@adds_context('OrderingFood') def handle_order(self, message): ...

来自 mycroft/skills/context.py:方法执行成功后,自动调用args[0].set_context(context, words)把上下文关键词注入 Adapt 上下文管理器,让后续省略了主语/宾语的追问(如「要加辣吗」)仍能命中同一技能。

4.removes_context(context)

@removes_context('OrderingFood') def handle_order_cancel(self, message): ...

方法执行成功后调用args[0].remove_context(context)清除指定上下文,用于在对话流程结束时释放语境。

四、mycroft.audio:语音播放状态控制

文档通过 doc/source/mycroft.audio.rst 引入mycroft.audio模块的三个核心函数,实现在 mycroft/audio/utils.py,并从 mycroft/audio/init.py 导出:

  • is_speaking():返回布尔值,True表示 TTS 仍在播报。底层实现是check_for_signal("isSpeaking", -1),即检查 IPC 信号目录中的isSpeaking标志,因此不依赖总线往返,性能开销极低。
  • wait_while_speaking():先time.sleep(0.3)等待排队的播报真正开始,再以 0.1 秒间隔轮询is_speaking()直到结束。MycroftSkill.speak(wait=True)正是复用它实现阻塞播报。
  • stop_speaking():若正在播报,则通过send('mycroft.audio.speech.stop')总线消息请求停止,并阻塞轮询至播报确实终止。源码 TODO 注释也指出:目前技能可停止任意播报,未来应限制为「只能停止自己发起的播报」。

五、mycroft.filesystem:FileSystemAccess 沙箱

文档指向 doc/source/mycroft.filesystem.rst,核心类FileSystemAccess实现在 mycroft/filesystem/init.py,意图是给每个技能一个隔离的命名空间目录,防止技能之间互相读写文件。

fs = FileSystemAccess('myskill') # 构造时即创建命名空间目录 handle = fs.open('config.json', 'w') # 在命名空间内打开文件 fs.exists('config.json') # 检查文件是否存在

实现细节:

  • 构造时把传入的path映射到 XDG 配置目录xdg.BaseDirectory.save_config_path('mycroft')/<path>;若旧位置~/.mycroft/<path>存在会自动迁移(源码中有 TODO 注明该迁移将在 22.02 移除);
  • open(filename, mode)与exists(filename)都只接受相对文件名,不支持子目录,从设计上限制了越界访问;
  • path为空或非字符串时抛ValueError("path must be initialized as a non empty string")。

MycroftSkill初始化时会为每个技能创建对应的FileSystemAccess实例,技能可通过self.file_system(或类似成员)读写自己的私有数据。

六、mycroft.util:技能开发的常备工具

doc/source/mycroft.util.rst 明确说明:该包汇集了播放音频、解析/生成自然语言文本、缓存目录查询、路径解析等技能开发高频操作。以下函数由 mycroft/util/init.py 统一导出。

1. LOG:随调用位置自动命名的日志器

LOG定义于 mycroft/util/log.py,是一个行为类似logging.Logger的类级日志器。它的特性是日志名自动取调用者的模块与行号:

LOG.debug('My message: %s', debug_str) # 输出: 13:12:43.673 - :<module>:1 - DEBUG - My message: hi LOG('custom_name').debug('Another message') # 输出: 13:13:10.462 - custom_name - DEBUG - Another message

支持debug / info / warning / error / exception五个级别方法。默认日志级别与输出格式只能在配置文件~/.config/mycroft/mycroft.conf(或/etc/mycroft/mycroft.conf)中设置:log_level控制级别(默认INFO),log_format覆盖输出格式(默认{asctime} | {levelname:8} | {process:5} | {name} | {message})。LOG.init()会在导入mycroft包时自动执行以读取配置。

2. play_wav / play_mp3 / play_ogg:后台播放音频

三个函数实现在 mycroft/util/audio_utils.py,共同特征是立即返回、后台播放(返回subprocess.Popen对象,失败返回None),播放器命令行来自配置:

  • play_wav(uri)→ 使用config['play_wav_cmdline']
  • play_mp3(uri)→ 使用config['play_mp3_cmdline']
  • play_ogg(uri)→ 使用config['play_ogg_cmdline']

命令行中的%1会被替换为实际 uri(_play_cmd的实现)。此外还有按扩展名自动分发的play_audio_file(uri),以及录音用的record(file_path, duration, rate, channels)(底层调用arecord)和find_input_device(device_name)。播放子进程会注入PULSE_PROP=media.role=music环境变量,以便与 TTS 角色区分(源码注释说明这可用于电话角色下的音频闪避)。

3. resolve_resource_file:资源路径解析

实现在 mycroft/util/file_utils.py。给定形如snd/beep.wav或path/filename.ext的资源名,按以下顺序查找并返回第一个存在的绝对路径:

  1. 直接可用的完整文件路径(如用户配置指定的绝对路径);
  2. $XDG_DATA_DIRS/mycroft/<res_name>(默认~/.local/share/mycroft/...);
  3. 旧位置~/.mycroft/<res_name>;
  4. config['data_dir']/res/<res_name>(默认/opt/mycroft/res/...);
  5. 源码包内mycroft/res/<res_name>(即仓库 mycroft/res 目录,如snd/acknowledge.mp3)。

全部找不到则返回None。MycroftSkill.acknowledge()播放确认音正是用resolve_resource_file定位sounds.acknowledge音频文件。

4. get_cache_directory:缓存目录

实现在 mycroft/util/file_utils.py。返回缓存根目录(优先取配置cache_path,否则get_temp_path('mycroft', 'cache')即/tmp/mycroft/cache),domain参数作为子目录用于隔离不同用途的缓存。配套函数curate_cache(directory, min_free_percent=5.0, min_free_disk=50)会在磁盘可用百分比低于min_free_percent且可用空间低于min_free_diskMB 时,按修改时间从旧到新删除文件释放空间。由于缓存目录可能位于小容量 RAM 盘且随时可能被清空,依赖缓存数据的代码必须能回退重建。

5. 其他值得关注的工具

mycroft/util/__init__.py还批量导出了:

  • read_stripped_lines/read_dict/create_file/get_temp_path:文件与临时路径工具;
  • connected():网络连通性检测;
  • check_for_signal/create_signal/get_ipc_directory:IPC 信号机制(is_speaking()依赖它);
  • create_daemon/reset_sigint_handler/start_message_bus_client:进程管理工具;
  • get_arch():平台架构识别。

七、mycroft.util.parse:从自然语言提取结构化数据

doc/source/mycroft.util.parse.rst 列出了 8 个解析函数。模块 docstring(mycroft/util/parse.py)说明:实际解析工作由 lingua-franca 库完成,本模块针对 Mycroft 技能场景做包装与默认语言注入。函数清单:

函数用途
extract_datetime(text, anchorDate="DEFAULT", lang=None, default_time=None)从句子中提取日期时间
extract_duration(text, lang=None)提取时长(如 "5 minutes")
extract_number(text, lang=None)/extract_numbers(...)提取单个/多个数字
get_gender(text, lang=None)判断性别词汇
normalize(text, lang=None)文本归一化(去标点、小写化等)
fuzzy_match(x, against, lang=None)模糊匹配评分
match_one(x, arr, lang=None)从候选列表中返回最佳匹配(confidence, item)

以extract_datetime为例(L65-L128),它解析 "tomorrow"、"Tuesday"、"5 days from today" 等相对日期,并对模糊时段赋默认值:morning = 8 AM、afternoon = 3 PM、evening = 7 PM;未提供时间时默认 12 AM。返回值是[datetime, leftover_string]元组,leftover_string为剔除时间关键词后的剩余文本;解析不到任何时间信息时返回None:

>>> extract_datetime("What is the weather like the day after tomorrow?", ... datetime(2017, 6, 30, 0, 0)) [datetime.datetime(2017, 7, 2, 0, 0), 'what is weather like'] >>> extract_datetime("Set up an appointment 2 weeks from Sunday at 5 pm", ... datetime(2016, 2, 19, 0, 0)) [datetime.datetime(2016, 3, 6, 17, 0), 'set up appointment']

anchorDate缺省时使用now_local()(即用户配置时区的当前时间);传入None会触发 DeprecationWarning。若指定语言不在 lingua-franca 支持列表,会通过_log_unsupported_language打印告警并列出全部支持语言。

八、mycroft.util.format:把数据格式化为人性化表达

doc/source/mycroft.util.format.rst 列出 9 个格式化函数,模块 docstring(mycroft/util/format.py)强调其目标是生成「可被人类消化」的内容(语音或屏幕显示),并支持本地化。函数清单:

函数用途
join_list(items, sep, lang=None)把列表按语言习惯连接成自然语句
nice_date(dt, lang=None)/nice_date_time(...)/nice_time(...)/nice_year(...)日期/时间/年份的友好格式化
nice_number(num, lang=None)/pronounce_number(...)数字的显示与朗读形式
nice_duration(duration, ...)秒数/timedelta→ 时长文本
nice_duration_dt(date1, date2, ...)两个datetime之间的时长文本

nice_duration与nice_duration_dt共用内部实现_duration_handler(L62-L299),参数最为丰富:

  • speech=True输出口语("two minutes forty three seconds"),False输出显示格式(2:43);
  • use_years=True输出年+天,False只输出总天数;
  • clock=True强制输出数码时钟样式(1:00),对 DAYS/YEARS 分辨率无效;
  • resolution为TimeResolution枚举(YEARS/DAYS/HOURS/MINUTES/SECONDS/MILLISECONDS),作为输出精度的下限;nice_duration只有传入 MILLISECONDS 才会产出毫秒,nice_duration_dt不支持毫秒(静默回退到 SECONDS)。

示例行为:

nice_duration(60) # 60 秒 # → speech: "one minute";display: "1:00" nice_duration(163) # → speech: "two minutes forty three seconds";display: "2:43" nice_duration_dt(datetime(2019, 3, 12), datetime(2019, 1, 1)) # → "seventy days"

实现细节上,_duration_handler会区分输入类型:两个datetime相减得到timedelta并自动处理闰年天数(leapdays);float秒数会拆出小数部分作为毫秒;整型会先转为timedelta。当speech=False且结果为空时会回退为"0"/"0m"/"0:00"等零值表达。

九、mycroft.util.time:本地/系统/UTC 时间处理

doc/source/mycroft.util.time.rst 将mycroft.util.time描述为「处理本地、系统与全局时间」的函数集合,实现在 mycroft/util/time.py。该模块的时区基准不是操作系统时区,而是Mycroft 配置中用户的位置设置:

  • default_timezone():优先取配置location.timezone.code(如America/Chicago,也支持location.timezone.name与offset),取不到则回退系统时区tzlocal();
  • now_utc():当前 UTC 时间(等价 GMT);
  • now_local(tz=None):当前用户本地时间,缺省用default_timezone();
  • to_utc(dt):带时区信息的时间转 UTC(naive datetime 先按 UTC 处理再转换);
  • to_local(dt):任意时间转用户本地时区(naive 输入视为 UTC);
  • to_system(dt):转操作系统时区。

这套工具的意义在于:即使设备系统时区与实际用户不符,extract_datetime、nice_date_time等解析/格式化函数仍能基于用户配置的时区保持一致体验。mycroft.util.parse.extract_datetime缺省锚点now_local()正是来自此模块。

十、配套文档与测试:继续深入的方向

mycroft.rst通过toctree指令引用了 7 份配套 API 文档,对应关系如下,可供继续查阅:

  • doc/source/mycroft.audio.rst —— 音频状态控制三函数
  • doc/source/mycroft.filesystem.rst ——FileSystemAccess
  • doc/source/mycroft.util.rst —— util 常用函数
  • doc/source/mycroft.util.log.rst ——LOG模块
  • doc/source/mycroft.util.parse.rst —— 解析函数
  • doc/source/mycroft.util.format.rst —— 格式化函数
  • doc/source/mycroft.util.time.rst —— 时间函数

若想验证上述 API 的真实行为,仓库自带测试是最佳佐证:技能类的行为可参考 test/unittests/skills/test_mycroft_skill.py、test/unittests/skills/test_common_play_skill.py、test/unittests/skills/test_common_query_skill.py 与 test/unittests/skills/test_fallback_skill.py;工具函数的测试覆盖在 test/unittests/util/test_parse.py、test/unittests/util/test_format.py、test/unittests/util/test_time.py、test/unittests/util/test_file_utils.py 与 test/unittests/util/test_log.py 中。结合这些测试阅读,可以快速理解每个函数的边界行为与本地化处理。

结语

mycroft.rst虽然只是一页 API 索引,但它精准勾勒了 Mycroft 技能开发的全部公共编程面:以MycroftSkill为基类、四个装饰器声明意图与上下文、四类通用技能抽象应对 IoT / 播放 / 问答 / 兜底场景,再辅以audio、filesystem、util三块基础设施完成语音交互、持久化与文本处理。开发新技能时,从本文的任一章节定位到对应源码与测试,即可获得最权威的行为定义。

  • 人工智能
  • 语音
  • 交互助手
  • 智能硬件

【免费下载链接】mycroft-core

Mycroft Core, the Mycroft Artificial Intelligence platform.

项目地址:https://gitcode.com/gh_mirrors/my/mycroft-core
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进