Microsoft Azure の音声サービスを使用して音声ファイルからテキストを抽出する

Siden oppdatert :
ページ作成日 :

動作確認環境

Microsoft Azure 音声サービス
  • 2022年7月版
Visual Studio
  • Visual Studio 2022
.NET
  • 6.0

前提条件

この Tips で動作を確認するためには事前に以下を行う必要があります。

サンプル素材について

音声ファイルを以下のサイトからお借りしています。サンプルコードには含めておりません。

参考サイト

はじめに

一例として打ち合わせの内容などを記録するために会話内容を録音し、後で議事録を作成するために録音した音声を聞きながらテキストに起こすという作業をやることがあると思います。 しかし会話内容から文章に書き出すのは非常に手間であることは容易に想像できます。

ここでは Microsoft Azure の音声サービスを利用して音声データから自動的にテキストに書き出して出力する方法について説明します。 先ほどの例では打ち合わせの録音データとしていますが、今回の Tips では音声ファイルから抽出するので会話内容が入っているデータであれば何にでも適用できます。

また、今回はテキストへの書き起こしについて説明していますが、 Microsoft Azure の音声サービスを使用すれば他にも録音しながら変換したり翻訳したりすることも可能です。

料金について

今回は Free プランを使用するので動作を試したとしても料金が発生することはありません。 ただ Free プランは時間や文字数の制限があるので、実際に運用してみてもっと変換する量が必要であれば有料プランに変更してください。

料金については以下の公式ページを参照してください。クラウドサービスなので時期によって料金が変動する場合があります。

Microsoft Azure ポータルにアクセスする

Web ブラウザで以下の URL にアクセスします。

すでにサインインしている場合はこれで終わりです。 まだサインインしていない場合は以下の画面が表示されるのでサインインしてください。

ログインすると以下のような画面が表示されます。設定しているデザインによっては表示は異なる場合があります。

Microsoft Azure で音声サービスを作成する

ポータルの上の検索入力欄に「音声」と入力すると「音声サービス」が出てくると思うので選択します。

「Cognitive Services | 音声サービス」の画面が表示されたら「作成」を選択します。

「Speech Services の作成」画面が開くので必要な項目を入力していきます。

Basics

項目 入力内容 入力例
サブスクリプション 支払い対象となるサブスクリプションを選択します。無料であっても必ず何らかのサブスクリプションに紐づける必要があります。
リソース グループ 作成する音声サービスをどのリソース グループの中に含めるか指定します。まだ一つも作成していない場合は下にある「新規作成」から作成してください。リソース グループはいろんなサービスを作成した際のグループ分けみたいなものと思って構いません。
リージョン 利用場面の多い場所の近くを選択します。ただしリージョンによって料金が変わる場合があるので注意してください。 Japan East
名前 この音声サービスの任意の名前です。音声サービスを複数作ることがある場合は分かりやすい名前にしてください。この名前はグローバルでユニークなので他で使用されている名前は使用できません。 SpeechToText-Test
価格レベル 無料で使用するなら「Free F0」を選択します。有料で使用するなら他のプランを選択してください。もちろん無料の場合は制限があります。 Free F0

入力したら下にある「次: ネットワーク >」 を選択します。

ネットワーク

項目 入力内容 入力例
種類 どの範囲からこの音声サービスにアクセス可能かを指定します。細かい設定をせずにどこからでもアクセスできるようにしたい場合は「インターネットを含む...」を選択します。「どこからでもアクセスできる」ということは「誰でもアクセスできる」という意味にもなりますが、実際にはこの後取得する「キー」を持っている人しかアクセスできないのでセキュリティ面についてはそこまで問題にはなりません。 インターネットを含む...

入力したら下にある「次: Identity >」 を選択します。

Identity

項目 入力内容 入力例
システム割り当てマネージドID 今回音声サービスを単独で使用するのでオフでいいです。 オフ
ユーザー割り当てマネージドID 今回特にユーザーを作成したりしないので追加しなくて良いです。 なし

入力したら下にある「次: タグ >」 を選択します。

タグ

今回タグは使用しないので未設定にします。

入力したら下にある「次: 確認と作成 >」 を選択します。

確認と作成

入力内容に問題がなければ「検証に成功しました」と表示されます。問題がある場合はエラーメッセージが表示されるので戻って再度設定してください。

入力内容に問題がなければ「作成」ボタンをクリックします。するとデプロイが開始されます。

しばらくするとデプロイが完了し以下のような画面が表示されます。デプロイ名が長いですがデプロイでの一時的なものなので気にする必要はありません。

「リソースに移動」ボタンをクリックすると音声サービスが作成されていることを確認できます。

キーの生成と取得

クライアントからこの音声サービスにアクセスするには認証キーが必要になります。 このキーを持っているプログラムでしかアクセス出来ないようになっているので逆にこのキーは第三者に盗まれないようにする必要があります。

ここでいう「クライアント」とはデスクトップアプリやスマフォアプリ、Web アプリなど Microsoft Azure を利用する全てのプログラムが該当します。

