AIで動画の文字起こし、記事作成、サムネ画像作成を同時に行う

公開日:2023/7/13更新日:2023/7/13

動画の文字起こしから、ブログ執筆、さらにはサムネイル画像の生成まで、AIの力で一気通貫で行う方法をご紹介します。動画とブログの二刀流を実現したい方におすすめの方法です。

利用するサービスはすべてOpenAIのものになり、役割は以下の通りです。

今回はすべての工程をNext.js(Node.js)上で実行しますが、おおまかな流れはPythonでも同じです。

得られるメリット

  • 動画に字幕をつける手間が劇的に減る
  • 労力を全くかけずにクオリティの高い記事を作成できる
  • 記事ごとにユニークな画像を表示できる
  • コストがほぼかからない(最重要)

正直なところ、DALL·Eが生成する画像をそのままYouTubeやブログで使うのは厳しいため、サムネ画像だけはCanvaなどの外部サービスを利用した方がいいですが、ユーザー投稿型のサービスなどでは重宝します。

プログラム実行時のポイント

この手のAIサービス全般に言えますが、プロンプト(指示・命令)をしっかり与えるのが重要です。今回のケースだと、「Whisperの文字起こしの精度を高めること」と「ChatGPTに意図したレスポンスを返してもらうこと」が必要です。

Whisperの文字起こしの精度を高める

promptパラメーターに「何についての音声データか」を渡せば実現できます。具体的な方法は別記事で紹介していますが、カンマ区切りで文字列を渡したり、「これは〇〇と〇〇についての音声データです」のように丁寧に指示することもできます。

ChatGPTのレスポンスの形式を指示する

promptパラメーターにフォーマット: <返して欲しいフォーマット>の形式で渡せば実現できます。例えば、フォーマット: { slug: "スラッグ", title: "タイトル" }といった具合です。

サンプルコード

ここまでの話を踏まえ、具体的なコードを以下に紹介します。

サーバサイドでの処理

/app/api/generate/route.tsのファイルを作成し、クライアントサイドから送信された音声データを受け取って一連の処理をするコードを記述します。

便宜上、エラーハンドリングを省いていますが、処理の全容は以下の通りです。

import { NextRequest, NextResponse } from "next/server";

export const runtime = "edge";

export async function POST(request: NextRequest) {
  // クライアントサイドから送られてきたフォームデータを取得
  const formData = await request.formData();

  // フォームデータから音声データを取得
  const resource = formData.get("resource") as File;

  // Whisper-1モデルで日本語の文字起こしを行うためのフォームデータを作成
  const transcriptionFormData = new FormData();
  transcriptionFormData.set("file", resource); // 音声データをセット
  transcriptionFormData.set("model", "whisper-1"); // モデルをwhisper-1にする
  transcriptionFormData.set("language", "ja"); // 言語を日本語にする

  // 文字起こしを実行
  const whisperRes = await fetch(
    "https://api.openai.com/v1/audio/transcriptions",
    {
      headers: {
        Authorization: `Bearer ${process.env.OPENAI_API_KEY}`,
      },
      method: "POST",
      body: transcriptionFormData,
    }
  );

  // 文字起こしの結果を取得
  const transcription: string = (await whisperRes.json()).text;

  // ここで文字起こしの結果を保存して動画の字幕作成に活用する

  // ブログ記事作成のプロンプトを作成
  const completionPrompt = `以下のトランスクリプションを基に、フォーマットに従ってブログ記事を作成して。
  トランスクリプション: ${transcription}
  フォーマット: ${JSON.stringify({
    slug: "unique-slug",
    title: "32文字以内のユニークなタイトル",
    description: "160文字以内の要約",
    content: "<p>HTML形式の記事本文</p>",
  })}
  `;

  // ブログ記事を作成
  const completionRes = await fetch(
    "https://api.openai.com/v1/chat/completions",
    {
      headers: {
        Authorization: `Bearer ${process.env.OPENAI_API_KEY}`,
        "Content-Type": "application/json",
      },
      method: "POST",
      body: JSON.stringify({
        model: "gpt-3.5-turbo-16k",
        messages: [
          {
            role: "system",
            content: "あなたは旅行が好きなWebライターです。",
          },
          {
            role: "user",
            content: completionPrompt,
          },
        ],
        temperature: 1,
        top_p: 1,
        frequency_penalty: 0,
        presence_penalty: 0,
      }),
    }
  );

  // ブログ記事のデータを取得
  const post: {
    slug: string;
    title: string;
    description: string;
    content: string;
  } = JSON.parse((await completionRes.json()).choices[0].message.content);

  // ここでpostデータを保存したり、別のAPIに送信したりする

  // タイトルや説明から画像を生成
  const imageRes = await fetch("https://api.openai.com/v1/images/generations", {
    headers: {
      Authorization: `Bearer ${process.env.OPENAI_API_KEY}`,
      "Content-Type": "application/json",
    },
    method: "POST",
    body: JSON.stringify({
      prompt: post.title,
      n: 1,
      size: "1024x1024",
    }),
  });

  // 画像のURLを取得
  const imageUrl: string = (await imageRes.json()).data[0].url;

  // ここで画像を保存したり、別のAPIに送信したりする

  // レスポンスを返す
  return NextResponse.json({ success: true, message: "OK" });
}

