Paper-Essence — チュートリアル: 自動論文要約ワークフローの構築
プロジェクト概要
Paper-Essenceは、Difyプラットフォーム上に構築された自動論文要約ワークフローです。このワークフローは以下のことができます。
毎日、指定された研究分野の最新論文をarXivから取得する
大規模言語モデルを使用して、最も価値のある論文をフィルタリングし、選択する
OCRでPDF論文を解析し、技術的な詳細を抽出する
構造化された日次要約を生成し、メールで送信する
GitHubリポジトリ: github.com/LiaoYFBH/PaperFlow — prj/Paper-Essence-CN.ymlまたはprj/Paper-Essence-EN.ymlを直接インポートできます。
前提条件
1. プラットフォームとアカウント
- Difyアカウント: Difyに登録してログインします
- メールアカウント: SMTP対応のメール(このチュートリアルでは163 Mailを使用)
- LLM API: Xinghe Community APIを設定します
2. 必要なプラグインのインストール
Difyプラグインマーケットプレイスから以下のプラグインをインストールします。
| プラグイン | 目的 |
|---|---|
paddle-aistudio/ernie-paddle-aistudio |
Xinghe Community API |
langgenius/paddleocr |
PDFおよび画像のOCR |
wjdsg/163-smtp-send-mail |
163 SMTPメール送信 |
langgenius/supabase |
プッシュされたレコードのデータベースストレージ |
3. Supabaseデータベースの準備
重複を避けるため、すでにプッシュされた論文を記録するためにクラウドデータベース(Supabase)を使用します。
ステップ1: ログインとプロジェクト作成
supabase.comにアクセスしてアカウントを作成し、新しいプロジェクトを開始します。
ステップ2: テーブルの作成
SQLエディタで、以下のSQLステートメントを実行して、プッシュされた論文IDを記録し、重複がないことを確認するテーブルを作成します。
create table pushed_papers (
arxiv_id text not null,
pushed_at timestamp default now(),
primary key (arxiv_id)
);
ステップ3: APIキーの取得
プロジェクト設定 → APIセクションに移動して、資格情報を確認します。
以下の情報を記録します。
NEXT_PUBLIC_SUPABASE_URL→ Difyプラグイン用のSupabase URLNEXT_PUBLIC_SUPABASE_PUBLISHABLE_DEFAULT_KEY→ Difyプラグイン用のSupabaseキー
ステップ4: DifyでのSupabaseプラグインの設定
Difyで、プラグインマーケットプレイスに移動し、Supabaseプラグインを見つけて、前のステップで取得したURLとキーを入力します。
(オプション) DockerでDifyをデプロイする
環境設定
このチュートリアルではWSL + Dockerを使用します。WSLとDockerの設定については、Microsoftのドキュメントを参照してください。
Difyリポジトリのクローン
まず、Difyリポジトリをクローンします。Gitを設定していない場合は、リポジトリページからZIPファイルを直接ダウンロードして解凍できます。
Gitを設定している場合は、ターミナルで以下のコマンドを実行します。
# Clone Dify repository
git clone https://github.com/langgenius/dify.git
GitとDockerが設定されている必要があります。
# Navigate to docker deployment directory
cd dify/docker
# Copy environment configuration file
cp .env.example .env
まず、Docker Desktopを開き、ターミナルで以下を入力します。
# Start Dify (this will automatically pull images and start all services)
docker compose up -d
ステータスを確認します。
docker compose ps
アプリケーションにアクセス: http://localhost/
ワークフローアーキテクチャ
ワークフローは以下の主要な流れに従います。
スケジュールトリガー → 設定 (コード) → LLM翻訳 (LLM - トピック翻訳) → 行の取得 (ツール - プッシュされた論文の確認) → 検索前処理 (コード) → HTTPリクエスト (http-request) → 検索後処理 (コード) → LLM初期レビュー (LLM) → JSON解析 (コード) → イテレーション (各論文について: データアンパック (コード) → 行の作成 (ツール) → ドキュメント解析 (ツール - OCR) → get_footnote_text (コード) → truncated_text (コード) → 分析 (LLM) → データアセンブリ (コード)) → テンプレート変換 (template-transform) → 163 SMTPメール送信者 (ツール) → 出力 (終了)
このワークフローの全体像:
ステップバイステップ設定
ステップ1 — ワークフローの作成
- Difyにログインします
- スタジオで「アプリを作成」をクリック → 「ワークフロー」を選択します
- アプリケーション名を入力します
- ワークフローのトリガータイプを選択します
ステップ2 — 環境変数の設定
右上隅の「設定」ボタンをクリックし、「変数を追加」を選択します。
これらの環境変数は、下流ノードのために処理および出力を行うConfigurationノード(コードノード)によって読み取られます。
主要な変数:
| 名前 | タイプ | 説明 | 例 |
|---|---|---|---|
table_name |
string | Supabaseテーブル名 | pushed_papers |
SMTP_PORT |
string | SMTPポート | 465 |
SMTP_SERVER |
string | SMTPサーバー | smtp.163.com |
SMTP_PASSWORD |
secret | SMTP認証コード | (あなたの認証コード) |
SMTP_USER |
secret | SMTPユーザー/メール | your_email@163.com |
MY_RAW_TOPIC |
string | 研究トピック | agent memory |
ステップ3 — スケジュールトリガー
ノード名: Scheduled Trigger
設定:
- トリガー頻度: 毎日
- トリガー時間:
8:59 AM(または必要に応じて調整)
ステップ4 — 設定 (コードノード)
ノード名: Configuration (タイプ: code) — このコードノードは、環境変数を読み込み、処理し、ダウンストリームノード用の設定値を出力します。
入力変数:
- 環境変数から:
SMTP_PORT,SMTP_SERVER,SMTP_USER,SMTP_PASSWORD,MY_RAW_TOPIC,table_name
出力変数:
raw_topic: 研究トピックuser_email: 受信者メールfetch_count: 取得する論文数 (デフォルト: 50)push_limit: プッシュ制限 (デフォルト: 3)days_lookback: 遡る日数 (デフォルト: 30)- およびSMTP設定
ステップ5 — LLM翻訳 (LLMノード)
ノード名: LLM trans (タイプ: llm) — 研究トピックをarXiv用の最適化された英語のブールクエリに変換します。
モデル設定:
- モデル:
ernie-4.5-turbo-128kまたはernie-5.0-thinking-preview。深層思考モデル (ernie-5.0-thinking-preview) を選択する場合、推論形式の分離を有効にする必要があります。 - 温度:
0.7
プロンプトルール: 中核となる概念を抽出し、用語を翻訳し (必要に応じて)、AND/OR を使用してブール論理を構築し、フレーズを引用符で囲み、クエリ文字列のみを出力します。
ステップ6 — プッシュ済みレコードのクエリ (Supabaseノード)
ノード名: Get Rows (タイプ: tool - Supabaseプラグイン) — 重複を避けるために、既存のプッシュ済みarXiv IDを取得します。
設定:
- テーブル名:
{{table_name}}(設定ノードから)
ステップ7 — 論文検索 (3ノード)
安定性と保守性を向上させるため、検索機能は「前処理」→「HTTPリクエスト」→「後処理」に分割されています。
7.1 検索前処理 (コードノード)
ノード名: Search Pre-process (タイプ: code) — arXiv APIリクエストを構築し、検索パラメーターを準備します。
入力変数:
topic: 翻訳された英語の検索語days_lookback: 遡る日数count: 取得する論文数supabase_output: すでにプッシュされたレコード (重複排除用)
コードロジック:
- カットオフ日を計算 (
cutoff_date) - Supabaseが返したプッシュ済み論文IDリストを解析
- トピックに基づいてブールクエリ文字列を構築 (AND/ORロジックをサポート)
- トピックキーワードに基づいてarXivカテゴリ制限を追加 (例: cs.CV, cs.CL)
- 後続のフィルタリングのために検索キーワードを抽出
出力変数:
base_query: 構築されたクエリ文字列pushed_ids: すでにプッシュされたIDのリストcutoff_str: カットオフ日文字列search_keywords: 検索キーワードのリストfetch_limit: APIフェッチ制限
7.2 HTTPリクエスト (HTTPノード)
ノード名: HTTP Request (タイプ: http-request) — arXiv APIを呼び出して生のXMLデータを取得します。
設定:
- API URL:
http://export.arxiv.org/api/query - メソッド:
GET
7.3 検索後処理 (コードノード)
ノード名: Search Post-process (タイプ: code) — XMLレスポンスを解析し、論文をフィルタリングします。
入力変数:
http_response_body: HTTPノードのレスポンスボディ- および前処理ノードからのすべての出力変数
コードロジック:
- XMLレスポンスを解析
- 重複排除フィルタリング:
pushed_ids内の論文を削除 - 日付フィルタリング:
cutoff_dateより古い論文を削除 - キーワードフィルタリング: タイトルまたは要約に少なくとも1つの検索キーワードが含まれていることを確認
- 出力をJSONオブジェクトリストとしてフォーマット
出力変数:
result: 最終的にフィルタリングされた論文リスト (JSON文字列)count: 最終的な論文数debug: デバッグ情報 (フィルタリング統計を含む)
ステップ8 — LLMによる初期レビュー
ノード名: LLM Initial Review (タイプ: llm) — LLMを使用して、上位論文 (トップ3) をスコアリングおよび選択します。
出力要件:
- 整形されたJSON配列形式
- すべての元のフィールドを保持
- 上位3論文を出力
ステップ9 — JSON解析 (コードノード)
ノード名: JSON Parse (タイプ: code) — LLM出力を正規化された論文リストに寛容に解析します。
コアロジック:
- ネストされたJSONを処理
papersまたはtop_papersフィールドをサポート- エラー耐性のある処理
ステップ10 — イテレーションノード
ノード名: Iteration — 選択された各論文を順次処理します (アンパック、Supabaseへの記録、PDFのOCR処理、LLMによる分析、最終オブジェクトの組み立て)。
設定:
- 入力:
top_papers(論文配列) - 出力:
merged_paper(処理済み論文オブジェクト) - 並列モード: オフ (順次実行)
- エラー処理: エラー時に停止
イテレーション内部フロー
| ノード名 | タイプ | 機能 | |
|---|---|---|---|
| 1 | DataUnpack | code | イテレーション項目を個々の変数にアンパック |
| 2 | Create a Row | tool | 重複を防ぐためにarxiv_idをSupabaseに記録 |
| 3 | Document Parsing | tool | PaddleOCRがPDFを解析してテキストを抽出 |
| 4 | get_footnote_text | code | 脚注情報を抽出 (所属認識用) |
| 5 | truncated_text | code | OCRテキストを切り詰める (LLM入力長を制御) |
| 6 | Analysis | llm | 主要情報を抽出するための詳細分析 |
| 7 | Data Assembly | code | 最終的な論文オブジェクトを組み立てる |
イテレーションアイテムを個別の変数にアンパックします。
出力:
title_str: 論文タイトルpdf_url: PDFリンクsummary_str: 要旨published: 公開日authors: 著者arxiv_id: ArXiv ID
10.2 行を作成 (Supabaseノード)
重複プッシュを防ぐため、論文のArXiv IDをデータベースに記録します。
設定:
- テーブル名: Configurationノードから
- データ:
{\"arxiv_id\": \"{{arxiv_id}}\"}
10.3 ドキュメント解析 (PaddleOCRノード)
ノード名: Document Parsing (タイプ: tool - PaddleOCR)
PaddleOCR (LLMではない) を使用して論文PDFを解析し、OCRを介してテキストコンテンツを抽出します。
設定:
file: PDF URLfileType: 0 (PDFファイル)useLayoutDetection: true (レイアウト検出を有効にする)prettifyMarkdown: true (出力を整形する)
10.4 get_footnote_text (コードノード)
OCRテキストから脚注情報を抽出し、その後の所属認識に利用します。
10.5 truncated_text (コードノード)
LLMの入力長を制御し、トークン制限を超えないようにOCRテキストを切り詰めます。
10.6 分析 (LLMノード)
ノード名: Analysis (タイプ: llm)
論文の深層分析を実行し、主要な情報を抽出します。
抽出フィールド:
- One_Liner: 1文での課題と解決策
- Architecture: モデルアーキテクチャと主要なイノベーション
- Dataset: データソースと規模
- Metrics: 主要なパフォーマンス指標
- Affiliation: 著者の所属
- Code_Url: コードリポジトリリンク
コア原則:
- 無駄を省く: 特定の方法を直接記述する
- 詳細に深く掘り下げる: アルゴリズムロジック、損失関数設計を要約する
- データ優先: SOTAに対する改善を示す
- N/Aなし: 合理的な推論を行う
出力形式: 純粋なJSONオブジェクト
10.7 データアセンブリ (コードノード)
ノード名: Data Assembly (タイプ: code)
すべての情報を構造化された論文オブジェクトに組み立てます。
コア機能:
- 公開ステータスの解析 (トップカンファレンス論文を特定する)
- LLM出力JSONの解析
- コードリンクの抽出
- 最終的な論文オブジェクトの組み立て
出力フィールド:
title: タイトルauthors: 著者affiliation: 所属pdf_url: PDFリンクsummary: 英語要旨published: 公開ステータスgithub_stats: コードステータスcode_url: コードリンクai_evaluation: AI分析結果
ステップ 11 — テンプレート変換
ノード名: Template Transform (タイプ: template-transform)
Jinja2テンプレートを使用して、論文データを整形されたメールコンテンツに変換します。
テンプレート構造:
📅 PaperEssence Daily
Based on your specified research topic "{{ raw_topic }}", here are the top 3 papers selected from ArXiv updates in recent times.
--------------------------------------------------
--------------------------------------------------
⚠️ Note: Content is AI-generated and for academic reference only. Please verify by checking the original PDF before citing or conducting in-depth research.
Date: {{ items.target_date | default('Today') }}
==================================================
{# Automatically adapt data structure #}
{% set final_list = items.paper | default(items) %}
{% for item in final_list %}
📄 [{{ loop.index }}] {{ item.title }}
--------------------------------------------------
👤 Authors: {{ item.authors }}
🏢 Affiliation: {{ item.affiliation }}
🔗 PDF: {{ item.pdf_url }}
📅 Status: {{ item.published }}
{% if item.code_url and item.code_url != 'N/A' %}
📦 Code: {{ item.github_stats }}
🔗 {{ item.code_url }}
{% else %}
📦 Code: {{ item.github_stats }}
{% endif %}
Abstract:
{{ item.summary | replace('\n', ' ') }}
🚀 Core Innovation:
{{ item.ai_evaluation.One_Liner }}
📊 Summary:
{# Use newlines and indentation for hierarchy, not relying on HTML tags #}
--------------------------------------------------
🏗️ Architecture:
{{ item.ai_evaluation.Architecture | replace('\n- ', '\n\n 🔹 ') | replace('- ', ' 🔹 ') }}
💾 Dataset:
{{ item.ai_evaluation.Dataset | replace('\n- ', '\n\n 🔹 ') | replace('- ', ' 🔹 ') }}
📈 Metrics:
{{ item.ai_evaluation.Metrics | replace('\n- ', '\n\n 🔹 ') | replace('- ', ' 🔹 ') }}
==================================================
{% else %}
⚠️ No new papers today.
{% endfor %}
ステップ 12 — メール送信 (163 SMTP)
ノード名: 163 SMTP Email Sender (タイプ: tool - 163-smtp-send-mail)
設定:
username_send: 送信者メールアドレス (環境変数SMTP_USER経由)authorization_code: メール認証コード (環境変数SMTP_PASSWORD経由)username_recv: 受信者メールアドレス (Configurationノードから)subject:PaperEssence-{{cutoff_str}}-{{today_str}}content: テンプレート変換からのコンテンツ
注: これらのパラメータ名 (username_send、authorization_code、username_recv) は163 SMTPプラグインに固有のものです。
ステップ 13 — 出力ノード
ノード名: Output (タイプ: end)
デバッグと検証のために最終結果を出力します。
ワークフローAPIの公開と取得
ワークフローが正しく動作することを確認し、テストした後、右上隅の「公開」ボタンをクリックします。
以下の情報を記録してください。
- APIエンドポイント:
https://api.dify.ai/v1/workflows/run(Difyクラウドデプロイの場合) またはプライベートデプロイURL (例:http://localhost/v1/workflows/run) - APIキー:
app-xxxxxxxxxxxx
代替案: ローカルスケジュールトリガー (Windowsタスクスケジューラ)
Difyクラウドのスケジューリングが無料枠で制限されている場合、Windowsタスクスケジューラを使用してcurl POST経由でワークフローをトリガーできます。
前提条件: Git for Windowsのインストール
このソリューションはGit Bashを使用してcurlコマンドを実行するため、まずGit for Windowsをインストールする必要があります (「Git for Windows」で検索してダウンロードしてください)。
インストールに関する注意:
- デフォルトのインストールパス (例:
C:\\Program Files\\Git) またはカスタムパス (例:D:\\ProgramFiles\\Git) を使用することをお勧めします。 - インストール中に「Git Bash Here」がチェックされていることを確認してください。
Windowsタスクスケジューラの設定
Win + Rを押す →taskschd.mscと入力 → Enter- 「タスクの作成」をクリック
全般タブ:
- 名前:
Paper-Essence Daily Run - 「最上位の特権で実行する」にチェックを入れる
トリガータブ:
- 「新規」をクリック
- 「スケジュールに従って」を選択
- 「毎日」を選択し、時刻を設定します (Difyワークフロータイマーと一致させることを推奨、例:
20:55) - 「OK」をクリック
操作タブ:
-
「新規」をクリック
-
操作: 「プログラムの開始」
-
プログラム/スクリプト: Git Bashのパスを入力します。例:
D:\\ProgramFiles\\Git\\bin\\bash.exeまたはデフォルトのインストールパス:
C:\\Program Files\\Git\\bin\\bash.exe -
引数の追加: curlコマンドを使用して、APIキーと共にワークフローAPIエンドポイントにPOSTします。
注: APIエンドポイントとキーは、前のステップで取得した実際の値に置き換えてください。
条件タブ (オプション):
- ノートPCがバッテリー駆動時でもタスクが実行されるように、「コンピューターがAC電源の場合にのみタスクを開始する」のチェックを外すことができます。
設定タブ (オプション):
- 「タスクが失敗した場合、再起動する」にチェックを入れ、再試行間隔を設定します。
- 「OK」をクリックしてタスクを保存します。
テストとデバッグ
手動テスト
- ワークフローエディタの右上にある「実行」をクリックします。
- ノードの実行と出力を観察します。
- 各ノードの出力が期待通りであることを確認します。
成功結果
ワークフローが正常に実行されると、日次論文ダイジェストを含むメールが届きます。
まとめ
このチュートリアルでは、arXivからの取得 → PaddleOCRによる解析 → LLM分析 → Jinja2テンプレート化 → SMTP配信という、Supabaseベースの重複排除とスケジューリングを備えた完全なエンドツーエンドパイプラインの構築について説明します。このワークフローには、YAMLノード設定、環境変数、Supabase統合が含まれており、ArXivからの取得からメール配信まで、強化された重複排除とエラー処理を備えた包括的なパイプラインを作成します。
提供されている prj/Paper-Essence-CN.yml と prj/Paper-Essence-EN.yml は、Difyワークスペースにインポートしてワークフローを再現できます。
謝辞
Alex Zhang、Guan Mu、Yang Youzhiの皆様のご指導に心より感謝いたします。