はじめに
Dify というサービスを聞いたことがあるけれど、「何ができるかわからない」、「どう使うのかわからない」などの理由で使ったことがない方は多いのではないでしょうか。
そのような方のために、「Dify で何ができるのか?」や Dify を使った活用事例を紹介する記事をシリーズ化していきます。
シリーズ記事はこちらです 【Difyで作るシリーズ 1】 PDFファイルの要約 【Difyで作るシリーズ 2】会社情報Q&Aチャットボット 【Difyで作るシリーズ 3】 ニュース要約チャットボット
今回は第10回目で、Gamma APIを使用して、スライドを自動作成するワークフローを作成する方法について紹介します。
Gamma とは Gammaは、AIを活用してプレゼンテーション資料やドキュメント、Webページなどを自動で生成するクラウドサービスです。従来、資料作成はスライド一枚一枚のデザインやレイアウトを手作業で行う必要がありましたが、Gammaは簡単なテキストでの指示(プロンプト)を与えるだけで、構成の考案から文章の生成、デザインの適用までを自動で行います。
https://gamma.app/ja 主な特徴
- 簡単な操作: 「AIについて」といったテーマを入力するだけで、AIが最適な構成のアウトラインを提案し、それに沿った内容のスライドを自動で作成します。
- 高品質なデザイン: 豊富なテンプレートが用意されており、専門的なデザインスキルがなくても、誰でも洗練された見た目の資料を作成できます。
- 時間の大幅な短縮: アイデア出しから清書までのプロセスをAIがサポートするため、資料作成にかかる時間を劇的に削減します。
今回使用する Gamma API はベータ版であり、以下のような制限があります。
- レートリミット: 一日あたり最大50回までコンテンツを生成することができます。
- **破壊的変更のリスク: APIの仕様が大幅に変更され、現在APIを利用しているプログラムが動作しなくなるような「破壊的変更」**が、事前の十分な告知なく行われる可能性があります。
この記事の対象者
- Dify という言葉を聞いたことがあるが、何ができるのかがわからない方
- Dify を業務に取り入れたいと検討している方
事前準備
環境
- Dify v1.8.0
- Gamma Proプランに加入している
概要
AIにどのようなスライドを作ってほしいか指示を出す(プロンプトを入力する)ことで、資料を自動生成します。指示の出し方には、簡単なテーマだけを伝える方法と、各ページの内容を細かく指定する方法の2通りがあります。 1. テーマを伝えるだけのシンプル作成 作りたいプレゼンテーションのテーマを短い文章で入力するだけで、AIがそのテーマに沿った構成や内容のスライド一式を自動で生成します。最も手軽な方法です。
入力例
AIを活用した生産性向上術
2. Markdown記法で各ページを細かく指定 各ページの内容をより具体的にコントロールしたい場合は、Markdownに似た記法で指示を出します。 「#」の後ろに各ページのタイトルを、「-」の後ろにそのページに含めたい箇条書きの要素を記述することで、スライドの構成と内容を正確に指定できます。
入力例
# 最後のフロンティア:深海探査
- 海の20%未満しか探索されていない
- 水深1,000メートルを超える領域はいまだに大部分が謎
- 人類は海の最深部よりも宇宙に行った人の方が多い
# 技術的ブレークスルー
- 極限の水圧に耐えられる高度な潜水艇
- 高解像度カメラとサンプリング装置を備えた遠隔操作探査機(ROV)
- 長期的なマッピング任務を行う自律型無人潜水機
- リアルタイムでデータ伝送を可能にする深海通信ネットワーク
# 生態学的発見
- 太陽光なしで繁栄する独自の生態系
- 化学合成を利用する熱水噴出孔の群集
- 生物発光や耐圧性など驚異的な適応を持つ生物
- 毎年数千もの新種が発見されている
完成イメージ
イメージ
-
「topic」スライド作成に必要な情報を入力します。
-
右側にスライドのリンクが表示されます。
-
リンク先のサイトに遷移すると、自動生成されたスライドが表示されます。


