File size: 7,624 Bytes
ad8cacf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
import os
import base64
from litellm import completion

class ImageCaptioner:
    """

    Geminiを使用して画像のキャプションを生成するクラス

    """
    
    def __init__(self, api_key=None, model=None):
        """

        初期化関数

        

        Args:

            api_key (str, optional): XAI API Key. 未指定の場合は.envのXAI_API_KEYを使用

            model (str, optional): 使用するモデル名. 未指定の場合は.envのXAI_MODELまたはデフォルト値を使用

        """
        # .envからAPIキーを取得(引数で指定がない場合)
        self.api_key = api_key or os.getenv('XAI_API_KEY')
        
        # .envからモデル名を取得(引数で指定がない場合)
        # 環境変数にない場合はデフォルト値を使用
        self.model = model or os.getenv('XAI_MODEL', 'xai/grok-2-vision-1212')
        
    def set_api_key(self, api_key):
        """APIキーを設定する"""
        self.api_key = api_key
        
    def is_configured(self):
        """APIキーが設定されているかを確認する"""
        return self.api_key is not None and self.api_key.strip() != ""
        
    def generate_caption(self, image_path, prompt=None):
        """

        画像のキャプションを生成する

        

        Args:

            image_path (str): 画像ファイルのパス

            prompt (str, optional): キャプション生成のためのプロンプト

            

        Returns:

            str: 生成されたキャプション

        """
        if not self.is_configured():
            return "APIキーが設定されていません"
            
        if not os.path.exists(image_path):
            return f"画像ファイルが見つかりません: {image_path}"
            
        # デフォルトプロンプト
        if prompt is None:
            prompt = "この画像に写っている動物を簡潔に説明してください。動物の種類と特徴を含めてください。"
            
        try:
            # APIキーを設定
            api_key = self.api_key or os.getenv('XAI_API_KEY')
            if not api_key:
                return "APIキーが設定されていません"
            os.environ['XAI_API_KEY'] = api_key
            
            # 画像をBase64エンコード
            with open(image_path, "rb") as f:
                image_data = f.read()
                base64_image = base64.b64encode(image_data).decode('utf-8')
            
            # LitellmでXAI APIを呼び出す
            response = completion(
                model=self.model,
                messages=[
                    {
                        "role": "user", 
                        "content": [
                            {"type": "text", "text": prompt},
                            {
                                "type": "image_url",
                                "image_url": {
                                    "url": f"data:image/jpeg;base64,{base64_image}"
                                }
                            }
                        ]
                    }
                ]
            )
            
            # レスポンスからテキストを抽出
            if response and hasattr(response, 'choices') and len(response.choices) > 0:
                return response.choices[0].message.content
            else:
                return "キャプションを生成できませんでした"
                
        except Exception as e:
            return f"エラーが発生しました: {str(e)}"
            
    def generate_filename(self, image_path, prefix="animal", prompt=None):
        """

        画像のキャプションを生成してファイル名として使用する

        

        Args:

            image_path (str): 画像ファイルのパス

            prefix (str): ファイル名のプレフィックス

            prompt (str, optional): キャプション生成のためのプロンプト

            

        Returns:

            tuple: (新しいファイル名, 生成されたキャプション)

        """
        # キャプション生成
        caption = self.generate_caption(image_path, prompt)
        
        # キャプションからファイル名を生成
        # 不正な文字を除去し、長さを制限
        invalid_chars = r'<>:"/\|?*'
        filename = caption.lower()
        
        # 不正な文字を除去
        for char in invalid_chars:
            filename = filename.replace(char, '')
            
        # 空白をアンダースコアに置換
        filename = filename.replace(' ', '_')
        
        # 長さを制限
        if len(filename) > 50:
            filename = filename[:50]
            
        # 拡張子を取得
        _, ext = os.path.splitext(image_path)
        
        # 最終的なファイル名を生成
        final_filename = f"{prefix}_{filename}{ext}"
        
        return final_filename, caption
        
    def batch_generate_filenames(self, image_dir, output_dir=None, prefix="animal", prompt=None):
        """

        ディレクトリ内の全画像のキャプションを生成してファイル名を変更する

        

        Args:

            image_dir (str): 画像ファイルのディレクトリ

            output_dir (str, optional): 出力ディレクトリ

            prefix (str): ファイル名のプレフィックス

            prompt (str, optional): キャプション生成のためのプロンプト

            

        Returns:

            dict: {元のファイルパス: (新しいファイルパス, キャプション)}

        """
        if not self.is_configured():
            print("APIキーが設定されていません")
            return {}
            
        # 出力ディレクトリが指定されていない場合は入力ディレクトリを使用
        if output_dir is None:
            output_dir = image_dir
            
        # 出力ディレクトリが存在しない場合は作成
        if not os.path.exists(output_dir):
            os.makedirs(output_dir)
            
        results = {}
        
        # ディレクトリ内の画像を処理
        for filename in os.listdir(image_dir):
            if not filename.lower().endswith(('.png', '.jpg', '.jpeg', '.bmp')):
                continue
                
            input_path = os.path.join(image_dir, filename)
            
            # キャプションとファイル名を生成
            new_filename, caption = self.generate_filename(input_path, prefix, prompt)
            output_path = os.path.join(output_dir, new_filename)
            
            # ファイルをコピーまたは移動
            if output_dir != image_dir:
                # 別ディレクトリの場合はコピー
                with open(input_path, 'rb') as src_file:
                    with open(output_path, 'wb') as dst_file:
                        dst_file.write(src_file.read())
            else:
                # 同じディレクトリの場合は名前変更
                os.rename(input_path, output_path)
                
            results[input_path] = (output_path, caption)
            print(f"処理完了: {filename}{new_filename}")
            print(f"キャプション: {caption}")
            
        return results