見出し画像

DifyとDiscordを連携させてみよう!

Difyで作ったアプリのインターフェースとしてDiscordを利用

Difyは作成したチャットボットやワークフローをアプリとして公開することが簡単にできます。Dify単体でもインタフェースを提供しているため、公開すること自体のハードルはとても低いです。
こちらの記事でDifyの機能を使ってチャット画面を簡単に公開する手順を紹介しています。

アプリを実行をするとそのままチャット画面が作れる
こんな感じのチャット画面がDifyだけでできる

一方で、インタフェースの好みは人それぞれで新しいインタフェースを利用することはそれだけでハードルとなり、せっかく頑張ってワークフローを作ってもタッチポイントが合わなければ利用することは少なくなってしまいます。

そこで!
Difyは作ったアプリやワークフローをAPIによって利用することができるため、APIを利用して今回はDiscordとつないでみます。

DifyとDiscordをつないでみよう!

実行環境

Windows11 WSL2 ubuntu
Dify:0.6.5(Docker)
cursor
python:3.11.0
※Discord以外はすべてローカル環境で開発、実行します

全体のイメージ

処理シーケンス

Discordボットの準備

まずはインタフェースとなるDiscordのボットを作ります。
今回は自分のサーバにボットを入れるため、自サーバをサクッと構築します。

ボットはDiscordのデベロッパーサイトから作成します。

ボットを作成したらトークンと権限の設定を行います。
トークンは作成したボットから「bot」から「Reset Token」を取得します。
ここで取得したトークンは後程、Pythonのスクリプトに使いますのでメモしておいてください。また、トークンは人に見せないように気を付けましょう。

画像下部にある、Reset TokenでTokenを取得

トークンを取得したらそのまま下へスクロールし、ボットの権限設定を行います。イベントやメッセージを取得できるようにPRESENCE INTENTMESSAGE CONTENT INTENTを有効にします。

PRESENCE INTENTとMESSAGE CONTENT INTENT

次に、自サーバにボットを招待するため「OAuth2」を選択し、OAuth2 URL Generaterで「bot」をチェックします。

今回はbot以外の設定はしません。ここも深堀っていきたいところ

「GENERATED URL」にURLが表示されますのでコピーしてブラウザの検索バーに入力してください。
そうするとアクセス要求の画面が表示されます

アクセス認証の画面

追加先のサーバは作成した自サーバを選択し、「認証」選択しましょう。
成功すると以下のように自サーバに作成したボットが追加されます。

Difyでチャットアプリの作成

次はDifyでチャットアプリを作成します。チャットアプリは以下の記事で作り方を紹介していますので、本記事では作成は省略します。

チャットアプリの作成まで行ったら、「公開」を選択し、「APIリファレンスにアクセス」を選択します。

APIリファレンスの画面から「APIキー」よりAPIキーを取得してください。
こちらのPythonのスクリプトに使いますのでメモをとってください。

APIリファレンス画面

Difyでの作業はここで完了ですが、このAPIリファレンスに基づいてPythonのコードを作成することになります。

余談
筆者はこのAPIリファレンスをmdファイルとして保存し、cursorで読み込ませて質問をしながらPythonのスクリプトを作成しました。

Discordボットを制御するコードの作成

実装するコードは以下となります。
適当なフォルダを作成し、Pythonスクリプトを作成してください。
トークンやAPIキーはPythonスクリプトと同階層に.envファイルを作成し、TOKEN={トークン}DIFY_API_KEY={APIキー}を書いて読み込ませるようにしています。

import os                                               # OS機能へのアクセスを提供するモジュールをインポート
import discord                                          # discord APIを利用するためのモジュールをインポート
from discord.ext import commands                        # discordのコマンド拡張機能をインポート
from dotenv import load_dotenv                          # .envファイルから環境変数をロードするためのモジュールをインポート
import aiohttp                                          # 非同期HTTPリクエストを行うためのモジュール

# 環境変数をロード
load_dotenv()                                           # .envファイルから環境変数をロード
# botのアクセストークン
TOKEN = os.getenv("TOKEN")                              # Discord botのトークンを環境変数から取得
DIFY_KEY = os.getenv("DIFY_API_KEY")                    # DIFY APIのキーを環境変数から取得

# 必要なIntentsを設定
intents = discord.Intents.default()
intents.messages = True
intents.message_content = True

client = commands.Bot(command_prefix='!', intents=intents)  # コマンドプレフィックスを'!'に設定したBotクライアントを作成

@client.command()                                       # コマンドデコレータを使用してchat関数をコマンドとして登録
async def chat(ctx, *, query: str):                     # chatコマンドの非同期関数定義
    url = 'http://localhost/v1/chat-messages'           # APIのURLを設定
    headers = {                                         # HTTPリクエストヘッダを設定
        'Authorization': f'Bearer {DIFY_KEY}',          # 認証用のBearerトークンを設定
        'Content-Type': 'application/json'              # コンテンツタイプをJSONに設定
    }
    data = {                                            # POSTリクエストのボディデータを設定
        'query': query,                                 # ユーザーからのクエリ
        'response_mode': 'blocking',                    # レスポンスモードをblockingに設定
        'user': 'user_identifier',                      # ユーザー識別子
        'conversation_id': '',                          # 会話ID(空の場合は設定なし)
        'inputs': {}                                    # APIが要求する追加のパラメータ
    }
    
    async with aiohttp.ClientSession() as session:      # 非同期HTTPセッションを開始
        async with session.post(url, headers=headers, json=data) as response:  # POSTリクエストを非同期で送信
            if response.status == 200:                  # HTTPステータスコードが200の場合
                json_response = await response.json()   # レスポンスのJSONを非同期で読み込み
                answer = json_response.get('answer', 'No answer provided.')  # JSONからanswerを取得、なければデフォルトメッセージ
                await ctx.send(answer)                  # Discordチャンネルに回答を送信
            else:                                       # HTTPステータスコードが200以外の場合
                error_message = await response.text()  # エラーメッセージの内容を取得
                await ctx.send(f'APIエラー: {response.status}, メッセージ: {error_message}')  # エラーメッセージを送信

client.run(TOKEN)                                       # Discordクライアントを実行

これで準備完了です!
今回はDiscordの入力時に、「!chat」と入れることでボットが入力に反応できるようにしています。

Discordから質問をしてみよう!

質問の前に、Pythonスクリプトを実行しておきます。
エラーが出なければOK

こんな感じで表示されてればOK

Dify側も起動しておきます。
チャットアプリのステータスが「稼働中」となっていることを確認してください。

ステータスが稼働中になっている

ここまできたら準備完了です!Discordから質問文を送ってみましょう。
では、「カレーの作り方」を聞いてみましょう!

ボットから返答が!
Discordで入力したメッセージがDifyに届いて、チャットアプリが回答してくれています

これで、DifyとDiscordの連携は完了です!お疲れ様でした!


次にやりたいこと

今回はDifyとDiscordを連携し、Discordで入力した内容に対してDifyから回答する方法をご紹介しました。
しかし、今回ご紹介した方法はローカル環境で作っていることもあり、PCをシャットダウンしたり、Pythonスクリプトを実行しているcursorなどの閉じてしまうと動かなくなってしまいます。
24時間いつでもどこでもDiscordからDifyにつなげられるように、DifyとPythonスクリプトをクラウドへデプロイする方法を試していきたいと思います。