Spaces:
Running
Running
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 |