Rhino-iOS 3.0.1

Rhino-iOS 3.0.1

Ian LaveryDavid BartleKwangsoo YeoMohammadreza RostamEric Mikulin维护。



Rhino-iOS 3.0.1

  • Picovoice

Rhino

GitHub release GitHub GitHub language count

PyPI Nuget Go Reference Pub Version npm Maven Central Maven Central npm npm npm npm

Crates.io

由位于加拿大温哥华的 Picovoice 制造

Twitter URL

YouTube Channel Views

Rhino 是 Picovoice 的语音到意图引擎。它可以直接从具有实际场景的环境中的语音命令中推断出意图,实时进行。例如,给定一个语音命令

我能喝一杯小份焦糖玛奇朵吗?

Rhino 推断用户的需求,并发出以下推断结果

{
  "isUnderstood": "true",
  "intent": "orderBeverage",
  "slots": {
    "beverage": "espresso",
    "size": "small",
    "numberOfShots": "2"
  }
}

Rhino 是

  • 使用在实际环境中训练的深度神经网络。
  • 紧凑和计算高效。非常适合物联网。
  • 跨平台
    • Arm Cortex-M、STM32、Arduino 和 i.MX RT
    • Raspberry Pi、NVIDIA Jetson Nano 和 BeagleBone
    • Android 和 iOS
    • Chrome、Safari、Firefox 和 Edge
    • Linux (x86_64)、macOS (x86_64, arm64) 和 Windows (x86_64)
  • 自助服务。开发者可以使用 Picovoice 控制台 训练自定义场景。

目录

用例

如果语音交互的领域是特定的(有限的),那么Rhin是一个合适的选择。

  • 如果您想创建类似于Alexa或Google的语音体验,请参阅Picovoice平台
  • 如果您需要识别一些静态(始终监听)的语音命令,请参阅Porcupine

试试看

Rhino in Action

语言支持

  • 英语、德语、法语、西班牙语、意大利语、日语、韩语和葡萄牙语。
  • 根据具体情况,商业客户可获取对其他语言的支持。

性能

这里提供了Rhin与主要基于云的替代方案的准确率对比。以下是基准测试的摘要

术语

Rhino 从用户在特定领域内的语音命令中推断出用户的意图。我们将这样的特定领域称为 上下文。上下文可以被视为一组语音指令,每个指令映射到一个意图。

turnLightOff:
  - Turn off the lights in the office
  - Turn off all lights
setLightColor:
  - Set the kitchen lights to blue

在上面的示例中,每个语音指令被称为 表达式。表达式是我们期望用户说出以与我们语音应用交互的内容。

考虑以下表达式:

关闭办公室的灯光

我们对 Rhino 的要求是

  1. 推断意图(《关闭灯光》)
  2. 记录从说法中获取的具体细节,在这种情况下是位置(《办公室》)

我们可以通过更新表达式来捕获这些细节

turnLightOff:
  - Turn off the lights in the $location:lightLocation.

$location:lightLocation 表示我们期望一个类型为 location 的变量发生,并希望将其值捕获在一个名为 lightLocation 的变量中。我们将此类变量称为 占位符。占位符使我们能够捕获语音命令的细节。每个占位符类型都被定义为一组短语。例如

lightLocation:
  - "attic"
  - "balcony"
  - "basement"
  - "bathroom"
  - "bedroom"
  - "entrance"
  - "kitchen"
  - "living room"
  - ...

您可以使用 Picovoice 控制台创建自定义上下文。

有关 Rhino 完整表达式语法的更多信息,请参阅 语音到意图语法速查表

演示

如果使用 SSH,使用下面命令克隆仓库

git clone --recurse-submodules [email protected]:Picovoice/rhino.git

如果使用 HTTPS,使用下面命令克隆仓库

git clone --recurse-submodules https://github.com/Picovoice/rhino.git

Python 演示程序

安装演示程序包

sudo pip3 install pvrhinodemo

将正在工作的麦克风连接到您的设备时,请在终端运行以下命令

rhino_demo_mic --access_key ${ACCESS_KEY} --context_path ${CONTEXT_PATH}

${CONTEXT_PATH} 替换为您使用 Picovoice 控制台创建的上下文文件或仓库中的任何上下文文件。

有关 Python 演示程序的更多信息,请参阅 demo/python

.NET 演示

Rhino .NET 演示 是一个命令行应用程序,允许您选择在音频文件或实时麦克风输入上运行 Rhino。

确保您的设备上连接了一个正常工作的麦克风。从 demo/dotnet/RhinoDemo 中,在终端运行以下命令

dotnet run -c MicDemo.Release -- --access_key ${ACCESS_KEY} --context_path ${CONTEXT_FILE_PATH}

${ACCESS_KEY} 替换为您的 Picovoice AccessKey,将 ${CONTEXT_FILE_PATH} 替换为使用 Picovoice 控制台创建的上下文文件或存储库中的一个。

有关 .NET 演示的更多信息,请访问 demo/dotnet

Java 演示

Rhino Java 演示 是一个命令行应用程序,允许您选择在音频文件或实时麦克风输入上运行 Rhino。

要尝试实时演示,请确保您的设备上连接了一个正常工作的麦克风。然后从终端运行以下命令

cd demo/java
./gradlew build
cd build/libs
java -jar rhino-mic-demo.jar -a ${ACCESS_KEY} -c ${CONTEXT_FILE_PATH}

${CONTEXT_FILE_PATH} 替换为使用 Picovoice 控制台创建的上下文文件或存储库中的一个。

有关 Java 演示的更多信息,请访问 demo/java

Go 演示

此演示需要 cgo,在 Windows 上可能意味着您需要安装一个类似 Mingw 的 gcc 编译器以正确构建。

demo/go 中,在终端运行以下命令以构建和运行麦克风演示

go run micdemo/rhino_mic_demo.go -access_key ${ACCESS_KEY} -context_path ${CONTEXT_FILE_PATH}

