使用AssemblyAI的流式语音转文字在Go语言中实现热词检测

realtime news  Jun 26, 2024 16:26  UTC 08:26

1 Min Read

热词检测是语音激活系统(如Siri或Alexa)的关键功能。在AssemblyAI最近的一篇教程中,开发者被指导如何使用AssemblyAI的流式语音转文字API和Go编程语言来实现这一功能。

热词检测简介

热词检测使AI系统能够响应特定的触发词或短语。流行的AI系统如Alexa和Siri使用预定义的热词来激活它们的功能。该教程展示了如何使用Go和AssemblyAI的API创建一个类似的系统,以向钢铁侠致敬,将其命名为“Jarvis”。

设置环境

在进行编码之前,开发者需要设置他们的环境。这包括安装PortAudio的Go绑定以从麦克风捕获原始音频数据和AssemblyAI Go SDK以与API进行交互。以下命令用于设置项目:

mkdir jarvis
cd jarvis
go mod init jarvis
go get github.com/gordonklaus/portaudio
go get github.com/AssemblyAI/assemblyai-go-sdk

接下来,需要一个AssemblyAI账户以获取API密钥。开发者可以在AssemblyAI网站上注册并配置他们的账单信息以访问流式语音转文字API。

实现录音器

核心功能从录制原始音频数据开始。教程指导如何创建一个recorder.go文件,以定义一个recorder结构,该结构使用PortAudio捕获音频数据。这个结构包括启动、停止和读取音频流的方法。

package main

import (
    "bytes"
    "encoding/binary"

    "github.com/gordonklaus/portaudio"
)

type recorder struct {
    stream *portaudio.Stream
    in     []int16
}

func newRecorder(sampleRate int, framesPerBuffer int) (*recorder, error) {
    in := make([]int16, framesPerBuffer)

    stream, err := portaudio.OpenDefaultStream(1, 0, float64(sampleRate), framesPerBuffer, in)
    if err != nil {
        return nil, err
    }

    return &recorder{
        stream: stream,
        in:     in,
    }, nil
}

func (r *recorder) Read() ([]byte, error) {
    if err := r.stream.Read(); err != nil {
        return nil, err
    }

    buf := new(bytes.Buffer)

    if err := binary.Write(buf, binary.LittleEndian, r.in); err != nil {
        return nil, err
    }

    return buf.Bytes(), nil
}

func (r *recorder) Start() error {
    return r.stream.Start()
}

func (r *recorder) Stop() error {
    return r.stream.Stop()
}

func (r *recorder) Close() error {
    return r.stream.Close()
}

创建实时转录器

AssemblyAI的实时转录器需要事件处理器来处理转录过程中的不同阶段。这些处理器在一个transcriber结构中定义,并包括OnSessionBeginsOnSessionTerminatedOnPartialTranscript等事件。

package main

import (
    "fmt"

    "github.com/AssemblyAI/assemblyai-go-sdk"
)

var transcriber = &assemblyai.RealTimeTranscriber{
    OnSessionBegins: func(event assemblyai.SessionBegins) {
        fmt.Println("session begins")
    },

    OnSessionTerminated: func(event assemblyai.SessionTerminated) {
        fmt.Println("session terminated")
    },

    OnPartialTranscript: func(event assemblyai.PartialTranscript) {
        fmt.Printf("%s\r", event.Text)
    },

    OnFinalTranscript: func(event assemblyai.FinalTranscript) {
        fmt.Println(event.Text)
    },

    OnError: func(err error) {
        fmt.Println(err)
    },
}

整合全部组件

最后一步是将所有组件整合到main.go文件中。这包括设置API客户端,初始化录音器并处理转录事件。代码还包括检测热词和适当响应的逻辑。

package main

import (
    "context"
    "fmt"
    "log"
    "os"
    "os/signal"
    "strings"
    "syscall"

    "github.com/AssemblyAI/assemblyai-go-sdk"
    "github.com/gordonklaus/portaudio"
)

var hotword string

var transcriber = &assemblyai.RealTimeTranscriber{
    OnSessionBegins: func(event assemblyai.SessionBegins) {
        fmt.Println("session begins")
    },

    OnSessionTerminated: func(event assemblyai.SessionTerminated) {
        fmt.Println("session terminated")
    },

    OnPartialTranscript: func(event assemblyai.PartialTranscript) {
        fmt.Printf("%s\r", event.Text)
    },

    OnFinalTranscript: func(event assemblyai.FinalTranscript) {
        fmt.Println(event.Text)
        hotwordDetected := strings.Contains(
            strings.ToLower(event.Text),
            strings.ToLower(hotword),
        )
        if hotwordDetected {
            fmt.Println("I am here!")
        }
    },

    OnError: func(err error) {
        fmt.Println(err)
    },
}

func main() {
    sigs := make(chan os.Signal, 1)
    signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)

    logger := log.New(os.Stderr, "", log.Lshortfile)

    portaudio.Initialize()
    defer portaudio.Terminate()

    hotword = os.Args[1]

    device, err := portaudio.DefaultInputDevice()
    if err != nil {
        logger.Fatal(err)
    }

    var (
        apiKey = os.Getenv("ASSEMBLYAI_API_KEY")
        sampleRate = device.DefaultSampleRate
        framesPerBuffer = int(0.2 * sampleRate)
    )

    client := assemblyai.NewRealTimeClientWithOptions(
        assemblyai.WithRealTimeAPIKey(apiKey),
        assemblyai.WithRealTimeSampleRate(int(sampleRate)),
        assemblyai.WithRealTimeTranscriber(transcriber),
    )

    ctx := context.Background()

    if err := client.Connect(ctx); err != nil {
        logger.Fatal(err)
    }

    rec, err := newRecorder(int(sampleRate), framesPerBuffer)
    if err != nil {
        logger.Fatal(err)
    }

    if err := rec.Start(); err != nil {
        logger.Fatal(err)
    }

    for {
        select {
        case <-sigs:
            fmt.Println("stopping recording...")
            if err := rec.Stop(); err != nil {
                log.Fatal(err)
            }
            if err := client.Disconnect(ctx, true); err != nil {
                log.Fatal(err)
            }
            os.Exit(0)
        default:
            b, err := rec.Read()
            if err != nil {
                logger.Fatal(err)
            }
            if err := client.Send(ctx, b); err != nil {
                logger.Fatal(err)
            }
        }
    }
}

运行应用程序

要运行应用程序,开发者需要将他们的AssemblyAI API密钥设置为环境变量,并使用期望的热词执行Go程序:

export ASSEMBLYAI_API_KEY='***'
go run . Jarvis

此命令将“Jarvis”设置为热词,当音频流中检测到热词时,程序将响应“我在这里!”

结论

AssemblyAI的这篇教程为开发者提供了一个全面的指南,让他们可以使用流式语音转文字API和Go语言实现热词检测。PortAudio捕获音频和AssemblyAI进行转录的组合,为创建语音激活的应用程序提供了强大的解决方案。欲了解更多详情,请访问原始教程



Read More