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