曲线救国:用谷歌语音助理唤起必应聊天

曲线救国:用谷歌语音助理唤起必应聊天

现在手机上的 Bing 应用 已支持 AI 聊天,并且可以语音对话。

声音还行,识别率也高,即便偶尔口误或者识别出错别字,也基本上能够返回正确的回答。

不过,Bing 还无法像 Siri、小爱那样在待机状态下用语音唤醒,也许未来微软会重新上线像曾经的 Cortana 那样的智能助理,但目前只能通过点击桌面上的图标打开。

Bing 桌面小组件

有没有办法直接用口令唤醒呢?

经尝试,我在 Android 手机上成功用 Google Assitant 和 Tasker 呼出 Bing Chat Voice 并连续对话。

本文只演示安卓设备上的操作,比较简单,欢迎探讨实现更复杂的功能,或者更直接的操作。理论上苹果 IOS 上的快捷指令也能实现 Siri 和 Bing 的联动,期待看到相关的教程。

前提:需要一部无障碍使用 Google 三件套的安卓设备,为什么要用 Google 待会儿再讲。

在 Google Play 中安装 Google 助理Tasker

似乎只安装 Google 也可以,它内置了 Google 助理。

Google Assistant 是 一款智能语音助手,可以通过语音或文本与用户进行交互,使用 Google Assistant,可以进行日程安排、查询新闻、控制智能家居设备等多种功能。

Google Assistant 还支持与其他应用程序集成,但没有和 Bing 联动,因此我们需要用 Tasker 曲线救国。

Tasker是一款安卓应用程序,它可以让你以自动化的方式控制你的设备,例如,在特定时间启用或禁用 Wi-Fi 连接、在特定位置打开或关闭音乐播放器等。

本文要实现用 Google Voice 启动 Tasker 中的任务,这个任务包括启动 Bing Voice 和 重置、退出。

之所以要用谷歌,是因为我尝试过在小米手机上用小爱同学唤醒 Bing,小爱无法操作非小米应用商店安装的应用,而小米应用商店没有 Tasker,也会把从别的来源安装的 Bing 自动替换成国内版的必应,而国内版的必应是无法换区的,也就没有 AI Chat 功能,即便不让它替换(关闭应用商店的自动升级功能),小爱也无法像 Google 助理那样对应用内组件进行操作,我想国产手机大概都是这么个情况。

设置 Tasker 任务

1. 设置一个全局变量

Bing Chat 每轮对话有问答次数限制(目前是8次),因此需设置一个计数的全局变量 %BCCount,用以触发退出和重置任务。

Bing Chat 计数变量

2. 创建 一条 退出任务:Bing Quit

这个任务比较简单,但不同权限的操作方式不同。

  • Root的手机可以直接停止应用,非 Root 的手机直接停止应用需启用 ADB Wifi,这个比较麻烦,需要用另外的软件或者连接到电脑上用命令进行设置,而每次手机重启后都要用同样的方式手动启用 ADB Wifi。

Tasker 结束应用 权限问题

  • 另一种方式是模拟返回键,不过 Bing 无法用返回的方式退出,只能返回到桌面,它在后台一段时间就自动关闭了,这个时长不太确定,有时候几秒,有时候一直不退出?

Tasker Bing Quit 任务

Tasker 操作设备需要各种权限,包括什么无障碍设置、应用使用情况、电池无限制等权限,碰到提示的时候启用就好了。

3. 创建一条 启动任务:Bing Chat

Tasker 可以启用应用或应用中的包(组件),选择应用并长按会弹出应用中的包名,对应不同的子功能:

Bing APP 中的应用包

任务的逻辑为先判断一下变量%BCCount 是否超过 Bing 单轮对话的次数限额,超过则执行退出任务,然后判断一下%BCCount是否第一次/重新开始计数,如果是则使用新的复制启动 Bing 预览窗口,并等待 100 毫秒,否则直接启动预览窗口并无需等待,然后以新的复制启动 Bing 语音对话窗口并增加变量的记数。

