外付けストレージ、ローカルAIノード、検索カードを抽象的に表したGX10 Galleryのプライバシー安全なテックビジュアル

Article

家庭内の写真・動画をローカルAIで検索できるようにする GX10 Gallery開発記

2026年6月3日
8 min read
ローカルAI
#ASUS Ascent GX10#Qwen#写真管理#動画管理#ローカルAI#SQLite

GX10を使って、家庭内の写真と動画をローカルAIで検索できるようにするメディアライブラリを作り始めた。

名前は仮にGX10 Galleryと呼んでいる。やっていることは、外付けストレージに入っている写真と動画を読み込み、EXIF、撮影日時、GPS由来の大まかな場所、動画のキーフレーム、音声認識、顔識別、Qwenによる説明文をまとめてインデックス化することだ。Web UIから検索したり、イベント単位で見返したり、自動で短いVlog風の動画を作ったりできるようにしたい。

最初から完成形が見えていたわけではない。きっかけはもっと素朴で、家族の写真と動画が大量にあるのに、いざ探そうとすると見つからない、という問題だった。

写真アプリのライブラリ、カメラのRAW、スマホ動画、ミラーレスの動画、動画編集用の素材。イベント単位では頭の中にあるのに、実際のファイルは複数のフォルダに分かれている。撮影日で探せることもあるが、「水族館イベントで子どもがショーを見ている動画」「旅行イベントで家族メンバーが歩いている場面」「キャンプイベントで料理をしている写真」みたいな探し方は難しい。

そこで、写真と動画を一度全部テキスト化して、検索できるようにしようと思った。

クラウドAIでやると怖い量

この手の処理は、いまならクラウドAI APIでもできる。

写真を1枚ずつ画像モデルに投げる。動画からフレームを切り出して投げる。音声をSTTにかける。説明文をembeddingにする。人物らしきものを整理する。やろうと思えばできる。

ただ、家庭内のメディアは量が多い。しかも、一回処理して終わりではない。

実装中は何度もやり直す。プロンプトを直したら再処理したい。GPS由来の場所名を追加したら、Qwenの説明文にも反映したい。人物ラベルを付けたら、「幼い子ども」ではなく「人物Aが写っている」と説明を更新したい。動画生成の品質を上げるために、クリップ候補をもう一度評価したい。

こうなると、クラウドAPIの従量課金はかなり怖い。画像、動画、音声、embeddingを大量に回し、さらに試行錯誤で再実行する。個人の写真や動画を外に出す抵抗もある。

GX10を使う理由はここにある。ローカルで回せば、コストは主に電気代と時間になる。個人メディアを外部APIに投げずに済む。そして失敗しても、もう一度回せる。

これはローカルAIのかなり実用的な使い道だと思う。

全体構成

構成は次のように分けた。

GX10 GalleryのローカルAIメディアライブラリ構成図

外付けストレージはソースとして読むだけにした。インデックス、キャッシュ、Markdown、生成動画はMac側の別の場所に書く。元の写真や動画を壊さないためだ。

実装言語はGoにした。理由はかなり実務的で、CLI、HTTP API、SQLite、ファイル走査、ffmpegの呼び出しを一つのバイナリにまとめやすいから。凝ったフレームワークを使うより、ローカルツールとして堅く動くことを優先した。

DBはSQLite。大量データだから最初は少し迷ったが、単一ユーザーのローカルメディアライブラリで、読み書きも基本的にはこのプロセスが握る。検索にはFTSを使える。まずはSQLiteで十分と判断した。

GX10側は、Qwenによる画像・動画フレーム理解、STT、embedding、顔検出を担当する。Mac側から見ると、必要なタイミングでGX10にHTTPで問い合わせるだけだ。重い推論をGX10に逃がし、ファイルI/Oや動画レンダリングはMac側で進める。この分担がかなり扱いやすい。

イベント単位で扱う

写真と動画は、完全に同じ構造で保存されているわけではない。

写真は写真用のフォルダ、動画は動画用のフォルダに分かれている。日付が同じでもイベント名が少し違うことがある。旅行のように、写真側は大きなセッションで、動画側は日付ごとのフォルダになっていることもある。

最初は、写真と動画を撮影日時で細かくマッチングすることも考えた。ただ、今回の目的はまず「イベントとして見返せること」なので、イベント単位で扱うことにした。

イベントには、写真rootと動画rootを持たせる。両方あるイベントもあれば、写真だけ、動画だけのイベントもある。今後、同日や前後日の似たフォルダを候補として出して、マッチ漏れを補正する余地はあるが、まずはイベント単位で十分だ。

ここで大事なのは、イベント名をそのまま公開情報にしないことだ。実装内部では元データと対応付ける必要があるが、記事や公開用の図では水族館イベント旅行イベントキャンプイベント公園イベントのような丸めた名前で扱う。