${ACCESS_KEY} 替换为您的 Picovoice AccessKey,将 ${CONTEXT_FILE_PATH} 替换为使用 Picovoice 控制台创建的上下文文件或来自 Rhino GitHub 存储库中的一个。

有关 Go 演示的更多信息,请访问 demo/go

Unity 演示

要运行 Rhino Unity 演示,将 Rhino Unity 包导入到您的项目,打开 RhinoDemo 场景然后开始播放。要在其他平台或运行时中运行,请转到 文件 > 构建设置,选择您的平台然后点击 构建并运行 按钮。

Flutter 演示

要在 Android 或 iOS 平台上使用 Flutter 运行 Rhino 演示,您必须在系统上安装 Flutter SDK。安装完毕后,您可以通过运行 flutter doctor 来确定相关平台的其他缺失需求。一旦设置好环境,启动一个模拟器或连接一个 Android/iOS 设备。

用语言代码运行 prepare_demo 脚本来将演示设置为您的选择语言(例如,de 表示德语,ko 表示韩语)。要查看可用的语言列表,请在没有语言代码的情况下运行 prepare_demo

cd demo/flutter
dart scripts/prepare_demo.dart ${LANGUAGE}

运行以下命令来构建并部署演示到您的设备

cd demo/flutter
flutter run

一旦演示应用已启动,请按开始按钮并说出命令以开始上下文推断。要查看有关当前上下文信息的更多详细资料,请在应用右上角点击 上下文信息 按钮。

React Native 演示

要运行 React Native Rhino 演示应用,您首先需要设置您的 React Native 环境。请参阅 React Native 的文档。一旦设置好环境,请转到 demo/react-native 并运行以下命令

对于 Android

yarn android-install    # sets up environment
yarn android-run        # builds and deploys to Android

对于 iOS

yarn ios-install        # sets up environment
yarn ios-run            # builds and deploys to iOS

这两个演示都使用智能照明上下文,可以理解以下命令

关掉灯光。

或者

将客厅的灯光设定为紫色。

Android 演示示例

使用 Android Studio,打开demo/android/Activity作为 Android 项目,然后运行应用程序。

当演示应用程序启动后,点击“开始”按钮,从上下文中说出一条命令以开始推理。要查看关于当前上下文信息的更多详细信息,请单击应用程序右上角的“显示上下文”按钮。

有关 Android 演示示例的更多信息,请访问demo/android

iOS 演示示例

要运行应用程序演示

  1. demo目录运行
pod install
  1. 在 XCode 中打开RhinoDemo.xcworkspace

  2. ContentView.swift文件中的let accessKey = "${YOUR_ACCESS_KEY_HERE}"替换为您的AccessKey

  3. 转到 产品 > 方案并选择您要演示的语言的方案(例如,arDemo -> 阿拉伯演示,deDemo -> 德国演示)

  4. 使用模拟器或连接的 iOS 设备运行演示。

  5. 当演示应用程序启动后,点击“开始”按钮以在上下文中推断音频。要查看关于当前上下文信息的更多详细信息,请单击应用程序右上角的“上下文信息”按钮。

有关 iOS 演示示例的更多信息,请访问demo/ios

Web 演示示例

原生JavaScript和HTML

demo/web 使用 yarnnpm 安装依赖项,并使用带语言代码的 start 脚本启动本地web服务器,以备您选择的任何语言托管示例(例如 pl -> 波兰语,ko -> 韩语)。要查看可用语言列表,请在没有语言代码的情况下运行 start

yarn
yarn start ${LANGUAGE}

(或者)

npm install
npm run start ${LANGUAGE}

在浏览器中打开 https://:5000 尝试示例。

Angular 示例

demo/angular 使用 yarnnpm 安装依赖项,并使用带语言代码的 start 脚本启动本地web服务器,以备您选择的任何语言托管示例(例如 pl -> 波兰语,ko -> 韩语)。要查看可用语言列表,请在没有语言代码的情况下运行 start

yarn
yarn start ${LANGUAGE}

(或者)

npm install
npm run start ${LANGUAGE}

在浏览器中打开 https://:4200 尝试示例。

React 示例

demo/react 使用 yarnnpm 安装依赖项,并使用带语言代码的 start 脚本启动本地web服务器,以备您选择的任何语言托管示例(例如 pl -> 波兰语,ko -> 韩语)。要查看可用语言列表,请在没有语言代码的情况下运行 start

yarn
yarn start ${LANGUAGE}

(或者)

npm install
npm run start ${LANGUAGE}

在浏览器中打开 https://:3000 尝试示例。

Vue 示例

demo/vue 使用 yarnnpm 安装依赖,并通过以下带有语言码的 start 脚本来启动一个本地服务器,该服务器将以您选择的语言托管示例(例如 pl -> 波兰语,ko -> 韩语)。要查看可用的语言列表,请在终端中运行不带语言码的 start

yarn
yarn start ${LANGUAGE}

(或者)

npm install
npm run start ${LANGUAGE}

命令行输出将为您提供可在浏览器中打开的本地链接和端口号。

Node.js 示例

安装演示程序包

yarn global add @picovoice/rhino-node-demo

将工作麦克风连接到您的设备后,在终端中运行以下命令

rhn-mic-demo --access_key ${ACCESS_KEY} --context_path ${CONTEXT_FILE_PATH}

${CONTEXT_FILE_PATH} 替换为使用 Picovoice 控制台创建的上下文文件或存储库中的一个。

有关 Node.js 示例的更多信息,请访问 demo/nodejs.

Rust 示例

此示例从一个麦克风打开音频流,并对语音命令进行推理。从 demo/rust/micdemo 运行以下命令

cargo run --release -- --access_key ${ACCESS_KEY} --context_path ${CONTEXT_FILE_PATH}

${CONTEXT_FILE_PATH} 替换为使用 Picovoice 控制台创建的上下文文件或存储库中的一个。

有关 Rust 示例的更多信息,请访问 demo/rust.

C 示例

C 示例需要 CMake 版本 3.4 或更高版本。

Windows 需要 MinGW 来构建示例。

麦克风演示

在仓库根目录中,使用以下命令进行构建:

