スマホやPCの中に、写真やスクショが山のようにたまっていませんか?😅 「これ何の画像だっけ」「レシートの合計だけ知りたい」「種類ごとにフォルダ分けしたい」——そんな作業を、ネット接続なしで動くローカルAIに手伝ってもらうようにしてみました。今回は新しいアプリを作るのではなく、以前作ったローカルAIエージェントの画像機能を“実用レベル”に強化します。
・写真をドラッグ&ドロップで複数まとめて渡す仕組み
・各画像を説明 → タグ付け → 文字起こし(OCR的)まで一括処理
・提案→確認→コピーの安全なやり方でタグ別フォルダに整理(元ファイルは触らない)
・スクショ→画面内容の説明、そしてすべてローカル完結(写真が外に出ない)
・再現できるよう、実装のキモになるコード(D&D/画像をローカルLLMに渡す/安全なコピー整理)も掲載
土台:p935 ローカルAIエージェント。画像を理解する頭脳は Ministral 3(vision対応)。実装はMac、コードはMac/Windows共通(前回p941で同一コードのWindows動作を確認済み)。
作るもの:写真をD&Dで説明・タグ・整理
完成形はこう動きます。複数の画像をまとめてエージェントにドラッグ&ドロップすると、1枚ずつ「これは何か(説明)」「関連するタグ」「写っている文字(OCR的)」を答え、さらに「タグごとにこう仕分けます」という整理案まで出してくれます。下は、レシート・会議メモ・セールのポスター・売上グラフの4枚を渡して一括処理した結果です。

なぜ“エージェントに足す”のか
p935のエージェントは、実はもともと画像を理解できます(Ministral 3のvision)。さらに「ファイルを読む・書く」「コマンドを実行する」という道具も持っています。つまり「画像を見て、名前を変えて、フォルダに振り分ける」ための部品はほぼ揃っているんですよね。
足りなかったのは“使い勝手”だけ。今回はそこを埋めます。独立アプリは作らず、エージェントに次を追加しました。
- ドラッグ&ドロップ(複数画像)で手軽に渡せるUI
- 各画像を説明・タグ・OCRする一括処理ボタン
- 提案→確認→コピーで安全に整理する仕組み+CSV書き出し
- スクショ→画面説明(既存のスクショ道具+vision)
ドラッグ&ドロップで複数画像を渡す
これまでは「画像添付」ボタンで1枚ずつでした。今回はエージェントの画面に、写真を何枚でもドラッグ&ドロップできます。ドロップすると「◯枚 受け取りました」と表示され、一括処理の準備完了です。画像を入れると画像を理解できるMinistral 3へ自動で切り替わるようにもしました(コード特化モデルを使っていても安心)。

実装はPySide6の標準的なドロップ受け口だけ。3ステップで、ファイル選択(複数可)と同じ入口に流し込みます(Mac/Windows共通)。
# ① ウィンドウでドロップを受け付ける(__init__ の中で一度だけ)
self.setAcceptDrops(True)
# ② ドラッグ中:画像ファイルが含まれていれば受け入れる
def dragEnterEvent(self, e):
urls = e.mimeData().urls()
if e.mimeData().hasUrls() and any(is_image(u.toLocalFile()) for u in urls):
e.acceptProposedAction()
# ③ ドロップされたら画像パスを集めて処理へ渡す
def dropEvent(self, e):
paths = [u.toLocalFile() for u in e.mimeData().urls()
if is_image(u.toLocalFile())]
if paths:
self._add_images(paths) # ← 「画像添付」ボタン(複数選択)も同じ入口に通す
※ is_image() は拡張子で画像かどうかを見るだけの小さな関数です。受け取り後の処理(表示更新・vision対応モデルへの自動切替)は _add_images() に集約しています。
一括処理:説明・タグ・文字起こし(OCR)
「一括処理」を押すと、各画像に対してローカルのvisionモデルが1回ずつ推論し、次の3つを返します。
- 説明:画像の内容を1文で(例:「カフェのレシートで、4品目の飲食代と合計金額が記載されている」)
- タグ:短い日本語タグを3〜5個(例:レシート/カフェ/金額)
- 文字(OCR的):画像に写っている文字をそのまま書き出す
肝は「画像をローカルのvisionモデルに渡す」ところ。画像をbase64にして、テキストと一緒に1つのメッセージにするだけです。あとは1画像=1回の推論で、説明・タグ・文字をまとめて答えてもらいます。
# 「テキスト+画像」を1つのメッセージにする(vision対応モデルへ渡す形)
def image_content(text, image_path):
b64 = base64.b64encode(open(image_path, "rb").read()).decode()
return [{"type": "text", "text": text},
{"type": "image_url",
"image_url": {"url": f"data:image/png;base64,{b64}"}}]
# 1回の推論で「説明・タグ・文字」をまとめて答えてもらう
prompt = (
"この画像について、次の形式で日本語で答えてください。\n"
"説明: 内容を1文で\n"
"タグ: カンマ区切りで3〜5個\n"
"文字: 画像に写っている文字をそのまま(無ければ「なし」)"
)
msg = llm.chat_message(
[{"role": "user", "content": image_content(prompt, path)}],
max_tokens=500, temperature=0.2)
# msg["content"] を「説明:/タグ:/文字:」の行ごとに分解して使う
特に文字起こしが便利で、レシートの品目や合計、会議メモの箇条書きなどをテキストに落とせます。結果は画面に表示するだけでなく、CSVにも書き出すので、あとで表計算ソフトで見返せます。
整理:提案→確認→コピー(安全)
タグが付いたら、いよいよ整理です。ここは安全第一にしました。AIが「この画像は『レシート』フォルダに『01_レシート.png』という名前で」という整理案を先に提示し、あなたが確認してから実行します。しかも実行は必ずコピー——元の写真は移動も変更もしません。

