File size: 16,620 Bytes
e8a0353
7b0f44b
 
13c244f
e8a0353
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52d94ea
 
 
 
c318e26
 
 
 
 
52d94ea
 
e8a0353
 
 
 
 
 
 
 
7700440
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7b0f44b
e8a0353
 
7700440
7b0f44b
e8a0353
7700440
 
 
 
e8a0353
 
 
 
 
 
 
 
 
 
 
 
 
7b0f44b
 
 
e8a0353
 
7b0f44b
e8a0353
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7b0f44b
 
 
 
 
 
 
 
13c244f
 
7b0f44b
13c244f
 
 
 
7b0f44b
 
13c244f
d2eb3a0
13c244f
7b0f44b
13c244f
 
7b0f44b
 
 
 
7700440
e8a0353
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7700440
 
 
 
 
 
 
 
672bfa6
 
e27660d
7b0f44b
e27660d
672bfa6
 
 
e27660d
 
672bfa6
e27660d
672bfa6
e27660d
 
672bfa6
7b0f44b
 
 
e8a0353
 
 
 
 
 
 
 
 
 
 
 
c318e26
e8a0353
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52d94ea
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c318e26
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52d94ea
 
 
 
 
 
 
 
 
 
 
 
e8a0353
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
import json
import os
import requests
from openai import OpenAI

class PromptGenerator:
    def __init__(self):
        """プロンプト生成エンジンの初期化"""
        self.system_prompt = self._load_system_prompt()
    
    def _load_system_prompt(self):
        """システムプロンプトを構築"""
        return """
あなたはMidJourneyとnijiJourneyのプロンプト生成の究極のエキスパートです。
以下の全テクニックを熟知し、適切に組み合わせてください:

1. 基本テクニック:
   - 構造化プロンプト (主題→詳細→スタイル→技術)
   - 重み付けシステム (::1.2 などの数値指定)
   - 否定的プロンプトの詳細な構築

2. 映像・写真テクニック:
   - プロ撮影設定 (レンズ、照明、アングル)
   - シネマトグラフィー用語の適切な使用
   - 構図テクニック (黄金比、三分割法)

3. 先進テクニック:
   - パターン中断 (対照的概念の融合)
   - 感情マトリックス (階層的感情表現)
   - マルチペルソナ (専門家コンソーシアム手法)
   - 非現実的カメラ視点

4. 実験的テクニック:
   - プロンプト暗号化技術 (ネスト埋め込み)
   - エモーショナルシネマティックス
   - 論理パラドックス法
   - 特殊コマンドと魔法の単語の活用

5. MidJourney/nijiJourney特有のパラメータ:
   - スタイルリファレンス (--sref)
   - パーソナライゼーション (--p)
   - キャラクター参照 (--cref)
   - シード値指定 (--seed)
   - ランダム性調整 (--c/--chaos)
   - ネガティブプロンプト (--no)
   - タイルモード (--tile)
   - 途中停止 (--stop)
   - その他のパラメータ (--sw, --sv, --r, --iw, モード設定など)

ユーザーの入力を分析し、最適なテクニックの組み合わせを選択してください。
最終的なプロンプトは英語で生成し、必要に応じてMidJourney/nijiJourney固有のパラメータを追加してください。

出力形式:
1. 最初に生成されたプロンプト本体のみを表示
2. その後に「解説:」という見出しをつけて、使用したテクニックの説明を記載してください。
"""

    def analyze_user_input(self, groq_client, user_input, model="qwen-qwq-32b"):
        """Qwenモデルでユーザー入力を分析する"""
        # 中国語のプロンプトを使用
        analysis_prompt = """
你是一个具有高级思维能力的AI。在解决问题时,必须严格按照以下"思维链"格式执行,确保真正的链式思考得以展现。你需要分析用户对AI绘画的输入要求,深入理解用户想要生成的图像。
## 重要禁止事项
- 禁止输出任何形式的代码!
- 禁止输出任何调试或系统信息!
- 禁止跳过任何分析步骤!
- 禁止使用自己的格式代替指定模板!
- 禁止使用<tool_response>、</tool_call>或任何其他未指定的标签!
## 1. 思考结构(必须严格遵循)
`<think>
### 初始分析(每项≤30字)
- 要求分析: [详述显性与隐性要素]
- 主题元素: [主要主题/对象]
- 背景元素: [场景/环境/时间]
- 情感元素: [应表达的情感/氛围]
- 风格元素: [期望的艺术形式/风格]

### 视觉洞察(每项≤40字)
- 初始洞察→[对用户要求的第一印象]
- 构图洞察→[最佳构图和视角]
- 色彩洞察→[色调和对比度的考量]
- 技术洞察→[应用的绘画技术/效果]
- 隐藏元素→[未明确但重要的视觉元素]

### 改进洞察(每项≤40字)
- 具体化→[如何使模糊表达更具体]
- 强调→[应特别强调的视觉元素]
- 添加→[添加后效果更佳的元素]
- 平衡→[元素间的优先级和平衡]

### 最终分析
- 最佳表达:[最有效的表达方式建议]
- 重要关键词:[应包含在提示中的重要英文单词,用逗号分隔]
</think>\n`
## 2. 输出格式
完成思考后,必须以以下格式输出:
1. **"TYPE:AI_ART"**
2. **"SUBJECT:[用英文简述主题]"**
3. **"STYLE:[用英文简述最佳艺术风格]"**
4. **"KEYWORDS:[用英文列出重要关键词,逗号分隔]"**
5. **"MEMO:[用日语特别说明,≤50字]"**
        """
        
        try:
            response = groq_client.chat.completions.create(
                model=model,
                messages=[
                    {"role": "system", "content": analysis_prompt},
                    {"role": "user", "content": user_input}
                ],
                temperature=0.7,
                max_tokens=1024,
            )
            
            return response.choices[0].message.content
        except Exception as e:
            return f"分析エラー: {str(e)}"

    def generate_prompt(self, client, params):
        """プロンプト生成のメインメソッド"""
        try:
            # 1. まずQwenモデルでユーザー入力を分析
            analysis = self.analyze_user_input(client, params["input"])
            
            # 2. 分析結果を含めたユーザーメッセージの構築
            user_message = self._build_user_message(params, analysis)
            
            # 3. 選択されたモデルでプロンプト生成
            model = params.get("model", "llama-3.3-70b-versatile")
            
            # モデルごとの最適なパラメータ設定
            temperature = 0.7  # デフォルト値
            max_tokens = 2048  # デフォルト値
            
            # モデル特性に基づく設定の微調整
            if "maverick" in model or "mistral" in model:
                # より小さいモデルはやや高いtemperatureで創造性を引き出す
                temperature = 0.8
            elif "qwen" in model:
                # 創造性に特化したモデルはさらに高い値
                temperature = 0.85
            elif "o4-mini" in model:
                # OpenAI GPT APIの場合
                return self._generate_with_openai(params, user_message)
            
            # Groq APIでプロンプト生成
            response = client.chat.completions.create(
                model=model,  # 選択されたモデルを使用
                messages=[
                    {"role": "system", "content": self.system_prompt},
                    {"role": "user", "content": user_message}
                ],
                temperature=temperature,
                max_tokens=max_tokens,
            )
            
            # レスポンスの取得
            return response.choices[0].message.content
            
        except Exception as e:
            return f"エラーが発生しました: {str(e)}"
    
    def _generate_with_openai(self, params, user_message):
        """OpenAI GPT APIを使用してプロンプトを生成"""
        try:
            # OpenAI APIキーを環境変数から取得
            api_key = os.environ.get("OPENAI_API_KEY")
            if not api_key:
                return "OpenAI APIキーが設定されていません。"
            
            # OpenAI APIクライアントを初期化
            client = OpenAI(api_key=api_key)
            
            # APIリクエスト送信
            response = client.chat.completions.create(
                model="o4-mini-2025-04-16",
                messages=[
                    {"role": "system", "content": self.system_prompt},
                    {"role": "user", "content": user_message}
                ],
                max_completion_tokens=2048  # temperatureパラメータを削除(デフォルト値の1が使用される)
            )
            
            # レスポンスの取得
            return response.choices[0].message.content
            
        except Exception as e:
            return f"OpenAI APIエラー: {str(e)}"
    
    def _build_user_message(self, params, analysis=None):
        """ユーザーメッセージの構築"""
        # 基本情報
        mode = "MidJourney" if params["mode"] == "midjourney" else "nijiJourney"
        complexity_map = {
            "シンプル": "simple",
            "バランス": "balanced",
            "詳細": "detailed",
            "実験的": "experimental"
        }
        complexity = complexity_map.get(params["complexity"], "balanced")
        
        # メッセージ構築
        message = f"""
以下の入力からAIアート生成のプロンプトを作成してください:

入力: {params["input"]}
モード: {mode}
複雑さ: {complexity}
"""

        # 分析結果があれば追加
        if analysis:
            message += f"""
\n分析結果:
{analysis}

この分析結果を考慮して、以下の重要なガイドラインに従ってプロンプトを生成してください:

1. プロンプトは必ず英語で生成すること(システムタグやパラメータ名も含め)
2. ユーザーの元の入力内容({params["input"]})を最優先し、その意図と本質を100%維持すること
3. 主体となる対象や重要な要素は絶対に変更しないこと
   例:「イルカ」を「シャチ」に変えるなど種類/種別を変更しない
   例:「猫」を「虎」に変えるなど、近い種でも誤変換しない
   例:「少女」を「少年」に変えるなど性別を変更しない
4. ユーザーが明示的に指定した具体的な特徴は必ず維持すること(色、形状、特性など)
5. 曖昧さを減らすため、必要に応じて固有名詞の正確な英語表記を追加すること
   例:イルカ→bottlenose dolphin、虎→tiger、桜→cherry blossom
6. ユーザーが望まない要素や誤解される可能性のある要素をネガティブプロンプト(--no)に含めること
   例:「イルカ」の場合は「--no orca, killer whale, shark」など
7. 代替解釈の可能性がある場合は、ユーザーの意図に最も近いと思われる解釈を選択すること
8. システムタグやパラメータ内の言語も必ず英語にすること(例:「图像:」→「image:」)

【重要】ユーザーの元の入力({params["input"]})を最も重視してください。分析結果はあくまで補助情報として使用し、
元の入力内容の意図を変えたり、要素を追加/除外したりしないでください。
プロンプトは必ずユーザーの入力を正確に英語に変換し、その上で適切なテクニックを適用してください。
"""
        
        # 基本設定
        message += f"""
基本設定:
- アスペクト比: {params["aspect_ratio"]}
- クオリティ (--q): {params["quality"]}
- スタイル: {params["style"]}
- スタイル強度 (--s): {params["stylize"]}
"""
        
        # 高度な設定
        if any(v for k, v in params["advanced"].items() if v and k not in ["advanced_params", "style_reference", "personalization", "character_reference", "repeat", "image_weight", "generation_mode", "visibility", "seed", "chaos", "negative_prompt", "tile", "stop"]):
            message += "\n高度な設定:"
            
            if params["advanced"]["camera_angle"]:
                message += f"\n- カメラアングル: {params['advanced']['camera_angle']}"
            
            if params["advanced"]["lens_type"]:
                message += f"\n- レンズタイプ: {params['advanced']['lens_type']}"
            
            if params["advanced"]["lighting"]:
                message += f"\n- 照明設定: {params['advanced']['lighting']}"
            
            if params["advanced"]["composition"]:
                message += f"\n- 構図: {params['advanced']['composition']}"
            
            if params["advanced"]["advanced_params"]:
                message += f"\n- カスタムパラメータ: {json.dumps(params['advanced']['advanced_params'], ensure_ascii=False)}"
        
        # MidJourney特有のパラメータ
        midjourney_params = []
        
        # スタイルリファレンス
        if params["advanced"].get("style_reference", {}).get("use"):
            sref_data = params["advanced"]["style_reference"]
            midjourney_params.append(f"--sref {sref_data['value']}")
            
            if "style_weight" in sref_data:
                midjourney_params.append(f"--sw {sref_data['style_weight']}")
            
            if "style_version" in sref_data:
                midjourney_params.append(f"--sv {sref_data['style_version']}")
        
        # パーソナライゼーション
        if params["advanced"].get("personalization", {}).get("use"):
            person_data = params["advanced"]["personalization"]
            if person_data["type"] == "デフォルト":
                midjourney_params.append("--p")
            else:
                midjourney_params.append(f"--p {person_data['value']}")
        
        # キャラクター参照
        if params["advanced"].get("character_reference", {}).get("use"):
            cref_data = params["advanced"]["character_reference"]
            midjourney_params.append(f"--cref {cref_data['value']}")
        
        # 繰り返し生成
        if params["advanced"].get("repeat", {}).get("use"):
            repeat_count = params["advanced"]["repeat"]["count"]
            midjourney_params.append(f"--r {repeat_count}")
        
        # 画像プロンプトの影響度
        if params["advanced"].get("image_weight", {}).get("use"):
            image_weight = params["advanced"]["image_weight"]["value"]
            midjourney_params.append(f"--iw {image_weight}")
        
        # seed値
        if params["advanced"].get("seed", {}).get("use"):
            seed_data = params["advanced"]["seed"]
            midjourney_params.append(f"--seed {seed_data['value']}")
        
        # chaosレベル
        if params["advanced"].get("chaos", {}).get("use"):
            chaos_data = params["advanced"]["chaos"]
            midjourney_params.append(f"--c {chaos_data['value']}")
        
        # ネガティブプロンプト
        if params["advanced"].get("negative_prompt", {}).get("use"):
            negative_data = params["advanced"]["negative_prompt"]
            neg_elements = negative_data['value'].split(',')
            for element in neg_elements:
                if element.strip():
                    midjourney_params.append(f"--no {element.strip()}")
        
        # タイル機能
        if params["advanced"].get("tile", {}).get("use"):
            midjourney_params.append("--tile")
        
        # stop値
        if params["advanced"].get("stop", {}).get("use"):
            stop_data = params["advanced"]["stop"]
            midjourney_params.append(f"--stop {stop_data['value']}")
        
        # 生成モード
        if params["advanced"].get("generation_mode") and params["advanced"]["generation_mode"] != "デフォルト":
            midjourney_params.append(f"--{params['advanced']['generation_mode']}")
        
        # 共有設定
        if params["advanced"].get("visibility") and params["advanced"]["visibility"] != "デフォルト":
            midjourney_params.append(f"--{params['advanced']['visibility']}")
        
        # MidJourney特有のパラメータがあれば追加
        if midjourney_params:
            message += "\nMidJourney特有のパラメータ:\n- " + "\n- ".join(midjourney_params)
        
        # 実験的機能
        if any(v for k, v in params["experimental"].items() if v):
            message += "\n実験的機能:"
            
            for k, v in params["experimental"].items():
                if v and k != "pattern_concepts" and k != "emotions":
                    message += f"\n- {k}: 有効"
            
            if params["experimental"].get("pattern_concepts"):
                message += f"\n- 対照的概念: {', '.join(params['experimental']['pattern_concepts'])}"
            
            if params["experimental"].get("emotions"):
                message += f"\n- 感情マトリックス: 主要={params['experimental']['emotions']['primary']}, 二次={params['experimental']['emotions']['secondary']}"
        
        # 選択されたテクニック
        if "techniques" in params and params["techniques"]:
            message += f"\n選択されたテクニック: {', '.join(params['techniques'])}"
        else:
            message += "\nテクニック: 自動選択"
        
        return message