🦙

いいねした記事を読み返さないので、AIに要約させて毎朝音声で届けてもらうことにした

に公開

いいねした記事を読み返さないので、AIに要約させて毎朝音声で届けてもらうことにした


どうも、AIエンジニアの@noprogllamaです。

Xでいいねした記事、後で読もうと思ってそのまま流れていきませんか。私はずっとそうでした。

いいねは「後で読む」のつもりで押しているのですが、タイムラインは止まらないし、他のことをやっていると忘れます。気づけば未読のいいねが溜まっていく一方でした。

これを解決するために、AIに毎朝ブリーフィングを届けてもらう仕組みを作りました。天気、カレンダーの予定、ニュース、いいねした記事の要約。推薦記事は音声でも生成されるので、朝の支度をしながらイヤホンで聴けます。

仕組みの全体像

自宅のMac miniでAIエージェントが動いています。毎朝6時に定時起動し、複数の情報源を並列に収集して、1つのレポートにまとめ、音声化してスマホに届けます。

自分はClaude Agent SDKとFastAPIで自作したWebアプリケーションで動かしていますが、AIを定時に動かすだけなら他の手段でも実現できます。Claude Codeのスケジュール実行(/schedule)もその一つです。記事の最後に道案内を書きます。

朝ブリーフィングの中身

AIが集めてくる情報です。

  • 天気(WebSearchで取得)
  • Googleカレンダーの今日の予定
  • 主要ニュース3〜5件(経済・テクノロジー中心)
  • Xでいいねした記事の全文取得と要約
  • Gmailのプロモーションメールからお得情報のピックアップ
  • 各プロジェクトの進捗情報
  • 前日の未完了タスク
  • Mac miniのシステムヘルス

これらを複数のエージェントが同時に集めます。全部が揃ったら、AIが統括してレポートにまとめ、その日のToDoを設計してくれます。

実際のブリーフィングの一部です(個人情報に関わる箇所は調整しています)。

2026年4月15日(水)

【天気】雨、最高18℃/最低15℃、降水確率80%

【ニュース】
- 日米関税の新局面 — 米最高裁が相互関税の大統領令を違法・無効と判断
- 2026年度国家予算122.3兆円が成立 — 史上最大規模
- MS、日本に1.6兆円投資 — AI基盤・人材育成

【いいね記事】1件中: 推薦0件 / 通常0件 / 見送り1件

【本日のToDo】5件
戦略メモ:
> 今夜の1時間はレポート整理に集中すること。
> 「やらなくてよいこと」: 新機能追加。

- [ ] BT結果レポート整理
- [ ] Xポスト1件
- [ ] 東映オンデマンド解約

毎朝これがスマホに届いています。天気を見て服を選び、予定を確認し、ニュースに目を通します。

いいね記事の振り分け

ブリーフィングの中で一番手間がかかっているのが、いいね記事の処理です。

Xのいいねを取得するスクリプトが、前日にいいねした記事のURLと本文を収集します。AIがそれぞれの記事を全文読んで要約し、3段階に振り分けます。

  • 推薦: 自分の関心事に直結する記事。AIの所見付き
  • 通常: 知識として有用だが、今すぐアクションが必要ない記事
  • 見送り: 一般的すぎるもの、既知の内容

推薦記事にはAIの所見が付きます。「この記事の内容は、今進めているプロジェクトの○○に応用できる」のように、自分の状況を踏まえた判断が入ります。汎用的な要約とは質が違っていて、推薦だけ読めば事足りるので、いいねした記事を後で全部読み返す手間がなくなりました。

各記事の要約はObsidianにノートとして保存されます。推薦記事はrecommend/、通常はnormal/に分けて保存されます。

~/Obsidian/article_summaries/
├── recommend/
│   ├── 2026-04-14_0605_Claude_CodeとNotebookLM使い分け.md
│   ├── 2026-04-14_0605_Claude_CodeとNotebookLM使い分け.mp3
│   ├── 2026-04-13_2101_株LS50億利回り15pct.md
│   └── ...
└── normal/
    └── ...

推薦記事にはMP3も生成されます。次のセクションで、この音声化の仕組みを詳しく書きます。

記事を音声で届ける

ここからが技術的な本題です。

ブリーフィングのレポートと推薦記事は、テキストだけでなくMP3としても生成されます。朝の支度をしながらイヤホンで聴くためです。

音声生成にはGoogle Cloud Text-to-Speechを使っています。REST APIにテキストを投げると、レスポンスのaudioContentフィールドにBase64エンコードされたMP3が返ってくるので、base64 -dでデコードして保存します。

音声はja-JP-Neural2-Bを使っています。Neural2系は自然な発話に近くて聴きやすいです。速度は1.1倍にしています。等速だと少しゆっくりに感じたので、気持ち速めに調整しました。

5,000バイトの壁

このAPIには1リクエストあたり5,000バイトの制限があります。

日本語のUTF-8は1文字あたり3バイトなので、約1,500文字が上限です。朝ブリーフィングの全文は軽く数千文字になるので、1回のAPIコールでは収まりません。

