Taste of Tech Topics

Acroquest Technology株式会社のエンジニアが書く技術ブログ

Azure Content Understandingを使って動画から構造化データを作る

こんにちは。データサイエンスチームYAMALEXの@Ssk1029Takashiです。
最近はLLMのFine Tuningに夢中の日々です。

昨年のMicrosoft Ignite 2024にて、Azure Content Understandingというサービスが発表されました。
このサービスはOfficeドキュメントや画像、音声、動画などのファイルをもとに、RAGシステムなどで使いやすいように生成AIなどを活用してユーザーが定義した構造にデータを取り込むサービスです。
今までだと、音声はSpeech Service、画像はAI Visionなどのサービスをそれぞれ使ってデータ処理する必要があったのを、一つのサービスで構造を定義するだけで処理できるようになりました。
今回はそんなAzure Content Understandingを使って動画から検索エンジンなどに取り込みやすいJSON形式の構造化データを作成します。

Azure Content Understandingとは

記事冒頭でも説明した通り、Azure Content Understandingでは一つのサービスで複数形式のファイルから構造化データを作成できます。
構造化データを作成するにあたって、以下の図のようにファイル内の文字抽出やトランスクリプトの作成などのコンテンツ抽出が可能です。
それに加えて、生成AIを通してユーザーが定義した項目を抽出したコンテンツから生成することでファイルを構造化したデータに変換までできます。

https://learn.microsoft.com/ja-jp/azure/ai-services/content-understanding/overview

この機能を使うことで、例えばドキュメントを検索データにするときだと、普通に実装するとOCRなどで文字列抽出→LLMを使ってデータ抽出→JSONに変換のようなパイプラインが必要になるところを、定義を作成するだけで実現可能になります。
そのうえで複数のファイルを一つのサービスで対応できるようになるので便利ですね。
現在はプレビューのため、一時的に無料で使用可能になっており、価格は後日詳細が発表予定とのことです。

Azure Content Understandingの利用準備

Azure Content Understandingを使用するには、West US, Sweden Central, Australia EastのいずれかのリージョンにAzure AI Servicesリソースを作成する必要があります。
上記以外のリージョンでは利用できないため注意してください。

Azure Content Understandingを利用して動画ファイルを解釈する

それでは実際に動画ファイルから、Azure Content Understandingを使ってサマリ、カテゴリを抽出して見ましょう。
今回は以下のリンクで提供されているサンプルを利用することでPythonから実行してみます。
github.com
実施するステップとしては以下になります。

  1. データ分析定義を作成する
  2. アナライザーを作成する
  3. アナライザーを使ってファイルを分析する

データ分析定義を作成する

まず、対象のファイル形式やどのような抽出したいデータの内容を定義します。

以下のようなJSONを作成します。

{
    "description": "ビデオからファイルを抽出するサンプル",
    "scenario": "videoShot", 
    "config": {
        "returnDetails": true,
        "locales": [
            "ja-JP"
        ],
        "enableFace": false
    },
    "fieldSchema": {
        "fields": {
            "summary": {
                "type": "string",
                "method": "generate",
                "description": "内容を要約した一文"
            },
            "category": {
                "type": "string",
                "method": "classify",
                "description": "動画ファイルのカテゴリ",
                "enum": [
                    "IT",
                    "Economy",
                    "Nature"
                ]
            }
        }
    }
}

この定義をのポイントは以下になります

  1. 動画を対象にするためscenarioにはvideoShotを指定
  2. localesでは日本語のため、ja-JPのみを設定
  3. fieldSchemaでは以下の2つの抽出する項目を定義
    1. Summary: 動画の内容を要約した文章
    2. Category: IT, Economy, Natureから選択する動画のカテゴリ

fieldSchemaで設定する内容では、特にdescriptionの内容を見て生成AIがフィールドの内容を抽出するので、重要なチューニング項目になります。
ただし、今回は簡単な動作検証のため簡易的な一文で検証しています。

アナライザーを作成する

定義を作成したら、ファイルを読み込んで分析するためのアナライザーを作成します。
今のところアナライザーの作成・実行はGUIREST APIからのみ可能になっています。
ただし、上述したGithubの以下のソースコードAPIを使いやすくしたクラスが提供されているので、今回はそれを利用します。
github.com

アナライザーの作成は以下のコードで可能です。

import uuid

# アナライザーの名前を作成
ANALYZER_TEMPLATE = "video"
ANALYZER_ID = "video-sample-" + str(uuid.uuid4())

