5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

LINE DCAdvent Calendar 2023

Day 21

LINExChatGPT 渾身の一激!画像から得られる教訓を大喜利風にトークグループにPUSH!

Last updated at Posted at 2023-12-20

トークグループに対しての通知はあまり気にしたことがなかったので、ちょうど別件で作っていたサンプルがあったのでそれを元に。Googleドライブにある画像ファイルをランダムにピックアップし、選ばれた1枚をトークグループに通知してくれます。

渾身の1枚を激写 => 1枚激写 => 一激ということで、定期的にグループに対して通知すれば話が弾むのではないでしょうか!

あと、せっかくなのでChatGPTを絡めて、「画像から得られる教訓を大喜利風」にコメントしてもらおうと思います。

本記事は下記アドベントカレンダーの記事でもあります。

必要なもの

  • LINE Developers Consoleアカウント
  • OpenAIアカウント(gpt-4-vision-preview利用)
    • 画像認識を使うには、Usage tier 1担っている必要があります(おそらく)
  • Googelアカウント(ドライブ、GAS利用)
    • GASのスクリプト
    • 写真置き場

LINE Developers Consoleアカウント

プロバイダやチャネルの作成については多数記事がありますので、そちらをご覧ください。
ここで使っているのは、Messaging APIチャネルです。

image.png

チャネルアクセストークンを発行し控えておきます

スクリーンショット 2023-12-20 7.11.15.png

グループトークについて

こちらに記載がありますが、グループトークルームにBotを追加するとグループIDを取得できるので、それを元にGASからグループトークルームに対して通知を送ることができます。

グループIDを取得

"source": {
    "type": "group",
    "groupId": "Ca56f94637c...",
    "userId": "U4af4980629..."
}

groupId が渡されるのでこれを取得しておきます。

グループではなくとりあえず自身に通知して試してみたいときは、「チャネル基本設定」にあるユーザーIDを指定すれば試すことができます。

スクリーンショット 2023-12-20 7.12.34.png

Googleドライブフォルダ共有

画像が入っているフォルダを共有します。共有しないと、LINEから画像リンクを参照できないため必要となります。「リンクを知っている人全員」「閲覧者」にします。

スクリーンショット 2023-12-19 16.02.40.png

以下URLの最後の部分(folders/以降)が、一意に識別されるIDとなりますので控えておきます。

url.png

ChatGPT

ChatGPTで画像を入力できるようになったので、APIでも同様のことを試してみたく。
画像から得られる教訓を聞いてみた。

image.png

以下を参考に叩こうとしたが権限がないと!

image.png

早速叩いてみたところ、以下のエラーがでました。

image.png

なにやらGPT4を叩く権限がないとのこと・・・・
形としては、modelに gpt-4-vision-preview を指定し、 content に指示と画像URLをセットします。今回、画像URLはGoogleドライブ上の画像にします。

色々調べているとどうもAPI利用料で1ドル?以上の請求が発生していないと使えないようです。

以下に記載がありますが、1ドルの支払いがないとGPT4が使えないということで、知らなかった。

また、アカウントを見ると CURRRENT TIER が Free となっています。

image.png

とりあえず5ドル分のクレジットを購入してみました。世の中やはりお金なのでしょうか。

スクリーンショット 2023-12-19 12.23.10.png

やはりお金のようです。購入後 Tier1 になってました。

image.png

ということで、これで新たにAPIキーを作成して実行したところ、無事に叩けました!
Googleドライブ上の画像ファイル名、画像、渾身の一激が通知されます。

APIキーは Tier1 になってから再度作成しないとだめかもしれません。

IMG_0518.PNG

IMG_0519.PNG

サンプル

以下、Googleドライブの指定のフォルダ配下にある画像をランダムに1枚選び、それをグループトークルームに通知するサンプルです。ほとんどChatGPTに書いてもらいましたが。GASのトリガーで1日1回などの設定でsendRandomImageToLine を叩けば画像と共に通知されます。

image.png

また、スクリプトプロパティに、以下を設定してからデプロイしてください。

プロパティ
DRIVE_DIR_ID Googleドライブの一意のID
LINE_ACCESS_TOKEN MessagingAPIで発行したアクセストークン
OPENAI_KEY OPEN AIのキー
TARGET_GROUP_ID 通知先のトークグループID

スクリーンショット 2023-12-19 15.50.24.png

クリック
const OPENAI_KEY =
  PropertiesService.getScriptProperties().getProperty("OPENAI_KEY");
const LINE_ACCESS_TOKEN =
  PropertiesService.getScriptProperties().getProperty("LINE_ACCESS_TOKEN");

function callChatGptChatCompletionsApi(imageUrl) {
  const apiEndpoint = "https://api.openai.com/v1/chat/completions";
  const payload = {
    model: "gpt-4-vision-preview",
    messages: [
      {
        role: "user",
        content: [
          {
            type: "text",
            text: `この画像から得られる教訓を大喜利風に解説して。落語家のように400文字以内で大喜利だけを返して`,
          },
          {
            type: "image_url",
            image_url: {
              url: imageUrl,
            },
          },
        ],
      },
    ],
    max_tokens: 500,
  };

  const headers = {
    Authorization: `Bearer ${OPENAI_KEY}`,
    "Content-Type": "application/json",
  };

  const options = {
    method: "post",
    headers: headers,
    payload: JSON.stringify(payload),
    muteHttpExceptions: true,
  };

  const response = UrlFetchApp.fetch(apiEndpoint, options);
  return JSON.parse(response.getContentText());
}

function sendRandomImageToLine() {
  const folderId =
    PropertiesService.getScriptProperties().getProperty("DRIVE_DIR_ID");
  const allFiles = getAllFilesInFolder(folderId);

  if (allFiles.length === 0) return;

  const randomFile = allFiles[Math.floor(Math.random() * allFiles.length)];
  const imageUrl =
    "https://drive.google.com/uc?export=view&id=" + randomFile.getId();
  const fileName = randomFile.getName();

  const chatGptResponse = callChatGptChatCompletionsApi(imageUrl);
  var botResponse = chatGptResponse.choices[0].message.content.trim();

  sendToLine(fileName, imageUrl, botResponse);
}

function getAllFilesInFolder(folderId) {
  const rootFolder = DriveApp.getFolderById(folderId);
  const allJpegFiles = [];

  const processFolder = function (folder) {
    var files = folder.getFilesByType(MimeType.JPEG);
    while (files.hasNext()) {
      var file = files.next();
      allJpegFiles.push(file);
    }

    const subFolders = folder.getFolders();
    while (subFolders.hasNext()) {
      const subFolder = subFolders.next();
      processFolder(subFolder);
    }
  };

  processFolder(rootFolder);

  return allJpegFiles;
}

function sendToLine(fileName, imageUrl, message) {
  const groupId =
    PropertiesService.getScriptProperties().getProperty("TARGET_GROUP_ID");
  const headers = {
    Authorization: `Bearer ${LINE_ACCESS_TOKEN}`,
    "Content-Type": "application/json",
  };

  const payload = {
    to: groupId,
    messages: [
      {
        type: "text",
        text: fileName,
      },
      {
        type: "image",
        originalContentUrl: imageUrl,
        previewImageUrl: imageUrl,
      },

      {
        type: "text",
        text: message,
      },
    ],
  };

  const options = {
    method: "post",
    headers: headers,
    payload: JSON.stringify(payload),
  };

  UrlFetchApp.fetch("https://api.line.me/v2/bot/message/push", options);
}
5
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?