2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

DifyAdvent Calendar 2024

Day 2

日報フィードバックアプリをDifyで構築してみた!

Last updated at Posted at 2024-12-02

こんにちは、ふくちです。

アドベントカレンダー Dify編2日目の記事です!投稿が遅れてしまって申し訳ありません🙇‍♂️

初めてDifyを触っているので大したプロダクトではないですが、自分が欲しいものを作ってみました!

今回作りたかったもの

一言で言えば、日報フィードバックアプリです。
その日やったことを記録すれば、AIがフィードバックしてくれるようなイメージですね。
そしてそれをNotionにまとめて、後で自分の成長を振り返られるようにしたい。

このアプリを作る目的としては、自身がより技術力を高めるための習慣付けをすることです。
要するに、エンジニアとしてより成長するための土台を作りたい、ということです。

しかし、ただ闇雲に、あるいは漠然と行動だけしていても、あまり成長できません。
成長のためには、「目標・行動・振り返り・改善」 が必要だと私は考えています。

ただ、この中の「振り返り・改善」って1人でやるのは結構難しいですよね。
客観的な評価や、それをベースにした改善策というのは1人ではなかなか思いつきませんし、時間もかかるので後回しにしてしまいがちです。

そこで、その日の自身の行動を振り返って、それを分析・添削・保存してくれるようなアプリを開発してみよう!となった次第です。

構成

このアプリのワークフローとしては以下の通りです。

  1. 日報を入力する
  2. 日報データをJSON形式に変換する
  3. データをNotonに転送する

この1~3をDify上で実現してみます。

1.Notionの準備

まずはNotionで日報保存用のデータベースを作成します。
このアプリにおけるNotionに到達するまでの流れとしては、以下の感じです。

Difyに日報送信 → Dify上でAIがフィードバックコメント作成 → DifyからNotionに送信

ということで、Dify上でどんな形に整形するかが鍵になりそうです。

また、後から振り返った時の見やすさを考えた結果、以下のようなプロパティでやってみることにしました。

  • 日付
  • 合否判定
  • フィードバック

image.png

合否判定は、その日の中で自己研鑽できたかを評価してもらいます。具体的な方が良さそうなので、ここでは「ブログ作成時間が2時間以上あったか」を基準とします。

※PoCなので、ひとまずこれで進めることにしました。
データが足りなかったり粒度が荒すぎたりした場合は後々修正しようと思います。

2.Notion Integrationの作成

DifyとNotionを接続するためには、このNotion Integrationというのが必要だそうです。

Notion Integrationとは…
外部ツール(Dify, Jira, Google Drive, Slackなど)をNotionに接続してワークフローを構築・強化できるようになる、というもの

https://www.notion.com/ja/integrations

1.Notion Integration管理ページにアクセス

2.「新しいインテグレーションの作成」をクリックする

3.以下の感じで設定する

  • 任意のインテグレーション名をつける(ここではDifyと命名)
  • 関連ワークスペース:先ほど作成したDBが存在するワークスペースを選択
  • 種類:内部(Internal)

image.png

4.インテグレーションの設定を開き、「内部インテグレーションシークレット」をコピー
→コピーする際は「表示」をクリックすることで、「コピー」の選択肢が出てきました。

image.png

ちなみにですが、設定ページの下部で権限設定も行えるようです。
デフォルト設定はこんな感じ。
image.png

5.Notionに戻って、以下の操作を行う

  • 作成したデータベースページを開く
  • 右上の3点メニューの中にある「接続先」を開く
  • 先ほど作成したインテグレーションを選択する

image.png

すると、こんな感じで接続が確保され、編集権限が表示されるようになります。
image.png

6.NotionデータベースのURLから、データベースIDを抜き出しておく
先程同様に3点メニューを開き、今度は「リンク/をコピー」を選択します。
→すると、 https://notion.so/XXXXXXXX?v
image.png

3.Difyでワークフローを構築

ようやくDifyの構築です。
今回はアプリケーションを新規作成していきます。タイプはワークフローです。
image.png

最終的に完成したワークフローはこんな感じです!
image.png

試しに実行してみると、無事成功し、Notionに登録されていました!
image.png

image.png

まぁ、ブログの内容なんてどこにも書いてないのに妄想で「内容がわかりやすく」なんて言われているので使い物にはなっていないのですが…ひとまずやりたいことはできた!ということで。

各ノードの工夫ポイント

工夫というか、ほぼエラー対処…という感じですが、上から順番にいきましょう。

LLMのプロンプト

最初のLLMでは、日報に対してフィードバックを作成しています。
image.png

プロンプトは最終的にこんな感じになりました。
image.png