# ContentUnderstanding用のクライアントを作成
client = AzureContentUnderstandingClient(
    endpoint=AZURE_AI_ENDPOINT,
    api_version=AZURE_AI_API_VERSION,
    subscription_key=AZURE_AI_SUBSCRIPTION_KEY
)
# データ分析定義を読み込んでアナライザーを作成する
response = client.begin_create_analyzer(ANALYZER_ID, analyzer_template_path="./content_video.json")
result = client.poll_result(response)

ここまで実行することでアナライザーを作成できたので、あとは分析を実行するだけになります。

アナライザーを実行する

それではアナライザーに動画ファイルを読み込ませて実行してみましょう。
対象のファイルとしては、当社が公開している以下の動画を対象にします。
www.youtube.com
この動画ではサブネットマスクの知識について基本を解説しているため、その内容が結果として抽出できることが期待結果になります。
実行自体は簡単で以下の2行で完了します。

response = client.begin_analyze(ANALYZER_ID, file_location=analyzer_sample_file_path)
result = client.poll_result(response)

分析結果を得られるまでの時間はファイルによって変化しますが、今回の11分の動画を対象にした場合は5分程度かかりました。

結果としては以下のようなJSONが得られます。
全体だと長すぎるため一部抜粋して記載します。

{
  "id": "82eb4975-4232-44a1-a4e6-d018fa45469f",
  "status": "Succeeded",
  "result": {
    "analyzerId": "video-sample-31341919-bf0d-45af-9228-7866b252a70a",
    "apiVersion": "2024-12-01-preview",
    "createdAt": "2025-01-28T05:32:48Z",
    "warnings": [],
    "contents": [
      {
        "markdown": "# Shot 00:00.000 => 00:03.303\n## Transcript\n```\nWEBVTT\n\n```\n## Key Frames\n- 00:00.825 ![](keyFrame.825.jpg)\n- 00:01.650 ![](keyFrame.1650.jpg)\n- 00:02.475 ![](keyFrame.2475.jpg)",
        "fields": {
          "category": {
            "type": "string",
            "valueString": "IT"
          },
          "summary": {
            "type": "string",
            "valueString": "新入若手エンジニア向けのIT基礎知識について説明する動画で、今回はサブネットマスクとCIDRについて解説する。"
          }
        },
        "kind": "audioVisual",
        "startTimeMs": 0,
        "endTimeMs": 3303,
        "width": 1280,
        "height": 720,
        "KeyFrameTimesMs": [
          825,
          1650,
          2475
        ],
        "transcriptPhrases": []
      },
      {
        "markdown": "# Shot 00:03.303 => 01:02.106\n## Transcript\n```\nWEBVTT\n\n00:04.680 --> 00:28.960\n<v Speaker>では次にサブネットマスクについて説明していきます。先ほどローカルネットワークを設定して、その中でIPアドレスを設定したり、利用したりするという話をしました。で、具体的にどうローカルネットワークを定義するかなんですけれども、ここでアイピーアドレスをネットワーク部とホスト部二つに分けて考えるというやり方をとります。\n00:29.480 --> 00:59.000\n<v Speaker>具体的にどうするかというとアイピーアドレスが一つ回った時に、これらをええ、それぞれの数字をビットで表します。つまり、二進数で表記するんですね。そうするとこのような形になりますで、この時にこのある場所を境目にして、この前半部分をネットワーク部、そして後半をホスト部という風に考えるんですね。この前半部分のネットワーク部が、いわばそのネットワーク自身を表す場所。\n00:59.600 --> 01:27.680\n<v Speaker>となります。そしてその後ろのホスト部がこのネットワークに所属するそれぞれの機器の場所を表すという形になります。つまり、その前半部分のネットワーク部が一致していれば、同じネットワークだというふうにみなすわけですね。このネットワークの定義の仕方としては、クラスという考え方が今、ええ、昔から使われています。クラスは3種類あってですね。クラスABC。\n```\n## Key Frames\n- 00:06.072 ![](keyFrame.6072.jpg)\n- 00:08.844 ![](keyFrame.8844.jpg)\n- 00:11.616 ![](keyFrame.11616.jpg)\n- 00:14.388 ![](keyFrame.14388.jpg)\n- 00:17.160 ![](keyFrame.17160.jpg)\n- 00:19.932 ![](keyFrame.19932.jpg)\n- 00:22.704 ![](keyFrame.22704.jpg)\n- 00:25.476 ![](keyFrame.25476.jpg)\n- 00:28.248 ![](keyFrame.28248.jpg)\n- 00:31.020 ![](keyFrame.31020.jpg)\n- 00:33.792 ![](keyFrame.33792.jpg)\n- 00:36.564 ![](keyFrame.36564.jpg)\n- 00:39.336 ![](keyFrame.39336.jpg)\n- 00:42.108 ![](keyFrame.42108.jpg)\n- 00:44.880 ![](keyFrame.44880.jpg)\n- 00:47.652 ![](keyFrame.47652.jpg)\n- 00:50.424 ![](keyFrame.50424.jpg)\n- 00:53.196 ![](keyFrame.53196.jpg)\n- 00:55.968 ![](keyFrame.55968.jpg)\n- 00:58.740 ![](keyFrame.58740.jpg)",
        "fields": {
          "summary": {
            "type": "string",
            "valueString": "サブネットマスクの説明が行われ、IPアドレスをネットワーク部とホスト部に分ける方法が示されています。クラスABCのネットワーク定義についても触れられています。"
          },
          "category": {
            "type": "string",
            "valueString": "IT"
          }
        },
        "kind": "audioVisual",
        "startTimeMs": 3303,
        "endTimeMs": 62106,
        "width": 1280,
        "height": 720,
        "KeyFrameTimesMs": [
          6072,
          8844,
          11616,
          14388,
          17160,
          19932,
          22704,
          25476,
          28248,
          31020,
          33792,
          36564,
          39336,
          42108,
          44880,
          47652,
          50424,
          53196,
          55968,
          58740
        ],
        "transcriptPhrases": [
          {
            "speaker": "speaker",
            "startTimeMs": 4680,
            "endTimeMs": 28960,
            "text": "では次にサブネットマスクについて説明していきます。先ほどローカルネットワークを設定して、その中でIPアドレスを設定したり、利用したりするという話をしました。で、具体的にどうローカルネットワークを定義するかなんですけれども、ここでアイピーアドレスをネットワーク部とホスト部二つに分けて考えるというやり方をとります。",
            "confidence": 1,
            "words": [],
            "locale": "en-US"
          },
          {
            "speaker": "speaker",
            "startTimeMs": 29480,
            "endTimeMs": 59000,
            "text": "具体的にどうするかというとアイピーアドレスが一つ回った時に、これらをええ、それぞれの数字をビットで表します。つまり、二進数で表記するんですね。そうするとこのような形になりますで、この時にこのある場所を境目にして、この前半部分をネットワーク部、そして後半をホスト部という風に考えるんですね。この前半部分のネットワーク部が、いわばそのネットワーク自身を表す場所。",
            "confidence": 1,
            "words": [],
            "locale": "en-US"
          },
          {
            "speaker": "speaker",
            "startTimeMs": 59600,
            "endTimeMs": 87680,
            "text": "となります。そしてその後ろのホスト部がこのネットワークに所属するそれぞれの機器の場所を表すという形になります。つまり、その前半部分のネットワーク部が一致していれば、同じネットワークだというふうにみなすわけですね。このネットワークの定義の仕方としては、クラスという考え方が今、ええ、昔から使われています。クラスは3種類あってですね。クラスABC。",
            "confidence": 1,
            "words": [],
            "locale": "en-US"
          }
        ]
      },

おそらく内部的にはVideo Indexerのようなものを使っていると思われますが、ビデオを自動的にチャプター分割して、各チャプターのトランスクリプト、キーフレームの時間が取得できています。
また、カスタムで定義したsummary, categoryについてもチャプターごとに取得しており、内容としても正しいものが取れています。
簡単に定義してアナライザーを実行するだけで動画をここまで詳細に構造化できるのは便利ですね。
トランスクリプトもついているため、検索データとしても有効そうです。

まとめ

今回はAzure Content Understandingを利用して、動画データを構造化して見ました。
全体を通してかなり手間なく動画データの解析ができ、便利なサービスでした。
まだプレビュー段階ですが、RAGデータへの活用などかなり幅広い活用が出来そうなサービスのため、さらに使い方を模索していきたいところです。
それではまた。

Acroquest Technologyでは、キャリア採用を行っています。

  • Azure OpenAI/Amazon Bedrock等を使った生成AIソリューションの開発
  • ディープラーニング等を使った自然言語/画像/音声/動画解析の研究開発
  • マイクロサービス、DevOps、最新のOSSクラウドサービスを利用する開発プロジェクト
  • 書籍・雑誌等の執筆や、社内外での技術の発信・共有によるエンジニアとしての成長

少しでも上記に興味を持たれた方は、是非以下のページをご覧ください。

www.wantedly.com