インデックスの中身

各メディアごとに、次のような情報を持つ。

metadata:
  ファイル種別
  撮影日時
  サイズ
  解像度
  動画の長さ
  カメラ情報

location:
  EXIF GPS
  逆ジオコーディングした大まかな場所名

vision:
  写真サムネイルの説明
  動画キーフレームの説明

audio:
  動画の短い音声区間から起こしたSTT結果

people:
  顔検出
  顔クラスタ
  匿名化した人物ラベル

search:
  SQLite FTS
  embedding

写真はサムネイルをQwenに見せて説明文を作る。

動画は全フレームを見るわけではない。キーフレームを数枚切り出し、短い音声区間をSTTにかけ、メタデータと合わせて説明文を作る。全フレームを見ると品質は上がるかもしれないが、処理時間が現実的ではない。まずは「探せる」ことを優先している。

人物ラベルも同じで、公開記事では実名や生のPeopleラベルは出さない。内部では検索に使えるようにするが、外向けには人物A人物B家族メンバー子どもくらいに丸める。これは単なる表記の問題ではなく、このプロジェクト全体の前提だ。家庭内メディアを扱うなら、検索しやすさと公開時の安全性を分けて考えないと危ない。

Web UIを作る

CLIだけでもインデックスは作れるが、メディアライブラリとして使うにはWeb UIが必要だった。

Web UIではイベント一覧を見られる。イベントを開くと、写真と動画のカードが並ぶ。動画はその場でプレビューできる。検索結果にもサムネイルや動画プレビューを出す。

検索は、単にファイル名を探すのではなく、Qwenが作った説明文、STT、場所名、人物ラベル、タグをまとめて見る。たとえば「水族館 ショー」「夜 風船」「キャンプ 料理」のような検索ができる。

この体験ができるだけで、普通のフォルダ管理とはかなり違う。

さらに、Web UIはただの閲覧画面ではなく、後続処理の入口にもなる。People画面で人物ラベルを確定する。Storyboardでイベント動画の候補を見る。Renderキューで動画生成の状態を見る。処理途中のイベントは、必要なコンテキスト更新が終わるまでレンダリングを止める。

このあたりは、写真管理アプリというより、ローカルAIの処理基盤に近い。

ローカルAI専用機としてのGX10

GX10側では、Qwen、embedding、STT、顔検出をOpenAI互換に近いAPIとして立てている。

実装側から見ると、MacはGX10にHTTPで問い合わせるだけだ。Qwenに画像を渡す。STTに音声を渡す。embeddingを取る。顔検出にサムネイルを渡す。

この分離は扱いやすい。Macは普段の作業マシンでもあるので、重いAI推論をGX10に逃がせる。一方で、ファイルI/Oや動画レンダリングはMac側でやった方が楽だ。

そして何より、試行錯誤しやすい。

実際、プロンプトやロジックは何度も変えた。写真の説明に余計な編集素材っぽい文言が入ることがあり、それを取り除いた。横倒しや天地逆転の動画クリップをQwenで落とすようにした。人物ラベルや場所名が後から入ったら、Qwen説明文だけを再実行する仕組みも入れた。

この「失敗して直して再処理する」流れは、ローカルAIでないと心理的にやりにくい。クラウドAPIでも技術的にはできるが、個人データの扱いと再実行コストを毎回考えることになる。GX10をローカルAI専用機として置くと、この試行錯誤の摩擦がかなり下がる。

現時点の到達点

現時点では、次のところまで動いている。

  • 写真と動画のイベント単位スキャン
  • EXIF、撮影日時、GPS情報の取得
  • GPSから大まかな場所名への変換
  • Qwenによる写真説明、動画キーフレーム説明
  • 動画音声のSTT
  • SQLite FTSとembeddingによる検索
  • Web UIでのイベント一覧、検索、プレビュー
  • 顔検出、人物クラスタ、匿名化した人物ラベル
  • 人物ラベルや場所名が変わった時のQwen再説明
  • イベント動画のドラフト作成とレンダリング
  • HLSによるWeb再生

まだ完成ではない。写真と動画のイベントマッチングは改善余地がある。動画生成も、プロの編集のようなテンポやストーリーにはまだ届かない。人物識別も、ラベル付けの運用をもう少し良くしたい。

それでも、家庭内メディアを「AIで検索できるライブラリ」にする土台としてはかなり見えてきた。

GX10を買ってローカルLLMを動かすだけだと、「速い」「遅い」「このモデルは動く」という話で終わりがちだ。でも、個人の大量データを扱うと、ローカルAIの価値はかなり分かりやすくなる。外に出したくない。何度も処理し直したい。検索できるようにしたい。この条件が揃うと、ローカルで回せること自体が機能になる。

次回は、実際にどうやって写真と動画をテキスト化し、人物ラベルや場所名まで検索に入れているのかを書く。