Dify と連携するLINE ボットを作ろう

本記事は、[Serverless Meetup Fukuoka #5](https://serverless.connpass.com/event/348712/) の後半（最後の方）、LINE連携パートにおける記事です。全体の流れは、[こちらの記事](https://zenn.dev/kensh/articles/deb33f97b728e4?fbclid=IwY2xjawKLqqlleHRuA2FlbQIxMABicmlkETF4bjdtanlvOUxSOGIzaU9UAR4y5fOC42vNFLQJsxcajETulj1rown_XWxf6s_DEfQQEX1zSj1Kyz2FEU6BiA_aem_3MLCaaQlJ1JzRWFaIwg2EQ)をご覧ください。

前提として、Dify上で動作するチャットボットがすでにある状態からのスタートを想定しています。

# 1. LINE Messaging API を作成する

(1) [LINE Developers のコンソール](https://developers.line.biz/console/)にログインします。LINEアプリでQRコードを読み取ってログインすると楽です。

(2) プロバイダがない場合は、プロバイダを作成します。
![Screenshot 2025-05-06 at 14.59.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71395/b5ee65ef-3528-4043-b1ad-7da482d0b4e5.png)

(3) 新規チャネル作成から、「Messaging API」を選択します。
![Screenshot 2025-05-06 at 15.00.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71395/bbfdd170-d003-4316-8c67-864571726d80.png)

(4) 「LINE公式アカウント作成する」をクリックし、遷移先のページで、LINE公式アカウントを作成します。必須項目を入力してください。
| 項目 | 内容 |
|:-:|:-:|
| アカウント名  |  Dify連携（お好きな名前で構いません） |
| メールアドレス  | ご自身のメールアドレス  |
| 会社・事業者の所在国・地域  | 日本  |
| 業種  | 個人　／　個人（その他） |
| 運用目的  | その他  |
| 主な使い方  | 上記以外の使い方  |

(5) アカウントが作成されたら、Official Account Managerのページへ移動します。情報利用に関する同意と、情報提供に関する個別規約への同意が求められます。

(6) 右上の「⚙️設定」をクリックします。

(7) 左の「Messaging API」を選択し、「Messaging APIを利用する」をクリックします。
![Screenshot 2025-05-06 at 15.09.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71395/d4e2e11a-5500-456a-8826-c7d0a56a7e3e.png)

(8) プロバイダを選択し、「同意」、「OK」、「OK」を順番にクリックします。

(9) 左の「応答設定」を開き、あいさつメッセージと応答メッセージをOFFにします。
![Screenshot 2025-05-06 at 15.15.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71395/314fb125-e0be-4245-ba94-fe718bc59912.png)

(10) [LINE Developers コンソール](https://developers.line.biz/console/)に戻り、チャネルシークレットとチャネルアクセストークンを控えます。
| 項目 | 場所 |
|:-:|:-:|
| チャネルシークレット  | チャネル基本設定タブ内の下の方  |
| チャネルアクセストークン  | Messaging API設定タブ内の一番下（発行が必要です）  |

:::note information
LINEボットの設定画面には、大きく分けて2種類あります。慣れるまでは混乱しやすいポイントですので、以下のようにご認識いただければ幸いです。
【LINE Developers コンソール】
技術者向け。LINEログインやMessaging APIなどの開発設定を行う。
【LINE Official Account Manager】
運用者向け。LINE公式アカウントのメッセージ配信・分析・チャット対応などを行う。
:::

# 2. Difyとの連携設定
### 【Case 1】 httpsで接続が可能な場合、Difyプラグインが利用できます
(1) Difyのプラグインで、「マーケットプレイスを探索する」から"LINE"で検索し、『LINE Bot』インストールします。
![Screenshot 2025-05-06 at 15.19.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71395/3bedd483-a360-445a-a614-b0515b487f9c.png)

(2) プラグインの「LINE Bot」からエンドポイントを追加します。
![Screenshot 2025-05-06 at 15.23.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71395/ce4cac5b-8b3c-446d-99d7-d5a69a041ec3.png)

(3) 必須項目を入力します。
| 項目 | 内容 |
|:-:|:-:|
| エンドポイント名  | Dify連携（こちらもお好きな名前で）  |
| チャネルシークレット  | LINE Developers コンソールで控えたもの  |
| チャネルアクセストークン  | LINE Developers コンソールで控えたもの  |
| アプリ  | Knowledge Retreival + Chatbot (Chatflow) |

(4) 保存すると、エンドポイントのURLが発行されます。

(5) LINE Developers コンソールに戻り、Messaging API設定タブ内のWebhook URLを設定します。Webhookの利用も同時にONにします。

(6) Messaging API設定タブ内のQRコードから友達登録をし、動作確認します。

:::note warn
このやり方では、2025年5月10日現在、conversation_idを使った会話のやり取りができないようです。
:::

### 【Case 2】 Google Apps Script(GAS)でBotアプリを構築
(1) まず、簡易的なおうむ返しLINE Botを作成してみます。以下のコードを[GAS](https://script.google.com)に貼り付け、デプロイします。先頭行のチャネルアクセストークンのみ書き換えてください。
```javascript
const LINE_CHANNEL_ACCESS_TOKEN = 'YOUR_LINE_CHANNEL_ACCESS_TOKEN';

function doPost(e) {
  const json = JSON.parse(e.postData.contents);

  const userMessage = json.events[0].message.text;
  const replyToken = json.events[0].replyToken;

  const reply = {
    replyToken: replyToken,
    messages: [
      {
        type: 'text',
        text: `「${userMessage}」ですね！`
      }
    ]
  };

  const options = {
    method: 'post',
    contentType: 'application/json',
    headers: {
      Authorization: 'Bearer ' + LINE_CHANNEL_ACCESS_TOKEN
    },
    payload: JSON.stringify(reply)
  };

  UrlFetchApp.fetch('https://api.line.me/v2/bot/message/reply', options);

  return ContentService.createTextOutput('OK');
}
```
:::note warn
GAS内にアクセストークンを直接埋め込むのは、小規模な個人開発や検証では一時的に許容されますが、本番運用では推奨されないので、Google Cloud Secret Managerなど代替手段を検討してください。
:::

(2) デプロイの種類は「ウェブアプリ(Web app)」を選択し、アクセスできるユーザーは、「全員(Anyone)」を選択してください。
![Screenshot 2025-05-06 at 15.54.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71395/d328526b-28ee-4c44-93f3-075439c4dd0e.png)

(3) URLが発行されるので、LINE Developers コンソールに戻り、Messaging API設定タブ内のWebhook URLを設定します。Webhookの利用も同時にONにします。検証してみて「成功」となればOKです。
例: https://script.google.com/macros/s/xxxxxxxxxx/exec

(4) Messaging API設定タブ内のQRコードから友達登録をし、動作確認します。
![Screenshot_20250506-161129.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71395/2e278e9b-f580-4d8a-9847-2706b2e85924.png)

(5) GASのコードを書き換えます。
```javascript
const API_URL = 'YOUR_API_URL';
const DIFy_API_KEY = 'YOUR_DIFY_API_KEY';
const LINE_CHANNEL_ACCESS_TOKEN = 'YOUR_LINE_CHANNEL_ACCESS_TOKEN';

function doPost(e) {
  const json = JSON.parse(e.postData.contents);
  const userMessage = json.events[0].message.text;
  const replyToken = json.events[0].replyToken;
  const userId = json.events[0].source.userId;

  const userProps = PropertiesService.getScriptProperties();
  const convKey = 'conv_' + userId;

  // 会話履歴のリセット
  if (userMessage === '最初から') {
    userProps.deleteProperty(convKey);
    replyToLine(replyToken, '会話履歴をリセットしました。最初からどうぞ。');
    return ContentService.createTextOutput('OK');
  }

  const conversationId = userProps.getProperty(convKey);

  const payload = {
    inputs: {},
    query: userMessage,
    response_mode: 'blocking',
    conversation_id: conversationId || '',
    user: userId,
    files: [
      {
        type: 'image',
        transfer_method: 'remote_url',
        url: 'https://cloud.dify.ai/logo/logo-site.png'
      }
    ]
  };

  const options = {
    method: 'post',
    contentType: 'application/json',
    headers: {
      Authorization: 'Bearer ' + DIFy_API_KEY
    },
    payload: JSON.stringify(payload)
  };

  try {
    const response = UrlFetchApp.fetch(API_URL, options);
    const responseData = JSON.parse(response.getContentText());
    const answer = responseData.answer || '応答が取得できませんでした。';
    const newConversationId = responseData.conversation_id;

    // 会話IDを保存
    if (newConversationId) {
      userProps.setProperty(convKey, newConversationId);
    }

    replyToLine(replyToken, answer);
  } catch (error) {
    Logger.log(error);
    replyToLine(replyToken, 'エラーが発生しました。後ほどお試しください。');
  }

  return ContentService.createTextOutput('OK');
}

function replyToLine(replyToken, message) {
  const reply = {
    replyToken: replyToken,
    messages: [
      {
        type: 'text',
        text: message
      }
    ]
  };

  const options = {
    method: 'post',
    contentType: 'application/json',
    headers: {
      Authorization: 'Bearer ' + LINE_CHANNEL_ACCESS_TOKEN
    },
    payload: JSON.stringify(reply)
  };

  UrlFetchApp.fetch('https://api.line.me/v2/bot/message/reply', options);
}
```
:::note information
連続したやり取りを可能としています。
最初から会話をやり直したい場合は、"最初から"と投稿することで会話がリセットされるように書いています（コメントの"会話履歴のリセット"部分）。
:::

(6) 保存し、デプロイします。
※新規でデプロイし直した場合は、URLが変わりますので、LINE Developers コンソールのWebhook URLも変更する必要があります。

(7) 動作確認します。
![Screenshot_20250506-164155.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71395/51a91065-2d57-4336-b183-0fb76aaceac5.png)
Difyの「ログ＆アナウンス」を確認しても、連続した会話ができていることが確認できます。
![Screenshot 2025-05-06 at 16.44.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71395/c2ea6413-210a-47a6-b6e9-d478e96abc6b.png)
![Screenshot 2025-05-06 at 16.44.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71395/c4e07b40-fd48-47d1-aef7-174a1f31e660.png)

# 3. 終わりに
冒頭で紹介した通り、こちらの記事は、福岡で行われたハンズオンイベントの後半最後の方のパートにおける手順書です。実は福岡で実施される数週間前に名古屋でも同様のハンズオンイベントが行われていまして、その際は、PostmanでのAPIテストの流れから、[Postman Flows](https://www.postman.com/product/flows/)を使ったLINE連携が紹介されていたそうです。
他にもノーコードツールを使った方法など、LINE連携にはバラエティに富む手段があり、お好みで使い分けて頂ければと思います。

いずれにしても、LINEアプリを使った快適なUIによる検証環境が簡単に実現できることを実感していただけたのではないでしょうか？