Tasker Bing Chat 任务

为什么要先启动 Bing 预览窗口且首测启动后要等待 100 毫秒?

首次直接调用 Voice 包会弹出一个确认对话框,无法直接使用语音,因此需要先调用预览框再启用语音。

Bing Voice 首次启动对话框

为什么使用新的复制?

有碰到无法启用语音、无法刷新的情况,新的复制可以降低这种几率,不知道什么原因。

设置 Google Assistant

首先将系统的数字助理应用设为 Google,不同手机可能设置方式不一样,这点略过。

Google 设置

尝试用手机系统默认的快捷方式唤起 Google 助理,点击头像进行设置。

在 Google 设置中启用 “Ok, Google”,并设置与 Google 助理交谈时的语言为只有英文,因为中文不支持应用快捷指令操作,而如果增加了其他语言为第二语言则会大大降低语音识别的速度和准确率。

Google 助理 语音设置

Google 操作 Tasker 的方式

直接说“ Ok Google, run task name in Tasker”就可以启动 Tasker 任务,还可以加上" with something..."传递参数,但是这种方式语音识别成功率很低(比 Bing 差远了),语句太长,参数也没用( Bing 的语音对话只能在被唤起后再用麦克风传入语音)。

因此用 Google 日常安排的方式简化口令并和其他操作联合。

添加 Google 日常安排

如果你不知道如何找到入口的话,用搜索,或在Google 设置 -快捷指令中,拉倒页面最末 -建议 -查看所有日常安排。

1. 新建退出 Bing 和 Google 对话弹框的日常安排

启动方式为当我对 Google 助理说出某个词语,尽量简短和没有近音词,例如“ clean”、“ quit”。
添加自定义操作,第一条为启动 Tasker 中的 Bing 退出任务,第二条为退出 Google 助理对话窗口。

Google 助理退出必应的指令

1. 新建启动 Bing 语音的日常安排

启动方式和操作同上:

Google 助理启动必应语音的指令

实际使用演示

现在就可以愉快的使用语音唤醒必应聊天了,有一些小问题:并不是总能直接启动 Bing 语音或者退出 Google 对话框,好在口令足够简短,使用起来不算麻烦。

Google 助理启动 Bing 演示

Google 助理关闭 Bing 演示

Tasker脚本导出

