パートナーシップ

n8nとTwelveLabsで動画解析とセマンティック検索を自動化する

ジョーダン・ウッズ、ブリス・パンヴァン、ジェームズ・ル

開発者は、カスタムの統合コードを作成することなく、n8nとTwelve Labsを使用して、本番環境に対応したビデオAIワークフローを構築できます。これには、並行してコンプライアンス、要約、チャプター、およびハイライト分析を実行しAirtableに保存するS3インジェストパイプラインや、ブランド化された結果ページを備えたセマンティックビデオ検索インターフェースが含まれます。

開発者は、カスタムの統合コードを作成することなく、n8nとTwelve Labsを使用して、本番環境に対応したビデオAIワークフローを構築できます。これには、並行してコンプライアンス、要約、チャプター、およびハイライト分析を実行しAirtableに保存するS3インジェストパイプラインや、ブランド化された結果ページを備えたセマンティックビデオ検索インターフェースが含まれます。

この記事の内容

No headings found on page

ニュースレターに登録する

ニュースレターに登録する

ビデオ理解に関する最新の技術進歩、チュートリアル、業界の動向をお届けします

ビデオ理解に関する最新の技術進歩、チュートリアル、業界の動向をお届けします

AIを活用してビデオを検索、分析、探索します。

2026/02/17

25分

記事へのリンクをコピー

1 - 概要紹介


1.1 - n8nの概要:技術チーム向けに構築された自動化プラットフォーム

n8nは、ビジュアルなノードベースのインターフェースを通じてアプリケーション、API、サービスを接続するオープンソースのワークフロー自動化プラットフォームです。多くの従来の自動化ツールとは異なり、n8nは開発者や技術チームにデータとロジックの完全な制御権を提供し、セルフホストまたはクラウドでの実行を柔軟に選択できます。

AI駆動のユースケースにおいて、n8nはAIサービスと既存のビジネスシステムとの架け橋となるため、強力な支持を得ています。400以上の構築済みの統合機能とカスタムコードのサポートにより、n8nはインフラをゼロから構築・維持することなく、チームが複雑なAIワークフローを編成できるようにします。

特にビデオAIにおいて、n8nはワークフローの地味ながらも重要な部分、つまりストレージシステム間のメディアの移動、分析ジョブのトリガー、再試行とエラーの処理、モデル出力のパース、そしてMAMやデータベースなどのオペレーショナルツールへの結果のルーティングを適切に処理することに適しています。

AI実装におけるn8nの真の強力さは、複数のステップを連結し、エラー復旧を管理し、異なるフォーマット間でデータを変換する能力にあります。これらすべてを、技術チームが要件の変化に合わせて迅速に反復し適応できるビジュアルインターフェースで行うことができます。


1.2 - TwelveLabs + n8nの理由:ビデオAIのプロダクション導入を加速する

TwelveLabsは、APIを通じて最先端のマルチモーダルビデオ理解を提供しますが、APIを呼び出すことは最初の一歩に過ぎません。実際のビデオワークフローは複雑です。コンテンツはMAMにあり、結果はデータベースに登録する必要があり、コンプライアンスチームは独自のツールを使用し、検索機能は既存のアプリケーション内で動作させる必要があります。

n8nは、TwelveLabsとお客様のシステムの間の接続を制御することでこれを解決します。各プラットフォーム向けにカスタム統合コードを記述する代わりに、n8nでは構築済みのコネクタと柔軟なロジックが提供されるため、ビデオURLをTwelveLabsにプッシュし、戻ってきた結果を処理して、必要な宛先に結果をルーティングすることができます。

これにより、本番環境への導入期間が劇的に短縮されます。TwelveLabsのお客様は、数か月ではなく数日でビデオAIを実際のワークフローに接続できます。それがメディアライブラリのメタデータによる充実化であれ、コンプライアンスレビューの自動化であれ、社内アプリへのセマンティック検索の追加であれ、同様です。


1.3 - 対象読者

このチュートリアルは、既存のツールとシームレスに統合できる実用的な自動化を必要としている、大規模にビデオを扱う技術チームを対象として構築されています。

  • メディア&エンターテインメントのプロフェッショナル(制作、ポストプロダクション、放送):大規模なライブラリにわたるビデオ分析、コンテンツモデレーション、メタデータ強化を自動化します。

  • エンタープライズチーム(社内ビデオ、企業コミュニケーション、マーケティング、トレーニングの管理):検索、整理、コンプライアンスワークフローを向上させます。

  • プラットフォームおよびエンジニアリングチーム(ビデオアプリケーションの構築):AIインフラを管理することなく、セマンティック検索、レコメンデーション、または自動分析を組み込みます。

  • システムインテグレーターおよびソリューションアーキテクト:異なるクライアント環境にわたってビデオAIプロジェクトを効率的に提供します。

  • APIおよびワークフローの実践者(ビジュアルまたはコードベース):必要な柔軟性を備えた、本番環境に対応したビデオAIをスタックに接続します。


2 - 主要な操作

TwelveLabs n8n コミュニティノードは、インデックスの作成やビデオのアップロードから、分析やインサイトの生成に至るまで、完全なビデオAIワークフローを処理する3つのコアリソースグループを提供します。各リソースには、本番のビデオワークフローにおける一般的なタスクに対応する特定の操作が含まれています。


2.1 - Index(インデックス)リソース:検索可能なビデオインデックスの管理

Indexリソースを使用すると、ビデオが保存され処理される基礎となるコンテナを作成および管理できます。

  • Create Index(インデックスの作成) – AIモデルを使用して新しい検索可能なインデックスをセットアップします。インデックスを駆動するモデル(Pegasus PlusまたはMarengo Plus)を選択し、モデル固有のオプションを設定し、ユースケースに必要なアドオンを有効にします。

  • List Indexes(インデックスの一覧取得) – アカウント内のすべてのインデックスを取得して、すでに作成されているものを確認し、複数のプロジェクトや環境を管理します。

  • Search Index by Name(名前によるインデックス検索) – 特定のビデオコレクションやプロジェクトをターゲットとするワークフローを構築する際に役立つ、名前による特定のインデックスの迅速な特定を行います。


2.2 - Video(ビデオ)リソース:インデックス内でのビデオのアップロードと管理

Videoリソースは、コンテンツをインデックスに取り込み、そのステータスを追跡する実務的な作業を処理します。

  • Upload Video(ビデオのアップロード) – 柔軟なインプットオプションを使用してインデックスにビデオを追加します。ビデオファイルを直接アップロードするか、ビデオのURLを提供できます(S3などのクラウドストレージにコンテンツがすでにある場合に便利です)。ビデオはアップロードされると自動的に処理され、インデックスに登録されます。

  • List Videos(ビデオの一覧取得) – 特定のインデックスに保存されているすべてのビデオを取得します。この操作はビデオのメタデータと処理ステータスを返すため、ビデオの分析準備がいつ整うかを把握し、取り込みの進行状況を追跡できます。


2.3 - Analysis(分析)リソース:ビデオからAI駆動のインサイトを生成

Analysisリソースは、インデックス化されたビデオコンテンツから実用的なインテリジェンスを生成します。

  • Generate Summary(要約の生成) – カスタマイズ可能な要約タイプと言い回しを調整できるプロンプトテンプレートを使用して、ビデオコンテンツの簡潔な要約を作成します。長いビデオをすばやく理解したり、メタデータ用の分かりやすい説明を作成したりするのに便利です。

  • Generate Chapters(チャプターの生成) – スマートなチャプター検出機能を使用して、ビデオを自動的にチャプターに分割します。結果にはタイムスタンプ付きのセグメントが含まれるため、長尺コンテンツのナビゲーションや構造化されたアウトラインの作成が容易になります。

  • Generate Highlights(ハイライトの生成) – 重要なシーンを特定して、ビデオから重要な瞬間を抽出します。これを使用して、ハイライトリールやクリップのコンピレーションを作成したり、ビデオライブラリの最も関連性の高い部分を表面化させたりします。


3 - 基本ワークフローのデモ:S3からメタデータへ


3.1 - ワークフローの概要

このワークフローは、S3からビデオを取り込み、TwelveLabsで分析し、充実したメタデータをAirtableに保存するという、エンドツーエンドのビデオAI自動化をデモンストレーションします。


前提条件

開始する前に、以下があることを確認してください:

  • n8nアカウント(クラウドまたはセルフホスト)

  • S3アクセス権を持つAWSアカウント

  • TwelveLabsアカウントとAPIキー

  • Airtableアカウント


パイプライン アーキテクチャ

ワークフローは主に3つのステージで構成されています:

1. TwelveLabsへのインデックス登録

  • S3バケットからビデオファイルを取得する

  • Lambda経由で署名付きURLを生成する

  • 重複するURLを削除する

  • TwelveLabsでビデオをインデックス登録する

2. TwelveLabsでビデオを分析する

  • 4つの分析を並行して実行する:

    • コンプライアンス: プラットフォームポリシー(YouTube ABCDフレームワーク)に照らし合わせてコンテンツをフラグ付けする

    • 要約: 主要なテーマと概要を抽出する

    • チャプター: タイムスタンプ付きのセグメントを生成する

    • ハイライト: 注目すべき瞬間を抽出する

  • 結果をマージし、コンプライアンスステータスを解析する

  • データベース保存用に出力を構造化する

3. 結果の保存

  • タグとメタデータを使用してAirtableにアップサート(挿入または更新)する

  • 本番環境では、通常、結果はMAM、SQL/NoSQLデータベース、またはクラウドデータプラットフォームに送信されます


主要な技術パターン
  • 署名付きURL - AWSの認証情報を公開することなく、プライベートなS3ファイルをTwelveLabsと安全に共有します

  • 並行処理 - 4つの分析タスクを同時に実行し、その後結果をマージします

  • アップサートロジック - Airtableのレコードをインテリジェントに作成または更新します(再実行時に重複が発生しません)

  • ステータス解析 - AIが生成したテキストから構造化されたコンプライアンスステータスを抽出します


3.2 - セットアップ:トリガーとS3接続


ステップ 1: 手動トリガーの作成

  1. n8nを開き、"New Workflow"(新規ワークフロー)をクリックします

  2. "+" ボタンをクリックして、最初のノードを追加します

  3. "Manual Trigger"(手動トリガー)を検索して選択します

手動トリガーは、ワークフローの「スタート」ボタンとして機能します。n8nで「Execute Workflow(ワークフローの実行)」をクリックすると、このノードが起動し、下流のすべてを開始します。

💡 本番環境のヒント:動作が確認できたら、Schedule Trigger(1時間/1日ごとに実行)、Webhook Trigger(別のアプリがリクエストを送信したときに実行)、S3 Trigger(新しいファイルがアップロードされたときに実行)などの自動トリガーに切り替えてください。