cmake -S demo/c/. -B demo/c/build && cmake --build demo/c/build --target rhino_demo_mic
Linux (x86_64), macOS (x86_64, arm64), Raspberry Pi, BeagleBone, and Jetson

使用以下命令列出输入音频设备:

./demo/c/build/rhino_demo_mic --show_audio_devices

运行演示:

./demo/c/build/rhino_demo_mic -l ${RHINO_LIBRARY_PATH} -m lib/common/rhino_params.pv \
-c resources/contexts/${PLATFORM}/smart_lighting_${PLATFORM}.rhn \
-d ${AUDIO_DEVICE_INDEX} -a ${ACCESS_KEY}

${LIBRARY_PATH} 替换为在 lib 下适当库的路径,将 ${PLATFORM} 替换为你正在运行的平台的名称(linuxraspberry-pimacbeaglebonejetson),将 ${AUDIO_DEVICE_INDEX} 替换为你的音频设备的索引,并将 ${ACCESS_KEY} 替换为你的 Picovoice 访问密钥。

Windows

使用以下命令列出输入音频设备:

.\\demo\\c\\build\\rhino_demo_mic.exe --show_audio_devices

运行演示:

.\\demo\\c\\build\\rhino_demo_mic.exe -l lib/windows/amd64/libpv_rhino.dll -c lib/common/rhino_params.pv -c resources/contexts/windows/smart_lighting_windows.rhn -d ${AUDIO_DEVICE_INDEX} -a ${ACCESS_KEY}

${AUDIO_DEVICE_INDEX} 替换为你的音频设备索引,并使用 ${ACCESS_KEY} 替换你的 Picovoice 访问密钥。

该演示打开音频流,并从智能照明系统的语音命令上下文中推断出你的意图。例如,你可以这样说:

"打开卧室的灯"。

文件演示

在仓库根目录中,使用以下命令进行构建:

cmake -S demo/c/. -B demo/c/build && cmake --build demo/c/build --target rhino_demo_file
Linux (x86_64), macOS (x86_64, arm64), Raspberry Pi, BeagleBone, and Jetson

运行演示:

./demo/c/build/rhino_demo_file -l ${LIBRARY_PATH} -m lib/common/rhino_params.pv \
-c resources/contexts/${PLATFORM}/coffee_maker_${PLATFORM}.rhn -w resources/audio_samples/test_within_context.wav \
-a ${ACCESS_KEY}

${LIBRARY_PATH} 替换为在 lib 下可用的适当库的路径,将 ${PLATFORM} 替换为您正在运行的平台的名称 (linux, raspberry-pi, mac, beaglebone, 或 jetson),将 ${ACCESS_KEY} 替换为您的 Picovoice AccessKey。

Windows

运行演示:

.\\demo\\c\\build\\rhino_demo_file.exe -l lib/windows/amd64/libpv_rhino.dll -m lib/common/rhino_params.pv -c resources/contexts/windows/coffee_maker_windows.rhn -w resources/audio_samples/test_within_context.wav -a ${ACCESS_KEY}

${ACCESS_KEY} 替换为您的 Picovoice AccessKey。

该演示将打开 WAV 文件并推断咖啡机系统中的意图。

有关 C 演示的更多信息,请访问 demo/c

SDKs

Python

安装 Python SDK

pip3 install pvrhino

SDK 通过一个工厂方法公开了一个用于创建引擎实例的方法

import pvrhino

access_key = "${ACCESS_KEY}" # AccessKey obtained from Picovoice Console (https://console.picovoice.ai/)

handle = pvrhino.create(access_key=access_key, context_path='/absolute/path/to/context')

其中 context_path 是使用 Picovoice 控制台或 Rhino 的 GitHub 仓库中可用的默认上下文之一创建的 Speech-to-Intent 上下文的绝对路径。

初始化时,可以使用 rhino.sample_rate 获取所需的采样率。输入数组中的预期帧长度(音频样本数)由 rhino.frame_length 提供。该对象可用于从语音命令中推断意图,如下所示

def get_next_audio_frame():
    pass

while True:
    is_finalized = handle.process(get_next_audio_frame())

    if is_finalized:
        inference = handle.get_inference()
        if not inference.is_understood:
            # add code to handle unsupported commands
            pass
        else:
            intent = inference.intent
            slots = inference.slots
            # add code to take action based on inferred intent and slot values

最后,完成时请务必显式释放资源使用 handle.delete()

.NET

使用 NuGet 或 dotnet CLI 安装 .NET SDK

dotnet add package Rhino

SDK 提供一个工厂方法来创建引擎实例,如下所示

using Pv;

const string accessKey = "${ACCESS_KEY}";
string contextPath = "/absolute/path/to/context.rhn";
Rhino handle = Rhino.Create(accessKey, contextPath);

初始化时,有效采样率由 handle.SampleRate 提供。期望的帧长度(输入数组中的音频样本数量)由 handle.FrameLength 提供。引擎接受 16 位线性编码的 PCM 并对单声道音频进行操作。

short[] GetNextAudioFrame()
{
    // .. get audioFrame
    return audioFrame;
}

while(true)
{
    bool isFinalized = handle.Process(GetNextAudioFrame());
    if(isFinalized)
    {
        Inference inference = handle.GetInference();
        if(inference.IsUnderstood)
        {
            string intent = inference.Intent;
            Dictionary<string, string> slots = inference.Slots;
            // .. code to take action based on inferred intent and slot values
        }
        else
        {
            // .. code to handle unsupported commands
        }
    }
}

Rhino 的资源将被垃圾回收器释放,但为了在使用后立即释放资源,请在其中使用 using 语句

using(Rhino handle = Rhino.Create(accessKey, contextPath))
{
    // .. Rhino usage here
}

Java

Rhino Java 绑定可在 Maven Central Repository 中找到,地址为 ai.picovoice:rhino-java:${version}

SDK 提供了一个 Builder,允许您创建引擎实例

import ai.picovoice.rhino.*;

