热词检测是语音激活系统(如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
结构中定义,并包括OnSessionBegins
、OnSessionTerminated
和OnPartialTranscript
等事件。
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进行转录的组合,为创建语音激活的应用程序提供了强大的解决方案。欲了解更多详情,请访问原始教程。
Image source: Shutterstock