技術ブログ
724本・549時間のYouTube動画を全文検索できるようにするまでに、 何を作って、何を壊したかの記録です。うまくいった話だけでなく、 失敗と、その後どう仕組みで止めたかも全部書いています。 数字はすべて実データから取っています。
| Python | 3.11.3 |
|---|---|
| DB | SQLite 3 (FTS5) / 386MB |
| Web | Flask + Jinja2 / Vercel |
| 音声認識 | mlx-community/whisper-large-v3-turbo |
| 規模 | 724本 / 549時間 / 1,305,865 セグメント |
-
01「あの話どの回だっけ」を検索可能にするまで。197万フレームを見る案を捨てて0.5%に絞った
音声認識にかけて終わりのつもりだった。壊れるのは固有名詞と専門用語だけで、そこがこの番組の価値そのものだった。取り得た構成と、採らなかった理由。
-
02Whisperは日本語のとき、聞いていない話者名を書く。無音で「ご視聴ありがとうございました」と言うのと同じ理由
文字起こし97,000行に、出演していない人の名前が入っていた。実装を変えても、モデルを変えても同じ数字が出る。英語では出ない。再現手順つきで、外れた推測も残して書く。
-
03置換辞書で4,056箇所を自動修正する。ただし辞書の向きが逆だと永遠に壊れ続ける
124行のCSVで機械的に直す仕組みと、その辞書自体を全件検算するスクリプトを書いた理由。
-
04LLMに校正させるとき、精度より効いたのは「作文の禁止」だった
文脈から自然な日本語を作れてしまうのが危ない。直してよい5つの型を定義し、それ以外は証拠を見に行かせる。
-
05焼き込み字幕をOCRで答え合わせする。fps=1にしないと19件中9件を取りこぼす
該当区間だけ切り出してタイル画像にまとめ、テロップを正解データとして使う。フレーム間隔の落とし穴。
-
06「要確認」を付けて確認する仕組みにした。ただし漏れが残るので、いまは全文を読んでいる
手で直した276件のうち233件は、機械が印を付けていない箇所だった。設計は印を追う形にしたが、精度が追いつくまでは全部読む。
-
07書き込み口を2つにしたら、人が入れた修正が黙って消えた
Upstash のオーバーレイと、バッチによる直接更新が衝突。drain-first と base 照合で lost update を止めるまで。
-
08追記専用の編集台帳とデプロイ前検査で、事故を出荷前に止める
193,849行の edit_stage テーブルと、5項目のプリフライト。証跡のない変更は本番に出せないようにした。
-
09SQLite FTS5(contentless)の索引が更新されず、テストは緑のままだった
日本語をバイグラムで投入している全文検索索引が、元テーブルの更新に追随していなかった。検算の作り方の話。
-
10日本語の全文検索を「表記が違っても引ける」ようにする正規化と読み
長音・中黒・全角半角・カタカナ英語。text_search と text_yomi の2列を持たせて吸収する。
-
11「この単語、もっと出てたはずなんだけど」を機械で探すツールを書いた
少なく見える語は、たいてい別の字で起こされている。読み・惜しい綴り・語尾・出ないはずがない回、の4通りで洗う。
-
12語ごとの「いつ・どの回で語られたか」を1枚に置く。時間軸をそのまま使うと潰れる
空いた期間の幅を頭打ちにして詰める。回と回を結ぶ線は、番組が過去回を明言した箇所だけにした。拡大縮小の中でカードを掴む話も。
-
13番組の言葉を年表にする。正規表現とSQLを組み合わせたら静かに0件になった
130万行の集計をページに置かない、表記ゆれを機械で束ねない、言い方が毎回変わる語をどう拾うか。載せない判断も含めて。