final String accessKey = "${ACCESS_KEY}"; // AccessKey obtained from Picovoice Console (https://console.picovoice.ai/)

try{
    Rhino handle = new Rhino.Builder()
                    .setAccessKey(accessKey)
                    .setContextPath("/absolute/path/to/context")
                    .build();
} catch (RhinoException e) { }

初始化时,有效采样率由 handle.getSampleRate() 提供。期望的帧长度(输入数组中的音频样本数量)由 handle.getFrameLength() 提供。引擎接受 16 位线性编码的 PCM 并对单声道音频进行操作。

short[] getNextAudioFrame(){
    // .. get audioFrame
    return audioFrame;
}

while(true) {
    boolean isFinalized = handle.process(getNextAudioFrame());
    if(isFinalized){
        RhinoInference inference = handle.getInference();
        if(inference.getIsUnderstood()){
            String intent = inference.getIntent();
            Map<string, string> slots = inference.getSlots();
            // .. code to take action based on inferred intent and slot values
        } else {
            // .. code to handle unsupported commands
        }
    }
}

完成 Rhino 使用后,请确保明确释放其资源

handle.delete();

Go

要安装 Rhino Go 模块到项目中,使用以下命令

go get github.com/Picovoice/rhino/binding/go

要使用默认参数创建引擎实例,将 AccessKey 和 Rhino 上下文文件 (.rhn) 的路径传递给 NewRhino 函数,然后调用 .Init()

import . "github.com/Picovoice/rhino/binding/go/v2"

const accessKey string = "${ACCESS_KEY}" // obtained from Picovoice Console (https://console.picovoice.ai/)

rhino := NewRhino(accessKey, "/path/to/context/file.rhn")
err := rhino.Init()
if err != nil {
    // handle error
}

初始化后,您可以将音频帧传递给引擎进行处理。引擎接受 16 位线性编码的 PCM 并对单声道音频进行操作。引擎所需的采样率由 SampleRate 提供,每帧样本数量由 FrameLength 提供。

要将音频送入 Rhino,请在捕获循环中使用 Process 函数。在调用 Process 之前,必须调用 Init()

func getNextFrameAudio() []int16 {
    // get audio frame
}

for {
    isFinalized, err := rhino.Process(getNextFrameAudio())
    if isFinalized {
        inference, err := rhino.GetInference()
        if inference.IsUnderstood {
            intent := inference.Intent
            slots := inference.Slots
            // add code to take action based on inferred intent and slot values
        } else {
            // add code to handle unsupported commands
        }
    }
}

完成引擎使用后,必须明确释放资源。

rhino.Delete()

Unity

Rhino Unity 包 导入您的 Unity 项目中。

SDK 提供了两个 API

高级 API

RhinoManager 提供了一个高级 API,用于处理音频录制。这是开始使用的最快方式。

使用构造函数 RhinoManager.Create 将创建一个使用提供的上下文文件进行初始化的 RhinoManager 实例。

using Pv.Unity;

string accessKey = "${ACCESS_KEY}"; // AccessKey obtained from Picovoice Console (https://console.picovoice.ai/)

try
{
    RhinoManager _rhinoManager = RhinoManager.Create(
                                    accessKey,
                                    "/path/to/context/file.rhn",
                                    (inference) => {});
}
catch (Exception ex)
{
    // handle rhino init error
}

一旦实例化了一个 RhinoManager,您可以通过调用

_rhinoManager.Process();

音频捕获停止且 Rhino 重置,一旦通过推理回调返回推理结果。当您想处理结果时,再次调用 .Process()

当应用完成使用 RhinoManager 的实例后,您可以显式释放音频资源,以及分配给 Rhino 的资源

_rhinoManager.Delete();

使用 RhinoManager 启用意图推理不需要处理音频捕获。这是因为它使用我们提供的 unity-voice-processor Unity 包来捕获音频帧并将它们自动传递给推理引擎。

低级 API

Rhino 为想要将语音到意图整合到现有音频处理管道的人提供了对推理引擎的低级访问。

要创建 Rhino 的实例,使用 .Create 静态构造函数和一个上下文文件。

using Pv.Unity;

string accessKey = "${ACCESS_KEY}"; // AccessKey obtained from Picovoice Console (https://console.picovoice.ai/)

try
{
    Rhino _rhino = Rhino.Create(accessKey, "path/to/context/file.rhn");
}
catch (RhinoException ex)
{
    // handle rhino init error
}

要向 Rhino 提供音频,您必须将其音频帧发送到它的 Process 函数,直到它完成推理。

short[] GetNextAudioFrame()
{
    // .. get audioFrame
    return audioFrame;
}

try
{
    bool isFinalized = _rhino.Process(GetNextAudioFrame());
    if(isFinalized)
    {
        Inference inference = _rhino.GetInference();
        if(inference.IsUnderstood)
        {
            string intent = inference.Intent;
            Dictionary<string, string> slots = inference.Slots;
            // .. code to take action based on inferred intent and slot values
        }
        else
        {
            // .. code to handle unsupported commands
        }
    }
}
catch (RhinoException ex)
{
    Debug.LogError(ex.ToString());
}

为了正确工作,音频数据必须符合 Picovoice 需要的音频格式。

Rhino 实现了 IDisposable 接口,因此您可以在 using 块中使用 Rhino。如果不使用 using 块,资源将由垃圾回收器自动释放,或者您也可以像这样显式地释放资源

_rhino.Dispose();

Flutter

Rhino Flutter 插件添加到您的pub.yaml文件中。

dependencies:
  rhino_flutter: ^<version>

SDK 提供了两个 API

高级API

RhinoManager提供一个处理音频录制的系统级API。这是快速开始的方式。

RhinoManager.create构造函数将创建一个RhinoManager实例,使用您传递给它的上下文文件。

import 'package:rhino_flutter/rhino_manager.dart';
import 'package:rhino_flutter/rhino_error.dart';

final String accessKey = "{ACCESS_KEY}";  // AccessKey obtained from Picovoice Console (https://console.picovoice.ai/)

