LoginSignup
4
2
音声認識APIを使ってみよう!

Elixir Livebook から AmiVoice の音声認識 API を呼び出す

Last updated at Posted at 2024-04-15

はじめに

Elixir から AmiVoice API による音声認識を実行します

今回も Livebook を使っていきます

AmiVoice API の利用方法については公式のマニュアルを参照

AmiVoice とは

AmiVoice は株式会社アドバンストメディアが開発した音声認識ソフトウェアです

特長はなんと言っても 「日本語に対する精度の高さ」 でしょう

世の中に音声認識サービスは数多ありますが、グローバルに展開しているものはどうしても日本語に非対応だったり、対応していても精度がいまいちだったりします

AmiVoice は私たち日本人が使うのに最適化されています

こちらから音声認識を実際に動かして試せるので使ってみましょう

例えば、以下のような文章もバッチリ認識できました

  • 拝啓春暖の候、ますますご清栄のこととお喜び申し上げます
  • 国民は、全ての基本的人権の享有を妨げられない
  • OECグループは、技術と信頼真心をモットーに、高い技術力を持ったICTサービス企業として、 お客様のニーズにお応えし、社会に貢献してまいります
  • 大分県大分市東春日町17番57号ソフトパーク内

更に医療系や金融・保険業界に特化したエンジンも選択できます

また、 API 利用量が安く、 毎月 60 分無料 であることも魅力です

発話時間にしか課金されないため、無音が続くような場合にも無駄がありません

加えて、昨今生成 AI 周りでよく気にされることですが、いわゆる オプアウト = 学習用にデータを使わせない 指定もできます(その分費用が高くなります)

音声データがサーバーに保存されるのはちょっと、、、という場合にも使えるのは嬉しいですね

アカウント登録

AmiVoice の API を使うためには、まずアカウント登録が必要です

最初の 60 分が無料なので 0 円で試すことが可能ですが、クレジットカードの登録は必須です

公式サイトのトップページから、右下の方にある「API を無料で利用開始」のボタンをクリックしましょう

スクリーンショット 2024-04-13 17.11.33.png

メールアドレスを入力する画面が表示されるので、あとは指示に従っていきます

スクリーンショット 2024-04-13 17.11.51.png

アカウントが登録できたら以下の URL からマイページにログインできます

ただし、クレジットカードを登録していないと以下のような表示になるため、クレジットカードを登録しましょう

スクリーンショット 2024-04-13 17.16.12.png

接続情報

マイページの左メニュー「接続情報」をクリックすると、 API 呼び出しに使う「APPKEY」が確認できます

スクリーンショット 2024-04-13 17.21.24.png

環境構築

音声の形式変換のため、 Vice というモジュールを使います

Vice には以下のモジュールが必要です

  • cmake
  • ffmpeg
  • libav
  • libopencv-dev
  • imagemagick
  • SoX

今回は音声を扱うため、少なくとも SoX が必須になります

Ubuntu の場合は以下もコマンドでインストールできます

apt install sox

私は以下のリポジトリーにある Docker コンテナで Livebook を立ち上げています
(今回、 SoX のインストールを追加しました)

セットアップ

Livebook を起動し、新しいノートブックのセットアップセルに以下のコードを入力、実行します

Mix.install([
  {:kino, "~> 0.12"},
  {:multipart, "~> 0.4"},
  {:req, "~> 0.4"},
  {:vice, "~> 0.1"}
])

API の呼び出しに Req を使います

音声データと認証情報、オプション等をマルチパートで送信するため、 Multipart を使用します

接続情報の設定

API の認証に使う APPKEY を入力します

appkey_input = Kino.Input.password("APPKEY")

APPKEY はAmiVoice マイページの接続情報からコピーしてください

スクリーンショット 2024-04-14 10.08.04.png

APPKEY をマルチパートのデータに格納します

Kino.nothing() はセルの出力結果に認証情報を表示しないためのコードです

auth_part =
  appkey_input
  |> Kino.Input.read()
  |> Multipart.Part.text_field("u")

Kino.nothing()

入力データの準備

AmiVoice API のエンドポイント URL を設定します

今回はログが残らない(音声データを AmiVoice のサーバー上に保存しない)エンドポイントを指定しています

api_endpoint = "https://acp-api.amivoice.com/v1/nolog/recognize"

音声入力を用意します

