Getting Started with Live Transcription and Vue.js

_phzn

Kevin Lewis

Posted on July 18, 2022

Getting Started with Live Transcription and Vue.js

This post will cover how to set up Deepgram for live transcriptions in your Vue.js application. We'll set up Deepgram in a single HTML file with the Vue.js <script> include and no other dependencies.

Before We Start

You will need a free Deepgram API Key.

Setting Up a Vue Project With a Script Include

Create an index.html file and open it in a code editor. Set up a Vue project:

<html>
<head></head>
<body>
  <div id="app">
  </div>

  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.0"></script>
  <script>
    const app = new Vue({
      el: '#app'
    })
  </script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

Get Microphone Data

This code will be written in the created() lifecycle method - meaning it will happen immediately.

Firstly, ask the user for access to their mic:

const app = new Vue({
  el: '#app',
  async created() {
    const stream = await navigator.mediaDevices.getUserMedia({ audio: true })
      .catch(error => alert(error))
  }
})
Enter fullscreen mode Exit fullscreen mode

Next, plug the stream into a MediaRecorder so we can later access the raw data from the accessed microphone:

const app = new Vue({
  el: '#app',
  async created() {
    const stream = await navigator.mediaDevices.getUserMedia({ audio: true })
      .catch(error => alert(error))

    // Create MediaRecorder
    if(!MediaRecorder.isTypeSupported('audio/webm')) return alert('Unsupported browser')
    this.mediaRecorder = new MediaRecorder(stream, { mimeType: 'audio/webm' })
  },
  // Store MediaRecorder
  data: {
    mediaRecorder: null
  }
})
Enter fullscreen mode Exit fullscreen mode

Remember that if you are creating Vue components, data must be a function that returns an object.

Connect to Deepgram

Create a button which will begin transcription. Trigger a new begin() method with it's clicked:

<html>
<head></head>
<body>
  <div id="app">
    <!-- Add button -->
    <button @click="begin">Begin transcription</button>
  </div>

  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.0"></script>
  <script>
    const app = new Vue({
      el: '#app',
      async created() {
        const stream = await navigator.mediaDevices.getUserMedia({ audio: true })
          .catch(error => alert(error))

        if(!MediaRecorder.isTypeSupported('audio/webm')) return alert('Unsupported browser')
        this.mediaRecorder = new MediaRecorder(stream, { mimeType: 'audio/webm' })
      },
      data: {
        mediaRecorder: null
      },
      // Create begin method
      methods: {
        begin() {

        }
      }
    })
  </script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

Take a moment to get a free Deepgram API Key before continuing.

Use the browser native WebSocket interface to connect to Deepgram's live transcription server. Store the WebSocket instance in data:

data: {
  mediaRecorder: null,
  // Add socket
  socket: null
},
methods: {
  begin() {
    const DG_URL = 'wss://api.deepgram.com/v1/listen?language=de'
    const DG_KEY = 'YOUR_DEEPGRAM_API_KEY'
    this.socket = new WebSocket(DG_URL, ['token', DG_KEY])
  }
}
Enter fullscreen mode Exit fullscreen mode

This WebSocket creates a 2-way connection with Deepgram. See the language=de in the URL? That's telling it you'll be speaking German. We have loads of supported languages to check out!

Send Data to Deepgram

Once the WebSocket connection is open, start sending mic data:

methods: {
  begin() {
    const DG_URL = 'wss://api.deepgram.com/v1/listen?language=de'
    const DG_KEY = 'YOUR_DEEPGRAM_API_KEY'
    this.socket = new WebSocket(DG_URL, ['token', DG_KEY])
    // Run the startStreaming method when socket is opened
    this.socket.onopen = this.startStreaming
  },
  // Create startStreaming method
  startStreaming() {
    this.mediaRecorder.addEventListener('dataavailable', event => {
      if(event.data.size > 0 && this.socket.readyState == 1) {
        this.socket.send(event.data)
      }
      // Send data every 250ms (.25s)
      mediaRecorder.start(250)
    })
  }
}
Enter fullscreen mode Exit fullscreen mode

