8
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

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

Last updated at Posted at 2025-06-11

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

📌はじめに

みなさんこんにちは。

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

今回も業務での課題を解決するBotを作成してみました!
その名も"スケジュール検索Bot"

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

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

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

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

🎉完成したもの

image.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から.txtファイルを作成する手順

PDFファイルをGoogleドライブにアップロード
Googleドキュメントとして開き、OCR(文字起こし)変換する
- → PDFの中身が「コピペできるテキスト」になる
変換したGoogleドキュメントのテキストをChatGPTに送信
- プロンプトで「スケジュールデータを 日付 : イベント 形式に変換してください」と依頼

実際にChatGPTに送信した内容の一部↓

このようにかなり見づらく改行が多い状態でしたが…
ちゃんと整形してくれました↓↓(順番はバラバラでOK)

今回は3企画分のスケジュールを入れたかったので、何の企画かわかるようにするため、ChatGPTに下記のように指示しました。

そうすると指示通り入れてくれました!

ChatGPTが整形したテキストをメモ帳などに貼り付けて .txt ファイルとして保存

⚙️制作過程

📚ナレッジの作成

まず、ナレッジとは何か知りたい方↓↓↓

Difyの「ナレッジ」とは?(クリックで開く)

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

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

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

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

イメージとしては:

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

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

  • PDF
  • Excel
  • テキストファイル(.txt)
  • Markdown(.md)

などが使えます。

ナレッジの作成手順
①画面上部の「ナレッジ」を選択

②画面左の「+ナレッジベースを作成」を選択

③データソースはデフォルトで「テキストファイルからインポート」が選択されているのでそのままでOKです。下の「テキストファイルをアップロード」のところに .txtファイルを追加し、右下の「次へ」を選択

④色々な設定が出てきますが、変更せず右下の「保存して処理」を選択
image.png

これでナレッジの完成です!


🤖チャットボットの作成

次にチャットボットを作成します。
①Difyを開き、「最初から作成」を選択

②「アプリタイプを選択」の「初心者向けの基本的なアプリタイプ」を選択

③「チャットボット」を選択

④「アプリのアイコンと名前」欄に任意の名前を作成し、右下の「作成する」を選択
今回は"スケジュール検索Bot”と名付けました。

⑤「プロンプト」欄に、ChatGPTに教えてもらったプロンプトを入力します。

使用したプロンプト(一例)

あなたはスケジュール管理アシスタントです。
ユーザーが日付を入力したら、その日に該当するギフトのスケジュールイベントをすべて答えてください。
もしその日にイベントがなければ「その日はスケジュールはありません」と返してください。
日付表現(7/4、7月4日、July 4 など)はすべて正しく認識してください。
回答は自然な日本語で行い、引用・出典・Knowledge Baseのファイル名などは一切表示しないでください。
複数のイベントがある場合は「7月4日は 冬ギフト ○○、旬ギフト △△ です。」のようにまとめて答えてください。
Knowledge Baseの検索結果が空の場合は「その日はスケジュールはありません」と返してください。

⑥「コンテキスト」欄の「+追加」を選択

⑦先ほどナレッジに登録したファイルが出てきます。
使用したいファイルを選択→右下の「追加」を選択

⑧右上のモデルを選択し、「gpt-4」→「gpt-4o-mini」に変更
(「gpt-4」は従来版のモデルで、トークンの消費が激しいそうです)

⑨最後にデバッグとプレビューで任意の日付を入力してみます。
するとプロンプトで指示した通りの返答がきました!!


🚀チャットボットアプリの公開

ここまできたらあと少しです!
①右上の「公開する」→「更新を公開」を選択

②「アプリを実行」を選択

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

⏳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

※ファイルIDは各ドキュメント・スプレッドシートのURLの一部(下図赤枠部分)
image.png

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

  1. Google Apps Script にアクセス
  2. 「新しいプロジェクト」を作成
  3. 下記のスクリプトを貼り付けて保存

💻使用したGASスクリプト(全文)

(クリックで開く)
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列対応済)');
}

⚠ スクリプトの2行目と3行目は以下のように書き換えてください:
image.png

const configSheetIdは管理用スプレッドシートのURLの一部、
image.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 プロンプト

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

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

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

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

【カタログ名】
・...

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

🤔 やってみた感想

Dify × GAS の連携で .txt 出力を自動化すれば、
毎回手動で整形 → アップロード」から解放されてとても効率的でした!

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

🔜 次に試したいこと

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

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


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

8
6
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
8
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?