SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

サーバーレスでAIシステム開発スタートダッシュ

OpenAI APIを使って議事録作成Botを作ってみよう!

サーバーレスでAIシステム開発スタートダッシュ 第3回

文字起こし

 Google Meetには録画機能があるので、まずそれを利用して会議を録画しておきます。録画したファイルはMP4形式でGoogleDriveに保存されるので、このファイルからOpenAIが提供しているWhisper APIを利用して文字起こしを行います。

 今回はSlack Botに動画を渡すため、Slack上から動画をアップロードし、ショートカットメニューからBotを起動させます。作成したBotの名前は「議事録作成くん」です。

 Slackメッセージのメニューに先ほど作成したSlack Botが表示されているので、これを選択することでイベントがBotに送信されます。

SlackメッセージのメニューにSlack Botが表示されている
SlackメッセージのメニューにSlack Botが表示されている

 ショートカットイベントを受け取って処理するには、以下のようなアノテーションを関数に付ける必要があります。ここで記載しているshortcut_pushedは、後ほどSlack Appを作成する際にInteractivity & Shortcutsで設定するショートカットのCallback IDです。

@app.shortcut("shortcut_pushed")
def shortcut_proceedings(ack, body, client, say):
    # Acknowledge the command request
    ack()

 イベントを受け取ったらすぐにack()で応答する必要があるため、忘れないようにしましょう。

 メッセージとしてアップロードされたファイルを取得する方法は以下のようになります。

movieURL = body["message"]["files"][0]["url_private_download"]
headers = {"Authorization": f"Bearer {SLACK_BOT_TOKEN}"}
response = requests.get(movieURL, headers=headers)

 ファイルをダウンロードするためのURLが取得できるため、そこにアクセスします。

 今回はrequestsライブラリを利用してHTTP通信を行います。ヘッダー認証にSlackのBot tokenを含める必要があります。

 オーディオファイルが取得できたら、OpenAI APIを利用してそれをWhisperモデルに入力します。OpenAIのクライアントは予め初期化処理を行なっておきます。

from openai import OpenAI

client = OpenAI(
    api_key="API key"
)

 Whisper APIを利用するコードがこちらです。

transcript = client.audio.transcriptions.create(
      model = "whisper-1",
      file = file,
      language = 'ja',
      prompt="これは複数人で行った会議の録音データです。",
      )

 入力する音声ファイルに存在する無音部分は出来る限り削除した方が文字書き起こしの精度が上がるので、事前に取り除く処理を入れておくことをお勧めします。また、入力ファイルサイズの制限もあるため、大きいファイルの場合は分割して入力する必要があります。

 一例ですが、文字起こしが完了すると以下のようにテキストが返ってきます。

 今、つまり。はい。っていう。まあ、ブラッシュアップ内容ですよね。まあ、そうかもね。はい。はい。一旦その単発のやつをあの直接呼び出すぐらいしかできないかもしれないね時間的に。そうですね。まだ画像周りも残ってますからね。画像あの。そう、はい。簡単ですよ。どうぞすあの一瞬で。まあ、確かに。URL。画像あれ、画像を生成する用のエーピーアイみたいなのって。 ええと。用意した方がいい。いや、いらないんじゃないですか?いや、商品を生成するAPIの中で。はい。画像も一緒に生成して一緒に返してくれるみたいな。...

 ...

要約する

 オーディオファイルからの文字起こしが完了したので、次はこのテキストを議事録としてまとめる工程に入ります。そのままChatGPTに「議事録として要約してください」という形で入力してもよいのですが、文字起こしで生成されたテキストには余分な相槌が含まれていたり、意味が通っていない文章になっていたりすることがあります。そのため、一旦これを書き言葉として整文させた方が、より綺麗な議事録になります。

 以下のようなプロンプトでGPTモデルに入力します。

prompt = """以下の文章は、ボイスレコーダーで録画した会議の文字起こしを行ったものです。これを書き言葉として出来るだけ意味の通るような自然な文章に整えてください。
# 出力形式
* 相槌はなるべく省くこと。
    * 主な相槌の参考:[はい, ええ, ああ, うん, そう, なるほど, そうですね]
* 意味が判断できない箇所は省略するのではなく、そのまま出力すること。
# 入力文章
{input_text}"""
prompt = prompt_template.format(input_text=text)