<TaskerData sr="" dvi="1" tv="6.0.10">
	<Task sr="task7">
		<cdate>1677690644423</cdate>
		<edate>1680619668025</edate>
		<id>7</id>
		<nme>Bing Chat</nme>
		<pri>1000</pri>
		<Action sr="act0" ve="7">
			<code>37</code>
			<coll>false</coll>
			<ConditionList sr="if">
				<Condition sr="c0" ve="3">
					<lhs>%BCCount</lhs>
					<op>7</op>
					<rhs>19</rhs>
				</Condition>
			</ConditionList>
		</Action>
		<Action sr="act1" ve="7">
			<code>130</code>
			<Str sr="arg0" ve="3">Bing Quit</Str>
			<Int sr="arg1">
				<var>%priority</var>
			</Int>
			<Int sr="arg10" val="1"/>
			<Str sr="arg2" ve="3"/>
			<Str sr="arg3" ve="3"/>
			<Str sr="arg4" ve="3"/>
			<Int sr="arg5" val="0"/>
			<Int sr="arg6" val="0"/>
			<Str sr="arg7" ve="3"/>
			<Int sr="arg8" val="0"/>
			<Int sr="arg9" val="0"/>
		</Action>
		<Action sr="act10" ve="7">
			<code>20</code>
			<App sr="arg0">
				<appClass>com.microsoft.clients.bing.voice.VoiceActivity</appClass>
				<appPkg>com.microsoft.bing</appPkg>
				<label>Bing:com.microsoft.clients.bing.voice.VoiceActivity</label>
			</App>
			<Str sr="arg1" ve="3"/>
			<Int sr="arg2" val="0"/>
			<Int sr="arg3" val="1"/>
		</Action>
		<Action sr="act11" ve="7">
			<code>888</code>
			<Str sr="arg0" ve="3">%BCCount</Str>
			<Int sr="arg1" val="1"/>
			<Int sr="arg2" val="0"/>
		</Action>
		<Action sr="act2" ve="7">
			<code>30</code>
			<Int sr="arg0" val="0"/>
			<Int sr="arg1" val="15"/>
			<Int sr="arg2" val="0"/>
			<Int sr="arg3" val="0"/>
			<Int sr="arg4" val="0"/>
		</Action>
		<Action sr="act3" ve="7">
			<code>38</code>
		</Action>
		<Action sr="act4" ve="7">
			<code>37</code>
			<ConditionList sr="if">
				<Condition sr="c0" ve="3">
					<lhs>%BCCount</lhs>
					<op>13</op>
					<rhs>1</rhs>
				</Condition>
			</ConditionList>
		</Action>
		<Action sr="act5" ve="7">
			<code>20</code>
			<App sr="arg0">
				<appClass>androidx.compose.ui.tooling.PreviewActivity</appClass>
				<appPkg>com.microsoft.bing</appPkg>
				<label>Bing:androidx.compose.ui.tooling.PreviewActivity</label>
			</App>
			<Str sr="arg1" ve="3"/>
			<Int sr="arg2" val="0"/>
			<Int sr="arg3" val="1"/>
		</Action>
		<Action sr="act6" ve="7">
			<code>30</code>
			<Int sr="arg0" val="100"/>
			<Int sr="arg1" val="0"/>
			<Int sr="arg2" val="0"/>
			<Int sr="arg3" val="0"/>
			<Int sr="arg4" val="0"/>
		</Action>
		<Action sr="act7" ve="7">
			<code>43</code>
		</Action>
		<Action sr="act8" ve="7">
			<code>20</code>
			<App sr="arg0">
				<appClass>androidx.compose.ui.tooling.PreviewActivity</appClass>
				<appPkg>com.microsoft.bing</appPkg>
				<label>Bing:androidx.compose.ui.tooling.PreviewActivity</label>
			</App>
			<Str sr="arg1" ve="3"/>
			<Int sr="arg2" val="0"/>
			<Int sr="arg3" val="0"/>
		</Action>
		<Action sr="act9" ve="7">
			<code>38</code>
		</Action>
		<Img sr="icn" ve="2">
			<cls>com.microsoft.sapphire.app.main.SapphireMainActivity</cls>
			<pkg>com.microsoft.bing</pkg>
		</Img>
	</Task>
</TaskerData>

<TaskerData sr="" dvi="1" tv="6.0.10">
	<Task sr="task4">
		<cdate>1677710013744</cdate>
		<edate>1680618992087</edate>
		<id>4</id>
		<nme>Bing Quit</nme>
		<pri>1000</pri>
		<Action sr="act0" ve="7">
			<code>20</code>
			<App sr="arg0">
				<appClass>androidx.compose.ui.tooling.PreviewActivity</appClass>
				<appPkg>com.microsoft.bing</appPkg>
				<label>Bing:androidx.compose.ui.tooling.PreviewActivity</label>
			</App>
			<Str sr="arg1" ve="3"/>
			<Int sr="arg2" val="0"/>
			<Int sr="arg3" val="0"/>
		</Action>
		<Action sr="act1" ve="7">
			<code>245</code>
		</Action>
		<Action sr="act2" ve="7">
			<code>245</code>
		</Action>
		<Action sr="act3" ve="7">
			<code>245</code>
		</Action>
		<Action sr="act4" ve="7">
			<code>245</code>
		</Action>
		<Action sr="act5" ve="7">
			<code>549</code>
			<Str sr="arg0" ve="3">%BCCount</Str>
			<Int sr="arg1" val="0"/>
			<Int sr="arg2" val="0"/>
			<Int sr="arg3" val="0"/>
		</Action>
	</Task>
</TaskerData>