クライアントサイドで音声データをアップロード

FormDataに音声データを含めてAPIにPOST送信します。

// /app/generate/components/Form.tsx

"use client";

export const Form = () => {
  return (
    <form
      onSubmit={async (e) => {
        e.preventDefault();

        const formData = new FormData(e.currentTarget);
        const res = await fetch(`${origin}/api/generate`, {
          method: "POST",
          body: formData,
        });

        alert(res.ok ? "Success" : "Something went wrong");
      }}
      className="flex flex-col gap-8"
    >
      <div className="flex flex-col">
        <label>音声ファイル</label>
        <input type="file" name="resource" accept="audio/*" required />
      </div>
      <div className="flex justify-center">
        <button type="submit">
          送信
        </button>
      </div>
    </form>
  );
};



// /app/generate/page.tsx

import { Form } from "./components/Form";

export const runtime = "edge";

export default async function GeneratePostPage() {
  return (
    <div>
      <Form />
    </div>
  );
}

実行結果

今回、GoogleのBardで音声の元となる文章を生成してもらい、その文章を音読さんで音声データにし、そのデータをアップロードしました。

元の文章

みなさん、こんにちは!今日は、旅行の時に気を付けるべきことをお話しします。

旅行は楽しいですよね。でも、楽しいだけじゃありません。トラブルに巻き込まれることもあります。そこで、今日は、旅行のトラブルを回避するための、ちょっとしたコツをご紹介します。

まずは、パスポートとビザを必ず持参しましょう。パスポートは、国境を越える際に必要な書類です。ビザは、入国する国によっては必要になる場合があります。パスポートとビザは、紛失や盗難に遭わないように、常に身に着けておくことが大切です。

次に、現地の治安に注意しましょう。旅行先の治安は、事前に調べておくことが大切です。特に、治安が悪い地域や時間帯は避けるようにしましょう。また、夜は一人歩きや繁華街を歩くことは避けましょう。

そして、貴重品は身に着けないことが大切です。特に、パスポート、財布、携帯電話などは、常に身に着けておくことが大切です。貴重品は、ホテルの金庫や貸金庫に預けるようにしましょう。

また、現地の法律を守ることも大切です。現地の法律を守らないと、罰金や逮捕される可能性があります。

現地の文化を尊重することも大切です。現地の文化に違反する行為は、避けましょう。

十分な睡眠をとることも大切です。旅行中は、十分な睡眠をとるようにしましょう。睡眠不足は、体調を崩したり、事故に遭ったりする原因になります。

水分をこまめに摂取することも大切です。旅行中は、水分をこまめに摂取するようにしましょう。水分不足は、脱水症状を引き起こす可能性があります。

病気や怪我に備えることも大切です。海外旅行保険に加入しておくと、万が一の時に安心です。また、常備薬を携帯しておくと良いでしょう。

