1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

生成AIにLINE Botを作ってもらう GPT4o編 その1

Posted at

はじめに

いろいろなパターンのLINE Botサーバーの開発を解説してきていますが、最近ふと生成AIが普通にLINE Botのコードを書くようになったらもうこういう説明必要なくね?と気づきました。

なので今回から現時点の生成AIがLINE Messaging API SDKとかを使ってどの程度書けるかを試してみようと思います。

やってみる

まず誰に聞いてみるかという話ですが、やはり超優秀と世界的に有名なGPT4o先生からだと思います。

ChatGPTのGPT4oモデルを選択した状態で、簡単なエコーサーバーを書いてもらおうと思います。最近の趣向の関係上、TypeScriptでDeno上で動くやつにしてもらいます。

最初のプロンプト

prompt.txt
LINE Botを開発したいです。以下の条件で簡単なLINE Botサーバーのコードを書いてください。

# 条件
1. LINE Messaging API SDK for nodejs を利用する
2. TypeScriptで記述する
3. その他LINE Botとして確実に作動するよう配慮したコードとする
4. コード以外に作動するために必要な設定等があれば解説文を書く

応答(コピペしてテキストレイアウトを調整したもの)

以下に、LINE Botを開発するための基本的なTypeScriptコードと、その設定手順を説明します。

前提条件

  1. Node.jsとnpmがインストールされていること
  2. LINE Developersで開発者アカウントを作成し、Messaging APIチャネルを作成していること

1. プロジェクトのセットアップ

プロジェクトディレクトリを作成します:

mkdir line-bot-ts
cd line-bot-ts

npm initでpackage.jsonを作成します:

npm init -y

必要なパッケージをインストールします:

npm install @line/bot-sdk express
npm install --save-dev typescript @types/node @types/express ts-node

TypeScriptの初期設定を行います:

npx tsc --init

この後、tsconfig.jsonの中で、"target": "es6"や"moduleResolution": "node"を確認してください。

2. LINE Botサーバーのコード

以下が基本的なLINE Botのサーバーコードです。

// src/app.ts
import express from 'express';
import { ClientConfig, Client, middleware, MiddlewareConfig, WebhookEvent } from '@line/bot-sdk';

const app = express();

// LINEのチャネルアクセストークンとチャネルシークレットを設定
const config: ClientConfig & MiddlewareConfig = {
  channelAccessToken: process.env.LINE_CHANNEL_ACCESS_TOKEN || '',
  channelSecret: process.env.LINE_CHANNEL_SECRET || '',
};

const client = new Client(config);

// ミドルウェアをセットアップ
app.use(middleware(config));

// Webhookエンドポイント
app.post('/webhook', (req, res) => {
  Promise.all(req.body.events.map(handleEvent))
    .then((result) => res.json(result))
    .catch((err) => {
      console.error(err);
      res.status(500).end();
    });
});

// イベントハンドラ
function handleEvent(event: WebhookEvent) {
  if (event.type !== 'message' || event.message.type !== 'text') {
    return Promise.resolve(null);
  }

  const replyText = `You said: ${event.message.text}`;
  return client.replyMessage(event.replyToken, {
    type: 'text',
    text: replyText,
  });
}

// サーバーを起動
const port = process.env.PORT || 3000;
app.listen(port, () => {
  console.log(`Server running on ${port}`);
});

3. 環境変数の設定

export LINE_CHANNEL_ACCESS_TOKEN="YOUR_CHANNEL_ACCESS_TOKEN"
export LINE_CHANNEL_SECRET="YOUR_CHANNEL_SECRET"

もしくは、.envファイルを作成して以下のように記述します:

.env
LINE_CHANNEL_ACCESS_TOKEN=YOUR_CHANNEL_ACCESS_TOKEN
LINE_CHANNEL_SECRET=YOUR_CHANNEL_SECRET

.envファイルを使う場合は、dotenvパッケージをインストールし、以下のようにインポートします:

npm install dotenv
// src/app.ts
import dotenv from 'dotenv';
dotenv.config();

4. TypeScriptコンパイルとサーバーの実行

TypeScriptコードをコンパイルして実行します:

npx tsc
node dist/app.js

もしくは、開発中はts-nodeを使って直接実行できます:

npx ts-node src/app.ts

5. Webhook URLの設定

LINE Developersコンソールで、Webhook URLを設定します。例えば、ローカル開発環境ではngrokを使って一時的な公開URLを作成し、そのURLをWebhook URLとして設定することが可能です。

ngrok http 3000

6. その他の注意点

  • セキュリティを確保するため、Webhookの検証を確実に行うようにしてください。
  • エラーハンドリングや例外処理を十分に行うことで、安定した動作を確保します。

これで、基本的なLINE Botのサーバーが完成です。追加機能を実装したり、イベントハンドリングを拡張することで、より高度なボットを開発できます。

プロンプト更新

ざっと読むとめっちゃそれっぽく要点を押さえているように見えますが、条件でDenoで動作することを忘れていました。なので追記します

prompt.txt
ありがとう。とてもよく理解できましたが、しかし条件を一つ忘れていました。TypeScriptのコードをDeno上で動作するよう更新してみてください。

応答

Denoで動作するようにTypeScriptコードを更新します。DenoはNode.jsとは異なり、標準ライブラリに多くの機能が組み込まれており、npmパッケージを使う代わりにDeno用のモジュールを使用します。

