0. 概要
この記事では、Dify で構築した AI エージェントをRaspberry Pi 4 (ラズパイ) の cron ジョブをトリガーとして定期実行し、日本の株価情報を取得・要約して Discord に毎日定刻で自動通知するシステム構築の方法について記載します。
実装の流れとしてはざっくり以下です:
- Dify ワークフローの構築
- Web Scraper ブロックによる情報収集
- LLM ブロックによる要約
- Discord Webhook を用いた通知連携
- Dify ワークフローを実行する Python スクリプトの作成
- Raspberry Pi にて cron を使った定期実行設定
1. 背景
趣味やプライベートの活動にかける時間が限られている人たちにとって、しょうもない雑務は自動化したいという欲求を持ったり、タイパ良く暮らしたいと思うことは、世間一般の共通認識と考えます。
子持ちで普通の会社員の自分も例に漏れず、夜中の少ないプライベート時間の中で、"やりたいこと"が"やらなきゃいけないこと"で埋もれていて、「あ~、今日もアレできなかったなぁ。また明日か、寝よ。」と悶々とした日々を送っています。
こういった現状を少しでも改善するべく、近頃進歩が目覚ましい AI エージェントを活用できないか、というのが辿り着いた一つの答えです(ありがちでしょうけどね)。
ということで、今回は、自動で情報収集・要約して通知するという、なんでも使えそうなシステムの構築を、Dify+ラズパイ+Discordで株式情報の取得/通知することを例としてシステムを作ってみました。
以下で実装について記載します。
2. Dify で AI ワークフローの構築
AI エージェント側について、今回は Dify を用います。
Dify(ディファイ)は、簡単に言うと、プログラミングの知識があまりなくても、AI を使ったアプリケーションを簡単に作れるツールです(もちろん、コードブロックとかはプログラミングの知識は必要です)。
具体的には以下のようなものが手軽に作成できます:
- ChatGPTのようなチャットボット
- Webサイトから情報を集めて要約するツール
- 質問に答えてくれるアシスタント
それでは、画面キャプチャとともに、順に作成方法を示します。
まずはこちら (https://dify.ai/jp) にアクセスします。
「今すぐ始める」をクリックすると、認証画面に遷移するので、好きな形式で認証してください。
認証が終わると、空のワークスペースが表示されます。
今回は web スクレイピングと Discord 通知を用いるので、ツールタブへ移動し、WebScrapper と Discord をインストールしてください。
スタジオのタブに戻り、ワークフロータブで「最初から作成」をクリックします。
すると作成画面が出るので、アプリタイプはワークフローを選択し、アプリのアイコンや名前はテキトーに設定して、「作成する」をクリックします。
すると、「開始」ブロックだけあるフローが表示されます。
この開始ブロックの右端の+ボタンを押すとポップアンプウィンドウが出て来るので、ツールタブの WebScrapper の Web Scrapper を選択します。
Web Scrapper ブロックをクリックすると設定のペインが開くので、スクレイピングして欲しい URL を入力変数の URL の欄に書き込みます。
ここでは、yahoo ファイナンスのニュースのページから情報を拾ってきて欲しいので、https://finance.yahoo.co.jp/news
を URL の欄に書き込みました。
USER AGENT についてはデフォルト値のままで問題ありません。
"WHETHER TO GENERATE SUMMARY" について、True ならばスクレイピング後に自動的に必要なところを要約してくれるのですが、今回はスクレイピングの生出力を LLM にて綺麗にしてもらうので、False を指定しました。
あとは、パット見でそのブロックが何をやってるか分かりやすくするために、ブロック名称も "stock news" などに適宜変更すると良いでしょう。
Webスクレイピングを行う際は、対象サイトの利用規約を必ず確認し、規約に違反しない範囲で行うようにしてください。
また、ストップ高/ストップ安の銘柄情報も取得したいので、それぞれ URL を https://finance.yahoo.co.jp/stocks/ranking/up
, https://finance.yahoo.co.jp/stocks/ranking/down
として同様にブロックを追加していきます。
次に LLM ブロックを追加し、先程作成した Web Scrapper ブロックを紐づけて、この LLM ブロックにスクレイピング結果を入力できるようにします。
LLM ブロックの設定としては以下のようにしました。
- AI モデル・・・・どの LLM モデルを用いるかを選択:
-
Gemini 2.0 Flash
を使用 - LLM モデルの利用にあたり API の認証が必要ですが、ここでは割愛します
-
- コンテキスト・・・・ナレッジを入れる:
- ここは空で問題ありません
- SYSTEM・・・・LLM 側における対話の基本動作や口調などを記載:
あなたは日本の株式市場の専門家です。 以下の情報に基づいて、今日の市場の主要なハイライトとトレンドを分かりやすく、簡潔に要約してください。 Discord通知に適した形式で、箇条書きなども活用して読みやすくまとめてください。
- USER・・・・LLM に対する指示や質問を記載(欄がない場合は + マークをクリックすることで追加可能):
- 下記のように記載しましたが、一つ注意点として、
{#ブロック名称.変数名}
となっているところはそのままコピペではなく、枠内で{
と入力することで変数の候補が出てくるので、それを選択することで添付画像のように変数として認識されるようになります
{{#stock news.text#}} 【今日の値上がり率上位銘柄】 {{#stock(up).text#}} 【今日の値下がり率上位銘柄】 {{#stock(down).text#}} ーーー 出力例: **今日の日本株ハイライト** - 日経平均は〇〇円で取引終了、〇〇円上昇(〇〇%) - 〇〇セクターが特に好調、〇〇セクターは軟調 - 主要ニュース: - 〇〇に関する経済指標が発表され、市場に〇〇の影響を与えました。 - 〇〇社の決算が発表され、株価に〇〇な動きがありました。 - 注目トレンド銘柄(ランキング/値上がり率/値下り率より、上位10位ずつ): - 〇〇 (コード: 〇〇) - 値上がり率〇〇% - 〇〇 (コード: 〇〇) - 出来高が急増 - (その他、ランキングから抽出した情報)
- 下記のように記載しましたが、一つ注意点として、
ここまでで情報取得と整理は終わったので、あとは Discord 通知のみです。
この通知の送受信をするために、Discord Webhook の設定を行いましょう(Discord そのものの導入については割愛します)。
基本的に個人しか使わないので、テキトーなサーバーを作り、テキトーなチャンネルの横にある歯車マークを押します。
遷移後の画面で「連携サービス」タブから、「ウェブフック」を選択し、「新しいウェブフック」を押してウェブフックを作成します。
名前は自由です。
ウェブフックが作成できたら、「ウェブフックの URL をコピー」を押下することで、URL をゲットできます。
LLM ブロックの + ボタンを押しツールタブから Discord の Incoming Webhook to send message を選択します。
INCOMING WEBHOOK TO SEND MESSAGE ブロックの設定は以下のようにします。
- content・・・・Discord で通知する内容:
- {{#LLM.text}} ← 枠内で
{
とタイプしたときにサジェストされる LLM.text を選択してください
- {{#LLM.text}} ← 枠内で
- Discord Webhook Username・・・・発言者みたいに表示される webhook の名称:
-
株式情報サマリ定期配信
としました
-
- DISCORD INCOMING WEBHOOK URL・・・・webhook のURL:
- 先程 Discord 側で作った webhook の URL をコピペします
最後に終了ブロックをつけて Dify 側は完成です。
それではデバッグしましょう。
全体のデバッグは実行ボタンから可能です。
実行が上手く行けば、以下のような通知が来ます。
これで、無事、Dify のワークフローが発火したら Discord に通知が行くことを確認できました。
外部から呼ぶ場合は公開する必要があるので、公開のボタンを押してワークフローを公開します。
3. 定期実行させるための設定
Dify 側だけではやりたいと思っている定期実行できません。
定期実行する方法としてはいくつか方法があるのですが、
- Github Actions から実行
- PC のタスクスケジューラから実行
の2パターンが主流です。
今回は、家庭内サーバーと化しているラズパイ4の cron ジョブで実行する python から定期実行するようにします。
そのためにはサービス API エンドポイント と API キーが必要であるため、以下から取得します。
まずは、画面左側のワークフローのオプションボタン(?)を押して、メニューを展開します。
そうすると、バックエンドサービス API のところに、サービス API エンドポイントが記載されており、こちらを控えておきます。
次に API キーの取得についてですが、ここのメニューで API キー ボタンを押します。
そうすると API シークレットキー のウィンドウがポップアップされるので、"+ 新しいシークレットキーを作成" を押します。
ここで出てきたキーを、python から Dify を実行する際に用います。
API キーについては流出しないよう、リポジトリであれば .gitignore するとかの対策を講じてください。
次に PC 側ですが、ここからは python 環境がある前提で進めます(python 環境の構築については他をご覧ください)。
もちろん pip / poetry / conda など好き好きで構いませんが、パッケージマネージャーは個人的に好みの uv を用いることとします。
どこでも良いのでソースを置くディレクトリを作成します。
今回は、dify_runner
とし、uv で仮想環境を作成します。
mkdir ~/dify_runner
cd ~/dify_runner
uv init
uv add pytz requests PyYAML
mkdir src
mkdir key
~/key/dify_api_key_url.yml
という名前で以下設定値を記載しておきます。
url: {サービス API エンドポイント}/workflows/run
key: {先程取得した API キー}
実行ファイルとしては ~/src/run_dify_agent_daily_stock_info.py
を新規作成し、以下コードをコピペします。
import datetime
from pathlib import Path
import pytz
import requests
from yaml import safe_load
def main():
path_key = Path(__file__).resolve().parent.parent / "key/dify_api_key_url.yml"
assert path_key.exists(), FileNotFoundError()
with path_key.open(mode="r") as f:
key_url = safe_load(stream=f)
dify_api_key = key_url["key"]
dify_api_url = key_url["url"]
if not dify_api_key or not dify_api_url:
print("error: キーもしくは url が空です")
exit(1)
try:
print(f"[{now()}] Dify agent を起動")
response = requests.post(
url=dify_api_url,
headers={
"Authorization": f"Bearer {dify_api_key}",
"Content-Type": "application/json",
},
json={
"inputs": {},
"response_mode": "blocking",
"user": "raspberry_pi_scheduler",
},
timeout=300,
)
if response.status_code != 200:
print(
"Dify APIからエラーレスポンス: ",
f"{response.status_code} - {response.text}"
)
exit(1)
response.raise_for_status()
except requests.exceptions.RequestException as e:
print(f"[{now()}] Dify API の呼び出しに失敗しました: {e}")
exit(1)
except Exception as e:
print(f"[{now()}] 予期せぬエラー: {e}")
exit(1)
def now() -> datetime.datetime:
return datetime.datetime.now(pytz.timezone("Asia/Tokyo"))
if __name__ == "__main__":
main()
exit()
最後に、この python ファイルを cron ジョブで毎日 23 時に自動実行させる設定をします。
コマンドラインから crontab -e
と入力して enter で設定ファイルが開くので、以下1行をファイル末尾にコピペします。
{コメントや他の設定など}
0 23 * * * /{リポジトリの絶対パス}/.venv/bin/python /{リポジトリの絶対パス}/src/run_dify_agent_daily_stock_info.py >> /{リポジトリの絶対パス}/src/dify_agent.log 2>&1
これで毎日 23 時になったら、株式情報のサマリー・S高/S安銘柄情報が流れてくるようになりました。
通知については、デバッグで確認した以下通知のようなものが来ます。
4. おわりに
今回は例として株式情報をまとめて自動通知しましたが、Web Scrapper でスクレイピングするサイトを変えたり、LLM ブロックのプロンプトを変えるだけで、フレームワークそのままで同じように欲しい情報が定期的に Discord 通知できるようになります。
発展形としては、コードブロックを使ってスクレイピングしたデータに対して python でさらに高度なデータ分析を行ったり、ナレッジブロックを使って特定の企業のIR資料をナレッジとして取り込み、その企業に関する質問に答えるAIエージェントを作成するなど色々拡張できるので、皆さんも Dify で遊んでみたり、日常の不要なルーチンを Dify でキャンセルしていきましょう。