はじめに
以前、Notionのエージェント機能が無料で使えた時期に、毎朝の予定やタスクをまとめたMorningレポートを作ってもらっていました。
その日の予定、やるべきタスク、少し先の予定などが朝にまとまっていると、1日のスタートがかなり楽になります。
しかし、エージェント機能が有料化されたタイミングで、同じような仕組みを継続するには別の方法が必要になりました。
そこで、
- Batch
- Notion API
- OpenAI API
を組み合わせて、Morningレポートを自動生成する仕組みを作りました。
作成したリポジトリはこちらです。
作ったもの
今回作成したのは、PHP 8.1以上で動作するCLIバッチです。
Notion上の複数データソースから対象データを取得し、日付やステータスで絞り込み、PHP側でレポートを整形します。
必要に応じてOpenAI APIへ予定一覧を渡し、冒頭に表示する短いコメントを生成します。
最終的なレポートは、設定に応じて以下へ送信できます。
- Notion
- Slack
- メール
全体像は次の通りです。
重要なのは、レポート本文の整形をOpenAI APIへ丸投げしていない点です。
タスクや予定の分類、表示順、グルーピングはPHP側で処理します。
OpenAI APIは、主に冒頭コメントを生成するために使っています。
そのため、OpenAI APIが利用できない場合でも、最低限のレポート生成は継続できます。
使用技術
| 用途 | 技術 |
|---|---|
| バッチ処理 | PHP 8.1以上 |
| 依存管理 | Composer |
| データ取得 | Notion API |
| コメント生成 | OpenAI Responses API |
| 通知 | Slack Incoming Webhook |
| メール送信 | SMTP |
| 定期実行 | Cron |
| 保存先 | Notion Data Source |
バックエンドフレームワークは使わず、CLIバッチとして構成しています。
毎朝決まった時間に実行する用途なので、シンプルなバッチ処理で十分でした。
どんなデータを取得しているか
現在の設定では、複数のNotionデータソースを対象にしています。
例えば、以下のような情報です。
| データソース | 用途 |
|---|---|
| ToDo | 今日やるべき作業の確認 |
| 各案件のタスク | 案件ごとの作業確認 |
| カレンダー | 今日以降1週間の予定確認 |
| 身分証明書 | 有効期限が迫っている証明書の確認 |
| 子供のお弁当 | 当日の献立確認 |
設定は app/config/app.php にまとめています。
$baseSources = [
[
'enabled' => true,
'name' => 'ToDo',
'role' => '今日やるべき作業の確認',
'date_property' => 'いつまでに',
'status_property' => 'ステータス',
'project_property' => '関連プロジェクト',
'lookback_days' => 0,
'lookahead_days' => 3,
'exclude_statuses' => ['完了', 'いつかやる'],
],
[
'enabled' => true,
'name' => 'カレンダー',
'role' => '今日以降1週間の予定の確認',
'date_property' => 'Date',
'lookback_days' => 0,
'lookahead_days' => 7,
'exclude_statuses' => [],
],
];
各データソースごとに、次のような条件を変えられます。
| 設定 | 用途 |
|---|---|
date_property |
日付として使うプロパティ |
status_property |
除外判定に使うステータス |
project_property |
案件別にグルーピングするためのプロパティ |
genre_property |
カレンダー予定などを分類するためのプロパティ |
lookback_days |
何日前まで含めるか |
lookahead_days |
何日先まで含めるか |
exclude_statuses |
レポートから除外する状態 |
レポートはPHP側で分類する
Notion APIから取得したデータは、PHP側で分類します。
主な分類は以下です。
| 分類 | 意味 |
|---|---|
overdue |
期限超過 |
today |
今日 |
upcoming |
今後の予定 |
recent_past |
直近の過去データ |
この分類を使って、レポートをセクションごとに整形します。
さらに、案件やジャンルごとにもグルーピングします。
例えば、単純に予定を羅列するのではなく、
- 今日やるべきこと
- 期限超過
- 数日以内の予定
- 案件別タスク
- 家族関連予定
- 身分証明書の期限
という形で、朝に確認しやすい順番へ整理できます。
OpenAI APIへすべてを任せるよりも、PHP側で構造を決めた方が安定します。
OpenAI APIは冒頭コメントに使う
OpenAI APIは、PHP側で整形した予定一覧を受け取り、日本語の冒頭コメントを生成します。
例えば、
今日は期限の近いタスクが複数あります。午前中に優先度の高い作業を整理しておくと進めやすそうです。
というような、その日の状況に応じた一言をレポート先頭に追加できます。
OpenAI APIは任意機能です。
.env で無効化できます。
OPENAI_ENABLED=true
OPENAI_API_KEY=sk-...
OPENAI_MODEL=auto
OPENAI_MODEL_CANDIDATES=gpt-4o-mini,gpt-4.1-mini,gpt-4o
このアプリでは、OPENAI_MODEL=auto を指定できます。
ただし、OpenAI API側にサーバー共通の AUTO モデルがあるわけではありません。
アプリ側で候補モデルを順番に試し、利用可能なモデルへ切り替える仕組みです。
OpenAI APIが利用できない場合は、PHP側で生成したレポートだけを送信します。
Notion APIから複数のData Sourceを読む
Notion APIでは、複数のData Source IDを指定できます。
.env では以下のように設定します。
NOTION_DATA_SOURCE_IDS=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx,yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
app/config/app.php の $baseSources と、指定したData Source IDがインデックス順に対応します。
例えば、
1番目のID → ToDo
2番目のID → 各案件のタスク
3番目のID → カレンダー
という対応になります。
Notion APIのバージョンによっては、Database IDとData Source IDが区別されます。
このバッチでは、Data Source IDを使う前提にしています。
単一Data SourceのDatabase IDであれば、自動解決できる場合もあります。
NotionへMorningレポートを保存する
レポート自体も、NotionのData Sourceへ保存できます。
設定は .env で行います。
REPORT_NOTION_ENABLED=true
REPORT_NOTION_DATA_SOURCE_ID=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
REPORT_NOTION_TITLE_PROPERTY=Name
REPORT_NOTION_DATE_PROPERTY=Date
Notionへ保存する本文は、Notionブロックとして組み立てています。
使用する主なブロックは次の通りです。
heading_2heading_3- callout
- linked bullet
- 3列テーブル
単なるテキスト貼り付けではなく、Notion上で見やすい形に整形して保存します。
Slackとメールにも送れる
Slack Incoming Webhookを設定すれば、MorningレポートをSlackへ投稿できます。
SLACK_ENABLED=true
SLACK_WEBHOOK_URL=https://hooks.slack.com/services/...
メール送信も任意で有効化できます。
MAIL_ENABLED=true
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_SECURE=tls
SMTP_USER=user@example.com
SMTP_PASSWORD=password
MAIL_FROM=user@example.com
MAIL_TO=recipient1@example.com,recipient2@example.com
送信先ごとに独立しているため、Notion保存に失敗してもSlack通知やメール送信は継続できます。
反対に、Slackで失敗してもNotion保存は継続します。
Cronで毎朝自動実行する
このバッチはCLIから実行できます。
php app/batch/daily_report.php
指定日で実行することもできます。
php app/batch/daily_report.php --date=2026-04-16
本番環境では、Cronへ登録して毎朝実行します。
例えばHostingerでは、UTC基準で実行時刻を指定します。
/usr/bin/php /home/USER/domains/DOMAIN/private/notion-daily-report/app/batch/daily_report.php \
>> /home/USER/domains/DOMAIN/private/notion-daily-report/app/logs/cron.log 2>&1
.env はWeb公開ディレクトリの外へ置く方が安全です。
失敗しても全体を止めない
複数のデータソースを扱う場合、1つのデータソースで失敗しただけでMorningレポート全体が止まるのは困ります。
このバッチでは、データソースごとに処理を分けています。
あるデータソースで取得に失敗しても、ログへ記録し、残りのデータソース処理を継続します。
Notion、Slack、メールへの配信も同様です。
どれか1つで送信に失敗しても、残りの配信処理を継続します。
また、JSON Lines形式のログへ以下を記録します。
- データソースごとの開始・完了・失敗
- 取得件数
- 抽出件数
- 絞り込み後の件数
- 分類ごとの件数
- 各通知先の送信結果
- レポート文字数
- 実行時間
毎日動かすバッチなので、正常系だけでなく、失敗時に原因を追えることも重要です。
作って良かったこと
Morningレポートが自動生成されることで、朝に複数のNotionデータベースを順番に開く必要がなくなりました。
仕事のタスクだけでなく、予定、期限管理、家族関連の情報もまとめて確認できます。
特に便利なのは、
- 今日何を優先すべきか
- 期限超過があるか
- 数日以内に予定があるか
- 忘れてはいけない期限があるか
を1つのレポートで確認できる点です。
Notionのエージェント機能をそのまま再現したわけではありません。
ただ、自分が毎朝必要としている情報だけに絞ったため、むしろ使いやすくなりました。
おわりに
Notionのエージェント機能が有料化したことがきっかけでしたが、結果として、自分専用のMorningレポートを作ることができました。
PHPバッチ、Notion API、OpenAI APIという比較的シンプルな構成でも、日常的に使える仕組みは作れます。
すべてをAIに任せるのではなく、安定させたい部分はPHPで処理し、文章生成だけをOpenAI APIへ任せる構成にしたのも良かった点です。
今後も、実際に使いながら必要な情報源や表示方法を追加していく予定です。