キーを取得するには作成した音声サービスにアクセスします。ダッシュボードやリソース グループなどからアクセス可能です。

音声サービスのページが開いたら左のメニューから「キーとエンドポイント」を選択します。

すると「キーとエンドポイント」のページが開き「キー1」「キー2」「場所/地域」「エンドポイント」の項目が表示されます。

いずれの項目も必要ですが「キー2」については予備枠なのでほとんどの場合は使用しないです。

それぞれの値をメモしておいてください。説明文にもありますがキーについては開発関係者意外とは共有しないでください。

仮にキーが漏洩した場合は上にある「キー1の再生成」をクリックすると新しいキーが発行されます。 もちろんこの場合は以前のキーは使用できなくなるので注意してください。

プログラムから音声サービスを使用して音声からテキストを抽出する

ここからは使うプログラムによって音声サービスの使い方が変わります。 今回は .NET のデスクトップアプリケーションからアクセスしますが、他のフレームワークを使用している場合はインターネットなどで使い方を調べてみてください。 公式サイトにもいくつかの言語での使用方法が書かれています。

今回は Visual Studio 2022 で WPF 版デスクトップアプリを作成しています。 Visual Studio Code の場合デザイナーがないので少し面倒ですが、プログラム部分だけ抜き出せばコンソールアプリや Web アプリで使うことも可能です。

プロジェクトを作成

Visual Studio 2022 を起動します。

「新しいプロジェクトの作成」を選択します。

「WPF アプリケーション」を選択します。

プロジェクト名や作成場所は任意です。入力したら「次へ」を選択します。

バージョンは「.NET 6.0」とします。設定したら「作成」ボタンをクリックします。

NuGet の設定

Microsoft Azure の API へのアクセスは1から作ることもできますが、すでに公式のライブラリがあるのでそれを使った方が簡単です。

ソリューションの「依存関係」を右クリックして「NuGet パッケージの管理」を選択します。

「参照」タブを選択し、検索入力欄に「Microsoft.CognitiveServices.Speech」と入力すると一覧が表示されるので「Microsoft.CognitiveServices.Speech」を選択してインストールボタンをクリックします。

OK ボタンをクリックします。

「同意する」を選択します。

完了するとパッケージに追加されます。

UI の作成

今回は音声が含まれる WAV ファイルを指定して Speech API で会話内容をテキストに抽出して表示するものを作ります。 とりあえず環境に依存するものは入力項目にしておいてコピー&ペーストでコードを使えるようにしておきます。

画面は以下のようにします。最低限のものしか入れていないので、例えばファイルの参照ボタンを追加したい場合は各自で実装してください。

MainWindow.xaml は以下のようになっています。

<Window x:Class="MicrosoftAzureSpeechToText.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:MicrosoftAzureSpeechToText"
        mc:Ignorable="d"
        Title="Microsoft Azure の音声サービスを使用したテキスト抽出" Height="450" Width="800">
  <Grid>
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="20*"/>
      <ColumnDefinition Width="80*"/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
      <RowDefinition Height="auto"/>
      <RowDefinition Height="auto"/>
      <RowDefinition Height="auto"/>
      <RowDefinition Height="auto"/>
      <RowDefinition Height="auto"/>
      <RowDefinition Height="auto"/>
      <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <Label Content="キー" Margin="4"/>
    <TextBox x:Name="KeyTextBox" Grid.Column="1" HorizontalAlignment="Stretch" Margin="4" Text="" />
    <Label Content="場所/地域" Margin="4" Grid.Row="1"/>
    <TextBox x:Name="RegionTextBox" Grid.Column="1" HorizontalAlignment="Stretch" Margin="4" Text="japaneast" Grid.Row="1"/>
    <Label Content="言語" Margin="4" Grid.Row="2"/>
    <TextBox x:Name="LanguageTextBox" Grid.Column="1" HorizontalAlignment="Stretch" Margin="4" Text="ja-JP" Grid.Row="2"/>
    <Label Content="WAV ファイルパス" Margin="4" Grid.Row="3"/>
    <TextBox x:Name="WavFilePathTextBox" Grid.Column="1" HorizontalAlignment="Stretch" Margin="4" Text="" Grid.Row="3"/>
    <Button x:Name="ExecuteButton" Content="実行" Margin="4" Grid.Row="4" Grid.ColumnSpan="2" FontSize="24" Click="ExecuteButton_Click"/>
    <Label Content="結果" Margin="4,2,4,2" Grid.Row="5"/>
    <TextBox x:Name="ResultTextBox" Margin="8" TextWrapping="Wrap" Text="" Grid.Row="6" Grid.ColumnSpan="2" VerticalScrollBarVisibility="Visible" />
  </Grid>
</Window>

処理の作成

プログラムは ExecuteButton_Click メソッドにすべてまとめています。他のフレームワークで使用したい場合はこのコードをベースに書き換えてください。

MainWindow.xaml.cs