1. プロジェクトのセットアップ

DenoはNode.jsのようにpackage.jsonファイルが不要で、直接コードを書き始めることができます。

2. LINE Botサーバーのコード

以下がDenoで動作するように書き直したコードです。

import { serve } from "https://deno.land/std/http/server.ts";
import { Client, middleware } from "https://esm.sh/@line/bot-sdk";

// LINEのチャネルアクセストークンとチャネルシークレットを設定
const config = {
  channelAccessToken: Deno.env.get("LINE_CHANNEL_ACCESS_TOKEN") || "",
  channelSecret: Deno.env.get("LINE_CHANNEL_SECRET") || "",
};

const client = new Client(config);

// Denoのサーバー設定
const port = Deno.env.get("PORT") || 3000;
const server = serve({ port: +port });
console.log(`Server running on port ${port}`);

for await (const req of server) {
  if (req.method === "POST" && req.url === "/webhook") {
    const body = await req.json();
    await Promise.all(body.events.map(handleEvent))
      .then((result) => {
        req.respond({ status: 200, body: JSON.stringify(result) });
      })
      .catch((err) => {
        console.error(err);
        req.respond({ status: 500, body: "Internal Server Error" });
      });
  } else {
    req.respond({ status: 404, body: "Not Found" });
  }
}

// イベントハンドラ
async function handleEvent(event: any) {
  if (event.type !== "message" || event.message.type !== "text") {
    return Promise.resolve(null);
  }

  const replyText = `You said: ${event.message.text}`;
  return client.replyMessage(event.replyToken, {
    type: "text",
    text: replyText,
  });
}

3. 環境変数の設定

Denoでは、環境変数を読み込むために--allow-envフラグを使用します。Denoを起動する際に、以下のように設定します。

deno run --allow-net --allow-env src/app.ts

LINE_CHANNEL_ACCESS_TOKENとLINE_CHANNEL_SECRETをDeno.env.getで取得していますので、.envファイルや環境変数の設定方法はNode.jsと同様です。

4. Webhook URLの設定

LINE Developersコンソールで、Webhook URLを設定します。Denoのサーバーも同様にngrokを使ってローカルホストを公開することが可能です。

ngrok http 3000

これで、Deno上で動作するLINE Botが完成です。Node.jsと比べて、Denoは簡潔で安全な実行環境を提供するため、--allow-netや--allow-envなどのパーミッションを明示的に指定する必要があります。

#実行してみる

AWSにEC2インスタンスを立てて実行してみます。

mkdir GPT4o-1 && cd $_
deno init
vi main.ts
main.ts
import { serve } from "https://deno.land/std/http/server.ts";
import { Client, middleware } from "https://esm.sh/@line/bot-sdk";

// LINEのチャネルアクセストークンとチャネルシークレットを設定
const config = {
  channelAccessToken: Deno.env.get("LINE_CHANNEL_ACCESS_TOKEN") || "",
  channelSecret: Deno.env.get("LINE_CHANNEL_SECRET") || "",
};

const client = new Client(config);

// Denoのサーバー設定
const port = Deno.env.get("PORT") || 3000;
const server = serve({ port: +port });
console.log(`Server running on port ${port}`);

for await (const req of server) {
  if (req.method === "POST" && req.url === "/webhook") {
    const body = await req.json();
    await Promise.all(body.events.map(handleEvent))
      .then((result) => {
        req.respond({ status: 200, body: JSON.stringify(result) });
      })
      .catch((err) => {
        console.error(err);
        req.respond({ status: 500, body: "Internal Server Error" });
      });
  } else {
    req.respond({ status: 404, body: "Not Found" });
  }
}

// イベントハンドラ
async function handleEvent(event: any) {
  if (event.type !== "message" || event.message.type !== "text") {
    return Promise.resolve(null);
  }

  const replyText = `You said: ${event.message.text}`;
  return client.replyMessage(event.replyToken, {
    type: "text",
    text: replyText,
  });
}

環境変数を設定します

export LINE_CHANNEL_ACCESS_TOKEN="YOUR_CHANNEL_ACCESS_TOKEN"
export LINE_CHANNEL_SECRET="YOUR_CHANNEL_SECRET"

実行します

deno run -A main.ts

以下のようなエラーが出ました

Warning Implicitly using latest version (0.224.0) for https://deno.land/std/http/server.ts
Download https://esm.sh/v135/axios@1.7.2/denonext/unsafe/platform/node/classes/URLSearchParams.js (6
Listening on http://localhost:8000/
Server running on port 3000
error: Uncaught (in promise) TypeError: server is not async iterable
for await (const req of server) {
                        ^
    at file:///home/ubuntu/llm-linebots/GPT4o-1/main.ts:17:25

おわりに(つづく)

はい。たしかにこの部分はなんじゃこれ?と思って怪しんでましたがやっぱエラーでした。なんか全体的にやりたいことは伝わるけど辻褄があってない感じですよね。

ここから4o先生に質問攻めをして動くコードに持っていってくれるかをやっていきたいですが、今日は時間がないので次回からやっていこうと思います。

方針としては人間(ボク)は一切コードを補完せず、プロンプトのみで修正していきます。

1
2
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
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?