実行すると、こんな形でコピーされます(元の4枚はそのまま)。
output/organized_20260709_.../ ├─ レシート/ 01_レシート.png ├─ 会議メモ/ 02_会議メモ.png ├─ セール/ 03_セール.png └─ 売上グラフ/ 04_売上グラフ.png
実行部分はこれだけ。ポイントは shutil.copy2(コピー)を使い、元ファイルには一切触らないことです。移動(move)や上書きは使いません。
import os, shutil, datetime
def apply_plan(plan, out_dir):
"""整理案どおりに仕分ける。★必ずコピー(元ファイルは触らない)。"""
stamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
root = os.path.join(out_dir, f"organized_{stamp}")
for r in plan: # r = {"path":元, "folder":タグ, "new_name":新名, ...}
dst_dir = os.path.join(root, r["folder"])
os.makedirs(dst_dir, exist_ok=True)
shutil.copy2(r["path"], os.path.join(dst_dir, r["new_name"])) # ← コピーのみ
return root
「AIにファイルを勝手に動かされるのは怖い」という不安に応えて、提案を見て納得してから・コピーで、という流れにしています。
画面を説明(スクショ→vision)
おまけで、「今の画面」を撮って説明させることもできます。エージェントは元々スクショを撮る道具を持っているので、それと画像理解をつなぐだけ。エラー画面の意味を聞いたり、UIの内容をメモに落としたり、といった使い方ができます。これもローカルで完結します。
つまずき・気づき
- 画像機能はvision対応モデルが必須:コード特化モデル(Qwen2.5-Coder)はテキスト専用なので、画像を入れたら自動でMinistral 3へ切替るようにしました。切替は「今のモデルを解放→次を読み込む」方式(前回のモデル切替をそのまま活用)。
- JSONは画像内テキストで壊れる:前述のとおり、OCRの複数行でJSON解析が失敗。ラベル形式に変えて解決。
- 日本語OCRの精度:今回のくっきりした画像ではかなり正確でしたが、手書き・低解像度・複雑な背景では崩れることがあります。過信せず「下書き」として使うのが安全です。
- 枚数と速度:1枚ずつ推論するので、枚数が増えるほど時間がかかります。大量の写真は小分けにするのがおすすめ。
- 画面撮影のOS差(Windows):後述のWindows動作確認で、「画面を説明」だけWindowsでは追加ライブラリ(Pillow)が必要と判明しました。原因は画面撮影に使っていた
pyautoguiがWindowsでPillowに依存するため(Macはscreencaptureを使うので不要)。PySide標準の画面撮影に切り替えて、追加依存なしで両OS共通にしました。
Mac/Windows 両方で動いた
このエージェントは前回と同じくMac/Windows同一コード。今回の画像機能も、Windows(RTX3060)でドラッグ&ドロップ・一括処理・整理コピー・画面説明の4つすべて動作を確認しました。下はWindowsで整理を実行した画面です(パスが C:\…\output\organized_… になっているのがWindowsの証拠)。

唯一のOS差が、前章で触れた「画面を説明」の画面撮影。ここだけPySide標準の撮影に統一して、Pillowなしで両OSとも動くようにしました。標準的なドラッグ&ドロップ(PySide)や、パスの扱い(os.path)はそのまま両OSで動きます👍
まとめ
ローカルAIエージェントの画像機能を、実際に使えるレベルまで強化できました。ポイントを整理します。
- 写真をドラッグ&ドロップで複数まとめて渡せる
- 説明・タグ・OCRを一括処理し、CSVにも書き出し
- 整理は提案→確認→コピーの安全設計(元ファイルは触らない)
- スクショ→説明も可能。すべてローカル完結=写真が外に出ない
- 画像はvision対応のMinistral 3で。Mac/Windows共通のコード
クラウドの画像AIは強力ですが、家族の写真やレシート・書類を外に送りたくない場面は多いはず。手元で完結する“画像整理の相棒”は、そういうときにこそ頼りになります😊 たまった写真の整理、AIに下ごしらえを任せてみると、思ったより気持ちよく片づきますよ。
それでは、今回はここまで。最後までありがとうございました😊