Fireflyの利便性とファイル名問題
Adobe Fireflyやその他のAI画像生成サービスは非常に便利ですが、ダウンロードするファイル名には共通の課題があります。
1. Firefly画像生成とファイル名の構造
高品質な画像を生成するためには、一般的に英語のプロンプトを使用するのがベストプラクティスです。
しかし、画像をダウンロードすると、ファイル名には自動的に Firefly_
というプレフィックス(接頭辞)が付き、その後ろにプロンプト全文とランダムなIDが続きます。
プロンプトの例:
A minimalist flat lay of a black coffee mug, a laptop, and a notepad on a wooden desk near a window, emphasizing a bright morning light, professional photography, high resolution, 16:9 aspect ratio
ファイル名の例:
Firefly_A minimalist flat lay of a black coffee mug, a laptop, and a notepad on a wooden desk 694213.jpg
このようにファイル名が非常に長くなるため、Finderでファイル名が見切れ、管理が困難になるという問題が発生します。
投稿文の例:
朝のブラックコーヒーは集中力を高める自然なスイッチです。適量を守れば、午前中の作業効率アップにつながります。まずは砂糖なしで試してみましょう。#コーヒーのある暮らし#集中力アップ#健康習慣
リネームしたファイル名:
朝のブラックコーヒー.jpg
1〜2枚なら苦になりませんが、複数枚あるともう大変です。
この問題を解決するため、私たちはSNS投稿のに使う画像と仮定して「Firefly_」のプレフィックスを自動削除し、CSVファイルに記載した投稿文に基づいて「先頭10文字」にリネームする、ダブルクリック起動のGUIアプリをPythonで作ります。
🛠️ ステップ 1:このアプリが解決する3つの「壁」(つまずきポイント解説)
Mac環境で安定してリネーム処理を行うには、3つの大きな技術的障壁を乗り越える必要がありました。この経験こそが、このスクリプトの安定性の秘密です。
壁 1:複雑なファイル名の照合とFirefly_の処理
- 課題: 画像ファイル名とCSVに記録されたプロンプトが完全に一致しない(ランダムなIDや省略、
Firefly_
プレフィックスが原因)。 - 解決策:
- コード内で比較処理を行う際、
Firefly_
プレフィックスを自動で無視(削除)するように設計しました。 - 照合に使うプロンプトの長さを、先頭から20文字に固定し、長いプロンプトでも高い精度でマッチングできるようにしました。
- リネーム後のファイル名が重複した場合は、自動で連番(例:
胃が弱い(1).jpg
)を付与するロジックで重複を回避します。
- コード内で比較処理を行う際、
壁 2:Macのパーミッション(権限)問題の回避
- 課題: Python標準の
os.rename()
を使うと、Macのセキュリティ機能によりファイルシステムへの書き込み権限がブロックされ、リネームが失敗することが多々あります。 - 解決策:
- Pythonの標準機能を使うのをやめ、
subprocess
モジュール経由でMacのシェルコマンドmv
(ムーブ)を呼び出します。 mv
コマンドはOSが持つ強力な機能であり、これを使用することで権限の問題を回避し、安定したリネーム動作を実現しました。
- Pythonの標準機能を使うのをやめ、
壁 3:ターミナル不要のダブルクリック起動とGUI化
- 課題:
.py
ファイルをダブルクリックで実行できず、ファイルパスの指定も手間がかかる。 - 解決策:
- Python標準の
tkinter
ライブラリを使用し、ファイルとフォルダをGUIウィンドウで選択できるようにしました。 .py
ファイルを右クリックし、「このアプリケーションで開く」を「ターミナル」に設定変更することで、ダブルクリックで実行できるようにします。(この設定方法は後述します)
- Python標準の
📄 ステップ 2:リネーム用CSVファイルの準備
リネームの元となるCSVファイルを用意します。このスクリプトは、以下の列を読み込みます。(実際は複数行になります)
- B列(インデックス1): 新しいファイル名の元データ(先頭10文字にリネームされます)。
- E列(インデックス4): Firefly画像と照合するためのプロンプトデータ。
列番号 | No | 列B(投稿文 / 新しいファイル名) | ステータス | 日付 | 列E(画像生成プロンプト / 照合キー) |
0 | ID | 朝のブラックコーヒーは集中力を高める自然なスイッチです。適量〜 | 未投稿 | 01/01 | A minimalist flat lay of a black coffee mug, a 〜 |
📜 ステップ 3:究極のPythonコードの貼り付けと準備
以下のコードを、Macの任意の場所(例:~/MyPython/
フォルダ内)に rename_script.py
という名前で保存してください。
1. ターミナルでファイルを作成・編集する
- Macの「ユーティリティ」フォルダ内にある「ターミナル」を起動します。
- 以下のコマンドを実行して、作業用フォルダに入ります。Bash
mkdir ~/MyPython cd ~/MyPython
- 【重要:Pythonパスの確認とメモ】Macの環境(Homebrewを使っているかなど)によってPythonの実行パス(シバン)が異なります。安定して実行するために、正確なパスを確認します。Bash
which python3
- 例:
/usr/local/bin/python3
や/opt/homebrew/bin/python3
のようなパスが表示されます。このパスをメモしておいてください。
- 例:
- 以下のコマンドを実行して、
rename_script.py
という新しいPythonファイルを作成し、nano
エディタで開きます。Bashnano rename_script.py
2. 【最終確定版コード全文】を貼り付け
⚠️ 注意: 以下のコードの一行目(シバン)にある #!/opt/homebrew/bin/python3
は、先ほど which python3
コマンドで確認したあなたの環境のパスに必ず書き換えてください。
以下のPythonコードをnano
エディタにすべて貼り付けます。
Python
#!/opt/homebrew/bin/python3
import csv
import os
import sys
import re
import subprocess
import logging
import tkinter as tk
from tkinter import filedialog
from tkinter import messagebox as mbox
# --- 設定項目 ---
FIREFLY_PREFIX = "Firefly_"
FILE_EXTENSION = ".jpg"
# マッチングに使用する文字数(FireflyプロンプトとCSVを比較するキー。20文字で安定)
MATCH_LENGTH = 20
# リネーム後のファイル名に使用する文字数(投稿文の先頭10文字)
POST_TEXT_LENGTH = 10
# エラーログファイルの設定 (デスクトップに自動生成されます)
LOG_FILE = os.path.join(os.path.expanduser("~/Desktop"), "rename_error.log")
logging.basicConfig(filename=LOG_FILE, level=logging.ERROR,
format='%(asctime)s - %(levelname)s - %(message)s')
def clean_prompt(text):
"""プロンプトから比較用のクリーンな文字列を生成する"""
if not text:
return ""
# 1. 特殊文字の統一とクリーンアップ
text = text.strip().strip('"').replace("\n", " ").replace("/", "_").replace("\\", "_").replace("?", "_").replace("*", "_").replace("|", "_").replace("<", "_").replace(">", "_")
# 2. 全角スペース、句読点、ハイフンを削除/統一
text = text.replace(" ", " ").replace(":", "").replace(",", "").replace(".", "").replace("-", "").replace("__", "_").replace(" ", " ")
# 3. ファイル名末尾のランダムな数字(4~6桁)を確実に削除
text = re.sub(r' \d{4,6}$', '', text)
return text.upper()
def read_csv_data(csv_path):
"""CSVファイルを読み込み、リーダーオブジェクトを返す"""
# 複数のエンコーディングで読み込みを試行し、日本語CSV(UTF-8 BOMやShift-JS)に対応
encodings = ['utf-8-sig', 'utf-8', 'cp932']
for encoding in encodings:
try:
with open(csv_path, 'r', encoding=encoding, newline='') as file:
return list(csv.reader(file))
except (UnicodeDecodeError, FileNotFoundError):
continue
raise ValueError(f"CSVファイルの読み込みに失敗しました。エンコーディングを確認してください: {os.path.basename(csv_path)}")
def rename_firefly_images_from_csv(csv_path, image_path):
"""画像フォルダ内のファイル名とCSVのプロンプトを比較してリネームする"""
rename_count = 0
try:
all_rows = read_csv_data(csv_path)
if not all_rows:
mbox.showerror("エラー", "CSVファイルが空であるか、読み込みに失敗しました。")
return
reader = all_rows[1:] # ヘッダー行をスキップ
POST_TEXT_COL = 1 # CSVの「投稿文」が入っている列番号(0から始まる)
PROMPT_COL = 4 # CSVの「画像生成プロンプト」が入っている列番号(0から始まる)
# 1. CSVデータから新しいファイル名とマッチングキーを準備
csv_data_map = {}
for row in reader:
# 必要な列がCSVに存在するか確認
if len(row) > PROMPT_COL:
post_text = row[POST_TEXT_COL].strip()
prompt_full = clean_prompt(row[PROMPT_COL])
if not post_text or not prompt_full: continue # 空欄はスキップ
match_key = prompt_full[:MATCH_LENGTH]
new_filename_base = post_text[:POST_TEXT_LENGTH]
# ファイル名に使用できない文字を置き換える
new_filename_base = new_filename_base.replace("/", "_").replace("\\", "_").replace(":", "_").replace("?", "_").replace("*", "_").replace("|", "_").replace("<", "_").replace(">", "_")
# 同じマッチングキーがあれば上書きせず、最初のものを使用する
if match_key not in csv_data_map:
csv_data_map[match_key] = {'base_name': new_filename_base}
processed_new_filenames = set() # 既にリネームされた新しいファイル名を記録
# 2. 画像フォルダ内のファイル名をチェックしてリネーム
for filename in os.listdir(image_path):
# Fireflyの画像ファイルかチェック
if not filename.startswith(FIREFLY_PREFIX) or not filename.lower().endswith(FILE_EXTENSION.lower()):
continue
# Firefly_プレフィックスと拡張子を除いたプロンプト部分を抽出
# これにより「Firefly_」を無視できる
prompt_in_file = filename[len(FIREFLY_PREFIX):-len(FILE_EXTENSION)]
cleaned_file_prompt = clean_prompt(prompt_in_file)
match_key = cleaned_file_prompt[:MATCH_LENGTH]
# 3. マッチング処理
if match_key in csv_data_map:
data = csv_data_map[match_key]
new_filename_base = data['base_name']
# 4. ファイル名の重複チェックと連番付与
base_name = new_filename_base
i = 0
final_new_filename = base_name + FILE_EXTENSION
new_path = os.path.join(image_path, final_new_filename)
# リネーム後のファイル名が既に存在するか、既にこのセッションでリネームに使われたかチェック
while os.path.exists(new_path) or final_new_filename in processed_new_filenames:
i += 1
final_new_filename = f"{base_name}({i}){FILE_EXTENSION}"
new_path = os.path.join(image_path, final_new_filename)
old_path = os.path.join(image_path, filename)
if os.path.exists(old_path):
try:
# mvコマンドによる権限回避 (subprocess.run)
subprocess.run(["mv", old_path, new_path], check=True)
rename_count += 1
processed_new_filenames.add(final_new_filename)
except subprocess.CalledProcessError as e:
# mvコマンドが失敗した場合のエラーログ出力
error_msg = f"MVエラー (リネーム失敗): {filename} -> {final_new_filename}. 詳細: {e.stderr.decode('utf-8', errors='ignore')}"
logging.error(error_msg)
except Exception as e:
error_msg = f"予期せぬエラー: {filename}. 詳細: {e}"
logging.error(error_msg)
# 実行結果の通知をGUIで行う
mbox.showinfo("処理完了", f"全ての処理が完了しました。\nリネームされたファイル数: {rename_count} 件\n画像フォルダをご確認ください。")
except ValueError as e:
mbox.showerror("CSV処理エラー", f"CSVファイルのデータ形式に問題があるか、指定された列が存在しません: {e}")
except Exception as e:
mbox.showerror("予期せぬエラー", f"予期せぬエラーが発生しました: {e}\n詳細はデスクトップのログファイルをご確認ください。")
def main():
# Tkinterのルートウィンドウを作成し、非表示にする (GUIのみを表示するため)
root = tk.Tk()
root.withdraw()
csv_file = None
image_folder = None
# 1. GUIファイル選択
# CSVファイル選択ダイアログ
mbox.showinfo("ステップ 1/2", "次に、リネームに使用するCSVファイルを選択してください。", icon='info')
csv_file = filedialog.askopenfilename(
title="リネーム用CSVファイルを選択",
filetypes=(("CSV files", "*.csv"), ("All files", "*.*"))
)
if not csv_file:
mbox.showinfo("キャンセル", "処理がキャンセルされました。", icon='warning')
return
# 画像フォルダ選択ダイアログ
mbox.showinfo("ステップ 2/2", "次に、Firefly画像が保存されているフォルダを選択してください。", icon='info')
image_folder = filedialog.askdirectory(
title="Firefly画像フォルダを選択"
)
if not image_folder:
mbox.showinfo("キャンセル", "処理がキャンセルされました。", icon='warning')
return
# 2. リネーム実行
if csv_file and image_folder:
rename_firefly_images_from_csv(csv_file, image_folder)
if __name__ == "__main__":
main()
3. ファイルの保存と実行権限の付与
Control
+O
、Enter
でファイルを保存し、Control
+X
でエディタを終了します。- ターミナルで、作成したPythonスクリプトに実行権限を与えます。(この作業は一度きりです)Bash
chmod +x /Users/ユーザーネーム/MyPython/rename_script.py
🚀 ステップ 4:ダブルクリックでアプリを起動する
最後に、ターミナルを開かずにアプリを起動するための設定を行い、実行します。
1. デフォルトのアプリケーションを「ターミナル」に設定
- Finderを開き、作成したファイル「rename_script.py」を右クリックします。
- メニューから「情報を見る」を選択します。
- 「情報」ウィンドウの「このアプリケーションで開く」セクションを見つけます。
- 現在の設定(IDLEなどになっている場合があります)をクリックし、リストから「ターミナル」を選択します。
- その直下にある 「すべて変更…」 ボタンをクリックし、確認のダイアログで「続ける」を押します。
2. アプリの実行と確認
- Finderで「rename_script.py」をダブルクリックします。
- ターミナルが起動した後、すぐにGUIのメッセージボックスとファイル選択ウィンドウが順番に表示されます。
- 指示に従い、CSVファイル、次にFirefly画像フォルダを順番に選択してください。
- 処理が完了すると、「処理完了」のメッセージボックスが表示され、画像フォルダ内のファイル名が新しいキャプション(先頭10文字)にリネームされています。
- 注:必ずバックアップをとってから作業してください。
もしエラーが発生した場合: デスクトップに rename_error.log
というファイルが自動で作成されています。このファイルの中身を確認することで、何が原因でリネームに失敗したかを特定できます。
この強力なGUIアプリが、あなたの画像管理の効率を劇的に向上させるはずです。
つまずいたらAIに相談してください。きっと解決してくれます。
コードはサンプルですが、パスの設定を行えば動くはずです。自己責任でのみご自由にどうぞ。