सार्वजनिक जानकारी से बना चयन मार्गदर्शन। केवल संदर्भ हेतु।
Rhino Flutter एक Flutter प्लगइन है जो Picovoice के Rhino स्पीच-टू-इंटेंट इंजन को एकीकृत करता है, जिससे ऐप्स को उच्च सटीकता और कम लेटेंसी के साथ बोली गई आदेशों को समझने में सक्षम बनाता है। यह डिवाइस पर इंफेरेंस समर्थन करता है, जिससे गोपनीयता और त्वरित प्रतिक्रिया सुनिश्चित होती है। ध्वनि सहायकों के लिए डिज़ाइन किया गया है, जिससे उपयोगकर्ता प्राकृतिक भाषा इनपुट के आधार पर कार्रवाई शुरू कर सकते हैं बिना बादल सेवाओं पर निर्भर होए। प्लगइन दोनों Android और iOS प्लेटफॉर्म पर बिना किसी समस्या के काम करता है।
उपयोग
वॉइस कंट्रोल एप्लिकेशन्स
स्मार्ट होम इंटीग्रेशन
हैंड्स-फ्री उपयोगकर्ता इंटरफेस
डिवाइस पर कमांड स्वीकृति
इंटरैक्टिव वॉयस असिस्टेंट्स
मुख्य विशेषताएँ
डिवाइस-आधारित बोलने-से-इच्छा प्रोसेसिंग
कम लेटेंसी इन्फेरेंस
गोपनीयता-रक्षित स्थानीय निष्पादन
बहुभाषी समर्थन
कस्टम वेक वर्ड और इंटेंट डिटेक्शन
इनके लिए उपयुक्त
वॉइस-समर्थित ऐप बनाने वाले डेवलपर्स
ऑफलाइन कार्यक्षमता की आवश्यकता वाले ऐप्स
उपयोगकर्ता गोपनीयता प्राथमिकता वाले प्रोजेक्ट
रियल-टाइम वॉइस इंटरैक्शन सिस्टम
प्लेटफॉर्म-समन्वय एम्बेडेड वॉइस असिस्टेंट
विचार योग्य बातें
मॉडल फ़ाइल सेटअप की आवश्यकता है
पूर्वनिर्धारित इच्छाओं तक सीमित
प्रदर्शन उपकरण के हार्डवेयर पर निर्भर करता है
प्रारंभिक सेटअप मॉडल कॉन्फ़िगरेशन शामिल होता है
सामान्य उद्देश्य के लिए बोली की पहचान के लिए उपयुक्त नहीं
मूल README
संबंधित सोर्स रिपॉज़िटरी के मूल README का स्नैपशॉट। नवीनतम सामग्री के लिए रिपॉज़िटरी देखें।
Rhino is Picovoice's Speech-to-Intent engine. It directly infers intent from spoken commands within a given context of
interest, in real-time. For example, given a spoken command:
Can I have a small double-shot espresso?
Rhino infers what the user wants and emits the following inference result:
A comparison between the accuracy of Rhino and major cloud-based alternatives is provided
here. Below is the summary of the benchmark:
Terminology
Rhino infers the user's intent from spoken commands within a domain of interest. We refer to such a specialized domain as
a Context. A context can be thought of a set of voice commands, each mapped to an intent:
In examples above, each voice command is called an Expression. Expressions are what we expect the user to utter
to interact with our voice application.
Consider the expression:
Turn off the lights in the office
What we require from Rhino is:
To infer the intent (turnLightOff)
Record the specific details from the utterance, in this case the location (office)
We can capture these details using slots by updating the expression:
$location:lightLocation means that we expect a variable of type location to occur, and we want to capture its value
in a variable named lightLocation. We call such variable a Slot. Slots give us the ability to capture details of the
spoken commands. Each slot type is be defined as a set of phrases. For example:
Replace ${CONTEXT_PATH} with either a context file created using Picovoice Console or one within the repository.
For more information about Python demos, go to demo/python.
.NET Demos
Rhino .NET demo is a command-line application that lets you choose between running Rhino on an audio
file or on real-time microphone input.
Make sure there is a working microphone connected to your device. From demo/dotnet/RhinoDemo
run the following in the terminal:
dotnet run -c MicDemo.Release -- --access_key ${ACCESS_KEY} --context_path ${CONTEXT_FILE_PATH}
Replace ${ACCESS_KEY} with your Picovoice AccessKey and ${CONTEXT_FILE_PATH} with either a context file created using Picovoice Console or one within the repository.
For more information about .NET demos, go to demo/dotnet.
Java Demos
The Rhino Java demo is a command-line application that lets you choose between running Rhino on an
audio file or on real-time microphone input.
To try the real-time demo, make sure there is a working microphone connected to your device. Then invoke the following commands from the terminal:
cd demo/java
./gradlew build
cd build/libs
java -jar rhino-mic-demo.jar -a ${ACCESS_KEY} -c ${CONTEXT_FILE_PATH}
Replace ${CONTEXT_FILE_PATH} with either a context file created using Picovoice Console or one within the repository.
For more information about Java demos go to demo/java.
Flutter Demos
To run the Rhino demo on Android or iOS with Flutter, you must have the Flutter SDK installed on your system. Once installed, you can run flutter doctor to determine any other missing requirements for your relevant platform. Once your environment has been set up, launch a simulator or connect an Android/iOS device.
Run the prepare_demo script with a language code to set up the demo in the language of your
choice (e.g. de -> German, ko -> Korean). To see a list of available languages, run prepare_demo without a language code.
cd demo/flutter
dart scripts/prepare_demo.dart ${LANGUAGE}
Run the following command to build and deploy the demo to your device:
cd demo/flutter
flutter run
Once the demo app has started, press the start button and utter a command to start inferring context. To see more details about the current context information, press the Context Info button on the top right corner in the app.
React Native Demos
To run the React Native Rhino demo app you will first need to set up your React Native environment. For this,
please refer to React Native's documentation. Once your environment has
been set up, navigate to demo/react-native/RhinoDemo to run the following commands:
For Android:
yarn android-install # sets up environment
yarn android-run # builds and deploys to Android
For iOS:
yarn ios-install # sets up environment
yarn ios-run # builds and deploys to iOS
Both demos use a smart lighting context, which can understand commands such as:
Turn off the lights.
or
Set the lights in the living room to purple.
Android Demos
Using Android Studio, open demo/android/Activity as an Android project and then run the
application.
Once the demo app has started, press the Start button and speak a command from the context to start inference. To see more details about
the current context information, press the Show Context button on the top right corner in the app.
For more information about Android demo, go to demo/android.
Replace let accessKey = "${YOUR_ACCESS_KEY_HERE}" in the file ContentView.swift with your AccessKey.
Go to Product > Scheme and select the scheme for the language you would like to demo (e.g. esDemo -> Spanish Demo, deDemo -> German Demo)
Run the demo with a simulator or connected iOS device.
Once the demo app has started, press the Start button to infer audio within a context. To see more details about
the current context information, press the Context Info button on the top right corner in the app.
For more information about iOS demo, go to demo/ios.
Web Demos
Vanilla JavaScript and HTML
From demo/web use yarn or npm to install the dependencies, and the start script with a language code
to start a local web server hosting the demo in the language of your choice (e.g. pl -> Polish, ko -> Korean).
To see a list of available languages, run start without a language code.
yarn
yarn start ${LANGUAGE}
(or)
npm install
npm run start ${LANGUAGE}
Open http://localhost:5000 in your browser to try the demo.
React Demos
From demo/react use yarn or npm to install the dependencies, and the start script with a language code
to start a local web server hosting the demo in the language of your choice (e.g. pl -> Polish, ko -> Korean).
To see a list of available languages, run start without a language code.
yarn
yarn start ${LANGUAGE}
(or)
npm install
npm run start ${LANGUAGE}
Open http://localhost:3000 in your browser to try the demo.
Node.js Demos
Install the demo package:
yarn global add @picovoice/rhino-node-demo
With a working microphone connected to your device, run the following in the terminal:
Replace ${LIBRARY_PATH} with path to appropriate library available under lib, ${PLATFORM} with the
name of the platform you are running on (linux, raspberry-pi, or mac), ${AUDIO_DEVICE_INDEX} with
the index of your audio device and ${ACCESS_KEY} with your Picovoice AccessKey.
Replace ${LIBRARY_PATH} with path to appropriate library available under lib, ${PLATFORM} with the
name of the platform you are running on (linux, raspberry-pi, or mac) and ${ACCESS_KEY}
with your Picovoice AccessKey.
Where context_path is the absolute path to the Speech-to-Intent context created either using Picovoice Console or one of
the default contexts available on Rhino's GitHub repository.
When initialized, the required sample rate can be obtained using rhino.sample_rate. The expected frame length
(number of audio samples in an input array) is provided by rhino.frame_length. The object can be used to infer intent from spoken
commands as below:
defget_next_audio_frame():
passwhileTrue:
is_finalized = handle.process(get_next_audio_frame())
if is_finalized:
inference = handle.get_inference()
ifnot inference.is_understood:
# add code to handle unsupported commandspasselse:
intent = inference.intent
slots = inference.slots
# add code to take action based on inferred intent and slot values
Finally, when done be sure to explicitly release the resources using handle.delete().
.NET
Install the .NET SDK using NuGet or the dotnet CLI:
dotnet add package Rhino
The SDK exposes a factory method to create instances of the engine as below:
When initialized, the valid sample rate is given by handle.SampleRate. The expected frame length (number of audio samples
in an input array) is handle.FrameLength. The engine accepts 16-bit linearly-encoded PCM and operates on
single-channel audio.
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 will have its resources freed by the garbage collector, but to have resources freed
immediately after use, wrap it in a using statement:
The Rhino Java binding is available from the Maven Central Repository at ai.picovoice:rhino-java:${version}.
The SDK exposes a Builder that allows you to create an instance of the engine:
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) { }
When initialized, the valid sample rate is given by handle.getSampleRate(). The expected frame length (number of audio samples
in an input array) is handle.getFrameLength(). The engine accepts 16-bit linearly-encoded PCM and operates on
single-channel audio.
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
}
}
}
Once you are done with Rhino, ensure you release its resources explicitly:
The inferenceCallback parameter is a function that you want to execute when Rhino makes an inference.
The function should accept a RhinoInference instance that represents the inference result.
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
}
}
Once you have instantiated a RhinoManager, you can start audio capture and intent inference using the .process() function.
Audio capture stops and rhino resets once an inference result is returned via the inference callback.
Once your app is done with using RhinoManager, be sure you explicitly release the resources allocated for it:
_rhinoManager.delete();
Our flutter_voice_processor Flutter plugin captures the frames of audio and automatically passes it to the speech-to-intent engine.
Low-Level API
Rhino provides low-level access to the inference engine for those who want to incorporate
speech-to-intent into an already existing audio processing pipeline.
Rhino is created by passing a context file to its static constructor create:
To deliver audio to the engine, you must send audio frames to its process function.
Each call to process will return a RhinoInference instance with following variables:
isFinalized - true if Rhino has made an inference, false otherwise
isUnderstood - null if isFinalized is false, otherwise true if Rhino understood what it heard based on the context or false if it did not
intent - null if isUnderstood is not true, otherwise name of intent that were inferred
slots - null if isUnderstood is not true, otherwise the dictionary of slot keys and values that were inferred
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
}
}
} onRhinoExceptioncatch (error) {
// handle error
}
// once you are donethis._rhino.delete();
Once you have instantiated a RhinoManager, you can start/stop audio capture and intent inference by calling .process().
Upon receiving an inference callback, audio capture will stop automatically and Rhino will reset. To restart it you must
call .process() again.
let didStart = awaitthis._rhinoManager.process();
When you are done using Rhino, you must explicitly release resources:
Rhino provides low-level access to the inference engine for those
who want to incorporate speech-to-intent into an already existing audio processing pipeline.
Rhino is created by passing a context file to its static constructor create:
To deliver audio to the engine, you must pass it audio frames
using the process function. The RhinoInference result that is returned from process will have up to four fields:
isFinalized - true if Rhino has made an inference, false otherwise
isUnderstood - null if isFinalized is false, otherwise true if Rhino understood what it heard based on the context or false if it did not
intent - null if isUnderstood is not true, otherwise name of intent that were inferred
slots - null if isUnderstood is not true, otherwise the dictionary of slot keys and values that were inferred
let buffer = getAudioFrame();
try {
let inference = awaitthis._rhino.process(buffer);
// use result// ..
}
} catch (e) {
// handle error
}
// once you are donethis._rhino.delete();
Android
To include the package in your Android project, ensure you have included mavenCentral() in your top-level build.gradle file and then add the following to your app's build.gradle:
There are two possibilities for integrating Rhino into an Android application: the High-level API and the Low-level API.
High-Level API
RhinoManager provides a high-level API
for integrating Rhino into Android applications. It manages all activities related to creating an input audio stream,
feeding it into Rhino, and invoking a user-provided inference callback. Context files (.rhn)
should be placed under the Android project assets folder (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) { }
The appContext parameter is the Android application context - this is used to extract Rhino resources from the APK.
Sensitivity is the parameter that enables developers to trade miss rate for false alarm. It is a floating-point number within
[0, 1]. A higher sensitivity reduces miss rate at cost of increased false alarm rate.
When initialized, input audio can be processed using manager.process(). When done, be sure to release the resources
using manager.delete().
Low-Level API
Rhino provides a binding for Android using JNI. It can be initialized using:
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) { }
Once initialized, handle can be used for intent inference:
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
}
Finally, prior to exiting the application be sure to release resources acquired:
handle.delete()
iOS
The Rhino iOS binding is available via CocoaPods. To import it into your iOS project, add the following line to your Podfile and run pod install:
pod 'Rhino-iOS'
There are two approaches for integrating Rhino into an iOS application: The high-level API and the low-level API.
High-Level API
RhinoManager provides a high-level API
for integrating Rhino into iOS applications. It manages all activities related to creating an input audio stream, feeding it to the engine, and invoking a user-provided inference callback.
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 { }
Sensitivity is the parameter that enables developers to trade miss rate for false alarm. It is a floating-point number within
[0, 1]. A higher sensitivity reduces miss rate at cost of increased false alarm rate.
When initialized, input audio can be processed using manager.process(). When done, be sure to release the resources
using manager.delete().
Low-Level API
Rhino provides low-level access to the Speech-to-Intent engine for those who want to incorporate intent inference into an already existing audio processing pipeline.
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 { }
Once initialized, handle can be used for intent inference:
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 { }
}
Finally, prior to exiting the application be sure to release resources acquired:
handle.delete()
Web
Rhino is available on modern web browsers (i.e. not Internet Explorer) via WebAssembly. Microphone audio is handled via the Web Audio API and is abstracted by the WebVoiceProcessor, which also handles downsampling to the correct format. Rhino is provided pre-packaged as a Web Worker.
Vanilla JavaScript and HTML (CDN Script Tag)
<!DOCTYPE html><htmllang="en"><head><scriptsrc="https://unpkg.com/@picovoice/rhino-web/dist/iife/index.js"></script><scriptsrc="https://unpkg.com/@picovoice/web-voice-processor/dist/iife/index.js"></script><scripttype="application/javascript">constRHINO_CONTEXT_BASE64 = /* Base64 representation of `.rhn` context file */;
constRHINO_MODEL_BASE64 = /* Base64 representation of the `.pv` model file */;
let rhino = null;
functionrhinoInferenceCallback(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.");
}
}
asyncfunctionstartRhino() {
console.log("Rhino is loading. Please wait...");
rhino = awaitRhinoWeb.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><buttonid="push-to-talk">Push to Talk</button></body></html>
import { WebVoiceProcessor } from"@picovoice/web-voice-processor"import { RhinoWorker } from"@picovoice/rhino-web";
constRHN_CONTEXT_BASE64 = /* Base64 representation of a `.rhn` context file */constRHINO_MODEL_BASE64 = /* Base64 representation of the `.pv` model file*/;
let rhino = nullfunctionrhinoInferenceCallback(inference) {
if (inference.isFinalized) {
console.log(`Rhino inference: ${JSON.stringify(inference)}`);
WebVoiceProcessor.unsubscribe(rhino);
}
}
asyncfunctionstartRhino() {
// Create a Rhino Worker to listen for commands in the specified context
rhino = awaitRhinoWorker.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.functionpushToTalk() {
if (rhino) {
WebVoiceProcessor.subscribe(rhino);
}
}
startRhino()
...
// Finished with Rhino? Release the WebVoiceProcessor and the worker.if (done) {
WebVoiceProcessor.unsubscribe(rhino);
rhino.release()
rhino.terminate()
}
importReact, { useEffect } from'react';
import { useRhino } from'@picovoice/rhino-react';
constRHINO_CONTEXT_BASE64 = /* Base64 representation of a Rhino context (.rhn) for WASM, omitted for brevity */constRHN_MODEL_BASE64 = /* Base64 representation of a Rhino parameter model (.pv), omitted for brevity */functionVoiceWidget(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 (
<divclassName="voice-widget"><buttononClick={() => process()} disabled={isListening || !isLoaded || error !== null}>
Process
</button><p>{JSON.stringify(inference)}</p></div>
)
Node.js
Install the Node.js SDK:
yarn add @picovoice/rhino-node
Create instances of the Rhino class by specifying the path to the context file:
constRhino = require("@picovoice/rhino-node");
const accessKey = "${ACCESS_KEY}"// Obtained from the Picovoice Console (https://console.picovoice.ai/)let handle = newRhino(accessKey, "/path/to/context/file.rhn");
When instantiated, handle can process audio via its .process method:
let getNextAudioFrame = function() {
...
};
let isFinalized = false;
while (!isFinalized) {
isFinalized = handle.process(getNextAudioFrame());
if (isFinalized) {
let inference = engineInstance.getInference();
// Insert inference event callback
}
}
When done, be sure to release resources acquired by WebAssembly using release():
handle.release();
C
Rhino is implemented in ANSI C and therefore can be directly linked to C applications. The pv_rhino.h
header file contains relevant information. An instance of the Rhino object can be constructed as follows:
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 *device = "best";
const char *context_path = ... // absolute path to context file for the domain of interest
const float sensitivity = 0.5f;
const float endpoint_duration_sec = 1.0f;
const bool require_endpoint = false;
pv_rhino_t *handle = NULL;
const pv_status_t status = pv_rhino_init(
access_key,
model_path,
device,
context_path,
sensitivity,
endpoint_duration_sec,
require_endpoint,
&handle);
if (status != PV_STATUS_SUCCESS) {
// add error handling code
}
Now the handle can be used to infer intent from an incoming audio stream. Rhino accepts single channel, 16-bit PCM
audio. The sample rate can be retrieved using pv_sample_rate(). Finally, Rhino accepts input audio in consecutive chunks
(frames); the length of each frame can be retrieved using 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);
}
}
When done, remember to release the resources acquired.
pv_rhino_delete(rhino);
Releases
v4.1.0 - September 8th, 2026
Added support for context wildcard feature
v4.0.0 - December 10th, 2025
Added support for running on GPU or multiple CPU cores
Node.js min version bumped to Node 18
iOS min version bumped to iOS 16
Patches to .NET support
Deprecated support for Unity
React Native version bumped to 0.73
Flutter version bumped to Flutter 3.10+ and Dart 3.0.0+
Added MCU library support and associated demo
v3.0.0 - October 26th, 2023
Improvements to error reporting
Upgrades to authorization and authentication system
Added reset() function to API
Various bug fixes and improvements
Node min support bumped to 16
Unity editor min support bumped to 2021
Patches to .NET support
v2.2.0 - April 12th, 2023
Added language support for Arabic, Dutch, Hindi, Mandarin, Polish, Russian, Swedish and Vietnamese
Added support for .NET 7.0 and fixed support for .NET Standard 2.0
iOS minimum support moved to 11.0
Improved stability and performance
v2.1.0 - January 20th, 2022
Added macOS arm64 support for Java and Unity SDKs
Support added for non-English built-in slots
Support for Macros added
Various bug fixes and improvements
v2.0.0 - November 25th, 2021
Improved accuracy
Added Rust SDK
macOS arm64 support
Added NodeJS support for Windows, NVIDIA Jetson Nano, and BeagleBone
Added .NET support for NVIDIA Jetson Nano and BeagleBone