開発アクティブ
ハイライト抽出ツール - 実装TODO
最終ゴール
Kindleのハイライトビューアのようなウェブアプリを作成する。
画面構成
+------------------+------------------------+------------------+
| | | |
| 本タイトル | ハイライト一覧 | 画像ビューア |
| 一覧 | (クリック可能) | |
| | | |
| - 本A | - テキスト1 | [ハイライト |
| - 本B | - テキスト2 | された箇所の |
| - 本C | - テキスト3 | 画像を表示] |
| | | |
+------------------+------------------------+------------------+
左側 中央 右側
用途
- ハイライトを文字列として識別 → 生成AIに読み込ませる
- 画像で実際の内容を確認
技術スタック
| レイヤー | 技術 |
|---|---|
| バックエンド | Python + FastAPI |
| フロントエンド | Vue.js (Vite) |
| データベース | SQLite + FTS5 |
| OCR | yomitoku |
| 画像処理 | OpenCV |
プロジェクト構造
highlight-viewer/
├── backend/ # FastAPI
│ ├── app/
│ │ ├── __init__.py
│ │ ├── main.py # FastAPIエントリーポイント
│ │ ├── database.py # SQLite接続
│ │ ├── models.py # Pydanticモデル
│ │ ├── routers/
│ │ │ ├── books.py # /api/books
│ │ │ ├── highlights.py # /api/highlights
│ │ │ └── upload.py # /api/upload(PDF/画像アップロード)
│ │ └── services/
│ │ ├── ocr.py # yomitoku呼び出し
│ │ ├── highlight_detector.py # OpenCV処理
│ │ └── file_processor.py # PDF→画像変換等
│ ├── requirements.txt
│ └── run.py
│
├── frontend/ # Vue.js
│ ├── src/
│ │ ├── components/
│ │ │ ├── BookList.vue # 左: 本一覧
│ │ │ ├── HighlightList.vue # 中央: ハイライト一覧
│ │ │ ├── ImageViewer.vue # 右: 画像ビューア
│ │ │ └── UploadModal.vue # アップロードUI
│ │ ├── views/
│ │ │ └── Home.vue
│ │ ├── api/ # API呼び出し
│ │ │ └── index.ts
│ │ └── App.vue
│ ├── package.json
│ └── vite.config.ts
│
├── data/ # データ永続化(gitignore)
│ ├── highlights.db # SQLite
│ ├── images/ # 処理済み画像
│ │ └── {book_id}/ # 書籍ごと(連番)
│ │ ├── page_001.jpg
│ │ └── page_002.jpg
│ └── uploads/ # アップロード一時保存
│
├── scripts/ # CLIツール(既存スクリプト)
│ ├── extract_highlights.py # 既存のOCR処理
│ └── batch_import.py # 一括インポート用
│
└── README.md
アップロードフロー
[ユーザー]
↓ ドラッグ&ドロップ(PDF or 画像)
[frontend: UploadModal.vue]
↓ POST /api/upload
[backend: upload.py]
↓ data/uploads/ に一時保存
↓ PDF→画像変換(必要なら)
↓ OCR + ハイライト検出
↓ DB登録 + data/images/{book_id}/ に画像保存
↓ 一時ファイル削除
[完了]
入力方法
| 方法 | 対応 |
|---|---|
| GUI(ドラッグ&ドロップ) | /api/upload エンドポイント |
| CLI(直接ファイル配置) | scripts/batch_import.py で処理 |
どちらも同じDB・画像フォルダに格納されるので混在可能。
Phase 1: データ抽出スクリプト
完了条件
- 横書きテスト合格(後述の基準を満たす)
- 出力スキーマ確定(SQLite用)
完了 ✅
- ハイライト検出(OpenCV)- 黄色・オレンジ・赤対応
- yomitokuでOCR
- 文字単位でハイライト部分を抽出
- 縦書き対応(読み順ソート)
- PDF→画像変換対応
- 一時ファイル自動削除
- 出力JSONにソース情報追加
- 複数ファイル対応
- ディレクトリ内の複数PDFを全て処理
- 画像ファイルをタイトルごとにグループ化
- 各ファイルごとにタイトルを抽出(ファイル名から)
未完了 📋
- 横書き対応テスト
- 横書き文章でハイライト抽出が正しく動作するか確認
- 必要に応じて調整
- 合格基準: 横書きサンプル3冊・各10ページ以上で抽出精度90%以上
- 出力データ構造の改善
- SQLite用スキーマに合わせた出力形式
- ハイライト箇所の座標情報を追加(画像表示用)
- 元画像のパス/参照を追加
Phase 2: データ管理(SQLite)
データベーススキーマ
-- 書籍
CREATE TABLE books (
id INTEGER PRIMARY KEY,
title TEXT NOT NULL,
author TEXT,
source_path TEXT, -- 元PDF/画像フォルダ
created_at TEXT DEFAULT CURRENT_TIMESTAMP
);
-- ハイライト
CREATE TABLE highlights (
id INTEGER PRIMARY KEY,
book_id INTEGER REFERENCES books(id),
page_num INTEGER,
text TEXT NOT NULL,
-- 座標系: 画像ピクセル座標(左上原点、回転なし前提)
bbox_x INTEGER, -- 左上X
bbox_y INTEGER, -- 左上Y
bbox_w INTEGER, -- 幅
bbox_h INTEGER, -- 高さ
image_width INTEGER, -- 元画像の幅(座標正規化用)
image_height INTEGER,-- 元画像の高さ
image_path TEXT, -- 該当ページ画像
confidence REAL, -- OCR信頼度 (0.0-1.0)
created_at TEXT DEFAULT CURRENT_TIMESTAMP
);
-- 全文検索用(FTS5)
CREATE VIRTUAL TABLE highlights_fts USING fts5(
text,
content=highlights,
content_rowid=id
);
未完了 📋
- SQLiteデータベース構築
- スキーマ作成スクリプト
- 抽出結果をDBに投入するスクリプト
- FTS5インデックス自動更新
- データディレクトリ構成
-
data/フォルダ作成 -
data/images/{book_id}/の自動作成処理 -
data/uploads/の一時ファイル管理
-
- メタデータ抽出
- ファイル名からタイトル抽出(アンダースコア区切り)
- フォールバック: 抽出失敗時は手動入力 or
_manual_title.txtから読み込み - ページ数、ハイライト数などの統計
Phase 3: ウェブビューア(FastAPI + Vue.js)
バックエンド(FastAPI)
- プロジェクトセットアップ
-
backend/ディレクトリ作成 - FastAPI + uvicorn セットアップ
- CORS設定(フロント開発用)
-
- APIエンドポイント
-
GET /api/books- 書籍一覧 -
GET /api/books/{id}- 書籍詳細 -
GET /api/books/{id}/highlights- 書籍のハイライト一覧 -
GET /api/highlights/search?q=- 全文検索(FTS5) -
POST /api/upload- PDF/画像アップロード -
GET /static/images/{book_id}/{filename}- 画像配信
-
フロントエンド(Vue.js)
- プロジェクトセットアップ
-
frontend/ディレクトリ作成 - Vite + Vue 3 + TypeScript セットアップ
- Tailwind CSS(またはお好みのCSS)
-
- コンポーネント
-
BookList.vue- 左サイドバー: 本タイトル一覧 -
HighlightList.vue- 中央: ハイライト一覧(検索・フィルタ) -
ImageViewer.vue- 右サイドバー: 画像ビューア(座標で枠表示) -
UploadModal.vue- ドラッグ&ドロップアップロード
-
- 機能
- ハイライトクリック → 対応画像表示
- テキストコピー機能(生成AI用)
- 全文検索(FTS5活用)
- エクスポート機能(Markdown、プレーンテキスト)
現在の作業
次のタスク(優先順):
- 横書きテスト - 合格基準: 3冊×10ページ、精度90%以上
- 出力スキーマ確定 - SQLite投入用のJSON形式を決める
- Phase 2移行 - SQLiteスキーマ作成・データ投入
ファイル名規則
No387_お金持ちになれる黄金の羽根の拾い方_墨消し済み_line_ページ_001.jpg
↑
タイトル部分(アンダースコア区切りで抽出)
抽出ルール
No{数字}_で始まる場合 → その後ろからタイトル開始_墨消し済み_line_ページなどは除外
フォールバック
タイトル抽出に失敗した場合:
- 同フォルダ内の
_manual_title.txtを確認 - なければ「Unknown - {フォルダ名}」をタイトルとして使用
- ビューアで後から手動編集可能にする
座標系の定義
| 項目 | 値 |
|---|---|
| 原点 | 画像左上 |
| X軸 | 右方向が正 |
| Y軸 | 下方向が正 |
| 単位 | ピクセル |
| 回転 | なし前提(回転済み画像を入力) |
表示時は image_width, image_height を使って正規化し、異なる解像度でも正しく表示する。