コンテキストとして日報の入力を明示的に渡しているのは、こうしないと全然正しく評価してくれなかったからです。
「ブログ作成時間が2時間以上あれば合格」という条件にしており、日報で「ブログ作成時間3時間」としているにも関わらず、判定が不合格にされてばかりでした。
image.png

これを解消するために、コンテキストとしてプロンプトの中に直接日報入力データを渡すようにしたところ、正しく判定してくれるようになりました。

またこの時、後でNotionに渡しやすくするため、JSON形式にしてあります。
Difyではモデル選択画面でレスポンスフォーマットをJSONオブジェクトなどで指定できるということで、これは非常に使いやすいなと思いました!
image.png


コードノード

LLMが出力したJSONをパースしてオブジェクト形式に変換します。
その後、変数として judgementfeedback を出力し、後続の処理に渡しています。
image.png


日時取得ノード

続いて、Notionに格納するための日付を取得します。
日報なので、あまり細かい時間の計測は不要と判断し、年月日だけ取得しています。日本時間で取得してくれるのもありがたかったです!
image.png


出力形式をテンプレート化

ここで、Notionが受け取るためのフォーマットに整形します。
image.png

フォーマットとしては以下の感じになりました。
{{ }} で囲われているのは、Dify上の入力変数を渡しているためです。

template.json
{
  "parent": { "database_id": "{{ db_id }}" },
  "properties": {
    "Date": {
      "title": [
        {
          "text": {
            "content": "{{ time }}"
          }
        }
      ]
    },
    "judgement": {
      "rich_text": [
        {
          "text": {
            "content": "{{ judgement }}"
          }
        }
      ]
    },
    "feedback": {
      "rich_text": [
        {
          "text": {
            "content": "{{ feedback }}"
          }
        }
      ]
    }
  }
}

このNotionのフォーマットで本当に悪戦苦闘しました…


LLMノードその2とHTTPリクエスト

続いて、再びLLMノードを通った後、HTTPリクエストを実行してNotionへのアクセス・データ保存を試みます。
image.png

ここのLLMの役割としては、HTTPリクエストボディにある文字列をエスケープ処理すること。
そして最終的に、望んだ形のリクエストボディだけを返してもらっています。
image.png

その値を持ったうえで、HTTPリクエストを送信します。
ここで指定したURLは、Notion APIでデータを保存する際に使用するAPIのようです。
image.png

また、認証APIキーには、環境変数として設定したNotionインテグレーションのシークレットキーを指定しています。
image.png

なぜこのようにしているかというと、テンプレートで整形したフォーマットをそのままHTTPリクエストに渡すと、エラーが出たためです。
一部だけお見せするとこんな感じです。
image.png

image.png

これらを調べたり、Claudeに原因を聞いたりした結果、どうやらエンコーディングでの問題が起こっているとのことでした。

追加で調査していると、エスケープ処理をした上でHTTPリクエストに送信している方がいたので見様見真似で試したところ、上手くいったという感じでした。

正直何が起こってるのか理解できていないので、ここは別途キャッチアップしておきます…


ということで、各ノードでやっていることのご紹介でした!
image.png

簡単なエラーハンドリング

最後はステータスコードを確認して、OKかそうじゃないかを確認しています。
エラーだった場合はリクエストのbodyが返されます。
image.png


環境変数

最後に、設定した環境変数について簡単にご紹介しておきます。
Notionとの連携に必要不可欠なので…
image.png

変数名 タイプ
NOTION_VERSION 2022-06-28 String
NOTION_DATABASE_ID ※<データベースID> Secret
NOTION_INTEGRATION_SECRET_KEY <シークレットキー> Secret
END Notionへの登録が完了しました! String

NotionのデータベースIDについてですが、設定する際にハイフンで区切る必要があります。

というのも、NotionデータベースのページからデータベースIDを取得してそのまま環境変数の値に格納していたのですが、ステータスコード400が返ってきてしまい、データを保存できていませんでした。
image.png

この時、「データベースIDはUUIDの形である必要がある」と指摘されていました。
それに倣って、「8桁-4桁-4桁-4桁-12桁 」の形に変換して格納したところ、成功しました!

ここは注意しておかないとドツボにハマりそうなので気をつけましょう!


まとめ

初めてDify使ってみたのですが、直感的に扱えて非常に面白かったです!
ただ、GUIでワークフロー組むだけなんだから簡単だろうと思っていたら、構築に丸2日かかりました…想像以上に難しかったです。

構築に時間がかかりすぎて投稿日(12/2)も超過してしまい申し訳ありませんでしたmm

なにはともあれ、なんとかやりたかったことが実現できました!
しかしまだまだ理想には程遠いので、この経験を土台にして少しずつDifyでの開発に慣れていきたいと思います!


参考にさせていただいたブログのリンクをこちらに掲載しておきます。

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?