Gemini APIを活用した自動テロップ生成システムの開発

こんにちは！今回は、Gemini API（Google製生成AI）とWeb検索を組み合わせて、動画用の高品質テロップを自動生成するシステムを開発したので紹介します。

## 開発の背景

動画編集において、テロップ（字幕）の作成は重要ながらも時間のかかる作業です。特に旅行動画などでは、地名や名所に関する情報を適切にテロップとして表示することで、視聴者の理解を深めることができます。この工程を自動化するために、AIを活用したテロップ生成システムを開発しました。

## システム概要

本システムは、以下の特徴を持っています：

- SRTファイル形式での入出力
- シナリオファイルに基づくコンテキスト理解
- Web検索による最新情報の取得
- Gemini APIによる自然な文章生成
- オープニングとエンドロールの自動生成
- 短く区切られた読みやすいテロップ

## 処理フロー

以下がテロップ生成の全体フローです：

```plantuml
@startuml
start
:入力SRTファイルの読み込み;
:シナリオファイルの読み込み;
:最大再生時間の取得;
:シーンに分割（10秒単位）;

:オープニングテロップ用のWeb検索実行;
:オープニングテロップの生成;
:オープニングテロップをSRTに追加;

repeat :各シーンを処理
  :シーン内の字幕からキーワードを抽出;
  if (キーワードが抽出できた?) then (yes)
    :シナリオ内の関連セクションを検索;
    :Web検索を実行（キーワード+観光情報）;
    :テロップ生成プロンプトを作成;
    :Gemini APIでテロップ文章を生成;
    :テロップを整形（改行除去、長さ制限等）;
    :生成されたテロップをSRTに追加;
  else (no)
    :このシーンはスキップ;
  endif
repeat while (未処理のシーンがある?)

:エンドロール用のWeb検索実行;
:エンドロールテロップの生成;
:エンドロールをSRTに追加;

:出力SRTファイルの書き出し;
stop
@enduml
```

## 実装詳細

### 1. SRTファイルの読み込みと解析

```python
def parse_srt_file(file_path: str) -> List[SRTBlock]:
    with open(file_path, 'r', encoding='utf-8') as file:
        content = file.read()
    
    blocks = content.strip().split("\n\n")
    srt_blocks = []
    
    for block in blocks:
        lines = block.strip().split("\n")
        if len(lines) < 3:
            continue
        
        try:
            index = int(lines[0])
            timestamp = lines[1]
            text = '\n'.join(lines[2:])
            srt_blocks.append(SRTBlock(index, timestamp, text))
        except ValueError:
            continue
    
    return srt_blocks
```

### 2. シーンからのキーワード抽出

シーン内の字幕テキストから重要なキーワードを抽出します。地名や交通機関、観光スポットなどを優先的に抽出するように設計しています。

```python
def extract_keywords_from_scene(srt_blocks: List[SRTBlock], start_time: float, end_time: float) -> str:
    # 指定した時間範囲内の字幕を収集
    scene_blocks = [block for block in srt_blocks if 
                   (block.start_time <= end_time and block.end_time >= start_time)]
    
    # すべてのテキストを結合
    combined_text = " ".join([block.text for block in scene_blocks])
    
    # キーワード抽出ロジック（省略）
    # ...
    
    return " ".join(top_keywords)
```

### 3. Web検索の実行

抽出したキーワードを使ってWeb検索を行い、最新の関連情報を取得します。

```python
def search_web(query: str, num_results: int = 3) -> str:
    print(f"検索クエリ: {query}")
    
    url = "https://google.serper.dev/search"
    payload = json.dumps({
        "q": query,
        "gl": "jp",
        "hl": "ja",
        "num": num_results
    })
    headers = {
        'X-API-KEY': SERPER_API_KEY,
        'Content-Type': 'application/json'
    }
    
    # 検索実行とレスポンス処理（省略）
    # ...
    
    return "\n".join(results)
```

### 4. テロップの生成

