4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【個人開発】ChatGPTの履歴JSONを「完全ローカル」で解析する爆速ビューアを作った話

Last updated at Posted at 2025-11-29

はじめに

はじめまして、@takumi です。平日は戦略コンサルとして働きつつ、週末はコードを書いてリフレッシュしています。仕事で感じる「あったらいいな」を、趣味で形にするのが最近のマイブームです。

ChatGPTをヘビーユーズしている皆さん、 「過去の会話がブラックボックス化」 していませんか?

  • 公式の検索機能だと、昔の神プロンプトが見つからない
  • Claude 4.5 や Gemini 3Pro に乗り換えたいけど、文脈(Context)の移行が面倒すぎる
  • かといって、機密情報を含むJSONを外部のビューアサイトにアップロードするのは怖い

そんな「自分自身の悩み」を解決するために、 サーバーへのデータ送信ゼロ、完全クライアントサイドで動作する履歴管理ツール「iLoveAI」 を開発しました。

今回は、開発にあたって採用した Next.js 16 や Tailwind CSS v4 (Alpha) の使用感、そして数百MBの巨大JSONをブラウザだけでサクサク動かすためのパフォーマンス・チューニングの裏側を共有します。

🚀 iLoveAI - The Ultimate AI History Hub

技術スタック:あえて「最新」に振る

個人開発の醍醐味は、業務では採用しづらい「Alpha版」や「最新メジャーバージョン」を自由に試せることです。今回は以下のスタックを選定しました。

Category Tech Why?
Framework Next.js 16.0.4 (App Router) React 19 ベースの最新環境。今回はServer Actions等は使わず、Static Exportに近い構成ですが、App Routerのルーティングを活用
Language TypeScript 5 型安全性は必須。特に複雑なJSON構造を扱うため、型定義が開発効率を支えました
Styling Tailwind CSS v4 (Alpha) ここが今回の一番の挑戦。新しいエンジンのビルド速度と、CSSファーストな設定方法を試したかったため
State Zustand ReduxやContext APIより軽量。シンプルさとパフォーマンスが最適解でした
Performance Web Workers / Virtual Scroll メインスレッドをブロックしないための必須技術(後述)

技術的な挑戦と実装の裏側

単に「JSONを表示するだけ」なら簡単ですが、「数千件の会話」「数百MBのファイル」を「ストレスなく」扱うには、いくつかの壁がありました。

1. Tailwind CSS v4 の実戦投入

v4はまだAlpha段階ですが、劇的な変化がありました。これまでの tailwind.config.js への依存が減り、CSSファイル内で設定が完結するようになっています。

/* main.css */
@import "tailwindcss";

@theme {
  --color-primary: #3b82f6;
  --font-family-sans: "Inter", sans-serif;
  /* コンフィグファイルではなく、CSS変数感覚でテーマ拡張ができる */
}

良かった点:

  • ビルドが速い: Rustベースの新しいエンジン(Oxide)のおかげか、変更の反映が爆速でした
  • 設定が直感的: CSSの中に設定を書けるので、ファイルを行き来する手間が減りました

2. Web Worker による「UIフリーズ」の回避

ChatGPTのヘビーユーザーの場合、エクスポートされた conversations.json数百MBに達します。これをメインスレッドで JSON.parse して加工しようとすると、ブラウザが数秒〜十数秒フリーズしてしまいます。

そこで、Web Worker を導入し、パース処理をバックグラウンドスレッドに逃がしました。

// worker.ts (イメージ)
self.onmessage = (e: MessageEvent<File>) => {
  const reader = new FileReader();
  reader.onload = () => {
    // 重たいパース処理やデータ整形はここで行う
    const parsedData = heavyParsingLogic(reader.result);
    // 完了したらメインスレッドに返す
    self.postMessage(parsedData);
  };
  reader.readAsText(e.data);
};

これにより、巨大なファイルをドロップしても、ローディングアニメーションが止まることなく、スムーズなUXを実現できました。

3. 仮想スクロール (Virtual Scrolling) でDOMを爆発させない

パースが終わっても、数千件のチャット履歴を一度にDOM(HTML)として描画すると、メモリを食いつぶしてブラウザが重くなります。

そこで、「画面に見えている部分だけをレンダリングする」仮想スクロールを導入しました。

  • サイドバー: 会話リストの表示に react-virtuoso を採用
  • チャット画面: メッセージ数が多くなっても軽快にスクロールできるように最適化

結果として、履歴が100件でも10,000件でも、変わらない操作感を実現しています。

4. 🔒 プライバシーファーストな設計

「ローカルで動く」と言っても、ユーザーは不安です。そこで、アーキテクチャ自体を**「サーバーレス(APIを持たない)」**構成にしました。

  • データの保存先はブラウザのメモリ(Zustand)と localStorage(設定のみ)だけ
  • Vercelには静的アセットを置くだけ

**「LANケーブルを抜いても動く」**状態を作ることで、技術的にも物理的にもデータ流出のリスクをゼロにしました。

こだわりの機能:AI間の「架け橋」になる

iLoveAIはただのビューアではありません。**「AI移行(Migration)」**のためのハブを目指しています。

コンテキスト最適化コピー機能

ChatGPTでの長い会話の文脈を、そのままClaudeやGeminiに引き継ぎたい時、単なるコピペでは「誰の発言か」が曖昧になりがちです。

iLoveAIでは、選択したスレッドを各モデルが理解しやすい形式に整形してクリップボードにコピーする機能を実装しました。

  • For Claude: Human: / Assistant: 形式に整形
  • For Gemini: User: / Model: 形式に整形
// converter.ts の一例
export const formatForClaude = (messages: Message[]) => {
  return messages.map(m => {
    const role = m.role === 'user' ? 'Human' : 'Assistant';
    return `\n\n${role}: ${m.content}`;
  }).join("");
};

これにより、**「ChatGPTでブレストした内容を、ワンクリックでClaudeに渡して推敲してもらう」**といった高度な使い分けが爆速になります。

まとめ

「自分が欲しいから作った」ツールですが、結果として Next.js 16 や Tailwind v4 といった最新技術のキャッチアップ、そしてWeb Workerや仮想スクロールといったパフォーマンス・チューニングの実践的な知見が得られました。

個人開発は、技術選定の自由度が無限大です。

「履歴が見づらい」「移行が面倒」と感じている方は、ぜひ iLoveAI を試してみてください。そして、もし技術的な部分で気になるところがあれば、Xなどでフィードバックをいただけると嬉しいです!

🔗 Link: https://ilove-ai.net/

参考リンク

【続編】Claudeにも対応したときの話

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?