今回作成するワークフローの全体図です。

作成手順
ここからは、ワークフロー構築の手順について説明します。
手順
- ワークフローの新規作成
- ワークフロー作成画面上での作業
- ワークフローの動作確認
1. ワークフローの新規作成
-
最初の画面の「最初から作成」を選択します。

-
「ワークフロー」を選択し、「アプリのアイコンと名前」を入力してから「作成する」を選択します。

2. ワークフロー作成画面上での作業
- Gamma API を呼び出すための APIキーを「環境変数」に設定します(キーの漏洩防止と安全な管理のため)。
- 画面右上にある「ENV」ボタンを押す
- 「+環境変数の追加」ボタンを押す
- 環境変数を以下のように設定する
| 項目 | 値 |
|---|---|
| 項目 | 値 |
| タイプ | String |
| 変数名 | gamma_api |
| 値 | Gamma APIキー 取得する方法はこちら |
以下の画像のようになっていればOKです。

- 「開始」ノードを選択した後、「+」ボタンを押し、下記の表のように4つの項目を追加します。
| 項目 | 値 |
|---|---|
| 項目 | 値 |
| フィールドタイプ | 段落 |
| 変数名 | user_input |
| ラベル名 | topic |
| 最大長 | 1000 |

- 入力のタイプを分類するために「IF/ELSE」ノードを作成し、以下の表のように設定します。 これによって、「#」で始まるテキストを各ページを細かく指定したテキストとして判定します。
| 項目 | 入力 | 値 |
|---|---|---|
| 項目 | 入力 | 値 |
| IF(で始まる) | 開始/user_input | # |
以下の画像のようになっていればOKです。
以降、「IF」の分岐での作業を行います。
-
「IF/ELSE」ノードの「+」ボタンを押し、「コード実行」ノードを作成します。
入力変数を以下のように設定します。
| ラベル名 | パラメータ |
|---|---|
| ラベル名 | パラメータ |
| input_text | 開始/user_input |
また、「コード」部分は以下のように設定します。Markdown記法で記述されたインプットをGamma APIのプロンプト(inputTextフィールド)の書式に合うように変換しています。
import json
def convert_markdown(input_text: str) -> str:
lines = input_text.strip().splitlines()
sections = []
buffer = []
for line in lines:
if line.startswith("#"):
if buffer:
sections.append("\n".join(buffer))
buffer = []
buffer.append(line)
elif line.strip().startswith("- "):
buffer.append(line.replace("- ", "* ", 1))
else:
buffer.append(line)
if buffer:
sections.append("\n".join(buffer))
# セクションごとに \n---\n で結合(実体は“本当の改行”)
return "\n---\n".join(sections)
def main(input_text: str):
# 1) 生の改行を含む文字列
raw = convert_markdown(input_text)
# 2) HTTP JSON ボディに安全な「エスケープ済み」文字列(\n など)
escaped_for_json = json.dumps(raw, ensure_ascii=False)[1:-1]
return {
"result": escaped_for_json # HTTPリクエストの Body に使う
}以下の画像のようになっていればOKです。(わかりやすいようにノード名を「コンテンツ作成(Long_ver)」としています。)