Gemini APIを使って、抽出したキーワード、シナリオ情報、Web検索結果を元に自然なテロップを生成します。

```python
def generate_caption_prompt(keywords: str, scenario_section: str, search_results: str) -> str:
    prompt = """
あなたは旅行ドキュメンタリーの字幕・テロップライターです。以下の情報に基づいて、魅力的な字幕テキストを1つだけ生成してください：

【キーワード】
{}

【シナリオセクション】
{}

【Web検索結果】
{}

以下の点に注意して、最大60文字程度の簡潔で魅力的な字幕テキストを1つだけ作成してください：
1. 視聴者に見どころや旅の魅力を伝える内容にする
2. シナリオセクションの内容と関連するWeb検索情報を活用する
3. ナレーターが説明している感じの文体にする
4. テロップの前に「テロップ例：」などの表現を入れないこと
5. マークダウン記法（**など）を使用しないこと
6. 改行を入れないこと
7. タイムスタンプを入れないこと
8. 複数の選択肢を提示しないこと
9. 短くて簡潔なテロップにすること

【生成テロップ】
""".format(keywords, scenario_section, search_results)
    
    return prompt
```

### 5. オープニングとエンドロールの生成

番組や映画風の専門的なオープニングとエンドロールも自動生成します。

```python
def generate_opening_prompt(scenario_text: str, search_results: str) -> str:
    prompt = """
あなたはテレビ番組や映画のオープニングテロップを作成するプロフェッショナルです。
以下の情報に基づいて、魅力的なオープニングテロップを生成してください：

【シナリオ概要】
{}

【Web検索結果】
{}

以下の点に注意して、番組/映画のオープニングとして適切な字幕テキストを作成してください：
1. テレビ番組や映画のプロローグのような簡潔で印象的な内容にする
2. 旅の魅力や見どころを視聴者に伝える内容を含める
3. 全体で100〜150文字程度にまとめる
4. 改行は必要最小限にする（2〜3行程度に収める）
5. 「ナレーション：」などの表記は入れない
6. 旅番組の導入部らしい語り口調にする

【オープニングテロップ】
""".format(scenario_text[:500], search_results)
    
    return prompt
```

## 生成されるテロップの例

### オープニングテロップ例

```
京都から特急はしだてで行く城崎温泉の旅。柳並木が美しい情緒ある街並み、七つの外湯、
そして冬の味覚・カニグルメ。千年の歴史を持つ温泉地で、
心も体も温まる1泊2日の癒しの旅へご案内します。
```

### 本編テロップ例（10秒ごと）

```
00:00:10,000 --> 00:00:20,000
京都駅から特急「はしだて」で出発！福知山駅で乗り換えです。

00:00:20,000 --> 00:00:30,000
車窓からは亀岡の美しい霧景色が楽しめます。

00:00:30,000 --> 00:00:40,000
福知山駅でコウノトリ号に乗り換え、城崎温泉へ向かいます。
```

### エンドロール例

```
制作・著作 © 2023 トラベルドキュメンタリー制作委員会

撮影協力：
城崎温泉観光協会
西日本旅客鉄道株式会社（JR西日本）
城崎温泉旅館協同組合

特別協力：
兵庫県豊岡市
豊岡観光イノベーション

音楽：
「旅のしらべ」作曲：音楽太郎

旅行情報提供：
JR西日本ツアーズ

本番組は2023年10月に撮影されたものです。
```

## まとめ

このシステムを使うことで、SRTファイルとシナリオから自動的にプロフェッショナルなテロップを生成できます。Gemini APIとWeb検索を組み合わせることで、単なる字幕変換ではなく、情報価値の高いテロップが実現しました。

今後は、映像解析と組み合わせることで、映像内容に基づいたさらに的確なテロップ生成を目指しています。

## 技術スタック

- Python 3.8+
- Google Gemini API
- Serper API（Google検索用）
- PlantUML（フロー図作成）

コードの全文はGitHubで公開予定です。質問やフィードバックはコメントでお待ちしています！