ステップ 2: S3からビデオを取得する

  1. 手動トリガーノードの "+" ボタンをクリックします

  2. "AWS S3" を検索して選択します

  3. ノードを設定します:

    • Operation(操作): "Get Many"(複数取得)を選択します

    • Bucket Name(バケット名): バケット名を入力します(例: my-video-bucket

    • Return All(すべて返却): これをオン(ON)に切り替えます

  4. "Credentials"(認証情報)をクリックし、AWSの認証情報を追加します:

    • AWSアクセスキーIDを入力します

    • AWSシークレットアクセスキーを入力します

    • リージョンを選択します

これにより、S3バケット内のすべてのファイルに関するメタデータ(キー(ファイルパス/名)、サイズ、最終更新タイムスタンプ)が取得されます。実際のビデオはダウンロードされず(低速で高コストになるため)、アクセスリンクの生成に必要な情報のみを取得します。

⚠️ 権限のチェック:AWSの認証情報に s3:ListBucket および s3:GetObject の権限があることを確認してください。「Access Denied(アクセス拒否)」が表示される場合は、IAMポリシーを確認してください。


ステップ 3: セキュアなアクセスリンクの生成

TwelveLabsはビデオをダウンロードする必要がありますが、S3バケットは非公開です。署名付きURLがこれを解決します。これらは、AWSの認証情報なしで動作する、一時的で安全なリンク(1時間有効)です。

  1. S3ノードの "+" ボタンをクリックします

  2. "AWS Lambda" を検索して選択します

  3. ノードを設定します:

    • Function(関数): Lambda関数のARNを選択または貼り付けます

    • Payload(ペイロード): "Add Expression"(式の追加)をクリックし、以下を入力します:

{{ JSON.stringify({ 
  bucketName: "your-bucket-name", 
  files: $input.all().map(item => item.json), 
  expiresIn: 3600 
}) }}

Lambda関数は、各ファイルをループ処理し、AWS SDKを使用して署名付きURLを生成し、すべてのURLをn8nに返す必要があります。

💡 なぜLambdaを使用するのですか? n8nは、サーバー側で動作するAWS SDKを必要とするため、署名付きURLを直接生成することはできません。Lambdaがこれを代わりに処理します。


ステップ 4: URLデータのパースとクリーンアップ

  1. Lambdaノードの "+" ボタンをクリックします

  2. "Code" を検索して選択します

  3. このコードを貼り付けます:

// Lambdaのレスポンスをパースし、重複を削除する
const seenKeys = new Set();
const results = [];

for (const item of $input.all()) {
  const response = JSON.parse(item.json.result.body);
  
  for (const file of response.files) {
    if (!seenKeys.has(file.Key)) {
      seenKeys.add(file.Key);
      results.push({
        json: {
          Key: file.Key,
          presignedUrl: file.presignedUrl,
          Size: file.Size,
          LastModified: file.LastModified,
          expiresIn: file.expiresIn
        }
      });
    }
  }
}

return results;

このコードは、Lambda応答(文字列を返す)をデコードし、Setを使用して重複するファイルを削除し、ビデオファイルごとに1つのクリーンなn8nアイテムを作成します。


3.3 - TwelveLabsでのビデオのインデックス登録

ここで、AI処理のために各ビデオをTwelveLabsにアップロードします。

  1. Codeノードの "+" ボタンをクリックします

  2. "TwelveLabs" を検索して選択します

  3. ノードを設定します:

    • Operation(操作): "Upload URL"(URLのアップロード)を選択します

    • Index ID(インデックスID): TwelveLabsのインデックスIDを入力します(これはTwelveLabsのダッシュボードで見つけることができます)

    • Video URL: "Add Expression"(式の追加)をクリックし、{{ $json.presignedUrl }} と入力します

  4. TwelveLabsのAPI認証情報を追加します


インデックス登録される内容

TwelveLabsは、以下の目的で各ビデオを処理します:

  • ビジュアルコンテンツの分析 - 物体、人物、アクション、シーン、色、構図

  • 音声の文字起こし - 話し言葉、対話、ナレーション

  • 画面上のテキストの抽出 - フレームに表示されるテキストのOCR処理

  • 埋め込み(Embeddings)の作成 - セマンティック検索用のベクトル表現

ノードは、後続の分析ステップで使用する videoId を返します。

⏱️ タイミング:インデックス登録には、ビデオの長さに応じて時間がかかります(通常、ビデオ1分あたり1〜3分)。n8nは完了を待ってから次に進みます。


3.4 - 並行分析の設定

分析を順次実行する(遅い)代わりに、時間を節約するために4つの異なる分析を同時に実行します。


並行ブランチのセットアップ

TwelveLabsのインデックス作成ノードから、4つの異なるTwelveLabs Analysisノードに 4つの独立した接続 を作成します:

  1. "Index to TwelveLabs" の出力からクリックしてドラッグします

  2. 最初のTwelveLabs Analysisノードを作成します

  3. 合計4つの分析ノードを作成するために、さらに3回繰り返します


分析タイプの比較

各分析ノードは同じ基本設定を使用しますが、異なるプロンプトを使用します:

1 - コンプライアンス分析

  • 目的: YouTubeのABCDフレームワークに照らしてコンテンツにフラグを立てる

  • 出力フォーマット: ステータス(合格/要レビュー/不合格) + タイムスタンプ付きのフラグが立った未解決事項

コンプライアンス分析プロンプト:

Analyze this video for content compliance using YouTube's ABCD framework:

**A - Adult Content:**
- Nudity or sexual content
- Sexually suggestive content
- Adult themes

**B - Brand Safety:**
- Inflammatory or demeaning content
- Hateful content targeting protected groups
- Harmful or dangerous acts
- Shocking or graphic content
- Profanity and crude language

**C - Copyright:**
- Copyrighted music, video, or images
- Unlicensed third-party content

**D - Dangerous/Harmful:**
- Violence or graphic content
- Drugs, dangerous products, or substances
- Firearms and weapons
- Misinformation (health, elections, etc.)

For each flagged issue, provide:
1. **Timestamp**: When it appears
2. **Category**: A, B, C, or D
3. **Issue**: Brief description
4. **Action**: Allow, Restrict (age-gate), Monetization off, or Remove

**Output:**


2 - 要約分析

  • 目的: 主要なテーマと概要を抽出する

  • 出力フォーマット: ビデオコンテンツに関する3〜4段落の要約

要約分析プロンプト:



3 - チャプター分析

  • 目的: タイムスタンプ付きのセグメントを生成する

  • 出力フォーマット: タイムスタンプと説明を含むチャプタータイトル

チャプター分析プロンプト:



4 - ハイライト分析

  • 目的: 注目すべき瞬間を抽出する

  • 出力フォーマット: タイムスタンプと理由を含む主要なシーン

ハイライト分析プロンプト:



共有ノードの設定

4つの分析ノードそれぞれに、このベース設定を使用します:

  • Operation(操作): "Generate" または "Analysis" を選択します

  • Index ID: {{ $json.indexId }}

  • Video ID: {{ $json.videoId }}

  • Temperature(温度): 0.2 に設定します(低いほど一貫した結果になります)


3.5 - 結果のマージと構造化


並行結果のマージ

  1. "+" をクリックし、"Merge"(マージ)を検索します

  2. ノードを設定します:

    • Number of Inputs(入力数): 4 に設定します

  3. 4つの分析ノードそれぞれを、このMergeノードに接続します:

    • Compliance(コンプライアンス) → Input 1

    • Summary(要約) → Input 2

    • Chapters(チャプター) → Input 3

    • Highlights(ハイライト) → Input 4

Mergeノードはチェックポイントとして機能し、4つの分析ノードすべてが完了するのを待ってから次に進みます。これにより、不完全なデータが保存されるのを防ぎます。


データの構造化

  1. Mergeノードの "+" をクリックし、Code ノードを追加します

  2. このコードを貼り付けます:

// すべて of analysis results を抽出して整理する
const allItems = $input.all();
const videoId = allItems[0]?.json?.videoId || '';
const complianceResponse = allItems[0]?.json?.response || '';

// AIの応答からコンプライアンスステータスを解析する
let complianceStatus = 'NEEDS REVIEW'; // デフォルト

if (complianceResponse.includes('Overall Status: Suitable')) {
  complianceStatus = 'PASS';
} else if (complianceResponse.includes('Overall Status: Not Suitable')) {
  complianceStatus = 'FAILED';
} else if (complianceResponse.includes('Overall Status: Needs Review')) {
  complianceStatus = 'NEEDS REVIEW';
}

// 構造化された出力を生成する
const result = {
  videoID: videoId,
  'Compliance Status': complianceStatus,
  'Compliance report': complianceResponse,
  'Summary': allItems[1]?.json?.response || '',
  'Chapters': allItems[2]?.json?.response || '',
  'Highlights': allItems[3]?.json?.response || ''
};

return [{ json: result }];

このコードは:

  1. 追跡用のビデオIDを抽出します

  2. AIの応答の中から特定のフレーズを探すことでコンプライアンスステータスを解析します

  3. Airtableの選択(Select)フィールドに合わせて、ステータスを正確に3つの値(PASS/FAILED/NEEDS REVIEW)のいずれかに正規化します

  4. 4つの分析結果すべてを単一のフラットなオブジェクトに整理します


3.6 - Airtableへの結果の保存


Airtableベースのセットアップ

  1. 新しいAirtableベースを作成します

  2. これらのフィールドを持つテーブルを作成します:

    • videoID(1行テキスト)

    • Compliance(「PASS」「FAILED」「NEEDS REVIEW」のオプションを持つ単一選択)

    • Compliance report(長いテキスト)

    • Summary(長いテキスト)

    • Chapters(長いテキスト)

    • Highlights(長いテキスト)


Airtableノードの設定

  1. Codeノードの "+" をクリックし、"Airtable" を検索します

  2. ノードを設定します:

    • Operation(操作): "Upsert" を選択します(これによりレコードが作成または更新されます)

    • Base(ベース): Airtableベースを選択します

    • Table(テーブル): テーブルを選択します

  3. フィールドをマッピングします:

    • videoID{{ $json.videoID }}

    • Compliance{{ $json["Compliance Status"] }}

    • Compliance report{{ $json["Compliance report"] }}

    • Summary{{ $json.Summary }}

    • Chapters{{ $json.Chapters }}

    • Highlights{{ $json.Highlights }}

  4. Matching Column(照合列)videoID に設定します

upsert 操作はスマートです:

  • videoID が存在しない場合 → 新規レコードを作成します

  • videoID がすでに存在する場合 → 既存のレコードを更新します

これは、重複を作成することなく、同じビデオに対してワークフローを再実行できることを意味します!


3.7 - ワークフローのテスト


事前チェックリスト

テストの前に、以下を確認してください:

  • [ ] すべてのノードが順序どおりに接続されていること

  • [ ] TwelveLabsとAWSの認証情報が設定されていること

  • [ ] インデックスIDがTwelveLabsダッシュボードの値と一致していること

  • [ ] TwelveLabsでビデオがインデックス登録されていること

  • [ ] Airtableのベースとテーブルがセットアップされていること

  • [ ] ワークフローが保存されていること


テストを実行する

  1. 右上隅にある "Inactive"(無効) 切り替えスイッチをクリックして、ワークフローをアクティブにします

  2. "Execute Workflow" ボタンをクリックします

  3. 各ノードを通過する実行の流れを確認します

  4. すべてのノードに緑色のチェックマークが表示されていることを確認します(成功を示します)


期待される結果

S3 ノード: メタデータを含むビデオファイルの一覧を返します

Lambda ノード: 各ファイルの署名付きURLを返します

Code ノード: 重複排除されたファイル一覧を返します

TwelveLabs Index ノード: 各アップロードに対して videoId を返します

4つの分析ノード: 分析応答を返します

Merge ノード: 4つすべての分析結果を結合します

Code ノード: 構造化されたデータオブジェクトを返します

Airtable ノード: レコードの作成/更新を確認します


Airtableでの確認

  1. Airtableベースを開きます

  2. 以下を含む新しいレコードを確認できるはずです:

    • ビデオID

    • コンプライアンスステータス(PASS/FAILED/NEEDS REVIEW)

    • それぞれのフィールド内の完全な分析結果


トラブルシューティング

未解決事項

考えられる原因

解決策

S3ノードが失敗する

権限の不足

IAMポリシーに s3:ListBuckets3:GetObject が含まれているか確認します

Lambdaがエラーを返す

関数が見つからないか、ARNが違う

AWSコンソールでLambdaのARNを確認します

TwelveLabsのインデックス登録が失敗する

インデックスIDが無効

TwelveLabsダッシュボードでインデックスIDを再確認します

分析結果がない

ビデオが完全にインデックス登録されていない

インデックス作成が完了するまで待ちます(TwelveLabsを確認)

Airtableが失敗する

フィールドマッピングの不一致

フィールド名が完全に一致していることを確認します(大文字と小文字を区別)

コンプライアンスステータスがテキストとして表示される

選択可能なオプションが設定されていない

選択オプションとしてPASS、FAILED、NEEDS REVIEWを追加します


実行履歴によるデバッグ

何かが失敗した場合:

  1. 左側のサイドバーの "Executions"(実行一覧)に移動します

  2. 最近のテスト実行を見つけます

  3. クリックして展開し、以下を確認します:

    • 各ノードを流れるデータ

    • スタックトレースを伴うエラーメッセージ

    • 各ステップの実行時間

💡プロのヒント:ステップの間に console.log(JSON.stringify($input.all(), null, 2)) を記述した一時的な "Set" または "Code" ノードを追加して、ワークフローの任意のポイントでデータを調査します。

これでS3からメタデータへのワークフローは完了です。ビデオは自動的にインデックス登録され、4つの次元(コンプライアンス、要約、チャプター、ハイライト)で分析され、簡単なアクセスと管理のためにAirtableに保存されます。


4 - n8nとTwelveLabsを使用したビデオセマンティック検索インターフェース


4.1 - ワークフローの概要

このワークフローは、TwelveLabsのマルチモーダルAIを使用した、セマンティックなビデオ検索のためのブランド化されたウェブインターフェースを作成します。


パイプライン アーキテクチャ


完全なワークフローは4つのノードで構成されています:

  1. Form Trigger - ユーザーに検索フォームを表示します

  2. TwelveLabs Search - インデックス化されたビデオ全体に対してセマンティック検索を実行します

  3. Code - JSON形式の結果を視覚的なHTMLグリッドに変換します

  4. Form Completion - フォーマットされた結果をユーザーに表示します


構築されるもの

  • ユーザーが自然言語の検索クエリを入力する、公開ウェブフォーム

  • ビジュアルコンテンツ、音声の文字起こし、画面上のテキストにわたるセマンティック検索

  • サムネイル、タイムスタンプ、文字起こしを含む、上位10件の一致を表示するブランド化された結果ページ

  • ブランドに合わせた、完全にカスタマイズ可能なCSSスタイリング


前提条件

開始する前に、以下があることを確認してください:

  • n8nアカウント(クラウドまたはセルフホスト)

  • APIキーを持つTwelveLabsアカウント

  • ビデオがすでにインデックス登録されているインデックスが少なくとも1つあること

  • 正常に処理されたビデオ(ステータスについてはTwelveLabsダッシュボードを確認)


4.2 - 検索フォームの作成

次に、フォームインターフェースを作成し、カスタムブランディングを適用します。


Form Triggerの設定

  1. n8nで新規ワークフローを作成します

  2. 最初のノードを追加するために "+" をクリックします

  3. "Form Trigger" を検索して選択します

  4. 基本設定を行います:

    • Form Title(フォームタイトル): "Semantic Search with TwelveLabs"(またはお好みのタイトル)

    • Form Description(フォームの説明): ユーザーに向けた任意の指示事項

  5. フォームフィールドを追加します:

    • "Add Field" をクリックします

    • Field Label(フィールドラベル): "Search Query"(検索クエリ)

    • Field Type(フィールドタイプ): Text(テキスト)

    • Required(必須): オン(ON)に切り替えます


カスタムスタイリングの適用

  1. Form Triggerノードで、"Options"(オプション)までスクロールします

  2. "Add Option""Custom CSS" をクリックします

  3. このCSS(紫のアクセントカラーを配したダークテーマ用にカスタマイズ)を貼り付けます:

:root {
    /* Colors - Change these to match your brand */
    --color-background: #0A0B0D;
    --color-card-bg: #141518;
    --color-accent: #8B5CF6;
    --color-text: #FFFFFF;
    --color-text-secondary: #9CA3AF;

    /* Apply colors to form elements */
    --color-header: var(--color-text);
    --color-label: #E5E7EB;
    --color-submit-btn-bg: var(--color-accent);
    --color-submit-btn-text: var(--color-text);
    --color-focus-border: var(--color-accent);

    /* Styling */
    --font-family: 'Inter', 'Open Sans', sans-serif;
    --border-radius-card: 12px;
    --border-radius-input: 8px;
    --container-width: 520px;
}

body {
    background: linear-gradient(135deg, #0A0B0D 0%, #1A1B1F 100%);
    min-height: 100vh;
}

button[type="submit"]:hover {
    background: #7C3AED;
    transform: translateY(-1px);
    box-shadow: 0 4px 12px rgba(139, 92, 246, 0.4);
    transition: all 0.2s ease;
}

input:focus, textarea:focus {
    box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.2);
    transition: box-shadow 0.2s ease;
}


Form Triggerは、検索フォームを表示するユニークなURLを作成します。ワークフローを保存してアクティブ化した後、ノード設定でURLを見つけてください(テスト用のテストURL、共有用の本番URL)。

🎨 カスタマイズする:ブランドに合わせてカラーの16進数値を変更してください。例えば、#8B5CF6(紫)をブランドカラーに置き換えます。


4.3 - 検索と結果の設定


TwelveLabs Searchの接続

  1. Form Triggerノードの "+" をクリックします

  2. "TwelveLabs" を検索して選択します

  3. ノードを設定します:

    • Operation(操作): "Search"(検索)を選択します

    • Index ID(インデックスID): TwelveLabsのインデックスIDを入力します(TwelveLabsダッシュボードで確認できます)

    • Query Text(クエリテキスト): "Add Expression"(式の追加)をクリックし、{{ $json["Search Query"] }} と入力します

  4. まだ設定していない場合は、TwelveLabsのAPI認証情報を追加します


TwelveLabs Searchの仕組み

TwelveLabsは、以下の3つのモダリティにわたって同時にセマンティック検索を実行します:

  • ビジュアル検索 - 物体、人物、アクション、シーン、色、画面上のテキスト(OCR)

  • 音声検索 - 話し言葉、対話、ナレーション、音楽、効果音、感情のトーン

  • 対話型検索 - 視覚+音声のコンテキストを組み合わせたセマンティックな理解

結果は、以下を含むランク付けされたクリップとして返されます:

  • video_id - ソースビデオの識別子

  • start / end - 秒単位のタイムスタンプ範囲

  • rank - 関連性ランク(1 = 最良一致)

  • confidence - AIの信頼度レベル(高/中/低)

  • thumbnail_url - プレビュー動画のURL

  • transcription - クリップ中の発話内容(利用可能な場合)

TwelveLabsは結果の配列を返します。以下はサンプルレスポンスです:

{
  "data": [
    {
      "video_id": "6579a2c1d4b5e8f9a0123456",
      "start": 45.2,
      "end": 52.8,
      "rank": 1,
      "confidence": "high",
      "thumbnail_url": "https://thumbnails.twelvelabs.io/...",
      "transcription": "So let me explain how machine learning works..."
    },
    {
      "video_id": "6579a2c1d4b5e8f9a0789012",
      "start": 120.5,
      "end": 135.0,
      "rank": 2,
      "confidence": "medium",
      "thumbnail_url": "https://thumbnails.twelvelabs.io/...",
      "transcription": "Neural networks are inspired by the human brain..."
    }
  ]
}


結果のHTMLフォーマット

  1. TwelveLabsノードの "+" をクリックします

  2. "Code" を検索して選択します

  3. JavaScript で以下のコードを貼り付けます

const searchData = $input.first().json.data;
const top10 = searchData.filter(result => result.rank <= 10);

let resultsHTML = `
<table style="width: 100%; border-collapse: separate; border-spacing: 20px; margin: 20px 0;">
  <tr>
    <td colspan="4" style="text-align: center; padding-bottom: 20px;">
      <h2 style="color: #8B5CF6; font-size: 28px; margin: 0;">
        Search Results (Top ${top10.length})
      </h2>
    </td>
  </tr>
`;

// Create 4-column grid
for (let i = 0; i < top10.length; i += 4) {
  resultsHTML += '<tr>';
  
  for (let j = 0; j < 4; j++) {
    if (i + j < top10.length) {
      const r = top10[i + j];
      resultsHTML += `
        <td style="width: 25%; vertical-align: top;">
          <div style="background: #141518;
                      border: 1px solid #2A2B30;
                      border-radius: 12px;
                      padding: 16px;
                      box-shadow: 0px 4px 12px rgba(139, 92, 246, 0.1);">
            
            <div style="position: relative; margin-bottom: 12px;">
              <span style="position: absolute;
                          top: 8px;
                          left: 8px;
                          background: #8B5CF6;
                          color: #FFFFFF;
                          padding: 6px 10px;
                          border-radius: 6px;
                          font-size: 14px;
                          font-weight: 600;
                          z-index: 10;">
                #${r.rank}
              </span>
              
              <img src="${r.thumbnail_url}"
                   alt="Result ${r.rank}"
                   style="width: 100%;
                          height: 140px;
                          object-fit: cover;
                          border-radius: 8px;
                          display: block;"/>
            </div>
            
            <div style="color: #FFFFFF; font-size: 13px; margin-bottom: 6px;">
              <strong style="color: #FFFFFF;">Video ID:</strong><br/>
              ${r.video_id.substring(0, 12)}...
            </div>
            
            <div style="color: #E5E7EB; font-size: 12px; margin-bottom: 6px;">
              <strong style="color: #FFFFFF;">Time:</strong>
              ${r.start}s - ${r.end}s
            </div>
            
            ${r.transcription ? `
              <div style="color: #D1D5DB;
                          font-size: 11px;
                          font-style: italic;
                          padding: 8px;
                          background: #1A1B1F;
                          border-radius: 6px;
                          margin-top: 8px;">
                "${r.transcription}"
              </div>
            ` : ''}
            
          </div>
        </td>
      `;
    } else {
      resultsHTML += '<td style="width: 25%;"></td>';
    }
  }
  
  resultsHTML += '</tr>';
}

resultsHTML += '</table>';
return [{ json: { html: resultsHTML } }];

このコードは、上位10件の結果にフィルタし、サムネイル、ランクバッジ、ビデオID、タイムスタンプ、書き起こしを含む4列のHTMLテーブルを構築します。


ユーザーへの結果の表示

  1. Codeノードの "+" をクリックします

  2. "Form" を検索し、通常のFormノードを選択します(Form Triggerではありません)

  3. ノードを設定します:

    • Operation(操作): "Completion"(完了表示)を選択します

    • Completion Title(完了画面のタイトル): "Search Results"(検索結果)

    • Completion Message(完了画面のメッセージ): "Expression"(式)をクリックし、{{ $json.html }} と入力します


結果ページのスタイル設定

結果ページをフォームのブランディングに合わせるために、同じカスタムCSSを追加します:

  1. ノード設定で "Options"(オプション) までスクロールします

  2. "Add Option""Custom CSS" をクリックします

  3. このCSSを貼り付けます:

:root {
    /* Colors */
    --color-background: #0A0B0D;
    --color-card-bg: #141518;
    --color-accent: #8B5CF6;
    --color-text: #FFFFFF;
    --color-html-text: #FFFFFF;

    /* Make the container full-width for better results display */
    --container-width: 100% !important;

    /* Typography */
    --font-family: 'Inter', 'Open Sans', sans-serif;
    --font-size-header: 24px;

    /* Borders */
    --border-radius-card: 12px;
}

body {
    background: linear-gradient(135deg, #0A0B0D 0%, #1A1B1F 100%);
    min-height: 100vh;
    color: #FFFFFF;
}

/* Force container to full width for grid layout */
.container, .form-container, .completion-container {
    max-width: 100% !important;
    width: 100% !important;
}

/* Ensure all text is visible on dark background */
div, p, span, strong, h1, h2, h3 {
    color: inherit !important;
}

Form Completionノードは、検索処理が完了した後、ユーザーにフォーマットされたHTML結果ページを表示します。URLはフォームURLと同じで、n8nは自動的にリダイレクトを処理します。


4.4 - テストとトラブルシューティング


事前チェックリスト

テストの前に、以下の項目を確認してください:

  • [ ] 4つのノードすべてが「Form Trigger → TwelveLabs → Code (Format HTML) → Form (Completion)」の順に接続されていること

  • [ ] TwelveLabsの認証情報が設定されていること

  • [ ] インデックスIDが正しいこと(TwelveLabsダッシュボードの値と一致)

  • [ ] ビデオがインデックス登録されていること(インデックス登録されていないビデオは検索で見つかりません)

  • [ ] ワークフローが保存されていること


有効化とテスト

  1. 右上隅にある "Inactive" 切り替えスイッチをクリックして、ワークフローをアクティブにします

  2. Form Trigger ノードをクリックして、URLを表示します:

    • Test URL - テストに使用します

    • Production URL - エンドユーザーと共有します

  3. テストURLをコピーし、新しいブラウザタブで開きます

  4. インデックス登録されたビデオに関連する検索クエリを入力します(例:「概念を説明する人」)

  5. 送信をクリックし、結果を待ちます(通常、3〜5秒)


期待される動作

✅ カスタムスタイリングを適用してフォームが読み込まれる

✅ 送信後、一時的に読み込み状態が表示される

✅ ビデオのサムネイル付きで結果ページが表示される

✅ 各結果にランク、タイムスタンプ、書き起こし(存在する場合)が表示される


一般的な未解決事項と解決策

未解決事項

考えられる原因

解決策

フォームが読み込まれない

ワークフローがアクティブ化されていない

右上にあるActive(アクティベート)スイッチをONに切り替えます

フォームが読み込まれない

ブラウザのキャッシュ

シークレット/プライベートウィンドウを試します

結果が見つからない

インデックスIDが間違い

TwelveLabsダッシュボードのインデックスIDがノード設定と一致しているか確認します

結果が見つからない

ビデオがインデックス登録されていない

TwelveLabsでインデックス作成ステータスを確認します(ビデオが「Ready」となっている必要があります)

結果が見つからない

クエリが具体的すぎる

ビデオに含まれていることが分かっている、より大まかな検索語を試します

結果に生のJSONテキストが表示される

Expression(式)の切り替えが有効になっていない

Form CompletionのMessage(メッセージ)フィールドで、「Expression」の切り替えをクリックします

結果に {{ $json.html }} がそのまま表示される

Expression(式)の切り替えが有効になっていない

プレーンテキストではなく、必ずExpressionモードを使用する必要があります

スタイリングが崩れる

CSSが両方のノードに適用されていない

Form TriggerとForm Completionの「両方」のノードにカスタムCSSを追加します

結果が表示されるが、サムネイル画像が壊れている

サムネイルURLの期限切れまたは無効

TwelveLabsのAPIレスポンスのチェックをします。サムネイルはアクセス可能である必要があります

誤った検索クエリが処理される

式の誤り

TwelveLabsのQuery Textが {{ $json["Search Query"] }} と正確に記述されているか確認します


実行履歴によるデバッグ

何かが失敗した場合:

  1. 左側のサイドバーの "Executions" に移動します

  2. 最近のテスト実行を見つけます(タイムスタンプとステータスが表示されます)

  3. クリックして展開し、以下を確認します:

    • 各ノードでのインプット/アウトプットデータ

    • スタックトレースを伴うエラーメッセージ

    • ステップごとの実行時間

特定のノードに赤いエラーインジケーターが表示されているか探してください。これによってワークフローがどこで壊れたかが正確に分かります。

💡 デバッグのヒント:TwelveLabsノードと、フォーマットを処理するCodeノードとの間に、一時的に console.log(JSON.stringify($input.all(), null, 2)); return $input.all(); と記述したCodeノードを追加し、生の検索レスポンスを確認します。


サンプルクエリによるテスト

動画コンテンツに基づいて、以下の検索パターンを試してみてください:

もし動画に以下が含まれている場合...

以下を検索してみてください...

うまくいく理由

人が話しているシーン

「カメラに向けて話している人」

映像+音声検出

製品デモ

「使い方の実演」

アクション認識+会話

屋外映像

「屋外の自然シーン」

シーン分類

プレゼンテーション

「図表のあるスライド」

映像検出+OCR

インタビュー

「2人の会話」

人物検出+ダイアログ

チュートリアル

「ステップバイステップのチュートリアル」

セマンティック理解

ブランディング

「画面上のロゴ」

視覚的オブジェクト検出+OCR


完全なワークフローの全体像

以下が、完全なセマンティック検索パイプラインです:


以上で、セマンティック検索インターフェースのワークフロー作成は完了です。ユーザーは自然言語のクエリを使用して動画ライブラリを検索できるようになり、結果はブランド化された視覚的なインターフェースに表示されます。同じフォームURLがリクエストの送信と結果の表示の両方に機能し、n8nが自動的に状態遷移を処理します。


5 - おわりに

統合用のカスタムコードを記述することなく、本番環境に対応可能な2つのビデオAIワークフローを構築しました。最初のワークフローは、S3からのビデオ取り込みを自動化し、並行してAI分析(コンプライアンス、要約、チャプター、ハイライト)を実行し、付加価値の高いメタデータをAirtableに保存します。2つ目のワークフローは、ユーザーが自然言語のクエリを使用してビデオクリップを見つけることができる、公開セマンティック検索インターフェースを構築します。両方のワークフローは、通常、ビデオAIプロジェクトで本番環境への導入を妨げるインフラストラクチャの複雑さを、n8nとTwelveLabsがいかに解消するかを示しています。

ビジュアルインターフェースを介して、TwelveLabs n8n コミュニティノードは、ビデオのマルチモーダルな理解(ビジュアル分析、音声の書き起こし、画面上のテキスト抽出、セマンティック検索)への即時アクセスを提供します。学習するSDKはなく、認証の定型手順もなく、再試行ロジックを構築する必要もありません。既存のツール(S3、Airtable、データベース、MAM、ウェブフック)を接続して、数週間ではなく数時間で機能するビデオAIの実装を完了させましょう。これらのワークフローはスタート地点です。Airtableをご利用のデータベースに変更する、コンプライアンスワークフローに承認フローを追加する、検索結果を既存のアプリケーションに統合するなど、様々なカスタム展開が可能です。

次のステップ:これらのパターンは、ソーシャルメディア用の自動クリップ生成、リアルタイムのコンテンツモデレーション、メタデータを利用したビデオライブラリの移行、またはカスタム推薦エンジンなど、他のユースケースにも拡張できます。TwelveLabs ドキュメントは、追加のAPI機能(埋め込みデータの抽出、カスタムプロンプト)をカバーしており、n8n コミュニティフォーラムには洗練されたワークフローパターンの例があります。技術的なご質問については、TwelveLabs Discord コミュニティに参加していただくか、jordan@twelvelabs.io または brice@twelvelabs.io までお気軽にお問い合わせください。

1 - 概要紹介


1.1 - n8nの概要:技術チーム向けに構築された自動化プラットフォーム

n8nは、ビジュアルなノードベースのインターフェースを通じてアプリケーション、API、サービスを接続するオープンソースのワークフロー自動化プラットフォームです。多くの従来の自動化ツールとは異なり、n8nは開発者や技術チームにデータとロジックの完全な制御権を提供し、セルフホストまたはクラウドでの実行を柔軟に選択できます。

AI駆動のユースケースにおいて、n8nはAIサービスと既存のビジネスシステムとの架け橋となるため、強力な支持を得ています。400以上の構築済みの統合機能とカスタムコードのサポートにより、n8nはインフラをゼロから構築・維持することなく、チームが複雑なAIワークフローを編成できるようにします。

特にビデオAIにおいて、n8nはワークフローの地味ながらも重要な部分、つまりストレージシステム間のメディアの移動、分析ジョブのトリガー、再試行とエラーの処理、モデル出力のパース、そしてMAMやデータベースなどのオペレーショナルツールへの結果のルーティングを適切に処理することに適しています。

AI実装におけるn8nの真の強力さは、複数のステップを連結し、エラー復旧を管理し、異なるフォーマット間でデータを変換する能力にあります。これらすべてを、技術チームが要件の変化に合わせて迅速に反復し適応できるビジュアルインターフェースで行うことができます。


1.2 - TwelveLabs + n8nの理由:ビデオAIのプロダクション導入を加速する

TwelveLabsは、APIを通じて最先端のマルチモーダルビデオ理解を提供しますが、APIを呼び出すことは最初の一歩に過ぎません。実際のビデオワークフローは複雑です。コンテンツはMAMにあり、結果はデータベースに登録する必要があり、コンプライアンスチームは独自のツールを使用し、検索機能は既存のアプリケーション内で動作させる必要があります。

n8nは、TwelveLabsとお客様のシステムの間の接続を制御することでこれを解決します。各プラットフォーム向けにカスタム統合コードを記述する代わりに、n8nでは構築済みのコネクタと柔軟なロジックが提供されるため、ビデオURLをTwelveLabsにプッシュし、戻ってきた結果を処理して、必要な宛先に結果をルーティングすることができます。

これにより、本番環境への導入期間が劇的に短縮されます。TwelveLabsのお客様は、数か月ではなく数日でビデオAIを実際のワークフローに接続できます。それがメディアライブラリのメタデータによる充実化であれ、コンプライアンスレビューの自動化であれ、社内アプリへのセマンティック検索の追加であれ、同様です。


1.3 - 対象読者

このチュートリアルは、既存のツールとシームレスに統合できる実用的な自動化を必要としている、大規模にビデオを扱う技術チームを対象として構築されています。

  • メディア&エンターテインメントのプロフェッショナル(制作、ポストプロダクション、放送):大規模なライブラリにわたるビデオ分析、コンテンツモデレーション、メタデータ強化を自動化します。

  • エンタープライズチーム(社内ビデオ、企業コミュニケーション、マーケティング、トレーニングの管理):検索、整理、コンプライアンスワークフローを向上させます。

  • プラットフォームおよびエンジニアリングチーム(ビデオアプリケーションの構築):AIインフラを管理することなく、セマンティック検索、レコメンデーション、または自動分析を組み込みます。

  • システムインテグレーターおよびソリューションアーキテクト:異なるクライアント環境にわたってビデオAIプロジェクトを効率的に提供します。

  • APIおよびワークフローの実践者(ビジュアルまたはコードベース):必要な柔軟性を備えた、本番環境に対応したビデオAIをスタックに接続します。


2 - 主要な操作

TwelveLabs n8n コミュニティノードは、インデックスの作成やビデオのアップロードから、分析やインサイトの生成に至るまで、完全なビデオAIワークフローを処理する3つのコアリソースグループを提供します。各リソースには、本番のビデオワークフローにおける一般的なタスクに対応する特定の操作が含まれています。


2.1 - Index(インデックス)リソース:検索可能なビデオインデックスの管理

Indexリソースを使用すると、ビデオが保存され処理される基礎となるコンテナを作成および管理できます。

  • Create Index(インデックスの作成) – AIモデルを使用して新しい検索可能なインデックスをセットアップします。インデックスを駆動するモデル(Pegasus PlusまたはMarengo Plus)を選択し、モデル固有のオプションを設定し、ユースケースに必要なアドオンを有効にします。

  • List Indexes(インデックスの一覧取得) – アカウント内のすべてのインデックスを取得して、すでに作成されているものを確認し、複数のプロジェクトや環境を管理します。

  • Search Index by Name(名前によるインデックス検索) – 特定のビデオコレクションやプロジェクトをターゲットとするワークフローを構築する際に役立つ、名前による特定のインデックスの迅速な特定を行います。


2.2 - Video(ビデオ)リソース:インデックス内でのビデオのアップロードと管理

Videoリソースは、コンテンツをインデックスに取り込み、そのステータスを追跡する実務的な作業を処理します。

  • Upload Video(ビデオのアップロード) – 柔軟なインプットオプションを使用してインデックスにビデオを追加します。ビデオファイルを直接アップロードするか、ビデオのURLを提供できます(S3などのクラウドストレージにコンテンツがすでにある場合に便利です)。ビデオはアップロードされると自動的に処理され、インデックスに登録されます。

  • List Videos(ビデオの一覧取得) – 特定のインデックスに保存されているすべてのビデオを取得します。この操作はビデオのメタデータと処理ステータスを返すため、ビデオの分析準備がいつ整うかを把握し、取り込みの進行状況を追跡できます。


2.3 - Analysis(分析)リソース:ビデオからAI駆動のインサイトを生成

Analysisリソースは、インデックス化されたビデオコンテンツから実用的なインテリジェンスを生成します。

  • Generate Summary(要約の生成) – カスタマイズ可能な要約タイプと言い回しを調整できるプロンプトテンプレートを使用して、ビデオコンテンツの簡潔な要約を作成します。長いビデオをすばやく理解したり、メタデータ用の分かりやすい説明を作成したりするのに便利です。

  • Generate Chapters(チャプターの生成) – スマートなチャプター検出機能を使用して、ビデオを自動的にチャプターに分割します。結果にはタイムスタンプ付きのセグメントが含まれるため、長尺コンテンツのナビゲーションや構造化されたアウトラインの作成が容易になります。

  • Generate Highlights(ハイライトの生成) – 重要なシーンを特定して、ビデオから重要な瞬間を抽出します。これを使用して、ハイライトリールやクリップのコンピレーションを作成したり、ビデオライブラリの最も関連性の高い部分を表面化させたりします。


3 - 基本ワークフローのデモ:S3からメタデータへ


3.1 - ワークフローの概要

このワークフローは、S3からビデオを取り込み、TwelveLabsで分析し、充実したメタデータをAirtableに保存するという、エンドツーエンドのビデオAI自動化をデモンストレーションします。


前提条件

開始する前に、以下があることを確認してください:

  • n8nアカウント(クラウドまたはセルフホスト)

  • S3アクセス権を持つAWSアカウント

  • TwelveLabsアカウントとAPIキー

  • Airtableアカウント


パイプライン アーキテクチャ

ワークフローは主に3つのステージで構成されています:

1. TwelveLabsへのインデックス登録

  • S3バケットからビデオファイルを取得する

  • Lambda経由で署名付きURLを生成する

  • 重複するURLを削除する

  • TwelveLabsでビデオをインデックス登録する

2. TwelveLabsでビデオを分析する

  • 4つの分析を並行して実行する:

    • コンプライアンス: プラットフォームポリシー(YouTube ABCDフレームワーク)に照らし合わせてコンテンツをフラグ付けする

    • 要約: 主要なテーマと概要を抽出する

    • チャプター: タイムスタンプ付きのセグメントを生成する

    • ハイライト: 注目すべき瞬間を抽出する

  • 結果をマージし、コンプライアンスステータスを解析する

  • データベース保存用に出力を構造化する

3. 結果の保存

  • タグとメタデータを使用してAirtableにアップサート(挿入または更新)する

  • 本番環境では、通常、結果はMAM、SQL/NoSQLデータベース、またはクラウドデータプラットフォームに送信されます


主要な技術パターン
  • 署名付きURL - AWSの認証情報を公開することなく、プライベートなS3ファイルをTwelveLabsと安全に共有します

  • 並行処理 - 4つの分析タスクを同時に実行し、その後結果をマージします

  • アップサートロジック - Airtableのレコードをインテリジェントに作成または更新します(再実行時に重複が発生しません)

  • ステータス解析 - AIが生成したテキストから構造化されたコンプライアンスステータスを抽出します


3.2 - セットアップ:トリガーとS3接続


ステップ 1: 手動トリガーの作成

  1. n8nを開き、"New Workflow"(新規ワークフロー)をクリックします

  2. "+" ボタンをクリックして、最初のノードを追加します

  3. "Manual Trigger"(手動トリガー)を検索して選択します

手動トリガーは、ワークフローの「スタート」ボタンとして機能します。n8nで「Execute Workflow(ワークフローの実行)」をクリックすると、このノードが起動し、下流のすべてを開始します。

💡 本番環境のヒント:動作が確認できたら、Schedule Trigger(1時間/1日ごとに実行)、Webhook Trigger(別のアプリがリクエストを送信したときに実行)、S3 Trigger(新しいファイルがアップロードされたときに実行)などの自動トリガーに切り替えてください。


ステップ 2: S3からビデオを取得する

  1. 手動トリガーノードの "+" ボタンをクリックします

  2. "AWS S3" を検索して選択します

  3. ノードを設定します:

    • Operation(操作): "Get Many"(複数取得)を選択します

    • Bucket Name(バケット名): バケット名を入力します(例: my-video-bucket

    • Return All(すべて返却): これをオン(ON)に切り替えます

  4. "Credentials"(認証情報)をクリックし、AWSの認証情報を追加します:

    • AWSアクセスキーIDを入力します

    • AWSシークレットアクセスキーを入力します

    • リージョンを選択します

これにより、S3バケット内のすべてのファイルに関するメタデータ(キー(ファイルパス/名)、サイズ、最終更新タイムスタンプ)が取得されます。実際のビデオはダウンロードされず(低速で高コストになるため)、アクセスリンクの生成に必要な情報のみを取得します。

⚠️ 権限のチェック:AWSの認証情報に s3:ListBucket および s3:GetObject の権限があることを確認してください。「Access Denied(アクセス拒否)」が表示される場合は、IAMポリシーを確認してください。


ステップ 3: セキュアなアクセスリンクの生成

TwelveLabsはビデオをダウンロードする必要がありますが、S3バケットは非公開です。署名付きURLがこれを解決します。これらは、AWSの認証情報なしで動作する、一時的で安全なリンク(1時間有効)です。

  1. S3ノードの "+" ボタンをクリックします

  2. "AWS Lambda" を検索して選択します

  3. ノードを設定します:

    • Function(関数): Lambda関数のARNを選択または貼り付けます

    • Payload(ペイロード): "Add Expression"(式の追加)をクリックし、以下を入力します:

{{ JSON.stringify({ 
  bucketName: "your-bucket-name", 
  files: $input.all().map(item => item.json), 
  expiresIn: 3600 
}) }}

Lambda関数は、各ファイルをループ処理し、AWS SDKを使用して署名付きURLを生成し、すべてのURLをn8nに返す必要があります。

💡 なぜLambdaを使用するのですか? n8nは、サーバー側で動作するAWS SDKを必要とするため、署名付きURLを直接生成することはできません。Lambdaがこれを代わりに処理します。


ステップ 4: URLデータのパースとクリーンアップ

  1. Lambdaノードの "+" ボタンをクリックします

  2. "Code" を検索して選択します

  3. このコードを貼り付けます:

// Lambdaのレスポンスをパースし、重複を削除する
const seenKeys = new Set();
const results = [];

for (const item of $input.all()) {
  const response = JSON.parse(item.json.result.body);
  
  for (const file of response.files) {
    if (!seenKeys.has(file.Key)) {
      seenKeys.add(file.Key);
      results.push({
        json: {
          Key: file.Key,
          presignedUrl: file.presignedUrl,
          Size: file.Size,
          LastModified: file.LastModified,
          expiresIn: file.expiresIn
        }
      });
    }
  }
}

return results;

このコードは、Lambda応答(文字列を返す)をデコードし、Setを使用して重複するファイルを削除し、ビデオファイルごとに1つのクリーンなn8nアイテムを作成します。


3.3 - TwelveLabsでのビデオのインデックス登録

ここで、AI処理のために各ビデオをTwelveLabsにアップロードします。

  1. Codeノードの "+" ボタンをクリックします

  2. "TwelveLabs" を検索して選択します

  3. ノードを設定します:

    • Operation(操作): "Upload URL"(URLのアップロード)を選択します

    • Index ID(インデックスID): TwelveLabsのインデックスIDを入力します(これはTwelveLabsのダッシュボードで見つけることができます)

    • Video URL: "Add Expression"(式の追加)をクリックし、{{ $json.presignedUrl }} と入力します

  4. TwelveLabsのAPI認証情報を追加します


インデックス登録される内容

TwelveLabsは、以下の目的で各ビデオを処理します:

  • ビジュアルコンテンツの分析 - 物体、人物、アクション、シーン、色、構図

  • 音声の文字起こし - 話し言葉、対話、ナレーション

  • 画面上のテキストの抽出 - フレームに表示されるテキストのOCR処理

  • 埋め込み(Embeddings)の作成 - セマンティック検索用のベクトル表現

ノードは、後続の分析ステップで使用する videoId を返します。

⏱️ タイミング:インデックス登録には、ビデオの長さに応じて時間がかかります(通常、ビデオ1分あたり1〜3分)。n8nは完了を待ってから次に進みます。


3.4 - 並行分析の設定

分析を順次実行する(遅い)代わりに、時間を節約するために4つの異なる分析を同時に実行します。


並行ブランチのセットアップ

TwelveLabsのインデックス作成ノードから、4つの異なるTwelveLabs Analysisノードに 4つの独立した接続 を作成します:

  1. "Index to TwelveLabs" の出力からクリックしてドラッグします

  2. 最初のTwelveLabs Analysisノードを作成します

  3. 合計4つの分析ノードを作成するために、さらに3回繰り返します


分析タイプの比較

各分析ノードは同じ基本設定を使用しますが、異なるプロンプトを使用します:

1 - コンプライアンス分析

  • 目的: YouTubeのABCDフレームワークに照らしてコンテンツにフラグを立てる

  • 出力フォーマット: ステータス(合格/要レビュー/不合格) + タイムスタンプ付きのフラグが立った未解決事項

コンプライアンス分析プロンプト:

Analyze this video for content compliance using YouTube's ABCD framework:

**A - Adult Content:**
- Nudity or sexual content
- Sexually suggestive content
- Adult themes

**B - Brand Safety:**
- Inflammatory or demeaning content
- Hateful content targeting protected groups
- Harmful or dangerous acts
- Shocking or graphic content
- Profanity and crude language

**C - Copyright:**
- Copyrighted music, video, or images
- Unlicensed third-party content

**D - Dangerous/Harmful:**
- Violence or graphic content
- Drugs, dangerous products, or substances
- Firearms and weapons
- Misinformation (health, elections, etc.)

For each flagged issue, provide:
1. **Timestamp**: When it appears
2. **Category**: A, B, C, or D
3. **Issue**: Brief description
4. **Action**: Allow, Restrict (age-gate), Monetization off, or Remove

**Output:**


2 - 要約分析

  • 目的: 主要なテーマと概要を抽出する

  • 出力フォーマット: ビデオコンテンツに関する3〜4段落の要約

要約分析プロンプト:



3 - チャプター分析

  • 目的: タイムスタンプ付きのセグメントを生成する

  • 出力フォーマット: タイムスタンプと説明を含むチャプタータイトル

チャプター分析プロンプト:



4 - ハイライト分析

  • 目的: 注目すべき瞬間を抽出する

  • 出力フォーマット: タイムスタンプと理由を含む主要なシーン

ハイライト分析プロンプト:



共有ノードの設定

4つの分析ノードそれぞれに、このベース設定を使用します:

  • Operation(操作): "Generate" または "Analysis" を選択します

  • Index ID: {{ $json.indexId }}

  • Video ID: {{ $json.videoId }}

  • Temperature(温度): 0.2 に設定します(低いほど一貫した結果になります)


3.5 - 結果のマージと構造化


並行結果のマージ

  1. "+" をクリックし、"Merge"(マージ)を検索します

  2. ノードを設定します:

    • Number of Inputs(入力数): 4 に設定します

  3. 4つの分析ノードそれぞれを、このMergeノードに接続します:

    • Compliance(コンプライアンス) → Input 1

    • Summary(要約) → Input 2

    • Chapters(チャプター) → Input 3

    • Highlights(ハイライト) → Input 4

Mergeノードはチェックポイントとして機能し、4つの分析ノードすべてが完了するのを待ってから次に進みます。これにより、不完全なデータが保存されるのを防ぎます。


データの構造化

  1. Mergeノードの "+" をクリックし、Code ノードを追加します

  2. このコードを貼り付けます:

// すべて of analysis results を抽出して整理する
const allItems = $input.all();
const videoId = allItems[0]?.json?.videoId || '';
const complianceResponse = allItems[0]?.json?.response || '';

// AIの応答からコンプライアンスステータスを解析する
let complianceStatus = 'NEEDS REVIEW'; // デフォルト

if (complianceResponse.includes('Overall Status: Suitable')) {
  complianceStatus = 'PASS';
} else if (complianceResponse.includes('Overall Status: Not Suitable')) {
  complianceStatus = 'FAILED';
} else if (complianceResponse.includes('Overall Status: Needs Review')) {
  complianceStatus = 'NEEDS REVIEW';
}

// 構造化された出力を生成する
const result = {
  videoID: videoId,
  'Compliance Status': complianceStatus,
  'Compliance report': complianceResponse,
  'Summary': allItems[1]?.json?.response || '',
  'Chapters': allItems[2]?.json?.response || '',
  'Highlights': allItems[3]?.json?.response || ''
};

return [{ json: result }];

このコードは:

  1. 追跡用のビデオIDを抽出します

  2. AIの応答の中から特定のフレーズを探すことでコンプライアンスステータスを解析します

  3. Airtableの選択(Select)フィールドに合わせて、ステータスを正確に3つの値(PASS/FAILED/NEEDS REVIEW)のいずれかに正規化します

  4. 4つの分析結果すべてを単一のフラットなオブジェクトに整理します


3.6 - Airtableへの結果の保存


Airtableベースのセットアップ

  1. 新しいAirtableベースを作成します

  2. これらのフィールドを持つテーブルを作成します:

    • videoID(1行テキスト)

    • Compliance(「PASS」「FAILED」「NEEDS REVIEW」のオプションを持つ単一選択)

    • Compliance report(長いテキスト)

    • Summary(長いテキスト)

    • Chapters(長いテキスト)

    • Highlights(長いテキスト)


Airtableノードの設定

  1. Codeノードの "+" をクリックし、"Airtable" を検索します

  2. ノードを設定します:

    • Operation(操作): "Upsert" を選択します(これによりレコードが作成または更新されます)

    • Base(ベース): Airtableベースを選択します

    • Table(テーブル): テーブルを選択します

  3. フィールドをマッピングします:

    • videoID{{ $json.videoID }}

    • Compliance{{ $json["Compliance Status"] }}

    • Compliance report{{ $json["Compliance report"] }}

    • Summary{{ $json.Summary }}

    • Chapters{{ $json.Chapters }}

    • Highlights{{ $json.Highlights }}

  4. Matching Column(照合列)videoID に設定します

upsert 操作はスマートです:

  • videoID が存在しない場合 → 新規レコードを作成します

  • videoID がすでに存在する場合 → 既存のレコードを更新します

これは、重複を作成することなく、同じビデオに対してワークフローを再実行できることを意味します!


3.7 - ワークフローのテスト


事前チェックリスト

テストの前に、以下を確認してください:

  • [ ] すべてのノードが順序どおりに接続されていること

  • [ ] TwelveLabsとAWSの認証情報が設定されていること

  • [ ] インデックスIDがTwelveLabsダッシュボードの値と一致していること

  • [ ] TwelveLabsでビデオがインデックス登録されていること

  • [ ] Airtableのベースとテーブルがセットアップされていること

  • [ ] ワークフローが保存されていること


テストを実行する

  1. 右上隅にある "Inactive"(無効) 切り替えスイッチをクリックして、ワークフローをアクティブにします

  2. "Execute Workflow" ボタンをクリックします

  3. 各ノードを通過する実行の流れを確認します

  4. すべてのノードに緑色のチェックマークが表示されていることを確認します(成功を示します)


期待される結果

S3 ノード: メタデータを含むビデオファイルの一覧を返します

Lambda ノード: 各ファイルの署名付きURLを返します

Code ノード: 重複排除されたファイル一覧を返します

TwelveLabs Index ノード: 各アップロードに対して videoId を返します

4つの分析ノード: 分析応答を返します

Merge ノード: 4つすべての分析結果を結合します

Code ノード: 構造化されたデータオブジェクトを返します

Airtable ノード: レコードの作成/更新を確認します


Airtableでの確認

  1. Airtableベースを開きます

  2. 以下を含む新しいレコードを確認できるはずです:

    • ビデオID

    • コンプライアンスステータス(PASS/FAILED/NEEDS REVIEW)

    • それぞれのフィールド内の完全な分析結果


トラブルシューティング

未解決事項

考えられる原因

解決策

S3ノードが失敗する

権限の不足

IAMポリシーに s3:ListBuckets3:GetObject が含まれているか確認します

Lambdaがエラーを返す

関数が見つからないか、ARNが違う

AWSコンソールでLambdaのARNを確認します

TwelveLabsのインデックス登録が失敗する

インデックスIDが無効

TwelveLabsダッシュボードでインデックスIDを再確認します

分析結果がない

ビデオが完全にインデックス登録されていない

インデックス作成が完了するまで待ちます(TwelveLabsを確認)

Airtableが失敗する

フィールドマッピングの不一致

フィールド名が完全に一致していることを確認します(大文字と小文字を区別)

コンプライアンスステータスがテキストとして表示される

選択可能なオプションが設定されていない

選択オプションとしてPASS、FAILED、NEEDS REVIEWを追加します


実行履歴によるデバッグ

何かが失敗した場合:

  1. 左側のサイドバーの "Executions"(実行一覧)に移動します

  2. 最近のテスト実行を見つけます

  3. クリックして展開し、以下を確認します:

    • 各ノードを流れるデータ

    • スタックトレースを伴うエラーメッセージ

    • 各ステップの実行時間

💡プロのヒント:ステップの間に console.log(JSON.stringify($input.all(), null, 2)) を記述した一時的な "Set" または "Code" ノードを追加して、ワークフローの任意のポイントでデータを調査します。

これでS3からメタデータへのワークフローは完了です。ビデオは自動的にインデックス登録され、4つの次元(コンプライアンス、要約、チャプター、ハイライト)で分析され、簡単なアクセスと管理のためにAirtableに保存されます。


4 - n8nとTwelveLabsを使用したビデオセマンティック検索インターフェース


4.1 - ワークフローの概要

このワークフローは、TwelveLabsのマルチモーダルAIを使用した、セマンティックなビデオ検索のためのブランド化されたウェブインターフェースを作成します。


パイプライン アーキテクチャ


完全なワークフローは4つのノードで構成されています:

  1. Form Trigger - ユーザーに検索フォームを表示します

  2. TwelveLabs Search - インデックス化されたビデオ全体に対してセマンティック検索を実行します

  3. Code - JSON形式の結果を視覚的なHTMLグリッドに変換します

  4. Form Completion - フォーマットされた結果をユーザーに表示します


構築されるもの

  • ユーザーが自然言語の検索クエリを入力する、公開ウェブフォーム

  • ビジュアルコンテンツ、音声の文字起こし、画面上のテキストにわたるセマンティック検索

  • サムネイル、タイムスタンプ、文字起こしを含む、上位10件の一致を表示するブランド化された結果ページ

  • ブランドに合わせた、完全にカスタマイズ可能なCSSスタイリング


前提条件

開始する前に、以下があることを確認してください:

  • n8nアカウント(クラウドまたはセルフホスト)

  • APIキーを持つTwelveLabsアカウント

  • ビデオがすでにインデックス登録されているインデックスが少なくとも1つあること

  • 正常に処理されたビデオ(ステータスについてはTwelveLabsダッシュボードを確認)


4.2 - 検索フォームの作成

次に、フォームインターフェースを作成し、カスタムブランディングを適用します。


Form Triggerの設定

  1. n8nで新規ワークフローを作成します

  2. 最初のノードを追加するために "+" をクリックします

  3. "Form Trigger" を検索して選択します

  4. 基本設定を行います:

    • Form Title(フォームタイトル): "Semantic Search with TwelveLabs"(またはお好みのタイトル)

    • Form Description(フォームの説明): ユーザーに向けた任意の指示事項

  5. フォームフィールドを追加します:

    • "Add Field" をクリックします

    • Field Label(フィールドラベル): "Search Query"(検索クエリ)

    • Field Type(フィールドタイプ): Text(テキスト)

    • Required(必須): オン(ON)に切り替えます


カスタムスタイリングの適用

  1. Form Triggerノードで、"Options"(オプション)までスクロールします

  2. "Add Option""Custom CSS" をクリックします

  3. このCSS(紫のアクセントカラーを配したダークテーマ用にカスタマイズ)を貼り付けます:

:root {
    /* Colors - Change these to match your brand */
    --color-background: #0A0B0D;
    --color-card-bg: #141518;
    --color-accent: #8B5CF6;
    --color-text: #FFFFFF;
    --color-text-secondary: #9CA3AF;

    /* Apply colors to form elements */
    --color-header: var(--color-text);
    --color-label: #E5E7EB;
    --color-submit-btn-bg: var(--color-accent);
    --color-submit-btn-text: var(--color-text);
    --color-focus-border: var(--color-accent);

    /* Styling */
    --font-family: 'Inter', 'Open Sans', sans-serif;
    --border-radius-card: 12px;
    --border-radius-input: 8px;
    --container-width: 520px;
}

body {
    background: linear-gradient(135deg, #0A0B0D 0%, #1A1B1F 100%);
    min-height: 100vh;
}

button[type="submit"]:hover {
    background: #7C3AED;
    transform: translateY(-1px);
    box-shadow: 0 4px 12px rgba(139, 92, 246, 0.4);
    transition: all 0.2s ease;
}

input:focus, textarea:focus {
    box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.2);
    transition: box-shadow 0.2s ease;
}


Form Triggerは、検索フォームを表示するユニークなURLを作成します。ワークフローを保存してアクティブ化した後、ノード設定でURLを見つけてください(テスト用のテストURL、共有用の本番URL)。

🎨 カスタマイズする:ブランドに合わせてカラーの16進数値を変更してください。例えば、#8B5CF6(紫)をブランドカラーに置き換えます。


4.3 - 検索と結果の設定


TwelveLabs Searchの接続

  1. Form Triggerノードの "+" をクリックします

  2. "TwelveLabs" を検索して選択します

  3. ノードを設定します:

    • Operation(操作): "Search"(検索)を選択します

    • Index ID(インデックスID): TwelveLabsのインデックスIDを入力します(TwelveLabsダッシュボードで確認できます)

    • Query Text(クエリテキスト): "Add Expression"(式の追加)をクリックし、{{ $json["Search Query"] }} と入力します

  4. まだ設定していない場合は、TwelveLabsのAPI認証情報を追加します


TwelveLabs Searchの仕組み

TwelveLabsは、以下の3つのモダリティにわたって同時にセマンティック検索を実行します:

  • ビジュアル検索 - 物体、人物、アクション、シーン、色、画面上のテキスト(OCR)

  • 音声検索 - 話し言葉、対話、ナレーション、音楽、効果音、感情のトーン

  • 対話型検索 - 視覚+音声のコンテキストを組み合わせたセマンティックな理解

結果は、以下を含むランク付けされたクリップとして返されます:

  • video_id - ソースビデオの識別子

  • start / end - 秒単位のタイムスタンプ範囲

  • rank - 関連性ランク(1 = 最良一致)

  • confidence - AIの信頼度レベル(高/中/低)

  • thumbnail_url - プレビュー動画のURL

  • transcription - クリップ中の発話内容(利用可能な場合)

TwelveLabsは結果の配列を返します。以下はサンプルレスポンスです:

{
  "data": [
    {
      "video_id": "6579a2c1d4b5e8f9a0123456",
      "start": 45.2,
      "end": 52.8,
      "rank": 1,
      "confidence": "high",
      "thumbnail_url": "https://thumbnails.twelvelabs.io/...",
      "transcription": "So let me explain how machine learning works..."
    },
    {
      "video_id": "6579a2c1d4b5e8f9a0789012",
      "start": 120.5,
      "end": 135.0,
      "rank": 2,
      "confidence": "medium",
      "thumbnail_url": "https://thumbnails.twelvelabs.io/...",
      "transcription": "Neural networks are inspired by the human brain..."
    }
  ]
}


結果のHTMLフォーマット

  1. TwelveLabsノードの "+" をクリックします

  2. "Code" を検索して選択します

  3. JavaScript で以下のコードを貼り付けます

const searchData = $input.first().json.data;
const top10 = searchData.filter(result => result.rank <= 10);

let resultsHTML = `
<table style="width: 100%; border-collapse: separate; border-spacing: 20px; margin: 20px 0;">
  <tr>
    <td colspan="4" style="text-align: center; padding-bottom: 20px;">
      <h2 style="color: #8B5CF6; font-size: 28px; margin: 0;">
        Search Results (Top ${top10.length})
      </h2>
    </td>
  </tr>
`;

// Create 4-column grid
for (let i = 0; i < top10.length; i += 4) {
  resultsHTML += '<tr>';
  
  for (let j = 0; j < 4; j++) {
    if (i + j < top10.length) {
      const r = top10[i + j];
      resultsHTML += `
        <td style="width: 25%; vertical-align: top;">
          <div style="background: #141518;
                      border: 1px solid #2A2B30;
                      border-radius: 12px;
                      padding: 16px;
                      box-shadow: 0px 4px 12px rgba(139, 92, 246, 0.1);">
            
            <div style="position: relative; margin-bottom: 12px;">
              <span style="position: absolute;
                          top: 8px;
                          left: 8px;
                          background: #8B5CF6;
                          color: #FFFFFF;
                          padding: 6px 10px;
                          border-radius: 6px;
                          font-size: 14px;
                          font-weight: 600;
                          z-index: 10;">
                #${r.rank}
              </span>
              
              <img src="${r.thumbnail_url}"
                   alt="Result ${r.rank}"
                   style="width: 100%;
                          height: 140px;
                          object-fit: cover;
                          border-radius: 8px;
                          display: block;"/>
            </div>
            
            <div style="color: #FFFFFF; font-size: 13px; margin-bottom: 6px;">
              <strong style="color: #FFFFFF;">Video ID:</strong><br/>
              ${r.video_id.substring(0, 12)}...
            </div>
            
            <div style="color: #E5E7EB; font-size: 12px; margin-bottom: 6px;">
              <strong style="color: #FFFFFF;">Time:</strong>
              ${r.start}s - ${r.end}s
            </div>
            
            ${r.transcription ? `
              <div style="color: #D1D5DB;
                          font-size: 11px;
                          font-style: italic;
                          padding: 8px;
                          background: #1A1B1F;
                          border-radius: 6px;
                          margin-top: 8px;">
                "${r.transcription}"
              </div>
            ` : ''}
            
          </div>
        </td>
      `;
    } else {
      resultsHTML += '<td style="width: 25%;"></td>';
    }
  }
  
  resultsHTML += '</tr>';
}

resultsHTML += '</table>';
return [{ json: { html: resultsHTML } }];

このコードは、上位10件の結果にフィルタし、サムネイル、ランクバッジ、ビデオID、タイムスタンプ、書き起こしを含む4列のHTMLテーブルを構築します。


ユーザーへの結果の表示

  1. Codeノードの "+" をクリックします

  2. "Form" を検索し、通常のFormノードを選択します(Form Triggerではありません)

  3. ノードを設定します:

    • Operation(操作): "Completion"(完了表示)を選択します

    • Completion Title(完了画面のタイトル): "Search Results"(検索結果)

    • Completion Message(完了画面のメッセージ): "Expression"(式)をクリックし、{{ $json.html }} と入力します


結果ページのスタイル設定

結果ページをフォームのブランディングに合わせるために、同じカスタムCSSを追加します:

  1. ノード設定で "Options"(オプション) までスクロールします

  2. "Add Option""Custom CSS" をクリックします

  3. このCSSを貼り付けます:

:root {
    /* Colors */
    --color-background: #0A0B0D;
    --color-card-bg: #141518;
    --color-accent: #8B5CF6;
    --color-text: #FFFFFF;
    --color-html-text: #FFFFFF;

    /* Make the container full-width for better results display */
    --container-width: 100% !important;

    /* Typography */
    --font-family: 'Inter', 'Open Sans', sans-serif;
    --font-size-header: 24px;

    /* Borders */
    --border-radius-card: 12px;
}

body {
    background: linear-gradient(135deg, #0A0B0D 0%, #1A1B1F 100%);
    min-height: 100vh;
    color: #FFFFFF;
}

/* Force container to full width for grid layout */
.container, .form-container, .completion-container {
    max-width: 100% !important;
    width: 100% !important;
}

/* Ensure all text is visible on dark background */
div, p, span, strong, h1, h2, h3 {
    color: inherit !important;
}

Form Completionノードは、検索処理が完了した後、ユーザーにフォーマットされたHTML結果ページを表示します。URLはフォームURLと同じで、n8nは自動的にリダイレクトを処理します。


4.4 - テストとトラブルシューティング


事前チェックリスト

テストの前に、以下の項目を確認してください:

  • [ ] 4つのノードすべてが「Form Trigger → TwelveLabs → Code (Format HTML) → Form (Completion)」の順に接続されていること

  • [ ] TwelveLabsの認証情報が設定されていること

  • [ ] インデックスIDが正しいこと(TwelveLabsダッシュボードの値と一致)

  • [ ] ビデオがインデックス登録されていること(インデックス登録されていないビデオは検索で見つかりません)

  • [ ] ワークフローが保存されていること


有効化とテスト

  1. 右上隅にある "Inactive" 切り替えスイッチをクリックして、ワークフローをアクティブにします

  2. Form Trigger ノードをクリックして、URLを表示します:

    • Test URL - テストに使用します

    • Production URL - エンドユーザーと共有します

  3. テストURLをコピーし、新しいブラウザタブで開きます

  4. インデックス登録されたビデオに関連する検索クエリを入力します(例:「概念を説明する人」)

  5. 送信をクリックし、結果を待ちます(通常、3〜5秒)


期待される動作

✅ カスタムスタイリングを適用してフォームが読み込まれる

✅ 送信後、一時的に読み込み状態が表示される

✅ ビデオのサムネイル付きで結果ページが表示される

✅ 各結果にランク、タイムスタンプ、書き起こし(存在する場合)が表示される


一般的な未解決事項と解決策

未解決事項

考えられる原因

解決策

フォームが読み込まれない

ワークフローがアクティブ化されていない

右上にあるActive(アクティベート)スイッチをONに切り替えます

フォームが読み込まれない

ブラウザのキャッシュ

シークレット/プライベートウィンドウを試します

結果が見つからない

インデックスIDが間違い

TwelveLabsダッシュボードのインデックスIDがノード設定と一致しているか確認します

結果が見つからない

ビデオがインデックス登録されていない

TwelveLabsでインデックス作成ステータスを確認します(ビデオが「Ready」となっている必要があります)

結果が見つからない

クエリが具体的すぎる

ビデオに含まれていることが分かっている、より大まかな検索語を試します

結果に生のJSONテキストが表示される

Expression(式)の切り替えが有効になっていない

Form CompletionのMessage(メッセージ)フィールドで、「Expression」の切り替えをクリックします

結果に {{ $json.html }} がそのまま表示される

Expression(式)の切り替えが有効になっていない

プレーンテキストではなく、必ずExpressionモードを使用する必要があります

スタイリングが崩れる

CSSが両方のノードに適用されていない

Form TriggerとForm Completionの「両方」のノードにカスタムCSSを追加します

結果が表示されるが、サムネイル画像が壊れている

サムネイルURLの期限切れまたは無効

TwelveLabsのAPIレスポンスのチェックをします。サムネイルはアクセス可能である必要があります

誤った検索クエリが処理される

式の誤り

TwelveLabsのQuery Textが {{ $json["Search Query"] }} と正確に記述されているか確認します


実行履歴によるデバッグ

何かが失敗した場合:

  1. 左側のサイドバーの "Executions" に移動します

  2. 最近のテスト実行を見つけます(タイムスタンプとステータスが表示されます)

  3. クリックして展開し、以下を確認します:

    • 各ノードでのインプット/アウトプットデータ

    • スタックトレースを伴うエラーメッセージ

    • ステップごとの実行時間

特定のノードに赤いエラーインジケーターが表示されているか探してください。これによってワークフローがどこで壊れたかが正確に分かります。

💡 デバッグのヒント:TwelveLabsノードと、フォーマットを処理するCodeノードとの間に、一時的に console.log(JSON.stringify($input.all(), null, 2)); return $input.all(); と記述したCodeノードを追加し、生の検索レスポンスを確認します。


サンプルクエリによるテスト

動画コンテンツに基づいて、以下の検索パターンを試してみてください:

もし動画に以下が含まれている場合...

以下を検索してみてください...

うまくいく理由

人が話しているシーン

「カメラに向けて話している人」

映像+音声検出

製品デモ

「使い方の実演」

アクション認識+会話

屋外映像

「屋外の自然シーン」

シーン分類

プレゼンテーション

「図表のあるスライド」

映像検出+OCR

インタビュー

「2人の会話」

人物検出+ダイアログ

チュートリアル

「ステップバイステップのチュートリアル」

セマンティック理解

ブランディング

「画面上のロゴ」

視覚的オブジェクト検出+OCR


完全なワークフローの全体像

以下が、完全なセマンティック検索パイプラインです:


以上で、セマンティック検索インターフェースのワークフロー作成は完了です。ユーザーは自然言語のクエリを使用して動画ライブラリを検索できるようになり、結果はブランド化された視覚的なインターフェースに表示されます。同じフォームURLがリクエストの送信と結果の表示の両方に機能し、n8nが自動的に状態遷移を処理します。


5 - おわりに

統合用のカスタムコードを記述することなく、本番環境に対応可能な2つのビデオAIワークフローを構築しました。最初のワークフローは、S3からのビデオ取り込みを自動化し、並行してAI分析(コンプライアンス、要約、チャプター、ハイライト)を実行し、付加価値の高いメタデータをAirtableに保存します。2つ目のワークフローは、ユーザーが自然言語のクエリを使用してビデオクリップを見つけることができる、公開セマンティック検索インターフェースを構築します。両方のワークフローは、通常、ビデオAIプロジェクトで本番環境への導入を妨げるインフラストラクチャの複雑さを、n8nとTwelveLabsがいかに解消するかを示しています。

ビジュアルインターフェースを介して、TwelveLabs n8n コミュニティノードは、ビデオのマルチモーダルな理解(ビジュアル分析、音声の書き起こし、画面上のテキスト抽出、セマンティック検索)への即時アクセスを提供します。学習するSDKはなく、認証の定型手順もなく、再試行ロジックを構築する必要もありません。既存のツール(S3、Airtable、データベース、MAM、ウェブフック)を接続して、数週間ではなく数時間で機能するビデオAIの実装を完了させましょう。これらのワークフローはスタート地点です。Airtableをご利用のデータベースに変更する、コンプライアンスワークフローに承認フローを追加する、検索結果を既存のアプリケーションに統合するなど、様々なカスタム展開が可能です。

次のステップ:これらのパターンは、ソーシャルメディア用の自動クリップ生成、リアルタイムのコンテンツモデレーション、メタデータを利用したビデオライブラリの移行、またはカスタム推薦エンジンなど、他のユースケースにも拡張できます。TwelveLabs ドキュメントは、追加のAPI機能(埋め込みデータの抽出、カスタムプロンプト)をカバーしており、n8n コミュニティフォーラムには洗練されたワークフローパターンの例があります。技術的なご質問については、TwelveLabs Discord コミュニティに参加していただくか、jordan@twelvelabs.io または brice@twelvelabs.io までお気軽にお問い合わせください。

1 - 概要紹介


1.1 - n8nの概要:技術チーム向けに構築された自動化プラットフォーム

n8nは、ビジュアルなノードベースのインターフェースを通じてアプリケーション、API、サービスを接続するオープンソースのワークフロー自動化プラットフォームです。多くの従来の自動化ツールとは異なり、n8nは開発者や技術チームにデータとロジックの完全な制御権を提供し、セルフホストまたはクラウドでの実行を柔軟に選択できます。

AI駆動のユースケースにおいて、n8nはAIサービスと既存のビジネスシステムとの架け橋となるため、強力な支持を得ています。400以上の構築済みの統合機能とカスタムコードのサポートにより、n8nはインフラをゼロから構築・維持することなく、チームが複雑なAIワークフローを編成できるようにします。

特にビデオAIにおいて、n8nはワークフローの地味ながらも重要な部分、つまりストレージシステム間のメディアの移動、分析ジョブのトリガー、再試行とエラーの処理、モデル出力のパース、そしてMAMやデータベースなどのオペレーショナルツールへの結果のルーティングを適切に処理することに適しています。

AI実装におけるn8nの真の強力さは、複数のステップを連結し、エラー復旧を管理し、異なるフォーマット間でデータを変換する能力にあります。これらすべてを、技術チームが要件の変化に合わせて迅速に反復し適応できるビジュアルインターフェースで行うことができます。


1.2 - TwelveLabs + n8nの理由:ビデオAIのプロダクション導入を加速する

TwelveLabsは、APIを通じて最先端のマルチモーダルビデオ理解を提供しますが、APIを呼び出すことは最初の一歩に過ぎません。実際のビデオワークフローは複雑です。コンテンツはMAMにあり、結果はデータベースに登録する必要があり、コンプライアンスチームは独自のツールを使用し、検索機能は既存のアプリケーション内で動作させる必要があります。

n8nは、TwelveLabsとお客様のシステムの間の接続を制御することでこれを解決します。各プラットフォーム向けにカスタム統合コードを記述する代わりに、n8nでは構築済みのコネクタと柔軟なロジックが提供されるため、ビデオURLをTwelveLabsにプッシュし、戻ってきた結果を処理して、必要な宛先に結果をルーティングすることができます。

これにより、本番環境への導入期間が劇的に短縮されます。TwelveLabsのお客様は、数か月ではなく数日でビデオAIを実際のワークフローに接続できます。それがメディアライブラリのメタデータによる充実化であれ、コンプライアンスレビューの自動化であれ、社内アプリへのセマンティック検索の追加であれ、同様です。


1.3 - 対象読者

このチュートリアルは、既存のツールとシームレスに統合できる実用的な自動化を必要としている、大規模にビデオを扱う技術チームを対象として構築されています。

  • メディア&エンターテインメントのプロフェッショナル(制作、ポストプロダクション、放送):大規模なライブラリにわたるビデオ分析、コンテンツモデレーション、メタデータ強化を自動化します。

  • エンタープライズチーム(社内ビデオ、企業コミュニケーション、マーケティング、トレーニングの管理):検索、整理、コンプライアンスワークフローを向上させます。

  • プラットフォームおよびエンジニアリングチーム(ビデオアプリケーションの構築):AIインフラを管理することなく、セマンティック検索、レコメンデーション、または自動分析を組み込みます。

  • システムインテグレーターおよびソリューションアーキテクト:異なるクライアント環境にわたってビデオAIプロジェクトを効率的に提供します。

  • APIおよびワークフローの実践者(ビジュアルまたはコードベース):必要な柔軟性を備えた、本番環境に対応したビデオAIをスタックに接続します。


2 - 主要な操作

TwelveLabs n8n コミュニティノードは、インデックスの作成やビデオのアップロードから、分析やインサイトの生成に至るまで、完全なビデオAIワークフローを処理する3つのコアリソースグループを提供します。各リソースには、本番のビデオワークフローにおける一般的なタスクに対応する特定の操作が含まれています。


2.1 - Index(インデックス)リソース:検索可能なビデオインデックスの管理

Indexリソースを使用すると、ビデオが保存され処理される基礎となるコンテナを作成および管理できます。

  • Create Index(インデックスの作成) – AIモデルを使用して新しい検索可能なインデックスをセットアップします。インデックスを駆動するモデル(Pegasus PlusまたはMarengo Plus)を選択し、モデル固有のオプションを設定し、ユースケースに必要なアドオンを有効にします。

  • List Indexes(インデックスの一覧取得) – アカウント内のすべてのインデックスを取得して、すでに作成されているものを確認し、複数のプロジェクトや環境を管理します。

  • Search Index by Name(名前によるインデックス検索) – 特定のビデオコレクションやプロジェクトをターゲットとするワークフローを構築する際に役立つ、名前による特定のインデックスの迅速な特定を行います。


2.2 - Video(ビデオ)リソース:インデックス内でのビデオのアップロードと管理

Videoリソースは、コンテンツをインデックスに取り込み、そのステータスを追跡する実務的な作業を処理します。

  • Upload Video(ビデオのアップロード) – 柔軟なインプットオプションを使用してインデックスにビデオを追加します。ビデオファイルを直接アップロードするか、ビデオのURLを提供できます(S3などのクラウドストレージにコンテンツがすでにある場合に便利です)。ビデオはアップロードされると自動的に処理され、インデックスに登録されます。

  • List Videos(ビデオの一覧取得) – 特定のインデックスに保存されているすべてのビデオを取得します。この操作はビデオのメタデータと処理ステータスを返すため、ビデオの分析準備がいつ整うかを把握し、取り込みの進行状況を追跡できます。


2.3 - Analysis(分析)リソース:ビデオからAI駆動のインサイトを生成

Analysisリソースは、インデックス化されたビデオコンテンツから実用的なインテリジェンスを生成します。

  • Generate Summary(要約の生成) – カスタマイズ可能な要約タイプと言い回しを調整できるプロンプトテンプレートを使用して、ビデオコンテンツの簡潔な要約を作成します。長いビデオをすばやく理解したり、メタデータ用の分かりやすい説明を作成したりするのに便利です。

  • Generate Chapters(チャプターの生成) – スマートなチャプター検出機能を使用して、ビデオを自動的にチャプターに分割します。結果にはタイムスタンプ付きのセグメントが含まれるため、長尺コンテンツのナビゲーションや構造化されたアウトラインの作成が容易になります。

  • Generate Highlights(ハイライトの生成) – 重要なシーンを特定して、ビデオから重要な瞬間を抽出します。これを使用して、ハイライトリールやクリップのコンピレーションを作成したり、ビデオライブラリの最も関連性の高い部分を表面化させたりします。


3 - 基本ワークフローのデモ:S3からメタデータへ


3.1 - ワークフローの概要

このワークフローは、S3からビデオを取り込み、TwelveLabsで分析し、充実したメタデータをAirtableに保存するという、エンドツーエンドのビデオAI自動化をデモンストレーションします。


前提条件

開始する前に、以下があることを確認してください:

  • n8nアカウント(クラウドまたはセルフホスト)

  • S3アクセス権を持つAWSアカウント

  • TwelveLabsアカウントとAPIキー

  • Airtableアカウント


パイプライン アーキテクチャ

ワークフローは主に3つのステージで構成されています:

1. TwelveLabsへのインデックス登録

  • S3バケットからビデオファイルを取得する

  • Lambda経由で署名付きURLを生成する

  • 重複するURLを削除する

  • TwelveLabsでビデオをインデックス登録する

2. TwelveLabsでビデオを分析する

  • 4つの分析を並行して実行する:

    • コンプライアンス: プラットフォームポリシー(YouTube ABCDフレームワーク)に照らし合わせてコンテンツをフラグ付けする

    • 要約: 主要なテーマと概要を抽出する

    • チャプター: タイムスタンプ付きのセグメントを生成する

    • ハイライト: 注目すべき瞬間を抽出する

  • 結果をマージし、コンプライアンスステータスを解析する

  • データベース保存用に出力を構造化する

3. 結果の保存

  • タグとメタデータを使用してAirtableにアップサート(挿入または更新)する

  • 本番環境では、通常、結果はMAM、SQL/NoSQLデータベース、またはクラウドデータプラットフォームに送信されます


主要な技術パターン
  • 署名付きURL - AWSの認証情報を公開することなく、プライベートなS3ファイルをTwelveLabsと安全に共有します

  • 並行処理 - 4つの分析タスクを同時に実行し、その後結果をマージします

  • アップサートロジック - Airtableのレコードをインテリジェントに作成または更新します(再実行時に重複が発生しません)

  • ステータス解析 - AIが生成したテキストから構造化されたコンプライアンスステータスを抽出します


3.2 - セットアップ:トリガーとS3接続


ステップ 1: 手動トリガーの作成

  1. n8nを開き、"New Workflow"(新規ワークフロー)をクリックします

  2. "+" ボタンをクリックして、最初のノードを追加します

  3. "Manual Trigger"(手動トリガー)を検索して選択します

手動トリガーは、ワークフローの「スタート」ボタンとして機能します。n8nで「Execute Workflow(ワークフローの実行)」をクリックすると、このノードが起動し、下流のすべてを開始します。

💡 本番環境のヒント:動作が確認できたら、Schedule Trigger(1時間/1日ごとに実行)、Webhook Trigger(別のアプリがリクエストを送信したときに実行)、S3 Trigger(新しいファイルがアップロードされたときに実行)などの自動トリガーに切り替えてください。


ステップ 2: S3からビデオを取得する

  1. 手動トリガーノードの "+" ボタンをクリックします

  2. "AWS S3" を検索して選択します

  3. ノードを設定します:

    • Operation(操作): "Get Many"(複数取得)を選択します

    • Bucket Name(バケット名): バケット名を入力します(例: my-video-bucket

    • Return All(すべて返却): これをオン(ON)に切り替えます

  4. "Credentials"(認証情報)をクリックし、AWSの認証情報を追加します:

    • AWSアクセスキーIDを入力します

    • AWSシークレットアクセスキーを入力します

    • リージョンを選択します

これにより、S3バケット内のすべてのファイルに関するメタデータ(キー(ファイルパス/名)、サイズ、最終更新タイムスタンプ)が取得されます。実際のビデオはダウンロードされず(低速で高コストになるため)、アクセスリンクの生成に必要な情報のみを取得します。

⚠️ 権限のチェック:AWSの認証情報に s3:ListBucket および s3:GetObject の権限があることを確認してください。「Access Denied(アクセス拒否)」が表示される場合は、IAMポリシーを確認してください。


ステップ 3: セキュアなアクセスリンクの生成

TwelveLabsはビデオをダウンロードする必要がありますが、S3バケットは非公開です。署名付きURLがこれを解決します。これらは、AWSの認証情報なしで動作する、一時的で安全なリンク(1時間有効)です。

  1. S3ノードの "+" ボタンをクリックします

  2. "AWS Lambda" を検索して選択します

  3. ノードを設定します:

    • Function(関数): Lambda関数のARNを選択または貼り付けます

    • Payload(ペイロード): "Add Expression"(式の追加)をクリックし、以下を入力します:

{{ JSON.stringify({ 
  bucketName: "your-bucket-name", 
  files: $input.all().map(item => item.json), 
  expiresIn: 3600 
}) }}

Lambda関数は、各ファイルをループ処理し、AWS SDKを使用して署名付きURLを生成し、すべてのURLをn8nに返す必要があります。

💡 なぜLambdaを使用するのですか? n8nは、サーバー側で動作するAWS SDKを必要とするため、署名付きURLを直接生成することはできません。Lambdaがこれを代わりに処理します。


ステップ 4: URLデータのパースとクリーンアップ

  1. Lambdaノードの "+" ボタンをクリックします

  2. "Code" を検索して選択します

  3. このコードを貼り付けます:

// Lambdaのレスポンスをパースし、重複を削除する
const seenKeys = new Set();
const results = [];

for (const item of $input.all()) {
  const response = JSON.parse(item.json.result.body);
  
  for (const file of response.files) {
    if (!seenKeys.has(file.Key)) {
      seenKeys.add(file.Key);
      results.push({
        json: {
          Key: file.Key,
          presignedUrl: file.presignedUrl,
          Size: file.Size,
          LastModified: file.LastModified,
          expiresIn: file.expiresIn
        }
      });
    }
  }
}

return results;

このコードは、Lambda応答(文字列を返す)をデコードし、Setを使用して重複するファイルを削除し、ビデオファイルごとに1つのクリーンなn8nアイテムを作成します。


3.3 - TwelveLabsでのビデオのインデックス登録

ここで、AI処理のために各ビデオをTwelveLabsにアップロードします。

  1. Codeノードの "+" ボタンをクリックします

  2. "TwelveLabs" を検索して選択します

  3. ノードを設定します:

    • Operation(操作): "Upload URL"(URLのアップロード)を選択します

    • Index ID(インデックスID): TwelveLabsのインデックスIDを入力します(これはTwelveLabsのダッシュボードで見つけることができます)

    • Video URL: "Add Expression"(式の追加)をクリックし、{{ $json.presignedUrl }} と入力します

  4. TwelveLabsのAPI認証情報を追加します


インデックス登録される内容

TwelveLabsは、以下の目的で各ビデオを処理します:

  • ビジュアルコンテンツの分析 - 物体、人物、アクション、シーン、色、構図

  • 音声の文字起こし - 話し言葉、対話、ナレーション

  • 画面上のテキストの抽出 - フレームに表示されるテキストのOCR処理

  • 埋め込み(Embeddings)の作成 - セマンティック検索用のベクトル表現

ノードは、後続の分析ステップで使用する videoId を返します。

⏱️ タイミング:インデックス登録には、ビデオの長さに応じて時間がかかります(通常、ビデオ1分あたり1〜3分)。n8nは完了を待ってから次に進みます。


3.4 - 並行分析の設定

分析を順次実行する(遅い)代わりに、時間を節約するために4つの異なる分析を同時に実行します。


並行ブランチのセットアップ

TwelveLabsのインデックス作成ノードから、4つの異なるTwelveLabs Analysisノードに 4つの独立した接続 を作成します:

  1. "Index to TwelveLabs" の出力からクリックしてドラッグします

  2. 最初のTwelveLabs Analysisノードを作成します

  3. 合計4つの分析ノードを作成するために、さらに3回繰り返します


分析タイプの比較

各分析ノードは同じ基本設定を使用しますが、異なるプロンプトを使用します:

1 - コンプライアンス分析

  • 目的: YouTubeのABCDフレームワークに照らしてコンテンツにフラグを立てる

  • 出力フォーマット: ステータス(合格/要レビュー/不合格) + タイムスタンプ付きのフラグが立った未解決事項

コンプライアンス分析プロンプト:

Analyze this video for content compliance using YouTube's ABCD framework:

**A - Adult Content:**
- Nudity or sexual content
- Sexually suggestive content
- Adult themes

**B - Brand Safety:**
- Inflammatory or demeaning content
- Hateful content targeting protected groups
- Harmful or dangerous acts
- Shocking or graphic content
- Profanity and crude language

**C - Copyright:**
- Copyrighted music, video, or images
- Unlicensed third-party content

**D - Dangerous/Harmful:**
- Violence or graphic content
- Drugs, dangerous products, or substances
- Firearms and weapons
- Misinformation (health, elections, etc.)

For each flagged issue, provide:
1. **Timestamp**: When it appears
2. **Category**: A, B, C, or D
3. **Issue**: Brief description
4. **Action**: Allow, Restrict (age-gate), Monetization off, or Remove

**Output:**


2 - 要約分析

  • 目的: 主要なテーマと概要を抽出する

  • 出力フォーマット: ビデオコンテンツに関する3〜4段落の要約

要約分析プロンプト:



3 - チャプター分析

  • 目的: タイムスタンプ付きのセグメントを生成する

  • 出力フォーマット: タイムスタンプと説明を含むチャプタータイトル

チャプター分析プロンプト:



4 - ハイライト分析

  • 目的: 注目すべき瞬間を抽出する

  • 出力フォーマット: タイムスタンプと理由を含む主要なシーン

ハイライト分析プロンプト:



共有ノードの設定

4つの分析ノードそれぞれに、このベース設定を使用します:

  • Operation(操作): "Generate" または "Analysis" を選択します

  • Index ID: {{ $json.indexId }}

  • Video ID: {{ $json.videoId }}

  • Temperature(温度): 0.2 に設定します(低いほど一貫した結果になります)


3.5 - 結果のマージと構造化


並行結果のマージ

  1. "+" をクリックし、"Merge"(マージ)を検索します

  2. ノードを設定します:

    • Number of Inputs(入力数): 4 に設定します

  3. 4つの分析ノードそれぞれを、このMergeノードに接続します:

    • Compliance(コンプライアンス) → Input 1

    • Summary(要約) → Input 2

    • Chapters(チャプター) → Input 3

    • Highlights(ハイライト) → Input 4

Mergeノードはチェックポイントとして機能し、4つの分析ノードすべてが完了するのを待ってから次に進みます。これにより、不完全なデータが保存されるのを防ぎます。


データの構造化

  1. Mergeノードの "+" をクリックし、Code ノードを追加します

  2. このコードを貼り付けます:

// すべて of analysis results を抽出して整理する
const allItems = $input.all();
const videoId = allItems[0]?.json?.videoId || '';
const complianceResponse = allItems[0]?.json?.response || '';

// AIの応答からコンプライアンスステータスを解析する
let complianceStatus = 'NEEDS REVIEW'; // デフォルト

if (complianceResponse.includes('Overall Status: Suitable')) {
  complianceStatus = 'PASS';
} else if (complianceResponse.includes('Overall Status: Not Suitable')) {
  complianceStatus = 'FAILED';
} else if (complianceResponse.includes('Overall Status: Needs Review')) {
  complianceStatus = 'NEEDS REVIEW';
}

// 構造化された出力を生成する
const result = {
  videoID: videoId,
  'Compliance Status': complianceStatus,
  'Compliance report': complianceResponse,
  'Summary': allItems[1]?.json?.response || '',
  'Chapters': allItems[2]?.json?.response || '',
  'Highlights': allItems[3]?.json?.response || ''
};

return [{ json: result }];

このコードは:

  1. 追跡用のビデオIDを抽出します

  2. AIの応答の中から特定のフレーズを探すことでコンプライアンスステータスを解析します

  3. Airtableの選択(Select)フィールドに合わせて、ステータスを正確に3つの値(PASS/FAILED/NEEDS REVIEW)のいずれかに正規化します

  4. 4つの分析結果すべてを単一のフラットなオブジェクトに整理します


3.6 - Airtableへの結果の保存


Airtableベースのセットアップ

  1. 新しいAirtableベースを作成します

  2. これらのフィールドを持つテーブルを作成します:

    • videoID(1行テキスト)

    • Compliance(「PASS」「FAILED」「NEEDS REVIEW」のオプションを持つ単一選択)

    • Compliance report(長いテキスト)

    • Summary(長いテキスト)

    • Chapters(長いテキスト)

    • Highlights(長いテキスト)


Airtableノードの設定

  1. Codeノードの "+" をクリックし、"Airtable" を検索します

  2. ノードを設定します:

    • Operation(操作): "Upsert" を選択します(これによりレコードが作成または更新されます)

    • Base(ベース): Airtableベースを選択します

    • Table(テーブル): テーブルを選択します

  3. フィールドをマッピングします:

    • videoID{{ $json.videoID }}

    • Compliance{{ $json["Compliance Status"] }}

    • Compliance report{{ $json["Compliance report"] }}

    • Summary{{ $json.Summary }}

    • Chapters{{ $json.Chapters }}

    • Highlights{{ $json.Highlights }}

  4. Matching Column(照合列)videoID に設定します

upsert 操作はスマートです:

  • videoID が存在しない場合 → 新規レコードを作成します

  • videoID がすでに存在する場合 → 既存のレコードを更新します

これは、重複を作成することなく、同じビデオに対してワークフローを再実行できることを意味します!


3.7 - ワークフローのテスト


事前チェックリスト

テストの前に、以下を確認してください:

  • [ ] すべてのノードが順序どおりに接続されていること

  • [ ] TwelveLabsとAWSの認証情報が設定されていること

  • [ ] インデックスIDがTwelveLabsダッシュボードの値と一致していること

  • [ ] TwelveLabsでビデオがインデックス登録されていること

  • [ ] Airtableのベースとテーブルがセットアップされていること

  • [ ] ワークフローが保存されていること


テストを実行する

  1. 右上隅にある "Inactive"(無効) 切り替えスイッチをクリックして、ワークフローをアクティブにします

  2. "Execute Workflow" ボタンをクリックします

  3. 各ノードを通過する実行の流れを確認します

  4. すべてのノードに緑色のチェックマークが表示されていることを確認します(成功を示します)


期待される結果

S3 ノード: メタデータを含むビデオファイルの一覧を返します

Lambda ノード: 各ファイルの署名付きURLを返します

Code ノード: 重複排除されたファイル一覧を返します

TwelveLabs Index ノード: 各アップロードに対して videoId を返します

4つの分析ノード: 分析応答を返します

Merge ノード: 4つすべての分析結果を結合します

Code ノード: 構造化されたデータオブジェクトを返します

Airtable ノード: レコードの作成/更新を確認します


Airtableでの確認

  1. Airtableベースを開きます

  2. 以下を含む新しいレコードを確認できるはずです:

    • ビデオID

    • コンプライアンスステータス(PASS/FAILED/NEEDS REVIEW)

    • それぞれのフィールド内の完全な分析結果


トラブルシューティング

未解決事項

考えられる原因

解決策

S3ノードが失敗する

権限の不足

IAMポリシーに s3:ListBuckets3:GetObject が含まれているか確認します

Lambdaがエラーを返す

関数が見つからないか、ARNが違う

AWSコンソールでLambdaのARNを確認します

TwelveLabsのインデックス登録が失敗する

インデックスIDが無効

TwelveLabsダッシュボードでインデックスIDを再確認します

分析結果がない

ビデオが完全にインデックス登録されていない

インデックス作成が完了するまで待ちます(TwelveLabsを確認)

Airtableが失敗する

フィールドマッピングの不一致

フィールド名が完全に一致していることを確認します(大文字と小文字を区別)

コンプライアンスステータスがテキストとして表示される

選択可能なオプションが設定されていない

選択オプションとしてPASS、FAILED、NEEDS REVIEWを追加します


実行履歴によるデバッグ

何かが失敗した場合:

  1. 左側のサイドバーの "Executions"(実行一覧)に移動します

  2. 最近のテスト実行を見つけます

  3. クリックして展開し、以下を確認します:

    • 各ノードを流れるデータ

    • スタックトレースを伴うエラーメッセージ

    • 各ステップの実行時間

💡プロのヒント:ステップの間に console.log(JSON.stringify($input.all(), null, 2)) を記述した一時的な "Set" または "Code" ノードを追加して、ワークフローの任意のポイントでデータを調査します。

これでS3からメタデータへのワークフローは完了です。ビデオは自動的にインデックス登録され、4つの次元(コンプライアンス、要約、チャプター、ハイライト)で分析され、簡単なアクセスと管理のためにAirtableに保存されます。


4 - n8nとTwelveLabsを使用したビデオセマンティック検索インターフェース


4.1 - ワークフローの概要

このワークフローは、TwelveLabsのマルチモーダルAIを使用した、セマンティックなビデオ検索のためのブランド化されたウェブインターフェースを作成します。


パイプライン アーキテクチャ


完全なワークフローは4つのノードで構成されています:

  1. Form Trigger - ユーザーに検索フォームを表示します

  2. TwelveLabs Search - インデックス化されたビデオ全体に対してセマンティック検索を実行します

  3. Code - JSON形式の結果を視覚的なHTMLグリッドに変換します

  4. Form Completion - フォーマットされた結果をユーザーに表示します


構築されるもの

  • ユーザーが自然言語の検索クエリを入力する、公開ウェブフォーム

  • ビジュアルコンテンツ、音声の文字起こし、画面上のテキストにわたるセマンティック検索

  • サムネイル、タイムスタンプ、文字起こしを含む、上位10件の一致を表示するブランド化された結果ページ

  • ブランドに合わせた、完全にカスタマイズ可能なCSSスタイリング


前提条件

開始する前に、以下があることを確認してください:

  • n8nアカウント(クラウドまたはセルフホスト)

  • APIキーを持つTwelveLabsアカウント

  • ビデオがすでにインデックス登録されているインデックスが少なくとも1つあること

  • 正常に処理されたビデオ(ステータスについてはTwelveLabsダッシュボードを確認)


4.2 - 検索フォームの作成

次に、フォームインターフェースを作成し、カスタムブランディングを適用します。


Form Triggerの設定

  1. n8nで新規ワークフローを作成します

  2. 最初のノードを追加するために "+" をクリックします

  3. "Form Trigger" を検索して選択します

  4. 基本設定を行います:

    • Form Title(フォームタイトル): "Semantic Search with TwelveLabs"(またはお好みのタイトル)

    • Form Description(フォームの説明): ユーザーに向けた任意の指示事項

  5. フォームフィールドを追加します:

    • "Add Field" をクリックします

    • Field Label(フィールドラベル): "Search Query"(検索クエリ)

    • Field Type(フィールドタイプ): Text(テキスト)

    • Required(必須): オン(ON)に切り替えます


カスタムスタイリングの適用

  1. Form Triggerノードで、"Options"(オプション)までスクロールします

  2. "Add Option""Custom CSS" をクリックします

  3. このCSS(紫のアクセントカラーを配したダークテーマ用にカスタマイズ)を貼り付けます:

:root {
    /* Colors - Change these to match your brand */
    --color-background: #0A0B0D;
    --color-card-bg: #141518;
    --color-accent: #8B5CF6;
    --color-text: #FFFFFF;
    --color-text-secondary: #9CA3AF;

    /* Apply colors to form elements */
    --color-header: var(--color-text);
    --color-label: #E5E7EB;
    --color-submit-btn-bg: var(--color-accent);
    --color-submit-btn-text: var(--color-text);
    --color-focus-border: var(--color-accent);

    /* Styling */
    --font-family: 'Inter', 'Open Sans', sans-serif;
    --border-radius-card: 12px;
    --border-radius-input: 8px;
    --container-width: 520px;
}

body {
    background: linear-gradient(135deg, #0A0B0D 0%, #1A1B1F 100%);
    min-height: 100vh;
}

button[type="submit"]:hover {
    background: #7C3AED;
    transform: translateY(-1px);
    box-shadow: 0 4px 12px rgba(139, 92, 246, 0.4);
    transition: all 0.2s ease;
}

input:focus, textarea:focus {
    box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.2);
    transition: box-shadow 0.2s ease;
}


Form Triggerは、検索フォームを表示するユニークなURLを作成します。ワークフローを保存してアクティブ化した後、ノード設定でURLを見つけてください(テスト用のテストURL、共有用の本番URL)。

🎨 カスタマイズする:ブランドに合わせてカラーの16進数値を変更してください。例えば、#8B5CF6(紫)をブランドカラーに置き換えます。


4.3 - 検索と結果の設定


TwelveLabs Searchの接続

  1. Form Triggerノードの "+" をクリックします

  2. "TwelveLabs" を検索して選択します

  3. ノードを設定します:

    • Operation(操作): "Search"(検索)を選択します

    • Index ID(インデックスID): TwelveLabsのインデックスIDを入力します(TwelveLabsダッシュボードで確認できます)

    • Query Text(クエリテキスト): "Add Expression"(式の追加)をクリックし、{{ $json["Search Query"] }} と入力します

  4. まだ設定していない場合は、TwelveLabsのAPI認証情報を追加します


TwelveLabs Searchの仕組み

TwelveLabsは、以下の3つのモダリティにわたって同時にセマンティック検索を実行します:

  • ビジュアル検索 - 物体、人物、アクション、シーン、色、画面上のテキスト(OCR)

  • 音声検索 - 話し言葉、対話、ナレーション、音楽、効果音、感情のトーン

  • 対話型検索 - 視覚+音声のコンテキストを組み合わせたセマンティックな理解

結果は、以下を含むランク付けされたクリップとして返されます:

  • video_id - ソースビデオの識別子

  • start / end - 秒単位のタイムスタンプ範囲

  • rank - 関連性ランク(1 = 最良一致)

  • confidence - AIの信頼度レベル(高/中/低)

  • thumbnail_url - プレビュー動画のURL

  • transcription - クリップ中の発話内容(利用可能な場合)

TwelveLabsは結果の配列を返します。以下はサンプルレスポンスです:

{
  "data": [
    {
      "video_id": "6579a2c1d4b5e8f9a0123456",
      "start": 45.2,
      "end": 52.8,
      "rank": 1,
      "confidence": "high",
      "thumbnail_url": "https://thumbnails.twelvelabs.io/...",
      "transcription": "So let me explain how machine learning works..."
    },
    {
      "video_id": "6579a2c1d4b5e8f9a0789012",
      "start": 120.5,
      "end": 135.0,
      "rank": 2,
      "confidence": "medium",
      "thumbnail_url": "https://thumbnails.twelvelabs.io/...",
      "transcription": "Neural networks are inspired by the human brain..."
    }
  ]
}


結果のHTMLフォーマット

  1. TwelveLabsノードの "+" をクリックします

  2. "Code" を検索して選択します

  3. JavaScript で以下のコードを貼り付けます

const searchData = $input.first().json.data;
const top10 = searchData.filter(result => result.rank <= 10);

let resultsHTML = `
<table style="width: 100%; border-collapse: separate; border-spacing: 20px; margin: 20px 0;">
  <tr>
    <td colspan="4" style="text-align: center; padding-bottom: 20px;">
      <h2 style="color: #8B5CF6; font-size: 28px; margin: 0;">
        Search Results (Top ${top10.length})
      </h2>
    </td>
  </tr>
`;

// Create 4-column grid
for (let i = 0; i < top10.length; i += 4) {
  resultsHTML += '<tr>';
  
  for (let j = 0; j < 4; j++) {
    if (i + j < top10.length) {
      const r = top10[i + j];
      resultsHTML += `
        <td style="width: 25%; vertical-align: top;">
          <div style="background: #141518;
                      border: 1px solid #2A2B30;
                      border-radius: 12px;
                      padding: 16px;
                      box-shadow: 0px 4px 12px rgba(139, 92, 246, 0.1);">
            
            <div style="position: relative; margin-bottom: 12px;">
              <span style="position: absolute;
                          top: 8px;
                          left: 8px;
                          background: #8B5CF6;
                          color: #FFFFFF;
                          padding: 6px 10px;
                          border-radius: 6px;
                          font-size: 14px;
                          font-weight: 600;
                          z-index: 10;">
                #${r.rank}
              </span>
              
              <img src="${r.thumbnail_url}"
                   alt="Result ${r.rank}"
                   style="width: 100%;
                          height: 140px;
                          object-fit: cover;
                          border-radius: 8px;
                          display: block;"/>
            </div>
            
            <div style="color: #FFFFFF; font-size: 13px; margin-bottom: 6px;">
              <strong style="color: #FFFFFF;">Video ID:</strong><br/>
              ${r.video_id.substring(0, 12)}...
            </div>
            
            <div style="color: #E5E7EB; font-size: 12px; margin-bottom: 6px;">
              <strong style="color: #FFFFFF;">Time:</strong>
              ${r.start}s - ${r.end}s
            </div>
            
            ${r.transcription ? `
              <div style="color: #D1D5DB;
                          font-size: 11px;
                          font-style: italic;
                          padding: 8px;
                          background: #1A1B1F;
                          border-radius: 6px;
                          margin-top: 8px;">
                "${r.transcription}"
              </div>
            ` : ''}
            
          </div>
        </td>
      `;
    } else {
      resultsHTML += '<td style="width: 25%;"></td>';
    }
  }
  
  resultsHTML += '</tr>';
}

resultsHTML += '</table>';
return [{ json: { html: resultsHTML } }];

このコードは、上位10件の結果にフィルタし、サムネイル、ランクバッジ、ビデオID、タイムスタンプ、書き起こしを含む4列のHTMLテーブルを構築します。


ユーザーへの結果の表示

  1. Codeノードの "+" をクリックします

  2. "Form" を検索し、通常のFormノードを選択します(Form Triggerではありません)

  3. ノードを設定します:

    • Operation(操作): "Completion"(完了表示)を選択します

    • Completion Title(完了画面のタイトル): "Search Results"(検索結果)

    • Completion Message(完了画面のメッセージ): "Expression"(式)をクリックし、{{ $json.html }} と入力します


結果ページのスタイル設定

結果ページをフォームのブランディングに合わせるために、同じカスタムCSSを追加します:

  1. ノード設定で "Options"(オプション) までスクロールします

  2. "Add Option""Custom CSS" をクリックします

  3. このCSSを貼り付けます:

:root {
    /* Colors */
    --color-background: #0A0B0D;
    --color-card-bg: #141518;
    --color-accent: #8B5CF6;
    --color-text: #FFFFFF;
    --color-html-text: #FFFFFF;

    /* Make the container full-width for better results display */
    --container-width: 100% !important;

    /* Typography */
    --font-family: 'Inter', 'Open Sans', sans-serif;
    --font-size-header: 24px;

    /* Borders */
    --border-radius-card: 12px;
}

body {
    background: linear-gradient(135deg, #0A0B0D 0%, #1A1B1F 100%);
    min-height: 100vh;
    color: #FFFFFF;
}

/* Force container to full width for grid layout */
.container, .form-container, .completion-container {
    max-width: 100% !important;
    width: 100% !important;
}

/* Ensure all text is visible on dark background */
div, p, span, strong, h1, h2, h3 {
    color: inherit !important;
}

Form Completionノードは、検索処理が完了した後、ユーザーにフォーマットされたHTML結果ページを表示します。URLはフォームURLと同じで、n8nは自動的にリダイレクトを処理します。


4.4 - テストとトラブルシューティング


事前チェックリスト

テストの前に、以下の項目を確認してください:

  • [ ] 4つのノードすべてが「Form Trigger → TwelveLabs → Code (Format HTML) → Form (Completion)」の順に接続されていること

  • [ ] TwelveLabsの認証情報が設定されていること

  • [ ] インデックスIDが正しいこと(TwelveLabsダッシュボードの値と一致)

  • [ ] ビデオがインデックス登録されていること(インデックス登録されていないビデオは検索で見つかりません)

  • [ ] ワークフローが保存されていること


有効化とテスト

  1. 右上隅にある "Inactive" 切り替えスイッチをクリックして、ワークフローをアクティブにします

  2. Form Trigger ノードをクリックして、URLを表示します:

    • Test URL - テストに使用します

    • Production URL - エンドユーザーと共有します

  3. テストURLをコピーし、新しいブラウザタブで開きます

  4. インデックス登録されたビデオに関連する検索クエリを入力します(例:「概念を説明する人」)

  5. 送信をクリックし、結果を待ちます(通常、3〜5秒)


期待される動作

✅ カスタムスタイリングを適用してフォームが読み込まれる

✅ 送信後、一時的に読み込み状態が表示される

✅ ビデオのサムネイル付きで結果ページが表示される

✅ 各結果にランク、タイムスタンプ、書き起こし(存在する場合)が表示される


一般的な未解決事項と解決策

未解決事項

考えられる原因

解決策

フォームが読み込まれない

ワークフローがアクティブ化されていない

右上にあるActive(アクティベート)スイッチをONに切り替えます

フォームが読み込まれない

ブラウザのキャッシュ

シークレット/プライベートウィンドウを試します

結果が見つからない

インデックスIDが間違い

TwelveLabsダッシュボードのインデックスIDがノード設定と一致しているか確認します

結果が見つからない

ビデオがインデックス登録されていない

TwelveLabsでインデックス作成ステータスを確認します(ビデオが「Ready」となっている必要があります)

結果が見つからない

クエリが具体的すぎる

ビデオに含まれていることが分かっている、より大まかな検索語を試します

結果に生のJSONテキストが表示される

Expression(式)の切り替えが有効になっていない

Form CompletionのMessage(メッセージ)フィールドで、「Expression」の切り替えをクリックします

結果に {{ $json.html }} がそのまま表示される

Expression(式)の切り替えが有効になっていない

プレーンテキストではなく、必ずExpressionモードを使用する必要があります

スタイリングが崩れる

CSSが両方のノードに適用されていない

Form TriggerとForm Completionの「両方」のノードにカスタムCSSを追加します

結果が表示されるが、サムネイル画像が壊れている

サムネイルURLの期限切れまたは無効

TwelveLabsのAPIレスポンスのチェックをします。サムネイルはアクセス可能である必要があります

誤った検索クエリが処理される

式の誤り

TwelveLabsのQuery Textが {{ $json["Search Query"] }} と正確に記述されているか確認します


実行履歴によるデバッグ

何かが失敗した場合:

  1. 左側のサイドバーの "Executions" に移動します

  2. 最近のテスト実行を見つけます(タイムスタンプとステータスが表示されます)

  3. クリックして展開し、以下を確認します:

    • 各ノードでのインプット/アウトプットデータ

    • スタックトレースを伴うエラーメッセージ

    • ステップごとの実行時間

特定のノードに赤いエラーインジケーターが表示されているか探してください。これによってワークフローがどこで壊れたかが正確に分かります。

💡 デバッグのヒント:TwelveLabsノードと、フォーマットを処理するCodeノードとの間に、一時的に console.log(JSON.stringify($input.all(), null, 2)); return $input.all(); と記述したCodeノードを追加し、生の検索レスポンスを確認します。


サンプルクエリによるテスト

動画コンテンツに基づいて、以下の検索パターンを試してみてください:

もし動画に以下が含まれている場合...

以下を検索してみてください...

うまくいく理由

人が話しているシーン

「カメラに向けて話している人」

映像+音声検出

製品デモ

「使い方の実演」

アクション認識+会話

屋外映像

「屋外の自然シーン」

シーン分類

プレゼンテーション

「図表のあるスライド」

映像検出+OCR

インタビュー

「2人の会話」

人物検出+ダイアログ

チュートリアル

「ステップバイステップのチュートリアル」

セマンティック理解

ブランディング

「画面上のロゴ」

視覚的オブジェクト検出+OCR


完全なワークフローの全体像

以下が、完全なセマンティック検索パイプラインです:


以上で、セマンティック検索インターフェースのワークフロー作成は完了です。ユーザーは自然言語のクエリを使用して動画ライブラリを検索できるようになり、結果はブランド化された視覚的なインターフェースに表示されます。同じフォームURLがリクエストの送信と結果の表示の両方に機能し、n8nが自動的に状態遷移を処理します。


5 - おわりに

統合用のカスタムコードを記述することなく、本番環境に対応可能な2つのビデオAIワークフローを構築しました。最初のワークフローは、S3からのビデオ取り込みを自動化し、並行してAI分析(コンプライアンス、要約、チャプター、ハイライト)を実行し、付加価値の高いメタデータをAirtableに保存します。2つ目のワークフローは、ユーザーが自然言語のクエリを使用してビデオクリップを見つけることができる、公開セマンティック検索インターフェースを構築します。両方のワークフローは、通常、ビデオAIプロジェクトで本番環境への導入を妨げるインフラストラクチャの複雑さを、n8nとTwelveLabsがいかに解消するかを示しています。

ビジュアルインターフェースを介して、TwelveLabs n8n コミュニティノードは、ビデオのマルチモーダルな理解(ビジュアル分析、音声の書き起こし、画面上のテキスト抽出、セマンティック検索)への即時アクセスを提供します。学習するSDKはなく、認証の定型手順もなく、再試行ロジックを構築する必要もありません。既存のツール(S3、Airtable、データベース、MAM、ウェブフック)を接続して、数週間ではなく数時間で機能するビデオAIの実装を完了させましょう。これらのワークフローはスタート地点です。Airtableをご利用のデータベースに変更する、コンプライアンスワークフローに承認フローを追加する、検索結果を既存のアプリケーションに統合するなど、様々なカスタム展開が可能です。

次のステップ:これらのパターンは、ソーシャルメディア用の自動クリップ生成、リアルタイムのコンテンツモデレーション、メタデータを利用したビデオライブラリの移行、またはカスタム推薦エンジンなど、他のユースケースにも拡張できます。TwelveLabs ドキュメントは、追加のAPI機能(埋め込みデータの抽出、カスタムプロンプト)をカバーしており、n8n コミュニティフォーラムには洗練されたワークフローパターンの例があります。技術的なご質問については、TwelveLabs Discord コミュニティに参加していただくか、jordan@twelvelabs.io または brice@twelvelabs.io までお気軽にお問い合わせください。