response = client.chat.completions.create(
  model="gpt-4",
  messages=[
        {"role": "system", "content": "あなたは話し言葉から書き言葉へと変換するスペシャリストです。"},
        {"role": "user", "content": prompt}
    ]
)

 modelには利用したいモデルを記載します。現在公開されているモデルはModelsのページから参照することができます。

 messagesの中でプロンプト等を構築していくのですが、APIではroleという項目を設定する必要があります。roleは3種類存在し、systemロールではモデルが回答するにあたって必要な前提条件を、assistantロールでは今までの会話においてAIモデルが回答した内容を、userロールには我々が入力するプロンプトをそれぞれ記述します。assistantに望ましい回答の例文を入れることで精度を高めることも可能です。

 今回はプロンプトで「出来るだけ意味の通るような自然な文章に整えてください」と指示を出すことで、文字起こしの際に出る不明瞭なテキストを省き、相槌も参考リストを渡す事である程度除去することができます。この工程を踏むと以下のような文章になります。

 ここでの話題は時間が限られていますが、個々の課題に対処する方向で考えたいと思います。特にブラッシュアップを必要とする内容がいくつかあります。時間の制約から、直接呼び出すしか選択肢がないと思われます。まだ画像周りの作業も残っていて、画像の生成に関するAPIを用意すべきかどうか検討しています。商品の生成と同時に画像も生成し、その結果を返すのが理想的と考えられます。

 話し言葉として乱雑だったものが、書き言葉としてかなりまとまった文章になりましたね。

 整文が終わったので、いよいよ議事録としてまとめる工程に入ります。以下のようなプロンプトでモデルに入力します。

prompt_template = """あなたは現在、会議の議事録を作成している最中です。
以下に示す文章に関して、話題ごとにタイトルを作成し、その話題ごとに要点を紐づけて、JSON形式でまとめてください。
# 入力文章:
{input_text}
# 出力形式:
* 要点はできるだけ簡潔にまとめてください。
* 次に示すJSONの形式で出力してください。topicとpointはリストになっており、必要に応じて数を増減させてください。
# JSON形式のテンプレート
{{"topic1":{{"title":"話題のタイトル","point1":"要点1","point2":"要点2"}},"topic2":{{"title":"話題のタイトル","point1":"要点2"}}}}"""
prompt = prompt_template.format(input_text=text)

 また、今回は回答をJSON形式で出力してほしいため、json_modeを利用します。

response = client.chat.completions.create(
  model="gpt-4-1106-preview",
  messages=[
        {"role": "system", "content": "あなたは議事録作成のスペシャリストで、文章の要点をJSON形式でまとめる能力に優れています。"},
        {"role": "user", "content": prompt}
    ],
response_format={"type": "json_object"}
)

 JSONで出力させずとも議事録は作成されるのですが、タイトルの付け方や段落の付け方、箇条書きの書き方などがバラバラになってしまう問題があるため、JSONで回答させたものをプログラムで整形させた方が綺麗になります。

 出力結果としては以下のような形になります。

{
    "topic1":{
        "title":"課題と方針",
        "point1":"時間が限られているため、個々の課題に直接対処する方向で考える",
        "point2":"特にブラッシュアップが必要な内容については、直接呼び出すしか選択肢がない",
        "point3":"画像周りの作業が残っており、画像生成に関するAPIの準備が必要か検討中"
    },
    "topic2":{
        "title":"画像生成について",
        "point1":"商品生成と同時に画像も生成し、その結果を返すことを考えている",
        "point2":"プロンプトとジェイソンを用いて、指定された画像を作成する流れを作りつつある",
        "point3":"パラメータを追加して画像のスタイルを調整する必要がある",
        "point4":"現在の方法が良好な結果を得るためのものだと思っているが、調整が必要"
    },
    "topic3":{
        "title":"全体の進捗と課題",
        "point1":"全体のシステムの概観や現在直面している課題はリアルな画像の生成に基づいている",
        "point2":"特に懸念事項はない"
    },
    "topic4":{
        "title":"東北の話題とセッショントークンの問題",
        "point1":"登録APIを使用する際にセッショントークンが必要だった部分に触れる",
        "point2":"内部での利用に限ることでサーバー間での安全な通信が可能になり、ログインの必要性を無くすことを考えている",
        "point3":"一方で、名前だけで固定の投稿を続けるという問題が残っている"
    }
}

 トピックごとにタイトルと要点がまとまっていますね。固有名詞のようなものは適切に文字起こしができていなかったり表記揺れがあったりしますが、意味の通る文章としてうまくまとめられています。

 後は、例えばマークダウン形式に整形するなどして議事録として文章を作成すれば完成です。

次のページ
Cloud Functionsへのデプロイ

この記事は参考になりましたか?

サーバーレスでAIシステム開発スタートダッシュ連載記事一覧

もっと読む

この記事の著者

株式会社ブリューアス AI-TEAM(カブシキガイシャブリューアス エーアイチーム)

 モバイルのアプリを中心にUI/UXデザインから開発保守まで、幅広い実績を持つ会社です。専門的な知識と豊富な開発経験を活かし、AIとサービスの統合を推進しています。 Brewus.inc

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/19051 2024/03/05 11:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー