【Dify × ChatGPT】明日の予定は何？スケジュールが一発でわかるBotを作ってみた！

# Dify × ChatGPTで「スケジュール検索Bot」を作ってみた話

## 📌はじめに
みなさんこんにちは。

前回はMakeを使って店舗情報が呼び出せるLINE Botを初めて作成しました。
前回の記事はこちら👇

 https://qiita.com/yuuuna04/items/cc0daea0f3e0d91713f2
 
今回も業務での課題を解決するBotを作成してみました！
その名も"**スケジュール検索Bot**"

私は小売業の本社でギフトを担当しています。
各企画（夏ギフトや冬ギフトなど）のスケジュール（PDF）を自分のスケジュール帳に落とし込んでスケジュール管理しているのですが…

PDFにまとまってはいるものの、「日付ごとに何があるか」が見づらく、特に**複数ギフト横断の確認がとても大変**です。
また、先の予定だとスケジュール帳から探すのも面倒…。

そこで今回、 **DifyとChatGPTを使って、ギフトのスケジュールを答えてくれるBot**  を作成しました。
例えば **「7/10は何の予定がある？」と聞けば複数ギフトのスケジュールを返してくれるBot** を目指しました。  

💡**わかりやすいように実際の画面のスクショを用いて一つひとつ手順を説明したので、Difyを使ってみたい方、業務効率化したい方の参考になれば嬉しいです♪**

## 🎉完成したもの
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4081005/67a29986-c0db-4b8d-be91-961c51a3c18f.png)


## 🛠️使用ツール

- **Dify**： チャットボット機能を活用 
- **ChatGPT**： スケジュールデータ整形・プロンプト作成など  
- **Googleドキュメント**：元データ整理用 
- **メモ帳**：.txtファイル変換用

## 💡課題と選んだAIツールの理由

### 課題

- スケジュール（PDF）が各企画ごと別々になっていてわかりづらい
　→**一元化したい**
- 予定をピンポイントで知りたいときに探すのが大変
　→**日付を入力するだけで予定がわかるようにしたい**

### 選んだ理由

| ツール | 選んだ理由 |
|--------|------------|
| Dify   | チャットアプリでカジュアルにBotを作れる。PDFやナレッジベース活用も簡単。 |
| ChatGPT | データ整形・自然言語回答のチューニングに有効。人に自然に返せるBotが作れる。 |


## 🎯今回作成したBotの目標
- PDFからスケジュールの取り込み
- Dify チャットアプリで **「日付を入力したらスケジュールを返すBot」** を作成
- 複数ギフトのイベントが同じ日にあればまとめて返す
    - 例：「7/10は 冬ギフト 撮影予定日④、旬ギフト 最終校正・色校 です」

## 🗂️事前準備
### PDF→Googleドキュメントに変換して`.txt`ファイルを作成する
「PDFをそのままアップロードできないの？」と思うかもしれませんが…変換することになった理由は後ほど説明します。
[PDFをそのまま読み取る方法 → Googleドキュメント変換に切り替えた理由にジャンプ](#pdfをそのまま読み取る方法--googleドキュメント変換に切り替えた理由)

#### PDFから`.txt`ファイルを作成する手順
① **PDFファイルをGoogleドライブにアップロード**
② **Googleドキュメントとして開き、OCR（文字起こし）変換する**
    - → PDFの中身が「コピペできるテキスト」になる
③ **変換したGoogleドキュメントのテキストをChatGPTに送信**
    - プロンプトで「スケジュールデータを `日付 : イベント` 形式に変換してください」と依頼

実際にChatGPTに送信した内容の一部↓
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4081005/da0701a7-efff-4f16-97a2-dc7dd0b41c5b.png" width=50%>

このようにかなり見づらく改行が多い状態でしたが…
ちゃんと整形してくれました↓↓（順番はバラバラでOK）
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4081005/9e47f648-1fc9-4436-9976-7f6dbb443828.png" width=50%>

今回は3企画分のスケジュールを入れたかったので、何の企画かわかるようにするため、ChatGPTに下記のように指示しました。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4081005/97714786-faae-4015-b46f-08d414a73864.png" width=50%>

そうすると指示通り入れてくれました！
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4081005/3a88e0f9-ad18-4fdb-b4c0-34aa0a260d22.png" width=50%>

④ **ChatGPTが整形したテキストをメモ帳などに貼り付けて `.txt` ファイルとして保存**
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4081005/1bd20047-1f1b-489a-a3ab-74177e215613.png" width=50%>

## ⚙️制作過程
### 📚ナレッジの作成
まず、ナレッジとは何か知りたい方↓↓↓
<details><summary>Difyの「ナレッジ」とは？（クリックで開く）</summary>

<br>

**Difyには「ナレッジベース」という機能**があります。  
これは簡単にいうと、**AIが参照できる「社内用の辞書／知識データベース」**のようなものです。  

例えば今回のような **ギフトスケジュールBot** では：

- **PDFやExcelから取り込んだ「ギフトのスケジュール一覧」をナレッジとして登録**
- DifyのChat Appでは、ユーザーから日付を聞かれたときに、このナレッジの中を検索して答えてくれる

という形で使っています。  

**イメージとしては：**

| 項目 | 役割 |
|------|------|
| ナレッジベース | AIが「参照する情報」 |
| Chat App | ユーザーと会話するチャット画面 |
| Prompt（指示文） | どう答えるかのルールを決める文章 |

ナレッジベースに入れるデータは：

- **PDF**
- **Excel**
- **テキストファイル（.txt）**
- **Markdown（.md）**

などが使えます。

</details>



**ナレッジの作成手順**
①画面上部の「ナレッジ」を選択
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4081005/cbf2114c-0800-4de3-8b6a-cf7ff2fdea73.png" width=50%>

②画面左の「＋ナレッジベースを作成」を選択
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4081005/16c5c066-2f17-4c16-964e-d2c80727351a.png" width=50%>

③データソースはデフォルトで「**テキストファイルからインポート**」が選択されているのでそのままでOKです。下の「**テキストファイルをアップロード**」のところに `.txt`**ファイル**を追加し、右下の「**次へ**」を選択
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4081005/2567c993-2421-4efa-908b-5c802bb95169.png" width=50%>

④色々な設定が出てきますが、変更せず右下の「**保存して処理**」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4081005/8ab3fa96-53ae-4e94-9750-d408e4876073.png)

**これでナレッジの完成です！**

---

### 🤖チャットボットの作成
次にチャットボットを作成します。
①Difyを開き、「**最初から作成**」を選択
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4081005/cb2cce5f-e99d-482a-83b1-dfad1df002b1.png" width=50%>

②「アプリタイプを選択」の「**初心者向けの基本的なアプリタイプ**」を選択
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4081005/288024a3-7c0d-4c93-8f3d-bc1ec98ce577.png" width=50%>

③「**チャットボット**」を選択
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4081005/ba7886f8-341f-448b-8cfe-2c0e0204bdd5.png" width=50%>

④「アプリのアイコンと名前」欄に**任意の名前を作成**し、右下の「**作成する**」を選択
今回は"スケジュール検索Bot”と名付けました。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4081005/2d58c7b0-d3d3-4467-b0e9-02eb3d1371ec.png" width=50%>

⑤「プロンプト」欄に、**ChatGPTに教えてもらったプロンプトを入力**します。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4081005/b9eca20b-540f-4171-a385-73ae1bfbad21.png" width=50%>

**使用したプロンプト（一例）**
```text
あなたはスケジュール管理アシスタントです。
ユーザーが日付を入力したら、その日に該当するギフトのスケジュールイベントをすべて答えてください。
もしその日にイベントがなければ「その日はスケジュールはありません」と返してください。
日付表現（7/4、7月4日、July 4 など）はすべて正しく認識してください。
回答は自然な日本語で行い、引用・出典・Knowledge Baseのファイル名などは一切表示しないでください。
複数のイベントがある場合は「7月4日は 冬ギフト ○○、旬ギフト △△ です。」のようにまとめて答えてください。
Knowledge Baseの検索結果が空の場合は「その日はスケジュールはありません」と返してください。
```
⑥「コンテキスト」欄の「**＋追加**」を選択
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4081005/f31d4ed2-c450-4585-84b4-785206292962.png" width=50%>

⑦先ほどナレッジに登録したファイルが出てきます。
使用したいファイルを選択→右下の「**追加**」を選択
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4081005/2a4896e8-2dfc-4a8f-beea-591542b0be3d.png" width=50%>

⑧右上のモデルを選択し、「gpt-4」→「**gpt-4o-mini**」に変更
（「gpt-4」は従来版のモデルで、トークンの消費が激しいそうです）
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4081005/86f192fd-b759-4ae1-b8b4-2bab273c72ab.png" width=50%>

⑨最後にデバッグとプレビューで任意の日付を入力してみます。
すると**プロンプトで指示した通りの返答がきました！！**
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4081005/6082c178-c108-4ff6-9685-4394c385005a.png" width=50%>

---

### 🚀チャットボットアプリの公開
ここまできたらあと少しです！
①右上の「**公開する**」→「**更新を公開**」を選択
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4081005/cc3242ea-2b0f-4e5f-9909-5769c030e3f0.png" width=50%>

②「**アプリを実行**」を選択
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4081005/4f9c711c-15e9-47da-b160-445ca6916634.png" width=50%>

**これにてチャットボットアプリが完成しました！！**

## ⏳ChatGPTによる時間短縮の成果と余剰時間で取り組んだこと

### 時間短縮の成果

- **PDFの整形**  
  通常は1件ずつ手作業 → ChatGPTで一括整形

- **Difyプロンプト設計**  
  ChatGPTに推奨フォーマット作成を依頼 → **試行回数を半減**

### 余剰時間で取り組んだこと

- **Makeを活用したLINE Bot化の試案**  
- **関連するQiita記事の検索**

## 📝PDFをそのまま読み取る方法 → Googleドキュメント変換に切り替えた理由
事前準備で少し触れましたが、なぜPDFをそのまま取り込まなかったのか、Googleドキュメントに変換した理由について説明します。
### 最初に試した方法：PDFをそのまま読み取る

最初はDifyのナレッジベースに **PDFファイルを直接アップロードしてスケジュールBotを作ろう**と考えました。  
DifyはPDFもナレッジに登録できるので、一見簡単そうに思えたのですが…。

### 課題が発生

PDFをそのままアップロードした場合：

- **レイアウト崩れ／改行位置がおかしい**
- **表組みがうまく読み取れない（2段組や複雑な罫線があると特に失敗）**
- **イベントの日付と内容が正しく対応しない**

などの問題が発生しました。  
**→ チャットボットに本来予定のある「7/10は何？」と聞いても「スケジュールはありません」と返ってくることが多発…。**

### 改善策：Googleドキュメント変換 → ChatGPTで整形する方法に変更

### メリット

- **表の崩れがなくなった**
- **スケジュールの整形ルールが統一できた（ChatGPTが揃えてくれる）**
- **Difyのナレッジで正しく検索・回答できるようになった**

### まとめ

**PDFをそのままアップロードする方法は簡単そうに見えて実は失敗しやすい。**  
→ **Googleドキュメント＋ChatGPT整形ルート**のほうが「**正確性・見やすさ・管理のしやすさ**」すべての面で優れていました。  

ただ、これでも手間がかかるのは事実なので、PDFでうまく読み取れる方法を模索したいと思います。

## ⚠️ChatGPTでもできなかったこと
- **スケジュールの整形に2時間&不完全だった**
PDF→.txtファイルに変換する過程で、ChatGPTが「.txt ファイル用にそのままコピペできる完成版（そのまま貼るだけ用） も作って送りますよ」と言ってくれたのでお願いしたのですが、それだと全部の処理を終えるのに**2時間近くかかる&情報が抜けている**という結果になりました…（15分～20分くらいでできると言っていたのですが）
また、今回のようにチャットにベタ打ちで整形したものを送ってもらうやり方であれば10分もかからず処理してくれましたが、最初は漏れているところもありすべて正しく送ってもらうまでに時間がかかってしまいました。

## 🔮まとめ・今後の展望

今回の試作により、「**スケジュールが一発で見える**」という改善が実現しました。  
ただ、本当は
「**PDFをDifyにそのまま取り込む→Googleスプレッドシートに落とし込む→LINE Bot化&自動通知**」という流れをMakeで自動化させるのが目標でした。

Difyでワークフロー作成、JSON配列でスケジュールを出力するところまではできましたが、MakeのHTTPからDifyAPIを叩くという工程でエラーが続き、実現できませんでした。
おそらくDify側でAPIの有効化や、HTTPモジュール内の設定がうまくいっていないことが原因と考えています。
### 今後は：