void createRhinoManager() async {
    try{
        _rhinoManager = await RhinoManager.create(
            accessKey,
            "/path/to/context/file.rhn",
            _inferenceCallback);
    } on RhinoException catch (err) {
        // handle rhino init error
    }
}

inferenceCallback参数是一个函数,当Rhino进行推理时,您希望执行这个函数。该函数应该接受一个代表推理结果的RhinoInference实例。

void _inference(RhinoInference inference) {
    if(inference.isUnderstood!) {
        String intent = inference.intent!;
        Map<String, String> = inference.slots!;
        // add code to take action based on inferred intent and slot values
    }
    else {
        // add code to handle unsupported commands
    }
}

一旦您实例化了一个RhinoManager,您就可以使用.process()函数开始音频捕获和意图推理。每当通过推理回调返回推理结果时,音频捕获停止,Rhino重置。

try {
    await _rhinoManager.process();
} on RhinoException catch (ex) { }

当您的应用程序不再使用RhinoManager时,请确保您明确释放为其分配的资源

_rhinoManager.delete();

我们的flutter_voice_processor Flutter插件捕获音频帧并将其自动传递给语音到意图引擎。

低级API

Rhino为希望将语音到意图功能集成到现有音频处理流程中的人提供对推理引擎的低级访问。

通过将其静态构造函数create传递上下文文件来创建Rhino

import 'package:rhino_flutter/rhino_manager.dart';
import 'package:rhino_flutter/rhino_error.dart';

final String accessKey = "{ACCESS_KEY}"; // AccessKey obtained from Picovoice Console (https://console.picovoice.ai/)

void createRhino() async {
    try {
        _rhino = await Rhino.create(accessKey, '/path/to/context/file.rhn');
    } on RhinoException catch (err) {
        // handle rhino init error
    }
}

要向引擎传递音频,您必须将音频帧发送到其process函数。每次调用process都将返回一个包含以下变量的RhinoInference实例

  • isFinalized - 如果Rhino进行了推理则为true,否则为false
  • isUnderstood - 如果isFinalized为false则为null,否则根据上下文理解Rhino听到的内容为true,如果没有则false
  • intent - 如果isUnderstood不为true则为null,否则为推断出的意图名称
  • slots - 如果isUnderstood不为true则为null,否则是推断出的slot键值对的字典
List<int> buffer = getAudioFrame();

try {
    RhinoInference inference = await _rhino.process(buffer);
    if(inference.isFinalized) {
        if(inference.isUnderstood!) {
            String intent = inference.intent!;
            Map<String, String> = inference.slots!;
            // add code to take action based on inferred intent and slot values
        }
    }
} on RhinoException catch (error) {
    // handle error
}

// once you are done
this._rhino.delete();

React Native

安装 @picovoice/react-native-voice-processor@picovoice/rhino-react-native。SDK 提供了两个 API

高级 API

RhinoManager 通过提供音频录制的高级 API,处理了音频录制。这个类是用来自学入门的最快方式。

RhinoManager.create 构造函数将使用传递给它的上下文文件创建一个 RhinoManager 实例。

const accessKey = "${ACCESS_KEY}"; // AccessKey obtained from Picovoice Console (https://console.picovoice.ai/)

async createRhinoManager(){
    try{
        this._rhinoManager = await RhinoManager.create(
            accessKey,
            '/path/to/context/file.rhn',
            inferenceCallback);
    } catch (err) {
        // handle error
    }
}

一旦创建了 RhinoManager,您可以通过调用 .process() 来开始/停止音频捕获和意图推断。在收到推断回调后,音频捕获将自动停止,Rhino 将重置。要重新启动它,您必须再次调用 .process()

let didStart = await this._rhinoManager.process();

当您完成使用 Rhino 后,必须显式释放资源

this._rhinoManager.delete();

@picovoice/react-native-voice-processor 处理音频捕获,并将帧传递给推理引擎。

低级 API

Ruibo 为希望将语音到意图集成到现有音频处理管道中的人提供了对推理引擎的低级访问。

通过将其静态构造函数create传递上下文文件来创建Rhino

const accessKey = "${ACCESS_KEY}"; // AccessKey obtained from Picovoice Console (https://console.picovoice.ai/)

async createRhino(){
    try{
        this._rhino = await Rhino.create(accessKey, '/path/to/context/file.rhn');
    } catch (err) {
        // handle error
    }
}

要将音频传递到引擎,您必须使用 process 函数传递音频帧。从 process 返回的 RhinoInference 结果将有最多四个字段

  • isFinalized - 如果Rhino进行了推理则为true,否则为false
  • isUnderstood - 如果isFinalized为false则为null,否则根据上下文理解Rhino听到的内容为true,如果没有则false
  • intent - 如果isUnderstood不为true则为null,否则为推断出的意图名称
  • slots - 如果isUnderstood不为true则为null,否则是推断出的slot键值对的字典
let buffer = getAudioFrame();
try {
    let inference = await this._rhino.process(buffer);
    // use result
    // ..
    }
} catch (e) {
    // handle error
}

// once you are done
this._rhino.delete();

Android

要将此包包含到您的Android项目中,请确保您已在顶级build.gradle文件中包含mavenCentral(),然后向您的app的build.gradle中添加以下内容

dependencies {
    implementation 'ai.picovoice:rhino-android:${LATEST_VERSION}'
}

将Rhino集成到Android应用程序中,有两种可能的方式:高级API和低级API。

高级API

RhinoManager为将Rhino集成到Android应用程序提供高级API。它管理创建输入音频流、将其馈送到Rhino并调用用户提供的推理回调的所有相关活动。上下文文件(.rhn)应放置在Android项目资源文件夹(src/main/assets/)下。

final String accessKey = "${ACCESS_KEY}"; // AccessKey obtained from Picovoice Console (https://console.picovoice.ai/)
final String contextPath = "/path/to/context.rhn" // path relative to 'assets' folder

