angularPicovoice - Angular API

  • Wake Word Engine
  • Offline Voice Commands
  • Local Speech Recognition
  • Always Listening
  • npm

This document outlines how to integrate the Picovoice SDK within an application using its Angular API.

Requirements

  • Angular 16.8+
  • yarn (or npm)

Compatibility

  • Chrome, Edge
  • Firefox
  • Safari

The Picovoice SDKs for Web are powered by WebAssembly (WASM), the Web Audio API, and Web Workers.

All modern browsers (Chrome/Edge/Opera, Firefox, Safari) are supported, including on mobile. Internet Explorer is not supported.

Using the Web Audio API requires a secure context (HTTPS connection), with the exception of localhost, for local development.

Installation

Use npm or yarn to install the package and its peer dependencies. Each spoken language (e.g. 'en', 'de') is a separate package. For this example we'll use English:

yarn add @picovoice/picovoice-web-angular @picovoice/picovoice-web-en-worker @picovoice/web-voice-processor

(or)

npm install @picovoice/picovoice-web-angular @picovoice/picovoice-web-en-worker @picovoice/web-voice-processor

Language-specific Picovoice web worker packages

These worker packages are compatible with the Angular SDK:

Usage

Picovoice SDK for Angular is provided as a service. In your Angular component, add the PicovoiceService. The PicovoiceService has keyword$ and inference$ events to which you can subscribe:

import { Subscription } from "rxjs"
import { PicovoiceService } from "@picovoice/picovoice-web-angular"
...
constructor(private picovoiceService: PicovoiceService) {
// Subscribe to Picovoice Keyword detections
// Store each detection so we can display it in an HTML list
this.keywordDetection = picovoiceService.keyword$.subscribe(
keywordLabel => this.detections = [...this.detections, keywordLabel])
// Subscribe to Rhino Inference events
// Show the latest one in the widget
this.inferenceDetection = picovoiceService.inference$.subscribe(
inference => this.latestInference = inference)
}

We need to initialize Picovoice to tell it which keyword and context we want to listen to (and at what sensitivity). We can use the Angular lifecycle hooks ngOnInit and ngOnDestroy to start up and later tear down the Picovoice engines.

async ngOnInit() {
// Load Picovoice worker chunk with specific language model (large ~4-6MB chunk; dynamically imported)
const pvFactoryEn = (await import('@picovoice/picovoice-web-en-worker')).PicovoiceWorkerFactory
// Initialize Picovoice Service
try {
await this.picovoiceService.init(pvFactoryEn,
{
// Built-in wake word
porcupineKeyword: {builtin: "Hey Google", sensitivity: 0.6},
// Rhino context (Base64 representation of a `.rhn` file)
rhinoContext: { base64: RHINO_CLOCK_64 },
start: true
})
}
catch (error) {
console.error(error)
}
}
ngOnDestroy() {
this.keywordDetection.unsubscribe()
this.inferenceDetection.unsubscribe()
this.picovoiceService.release()
}

The PicovoiceServiceArgs accepts a single porcupineKeyword of type PorcupineKeyword object argument(s). PorcupineKeyword can be either PorcupineKeywordBuiltin or PorcupineKeywordCustom:

export type PorcupineKeywordBuiltin = {
/** Name of a builtin keyword for the specific language (e.g. "Grasshopper" for English, or "Ananas" for German) */
builtin: string
/** Value in range [0,1] that trades off miss rate for false alarm */
sensitivity?: number
}
EnglishFrenchGermanSpanish
  • "Americano"
  • "Blueberry"
  • "Bumblebee"
  • "Grapefruit"
  • "Grasshopper"
  • "Hey Google"
  • "Hey Siri"
  • "Jarvis"
  • "Okay Google"
  • "Picovoice"
  • "Porcupine"
  • "Terminator"
  • "Framboise"
  • "Mon Chouchou"
  • "Parapluie"
  • "Perroquet"
  • "Tournesol"
  • "Ananas"
  • "Heuschrecke"
  • "Himbeere"
  • "Leguan"
  • "Stachelschwein"
  • "Emparedado"
  • "Leopardo"
  • "Manzana"
  • "Murcielago"

If you simply pass a string of a builtin keyword instead of an object, that will also work.

Use PorcupineKeywordCustom for custom keywords:

export type PorcupineKeywordCustom = {
/** Base64 representation of a trained Porcupine keyword (`.ppn` file) */
base64: string
/** An arbitrary label that you want Porcupine to report when the detection occurs */
custom: string
/** Value in range [0,1] that trades off miss rate for false alarm */
sensitivity?: number
}

Imports

Using static imports for the picovoice-web-xx-worker packages is straightforward, but will impact your initial bundle size with an additional ~6MB. Depending on your requirements, this may or may not be feasible. If you require a small bundle size, see dynamic importing below.

Static Import

import {PicovoiceWorkerFactory as pvFactoryEn } from '@picovoice/picovoice-web-en-worker'
async ngOnInit() {
const pvFactoryEn =
// Initialize Picovoice Service
try {
await this.picovoiceService.init(pvFactoryEn,
{
// Built-in wake word
porcupineKeyword: {builtin: "Hey Google", sensitivity: 0.6},
// Rhino context (Base64 representation of a `.rhn` file)
rhinoContext: { base64: RHINO_CLOCK_64 },
start: true
})
}
catch (error) {
console.error(error)
}
}
ngOnDestroy() {
this.keywordDetection.unsubscribe()
this.inferenceDetection.unsubscribe()
this.picovoiceService.release()
}

Dynamic Import

async ngOnInit() {
// Load Picovoice worker chunk with specific language model (large ~4-6MB chunk; dynamically imported)
const pvFactoryEn = (await import('@picovoice/picovoice-web-en-worker')).PicovoiceWorkerFactory
// Initialize Picovoice Service
try {
await this.picovoiceService.init(pvFactoryEn,
{
// Built-in wake word
porcupineKeyword: {builtin: "Hey Google", sensitivity: 0.6},
// Rhino context (Base64 representation of a `.rhn` file)
rhinoContext: { base64: RHINO_CLOCK_64 },
start: true
})
}
catch (error) {
console.error(error)
}
}
ngOnDestroy() {
this.keywordDetection.unsubscribe()
this.inferenceDetection.unsubscribe()
this.picovoiceService.release()
}

Issue with this doc? Please let us know.