为已经拥有几乎一切的亲戚找到有意义的礼物可能很困难。我和我的妻子给我们的父母送过“体验”礼物,让他们尝试一些新奇的东西,例如去主题餐厅或看音乐会,但随着我们的父母年龄越来越大,这变得更加困难。今年也不例外——直到我想到了开源可以给他们带来一些真正特别的东西。
如果他们向人工智能 (AI) 语音助手(例如 Mycroft)请求帮助时,我的岳父母可以获得特别的问候语呢?我查看了现有的语音助手 API,看看是否已经存在类似的东西。有一些接近,但并不完全是我想要的。我的想法是录制他们的曾孙/曾孙女的一段简短问候语,每当他们按下按钮时,在与语音助手开始对话之前播放。问候语会是这样的:
“早上好,Nana 和 Poppy。今天是 12 月 25 日。现在是下午 3:10。Waynesboro 目前的气温是 47 度。Ocean City 目前的气温是 50 度。”
当他们按下按钮时,我的岳父母会听到他们的曾孙/曾孙女报告他们家和他们最喜欢的度假胜地的日期、时间和温度。为了实现这一点,我必须解决一些问题。
太多的音频文件了……
第一个问题是弄清楚语音助手需要说什么短语。考虑到我需要涵盖的所有日期、时间和温度,我列出了 79 个短语的列表。我把这些说明发给了我的侄女们
请录制孩子们说下面的每一行。对不起,有这么多。如果这样更容易,可以在一个设置中提示他们。我可以编辑音频文件并处理大多数格式,所以这些都不应该成为问题。只需用你的手机以任何最简单的方式录制即可。
确保孩子们清楚响亮地说出每一行。每行之间应该有一个轻微的停顿,以便于编辑(提示有助于像“跟我重复……”)。这将使我更容易将它们分成单独的声音文件。
每当按下设备上的按钮时,它将以随机的孙子/孙女的声音响应正确的日期/时间/温度,例如
“下午好,Nana 和 Poppy。今天是 1 月 3 日。现在是下午 1:04。Waynesboro 目前的气温是 30 度。Ocean City 目前的气温是 34 度。”
请录制每个孩子用短暂的停顿说出以下短语
然后我提供了以下单词列表供孩子们录制
好 早上 下午 晚上 夜晚 Nana 和 Poppy 时间 上午 一月 |
六月 七月 八月 九月 十月 十一月 十二月 第一 第二 第三 第四 第五 第六 第七 第八 第九 第十 第十一 第十二 第十三 第十四 第十五 第十六 第十七 第十八 第十九 第二十 第三十 零 |
一 二 三 四 五 六 七 八 九 十 十一 十二 十三 十四 十五 十六 十七 十八 十九 二十 三十 四十 五十 六十 七十 八十 九十 百 |
我的侄女们真是双重幸福,有 10 岁以下的孩子和近乎无限的耐心。所以,经过几个月的催促,我收到了每个孩子三分钟的音频文件。
现在我的问题是如何编辑它们。我需要标准化录音,减少噪音,并将它们剪切成单独的单词和短语的音频片段。我还想利用无损音频,我决定将音轨转换为 Waveform Audio File Format (WAV)。Audacity 正是完成所有这些工作的开源工具。
Audacity 来救援!
Audacity 是一款功能丰富的开源声音编辑工具。该软件的功能和能力可能令人难以置信,因此我将描述我为实现目标而遵循的工作流程。我不声称自己是 Audacity 专家,但我遵循的步骤似乎效果很好。(欢迎对如何改进我所做的工作提出意见。)
Audacity 有适用于 Linux、Windows 和 macOS 的下载。我抓取了最新的 macOS 二进制文件并快速将其安装在我的笔记本电脑上。启动 Audacity 会打开一个空的新项目。我使用 导入 功能导入了所有孩子的音频文件。

(Rich Lucente, CC BY-SA 4.0)
标准化音频文件
有些孩子说话比其他孩子更响亮,因此各种音频文件的音量级别不同。我需要标准化音轨,以便无论哪个孩子说话,问候语的音量都相同。为了标准化音量,我首先选择了导入后所有的音轨。

(Rich Lucente, CC BY-SA 4.0)
为了标准化孩子们的峰谷,这样一个孩子不会比另一个孩子更响亮,我使用了 Audacity 的 标准化 效果。

