5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

DifyとLINEボットサーバーを連携してみる その3 conversation_id編

Posted at

はじめに

前回の続きです。DifyのAPIではconversation_idを使って継続的にエージェントとの会話を続けることができます。前回の応答に含まれるconversation_idをボットサーバーの中で一時保存することができれば、よりDifyのエージェント対話品質が上がりそうなのでやってみました。

LINE Botサーバーをカスタマイズする

前回routes/api/messaging.tsを以下のようにアップデートしました

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 DifyChatMessageResponse {
  event: string;
  task_id: string;
  id: string;
  message_id: string;
  conversation_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; 
}

declare interface DifyChatMessageRequest {
  // deno-lint-ignore ban-types
  inputs: {};
  query: string;
  response_mode: "blocking";
  user: string;
  conversation_id?: string;
}

declare type conversationIds = { userId: string, conversationId: string }[];
let conversationIds: conversationIds = [];
// deno-lint-ignore no-inferrable-types
let invervalId: number = 0;
const conversationCanselMin = 1;

const getConversationId = (event: MessageEvent): string|null => {
  const userId = event.source.userId;
  if (!userId) return null;
  if (conversationIds.length === 0) return null;
  for (const conversationId of conversationIds) {
    if (conversationId.userId === userId) {
      return conversationId.conversationId;
    }
  }
  return null;
}

const setConversationId = (event: MessageEvent, conversationId: string): void => {
  const userId = event.source.userId;
  let updated = false;
  if (!userId) return;
  if (invervalId) clearInterval(invervalId);
  for (let i = 0; i < conversationIds.length; i++) {
    if (conversationIds[i].userId === userId) {
      conversationIds[i].conversationId = conversationId;
      updated = true;
      break;
    }
  }
  if (!updated) {
    conversationIds.push({ userId, conversationId });
  }
  invervalId = setTimeout(() => {
    conversationIds = [];
  }, 1000 * 60 * conversationCanselMin);
};

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: DifyChatMessageRequest = {
      inputs: {},
      query: textMessage.text,
      response_mode: "blocking",
      user: "line-bot",
    };
    // get conversation id
    const conversationId = getConversationId(event);
    console.log(conversationId);
    if (conversationId) requestData["conversation_id"] = conversationId;
    const resp = await fetch("https://api.dify.ai/v1/chat-messages", {
      method: "POST",
      headers: {
	"Authorization": "Bearer ENTER-YOUR-SECRET-KEY",
        "Content-Type": "application/json",
      },
      body: JSON.stringify(requestData),
    });
    const res = await resp.json() as DifyChatMessageResponse;
    await client.replyMessage({
      replyToken: event.replyToken,
      messages: [
        {
          type: "text",
          text: res.answer,
        },
      ],
    });
    // set conversation id
    setConversationId(event, res.conversation_id);
    return new Response(null, { status: 204 });
  }
};

使ってみる

まず、コード更新前のBotの応答は以下のようになっていました。

Screenshot_20240728-154734.png

アスナの方は容姿についての説明になっていません。

コードを更新したサーバーを実行します

deno task start
Task start deno run -A --watch=static/,routes/ dev.ts
Watcher Process started.
The manifest has been generated for 7 routes and 1 islands.

 🍋 Fresh ready 
    Local: https://localhost:8000/

Screenshot_20240728-161805.png

アスナのほうも容姿について説明するようになりました。

conversation_idの保存方法

conversation_idをサーバー内に保持するためのコードは以下です

messaging.ts
const setConversationId = (event: MessageEvent, conversationId: string): void => {
  const userId = event.source.userId;
  let updated = false;
  if (!userId) return;
  if (invervalId) clearInterval(invervalId);
  for (let i = 0; i < conversationIds.length; i++) {
    if (conversationIds[i].userId === userId) {
      conversationIds[i].conversationId = conversationId;
      updated = true;
      break;
    }
  }
  if (!updated) {
    conversationIds.push({ userId, conversationId });
  }
  invervalId = setTimeout(() => {
    conversationIds = [];
  }, 1000 * 60 * conversationCanselMin);
};

LINEのuserIdとDifyのconversationIdを対にして配列に保存して、一定時間経つと揮発するようにしています。揮発までの時間はconversationCanselMinで任意に変更できます。

配列からconversationIdを取得するのは以下のコードです。

messaging.ts
const getConversationId = (event: MessageEvent): string|null => {
  const userId = event.source.userId;
  if (!userId) return null;
  if (conversationIds.length === 0) return null;
  for (const conversationId of conversationIds) {
    if (conversationId.userId === userId) {
      return conversationId.conversationId;
    }
  }
  return null;
}

おわりに

conversation_idを利用することで、前回よりも対話能力が高いボットサーバーにアップデートすることができました。Dify APIはシンプルで便利なのでLINE Botとの相性も良いと思います。

みなさんのDifyを利用したLINE Bot開発の参考になれば幸いです。

5
3
2

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
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?