- **LINE Bot連携** → **現場で使えるレベルに発展したい**
- **ChatGPTをもっと使いこなしたい**
- **Difyを使ってほかの業務課題解決にも取り組んでいきたい**

## 🎁最後に
今回使用したDifyは、**Makeよりもかなり感覚的に使えるツール**だと感じました。
**PDFや画像の情報を読み取るなんてできるの**？と最初は半信半疑でしたが、ある程度項目がまとまっていればほぼ正確に抜き取ることができると思います。

また、最初から最後まで**ChatGPT**を活用してアプリを作成してみて、**本当に知識が0でもできること**に衝撃を受けました。**指示をいかに的確に行うかで返ってくる情報の正確さが変わってくる**と思います。今後もAIツールを活用して様々な業務課題を解決していきたいです。
そして、この記事が少しでも**業務改善Bot作りの参考**になれば嬉しいです。

---

## 📝 追記：GASを使ってスケジュール`.txt`を自動生成してみた話

ここまで、Googleドキュメントから抜き出したスケジュールをChatGPTで整形するのにかなり時間がかかったという話をしました。
そこで、自動整形する方法ってほかにないの？と思いChatGPTに相談したところ、
**Google Apps Script（GAS）を使って `.txt` ファイルを自動生成できる**ということがわかりました。今回はその方法をご紹介します。

### 🧩 ステップ①：Googleドキュメント or Googleスプレッドシートに変換

1. PDF or Excel を Googleドライブにアップロード  →PDFはGoogleドキュメントに、ExcelはGoogleスプレッドシートにそれぞれ変換する

### 🧩 ステップ②：任意の管理用スプレッドシートに以下の情報を入力

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4081005/78bb37f5-e252-4406-9f66-37838160ee18.png)

※ファイルIDは各ドキュメント・スプレッドシートのURLの一部（下図赤枠部分）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4081005/1f3f734b-3e9d-461c-bcf2-3e7f8348bdf7.png)

### 🧩 ステップ③：GASスクリプト作成

1. [Google Apps Script](https://script.google.com/) にアクセス  
2. 「新しいプロジェクト」を作成  
3. 下記のスクリプトを貼り付けて保存  


#### 💻使用したGASスクリプト（全文）
<details><summary>（クリックで開く）</summary>


```
function exportSchedulesFromListToTxt() {
  const configSheetId = '1aZvX71wDQfK732pAK4jfyreEMOzAyI9zekHwbd_baMU';
  const configSheetName = 'シート1'; // 実際のシート名に合わせてください
  const outputFileName = '全スケジュールまとめ.txt';

  const configSheet = SpreadsheetApp.openById(configSheetId).getSheetByName(configSheetName);
  if (!configSheet) throw new Error('📛 指定されたシート名が存在しません：' + configSheetName);
  const configs = configSheet.getDataRange().getValues();
  configs.shift(); // ヘッダー削除

  let allOutput = '';

  configs.forEach(row => {
    const [type, name, fileId] = row;

    if (type === 'doc') {
      const docFile = DocumentApp.openById(fileId);
      const tables = docFile.getBody().getTables();
      let lines = [];

      for (const table of tables) {
        const rows = table.getNumRows();
        for (let r = 0; r < rows; r++) {
          const row = table.getRow(r);
          const cols = row.getNumCells();

          for (let c = 0; c < cols; c += 3) {
            const dateCell = row.getCell(c);
            const planCell = (c + 2 < cols) ? row.getCell(c + 2) : null;

            const rawDate = dateCell.getText().trim();
            const plan = planCell ? planCell.getText().trim() : '';
            if (rawDate && plan) {
              lines.push(`${rawDate} : ${plan}`);
            }
          }
        }
      }

      if (lines.length > 0) {
        allOutput += `【${name}】\n` + lines.join('\n') + '\n\n';
      }

    } else if (type === 'sheet') {
  const sheet = SpreadsheetApp.openById(fileId).getSheets()[0];
  const data = sheet.getDataRange().getValues();
  let lines = [];

  for (let i = 1; i < data.length; i++) {
    const row = data[i];

    for (let c = 0; c < row.length; c += 3) {
      const rawDate = row[c];
      const rawPlan = row[c + 2];

      const plan = rawPlan ? rawPlan.toString().trim() : '';
      if (!rawDate || !plan) continue;  // ✅ イベント or 日付が空ならスキップ

      let formattedDate = '';
      if (rawDate instanceof Date) {
        formattedDate = Utilities.formatDate(rawDate, Session.getScriptTimeZone(), 'M/d');
      } else {
        formattedDate = rawDate.toString().trim();
      }

      lines.push(`${formattedDate} : ${plan}`);
    }
  }

  if (lines.length > 0) {
    allOutput += `【${name}】\n` + lines.join('\n') + '\n\n';
  }
}


  });

  DriveApp.createFile(outputFileName, allOutput, MimeType.PLAIN_TEXT);
  Logger.log('✅ 全スケジュールを出力しました（空行スキップ・C列対応済）');
}

```
</details>

**⚠ スクリプトの2行目と3行目は以下のように書き換えてください：**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4081005/e484882c-c77b-48b3-a881-a9c2f0a8a87c.png)

