Zettelkasten Inbox / ブロック詳細
選んだノートのNotion本文を12,000文字まで取り出し、ブラウザ側で重要な4文を抜き出す。AIは使わず、文を2文字ずつに刻んだ重なりの数え上げだけで中心の文を選んでいる。
抽象度 Lv.4(技術用語+システム上のやりとりまで/製品名・ライブラリ名は書かない)受信箱で1件のノートを選んだ瞬間に走る読み取り。そのノートのNotion本文(ページの中身)を 先頭12,000文字まで取り出して返し、ブラウザ側で重要そうな4文を抜き出して要約にする。
ここで出来た文章には2つの役目がある。1つは画面に出す要約。 もう1つは、5番のTag推薦・6番のABC Note推薦が使う点数計算の材料。 つまり「このノートは何の話か」を機械に伝える唯一の入力が、ここで作られている。
要約にAIは使っていない。文を2文字ずつに刻んで出現回数を数え、 他の文と語句を多く共有している文=話の中心にある文、として選んでいるだけである。
2. 受信箱の初期読込 → 3. 本文の取り出しと自動要約 → 4. 原典プレビュー(本文が無いときだけ)/5. Tagの推薦
GET /api/notes/{id}。要約はサーバーではなくブラウザで作る400ここより前には置けない。本文の取り出しは選ばれた1件に対してだけ行う。 受信箱に並ぶ全件の本文を先に取ると、40件なら40往復。 2番が一覧だけを返し、本文は選んだ瞬間に1件ずつ取る、という分担になっている。
ここより後ろにも置けない。5番のTag推薦と6番のABC推薦は、 この本文を材料にして点数を出す。本文が無ければ題名とコメントだけが材料になり、精度が落ちる。 だから選択の前に本文が揃っている必要がある。
要約をサーバーではなくブラウザでやっている理由。 同じ本文から作った特徴量(2文字の並びの集合)を、要約にも推薦にも使い回している。 これをサーバーでやると、利用者がコメントを書き換えるたびに通信が必要になる。 ブラウザに置いたことで、「候補を更新」ボタンを押した瞬間に、通信ゼロで推薦が作り直される。
| 工程 | 主体 | やりとりの内容 | 方向 |
|---|---|---|---|
| 3-1 | ブラウザ → 本文API | 選んだノートのID | → |
| 3-2 | 本文API(内部) | IDの形の検査 | ↻ |
| 3-3 | 本文API → Notion | ページ直下のブロックを100件ずつ取得 | → |
| 3-4 | 本文API(内部) | ブロックの種類ごとに文字を取り出す | ↻ |
| 3-5 | 本文API(内部) | 12,000文字で打ち切り、印を立てる | ↻ |
| 3-6 | 本文API → ブラウザ | 本文の文字列と、打ち切りの有無 | ← |
| 3-7 | ブラウザ(内部) | 文に割り、中心となる4文を選ぶ | ↻ |
3-1 左の一覧でノートを1件押すと、その本文だけを取りに行く。 別のノートに切り替えると、前の取得は結果が来ても捨てられる。
技術的には GET /api/notes/{id}、
Cache-Control: no-store。IDはURLの一部(パス)に載せる。
ブラウザ側は「取り消し用の印」を1つ持っていて、切り替えが起きたら印を立て、
あとから届いた応答を無視する。速く連打したとき、古い本文が新しいノートの画面に出る事故を防ぐ定石。
3-2 番号の形だけを先に確かめる。
技術的には ここだけ検査がゆるく、
16進の文字とハイフンで32〜36文字という条件しか見ていない。
2番や8番のように「32桁ちょうど、または 8-4-4-4-12」とは指定していないので、
- の位置がおかしい文字列も通る。通ったあとはNotionが 404 で弾くため実害は無いが、
同じアプリの中で検査の厳しさが揃っていないのは確か。
3-3 Notionのページは「ブロック」という部品が縦に並んだ構造なので、 その並びを先頭から100個ずつもらう。
技術的には GET /v1/blocks/{id}/children?page_size=100。
「続きの目印」が返る限り、それを付けて繰り返す。
入れ子(トグルの中、リストの子)には降りないので、
折りたたみの中に書いた内容は本文として拾われない。
この点は10番のサブ埋没判定(そちらは入れ子の奥まで降りる)と対照的。
3-4 1つ1つのブロックから、文字だけを取り出す。 画像や埋め込みのように文字を持たないものは、キャプション(説明文)があればそれを本文として扱う。
技術的には ブロックの種類名を鍵にして中身を取り出し、 装飾情報を捨てて素の文字だけを連結する。 音声・ブックマーク・埋め込み・ファイル・画像・リンクプレビュー・PDF・動画の8種類は URLを本文に混ぜないと決められている。 これは要約の質に直接効く判断で、長いURLが1つ紛れ込むだけで、 2文字の並びの数え上げが大きく歪むため。
3-5 文字を足していって12,000文字に達したら、そこで止める。 止めたことは画面にも伝える。
技術的には 1ブロック足すごとに現在の合計長を測り、 上限に達したら取得のページ送り自体を打ち切る。 上限は保存できるコメントの上限(12,000文字)と同じ値に揃えられている。 打ち切ったときは画面に「先頭12,000文字を対象にしています。」と出る。 黙って切らずに、切ったことを見せるのは、要約が話の後半を見ていない可能性を利用者に知らせるため。
3-6 本文と「途中で切ったかどうか」を返す。ここまでがサーバーの仕事。
技術的には 200 + application/json で
text と truncated の2項目だけ。要約は含まれない。
要約という重い処理をサーバーに置かないことで、このAPIは「取ってきて連結するだけ」に保たれている。
3-7 ブラウザは受け取った本文を文に割り、価値の低い行を捨て、 残った文の中から「話の中心にいる文」を4つ選ぶ。
技術的には 4段階。
(1) 文に割る:改行で行に分け、各行を 。!?!? で文に割る。
(2) 捨てる:記号と空白を除いて10文字未満の断片、
「copyright」「ログイン」「会員登録」「関連記事」などで始まる定型行、
年月日で始まる行、そして同じ内容の重複(記号・空白を除いた形が一致するもの)を落とす。上限80文。
(3) 点数を付ける:各文を2文字の並び(バイグラム)の集合に変換し、
「その並びが本文全体で何回出たか」の合計を、集合の大きさの平方根で割る。
要するに「他の文とよく語句を共有している文ほど、話の中心にいる」という考え方で、
平方根で割るのは長い文が有利になりすぎるのを抑えるため。
これに「読みやすい長さ(140文字までは加点、220文字を超えると減点)」と
「先頭に近いほど加点、1文目は特別に大きく加点」を足す。
(4) 並べ直す:点数の高い順に4文選び、元の登場順に戻して連結し、560文字まで。
点数順のまま並べると話の順序が壊れるので、選ぶのは点数、並べるのは元の順、という二段構え。
400 +「ノートIDが不正です。」404 がそのまま返る。
画面は本文の代わりに「Notionで本文を確認する →」というリンクを出す。
このとき5番・6番の推薦は、題名とコメントだけを材料に動き続ける(止まらない)。※ 2026年8月14〜15日時点の zettelkasten-inbox のプログラムを読んで作成しました。過去の設計資料は参照していません。
※ 番号は全体図・この解説・シーケンス図で共通です。工程番号は「ブロック番号-連番」で書いています。