これらの注意点を守ることで、安全で楽しい旅行をすることができます。

それでは、みなさん、楽しい旅行を!

Whisperからのレスポンス

皆さんこんにちは今日は旅行の時に気をつけるべきことをお話しします 旅行は楽しいですよね でも楽しいだけじゃありません トラブルに巻き込まれることもあります そこで今日は旅行のトラブルを回避するためのちょっとしたコツをご紹介します まずはパスポートとビザを必ず持参しましょう パスポートは国境を越える際に必要な書類です ビザは入国する国によっては必要になる場合があります パスポートとビザは紛失や盗難に合わないように常に身につけておくことが大切です 次に現地の治安に注意しましょう 旅行先の治安は事前に調べておくことが大切です 特に治安が悪い地域や時間帯は避けるようにしましょう また夜は一人歩きや繁華街を歩くことは避けましょう そして貴重品は身につけないことが大切です 特にパスポート財布携帯電話などは常に身につけておくことが大切です 貴重品はホテルの金庫や貸金庫に預けるようにしましょう また現地の法律を守ることも大切です 現地の法律を守らないと罰金や逮捕される可能性があります 現地の文化を尊重することも大切です 現地の文化に違反する行為は避けましょう 十分な睡眠をとることも大切です 旅行中は十分な睡眠をとるようにしましょう 睡眠不足は体調を崩したり事故にあったりする原因になります 水分をこまめに摂取することも大切です 旅行中は水分をこまめに摂取するようにしましょう 水分不足は脱水症状を引き起こす可能性があります 病気や怪我に備えることも大切です 海外旅行保険に加入しておくと万が一の時に安心です また常備薬を携帯しておくと良いでしょう これらの注意点を守ることで安全で楽しい旅行をすることができます それでは皆さん楽しい旅行を

ChatGPTからのレスポンス

{
  "slug": "travel-tips",
  "title": "旅行のトラブルを回避するためのコツ",
  "description": "旅行のトラブルを回避するためのちょっとしたコツをご紹介します。",
  "content": "<p>みなさん、こんにちは!今日は、旅行の時に気を付けるべきことをお話しします。</p><p>旅行は楽しいですよね。でも、楽しいだけじゃありません。トラブルに巻き込まれることもあります。そこで、今日は、旅行のトラブルを回避するための、ちょっとしたコツをご紹介します。</p><p>まずは、パスポートとビザを必ず持参しましょう。パスポートは、国境を越える際に必要な書類です。ビザは、入国する国によっては必要になる場合があります。パスポートとビザは、紛失や盗難に遭わないように、常に身に着けておくことが大切です。</p><p>次に、現地の治安に注意しましょう。旅行先の治安は、事前に調べておくことが大切です。特に、治安が悪い地域や時間帯は避けるようにしましょう。また、夜は一人歩きや繁華街を歩くことは避けましょう。</p><p>そして、貴重品は身に着けないことが大切です。特に、パスポート、財布、携帯電話などは、常に身に着けておくことが大切です。貴重品は、ホテルの金庫や貸金庫に預けるようにしましょう。</p><p>また、現地の法律を守ることも大切です。現地の法律を守らないと、罰金や逮捕される可能性があります。</p><p>現地の文化を尊重することも大切です。現地の文化に違反する行為は、避けましょう。</p><p>十分な睡眠をとることも大切です。旅行中は、十分な睡眠をとるようにしましょう。睡眠不足は、体調を崩したり、事故に遭ったりする原因になります。</p><p>水分をこまめに摂取することも大切です。旅行中は、水分をこまめに摂取するようにしましょう。水分不足は、脱水症状を引き起こす可能性があります。</p><p>病気や怪我に備えることも大切です。海外旅行保険に加入しておくと、万が一の時に安心です。また、常備薬を携帯しておくと良いでしょう。</p><p>これらの注意点を守ることで、安全で楽しい旅行をすることができます。</p><p>それでは、みなさん、楽しい旅行を!</p>"
}

DALL·Eからのレスポンス

https://oaidalleapiprodscus.blob.core.windows.net/private/***

実際の画像はこちらです。