Rufly

Webページや選択したテキストを、LLMで要約するサービスを作った。

Chrome拡張のサイドパネルから、見ているページをそのまま要約できる。サイドパネルには要約・履歴・利用状況・設定のタブがあり、同じ内容はWebのダッシュボードからも見られる。

概要

以前、同じようにページを要約するChrome拡張 Roughlet(旧 tl;dr) を作った。あれは、ユーザーが自分でOpenAIのAPIキーを用意して設定する方式だった。

ただ、これがけっこうハードルが高い。OpenAIにサインアップして、支払い情報を設定して、APIキーを取得して、拡張をインストールして、設定画面にキーをセットする……という手順を全部踏まないと使えない。ガイドを書くのも難しい。

どうせそんなに使われないだろうし、仮に使いまくられたとしてもたかが知れている。なので、一旦は自分のAPIキーで、誰でもそのまま使える形にすることにした。

そのぶん、バックエンドを持つことになった。使いすぎを防ぐためにクレジット制にしている。

クレジット制

トークン課金をそのまま見せてもわかりにくいので、1000トークン = 1クレジットに丸めている。

  • 新規ユーザーに初期100クレジット
  • 要約1回ごとに、使ったトークン量 ÷ 1000(切り上げ)を消費
  • 毎日0時に、残量が少ないユーザーへ補充

補充の量は、登録ユーザー数に応じて変える段階制にした。人が少ないうちは多めに配って、増えてきたら絞る。今のところ人は少ないので、多めに配られる。

使い方

Chrome拡張のアイコンを押すとサイドパネルが開く。

ページの本文は自動で検出する。<article><main><body> の優先度で、300文字以上のかたまりを探す。テキストを選択してコンテキストメニューから要約することもできる。

うまく拾えないときのために、ページ上の要素をクリックして範囲を指定する「ピッカーモード」もある。

出力は essential / digest / detailed の3段階。auto にしておくと入力の長さで勝手に決まる。出力言語は21言語から選べる。

要約した結果は履歴に残るので、後から見返せる。

自動検出はまだ甘い

要約したい長文らしき箇所を自動で選んでターゲットにしているが、まだ完全ではない。

本当は、利用規約やプライバシーポリシーのページを開いたら、勝手に要約ボタンが出てくるくらいにしたい。

API・Web・拡張の3本立て

3つのパーツでできている。

  • API — NestJS。要約リクエストの仲介、認証、クレジット管理。Cloud Run で動かしている
  • Web — SolidJS + Vite + Tailwind CSS のダッシュボード。Cloudflare Pages
  • Chrome拡張 — SolidJS + Manifest V3。サイドパネルのUIと、ページ解析の content script

DBは PostgreSQL(本番は Neon)、ORMは Drizzle。UIコンポーネントは自作の soluid を使っている。Cloud Scheduler などの GCP リソースは Terraform で管理。ランタイムは全部 Bun。

SolidJS を使っているのは、個人のプロジェクトなので単に趣味。自分にとっては一番楽ではある。

たまにしか使わないが

自分でもたまに使うが、本当にたまにしか使わない。

利用規約やプライバシーポリシーはもちろん、興味はあるんだけど自分の読める言語で書かれていなくて、しかも長い、みたいな記事を読むときに良いかもしれない。