🐷

HeyGenで次世代動画制作を実現!Pythonで一気通貫の自動化に挑戦

2024/10/13に公開

autumn.jpg

はじめに

先日、HeyGenを使ったAPI活用法を紹介しましたが、今回はさらに進化させてみました。Curlを使ったAPIコールで、自由自在にアバターを作成するだけでなく、Pythonを使って一気通貫で動画を自動生成できるように挑戦しています。

これにより、手元にある「アバター」と「音声」さえあれば、あとは指定したスクリプトをアバターが代わりに読み上げてくれる!もう、面倒な編集作業に悩まされることはありません。AIアバターが、あなたのコンテンツを24時間365日サポートしてくれる時代が到来です。

前提条件

今回のプロジェクトに進む前に、まず「アバター」と「音声」が既に作成されていることが前提です。もしまだの方は、私の以前の記事を参考にしていただくと、HeyGenのAPIを使ったアバター作成方法が詳しく紹介されています。

https://qiita.com/ogi_kimura/items/4e653af5e94b89188b56

プログラミング

以下に、実際に作成したプログラムを示します。このプログラムでは、2024年10月12日に公開された「大量閉店の『イトーヨーカドー』、2025年の店舗数はどうなる? 残る都道府県を検証」という記事をもとに、アバターが話すシナリオを想定しています。

import subprocess
import time
import json


# --- ogi_kimura@yahoo.co.jp ---
HEYGEN_API_KEY =   '************************************************************'
AVATAR_ID =        '*******************************'
VOICE_ID =         '*******************************'
AVATAR_CONTEXT =   '2024年10月10日、コンビニ事業に集中すべくグループの再編を発表した「セブン&アイ・ホールディングス」。企業名を変更するほか、コンビニ以外の事業を新たに設立した中間持株会社に分離させるとしています。分離する事業の一つが、傘下の「イトーヨーカ堂」が運営するスーパーマーケット「イトーヨーカドー」です。イトーヨーカドーでは、構造改革の一環として首都圏を中心とした都市部に集中するため、店舗の閉店がすでに進行中。2024年7月には、「クレヨンしんちゃん」に登場するスーパーのモデルにもなった春日部店の閉店が発表され、話題となりました。今後も、10月に閉店する千葉県の柏店をはじめ、2025年2月末までに16店舗の閉店が続く予定ですが、一段落を迎える2025年3月にはどのような出店状況になっているのでしょうか。'

OUTPUT_FILE_NAME = 'first_output.mp4'

def create_avatar_video():
    payload = {
        "video_inputs": [
            {
                "character": {
                    "type": "avatar",
                    "avatar_id": AVATAR_ID,
                    "avatar_style": "normal"
                },
                "voice": {
                    "type": "text",
                    "input_text": AVATAR_CONTEXT,
                    "voice_id": VOICE_ID
                },
                "background": {
                    "type": "color",
                    "value": "#008000"
                }
            }
        ],
        "dimension": {
            "width": 1280,
            "height": 720
        },
        "aspect_ratio": "16:9",
        "test": True
    }
    json_data = json.dumps(payload)

    # curlコマンドをリストとして定義
    CURL_COMMAND_1 = [
        'curl', '-X', 'POST', 
        'https://api.heygen.com/v2/video/generate',  # URL
        '-H', f'X-Api-Key: {HEYGEN_API_KEY}',        # APIキー
        '-H', 'Content-Type: application/json',      # コンテンツタイプ
        '-d', json_data                              # データペイロード
    ]
    # curlコマンドを実行し、結果を取得
    result_1 = subprocess.run(CURL_COMMAND_1, capture_output=True, text=True)
    
    # 応答結果の確認
    video_id = ""
    if result_1.returncode == 0:
        response_data = result_1.stdout
        print("APIコール成功:")
        # 必要に応じてJSONデータとしてパース
        try:
            response_json = json.loads(response_data)
            video_id = response_json['data']['video_id']
        except json.JSONDecodeError:
            print("APIレスポンスがJSON形式ではありません。")
    else:
        print("APIコール失敗:")
        print(result_1.stderr)


    # ==========================================================================
    # curlコマンドをリストとして定義
    CURL_COMMAND_2 = [
        'curl', '-X', 'GET', 
        f'https://api.heygen.com/v1/video_status.get?video_id={video_id}',  # URL
        '-H', f'X-Api-Key: {HEYGEN_API_KEY}'
    ]
    
    video_url = ""
    while True:
        # curlコマンドを実行し、結果を取得
        result_2 = subprocess.run(CURL_COMMAND_2, capture_output=True, text=True)
        
        # 応答結果の確認
        video_url = ""
        if result_2.returncode == 0:
            response_data = result_2.stdout
            print("APIコール成功:")
            # 必要に応じてJSONデータとしてパース
            try:
                response_json = json.loads(response_data)
                video_url = response_json['data']['video_url']
                if video_url == None:
                    time.sleep(30)
                    continue
                else:
                    break
            except json.JSONDecodeError:
                print("APIレスポンスがJSON形式ではありません。")
                break
        else:
            print("APIコール失敗:")
            print(result_2.stderr)
            break
            
   
    # ==========================================================================
    CURL_COMMAND_3 = [ 
        'curl', 
        f'{video_url}',  # URL
        '--output', f'{OUTPUT_FILE_NAME}'        # mp4ファイル
    ]
    # curlコマンドを実行し、結果を取得
    result_3 = subprocess.run(CURL_COMMAND_3, capture_output=True, text=True)
    
    # 応答結果の確認
    if result_3.returncode == 0:
        response_data = result_3.stdout
        print("3. APIコール成功:")
    else:
        print("4. APIコール失敗:")
        print(result_3.stderr)

# ===========================================================================
# ===========================================================================
# ===========================================================================
if __name__ == "__main__":
    create_avatar_video()

1. アバター動画の作成

まず、「アバターID」「音声ID」、そして「プロンプト(話す内容)」を基に、アバターの動画を作成します。結果はresult_1に出力され、その中からvideo_idを取得します。

    # curlコマンドを実行して結果を取得
    result_1 = subprocess.run(CURL_COMMAND_1, capture_output=True, text=True)

2. 動画作成の進捗確認

次に、動画(video_url)を取得するためにAPIを呼び出します。動画の生成には3~5分ほどかかるため、30秒ごとにAPIを呼び出して「video_url」が生成されているかを確認するループ処理を行います。

    while True:
        # curlコマンドを実行して結果を取得
        result_2 = subprocess.run(CURL_COMMAND_2, capture_output=True, text=True)
        .....
                if video_url == None:
                    time.sleep(30)
                    continue
        .....

3. 動画のダウンロード

動画が無事作成されたら、mp4ファイルとしてPCにダウンロードします。

    # curlコマンドを実行して結果を取得
    result_3 = subprocess.run(CURL_COMMAND_3, capture_output=True, text=True)

実行

無料版では1日に5回までしか動画を作成できない制限があるため、プログラムを実行する際はその点に注意してください。プログラムが正常に終了すると、指定したフォルダ内にfirst_output.mp4というファイルが生成されます。作成された動画は、動画編集ソフトなどで確認可能です。

ちなみに、私が作成した動画はこちらです:

https://www.youtube.com/watch?v=WKfDLPPjIQQ

おわりに

生成AIはチャットでのQAだけでなく、今回のようにアバターの作成にも大きな可能性を秘めています。これまでビジネススキルとしては「英語」「会計」「IT」が重視されてきましたが、これからは「生成AI」が新たに加わる時代が訪れるでしょう。皆さんもぜひ時間があるときに、この新しい技術を触ってみることをおすすめします。

Discussion