1 min read

自分が読みたいニュースを集めるために、ニュースアプリを作った

自分が読みたいニュースを集めて読むためのWebアプリ、Briefingを作っています。

複数のメディアが報じた記事を出来事ごとにまとめて、一覧から気になったものを読めるアプリです。 ニュースを読む場所と、その選び方を自分向けに改善していく場所を、一緒に作りたいと思ったのがきっかけでした。

自分が読みたいニュースを、読みやすい場所に

もともとはHermes Agentで、ウォッチしておくとよい記事をTelegramに通知していました。 ただ、インターフェースがチャットなので、ニュースを読む場所としては単純に読みづらかった。 欲しかったのは、自分が読みたいニュースがキュレーションされていて、それを見渡せるUIでした。

それなら通知先を変えて一覧にすればよさそうですが、気になっていたのは、その先です。

この手のサービスは、記事を集めること以上に、集めた中から何を自分に見せるかが大事だと思っています。 最初に決めた選び方がずっと自分に合うとも思えないので、作って終わりにはしたくありませんでした。 使っているときに「これは読みたい」「これはそこまででもない」と思ったことを残して、選び方の改善につなげたい。 そのフィードバックをどう受け取るかも含めて、Web UIなら自分でカスタマイズしやすい。 読む体験と、使いながら改善していく体験を作るために、スクラッチで始めました。

記事ではなく「ストーリー」が並ぶ

トップページに並ぶ単位は、メディアの記事ではなく「ストーリー」にしています。 同じ出来事について複数のメディアが記事を書いていたら、それらを一つにまとめる。 6媒体が報じていれば、6本の記事が並ぶのではなく、6つのソースを持つ一つのストーリーとして表示します。

Briefingのトップページ。ヘッダーの下にAmazon貨物機のストーリーが並び、2媒体が報じていることと代表記事へのリンクが見える。

まず出来事を見渡して、気になったものは元の記事を読みにいく、という使い方を考えています。 ソース記事へのリンクは一覧にも出していて、詳細ページでは、どのメディアが何を報じたかを確認できます。 この後に載せている詳細画面も、一覧と同じAmazon貨物機のストーリーです。

ちなみに、現時点では生成AIによる要約は作っていません。詳細のリード文には、最初に報じた記事のdescriptionがあれば使っています。

並び順は、ストーリーの新しさと、報じている媒体数を使って決めています。 複数の媒体が取り上げた出来事を拾いやすくするための、最初の基準です。

ただ、広く報じられていることと、自分が読みたいことは同じではありません。 ここは使いながら育てたい部分です。

また、クーポン記事などはルールで判定して、一覧の対象から外しています。 ニュースとして読みたいものに混ざっているのが気になったので、まずはこうしたノイズを減らすところから手を入れました。

読みながら、自分向けのキュレーションを育てる

改善のために、ストーリーの詳細ページに自由記述のフィードバックフォームを置きました。 たとえば「これより、さっきのセキュリティのニュースを上に出してほしい」「この二つの記事は別の出来事では」といったことを書けます。 単にgood / badを押すより、そのとき何が気になったのかを言葉で残せる形から始めています。

ストーリー詳細。The VergeとBloombergの3記事が一つのストーリーにまとまっている。

その下に、フィードバックを残せるフォームを置いています。

ストーリー詳細のフィードバックフォーム。順位や記事のまとまり方について、自由記述で送信できる。

コメントだけでなく、対象のストーリーやソース記事の情報も一緒に保存しています。 トップの一覧から同じタブで開いた場合は、そのときの並び順も残します。 後でランキングやストーリーのまとまり方が変わっても、何を見て書いたフィードバックなのかを振り返れるようにするためです。 いまはここまでで、投稿すると自動で順位が変わるわけではありません。

わざわざ評価用の管理画面を開いて、ニュースに点数をつけ続けるのは、自分でもやらなくなる気がしています。 普段読む画面の中で、気になったときに一言残すくらいなら続けられるかもしれない。 その記録がたまれば、キュレーションのどこを変えるべきかを考えたり、変更前後を評価したりする材料になるのでは、という仮説です。

まずは自分で使って、反応をためてみます。

裏側はどう動いているか

記事は各メディアのRSSから定期的に取得しています。 一覧の対象にしない記事を除外した後、内容の近さを使ってストーリーにまとめ、ランキングを計算して画面に出す、という流れです。

RSSから記事を取得し、不要な記事の除外、embedding生成、ストーリーへの集約、ランキング計算を経て一覧に表示する処理フロー。

記事をまとめるために使っているのが、embeddingです。 テキストを内容の近さを比較できる数値の並びに変換して、近い記事を同じストーリーの候補にします。 似た話題だからといって同じ出来事とは限らないので、まとめ方もフィードバックを通じて確かめていきたいところです。

実行基盤はCloudflareにまとめています。WebアプリはWorkers、定期的な取得と処理はWorkflows、データの保存はD1、embeddingの生成はWorkers AIが担当しています。 取得からランキングまでの処理はステップに分け、途中で失敗した場合にそのステップをリトライできるようにしています。

自分向けのキュレーションは、まだこれからです。 ただ、読む場所と、読んで感じたことを残す場所はできました。

まずはここを日々使いながら、自分が読みたいニュースに近づけていくつもりです。