try {
    RhinoManager rhinoManager = new RhinoManager.Builder()
                        .setAccessKey(accessKey)
                        .setContextPath("/path/to/context.rhn")
                        .setSensitivity(0.35f)
                        .build(appContext, new RhinoManagerCallback() {
                            @Override
                            public void invoke(RhinoInference inference) {
                                if (inference.getIsUnderstood()) {
                                    final String intent = inference.getIntent();
                                    final Map<String, String> slots = inference.getSlots();
                                    // add code to take action based on inferred intent and slot values
                                }
                                else {
                                    // add code to handle unsupported commands
                                }
                            }
                        });
} catch (RhinoException e) { }

appContext参数是Android应用程序上下文——该参数用于从APK提取Rhino资源。灵敏度是参数,允许开发者以牺牲误报率为代价降低漏报。它是一个[0, 1]范围内的浮点数。灵敏度更高,可以降低漏报,但会增加误报率。

初始化时,可以使用manager.process()处理输入音频。处理完成后,务必使用manager.delete()释放资源。

低级API

Rhino提供了一个用于 Android 的 JNI 绑定。它可以使用以下方式初始化

import ai.picovoice.rhino.*;

final String accessKey = "${ACCESS_KEY}"; // AccessKey obtained from Picovoice Console (https://console.picovoice.ai/)

try {
    Rhino rhino = new Rhino.Builder()
                        .setAccessKey(accessKey)
                        .setContextPath("/path/to/context.rhn")
                        .build(appContext);
} catch (RhinoException e) { }

初始化后,可以使用handle进行意图推理

private short[] getNextAudioFrame();

while (!handle.process(getNextAudioFrame()));

final RhinoInference inference = handle.getInference();
if (inference.getIsUnderstood()) {
    // logic to perform an action given the intent object.
} else {
    // logic for handling out of context or unrecognized command
}

最后,在退出应用程序之前,务必释放获取的资源

handle.delete()

iOS

Rhino iOS 绑定可通过 CocoaPods 获取。要将它导入到您的 iOS 项目中,请将以下行添加到您的 Podfile 并运行 pod install

pod 'Rhino-iOS'

将 Rhino 集成到 iOS 应用的方法有两种:高级 API 和低级 API。

高级 API

RhinoManager 提供了一个高端 API,用于集成 Rhino 到 iOS 应用程序中。它管理与创建输入音频流、将其馈送到引擎以及调用用户提供的推断回调有关的所有活动。

import Rhino

let accessKey = "${ACCESS_KEY}" // Obtained from Picovoice Console (https://console.picovoice.ai)
do {
    let manager = try RhinoManager(
        accessKey: accessKey,
        contextPath: "/path/to/context/file.rhn",
        modelPath: "/path/to/model/file.pv",
        sensitivity: 0.35,
        onInferenceCallback: { inference in
                if inference.isUnderstood {
                    let intent:String = inference.intent
                    let slots:Dictionary<String,String> = inference.slots
                    // use inference results
                }
            })
} catch { }

灵敏度是允许开发者以牺牲误报率为代价进行换算的参数。它是一个位于 [0, 1] 内的浮点数。更高的灵敏度会以增加误报率为代价降低漏报率。

初始化时,可以使用manager.process()处理输入音频。处理完成后,务必使用manager.delete()释放资源。

低级 API

Rhino 为希望将意图推断集成到已经存在的音频处理管道中的用户提供对语音到意图引擎的低级访问。

import Rhino

let accessKey = "${ACCESS_KEY}" // Obtained from Picovoice Console (https://console.picovoice.ai)
do {
    let handle = try Rhino(
      accessKey: accessKey,
      contextPath: "/path/to/context/file.rhn")
} catch { }

初始化后,可以使用handle进行意图推理

func getNextAudioFrame() -> [Int16] {
    // .. get audioFrame
    return audioFrame
}

while true {
    do {
        let isFinalized = try handle.process(getNextAudioFrame())
        if isFinalized {
            let inference = try handle.getInference()
            if inference.isUnderstood {
                let intent:String = inference.intent
                let slots:Dictionary<String, String> = inference.slots
                // add code to take action based on inferred intent and slot values
            }
        }
    } catch { }
}

最后,在退出应用程序之前,务必释放获取的资源

handle.delete()

网络

Rhino可在现代网络浏览器(即非Internet Explorer)中通过WebAssembly使用。通过Web Audio API处理麦克风音频,并通过WebVoiceProcessor抽象化处理,该处理器还负责将音频下采样到正确的格式。Rhino作为Web Worker提供打包版本。

原生JavaScript和HTML (CDN Script 标签)

<!DOCTYPE html>
<html lang="en">
  <head>
    <script src="https://unpkg.com/@picovoice/rhino-web/dist/iife/index.js"></script>
    <script src="https://unpkg.com/@picovoice/web-voice-processor/dist/iife/index.js"></script>
    <script type="application/javascript">
      const RHINO_CONTEXT_BASE64 = /* Base64 representation of `.rhn` context file  */;
      const RHINO_MODEL_BASE64 = /* Base64 representation of the `.pv` model file */;

      let rhino = null;

      function rhinoInferenceCallback(inference) {
        if (inference.isFinalized) {
          console.log(`Inference detected: ${JSON.stringify(inference)}`);
          WebVoiceProcessor.WebVoiceProcessor.unsubscribe(rhino);
          document.getElementById("push-to-talk").disabled = false;
          console.log("Press the 'Push to Talk' button to speak again.");
        }
      }

      async function startRhino() {
        console.log("Rhino is loading. Please wait...");
        rhino = await RhinoWeb.RhinoWorker.create(
            accessKey: "${ACCESS_KEY}",  // AccessKey obtained from Picovoice Console (https://console.picovoice.ai/)
            { base64: RHINO_CONTEXT_BASE64 },
            rhinoInferenceCallback,
            { base64: RHINO_MODEL_BASE64 }
        );

        console.log("Rhino worker ready!");
        document.getElementById("push-to-talk").disabled = false;
        writeMessage("Press the 'Push to Talk' button to talk.");
      }

      document.addEventListener("DOMContentLoaded", function () {
        document.getElementById("push-to-talk").onclick = function (event) {
          if (rhino) {
            console.log("Rhino is listening for your commands ...");
            this.disabled = true;
            WebVoiceProcessor.WebVoiceProcessor.subscribe(rhino);
          }
        };
      });
    </script>
  </head>
  <body>
    <button id="push-to-talk">Push to Talk</button>
  </body>
