すくらっぷ あんど びるどー(したい)

日々やった事のメモとかまとめ。

【AI】Zoteroの蔵書データを可視化するダッシュボードを作成してもらった【Antigravity】

文献管理ソフトZoteroで読書管理をしている。基本的には読んだ本を登録しているだけだが、レポート作成時に必要な本来の文献管理ソフトとしても使用している。特にwebクリップが便利でこれで参考文献に必要な情報が手に入りやすいから助かっている。
今回はそのデータを可視化したかったので、AIにダッシュボードを作成してもらった。

UI構成

  • 蔵書累計推移: 1年間でどれだけ知識が積み上がったか
  • 読書活動ヒートマップ: どの曜日に新刊を追加したか(GitHub風)
  • 読書状況状況: 「読了」「読書中」「未読」の正確な配分
  • タグクラウド: 自分の関心の偏りを視覚化
  • トップ著者名: 著者名の数を可視化

技術構成とセットアップ

技術スタック

  • Frontend: Next.js 14+ (App Router), Tailwind CSS
  • Charts: Recharts, Framer Motion
  • Visuals: react-calendar-heatmap (GitHub風ヒートマップ)
  • Database: SQLite3 (node-sqlite3)

インストール

プロジェクトを作成したら、以下のパッケージを導入

npm install sqlite3 recharts react-calendar-heatmap date-fns lucide-react framer-motion

つまずいた部分

SQLITE_BUSY(データベースロック)の回避

Zoteroが起動していると、DBファイルはロックされます。これを避けるため、読み取り時にファイルを一時コピーするのがエンジニアらしい賢い解決策です。

// lib/zotero.js
import fs from 'fs';
import sqlite3 from 'sqlite3';

const SOURCE_DB = 'D:\\Zotero\\library\\zotero.sqlite';
const TEMP_DB = './zotero-temp.sqlite';

export async function getStats() {
    // 安全にコピーを作成して読み取り専用で開く
    fs.copyFileSync(SOURCE_DB, TEMP_DB);
    const db = new sqlite3.Database(TEMP_DB, sqlite3.OPEN_READONLY);
    // ...クエリ実行
}

とかいってるけど、初めは直接さわっていたぞ。
なもんで起動中には開かんってことになった。

純粋な本だけを抽出する

Zoteroの items テーブルにはPDFやノートも混ざっています。これを除外しないと、蔵書数が数千件に膨れ上がってしまいます。

/* 書籍、レポート、ウェブページなど実体のあるアイテムのみ抽出 */
WHERE itemTypeID NOT IN (
    SELECT itemTypeID FROM itemTypes 
    WHERE typeName IN ('attachment', 'note')
)
AND itemID NOT IN (SELECT itemID FROM deletedItems) -- ゴミ箱も除外

これもアイテムを弾くのができなくて、そこで詰まって調査して初めてできた。
でも頼めば出来るからスゲーなと思う。部下を持つ気持ちはこんなものなのかもしれない。

読書ステータスの動的集計

Zoteroの「読んだ本」という名前のコレクション(フォルダ)と連携させるクエリです。

SELECT COUNT(DISTINCT ci.itemID) as count 
FROM collectionItems ci
JOIN collections c ON ci.collectionID = c.collectionID
WHERE c.collectionName = '読んだ本'

これはかってにAIが判断した。そもそもそんなカテゴリはない。
とはいえ確かにそれがあれば分かりやすい。が、やるかどうかはちょっと分からん。

プロジェクトのディレクトリ構造

.
├── src/
│   ├── app/
│   │   ├── api/zotero-stats/route.js # データ提供API
│   │   ├── globals.css               # ガラス質UIの定義
│   │   └── page.js                  # メイン画面
│   ├── components/
│   │   └── Dashboard.js             # グラフ描画コンポーネント
│   └── lib/
│       └── zotero.js                # DB操作・集計ロジック
├── public/
└── 起動.bat                          # ワンクリック起動

まとめ

これでとりあえず自分の興味関心とどれだけ文章読んでいるか、好きな著者は何かとかが視覚情報として得られるようになった。単純に見ていて楽しいのと、どんなの読んでいるかが分かりやすくなった。
ただブクログとかで読書データを管理しているなら正直これはいらないと思う。
レポート書いたり課題作成したりするときに、文献管理が必要でこっちに移動した経緯があって、それで使用しているので、Zoteroでなくてはならい理由って本来の読書だけならいらないと思う。
他のサービスを素直に使った方が確実にはやい。UIとか整っているし。
とはいえできたのでこれから使用していく。