☎️

GolangとAmazon Connectで実現する自動音声架電

2024/12/05に公開

このエントリーは一休.com Advent Calendar 2024の5日目の記事になります。


電話番号に対してsmsを送信し、メッセージに含まれている認証コードをシステムに入力してもらうことで、その人物の本人確認をする、というのはかなり一般的になりました。
ただ、smsが届かない場合のフォールバックの確認方法も提供したい場合があります。この場合、メールアドレスで代替の認証を行う、というやり方もありそうです。が、自動音声架電を使えば、電話番号を認証することができます。
この自動架電ですが、GolangのAWS SDKとAWS Connectを使うと比較的簡単に実現できます。

やりたいことは、以下。

  • 対象の電話番号に対して、システムから架電する。
  • その電話番号の電話の保有者が受電すると自動音声で、認証コードを伝える。
  • 電話の保有者は、聞いた認証コードを画面入力する。

認証コード入力ダイアログ表示を割愛すると、やらなければならないのは、以下ふたつ。

  • Amazon ConnectのFlowを用意する。
  • Amazon Connect APIに電話番号を渡して架電を要求する。

それぞれ説明します。
※ 事前にAmazon Connectのインスタンスを準備し架電用の電話番号を取得する必要がありますが、この記事では割愛します。以下の公式ドキュメントに詳しいです。

Amazon ConnectのFlowを用意する。

定義は、以下の通りです。

  • 今回は、英語で自動音声を流します。なので、Set Voice"で、英語の話者を選択しました。
  • "Play prompt"は、"Text-to-speech or chat text"を選択し、"$.Attributes.message" という文字列をtextに設定しています。また、後述するようにSSMLとして解釈してもらいたいためそのように設定します。

  • また、受電者が切らなければ、自動音声を3回流したいので3回ループするように"Loop"の設定を行います。

ここまで作成したら、フローをPublishをして、フローのIDをメモしておきます。

Amazon Connect APIに電話番号を渡して架電を要求する

Golang のAWS SDKを使います。
コマンドラインアプリとして、コードを示すと、以下の通り。


package main

import (
	"bytes"
	"html/template"
	"log"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/connect"
)

func main() {

	ssmlTemplate := `<speak>
		This is ikyu.com. your verification code is 
		{{range $index, $element := .}}
			{{$element}}<break time="1s"/>
		{{end}}.
		Please enter this code to confirm your identity.<break time="500ms"/>
	</speak>`

	verificationCode := []string{"2", "1", "3", "5", "4", "6"} // 例として6桁のコードを使用

	// テンプレートをパース
	tmpl, err := template.New("ssml").Parse(ssmlTemplate)
	if err != nil {
		log.Fatal(err)
	}

	// テンプレートにデータを適用
	var ssmlOutput bytes.Buffer
	err = tmpl.Execute(&ssmlOutput, verificationCode)
	if err != nil {
		log.Fatal(err)
	}

	se := session.Must(session.NewSession())

	co := connect.New(se, &aws.Config{Credentials: credentials.NewStaticCredentials("----", "--------------", ""), Region: aws.String("ap-northeast-1")})

	_, err = co.StartOutboundVoiceContact(&connect.StartOutboundVoiceContactInput{
		Attributes: map[string]*string{
			"message": aws.String(ssmlOutput.String()),
		},
		InstanceId:             aws.String("<Amazon ConnectのインスタンスID>"),
		SourcePhoneNumber:      aws.String("Connectで取得した架電元の電話番号"),
		DestinationPhoneNumber: aws.String("宛先の電話番号"),
		ContactFlowId:          aws.String("作成したFlowのID"),
	})

	if err != nil {
		panic(err)
	}
}

ポイントは以下の通り。

  • 自動音声で流れる発話をSSML(音声合成マークアップ言語)で定義しています。SSMLのテンプレートにランダムな認証コード(サンプルコード上は固定にしていますが)を変数として差し込む、という実装です。認証コードを1文字ずつはっきりと読ませるために<break time="1s"/> というマークアップを差し込む、という工夫をしています。

  • "StartOutboundVoiceContact"関数のパラメータのStartOutboundVoiceContactInputにAttributesが設定できます。このAttributesに"message"というキーで、パースしたssmlを設定しています。

    • "message"というキーにすることで、前述で用意したフローの"Play Prompt"に設定した"$.Attributes.message"に差し込まれ、実際の発話内容になる、という算段です。
  • StartOutboundVoiceContactInputのそのほかの属性は、サンプルコードに記載した通りです。

    • 電話番号は、国番号を付与して記述する必要があります。

これで、実際にこのコマンドラインを実行してみると、電話がかかってくきます。
音声については、SSMLの記述だけでは、どういうふううに聞こえるのかわからないので、実際に聞きながら微調整するとよさそうです。


一休では、ともに良いサービスをつくっていく仲間を募集中です。クラウドインフラの運用やSREに興味がある方はぜひ募集ください。

https://hrmos.co/pages/ikyu/jobs/1693126708022206468

カジュアル面談もやっています。

https://www.ikyu.co.jp/recruit/engineer/

Discussion