</html>

原生JavaScript和HTML (ES 模块)

yarn add @picovoice/rhino-web @picovoice/web-voice-processor

(或者)

npm install @picovoice/rhino-web @picovoice/web-voice-processor
import { WebVoiceProcessor } from "@picovoice/web-voice-processor"
import { RhinoWorker } from "@picovoice/rhino-web";

const RHN_CONTEXT_BASE64 = /* Base64 representation of a `.rhn` context file */
const RHINO_MODEL_BASE64 = /* Base64 representation of the `.pv` model file*/;

let rhino = null

function rhinoInferenceCallback(inference) {
  if (inference.isFinalized) {
    console.log(`Rhino inference: ${JSON.stringify(inference)}`);
    WebVoiceProcessor.unsubscribe(rhino);
  }
}

async function startRhino() {
  // Create a Rhino Worker to listen for commands in the specified context
  rhino = await RhinoWorker.create(
    accessKey: "${ACCESS_KEY}",  // AccessKey obtained from Picovoice Console (https://console.picovoice.ai/)
    { base64: RHINO_CONTEXT_BASE64 },
    rhinoInferenceCallback,
    { base64: RHINO_MODEL_BASE64 }
  );
}

// Start a voice interaction:
// WebVoiceProcessor will request microphone permission.
// n.b. This promise will reject if the user refuses permission! Make sure you handle that possibility.
function pushToTalk() {
  if (rhino) {
    WebVoiceProcessor.subscribe(rhino);
  }
}

startRhino()

...

// Finished with Rhino? Release the WebVoiceProcessor and the worker.
if (done) {
  WebVoiceProcessor.unsubscribe(rhino);
  rhino.release()
  rhino.terminate()
}

Angular

yarn add @picovoice/rhino-angular @picovoice/web-voice-processor

(或者)

npm install @picovoice/rhino-angular @picovoice/web-voice-processor
import { Subscription } from "rxjs";
import { RhinoService } from "@picovoice/rhino-angular";
import rhinoParams from "${PATH_TO_RHINO_PARAMS_BASE64}";
import rhinoContext from "${PATH_TO_RHINO_CONTEXT_BASE64}";

constructor(private rhinoService: RhinoService) {
  this.contextInfoDetection = rhinoService.contextInfo$.subscribe(
    contextInfo => {
      console.log(contextInfo);
    });
  this.inferenceDetection = rhinoService.inference$.subscribe(
    inference => {
      console.log(inference);
    });
  this.isLoadedDetection = porcupineService.isLoaded$.subscribe(
    isLoaded => {
      console.log(isLoaded);
    });
  this.isListeningDetection = porcupineService.isListening$.subscribe(
    isListening => {
      console.log(isListening);
    });
  this.errorDetection = porcupineService.error$.subscribe(
    error => {
      console.error(error);
    });
}

async ngOnInit() {
  await this.rhinoService.init(
    ${ACCESS_KEY},
    { base64: rhinoContext },
    { base64: rhinoParams },
  )
}

async process() {
  await this.rhinoService.process();
}

ngOnDestroy() {
  this.contextInfoDetection.unsubscribe();
  this.inferenceDetection.unsubscribe();
  this.isLoadedDetection.unsubscribe();
  this.isListeningDetection.unsubscribe();
  this.errorDetection.unsubscribe();
  this.rhinoService.release();
}

React

yarn add @picovoice/rhino-react @picovoice/web-voice-processor

(或者)

npm install @picovoice/rhino-react @picovoice/web-voice-processor
import React, { useEffect } from 'react';
import { useRhino } from '@picovoice/rhino-react';

const RHINO_CONTEXT_BASE64 = /* Base64 representation of a Rhino context (.rhn) for WASM, omitted for brevity */
const RHN_MODEL_BASE64 = /* Base64 representation of a Rhino parameter model (.pv), omitted for brevity */