const configSheetIdは管理用スプレッドシートのURLの一部、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4081005/2eabf614-a87f-4ba6-9c55-bc0599dfecf3.png)
    const configSheetNameはシート名（ここでは「**シート1**」）を入力

### 🧩 ステップ④：実行する
1. スクリプトを保存
2. ▶（実行）ボタンを押す
3. 初回のみ「権限の承認」画面が表示されるので許可
4. `.txt`ファイルがGoogleドライブに保存されれば成功 🎉

### 💥 詰まったポイント

- `Cannot read properties of null`  
　→ **シート名が違っていた**（全角や空白に注意）

- `Document is missing`  
　→ **Googleドキュメントの共有設定** or **ファイルIDが間違っていた**

- `.txt` に出力されたのに Dify が予定を拾わない  
　→ プロンプトに **「すべて表示する」旨を明記し忘れた**

- スプレッドシートが「横に3列ずつ（例：A列〜C列、D列〜F列のように繰り返す）」形式だった  
　→ `for (let c = 0; c < row.length; c += 3)` に変更して対応

### 💬 最終的に使用した Dify プロンプト

```plaintext
あなたはカタログ制作スケジュール管理アシスタントです。

ユーザーが日付（例：6/17、6月17日、8/20、2025年8月20日 など）に関する質問をしたら、
その日に該当するすべてのカタログの予定を、漏れなく出力してください。

回答形式は以下に従ってください：

【カタログ名】
・日付 : イベント内容
・日付 : イベント内容（複数ある場合）

【カタログ名】
・...

■重要：
・同じカタログで1日に複数の予定がある場合は **すべての予定を表示してください**
・他のカタログにも同じ日付の予定がある場合は **すべて出力してください**
・省略や要約はしないでください。**該当するイベントはすべて漏れなく表示してください**
・ユーザーの入力が自然文（例：「○○ってあった？」）でも正しく解釈してください
・引用元やファイル名などは一切表示しないでください
・回答は自然な日本語で簡潔にまとめてください
```

### 🤔 やってみた感想
Dify × GAS の連携で `.txt` 出力を自動化すれば、
「**毎回手動で整形 → アップロード**」から解放されてとても効率的でした！

ただし、GPTモデルの仕様上、**同日付に複数予定がある場合に見落としがどうしても発生してしまうのが課題**です。プロンプトやGPTのモデルを変えたりと色々試しましたが、やはりすべての予定を拾うことはできませんでした。



### 🔜 次に試したいこと
次は、`.txt` ではなく JSON形式でナレッジを構造化し、
「**Difyが複数のイベントを確実に拾ってくれるように**」工夫したバージョンを試す予定です。
また、**Googleスケジュールと連携してスケジュールを一括管理できるような仕組みも作りたい**と考えています。

**☑スケジュール管理は今チーム内で解決したい課題の一つなので、働きやすい環境を作るべく今後も頑張っていきたいと思います！✊**

---
📌 おまけメモ：
この記事は、ChatGPTに補助してもらって作成しています。  
手順の整理や文体の調整などを効率化しながら、自分の業務内容と組み合わせて構成しています。  
AIを使った記事作成、思っていたよりかなり便利で感動しました！