-
「コンテンツ作成(Long_ver)」ノードの「+」ボタンを押し、「HTTPリクエスト」ノードを作成します。 Gamma APIを使ってスライドの作成をリクエストします。
APIの設定で「認証なし」を選択し、以下のように値を設定します。
| 項目 | 値 |
|---|---|
| 項目 | 値 |
| 認証タイプ | APIキー |
| API認証タイプ | カスタム |
| ヘッダー | X-API-KEY |
| APIキー | gamma_api(環境変数) |
また、「HTTPリクエスト」の設定を以下の表のように設定します。
| 項目 | 値 |
|---|---|
| 項目 | 値 |
| メソッド | POST |
| URL | https://public-api.gamma.app/v0.2/generations |
| キー(ヘッダー) | Content-Type |
| 値(ヘッダー) | application/json |
また、「ボディ」には「raw」を選択し、以下のコードを記述します。(「input_text」には「コンテンツ作成/result」を入れます。)
{
"inputText": "{**ここに「コンテンツ作成/result」を入れる**}",
"textMode": "generate",
"format": "presentation",
"cardSplit": "inputTextBreaks",
"textOptions": {
"amount": "medium",
"language": "ja"
},
"imageOptions": {
"source": "aiGenerated"
},
"cardOptions": {
"dimensions": "16x9"
},
"sharingOptions": {
"externalAccess": "edit"
}
}
今回は、デフォルトの設定にしていますが、Gamma APIではこのbodyを用いて様々なパラメータが調整できます。
(参考)Gamma APIで調整できる項目
| パラメータ | データ型 | 必須/任意 | デフォルト値 | 許容値/フォーマット | 説明 |
|---|---|---|---|---|---|
| パラメータ | データ型 | 必須/任意 | デフォルト値 | 許容値/フォーマット | 説明 |
| inputText | String | 必須 | - | 1~750,000文字 | コンテンツ生成の基盤となるテキスト。\n---\nでカード分割を制御可能。 |
| textMode | Enum | 任意 | generate | generate, condense, preserve | inputTextの処理方法を定義。preserveはテキストをそのまま維持する。 |
| format | Enum | 任意 | presentation | presentation, document, social | 生成される成果物の種類(プレゼン、ドキュメント等)を決定 |
| themeName | String | 任意 | ワークスペースのデフォルト | 標準またはカスタムテーマ名 | ビジュアルテーマ(色、フォント)を指定 |
| numCards | Integer | 任意 | 10 | Proプラン: 1~50, Ultraプラン: 1~75 | cardSplitがautoの場合に生成されるカード数 |
| cardSplit | Enum | 任意 | auto | auto, inputTextBreaks | コンテンツのカード分割方法inputTextBreaksはinputText内の\n---\nを使用 |
| additionalInstructions | String | 任意 | - | 1~500文字 | コンテンツやレイアウトに関する追加の指示 |
| exportAs | Enum | 任意 | - | pdf, pptx | 生成物と同時にPDFまたはPPTXファイルも出力 |
| textOptions.amount | Enum | 任意 | medium | brief, medium, detailed, extensive | カードあたりのテキスト量に影響 |
| textOptions.tone | String | 任意 | - | 1~500文字 | テキストのトーンや雰囲気を定義 |
| textOptions.audience | String | 任意 | - | 1~500文字 | 想定される読者層を記述 |
| textOptions.language | String | 任意 | en | 言語コード | 出力言語を指定 |
| imageOptions.source | Enum | 任意 | aiGenerated | aiGenerated, unsplash, noImages, etc. | 画像のソースを指定。商用利用可能なオプションも存在 |
| imageOptions.model | String | 任意 | - | AI画像生成モデル名 | sourceがaiGeneratedの場合に使用するモデル |
| imageOptions.style | String | 任意 | - | 1~500文字 | sourceがaiGeneratedの場合の画像スタイル |
| cardOptions.dimensions | Enum | 任意 | - | fluid, 16x9, 4x3 (プレゼン用) | カードのアスペクト比を決定。formatに依存 |
| sharingOptions.workspaceAccess | Enum | 任意 | ワークスペース設定 | noAccess, view, comment, edit, fullAccess | ワークスペースメンバーのアクセス権限 |
| sharingOptions.externalAccess | Enum | 任意 | ワークスペース設定 | noAccess, view, comment, edit | 外部ユーザーのアクセス権限 |
次に「ELSE」分岐に移動し、作業を行います。
-
「IF/ELSE」ノードの「+」ボタンを押し、「LLM」ノードを作成します。 ユーザのプロンプトをもとにスライドのタイトルを生成します。
AIモデルには「gpt-4o-mini」を選択し、「コンテキスト」には「開始/user_input」を選択します。
「SYSTEM」に入力するプロンプトは以下です。ユーザはスライド資料の作成を依頼しています。 ユーザのインプット({{#context#}})をもとにスライドのタイトルを作成して、スライドのタイトルのみを出力してください。 必ずタイトルのみを出力してください。
以下の画像のようになっていればOKです。(わかりやすいようにノードの名前を「トピック作成(Short_ver)」にしています。)

-
「トピック作成(Short_ver)」ノードから「HTTPリクエスト」ノードを作成し、「IF」の分岐と同じように設定しますが「raw」の「ボディ」には以下のように記述します。
{ "inputText": "**ここに「トピック作成/text」を入れる**", "textMode": "generate", "format": "presentation", "cardSplit": "auto", "textOptions": { "amount": "medium", "language": "ja" }, "imageOptions": { "source": "aiGenerated" }, "cardOptions": { "dimensions": "16x9" }, "sharingOptions": { "externalAccess": "edit" } }
以下の画像のようになっていれば大丈夫です。

-
「変数集約器」ノードを作成し、「IF/ELSE」の分岐を合流させます。
IF・ELSEそれぞれの分岐にある「HTTPリクエスト/body」を変数代入し、集約させます。
-
「変数集約器」ノードの「+」ボタンを押し、「コード実行」ノードを作成します。
「入力変数」にはラベル名を「body」に、パラメータを「変数集約器/output」に設定します。スライド作成の識別番号である「generationId」を取得するために、コード部分の記述は以下のようにします。pythonimport json def main(body): body = json.loads(body) return { "generationId": body.get('generationId') }
最後に「出力変数」を「generationId」とします。最終的に以下のような画像に設定できていたらOKです。(わかりやすくするためにノード名を「generationId取得」としています。)

-
「generationId取得」ノードの「+」ボタンを押し、「ループ」ノードを作成します。
:::message
「ループ」ノード 終了条件が達成できるまで、または反復上限回数まで特定のワークフローを繰り返します。 スライド作成のHTTPリクエストを送信してから実際にスライドおよびそのリンク(gammaUrl)が作成されるまでには時間がかかります。所要時間はスライドの量に依存するため、定期的にリクエスト(ポーリング処理)するために「ループ」ノードを追加しています。
:::
「ループ変数」の「+」ボタンを押し、設定を以下の表のようにします。
| 項目 | 値 |
|---|---|
| 項目 | 値 |
| ラベル名 | gammaUrl |
| データ型 | String |
| 入力モード | Constant |
| URL | https://gamma.app/ |
こちらで設定した「URL」は、ループが終了し正常にスライド作成のリンクが生成された後に、gammaUrlで上書きされます。また、万が一上書きされない場合(ループが最大回数に達するなど)に備えて 「gammaワークスペース」のURLにしています。 以下の画像のようになっていればOKです。
これ以後は、「ループ」ノード内でワークフローを構築していきます。
-
「ループ」ノード内にある「+ブロックを追加」ボタンを押し、「HTTPリクエスト」ノードを作成します。 このノードで、Gamma側でのスライド作成の進捗状況を確認し、実際に作成されたスライドのリンク(gammaUrl)を取得します。
APIキーの認証については先ほどと同じように設定し、「メソッド」を「GET」にします。また、リクエストするURLを以下のように設定します。(「generation_Id」の部分では、自身の「コード実行」で取得したIdを入力します。「」は不要です。)https://public-api.gamma.app/v0.2/generations/「generation_Id取得/generation_Id(この部分を変数に変更)」
-
「HTTPリクエスト」ノードで取得した情報から、「進捗状況(status)」と「gammaUrl」を抽出します。「HTTPリクエスト」ノードから「コード実行」ノードを作成し、入力変数を以下のように設定します。
| ラベル名 | パラメータ |
|---|---|
| ラベル名 | パラメータ |
| body | httpリクエスト(URL取得)/body |
また、コードの「ボディ」部分には以下のように記述します。
import json
def main(body):
body = json.loads(body)
return {
"status": body.get('status'),
"gammaUrl": body.get('gammaUrl', "")
}また、出力変数に「gammaUrl」と「status」を設定します。 以下の画像のようになっていればOKです。(ノード名を「GammaURL取得」に変更)

- スライド作成が完了しているかどうかを確認するために、「GammaURL取得」ノードから「IF/ELSE」ノードを作成し、分岐を以下のように設定します。
| 分岐名 | 項目 | 条件 |
|---|---|---|
| 分岐名 | 項目 | 条件 |
| CASE 1 | IF「GammaUrl取得/status」(である) | completed(完了) |
| CASE 2 | ELIF「GammaUrl取得/status」(である) | pending(作成中) |

-
「IF(CASE 1)」の「+」ボタンを押し「変数代入」ノードを作成します。
変数代入の設定を以下の表のように設定します。
| 代入する変数 | 操作 | パラメータ |
|---|---|---|
| 代入する変数 | 操作 | パラメータ |
| ループ/GammaUrl | 上書き | GammaURL取得/gammaUrl |
最後に「ループ完了」ノードを作成してループを終了します。
-
「IF/ELSE」ノードに戻り、「ELIF(CASE 2)」の「+」ボタンを押し、「コード実行」ノードを作成します。(ここで「ELSE」の分岐でないことに注意します。)
「入力変数」は何も設定せず、「コード」部分を以下のように記述します。(ノード名を「10秒待機」に変更)pythonimport time def main(): time.sleep(10) return { "result": "" }
ここで分岐は終了し、メインループに戻ります。これでループ内のワークフローは完成したので、「ループ」ノードから「終了」ノードを作成し、「ループ/gammaUrl」を出力します。これでワークフローは完成です。
3. ワークフローの動作確認
実際にワークフローが動作しているか確認します。「公開する」を選択し、「更新を公開」した後、「アプリを実行」を選択します。
動作確認では、「スライドのページごとの内容」をインプットにした場合を試していますが、Gammaスライドが作成されたサイトのURLが正常に表示されました。
入力例(再掲)
# 最後のフロンティア:深海探査
- 海の20%未満しか探索されていない
- 水深1,000メートルを超える領域はいまだに大部分が謎
- 人類は海の最深部よりも宇宙に行った人の方が多い
# 技術的ブレークスルー
- 極限の水圧に耐えられる高度な潜水艇
- 高解像度カメラとサンプリング装置を備えた遠隔操作探査機(ROV)
- 長期的なマッピング任務を行う自律型無人潜水機
- リアルタイムでデータ伝送を可能にする深海通信ネットワーク
# 生態学的発見
- 太陽光なしで繁栄する独自の生態系
- 化学合成を利用する熱水噴出孔の群集
- 生物発光や耐圧性など驚異的な適応を持つ生物
- 毎年数千もの新種が発見されている
また出力されたリンクに飛んでみると、正常にスライドが生成されていることが確認できました。
「スライドのテーマ」のみをインプットにした場合も、正常にスライドが生成されていることが確認できました。(テスト実行ではタイムアウトが起きてしまい結果が出力されていませんが、ログを参照すると、正常にスライドが生成されていることが確認できます。)

出力されたリンク先を参照すると正常にスライドが生成されていることが確認できました。

応用
今回はGamma APIに対して基本的なリクエストしか飛ばしていませんが、想定される読者の設定や、スライド出力言語の設定など、より場面にあったスライドを作成することができます。
おわりに
今回は、インプットに合わせてスライドを自動作成するワークフローを作成しました。今後もDifyを利用したアプリの作成手順を紹介していきます。ぜひ引き続きご覧ください。

