はじめに
Difyがすごい勢いで流行っているのでLINEボットサーバーと連携をやってみることにしました。
本記事ではDifyのクラウド版で試してみます。Difyの出自はTencent系なのでクラウドはやばい?という話もあるようですが、このあたりは各自で判断してください。
やってみる
今回はカンタンのためにサラのテキストジェネレーターアプリを作成します。Difyの基本的な使い方に関しては他のWebサイトにたくさん情報が載っているのでそちらを参考にしてください。現時点では頻繁にUIがアップデートされていっている感があります。
適当なアプリをつくる
ダッシュボードから最初から作成をクリックします
テキストジェネレーターを選択してアプリの名前を入力し作成するをクリックします
アプリが作成されました。デバッグとプレビュー欄で何かプロンプトを入力すると回答が返ってきます。
APIを叩いてみる
サイドメニューの概要をクリックしてバックエンドサービスAPI欄に移動しAPIキーをクリックします
新しいシークレットキーを作成をクリックします
生成されたAPIシークレットキーをコピーしてメモ帳などに控えます
サイドメニューのAPIアクセスをクリックするとAPIリファレンスが参照できます
APIリファレンスを参考にcurlでAPIを叩いてみます。ENTER-YOUR-SECRET-KEYは先程控えたAPIシークレットキーに差し替えてください
curl -X POST 'https://api.dify.ai/v1/completion-messages' \
--header 'Authorization: Bearer ENTER-YOUR-SECRET-KEY' \
--header 'Content-Type: application/json' \
--data-raw '{
    "inputs": {"query": "Hello world!"},
    "response_mode": "blocking",
    "user": "abc-123"
}'|jq .
回答が返ってきました。つまりinputs.queryにLINEメッセージを入力してリクエストしてレスポンスのanswerをリプライすれば良さげです
{
  "event": "message",
  "task_id": "b7bf90b5-5fd5-4519-9edf-ef55b724183b",
  "id": "f0521730-cf3f-408e-ba9c-9441006d30ec",
  "message_id": "f0521730-cf3f-408e-ba9c-9441006d30ec",
  "mode": "completion",
  "answer": "Hello! How can I assist you today?",
  "metadata": {
    "usage": {
      "prompt_tokens": 10,
      "prompt_unit_price": "0.001",
      "prompt_price_unit": "0.001",
      "prompt_price": "0.0000100",
      "completion_tokens": 9,
      "completion_unit_price": "0.002",
      "completion_price_unit": "0.001",
      "completion_price": "0.0000180",
      "total_tokens": 19,
      "total_price": "0.0000280",
      "currency": "USD",
      "latency": 0.3724584267474711
    }
  },
  "created_at": 1715491205
}
LINE Botサーバーをカスタマイズする
Botサーバーは[Deno] FreshでLINE Messaging API SDKを使ってみるで作ったものをカスタムするかたちでやってみます。次のAPIトークンの値は適宜差し替えてください。
- 
YOUR_CHANNEL_ACCESS_TOKEN: LINEチャンネルアクセストークン
- 
YOUR_CHANNEL_SECRET: LINEチャンネルシークレット
- 
ENTER-YOUR-SECRET-KEY: Dify APIシークレットキー
下記のようにroutes/api/messaging.tsを更新します。
import type { Handlers, FreshContext } from "$fresh/server.ts";
import { messagingApi, MessageEvent } from "npm:@line/bot-sdk@9.2.2";
import type { ClientConfig, TextEventMessage } from "npm:@line/bot-sdk@9.2.2";
declare interface DifyCompletionMessageResponse {
  event: string;
  task_id: string;
  id: string;
  message_id: string;
  mode: string;
  answer: string;
  metadata: {
    usage: {
      prompt_tokens: number;
      prompt_unit_price: string;
      prompt_price_unit: string;
      prompt_price: string;
      completion_tokens: number;
      completion_unit_price: string;
      completion_price_unit: string;
      completion_price: string;
      total_tokens: number;
      total_price: string;
      currency: string;
      latency: number;
    }
  },
  created_at: number; 
}
const config: ClientConfig = {
    channelAccessToken: "YOUR_CHANNEL_ACCESS_TOKEN",
    channelSecret: "YOUR_CHANNEL_SECRET",
};
const client = new messagingApi.MessagingApiClient(config);
export const handler: Handlers =  {
  async POST(_req: Request, _ctx: FreshContext): Promise<Response> {
    const body = await _req.json(); 
    const event: MessageEvent = body.events[0];
    const textMessage = event.message as TextEventMessage;
    console.log(textMessage.text);
    // request to Dify API
    const requestData = {
      inputs: {
        query: textMessage.text,
      },
      response_mode: "blocking",
      user: "line-bot",
    };
    const resp = await fetch("https://api.dify.ai/v1/completion-messages", {
      method: "POST",
      headers: {
        "Authorization": "Bearer ENTER-YOUR-SECRET-KEY",
        "Content-Type": "application/json",
      },
      body: JSON.stringify(requestData),
    });
    const res = await resp.json() as DifyCompletionMessageResponse;
    await client.replyMessage({
      replyToken: event.replyToken,
      messages: [
        {
          type: "text",
          text: res.answer,
        },
      ],
    });
    return new Response(null, { status: 204 });
  }
};
使ってみる
実行します
deno task start
Task start deno run -A --watch=static/,routes/ dev.ts
Watcher Process started.
The manifest has been generated for 6 routes and 1 islands.
 🍋 Fresh ready 
    Local: http://localhost:8000/
正常に実行できました。
カレーライスについては長文でけっこういい回答が返ってきました。最近GPT3.5は使ってなかったんですが、かなり性能が上がっていますね。
おわりに
DifyとLINEボットの連携を簡単にやってみました。今回のようにDifyのテキストジェネレーターの場合はAPIが簡単に使えますが、エージェントの場合はresponse_mode:"blocking"が使えずstreamingのみのようなので使う場合は工夫が必要そうです。
他にもpre promptやナレッジデータの利用などもまだわかってないのでDify APIをもうちょっと調べて次回以降アップデートしてみようと思います。