using Microsoft.CognitiveServices.Speech;
using Microsoft.CognitiveServices.Speech.Audio;
using System;
using System.Media;
using System.Threading.Tasks;
using System.Windows;

namespace MicrosoftAzureSpeechToText
{
  /// <summary>
  /// MainWindow.xamlのインタラクションロジック
  /// </summary>
  public partial class MainWindow : Window
  {
    public MainWindow()
    {
      InitializeComponent();
    }

    private void AppendLineLog(string log)
    {
      // 非同期処理から書き込むので Dispatcher.Invoke を使用
      Dispatcher.Invoke(()=>ResultTextBox.AppendText(log + Environment.NewLine));
    }

    private async void ExecuteButton_Click(object sender, RoutedEventArgs e)
    {
      // 入力内容をテキストボックスから取得
      var key = KeyTextBox.Text;
      var region = RegionTextBox.Text;
      var lang = LanguageTextBox.Text;
      var wavFilePath = WavFilePathTextBox.Text;

      try
      {
        // 音声ファイルが指定されているか確認するため再生する
        var wavPlayer = new SoundPlayer(wavFilePath);
        wavPlayer.Play();

        var stopRecognition = new TaskCompletionSource<int>();

        // 音声サービスを構成する
        var speechConfig = SpeechConfig.FromSubscription(key, region);
        AppendLineLog($"{speechConfig.Region} で音声サービスを使用する準備ができました。");

        // 音声認識言語の指定
        // 使用できる値一覧:https://docs.microsoft.com/ja-jp/azure/cognitive-services/speech-service/language-support?tabs=speechtotext#speech-to-text
        speechConfig.SpeechRecognitionLanguage = lang;

        // 入力を WAV ファイルとして設定
        using var audioConfig = AudioConfig.FromWavFileInput(wavFilePath);
        using var speechRecognizer = new SpeechRecognizer(speechConfig, audioConfig);

        // 解析結果が受信されたことを通知します。
        // このイベントは抽出が完了したものから随時発生します。
        speechRecognizer.Recognized += (s, e) =>
        {
          if (e.Result.Reason == ResultReason.RecognizedSpeech)
          {
            // 音声結果に認識されたテキストが含まれていることを示します。
            var time = TimeSpan.FromSeconds(e.Result.OffsetInTicks / 10000000).ToString(@"hh\:mm\:ss");
            var text = $"{time} {e.Result.Text}";
            AppendLineLog(text);
          }
          else if (e.Result.Reason == ResultReason.NoMatch)
          {
            // 音声を認識できなかったことを示します。
            AppendLineLog("音声を認識できませんでした。");
          }
        };

        // 音声認識が中断されたことを通知します。
        speechRecognizer.Canceled += (s, e) =>
        {
          AppendLineLog($"処理が終了しました。(Reason={e.Reason})");

          if (e.Reason == CancellationReason.Error)
          {
            AppendLineLog($"ErrorCode={e.ErrorCode}\r\n");
            AppendLineLog($"ErrorDetails={e.ErrorDetails}\r\n");
          }

          stopRecognition.TrySetResult(0);
        };

        // 継続的な処理を開始します。 StopContinuousRecognitionAsync を使用して処理を停止します。
        await speechRecognizer.StartContinuousRecognitionAsync().ConfigureAwait(false);

        // 完了するのを待ちます。Task.WaitAny を使用して、タスクをルート化してください。
        Task.WaitAny(new[] { stopRecognition.Task });

        // 処理を停止します。
        await speechRecognizer.StopContinuousRecognitionAsync().ConfigureAwait(false);
      }
      catch (Exception ex)
      {
        // 何らかの例外が発生した場合はエラー内容を出力
        AppendLineLog(ex.Message);
      }

      MessageBox.Show("処理が終了しました。");
    }
  }
}

説明はほとんどコードの中に書いてあるので詳細は説明しませんが、重要な箇所を上げると以下のような感じになります。

  • SpeechConfig で音声サービスの設定
  • AudioConfig で音声データの設定
  • SpeechRecognizer で処理クラスを生成
  • 逐一音声データの解析が行われ、随時出来あがったテキストは SpeechRecognizer.Recognized イベントで渡される。
  • 何らかの原因で処理が終わると SpeechRecognizer.Canceled イベントが呼ばれる
  • 処理の開始は SpeechRecognizer.StartContinuousRecognitionAsync メソッド、処理の完了は SpeechRecognizer.StopContinuousRecognitionAsync メソッドを呼び出す。

動作確認

プログラムを作成したら実行し、必要な項目を入力して実行ボタンを押してください。 正しい音声ファイルを指定しているなら音声が再生され、裏で Microsoft Azure の音声サービスを使用してテキストが逐一抽出されるはずです。

抽出の制度は Microsoft Azure の音声サービスに依存しますので完ぺきではありませんが、 雑音が少なくはっきりとしゃべっている声であればかなりの高精度で抽出してくれると思います。 クラウドサービスなので、今精度があまり高くなくてもいつの間にか良くなっている場合がありますので、そのあたりは何もしなくてもいいのはお手軽ですね。