• #TODO
  • #Python
  • #OCR
  • #ツール開発
  • #SQLite
  • #FastAPI
  • #Vue.js
開発アクティブ

ハイライト抽出ツール - 実装TODO

最終ゴール

Kindleのハイライトビューアのようなウェブアプリを作成する。

画面構成

+------------------+------------------------+------------------+
|                  |                        |                  |
|   本タイトル     |    ハイライト一覧      |   画像ビューア   |
|   一覧          |    (クリック可能)     |                  |
|                  |                        |                  |
|   - 本A         |    - テキスト1         |   [ハイライト    |
|   - 本B         |    - テキスト2         |    された箇所の  |
|   - 本C         |    - テキスト3         |    画像を表示]   |
|                  |                        |                  |
+------------------+------------------------+------------------+
     左側                  中央                    右側

用途

  • ハイライトを文字列として識別 → 生成AIに読み込ませる
  • 画像で実際の内容を確認

技術スタック

レイヤー技術
バックエンドPython + FastAPI
フロントエンドVue.js (Vite)
データベースSQLite + FTS5
OCRyomitoku
画像処理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、プレーンテキスト)

現在の作業

次のタスク(優先順):

  1. 横書きテスト - 合格基準: 3冊×10ページ、精度90%以上
  2. 出力スキーマ確定 - SQLite投入用のJSON形式を決める
  3. Phase 2移行 - SQLiteスキーマ作成・データ投入

ファイル名規則

No387_お金持ちになれる黄金の羽根の拾い方_墨消し済み_line_ページ_001.jpg
     ↑
     タイトル部分(アンダースコア区切りで抽出)

抽出ルール

  • No{数字}_ で始まる場合 → その後ろからタイトル開始
  • _墨消し済み _line _ページ などは除外

フォールバック

タイトル抽出に失敗した場合:

  1. 同フォルダ内の _manual_title.txt を確認
  2. なければ「Unknown - {フォルダ名}」をタイトルとして使用
  3. ビューアで後から手動編集可能にする

座標系の定義

項目
原点画像左上
X軸右方向が正
Y軸下方向が正
単位ピクセル
回転なし前提(回転済み画像を入力)

表示時は image_width, image_height を使って正規化し、異なる解像度でも正しく表示する。