AmiVoice Techblog

AmiVoiceの音声認識に関する技術情報・活用方法・組み込み方などを発信するアドバンスト・メディアのテックブログです

【Swift】AmiVoice APIとAlamofireでつくる感情解析アプリ


f:id:amivoice_techblog:20210203154550p:plain 林政樹

こんにちは。林です。
株式会社アドバンスト・メディアにて、iOS/WatchOSアプリの開発を担当しています。

はじめに

先日、弊社のAmiVoice APIにおける非同期HTTP音声認識APIのオプション機能として感情解析の機能が追加されました。音声から感情を可視化することが可能で、コールセンターで従業員のストレスチェックやオンライン面接でのパーソナリティ診断などとユースケースは多岐にわたります。詳しくは感情解析の紹介記事をご覧ください。

では実際に音声データから抽出される感情はどのように可視化されるのでしょうか。そこで今回は、感情の振る舞いを確認するために、再生中の音声と時間的に同期した感情解析結果と音声認識結果を確認できるようなアプリを開発してみました(下図)。

 

                                                  図 本記事のアプリ

また過去の記事では、AmiVoice APIの非同期HTTP音声認識APIを利用して、Apple Watch音声認識を試せるWatchOSアプリを開発しました。

過去の記事では、標準フレームワークのURLSessionでHTTP通信を実装しましたが、今回は個人的にはURLSessionよりも容易に実装できるAlamofireというライブラリで実装しました。

 

・感情解析をiOSアプリで試してみたい

・Swiftで簡単にAmiVoice APIを利用してみたい

方がいらっしゃいましたら、ぜひご一読お願いします。  

実装

○開発環境

GitHub

○非同期HTTP音声認識API

iOSアプリで感情解析を実施するためにはまず、AmiVoice APIの非同期HTTP音声認識APIをSwiftで実装する必要があります。Swiftでの非同期HTTP音声認識APIの実装に関しては、過去の記事をご参照ください。

Apple WatchでAmiVoiceの非同期APIを試してみた - AmiVoice Techblog

①POSTで音声認識のリクエス

AmiVoice APIの非同期HTTP音声認識APIで感情解析を利用する場合は、下記のリクエストイメージの通り、dパラメータの箇所にsentimentAnalysis=Trueを追記する必要があります。

POST https://acp-api-async.amivoice.com/v1/recognitions
Content-Type: multipart/form-data;boundary=some-boundary-string

--some-boundary-string
Content-Disposition: form-data; name="u"

(<AppKey>)
--some-boundary-string
Content-Disposition: form-data; name="d"

grammarFileNames=-a-general sentimentAnalysis=True profileWords=hogehoge%20%E3%81%BB%E3%81%92%E3%81%BB%E3%81%92%E3%81%A6%E3%81%99%E3%81%A8
--some-boundary-string
Content-Disposition: form-data; name="a"
Content-Type: application/octet-stream

(音声データ)
--some-boundary-string--

上記のリクエストイメージを参考にすると、AmiVoice API音声認識のリクエストはAlamofireを利用して下記の通り実装することができます。

let appKey = "ABCD..." 
let url = "https://acp-api-async.amivoice.com/v1/recognitions"

let headers: HTTPHeaders = [
"Content-type": "multipart/form-data"
]

AF.upload(multipartFormData: { multipartFormData in
multipartFormData.append(appKey.data(using: .utf8)!,
withName: "u",
fileName: nil,
mimeType: nil)
multipartFormData.append("grammarFileNames=-a-general sentimentAnalysis=True".data(using: .utf8)!,
withName: "d",
fileName: nil,
mimeType: nil)
multipartFormData.append(audioData,
withName: "a",
fileName: "audio.wav",
mimeType: "application/octet-stream")
}, to: url, method: .post, headers: headers)
.validate(statusCode: 200..<400)
.responseData(completionHandler: { response in
switch response.result {
case .success(let data):
// 成功時の処理
case .failure(let error):
// 失敗時の処理
}
})

リクエスト後は、.responseDataのコールバック内におけるresponse.resultを利用してください。

②GETでジョブの状態の取得

ジョブの状態の取得は下記の通り実装します。

let path = url + "/" + "セッションID"
let headers: HTTPHeaders = [
"Authorization":"Bearer \(appKey)"
]

AF.request(path, method: .get, headers: headers)
.validate(statusCode: 200..<400)
.responseData { response in
switch response.result {
case .success(let data):
// 成功時の処理
case .failure(let error):
// 失敗時の処理
}
}

時間経過とともにAmiVoice API側のジョブの状態も遷移していきますので、任意のタイミングで上記のリクエストを呼ぶ必要があります。

感情解析の結果を利用する場合は、ジョブの状態が"completed"のときに取得できるjsonsentiment_analysis内の値を利用してください。

補足: アプリの操作について

今回のアプリは、「録音した音声を再生しながら、感情解析結果と音声認識結果を時間推移で確認できる」というものです。

実際にご利用になる場合には、以下の順序で操作をお試しください。

  ①APPKEYの設定

  ②音声の録音

  ③音声認識結果・感情解析結果の表示

※またAPPKEYを設定する際に、「文字認識」を利用してAPPKEYを取得することもできます。APPKEYがコピペできない場合などでお試しください。

     

アプリの操作については以上となります。

おわりに

今回は、AmiVoice APIの非同期HTTP音声認識APIを利用して、録音した音声から数値化された感情を可視化するようなアプリの開発をしてみました。音声認識結果に併せて感情解析の結果も用いることで、ユースケースがさらに広がると思います。

ご興味ある方はぜひ一度お試しください。

参考

AmiVoice API関連

非同期 HTTP インタフェース | AmiVoice Cloud Platform

感情解析 | AmiVoice Cloud Platform

Alamofire

GitHub - Alamofire/Alamofire: Elegant HTTP Networking in Swift

Alamofireでmultipart/form-dataリクエスト - Qiita

Alamofire vs URLSession: a comparison for networking in Swift - SwiftLee

Charts (感情解析結果を表示するのに使用)

GitHub - nubank/ios-charts: Beautiful charts for iOS/tvOS/OSX! The Apple side of the crossplatform MPAndroidChart.

[Swift]グラフを作成するライブラリChartsを使って折れ線グラフを描画してみた | DevelopersIO

この記事を書いた人


  • 林政樹

    Swift/Objective-Cで、iOS/WatchOSアプリの開発をしています。