Speech Recognition with Vue
Tags: 100daysofcode, challenge, webdev, vue
Published: 2023-02-09 18:18:10

Keyword spotting is the first defined problem in speech recognition. It enables applications such as wake word detection. 

On day 29, we'll work with [Porcupine Wake Word Vue SDK](https://picovoice.ai/docs/quick-start/porcupine-vue/) 

**1. Setup the Project**

- Create a new Vue project (with TypeScript support):

```
npm init vue@latest
```
- Update `tsconfig.config.json` to:

```
{
  "extends": "@vue/tsconfig/tsconfig.node.json",
  "include": [
    "vite.config.*",
    "vitest.config.*",
    "cypress.config.*",
    "playwright.config.*"
  ],
  "compilerOptions": {
    "allowSyntheticDefaultImports": true,
    "composite": true,
    "esModuleInterop": true,
    "moduleResolution": "node",
    "types": ["node"]
  }
}
```
- Update `vite.config.ts` to:

```
import { fileURLToPath, URL } from "node:url";

import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
  resolve: {
    alias: {
      "@": fileURLToPath(new URL("./src", import.meta.url)),
    },
  },
  optimizeDeps: {
    include: ["@/lib/porcupine_params.js", "@/lib/hey_jarvis.js"],
  },
  build: {
    commonjsOptions: {
      include: [/lib/],
    },
  },
});
```
- Install the dependencies:

```
npm install @picovoice/porcupine-vue @picovoice/web-voice-processor
```
Download the Porcupine [model](https://github.com/Picovoice/porcupine/raw/master/lib/common/porcupine_params.pv). Turn the binary model into a base64 string by running: 
```
npx pvbase64 \
-i ${DOWNLOADED_MODEL_PATH} \
-o src/lib/porcupine_params.js
```
_Don't forget to replace _${DOWNLOADED_MODEL_PATH}. It could be something like ~/Downloads/porcupine_params.pv depending on where you save downloaded files.
- Run the local server to load the page:

```
npm run dev
```
2. Train Wake Word Models
- Sign up for [Picovoice Console](https://console.picovoice.ai/) for free
- Go to the Porcupine Page.
- Select English as the language for your model.
- Type in Hey Jarvis as the phrase you want to build the model for.
- Select Web (WASM) as the platform.
- Click on Download. 
- Unzip the folder and find the file with the suffix `.ppn`. That's Porcupine Wake Word model. 
- Transform it into a `base64` string. Remember that you need to replace 

```
npx pvbase64 \
-i ${DOWNLOADED_PPN_PATH} \
-o src/lib/hey_jarvis.js \
-n heyJarvisKeywordModel
```
Again do not forget to replace ${DOWNLOADED_PPN_PATH}. It might be something like _~/Downloads/Hey-Jarvis_en_wasm_v2_1_0/Hey-Jarvis_en_wasm_v2_1_0.ppn_

**Let's wrap up**
- Get your `AccessKey` from the [Picovoice Console](https://console.picovoice.ai/).
- Create a component called `VoiceWidget` and paste the below into it. Remember to replace ${ACCESS_KEY} with your `AccessKey`.

```
<template>
  <div class="voice-widget">
    <h3>
      <button class="start-button" v-on:click="initEngine">
        Start
      </button>
    </h3>
    <ul v-if="detections.length > 0">
      <li v-for="(item, index) in detections" :key="index">
        {{ item }}
      </li>
    </ul>
  </div>
</template>

<script lang="ts">
import { onBeforeUnmount, defineComponent, ref, watch } from "vue";
import { usePorcupine } from "@picovoice/porcupine-vue";
// @ts-ignore
import modelParams from "@/lib/porcupine_params.js";
// @ts-ignore
import heyJarvisKeywordModel from "@/lib/hey_jarvis.js";

const VoiceWidget = defineComponent({
  name: "VoiceWidget",
  setup() {
    const porcupine = usePorcupine();
    const detections = ref<string[]>([]);
    watch(
      () => porcupine.state.keywordDetection,
      keyword => {
        if (keyword !== null) {
          detections.value.push(keyword.label);
        }
      }
    );
    async function initEngine() {
      await porcupine.init(
        ${ACCESS_KEY},
        {
            "base64": heyJarvisKeywordModel,
            "label": "Hey Jarvis"
        },
        { base64: modelParams }
      );
      await porcupine.start();
    }
    onBeforeUnmount(() => {
      porcupine.release();
    });
    return {
      detections,
      initEngine,
      ...porcupine,
    };
  },
});
export default VoiceWidget;
</script>
```
- Update App:

```
<template>
  <div>
    <VoiceWidget />
  </div>
</template>

<script>
import { defineComponent, defineAsyncComponent } from "vue";
export default defineComponent({
  name: "App",
  components: {
    VoiceWidget: defineAsyncComponent(() =>
      import("./components/VoiceWidget.vue")
    ),
  },
});
</script>
```
This article was first published on the [Picovoice Blog](https://picovoice.ai/blog/always-listening-voice-commands-for-vuejs/).