【OpenAI】星占いのショート動画を生成するプログラム【Python】

 コンピュータ  1441

 以前の記事で、ChatGPTを利用してプログラマーのための星座占いを作成した。今回は、星占いのYoutubeショート動画を生成するプログラム作成したので紹介する。

プログラム概要

 このプログラムは、Linux(Ubuntu)環境で動作するPythonのプログラムで、テキストファイルのシナリオに基づいて動画を生成する。また、音声データも含めて作成するために、無料の「VOICEVOX」というテキスト読み上げソフトウェアを使っている。動画はYouTubeのショート動画の規格に合わせ、1分以内の縦長の動画となっている。

 

生成した動画のサンプル(Youtubeショート動画)

 ドット絵や星占いデータは、OpenAIのAPIを利用して作成している。

 

メインプログラムのソースコード

from PIL import Image, ImageDraw, ImageFont
from moviepy.editor import *
from voicevox import generate_speech
import numpy as np

# 背景画像を読み込む
background = Image.open('bg.jpg')

# astrology.txtというテキストファイルを読み込む
# txtのデータの内容:duration(再生時間),image_file(画像ファイル名), text(テキスト)
with open('astrology.txt', 'r') as file:
    # 1行ずつ読み込み、astrology_textというリストに格納する
    astrology_text = file.readlines()

# astrology_textの行数を計算
num_lines = len(astrology_text)

# 現在の行番号を初期化
current_line = 0

# 現在の行の持続時間を取得する
now_line_duration = float(astrology_text[current_line].strip().split(',')[0])

# フレーム生成
def generate_frame(t):
    global current_line,now_line_duration,num_lines
    frame = background.copy()

    try:
    # 表示秒数を超えたら次のラインにする
        # テキストを分割して行にする
        duration,image_file, text = astrology_text[current_line].strip().split(',')
        duration = float(duration)
        draw = ImageDraw.Draw(frame)

        # 画像ファイルが存在するか確認
        if image_file:
            # 画像を読み込んで描画する
            image = Image.open(image_file)
            # 画像のサイズを取得
            image_width, image_height = image.size

            # 画面の中心に描画するための位置を計算
            x = (background.width - image_width) // 2
            y = (background.height - image_height) // 2

            frame.paste(image, (x, y))

        if text:        
            # テキストを描画する
            font_path ='/usr/share/fonts/truetype/fonts-japanese-gothic.ttf'
            font = ImageFont.truetype(font_path, 100)
            lines = split_text_to_lines(text, font, draw, frame.width)
            line_height = draw.textsize(' ', font)[1]
            y = background.height - len(lines) * line_height
            for line in lines:
                size = draw.textsize(line, font)
                x = (background.width - size[0]) // 2
                draw.text((x, y), line, font=font, fill=(255, 255, 255), stroke_width=5, stroke_fill=(0, 0, 0))
                y += line_height

        # 表示秒数を超えていたら次の行にする
        if(int(t / now_line_duration) > 0):
            current_line +=1
            duration = float(astrology_text[current_line].strip().split(',')[0])
            now_line_duration += duration

        return np.array(frame)
    except IndexError:
        return np.array(frame)

# テキスト折り返し処理
def split_text_to_lines(text, font, draw, max_width):
    characters = list(text)
    lines = []
    line = ''
    for character in characters:
        new_line = line + character
        size = draw.textsize(new_line, font)

        if size[0] > max_width:
            lines.append(line.strip())
            line = character
        else:
            line = new_line
    lines.append(line.strip())
    return lines

# main関数
def main():
    """
    メイン関数
    """
    # 音声ファイルを生成・追加
    audio_clips = []

    for i in range(num_lines):
        line_duration, _, text = astrology_text[i].strip().split(',')
        line_duration = float(line_duration)
        speaker = 1
        speech_clip = AudioFileClip(generate_speech(text, speaker, i), fps=44100)
        audio_clips.append(speech_clip)
    
    # BGMを追加
    music = AudioFileClip("bgm.mp3")
    music = music.set_duration(59).set_start(0)

    # ビデオクリップを生成
    clip = VideoClip(generate_frame, duration=59)
    audio = concatenate_audioclips(audio_clips)
    final_audio = CompositeAudioClip([music,audio])
    final_clip = clip.set_audio(final_audio)

    # 書き出し
    final_clip.write_videofile("astrology.mp4",codec= 'mpeg4',audio_codec='aac', fps=30)

# main関数の呼び出し
if __name__=="__main__":
    # プログラムのエントリーポイント
    main()

 
VOICEVOXのAPIにリクエストを送信するプログラムのソースコード

import requests, tempfile, json

def generate_speech(text, speaker,i):
# text : 合成するテキストを指定します。
# speaker : 合成するスピーカーを指定します。
# i : 音声ファイル番号を指定します。

    # VOICEVOX APIのホストアドレス
    host = "127.0.0.1" 
    # VOICEVOX APIのポート番号
    port = 50021

    # リクエストパラメーターを設定
    params = (
        ("text", text),# 合成するテキスト
        ("speaker", speaker)# 合成するスピーカー
    )

    # audio_queryエンドポイントにPOSTリクエストを送信
    response1 = requests.post(
        f"http://{host}:{port}/audio_query",
        params=params
    )

    # synthesisエンドポイントにPOSTリクエストを送信
    response2 = requests.post(
        f"http://{host}:{port}/synthesis",
        headers={"Content-Type": "application/json"},
        params=params,
        data=json.dumps(response1.json())
    )

    # 合成した音声を保存
    with tempfile.TemporaryDirectory() as tmp:
        with open(f"tmp/audi_{i}.wav", "wb") as f:
            f.write(response2.content)
            return f"tmp/audi_{i}.wav"

 

まとめ

 今回は、テキストデータのシナリオに基づいてYoutubeショート動画を作成するPythonプログラムを作成した。
 以下のプログラムを追加することで、動画の作成から投稿まで自動化が可能となる。
1)動画のシナリオを作成するプログラム。
2)YoutubeのAPIを利用して自動的に投稿するプログラム。

 今回のような星占いのシナリオはシンプルな配列などで実装できるので、一度仕組みを作れば動画の作成ごとにOpenAIのAPIを使う必要は無い。日々のニュースのまとめ動画のようなものを作成する場合は、別の記事で紹介しているようなスクレイピングやOpenAIによる要約を組み合わせることが必要になるだろう。



関連記事