Receive Transcript Results

You are currently sending data through our persistent connection to Deepgram every 0.25 seconds. You will receive transcripts back nearly as often - it's time to write the handling code.

methods: {
  begin() {
    const DG_URL = 'wss://api.deepgram.com/v1/listen?language=de'
    const DG_KEY = 'YOUR_DEEPGRAM_API_KEY'
    this.socket = new WebSocket(DG_URL, ['token', DG_KEY])
    this.socket.onopen = this.startStreaming
    // Run the handleResponse method when data is received
    this.socket.onmessage = this.handleResponse
  },
  startStreaming() {
    this.mediaRecorder.addEventListener('dataavailable', event => {
      if(event.data.size > 0 && this.socket.readyState == 1) {
        this.socket.send(event.data)
      }
      mediaRecorder.start(250)
    })
  },
  // Create handleResponse method
  handleResponse(message) {
    const received = JSON.parse(message.data)
    const transcript = received.channel.alternatives[0].transcript
    if(transcript) {
      console.log(transcript)
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Refresh your browser, and you should see transcripts showing in your console.

Browser console showing one line in German

Show Transcripts On Page

First, create a new transcripts property in data with an empty array:

data: {
  mediaRecorder: null,
  socket: null,
  // Add this
  transcripts: []
},
Enter fullscreen mode Exit fullscreen mode

Then, instead of logging transcripts, add them to this array:

if(transcript) {
  this.transcripts.push(transcript)
}
Enter fullscreen mode Exit fullscreen mode

Finally, update your HTML to display items from the array:

<div id="app">
  <button @click="begin">Begin transcription</button>
  <!-- Add looping element -->
  <p v-for="transcript in transcripts">{{ transcript }}</p>
</div>
Enter fullscreen mode Exit fullscreen mode

Your page should look like this once you've spoken a couple of phrases:

Page showing two lines - each with one line of transcripted German text

Wrapping Up

The final code looks like this:

<html>
<head></head>
<body>
  <div id="app">
    <button @click="begin">Begin transcription</button>
    <p v-for="transcript in transcripts">{{ transcript }}</p>
  </div>

  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.0"></script>
  <script>
    const app = new Vue({
      el: '#app',
      async created() {
        const stream = await navigator.mediaDevices.getUserMedia({ audio: true })
          .catch(error => alert(error))

        if(!MediaRecorder.isTypeSupported('audio/webm')) return alert('Unsupported browser')
        this.mediaRecorder = new MediaRecorder(stream, { mimeType: 'audio/webm' })
      },
      data: {
        mediaRecorder: null,
        socket: null,
        transcripts: []
      },
      methods: {
        begin() {
          const DG_URL = 'wss://api.deepgram.com/v1/listen?language=de'
          const DG_KEY = 'YOUR_DEEPGRAM_API_KEY'
          this.socket = new WebSocket(DG_URL, ['token', DG_KEY])
          this.socket.onopen = this.startStreaming
          this.socket.onmessage = this.handleResponse
        },
        startStreaming() {
          this.mediaRecorder.addEventListener('dataavailable', event => {
            if(event.data.size > 0 && this.socket.readyState == 1) {
              this.socket.send(event.data)
            }
            mediaRecorder.start(250)
          })
        },
        handleResponse(message) {
          const received = JSON.parse(message.data)
          const transcript = received.channel.alternatives[0].transcript
          if(transcript) {
            this.transcripts.push(transcript)
          }
        }
      }
    })
  </script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

This is the most simple implementation with Vue and is written for clarity over conciseness. If you want to learn more about Vue 3, including its setup() function and composables, then Sandra wrote an excellent tutorial series on Vue 3.

If you have questions, please feel free to message us on Twitter, @DeepgramDevs.

💖 💪 🙅 🚩
_phzn
Kevin Lewis

Posted on July 18, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related