AmiVoice API は wav 形式に対応しているため、形式に :wav を指定します

16k 以上のサンプリングレートは意味がない(API に送っても 16k にダウンサンプリングされる)ため、サンプリングレートを 16_000 に指定します

audio_input = Kino.Input.audio("Audio", format: :wav, sampling_rate: 16_000)

スクリーンショット 2024-04-14 10.16.50.png

「Record」ボタンをクリックするとマイクから録音できます

初回は以下のようなアラートがブラウザに表示されるので、マイクの使用を許可してください

スクリーンショット 2024-04-14 10.17.30.png

録音できると以下のような表示になります

スクリーンショット 2024-04-14 10.23.42.png

以下のコードにより、音声データの保存先パスが取得できます

audio_path =
  audio_input
  |> Kino.Input.read()
  |> Map.get(:file_ref)
  |> Kino.Input.file_path()

出力結果(一例)

"/tmp/livebook/sessions/gfwl4emfac5g3ipnryin7zya57i3h236pahpnzqv5alt6z2l/registered_files/7c77otkkqjt7kjzm"

この音声ファイルはビットレート 32 になっていますが、 AmiVoice API はビットレート 16 に変換しないと「サポートしていない形式」としてエラーになってしまいます

そこで、 Vice を使ってビットレートを変換します

まず、一時ファイルとして .wav の拡張子を付けてコピーします

File.copy!(audio_path, "/tmp/input.wav")

Vice のプロセスを起動します

Vice.start()

Vice に変換を依頼します(非同期です)

{:async, worker} = Vice.convert("/tmp/input.wav", "/tmp/input_16b.wav", output_bits: 16)

worker の状態は以下のコードで確認できるので、結果が :done になるまで待ちます

Vice.status(worker)

変換した入力ファイルをマルチパートのデータに格納します

audio_content = File.read!("/tmp/input_16b.wav")
audio_part = Multipart.Part.file_content_field("audio", audio_content, "a")

認証情報、エンジンの指定、音声データをマルチパートにまとめます
公式マニュアルにある通り、必ず音声データを一番最後に追加します

multipart =
  Multipart.new()
  |> Multipart.add_part(auth_part)
  |> Multipart.add_part(Multipart.Part.text_field("-a-general", "d"))
  |> Multipart.add_part(audio_part)

Kino.nothing()

リクエスト時のヘッダーを設定します

content_length = Multipart.content_length(multipart)
content_type = Multipart.content_type(multipart, "multipart/form-data")

headers = [
  {"Content-Type", content_type},
  {"Content-Length", to_string(content_length)}
]

リクエストを送信します

{:ok, response} = Req.post(api_endpoint, headers: headers, body: Multipart.body_stream(multipart))

出力結果を確認してみます

response.body

出力結果

%{
  "code" => "",
  "message" => "",
  "results" => [
    %{
      "confidence" => 0.998,
      "endtime" => 2516,
      "rulename" => "",
      "starttime" => 900,
      "tags" => [],
      "text" => "こんにちは。",
      "tokens" => [
        %{
          "confidence" => 0.96,
          "endtime" => 2164,
          "spoken" => "こんにちは",
          "starttime" => 1204,
          "written" => "こんにちは"
        },
        %{
          "confidence" => 0.77,
          "endtime" => 2516,
          "spoken" => "_",
          "starttime" => 2164,
          "written" => "。"
        }
      ]
    }
  ],
  "text" => "こんにちは。",
  "utteranceid" => "20240414/10/018eda4081d80a301ee894c7_20240414_103724"
}

上記は「こんにちは」だけの例ですが、以下のような長文でも正しく認識できました
(一部、漢字がおかしい箇所がありますが、裁判に特化しているわけではないので致し方ないでしょう)

本日はこの裁判所において、被告桃太郎氏および彼の同行者犬猿雉に対する公判を改定いたします。
被告らは、不法侵入、盗難および暴力行為の罪に問われています。

まとめ

マルチパートで送信する点、ビットレートを16に変換する点で少し躓きましたが、無事、 Elixir から AmiVoice API を呼び出して音声認識を実行できました

毎月 60 分無料であるため、気軽に試すことができました

また、他の音声認識サービスと比較して、かなり日本語の認識精度が高いことも確認できました

日本向けのサービスであれば、かなり利用できそうですね

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2