function VoiceWidget(props) {
  const {
    inference,
    contextInfo,
    isLoaded,
    isListening,
    error,
    init,
    process,
    release,
  } = useRhino();

  useEffect(() => {
    if (!isLoaded) {
      init(
        "${ACCESS_KEY}", // AccessKey obtained from Picovoice Console (https://console.picovoice.ai/)
        { base64: RHINO_CONTEXT_BASE64 },
        { base64: RHN_MODEL_BASE64 }
      );
    }
  }, [isLoaded])

return (
  <div className="voice-widget">
    <button onClick={() => process()} disabled={isListening || !isLoaded || error !== null}>
      Process
    </button>
    <p>{JSON.stringify(inference)}</p>
  </div>
)

Vue

yarn add @picovoice/rhino-vue @picovoice/web-voice-processor

(或者)

npm install @picovoice/rhino-vue @picovoice/web-voice-processor
<script lang='ts'>
import { useRhino } from '@picovoice/rhino-vue';

import rhinoParams from "${PATH_TO_RHINO_PARAMS_BASE64}";
import rhinoContext from "${PATH_TO_RHINO_CONTEXT_BASE64}";

export default {
  data() {
    const {
      state,
      init,
      process,
      release
    } = useRhino();

    init(
      ${ACCESS_KEY},
      { base64: rhinoContext },
      { base64: rhinoParams },
    );

    return {
      state,
      process,
      release
    }
  },
  watch: {
    "state.inference": function(inference) {
      if (inference !== null) {
        console.log(inference)
      }
    },
    "state.contextInfo": function(contextInfo) {
      if (contextInfo !== null) {
        console.log(contextInfo)
      }
    },
    "state.isLoaded": function(isLoaded) {
      console.log(isLoaded)
    },
    "state.isListening": function(isListening) {
      console.log(isListening)
    },
    "state.error": function(error) {
      console.error(error)
    },
  },
  onBeforeDestroy() {
    this.release();
  },
};
</script>

Node.js

安装Node.js SDK

yarn add @picovoice/rhino-node

通过指定上下文文件的路径创建Rhino类的实例

const Rhino = require("@picovoice/rhino-node");
const accessKey = "${ACCESS_KEY}" // Obtained from the Picovoice Console (https://console.picovoice.ai/)
let handle = new Rhino(accessKey, "/path/to/context/file.rhn");

当实例化后,可以通过handle对象的.process方法处理音频

let getNextAudioFrame = function() {
    ...
};

let isFinalized = false;
while (!isFinalized) {
  isFinalized = handle.process(getNextAudioFrame());
  if (isFinalized) {
    let inference = engineInstance.getInference();
    // Insert inference event callback
  }
}

完成后,务必使用release()方法释放WebAssembly获取的资源

handle.release();

Rust

首先,您需要在您的系统上安装Rust和Cargo

要将rhino库添加到您的应用中,将pv_rhino添加到您的应用的Cargo.toml清单文件中。

[dependencies]
pv_rhino = "*"

要创建引擎实例,首先创建一个带有语音到意图引擎配置参数的RhinoBuilder实例,然后调用.init()方法。

use rhino::RhinoBuilder;

let access_key = "${ACCESS_KEY}"; // AccessKey obtained from Picovoice Console (https://console.picovoice.ai/)

let rhino: Rhino = RhinoBuilder::new(access_key, "/path/to/context/file.rhn").init().expect("Unable to create Rhino");

要向Rhino输入音频,请在捕获循环中使用process函数。

fn next_audio_frame() -> Vec<i16> {
    // get audio frame
}

loop {
    if let Ok(is_finalized) = rhino.process(&next_audio_frame()) {
        if is_finalized {
            if let Ok(inference) = rhino.get_inference() {
                if inference.is_understood {
                    let intent = inference.intent.unwrap();
                    let slots = inference.slots;
                    // add code to take action based on inferred intent and slot values
                } else {
                    // add code to handle unsupported commands
                }
            }
        }
    }
}

C

Rhino是用ANSI C实现的,因此可以直接链接到C应用程序。头文件pv_rhino.h包含相关信息。 Rhino对象的实例可以按如下方式构建

const char *access_key = "${ACCESS_KEY}" // obtained from the Picovoice Console (https://console.picovoice.ai/)
const char *model_path = ... // Available at lib/common/rhino_params.pv
const char *context_path = ... // absolute path to context file for the domain of interest
const float sensitivity = 0.5f;
bool require_endpoint = false;

pv_rhino_t *handle = NULL;
const pv_status_t status = pv_rhino_init(access_key, model_path, context_path, sensitivity, require_endpoint, &handle);
if (status != PV_STATUS_SUCCESS) {
    // add error handling code
}

现在,可以使用handle从传入的音频流中推断意图。Rhino接受单通道、16位PCM音频。可以通过pv_sample_rate()获取采样率。最后,Rhino接受连续块(帧)的输入音频;可以通过pv_rhino_frame_length()获取每个帧的长度。

extern const int16_t *get_next_audio_frame(void);

while (true) {
    const int16_t *pcm = get_next_audio_frame();

    bool is_finalized = false;
    pv_status_t status = pv_rhino_process(handle, pcm, &is_finalized);
    if (status != PV_STATUS_SUCCESS) {
        // add error handling code
    }

    if (is_finalized) {
        bool is_understood = false;
        status = pv_rhino_is_understood(rhino, &is_understood);
        if (status != PV_STATUS_SUCCESS) {
            // add error handling code
        }

        if (is_understood) {
            const char *intent = NULL;
            int32_t num_slots = 0;
            const char **slots = NULL;
            const char **values = NULL;
            status = pv_rhino_get_intent(rhino, &intent, &num_slots, &slots, &values);
            if (status != PV_STATUS_SUCCESS) {
                // add error handling code
            }

            // add code to take action based on inferred intent and slot values

            pv_rhino_free_slots_and_values(rhino, slots, values);
        } else {
            // add code to handle unsupported commands
        }

        pv_rhino_reset(rhino);
    }
}

完成时,请记住释放所获取的资源。

pv_rhino_delete(rhino);

版本发布

v2.2.0 - 2023年4月12日

  • 添加了对阿拉伯语、荷兰语、印地语、中文、波兰语、俄语、瑞典语和越南语的本地化支持
  • 添加了对.NET 7.0的支持,并修复了对.NET Standard 2.0的支持
  • 将iOS最低支持版本提升到11.0
  • 提高了稳定性和性能

v2.1.0 - 2022年1月20日

  • 为Java和Unity SDK添加macOS arm64支持
  • 支持非英语内置槽
  • 添加了对宏的支持
  • 各种错误修复和改进

v2.0.0 - 2021年11月25日

  • 提高了准确性。
  • 添加了Rust SDK。
  • 支持macOS arm64。
  • 为Windows、NVIDIA Jetson Nano和BeagleBone添加了对NodeJS的支持。
  • 为NVIDIA Jetson Nano和BeagleBone添加了对.NET的支持。
  • 运行时优化。

v1.6.0 2020年12月2日

  • 增加对React Native的支持。
  • 增加对Java的支持。
  • 增加对.NET的支持。
  • 增加对NodeJS的支持。

v1.5.0 2020年6月4日

  • 准确性提升。

v1.4.0 2020年4月13日

  • 准确性提升。
  • 本地插槽。

v1.3.0 2020年2月13日

  • 准确性提升。
  • 运行时优化。
  • 增加对Raspberry Pi 4的支持。
  • 增加对JavaScript的支持。
  • 增加对iOS的支持。
  • 更新文档。

v1.2.0 2019年4月26日

  • 准确性提升。
  • 运行时优化。

v1.1.0 2018年12月23日

  • 准确性提升。
  • 开源的树莓派构建。

v1.0.0 2018年11月2日

  • 初始版本

常见问题

您可以在这里找到常见问题。