はじめに
前回:第4回:カレンダー・トレンドワード・検索・総括で「学べるサイト」にする
シリーズ公開後、翌朝6時にちゃんと自動実行されて、今日のおすすめが並んでいるのを確認できました。
そして毎朝使い始めると、また欲しいものが出てきます。
「今は時間ないから、この記事あとで読みたい」
「この記事、Geminiの無料枠じゃなくて、いつも使っているAIでじっくり聞きたい」
「トレンドワード、なんだか数が少なくない?」
番外編では、こうした「使ってみて気づいたこと」をもとに足した機能を紹介します。
こんな方におすすめ
- 作ったアプリを、使いながら少しずつ改善していきたい方
- 自分のアプリから、ClaudeやChatGPTなどに質問を渡す仕組みを作りたい方
- AIのAPI利用回数を抑えながら、機能を増やしたい方
- Supabaseで、あとから列を追加するときの進め方を知りたい方
お気に入りと「後で見る」
朝は総括とおすすめをざっと眺めるだけで、じっくり読むのは夜、という使い方が多くなりました。そこで、記事ごとに「後で見る」と「お気に入り(☆)」のボタンを付けました。
- 後で見る:時間がないときの一時置き場。読んだら外す
- お気に入り:何度も見返したい記事をずっと残しておく場所
データベースには、既存の記事テーブルに列を足しただけです。
alter table articles
add column favorite boolean not null default false,
add column read_later boolean not null default false,
add column opened_at timestamptz;
ボタンは、押した瞬間に見た目を切り替えて、保存は裏で行うようにしています。保存に失敗したときだけ元に戻すので、押したときの反応が軽くなります。
最後の opened_at は、記事を開いた日時の記録です。今はまだ使っていませんが、ある程度たまったら「よく読む分野」をおすすめの選び方に反映させる予定で、そのためのデータを先に集め始めています。
質問は「自分の好きなAI」で
当初は、記事についてAIに質問できるチャットを、要約と同じGemini APIで作るつもりでした。でも、考えてみると気になる点がありました。
- 無料枠なので、質問の回数を気にしながら使うことになる
- 普段はClaudeを契約して使っているので、そちらでじっくり聞きたい
- 人によって、契約しているAIサービスは違う
そこで、サイトの中で答えを出すのではなく、記事の情報をまとめた質問文を持って、自分の好きなAIの画面を開くボタンにしました。
export const PROVIDERS = {
claude: { name: "Claude", url: (q: string) => `https://claude.ai/new?q=${encodeURIComponent(q)}` },
chatgpt: { name: "ChatGPT", url: (q: string) => `https://chatgpt.com/?q=${encodeURIComponent(q)}` },
gemini: { name: "Gemini", url: () => "https://gemini.google.com/app" },
perplexity: { name: "Perplexity", url: (q: string) => `https://www.perplexity.ai/search?q=${encodeURIComponent(q)}` },
} as const;
URLに質問文を入れて開けるサービスは、開いた時点で入力欄に文章が入った状態になります。念のため質問文はクリップボードにもコピーしているので、自動で入らないサービスでも貼り付けるだけで使えます。使うAIはサイドバーで選べて、ブラウザに保存しておくようにしました。
役割分担はこうなりました。
| 用途 | 使うAI | 理由 |
|---|---|---|
| おすすめ選別・要約・総括・タグ付け | Gemini API(無料枠) | サイトの裏側で毎朝自動で動かすため |
| 記事についての質問 | 自分が契約しているAI | 回数を気にせず、じっくり聞けるため |
ちなみに、Claudeでこの方法を使うと「このプロンプトを実行する前にご注意ください」という注意文が表示されました。URLから自動で入力された文章なので、念のため確認を促しているのだと思います。自分のサイトで作った質問文なので、そのまま送信して使っています。
全記事にタグを付けて、トレンドワードの精度を上げる
第4回で作ったトレンドワードは、要約した記事のキーワードを数えていました。ただ、要約するのは1日10〜20件ほどで、残りの80件以上は集計に入っていませんでした。
そこで、毎朝の処理にタイトルからタグを付けるステップを足しました。タグが付いていない記事のタイトルをまとめて渡すので、Geminiの呼び出しは1回増えるだけです。
表記ゆれを防ぐために、よく使われている既存のタグの一覧もプロンプトに入れています。
const prompt = `次の記事それぞれに、内容を表すタグを1〜3個付けてください。
- 一般的な正式名称に統一する(例: 「検索拡張生成」ではなく「RAG」)
- 下の「既存のタグ」に同じ意味のものがあれば、必ずその表記を使う
- 当てはまるものが無ければ空の配列にする
既存のタグ:
${vocabulary.join("、")}`;
タグは text[] 型の列に保存し、GINインデックスを付けました。すでに要約済みの記事は、キーワードをそのままタグに写しています。
alter table articles add column tags text[];
create index articles_tags_idx on articles using gin (tags);
update articles
set tags = (select array_agg(distinct k->>'term') from jsonb_array_elements(keywords) k)
where keywords is not null and jsonb_array_length(keywords) > 0;
これで、トレンドワード・キーワードの記事一覧・検索・関連キーワードを、すべて同じタグで扱えるようになりました。要約していない記事にもタイトルの下にタグが並ぶので、気になった言葉からそのまま関連記事をたどれます。
小さな改善:カレンダーの点をなくした
カレンダーでは、おすすめがある日に点を付けて、「点の付いた日におすすめがあります」と書いていました。でも、自動実行が毎日動くようになると、ほぼ毎日おすすめがあります。
おすすめが無い日はもともとグレーで押せない表示にしていたので、点と説明文は消しました。機能を足すだけでなく、使ってみて不要になったものを減らすのも、育てていく中で大事なことだと感じました。
まとめ
- 「後で見る」と「お気に入り」で、朝に眺めて夜に読む使い方ができるようになった
- 記事を開いた記録を、将来のおすすめ改善のために先に集め始めた
- 質問は自分の契約しているAIに任せ、回数を気にせず聞けるようにした
- 全記事にタグを付けて、トレンドワードの精度を上げた(Geminiは1日4回)
- 使ってみて不要になった表示は、思い切って消した
今後は、1週間の流れを振り返る週次まとめや、よく読む分野をおすすめに反映する機能に取り組む予定です。毎朝使いながら、また「こうだったらいいな」が出てきたら、少しずつ足していきます。