解決策は、テキストを句点(。)で区切りながら1,500文字以下のチャンクに分割し、チャンクごとにAPIを叩いて、最後にffmpegで結合しています。

テキスト全体が1,500文字以下ならそのままAPIに投げます。超える場合はsed 's/。/。\n/g'で句点ごとに改行を入れ、1文ずつ読みながら1,500文字以下のチャンクに詰めていきます。チャンクごとにAPIを叩いて一時MP3を作り、ffmpegのconcatで1本に結合します。

# 句点で区切り、1500文字以下のチャンクに振り分ける
chunks=()
current=""
current_len=0

while IFS= read -r sentence; do
  sent_len=${#sentence}
  if [ $((current_len + sent_len)) -gt 1500 ] && [ "$current_len" -gt 0 ]; then
    chunks+=("$current")
    current="$sentence"
    current_len=$sent_len
  else
    current="${current}${sentence}"
    current_len=$((current_len + sent_len))
  fi
done <<< "$(echo "$FULL_TEXT" | sed 's/。/。\n/g')"
[ -n "$current" ] && chunks+=("$current")

# 各チャンクを個別MP3に変換
concat_list=$(mktemp /tmp/tts_concat_XXXXXX)
for i in "${!chunks[@]}"; do
  tmp_mp3=$(mktemp /tmp/tts_chunk_XXXXXX)
  json_text=$(printf '%s' "${chunks[$i]}" | jq -Rs .)
  curl -s -X POST \
    "https://texttospeech.googleapis.com/v1/text:synthesize?key=${API_KEY}" \
    -H "Content-Type: application/json" \
    -d "{\"input\":{\"text\":${json_text}},\"voice\":{\"languageCode\":\"ja-JP\",\"name\":\"ja-JP-Neural2-B\"},\"audioConfig\":{\"audioEncoding\":\"MP3\",\"speakingRate\":1.1}}" \
    | jq -r '.audioContent' | base64 -d > "$tmp_mp3"
  echo "file '${tmp_mp3}'" >> "$concat_list"
done

# ffmpegで1本に結合
ffmpeg -y -f concat -safe 0 -i "$concat_list" -c copy "$OUTPUT_FILE"

句点で区切っているのは、文の途中で切ると音声の繋ぎ目が不自然になるためです。句点の位置は自然なポーズが入る場所なので、チャンクの境目が聴いていてわかりにくくなります。

音声用にテキストをリライトする

Markdownのレポートをそのまま読み上げても聴きづらいです。箇条書きの-は無音のまま消えるし、URLを読み上げられても困ります。

音声化の前に、テキストを読み上げ用にリライトしています。Markdown記法やURLの除去、表を口語的な文章に変換、固有名詞の読み対策(漢字をそのまま渡すとTTSが読み間違えることがあるので、ひらがなに開く)。

このリライト工程はAIにやらせています。プロンプトで変換ルールを指定すれば、適切に処理してくれます。

コスト

コストについてGoogle Cloud TTSの料金は、Neural2音声で100万文字あたり$16です。ただ、現在のところ100万文字も音声化していないので、料金はかかっていません。

毎朝、定時に届ける

この仕組みを毎朝6時に自動で動かしています。

自分の場合は、自作のWebアプリケーション(Claude Agent SDK + FastAPI)がMac miniで常駐していて、macOSのLaunchAgentが定時にHTTPリクエストを投げてAIエージェントを起動する構成です。

LaunchAgent (plist)  →  trigger.sh  →  HTTP POST  →  AIエージェント起動
    06:00に発火           APIに投げる       15秒ごとに完了をポーリング
                                            完了したらスマホにPush通知

ただ、これは自分が既にWebアプリを作っていたから成り立つ構成です。

同じことをもっと手軽にやるなら、Claude Codeのスケジュール実行(/schedule)が選択肢になると思います。自分は使ったことがないのですが、定時にプロンプトを実行してくれる仕組みなので、朝ブリーフィングの自動化に使えるんじゃないかな、と。

やっていることの本質は「AIに定時でプロンプトを実行させる」です。手段はClaude Codeでも、cronでCLIを叩く方法でも、GASのトリガーからGemini APIを叩く方法でも構いません。

数ヶ月動かしてみて

この仕組みを数ヶ月運用しています。

朝起きて、歯を磨きながらブリーフィングの音声を聴く。今日やるべきことが整理された状態で一日が始まる。これが日常になりました。

一番変わったのは、いいねした記事との付き合い方です。以前は溜まる一方だったのが、今は翌朝にはAIが選んだ推薦記事だけ音声で聴けています。全部は読まなくても、自分に関係ある記事だけ確実に消化できるようになりました。

それと、ブリーフィングのフォーマット自体が少しずつ変わっています。深夜0時半に動く改善提案タスクがあって、AIが日中の運用を振り返り、フォーマットの改善点を出してくれます。お得メールのピックアップやいいね記事の音声化は、この改善提案から生まれた機能です。今のブリーフィングは2ヶ月前とはかなり形が違います。仕組みが勝手に育っていく感覚は、なかなか面白いです。

AIで仕組み化する実践知を発信しています → @noprogllama

Discussion