(Rich Lucente, CC BY-SA 4.0)
重要的是要理解标准化和放大效果的作用非常不同。标准化调整多个音轨的最高峰和最低谷,因此它们都是相似的,而放大则夸大了现有的峰谷。如果我使用放大而不是标准化,响亮的孩子会变得更加响亮。我使用默认设置来标准化两个音轨。

(Rich Lucente, CC BY-SA 4.0)
去除背景噪音
我注意到的另一件事是音轨上口语短语之间存在噪音。 Audacity 有工具可以帮助减少背景噪音,从而产生更清晰的音频。为了减少噪音,请选择一个带有背景噪音的音轨样本。我使用 查看->缩放 菜单选项可以更轻松地看到音轨的噪音。

(Rich Lucente, CC BY-SA 4.0)
为了确保我只选择了背景噪音,我使用工具栏中的 播放 按钮收听了选定的音频剪辑。接下来,我选择了 效果->降噪。

<p class="rtecenter"><sup>(Rich Lucente, <a href="https://open-source.net.cn/%3Ca%20href%3D"https://creativecommons.org/licenses/by-sa/4.0/" rel="ugc">https://creativecommons.org/licenses/by-sa/4.0/" target="_blank">CC BY-SA 4.0</a>)</sup></p>
然后我使用 降噪 对话框中的步骤 1 创建了一个 噪音配置文件。

(Rich Lucente, CC BY-SA 4.0)
Audacity 会描述音频样本中的背景噪音,以便可以将其去除。为了去除背景噪音,我通过按下音轨左侧的小 选择 按钮来选择整个音轨。

(Rich Lucente, CC BY-SA 4.0)
我再次应用了 降噪 效果,但这次我在对话框的步骤 2 中按了 确定。我接受了默认设置。

(Rich Lucente, CC BY-SA 4.0)
我对每个孩子的音轨重复了这些步骤,所以我有了标准化的音轨,并且背景噪音已被描述和去除。
将剪辑导出为 WAV 文件
剩下的任务是缩放和滚动每个音轨,并将特定的剪辑导出为 WAV 格式的单独音频文件。当处理一个孩子的音轨时,我需要使用每个音轨左侧的小 静音 按钮来静音其他音轨,或者,由于音轨太多,选择我要处理的音轨的 独奏 按钮。

(Rich Lucente, CC BY-SA 4.0)
选择每个单词和短语可能很棘手,但是能够缩放到音轨中是我的朋友。我试图将每个音频剪辑的开始和结束设置为恰好在说出的单词或短语之前和之后。在导出任何音频剪辑之前,我使用工具栏上的 播放 图标播放选定的剪辑,以确保我获得了所有内容。
有趣的一件事是波形如何映射到口语单词。“six”和“sixth”的波形非常相似,后者在右侧有一个较小的音频波形,用于发出“th”声音。在导出每个剪辑之前,我仔细测试了它,以确保我捕获了完整的单词或短语。
为单词或短语选择音频剪辑后,我使用 文件->导出 菜单导出选定的音频。

(Rich Lucente, CC BY-SA 4.0)
我必须确保使用单词和短语列表中的正确文件名保存每个剪辑。这是因为我用来自定义语音助手的应用程序希望文件名与短语列表中的条目匹配。
下面列出了音频剪辑的预期文件名(不含 .wav 扩展名)。请注意短语中的下划线。 如果您正在进行此项目,请调整粗体文件名以匹配您亲人的昵称和位置偏好。 您还需要在应用程序源代码中进行相同的更改。
good 早上 下午 晚上 夜晚 nana_and_poppy(奶奶和爷爷) the_time(时间) today(今天) the_current_temperature_for(...的当前温度) waynesboro(韦恩斯伯勒) ocean_city(海洋城) 是 和 度 负 上午 下午 january(一月) february(二月) march(三月) april(四月) may(五月) june(六月) july(七月) august(八月) september(九月) october(十月) |
november(十一月) december(十二月) 第一 第二 第三 第四 第五 第六 第七 第八 第九 第十 第十一 第十二 第十三 第十四 第十五 第十六 第十七 第十八 第十九 第二十 第三十 零 一 二 |
三 四 五 六 七 八 九 十 十一 十二 十三 十四 十五 十六 十七 十八 十九 二十 三十 四十 五十 六十 七十 八十 九十 百 |
该项目的 GitHub 存储库还包括一个 Bash 脚本,用于运行作为检查任何丢失或命名错误文件的健全性检查。
在选择每个剪辑的适当名称后,我将剪辑以 WAV 格式文件保存在孩子的特定文件夹(child1、child2 等)中。 我接受了默认导出设置。

(Rich Lucente, CC BY-SA 4.0)
导出所有音频剪辑后,我为每个孩子都创建了一个文件夹,其中完全填充了上述短语的 WAV 文件。 这似乎工作量很大,但每个孩子大约只花费了 90 分钟,而且我处理每个后续音频剪辑的效率都更高。
打包应用程序
既然我已经有了问候语的音频剪辑,我需要考虑应用程序以及如何打包它。 我还想要一个对开源友好的解决方案,该解决方案可以进行修改。
大约两年前,一位同事给了我一个 Google AIY Voice Kit,他从清仓箱里花了 10 美元买的。 这是一个巧妙折叠的盒子,包含扬声器、麦克风和定制电路板。 您提供一个 Raspberry Pi,就可以快速拥有一个自制的 Google 语音助手。 这些套件可以在网上和电子商店购买。 这个小盒子提供了一种打包项目的简单方法。

(Rich Lucente, CC BY-SA 4.0)
自定义语音助手
Google 套件包含一个 Python API 和几个 Python 模块。 我按照套件的说明使初始配置正常工作。 Google Assistant gRPC 软件在 Apache 2.0 许可下开源。
我调整了 Google Assistant gRPC 演示来实现我的应用程序。 应用程序的操作非常简单:首先,它等待设备按钮被按下。 然后,代码构造四个单独的单词列表:1. 问候语和日期,2. 当前时间,3. 第一个位置的当前温度,以及 4. 第二个位置的当前温度。 孩子的声音会随机洗牌,然后每个单词列表用于播放与分配给该列表的孩子相对应的音频剪辑。 (这就是为什么严格遵循音频剪辑的命名约定非常重要的原因。)然后,应用程序启动与 Google Assistant API 的对话。
起初,我认为收集当前温度的天气数据并将数字转换为单词的代码会很有挑战性。 事实证明根本不是这种情况。 事实上,现有的开源 Python 模块使这一切变得简单直观。
将数字转换为单词列表需要解决两种情况:我需要将序数转换为单词(例如,1 和 2 转换为 first 和 second),并且我还需要将基数转换为单词(例如,28 转换为 twenty-eight)。 开源 inflect.py module 模块具有可以轻松处理这两种情况的函数。
import inflect
p = inflect.engine()
number = 23
# get a cardinal word list (e.g. ['twenty', 'three'])
print(p.number_to_words(number).replace('-', ' ').split(' '))
# get an ordinal word list (e.g. ['twenty', 'third'])
print(p.number_to_words(p.ordinal(number)).replace('-', ' ').split(' '))
inflect 引擎返回带有嵌入式连字符的数字的字符串表示形式(例如,twenty-three),因此代码通过将连字符转换为空格并将字符串用空格作为分隔符拆分为列表,从而将字符串拆分为可变长度的单词列表。
接下来要解决的问题是获取两个位置的当前温度。 Open Weather Map 提供免费的天气服务,允许每分钟最多 60 次调用或每月 100 万次调用,这远远超过了本项目需要的。 我注册了免费服务并收到了 API 密钥。 通过使用开源 Python 包装器模块 PyOWM 访问该服务非常容易。 这是一个简化的代码片段
import pyowm
# use the OpenWeatherMap API key to get a weather manager
owm = pyowm.OWM('YOUR-OPEN-WEATHER-MANAGER-API-KEY')
mgr = owm.weather_manager()
# convert location phrase to city for OWM API
# e.g. ocean_city becomes 'Ocean City, US'
location = 'ocean_city'
city = location.replace('_', ' ').title() + ', US'
# get current temperature in fahrenheit for location
observation = owm_mgr.weather_at_place(city)
temp = round(observation.weather.temperature('fahrenheit')['temp'])
用蝴蝶结包装起来
该项目的完整源代码可在我的 GitHub 存储库中找到。 该项目包括一个系统d服务单元文件,该文件改编自 Google 的演示,以在设备启动时自动启动应用程序。 GitHub 存储库包含安装 Python 模块和配置 systemd 服务的说明。
我创建了一个 短视频 的结果。 在假期期间分发了五个定制语音助手:每个孩子的曾祖父母和祖父母各一个。 对于某些人来说,这些礼物带来了喜悦的泪水。 孩子们的声音绝对可爱,这些盒子捕捉了童年转瞬即逝的时刻,可以长期享受。
评论已关闭。