GPTの視覚的機能とTTS APIを用いた動画の処理とナレーション生成

このチュートリアルは面白かったです。

https://cookbook.openai.com/examples/gpt_with_vision_for_video_understanding

Databricksで動かしました。翻訳したノートブックはこちらです。

https://github.com/taka-yayoi/gpt-4-visual-tts/tree/main

```py
%pip install opencv-python
%pip install -U openai
%restart_python
```

このノートブックは、ビデオを使用してGPTの視覚的な機能を示します。GPT-4oはビデオを直接入力として受け取りませんが、ビジョンと128Kコンテキストウィンドウを使用して、ビデオ全体の静止フレームを一度に説明することができます。2つの例を通して説明します：

1. GPT-4oを使用してビデオの説明を取得する
1. GPT-oとTTS APIを使用してビデオのナレーションを生成する

```py
from IPython.display import display, Image, Audio

import cv2  # ビデオを読み取るためにOpenCVを使用しています。インストールするには !pip install opencv-python
import base64
import time
from openai import OpenAI
import os
import requests

client = OpenAI(api_key=dbutils.secrets.get("demo-token-takaaki.yayoi", "openai_api_key"))

os.environ['OPENAI_API_KEY'] = dbutils.secrets.get("demo-token-takaaki.yayoi", "openai_api_key")
```

# 1. GPTの視覚的な機能を使用してビデオの説明を取得する

まず、OpenCVを使用して[鳥が写っている動画](https://github.com/taka-yayoi/gpt-4-visual-tts/blob/main/data/birds.MP4)(うちのインコたちです)からフレームを抽出します：

```py
video = cv2.VideoCapture("data/birds.MP4")

base64Frames = []
while video.isOpened():
    success, frame = video.read()
    if not success:
        break
    _, buffer = cv2.imencode(".jpg", frame)
    base64Frames.append(base64.b64encode(buffer).decode("utf-8"))

video.release()
print(len(base64Frames), "frames read.")
```
```
1350 frames read.
```

フレームが正しく読み込まれたことを確認するために表示します：

:::note info
Databricksノートブックでは以下のコードブロックは動きませんでした。
:::

```py
display_handle = display(None, display_id=True)

for img in base64Frames:
    display_handle.update(Image(data=base64.b64decode(img.encode("utf-8"))))
    time.sleep(0.025)
```

ビデオフレームを取得したら、プロンプトを作成してGPTにリクエストを送信します（GPTが状況を理解するためにすべてのフレームを送信する必要はありません）：

```py
PROMPT_MESSAGES = [
    {
        "role": "user",
        "content": [
            "これはアップロードしたいビデオのフレームです。ビデオと一緒にアップロードできる魅力的な説明を生成してください。",
            *map(lambda x: {"image": x, "resize": 768}, base64Frames[0::50]),
        ],
    },
]
params = {
    "model": "gpt-4o",
    "messages": PROMPT_MESSAGES,
    "max_tokens": 200,
}

result = client.chat.completions.create(**params)
print(result.choices[0].message.content)
```
```
愛らしいインコたちが冒険中！彼らの色鮮やかな羽根が魅力的な動きを見せ、毎日がまるでカラフルな物語の一部みたい。このビデオで彼らの小さな世界をお楽しみください！🌈🐦
```

ここでも[MLflow Tracing](https://qiita.com/taka_yayoi/items/35c96ecd401c199e617b)で動作を確認できます。

![Screenshot 2025-02-26 at 15.32.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/c272a8bf-3959-4077-8cf2-4cafb0f211a7.png)

# 2. GPT-4とTTS(Text To Speech) APIを使用したビデオのナレーション生成

このビデオのナレーションを[デイビッド・アッテンボロー](https://ja.wikipedia.org/wiki/%E3%83%87%E3%82%A4%E3%83%93%E3%83%83%E3%83%89%E3%83%BB%E3%82%A2%E3%83%83%E3%83%86%E3%83%B3%E3%83%9C%E3%83%AD%E3%83%BC)風に作成しましょう。同じビデオフレームを使用して、GPTに短いスクリプトを作成させます：

```py
PROMPT_MESSAGES = [
    {
        "role": "user",
        "content": [
            "これらはビデオのフレームです。デイビッド・アッテンボローのスタイルで短いナレーションスクリプトを作成してください。ナレーションのみを含めてください。",
            *map(lambda x: {"image": x, "resize": 768}, base64Frames[0::60]),
        ],
    },
]
params = {
    "model": "gpt-4o",
    "messages": PROMPT_MESSAGES,
    "max_tokens": 500,
}

result = client.chat.completions.create(**params)
print(result.choices[0].message.content)
```
```  
今、我々は小さな世界の一端を垣間見ることができます。この愛らしいインコたちは、興味津々に身の回りの世界を探検しています。彼らは何を見つけるのでしょうか？

そのカラフルな羽を輝かせながら、彼らは新しい発見を楽しんでいます。好奇心旺盛な彼らにとって、どんな小さな物も興味の対象です。テーブルの上に置かれたアイテムに向かい、細やかな視線を送るその姿には、身近な自然の神秘が詰まっています。

インコたちが日々新しい何かを見つけ出すその冒険心こそが、彼らを自然界の究極の探求者にしているのです。
```  

次に、スクリプトをTTS APIに渡して、ナレーションのmp3を生成します:

```py
response = requests.post(
    "https://api.openai.com/v1/audio/speech",
    headers={
        "Authorization": f"Bearer {os.environ['OPENAI_API_KEY']}",
    },
    json={
        "model": "tts-1-1106",
        "input": result.choices[0].message.content,
        "voice": "onyx",
    },
)

audio = b""
for chunk in response.iter_content(chunk_size=1024 * 1024):
    audio += chunk
Audio(audio)
```
以下のようにプレーヤーが表示されるので、音声を確認できます(以下は画像を貼り付けているだけなので再生できません)。保存した音声ファイルは[こちら](https://github.com/taka-yayoi/gpt-4-visual-tts/blob/main/data/birds_narration.wav)です。

![Screenshot 2025-02-26 at 15.34.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/ed50872a-3134-4041-9e43-5bf1e606a112.png)

音声ファイルを保存します。

```py
with open('data/birds_narration.wav', 'wb') as f:
  f.write(audio)
```

これで、元の動画と生成されたナレーションが揃ったので、iMovieなどでまとめます。結果がこちらです。

<iframe width="560" height="315" src="https://www.youtube.com/embed/S8bNxhfojx8?si=XHNajgLe6eRlbu6Z" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

なにこれ楽しい。他の動画でも作ってみたくなりました。

### はじめてのDatabricks

[はじめてのDatabricks](https://qiita.com/taka_yayoi/items/8dc72d083edb879a5e5d)

### Databricks無料トライアル

[Databricks無料トライアル](https://databricks.com/jp/try-databricks)