ウェブサイト検索

StreamlitとPythonを使ったAI画像プロンプトビルダーアプリを作成する


紹介

AI画像生成は、ChatGPT、Ideogram、Midjourney、Stable Diffusionなどのツールでますます人気が高まっています。しかし、求めるものを正確に得るための完璧なプロンプトを作成することは、挑戦的で時間がかかる場合があります。構造化されたプロンプトビルダーアプリケーションは、視覚要素のための整理されたカテゴリとオプションを提供することで、ユーザーが詳細で一貫したプロンプトを作成するのを助けることができます。

このチュートリアルでは、StreamlitとPythonを使用して包括的なAI画像プロンプトビルダーアプリケーションを作成します。このアプリケーションには、詳細なビジュアルプロンプトを作成するための一般的なPromptBuilderと、ミームスタイルの画像を作成するための専門的なミームジェネレーターの2つの主要なモードが搭載されます。

ユーザーは数十の視覚的パラメータをカスタマイズし、インスピレーションのために設定をランダム化し、AI画像生成サービスで使用するために構成をJSONファイルとしてエクスポートできるようになります。また、DigitalOcean MCPサーバーを使用してDigitalOcean App Platformにアプリを展開します。

このチュートリアルの終わりまでには、テキストオーバーレイオプションとダウンロード可能なプロンプトプロファイルを備えた、AI画像生成のための構造化されたプロンプトを生成する完全に機能するWebアプリケーションを構築することになるでしょう。

前提条件

このチュートリアルを始める前に、あなたが必要なもの:

  • システムにPython 3.7以上がインストールされている。
  • あなたのコンピュータにインストールされたCursorのようなコードエディタ。
  • 関数、辞書、およびリストを含むPythonプログラミングの基本的な概念に関する基本的な理解。
  • ウェブアプリケーションの概念とユーザーインターフェースの理解。
  • バージョン管理のためのGitHubアカウント。
  • あなたのCursor IDEにインストールされたDigitalOcean MCPサーバー。

ステップ1 — 環境の設定

まず、新しいディレクトリを作成し、AI画像プロンプトビルダーアプリケーション用にその中に移動します:

mkdir ai-prompt-builder
cd ai-prompt-builder

次に、依存関係を管理するためにプロジェクト用の仮想環境を作成します:

python -m venv venv
source venv/bin/activate

必要なPythonパッケージをインストールします:

pip install streamlit

メインアプリケーションファイルを作成します:

touch prompt_builder.py

このファイルには、ユーザーインターフェース、フィールド定義、プロンプト生成ロジックを含むすべてのStreamlitアプリケーションのコードが含まれます。

ステップ2 — 依存関係のインポートとヘルパー関数の作成

テキストエディタでprompt_builder.pyを開き、必要なインポートとヘルパー関数を追加します:

import streamlit as st
import json
import random

Helper function to dynamically render Streamlit input widgets based on field properties
def render_field(field, value, key, random_mode=False):
    """
    Dynamically renders a Streamlit input widget based on the field's properties.
    Supports selectbox with custom option, text input, number input, and checkbox.
    Includes help text as a tooltip.
    """
    options = field.get("options")  # Check if the field has predefined options
    helptext = field.get("desc", "")  # Retrieve the field's description for help text
    if options:  # If options are available, render a selectbox with a custom option
        extended_options = list(options) + ["Custom..."]  # Add a custom option to the end
        sel = st.selectbox(field["label"], extended_options, index=extended_options.index(value) if value in extended_options else len(extended_options)-1, help=helptext, key=key)
        if sel == "Custom...":  # If the custom option is selected
            return st.text_input(f"Custom value for {field['label']}", value="" if random_mode else value, help=helptext, key=f"{key}_custom")
        return sel
    elif isinstance(field["default"], bool):  # If the field's default is a boolean, render a checkbox
        return st.checkbox(field["label"], value=value, help=helptext, key=key)
    elif isinstance(field["default"], int):  # If the field's default is an integer, render a number input
        return st.number_input(field["label"], value=value, min_value=0, max_value=200, help=helptext, key=key)
    else:  # For any other field type, render a text input
        return st.text_input(field["label"], value=value, help=helptext, key=key)

Function to generate random values for fields based on their type
def random_from_field(field):
    """
    Generates a random value for a field based on its type.
    Supports options, boolean, integer, and default values.
    """
    if field.get("options"):  # If the field has options, choose a random one
        return random.choice(field["options"])
    elif isinstance(field["default"], bool):  # If the field's default is a boolean, choose a random boolean value
        return random.choice([True, False])
    elif isinstance(field["default"], int):  # If the field's default is an integer, generate a random integer within a range
        return random.randint(18, 72)
    else:  # For any other field type, return the default value
        return field["default"]

このコードブロックは、フィールドプロパティに基づいてStreamlit入力ウィジェットを動的にレンダリングし、フィールドのためにランダムな値を生成する2つのヘルパー関数を定義しています。render_field関数は、フィールドの定義、値、キー、およびオプションのランダムモードフラグを受け取ります。この関数は、オプション、デフォルト値、説明など、フィールドのプロパティに基づいてStreamlit入力ウィジェットを動的にレンダリングします。この関数は、カスタムオプションを持つ選択ボックス、テキスト入力、数値入力、およびチェックボックスをサポートし、ツールチップとしてヘルプテキストを含んでいます。カスタムオプションが選択された場合は、カスタム値のためのテキスト入力がレンダリングされます。random_from_field関数は、タイプに基づいてフィールドのためにランダムな値を生成し、オプション、ブール値、整数、デフォルト値をサポートします。これは、フィールドのオプションからランダムなオプションを選択したり、ランダムなブール値、範囲内のランダムな整数を選択したり、その他のフィールドタイプの場合はデフォルト値を返します。

視覚的パラメーターオプションの定義

各視覚パラメーターの包括的なオプションリストを追加します。これらのリストは、ユーザーに厳選された選択肢を提供しつつ、カスタム値を入力するオプションも維持します:

Massive options lists for each parameter
ASPECT_RATIOS = ["16:9", "3:2", "1:1", "4:3", "2:3", "21:9", "5:4", "7:5", "4:5", "2:1", "9:16"]
SUBSTRATES = ["inked comic illustration", "digital paint", "oil painting", "sketch", "realistic", "3D render", "collage", "pastel", "pixel art", "watercolor"]
ARTISTS = ["Frank Miller", "vintage DC", "photorealism", "pop art", "noir comics", "Moebius", "Hergé", "Jack Kirby", "Studio Ghibli", "Banksy", "Bill Sienkiewicz", "Jim Lee"]
COATINGS = ["crosshatch texture", "smooth paint", "grainy paper", "canvas", "scratched vinyl", "halftone", "glossy", "matte"]
MEME_REFS = ["1960s detective comics", "classic noir cinema", "viral meme", "wholesome meme", "internet meme", "cat meme", "Pepe", "Distracted Boyfriend", "Swole Doge", "Wojak"]
ACCESSORIES = ["fedora", "overcoat", "martini glass", "newspaper", "classic car", "microphone", "sword", "smartphone", "laptop", "cigarette", "rose", "gun", "wine glass"]
ENVIRONMENTS = ["mid-century modern cafe", "nightclub", "alleyway", "office", "foggy street", "apartment", "desert", "battlefield", "studio", "mountaintop", "subway", "beach", "city park", "library", "rooftop"]
STYLES = ["dramatic noir illustration", "graphic novel", "fine art", "cartoon", "cinematic", "modern comic", "vintage comic", "hyper-real", "expressionist", "anime", "abstract"]
WEATHERS = ["indoors", "rainy", "foggy", "clear", "dusty", "snowy", "stormy", "hazy", "humid"]
TIMES = ["evening", "night", "sunset", "day", "afternoon", "dawn", "midnight"]
MATERIALS = ["pen-and-ink texture on paper", "oil paint", "charcoal", "digital ink", "photographic", "watercolor", "acrylic", "mixed media"]
MOODS = ["shocking and suspenseful", "comedic", "mysterious", "heroic", "melancholic", "uplifting", "tense", "peaceful", "playful", "romantic", "tragic", "epic"]
SURFACES = ["fine comic hatching", "smooth", "rough paper", "canvas", "film grain", "brushed metal", "wood grain", "cracked", "stippled", "matte"]
LIGHTING_TYPES = ["harsh directional lighting with strong contrast", "soft ambient", "backlit", "spotlight", "natural", "dramatic", "painterly directional lighting", "noon sun", "candlelight", "neon", "moonlit"]
LIGHT_TEMPS = ["cool monochrome", "warm yellow", "neutral", "blue hour", "red sunset", "greenish", "pinkish", "icy blue"]
LIGHT_INTENS = ["high", "medium", "low", "soft", "high contrast shadows", "dappled", "blinding", "faint"]
LIGHT_DIRS = ["angled golden hour side-light", "overhead and front-lit with deep shadows", "side-lit", "backlit", "underlit", "from below", "from above", "rim light", "cross light", "front light"]
LIGHT_ACCENTS = ["#800000,#d4af37,#5c4033,golden yellow", "white ink highlights", "gray tones", "sepia", "yellow glow", "blue highlights", "violet", "red edge", "#FFFF00", "#00FF00", "#FF00FF"]
COLOR_SCHEME_PRIMARY = ["sepia bronze tones", "black and white", "sepia", "monochrome", "colorful", "gray tones", "blue palette", "red palette", "earth tones", "pastel"]
COLOR_SCHEME_SECOND = ["desaturated earth shadows", "gray tones", "desaturated", "subtle color accent", "saturated", "neon", "metallic"]
COLOR_SCHEME_HIGHLIGHTS = ["sharp golden highlights", "white ink highlights", "silver", "yellow highlights", "red highlights", "cyan", "orange", "lime"]
COLOR_SCHEME_RIM = ["subtle crimson rim light on figures", "subtle rim light", "none", "warm rim light", "cool rim light", "hard white rim", "neon edge"]
BG_COLORS = ["dusty bronze gradient", "plain white", "deep black", "sepia", "gray", "vivid color", "sunset", "night sky", "gradient blue-purple"]
BG_TEXTURES = ["foggy battlefield haze", "smooth", "rough", "grunge", "film grain", "cloudy", "geometric", "tiled", "marble"]
CAMERA_TYPES = ["DSLR", "film", "smartphone", "cinema", "mirrorless", "vintage Leica", "polaroid", "pinhole"]
CAM_ANGLES = ["low heroic angle", "high angle", "eye level", "bird's eye", "worm's eye", "overhead", "close-up", "wide shot"]
FOCALS = ["85mm", "35mm", "50mm", "24mm", "135mm", "14mm", "70mm", "200mm"]
DOFS = ["shallow", "deep"]
CLOTHES = ["tunic", "t-shirt", "armor", "suit", "vest", "cape", "jacket", "robe", "overcoat", "scarf"]
EYEWEARS = ["none", "glasses", "sunglasses", "monocle", "visor", "goggles", "eyepatch"]
SHOES = ["none", "boots", "sandals", "dress shoes", "sneakers", "barefoot", "loafers", "combat boots"]
WILDLIFE = ["none", "giraffe", "panda", "chimpanzee", "lion", "wolf", "owl", "cat", "dog", "falcon", "tiger", "elephant", "fox"]
MAKEUP = ["none", "dramatic", "subtle", "theatrical", "stage", "cyberpunk", "goth", "neon", "clown"]

FONT_FAMILIES = ["Arial", "Times New Roman", "Comic Sans MS", "Courier New", "Impact", "Roboto", "Open Sans", "Oswald", "Montserrat", "Georgia", "Helvetica", "Futura"]
TEXT_POSITIONS = ["top", "center", "bottom", "left", "right"]
TEXT_EFFECTS = ["none", "drop shadow", "glow", "outline", "emboss", "engraved"]

Field definition as dicts for clarity
FIELD_DEFINITIONS = [
    {"key": "aspect_ratio", "label": "Aspect Ratio", "default": "16:9", "desc": "Image width to height ratio, e.g. 16:9 for cinematic, 1:1 for square.", "options": ASPECT_RATIOS},
    {"key": "character_substrate_base", "label": "Character Substrate Base", "default": "inked comic illustration", "desc": "The underlying art medium for the subject.", "options": SUBSTRATES},
    {"key": "artist_style", "label": "Artist Style", "default": "Frank Miller", "desc": "Mimic the style of a famous artist or movement.", "options": ARTISTS},
    {"key": "character_substrate_coating", "label": "Character Substrate Coating", "default": "crosshatch texture", "desc": "Texture or visual overlay on top of the main character.", "options": COATINGS},
    {"key": "meme_reference", "label": "Meme Reference", "default": "1960s detective comics", "desc": "Reference a meme, pop-culture, or comic genre.", "options": MEME_REFS},
    {"key": "starter_pack_accessories", "label": "Starter Pack Accessories", "default": "fedora", "desc": "Add iconic props or accessories.", "options": ACCESSORIES},
    {"key": "environment", "label": "Environment", "default": "mid-century modern cafe", "desc": "Where the scene is set.", "options": ENVIRONMENTS},
    {"key": "style", "label": "Overall Style", "default": "dramatic noir illustration", "desc": "General mood and look of the image.", "options": STYLES},
    {"key": "weather", "label": "Weather", "default": "indoors", "desc": "Atmospheric conditions in the scene.", "options": WEATHERS},
    {"key": "time_of_day", "label": "Time of Day", "default": "evening", "desc": "Daytime setting for the scene.", "options": TIMES},
    {"key": "material", "label": "Material", "default": "pen-and-ink texture on paper", "desc": "Main material used (for a tactile/retro feel).", "options": MATERIALS},
    {"key": "mood_atmosphere", "label": "Mood / Atmosphere", "default": "shocking and suspenseful", "desc": "Scene's emotional energy.", "options": MOODS},
    {"key": "surface_texture", "label": "Surface Texture", "default": "fine comic hatching", "desc": "Visual texture for surface details.", "options": SURFACES},
    {"key": "lighting_type", "label": "Lighting Type", "default": "harsh directional lighting with strong contrast", "desc": "How the scene is lit, and the kind of shadows.", "options": LIGHTING_TYPES},
    {"key": "lighting_temperature", "label": "Lighting Temperature", "default": "cool monochrome", "desc": "Hue/tone of the light source.", "options": LIGHT_TEMPS},
    {"key": "lighting_intensity", "label": "Lighting Intensity", "default": "high", "desc": "How bright, dark, or contrasted the lighting is.", "options": LIGHT_INTENS},
    {"key": "lighting_direction", "label": "Lighting Direction", "default": "angled golden hour side-light", "desc": "Direction from which the main light comes.", "options": LIGHT_DIRS},
    {"key": "lighting_accent_colors", "label": "Lighting Accent Colors", "default": "#800000,#d4af37,#5c4033,golden yellow", "desc": "Accent colors in lighting (comma separated or hex).", "options": LIGHT_ACCENTS},
    {"key": "color_scheme_primary", "label": "Color Scheme (Primary)", "default": "sepia bronze tones", "desc": "Main color palette for the scene.", "options": COLOR_SCHEME_PRIMARY},
    {"key": "color_scheme_secondary", "label": "Color Scheme (Secondary)", "default": "desaturated earth shadows", "desc": "Secondary or supporting color palette.", "options": COLOR_SCHEME_SECOND},
    {"key": "color_scheme_highlights", "label": "Color Scheme (Highlights)", "default": "sharp golden highlights", "desc": "Highlight or accent color for shiny/emphasized areas.", "options": COLOR_SCHEME_HIGHLIGHTS},
    {"key": "color_scheme_rim_light", "label": "Color Scheme (Rim Light)", "default": "subtle crimson rim light on figures", "desc": "Color for edge/rim light effects.", "options": COLOR_SCHEME_RIM},
    {"key": "background_color", "label": "Background Color", "default": "dusty bronze gradient", "desc": "Color or gradient for the image background.", "options": BG_COLORS},
    {"key": "background_texture", "label": "Background Texture", "default": "foggy battlefield haze", "desc": "Texture overlay for the background.", "options": BG_TEXTURES},
    {"key": "camera_type", "label": "Camera Type", "default": "DSLR", "desc": "Type of camera simulated.", "options": CAMERA_TYPES},
    {"key": "camera_angle", "label": "Camera Angle", "default": "low heroic angle", "desc": "Perspective/viewpoint from which the image is drawn.", "options": CAM_ANGLES},
    {"key": "focal_length", "label": "Focal Length", "default": "85mm", "desc": "Camera lens focal length.", "options": FOCALS},
    {"key": "depth_of_field", "label": "Depth of Field", "default": "shallow", "desc": "Blurriness of the background.", "options": DOFS},
    {"key": "clothing_top", "label": "Clothing (Top)", "default": "tunic", "desc": "Upper body clothing style.", "options": CLOTHES},
    {"key": "eyewear", "label": "Eyewear", "default": "none", "desc": "Any glasses, shades, monocle, etc.", "options": EYEWEARS},
    {"key": "shoe_type", "label": "Shoe Type", "default": "boots", "desc": "Type of footwear.", "options": SHOES},
    {"key": "wildlife_in_scene", "label": "Wildlife In Scene", "default": "none", "desc": "Add an animal or wildlife element to the scene.", "options": WILDLIFE},
    {"key": "makeup", "label": "Makeup", "default": "none", "desc": "Style of makeup applied to subjects.", "options": MAKEUP}
]

TEXT_OVERLAY_FIELDS = [
    {"key": "add_text_overlay", "label": "Add Text to Image?", "default": False, "desc": "Enable to overlay text directly onto the image.", "options": None},
    {"key": "overlay_text", "label": "Overlay Text", "default": "Welcome to the noir comic generator!", "desc": "Text to display over the image.", "options": None},
    {"key": "font_family", "label": "Font Family", "default": "Arial", "desc": "Font used for the overlay text.", "options": FONT_FAMILIES},
    {"key": "font_size", "label": "Font Size (px)", "default": 48, "desc": "Font size for the overlay text.", "options": None},
    {"key": "font_color", "label": "Font Color", "default": "#FFFFFF", "desc": "Hex color for the overlay text (e.g., #FFFFFF for white).", "options": None},
    {"key": "text_position", "label": "Text Placement", "default": "center", "desc": "Where the text appears in the image.", "options": TEXT_POSITIONS},
    {"key": "text_effect", "label": "Text Effect", "default": "none", "desc": "Extra effects for the overlay text.", "options": TEXT_EFFECTS}
]

DEFAULT_INSTRUCTION_PROMPTS = [
    "Create a cinematic hero shot in bronze hues.",
    "Comic-style noir scene with expressive lighting.",
    "Dramatic sunset battle with ancient warriors.",
    "Cartoon meme in black and white.",
    "Suspenseful moment inside a dimly lit cafe.",
    "Futuristic cityscape in graphic novel style.",
    "Shocking twist in a detective story.",
    "Epic landscape inspired by Greek myth.",
    "1960s noir illustration with emotional contrast."
]

このコードブロックは、AI画像生成プロンプトビルダーのための包括的な設定オプションのセットを定義しています。アスペクト比、アートスタイル、照明条件、キャラクター属性などのさまざまな視覚パラメータに対する事前定義された選択肢のリストを作成します。

これらのオプションは、ラベル、デフォルト値、説明、およびそれに対応するオプションリストを含む構造化されたフィールド定義に整理されます。また、コードにはテキストオーバーレイとデフォルトの指示プロンプトのための特別な設定も含まれています。

この構造化されたアプローチにより、ユーザーはキュレーションされたオプションから選択しながら、カスタム値を入力する柔軟性を保ちながら、詳細な画像生成プロンプトを構築することができます。

ステップ3 — ステート管理機能の実装

ランダム化とフィールド値取得を処理する関数を作成します:

#----------- APP LOGIC -----------

st.set_page_config(page_title="PromptBuilder (Power User)", layout="wide")
st.title("🖼️ Ultimate PromptBuilder & Meme Generator")

tab1, tab2 = st.tabs(["PromptBuilder", "Meme Generator"])

--- Helper for storing randomize state ---
def set_random_state(tabkey, fields, overlayfields):
    st.session_state[f"random_{tabkey}_fields"] = {f["key"]: random_from_field(f) for f in fields}
    st.session_state[f"random_{tabkey}_overlay"] = {f["key"]: random_from_field(f) for f in overlayfields}
    st.session_state[f"random_{tabkey}_instruction"] = random.choice(DEFAULT_INSTRUCTION_PROMPTS)

def get_field_value(tabkey, key, field):
    # If randomize state, use it; else, use default
    randval = st.session_state.get(f"random_{tabkey}_fields", {}).get(key)
    return randval if randval is not None else field["default"]

def get_overlay_value(tabkey, key, field):
    randval = st.session_state.get(f"random_{tabkey}_overlay", {}).get(key)
    return randval if randval is not None else field["default"]

def get_instruction(tabkey):
    return st.session_state.get(f"random_{tabkey}_instruction", DEFAULT_INSTRUCTION_PROMPTS[0])

このコードブロックは、フィールドのランダム化やフィールド値の取得を含むアプリケーション状態を管理するためのいくつかのヘルパー関数を定義しています。set_random_state関数は、ランダム化されたフィールド値をセッション状態に保存し、get_field_valueとget_overlay_value関数は、利用可能な場合はランダム化された値を用いてフィールドまたはオーバーレイフィールドの現在の値を取得します。get_instruction関数は、セッション状態からデフォルトの指示プロンプトを取得します。

ステップ4 — プロンプトビルダータブの実装

一般的なプロンプト作成のための最初のタブを作成します:

-------- Prompt Builder TAB --------
with tab1:
    col1, col2 = st.columns([1, 2])
    with col1:
        if st.button("🔀 Randomize All Fields!", key="rand_pb"):
            set_random_state("pb", FIELD_DEFINITIONS, TEXT_OVERLAY_FIELDS)
        if st.button("Reset", key="reset_pb"):
            st.session_state["random_pb_fields"] = {}
            st.session_state["random_pb_overlay"] = {}
            st.session_state["random_pb_instruction"] = DEFAULT_INSTRUCTION_PROMPTS[0]
    with col2:
        pb_instruction = st.text_area(
            "Instruction Prompt",
            value=get_instruction("pb"),
            key="pb_instruction"
        )

    st.markdown("### Visual Prompt Fields")
    pb_field_values = {}
    for field in FIELD_DEFINITIONS:
        val = render_field(field, get_field_value("pb", field["key"], field), key=f"pb_{field['key']}")
        pb_field_values[field["key"]] = val

    st.markdown("### Text-on-Image Controls (Optional)")
    pb_overlay_values = {}
    for field in TEXT_OVERLAY_FIELDS:
        val = render_field(field, get_overlay_value("pb", field["key"], field), key=f"pb_{field['key']}")
        pb_overlay_values[field["key"]] = val
    if not pb_overlay_values.get("add_text_overlay", False):
        pb_overlay_values = {k: v for k, v in pb_overlay_values.items() if k == "add_text_overlay"}

    if st.button("Generate JSON Prompt", key="gen_pb"):
        pb_profile = {
            "instruction_prompt": pb_instruction,
            "profile_parameters": pb_field_values
        }
        if pb_overlay_values.get("add_text_overlay"):
            overlay_params = {k: v for k, v in pb_overlay_values.items() if k != "add_text_overlay"}
            pb_profile["text_overlay"] = overlay_params
        st.session_state["prompt_profile"] = pb_profile

    if "prompt_profile" in st.session_state:
        st.markdown("#### JSON Prompt Profile")
        json_str = json.dumps(st.session_state["prompt_profile"], indent=4)
        st.code(json_str, language="json")
        st.download_button("Download JSON", json_str, file_name="prompt_profile.json")
        st.text_area("Copy JSON (with preamble):", json_str, height=200)

このコードブロックは、ランダム化コントロールやすべての視覚パラメータフィールドを含む、メインプロンプトビルダーのユーザーインターフェースを作成します。また、JSONプロンプトプロファイルを生成して表示する機能も含まれています。この条件付きロジックは、ユーザーがテキストオーバーレイ機能を有効にしたときのみテキストオーバーレイパラメータを含めており、出力をクリーンで関連性のあるものに保っています。

このコードブロックは、ユーザーがAI画像生成サービスで使用するためにダウンロードまたはコピーできる構造化されたJSON出力も作成します。この条件付きロジックは、ユーザーがテキストオーバーレイ機能を有効にしたときのみテキストオーバーレイパラメータを含め、出力をクリーンかつ関連性のあるものに保ちます。

ステップ5 — ミームプロンプトジェネレータータブの実装

同様の機能を持ちながらも、ミームプロンプト生成に焦点を当てた2番目のタブを作成してください。

-------- Meme Prompt Generator TAB --------
with tab2:
    col1, col2 = st.columns([1, 2])
    with col1:
        if st.button("🔀 Randomize Meme Fields!", key="rand_meme"):
            set_random_state("meme", FIELD_DEFINITIONS, TEXT_OVERLAY_FIELDS)
        if st.button("Reset Meme Fields", key="reset_meme"):
            st.session_state["random_meme_fields"] = {}
            st.session_state["random_meme_overlay"] = {}
            st.session_state["random_meme_instruction"] = DEFAULT_INSTRUCTION_PROMPTS[0]
    with col2:
        meme_instruction = st.text_area(
            "Instruction Prompt",
            value=get_instruction("meme"),
            key="meme_instruction"
        )

    st.markdown("### Meme Visual Fields")
    meme_field_values = {}
    for field in FIELD_DEFINITIONS:
        val = render_field(field, get_field_value("meme", field["key"], field), key=f"meme_{field['key']}")
        meme_field_values[field["key"]] = val

    st.markdown("### Meme Text Controls")
    meme_overlay_values = {}
    for field in TEXT_OVERLAY_FIELDS:
        val = render_field(field, get_overlay_value("meme", field["key"], field), key=f"meme_{field['key']}")
        meme_overlay_values[field["key"]] = val
    if not meme_overlay_values.get("add_text_overlay", False):
        meme_overlay_values = {k: v for k, v in meme_overlay_values.items() if k == "add_text_overlay"}

    if st.button("Generate Meme JSON Prompt", key="gen_meme"):
        meme_profile = {
            "instruction_prompt": meme_instruction,
            "profile_parameters": meme_field_values
        }
        if meme_overlay_values.get("add_text_overlay"):
            overlay_params = {k: v for k, v in meme_overlay_values.items() if k != "add_text_overlay"}
            meme_profile["text_overlay"] = overlay_params
        st.session_state["meme_profile"] = meme_profile

    if "meme_profile" in st.session_state:
        st.markdown("#### Meme JSON Prompt Profile")
        meme_json_str = json.dumps(st.session_state["meme_profile"], indent=4)
        st.code(meme_json_str, language="json")
        st.download_button("Download Meme JSON", meme_json_str, file_name="meme_profile.json")
        st.text_area("Copy Meme JSON (with preamble):", meme_json_str, height=200)

st.markdown("<hr><center>Made with ❤️ for pro users | by ChatGPT PromptBuilder</center>", unsafe_allow_html=True)

このコードブロックは、ミームプロンプトジェネレーターのユーザーインターフェースを作成し、ランダム化コントロールやすべての視覚的パラメータフィールドを含んでいます。また、JSONプロンプトプロファイルを生成し表示する機能も含まれています。この条件付きロジックは、ユーザーがテキストオーバーレイ機能を有効にした場合にのみテキストオーバーレイパラメータを含み、出力をクリーンで関連性のあるものに保ちます。

これがアプリのためのPythonコードの見た目です:

import streamlit as st
import json
import random

Helper: Field rendering
def render_field(field, value, key, random_mode=False):
    """Render field as selectbox+custom or text/number/checkbox, with help/tooltip."""
    options = field.get("options")
    helptext = field.get("desc", "")
    if options:
        extended_options = list(options) + ["Custom..."]
        sel = st.selectbox(field["label"], extended_options, index=extended_options.index(value) if value in extended_options else len(extended_options)-1, help=helptext, key=key)
        if sel == "Custom...":
            return st.text_input(f"Custom value for {field['label']}", value="" if random_mode else value, help=helptext, key=f"{key}_custom")
        return sel
    elif isinstance(field["default"], bool):
        return st.checkbox(field["label"], value=value, help=helptext, key=key)
    elif isinstance(field["default"], int):
        return st.number_input(field["label"], value=value, min_value=0, max_value=200, help=helptext, key=key)
    else:
        return st.text_input(field["label"], value=value, help=helptext, key=key)

def random_from_field(field):
    if field.get("options"):
        return random.choice(field["options"])
    elif isinstance(field["default"], bool):
        return random.choice([True, False])
    elif isinstance(field["default"], int):
        return random.randint(18, 72)
    else:
        return field["default"]

Massive options lists for each parameter
ASPECT_RATIOS = ["16:9", "3:2", "1:1", "4:3", "2:3", "21:9", "5:4", "7:5", "4:5", "2:1", "9:16"]
SUBSTRATES = ["inked comic illustration", "digital paint", "oil painting", "sketch", "realistic", "3D render", "collage", "pastel", "pixel art", "watercolor"]
ARTISTS = ["Frank Miller", "vintage DC", "photorealism", "pop art", "noir comics", "Moebius", "Hergé", "Jack Kirby", "Studio Ghibli", "Banksy", "Bill Sienkiewicz", "Jim Lee"]
COATINGS = ["crosshatch texture", "smooth paint", "grainy paper", "canvas", "scratched vinyl", "halftone", "glossy", "matte"]
MEME_REFS = ["1960s detective comics", "classic noir cinema", "viral meme", "wholesome meme", "internet meme", "cat meme", "Pepe", "Distracted Boyfriend", "Swole Doge", "Wojak"]
ACCESSORIES = ["fedora", "overcoat", "martini glass", "newspaper", "classic car", "microphone", "sword", "smartphone", "laptop", "cigarette", "rose", "gun", "wine glass"]
ENVIRONMENTS = ["mid-century modern cafe", "nightclub", "alleyway", "office", "foggy street", "apartment", "desert", "battlefield", "studio", "mountaintop", "subway", "beach", "city park", "library", "rooftop"]
STYLES = ["dramatic noir illustration", "graphic novel", "fine art", "cartoon", "cinematic", "modern comic", "vintage comic", "hyper-real", "expressionist", "anime", "abstract"]
WEATHERS = ["indoors", "rainy", "foggy", "clear", "dusty", "snowy", "stormy", "hazy", "humid"]
TIMES = ["evening", "night", "sunset", "day", "afternoon", "dawn", "midnight"]
MATERIALS = ["pen-and-ink texture on paper", "oil paint", "charcoal", "digital ink", "photographic", "watercolor", "acrylic", "mixed media"]
MOODS = ["shocking and suspenseful", "comedic", "mysterious", "heroic", "melancholic", "uplifting", "tense", "peaceful", "playful", "romantic", "tragic", "epic"]
SURFACES = ["fine comic hatching", "smooth", "rough paper", "canvas", "film grain", "brushed metal", "wood grain", "cracked", "stippled", "matte"]
LIGHTING_TYPES = ["harsh directional lighting with strong contrast", "soft ambient", "backlit", "spotlight", "natural", "dramatic", "painterly directional lighting", "noon sun", "candlelight", "neon", "moonlit"]
LIGHT_TEMPS = ["cool monochrome", "warm yellow", "neutral", "blue hour", "red sunset", "greenish", "pinkish", "icy blue"]
LIGHT_INTENS = ["high", "medium", "low", "soft", "high contrast shadows", "dappled", "blinding", "faint"]
LIGHT_DIRS = ["angled golden hour side-light", "overhead and front-lit with deep shadows", "side-lit", "backlit", "underlit", "from below", "from above", "rim light", "cross light", "front light"]
LIGHT_ACCENTS = ["#800000,#d4af37,#5c4033,golden yellow", "white ink highlights", "gray tones", "sepia", "yellow glow", "blue highlights", "violet", "red edge", "#FFFF00", "#00FF00", "#FF00FF"]
COLOR_SCHEME_PRIMARY = ["sepia bronze tones", "black and white", "sepia", "monochrome", "colorful", "gray tones", "blue palette", "red palette", "earth tones", "pastel"]
COLOR_SCHEME_SECOND = ["desaturated earth shadows", "gray tones", "desaturated", "subtle color accent", "saturated", "neon", "metallic"]
COLOR_SCHEME_HIGHLIGHTS = ["sharp golden highlights", "white ink highlights", "silver", "yellow highlights", "red highlights", "cyan", "orange", "lime"]
COLOR_SCHEME_RIM = ["subtle crimson rim light on figures", "subtle rim light", "none", "warm rim light", "cool rim light", "hard white rim", "neon edge"]
BG_COLORS = ["dusty bronze gradient", "plain white", "deep black", "sepia", "gray", "vivid color", "sunset", "night sky", "gradient blue-purple"]
BG_TEXTURES = ["foggy battlefield haze", "smooth", "rough", "grunge", "film grain", "cloudy", "geometric", "tiled", "marble"]
CAMERA_TYPES = ["DSLR", "film", "smartphone", "cinema", "mirrorless", "vintage Leica", "polaroid", "pinhole"]
CAM_ANGLES = ["low heroic angle", "high angle", "eye level", "bird's eye", "worm's eye", "overhead", "close-up", "wide shot"]
FOCALS = ["85mm", "35mm", "50mm", "24mm", "135mm", "14mm", "70mm", "200mm"]
DOFS = ["shallow", "deep"]
CLOTHES = ["tunic", "t-shirt", "armor", "suit", "vest", "cape", "jacket", "robe", "overcoat", "scarf"]
EYEWEARS = ["none", "glasses", "sunglasses", "monocle", "visor", "goggles", "eyepatch"]
SHOES = ["none", "boots", "sandals", "dress shoes", "sneakers", "barefoot", "loafers", "combat boots"]
WILDLIFE = ["none", "giraffe", "panda", "chimpanzee", "lion", "wolf", "owl", "cat", "dog", "falcon", "tiger", "elephant", "fox"]
MAKEUP = ["none", "dramatic", "subtle", "theatrical", "stage", "cyberpunk", "goth", "neon", "clown"]

FONT_FAMILIES = ["Arial", "Times New Roman", "Comic Sans MS", "Courier New", "Impact", "Roboto", "Open Sans", "Oswald", "Montserrat", "Georgia", "Helvetica", "Futura"]
TEXT_POSITIONS = ["top", "center", "bottom", "left", "right"]
TEXT_EFFECTS = ["none", "drop shadow", "glow", "outline", "emboss", "engraved"]

Field definition as dicts for clarity
FIELD_DEFINITIONS = [
    {"key": "aspect_ratio", "label": "Aspect Ratio", "default": "16:9", "desc": "Image width to height ratio, e.g. 16:9 for cinematic, 1:1 for square.", "options": ASPECT_RATIOS},
    {"key": "character_substrate_base", "label": "Character Substrate Base", "default": "inked comic illustration", "desc": "The underlying art medium for the subject.", "options": SUBSTRATES},
    {"key": "artist_style", "label": "Artist Style", "default": "Frank Miller", "desc": "Mimic the style of a famous artist or movement.", "options": ARTISTS},
    {"key": "character_substrate_coating", "label": "Character Substrate Coating", "default": "crosshatch texture", "desc": "Texture or visual overlay on top of the main character.", "options": COATINGS},
    {"key": "meme_reference", "label": "Meme Reference", "default": "1960s detective comics", "desc": "Reference a meme, pop-culture, or comic genre.", "options": MEME_REFS},
    {"key": "starter_pack_accessories", "label": "Starter Pack Accessories", "default": "fedora", "desc": "Add iconic props or accessories.", "options": ACCESSORIES},
    {"key": "environment", "label": "Environment", "default": "mid-century modern cafe", "desc": "Where the scene is set.", "options": ENVIRONMENTS},
    {"key": "style", "label": "Overall Style", "default": "dramatic noir illustration", "desc": "General mood and look of the image.", "options": STYLES},
    {"key": "weather", "label": "Weather", "default": "indoors", "desc": "Atmospheric conditions in the scene.", "options": WEATHERS},
    {"key": "time_of_day", "label": "Time of Day", "default": "evening", "desc": "Daytime setting for the scene.", "options": TIMES},
    {"key": "material", "label": "Material", "default": "pen-and-ink texture on paper", "desc": "Main material used (for a tactile/retro feel).", "options": MATERIALS},
    {"key": "mood_atmosphere", "label": "Mood / Atmosphere", "default": "shocking and suspenseful", "desc": "Scene's emotional energy.", "options": MOODS},
    {"key": "surface_texture", "label": "Surface Texture", "default": "fine comic hatching", "desc": "Visual texture for surface details.", "options": SURFACES},
    {"key": "lighting_type", "label": "Lighting Type", "default": "harsh directional lighting with strong contrast", "desc": "How the scene is lit, and the kind of shadows.", "options": LIGHTING_TYPES},
    {"key": "lighting_temperature", "label": "Lighting Temperature", "default": "cool monochrome", "desc": "Hue/tone of the light source.", "options": LIGHT_TEMPS},
    {"key": "lighting_intensity", "label": "Lighting Intensity", "default": "high", "desc": "How bright, dark, or contrasted the lighting is.", "options": LIGHT_INTENS},
    {"key": "lighting_direction", "label": "Lighting Direction", "default": "angled golden hour side-light", "desc": "Direction from which the main light comes.", "options": LIGHT_DIRS},
    {"key": "lighting_accent_colors", "label": "Lighting Accent Colors", "default": "#800000,#d4af37,#5c4033,golden yellow", "desc": "Accent colors in lighting (comma separated or hex).", "options": LIGHT_ACCENTS},
    {"key": "color_scheme_primary", "label": "Color Scheme (Primary)", "default": "sepia bronze tones", "desc": "Main color palette for the scene.", "options": COLOR_SCHEME_PRIMARY},
    {"key": "color_scheme_secondary", "label": "Color Scheme (Secondary)", "default": "desaturated earth shadows", "desc": "Secondary or supporting color palette.", "options": COLOR_SCHEME_SECOND},
    {"key": "color_scheme_highlights", "label": "Color Scheme (Highlights)", "default": "sharp golden highlights", "desc": "Highlight or accent color for shiny/emphasized areas.", "options": COLOR_SCHEME_HIGHLIGHTS},
    {"key": "color_scheme_rim_light", "label": "Color Scheme (Rim Light)", "default": "subtle crimson rim light on figures", "desc": "Color for edge/rim light effects.", "options": COLOR_SCHEME_RIM},
    {"key": "background_color", "label": "Background Color", "default": "dusty bronze gradient", "desc": "Color or gradient for the image background.", "options": BG_COLORS},
    {"key": "background_texture", "label": "Background Texture", "default": "foggy battlefield haze", "desc": "Texture overlay for the background.", "options": BG_TEXTURES},
    {"key": "camera_type", "label": "Camera Type", "default": "DSLR", "desc": "Type of camera simulated.", "options": CAMERA_TYPES},
    {"key": "camera_angle", "label": "Camera Angle", "default": "low heroic angle", "desc": "Perspective/viewpoint from which the image is drawn.", "options": CAM_ANGLES},
    {"key": "focal_length", "label": "Focal Length", "default": "85mm", "desc": "Camera lens focal length.", "options": FOCALS},
    {"key": "depth_of_field", "label": "Depth of Field", "default": "shallow", "desc": "Blurriness of the background.", "options": DOFS},
    {"key": "clothing_top", "label": "Clothing (Top)", "default": "tunic", "desc": "Upper body clothing style.", "options": CLOTHES},
    {"key": "eyewear", "label": "Eyewear", "default": "none", "desc": "Any glasses, shades, monocle, etc.", "options": EYEWEARS},
    {"key": "shoe_type", "label": "Shoe Type", "default": "boots", "desc": "Type of footwear.", "options": SHOES},
    {"key": "wildlife_in_scene", "label": "Wildlife In Scene", "default": "none", "desc": "Add an animal or wildlife element to the scene.", "options": WILDLIFE},
    {"key": "makeup", "label": "Makeup", "default": "none", "desc": "Style of makeup applied to subjects.", "options": MAKEUP}
]

TEXT_OVERLAY_FIELDS = [
    {"key": "add_text_overlay", "label": "Add Text to Image?", "default": False, "desc": "Enable to overlay text directly onto the image.", "options": None},
    {"key": "overlay_text", "label": "Overlay Text", "default": "Welcome to the noir comic generator!", "desc": "Text to display over the image.", "options": None},
    {"key": "font_family", "label": "Font Family", "default": "Arial", "desc": "Font used for the overlay text.", "options": FONT_FAMILIES},
    {"key": "font_size", "label": "Font Size (px)", "default": 48, "desc": "Font size for the overlay text.", "options": None},
    {"key": "font_color", "label": "Font Color", "default": "#FFFFFF", "desc": "Hex color for the overlay text (e.g., #FFFFFF for white).", "options": None},
    {"key": "text_position", "label": "Text Placement", "default": "center", "desc": "Where the text appears in the image.", "options": TEXT_POSITIONS},
    {"key": "text_effect", "label": "Text Effect", "default": "none", "desc": "Extra effects for the overlay text.", "options": TEXT_EFFECTS}
]

DEFAULT_INSTRUCTION_PROMPTS = [
    "Create a cinematic hero shot in bronze hues.",
    "Comic-style noir scene with expressive lighting.",
    "Dramatic sunset battle with ancient warriors.",
    "Cartoon meme in black and white.",
    "Suspenseful moment inside a dimly lit cafe.",
    "Futuristic cityscape in graphic novel style.",
    "Shocking twist in a detective story.",
    "Epic landscape inspired by Greek myth.",
    "1960s noir illustration with emotional contrast."
]

----------- APP LOGIC -----------

st.set_page_config(page_title="PromptBuilder (Power User)", layout="wide")
st.title("🖼️ Ultimate PromptBuilder & Meme Generator")

tab1, tab2 = st.tabs(["PromptBuilder", "Meme Generator"])

--- Helper for storing randomize state ---
def set_random_state(tabkey, fields, overlayfields):
    st.session_state[f"random_{tabkey}_fields"] = {f["key"]: random_from_field(f) for f in fields}
    st.session_state[f"random_{tabkey}_overlay"] = {f["key"]: random_from_field(f) for f in overlayfields}
    st.session_state[f"random_{tabkey}_instruction"] = random.choice(DEFAULT_INSTRUCTION_PROMPTS)

def get_field_value(tabkey, key, field):
    # If randomize state, use it; else, use default
    randval = st.session_state.get(f"random_{tabkey}_fields", {}).get(key)
    return randval if randval is not None else field["default"]

def get_overlay_value(tabkey, key, field):
    randval = st.session_state.get(f"random_{tabkey}_overlay", {}).get(key)
    return randval if randval is not None else field["default"]

def get_instruction(tabkey):
    return st.session_state.get(f"random_{tabkey}_instruction", DEFAULT_INSTRUCTION_PROMPTS[0])

-------- Prompt Builder TAB --------
with tab1:
    col1, col2 = st.columns([1, 2])
    with col1:
        if st.button("🔀 Randomize All Fields!", key="rand_pb"):
            set_random_state("pb", FIELD_DEFINITIONS, TEXT_OVERLAY_FIELDS)
        if st.button("Reset", key="reset_pb"):
            st.session_state["random_pb_fields"] = {}
            st.session_state["random_pb_overlay"] = {}
            st.session_state["random_pb_instruction"] = DEFAULT_INSTRUCTION_PROMPTS[0]
    with col2:
        pb_instruction = st.text_area(
            "Instruction Prompt",
            value=get_instruction("pb"),
            key="pb_instruction"
        )

    st.markdown("### Visual Prompt Fields")
    pb_field_values = {}
    for field in FIELD_DEFINITIONS:
        val = render_field(field, get_field_value("pb", field["key"], field), key=f"pb_{field['key']}")
        pb_field_values[field["key"]] = val

    st.markdown("### Text-on-Image Controls (Optional)")
    pb_overlay_values = {}
    for field in TEXT_OVERLAY_FIELDS:
        val = render_field(field, get_overlay_value("pb", field["key"], field), key=f"pb_{field['key']}")
        pb_overlay_values[field["key"]] = val
    if not pb_overlay_values.get("add_text_overlay", False):
        pb_overlay_values = {k: v for k, v in pb_overlay_values.items() if k == "add_text_overlay"}

    if st.button("Generate JSON Prompt", key="gen_pb"):
        pb_profile = {
            "instruction_prompt": pb_instruction,
            "profile_parameters": pb_field_values
        }
        if pb_overlay_values.get("add_text_overlay"):
            overlay_params = {k: v for k, v in pb_overlay_values.items() if k != "add_text_overlay"}
            pb_profile["text_overlay"] = overlay_params
        st.session_state["prompt_profile"] = pb_profile

    if "prompt_profile" in st.session_state:
        st.markdown("#### JSON Prompt Profile")
        json_str = json.dumps(st.session_state["prompt_profile"], indent=4)
        st.code(json_str, language="json")
        st.download_button("Download JSON", json_str, file_name="prompt_profile.json")
        st.text_area("Copy JSON (with preamble):", json_str, height=200)

-------- Meme Generator TAB --------
with tab2:
    col1, col2 = st.columns([1, 2])
    with col1:
        if st.button("🔀 Randomize Meme Fields!", key="rand_meme"):
            set_random_state("meme", FIELD_DEFINITIONS, TEXT_OVERLAY_FIELDS)
        if st.button("Reset Meme Fields", key="reset_meme"):
            st.session_state["random_meme_fields"] = {}
            st.session_state["random_meme_overlay"] = {}
            st.session_state["random_meme_instruction"] = DEFAULT_INSTRUCTION_PROMPTS[0]
    with col2:
        meme_instruction = st.text_area(
            "Instruction Prompt",
            value=get_instruction("meme"),
            key="meme_instruction"
        )

    st.markdown("### Meme Visual Fields")
    meme_field_values = {}
    for field in FIELD_DEFINITIONS:
        val = render_field(field, get_field_value("meme", field["key"], field), key=f"meme_{field['key']}")
        meme_field_values[field["key"]] = val

    st.markdown("### Meme Text Controls")
    meme_overlay_values = {}
    for field in TEXT_OVERLAY_FIELDS:
        val = render_field(field, get_overlay_value("meme", field["key"], field), key=f"meme_{field['key']}")
        meme_overlay_values[field["key"]] = val
    if not meme_overlay_values.get("add_text_overlay", False):
        meme_overlay_values = {k: v for k, v in meme_overlay_values.items() if k == "add_text_overlay"}

    if st.button("Generate Meme JSON Prompt", key="gen_meme"):
        meme_profile = {
            "instruction_prompt": meme_instruction,
            "profile_parameters": meme_field_values
        }
        if meme_overlay_values.get("add_text_overlay"):
            overlay_params = {k: v for k, v in meme_overlay_values.items() if k != "add_text_overlay"}
            meme_profile["text_overlay"] = overlay_params
        st.session_state["meme_profile"] = meme_profile

    if "meme_profile" in st.session_state:
        st.markdown("#### Meme JSON Prompt Profile")
        meme_json_str = json.dumps(st.session_state["meme_profile"], indent=4)
        st.code(meme_json_str, language="json")
        st.download_button("Download Meme JSON", meme_json_str, file_name="meme_profile.json")
        st.text_area("Copy Meme JSON (with preamble):", meme_json_str, height=200)

st.markdown("<hr><center>Made with ❤️ for pro users | by ChatGPT PromptBuilder</center>", unsafe_allow_html=True)

ステップ6 — アプリケーションの実行とテスト

prompt_builder.pyファイルを保存し、Streamlitアプリケーションを実行します:

streamlit run prompt_builder.py

あなたのアプリケーションはデフォルトのウェブブラウザーで http://localhost:8501 に開きます。次の機能をテストしてください:

  • フィールド選択: ドロップダウンメニューから異なるオプションを選択し、カスタム入力が正しく動作することを確認します
  • ランダム化: すべてのフィールドに無作為に値が適用されるように、ランダム化ボタンをクリックしてください。
  • タブの切り替え: 各タブがそれぞれ独立した状態を維持していることを確認してください
  • JSON生成: JSON出力を生成し、ダウンロード機能をテストする
  • テキストオーバーレイ: テキストオーバーレイを有効にして、テキストの表示オプションを設定します

アプリはこのように見えるべきです:

上のアプリのスクリーンショットに表示されているすべての設定を構成することができるか、独自のカスタム設定を追加することができます。

画像にテキストオーバーレイを追加することもできます。

JSONプロンプトプロファイルをダウンロードして、ChatGPT、Ideogram、Geminiなどのお気に入りのAI画像生成ツールで使用することもできます。

今、あなたはこのJSONプロンプトプロファイルをお気に入りのAI画像生成器にコピー&ペーストするだけで、準備完了です。こちらがChatGPTからの出力です:

ステップ7 — DigitalOcean MCPサーバーを使用してDigitalOcean App Platformにデプロイする

アプリケーションが完成し、ローカルでテストが終了したので、公開アクセスのためにDigitalOcean App Platformにデプロイできます。DigitalOcean App Platformは、アプリケーションのデプロイ、管理、スケーリングを容易にするプラットフォーム・アズ・ア・サービス(PaaS)です。

あなたのAI画像プロンプトビルダーをDigitalOcean App Platformにデプロイするには、DigitalOcean MCPサーバーを設定する必要があります。このプロセスでは、DigitalOcean APIトークンを生成し、AI画像プロンプトビルダーをそれを使用するように設定します。

ステップ1: DigitalOcean APIトークンを生成する

まず、DigitalOceanアカウントからパーソナルアクセス トークンを生成する必要があります。このトークンは、あなたのAIアシスタントをDigitalOcean App Platformで認証するために使用されます。それを行うには:

  1. DigitalOceanアカウントにログインし、API設定に移動します。
  2. 新しいトークンを生成ボタンをクリックしてください。
  3. アプリプラットフォームをトークンのスコープとして選択します。
  4. トークンに名前を付けて(例:“AIアシスタントトークン”)、トークンを生成をクリックしてください。

ステップ2:APIトークンでAIアシスタントを設定する

次に、生成されたAPIトークンを使用するためにAIアシスタントを設定する必要があります。これには、Cursorを使用してDigitalOcean MCPサーバーをセットアップすることが含まれます。

カーソルの設定

  • カーソル設定を開き、MCPに移動してください。
  • “新しいグローバルMCPサーバーを追加”をクリックしてください。
  • 設定ファイル~/.cursor/mcp.jsonに次のJSONブロックを追加します:
{
  "mcpServers": {
    "github": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-github"
      ],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "YOUR_GITHUB_PERSONAL_ACCESS_TOKEN"
      }
    },
    "everything": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-everything"]
    },
    "sequential-thinking": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-sequential-thinking"
      ]
    },
    "digitalocean": {
      "command": "npx",
      "args": ["@digitalocean/mcp"],
      "env": {
        "DIGITALOCEAN_API_TOKEN": "YOUR_DO_TOKEN"
      }
    }
  }
}

以下のJSONブロックは、カーソルツールのためのMCP(モデルコンテキストプロトコル)サーバーを設定します。

  • 「github」サーバーは、GitHubの個人アクセストークンを使用して@modelcontextprotocol/server-githubパッケージを使用するために、Github MCPサーバーを使用するように設定されています。
  • 「everything」サーバーは、@modelcontextprotocol/server-everythingパッケージを使用するためにEverything MCPサーバーを使用します。
  • 「シーケンシャル・シンキング」サーバーは、@modelcontextprotocol/server-sequential-thinking パッケージを使用するために、シーケンシャル・シンキング MCP サーバーを使用します。
  • 「digitalocean」サーバーは、DigitalOcean APIトークンを使用して@digitalocean/mcpパッケージを利用するためにDigitalOcean MCPサーバーを使用します。

MCPサーバーのステータスがすべてアクティブで、下のスクリーンショットに示されているように緑色になっていることを確認してください:

MCPサーバーのテスト

DigitalOceanのMCPサーバーをセットアップしたら、Cursorでいくつかのコマンドを実行してテストできます。サーバーが正しく動作していることを確認するために、次のプロンプトを試してみてください:

    List all active apps on my account
    Create a new flask app with 2GB RAM from this GitHub repo - https://github.com/do-community/do-one-click-deploy-flask
    Remove the old staging-env app

AI画像プロンプトビルダーアプリの展開

DigitalOceanのMCPサーバーが設定され、テストされたので、AI画像プロンプトビルダーアプリをDigitalOcean App Platformにデプロイできます。これを行うには、Cursorチャットウィンドウで以下のプロンプトを使用してください:

Please deploy this @prompt_builder.py image prompt builder app to the DigitalOcean App Platform using the digitalocean mcp server

これらのMCPサーバーを使用して、DigitalOcean App PlatformにAI画像プロンプトビルダーアプリをデプロイする手順に従ってください。

要するに、新しいGitHubリポジトリを作成し、それをDigitalOceanアプリプラットフォームにデプロイします。

次のような質問をすることができます:

デプロイされたアプリケーションへのアクセス

デプロイメントが完了すると、DigitalOceanはAI画像プロンプトビルダーアプリケーションにアクセスできる公開URLを提供します。URLは通常、次の形式になります:

https://your-app-name-random-string.ondigitalocean.app

あなたのアプリケーションは現在、世界中のユーザーにアクセス可能です!DigitalOceanアプリプラットフォームは、自動的にSSL証明書、ロードバランシング、および設定に基づくスケーリングを処理します。

デプロイメントの問題をトラブルシューティングする

デプロイ中に問題が発生した場合は、以下のことができます:

  • ビルドログを確認して、コンパイルや依存関係の問題を特定するために、Cursor上のMCPサーバー機能を使用します。ビルドログとは何ですか?やエラーとは何ですか?、デプロイメントの状態はどうですか?などの質問をすることができます。

  • requirements.txtに必要な依存関係がすべて含まれており、互換性のあるバージョンであることを確認してください
  • Streamlitの設定が0.0.0.0にバインドされ、$PORT環境変数を使用するように設定されていることを確認してください
  • アプリの仕様を確認して、設定エラーがないか確認してください

よくある質問

1. デプロイされたアプリケーションをどのように更新しますか?

GitHubリポジトリに変更をプッシュすることで、アプリケーションを更新できます。DigitalOcean App Platformはこれらの変更を自動的に検出し、アプリケーションを再展開します。

2. もし私のデプロイメントが失敗したらどうしますか?

デプロイに失敗した場合は、DigitalOceanのダッシュボードを通じてビルドログを確認するか、CursorのMCPサーバー機能を使用して確認できます。一般的な問題には、依存関係の欠如や設定エラーが含まれ、これらはrequirements.txtやアプリの仕様を更新することで解決できます。

3. DigitalOcean MCPサーバーとは何ですか?

DigitalOcean MCP(モデルコンテキストプロトコル)サーバーは、DigitalOcean App Platform上でのアプリケーションのAI支援によるデプロイおよび管理を可能にするツールです。これは、Cursor IDEを通じてDigitalOceanリソースと対話するための自然言語インターフェースを提供します。

4. DigitalOcean MCPサーバーをどのように設定しますか?

DigitalOcean MCPサーバーは、Cursor IDEのMCP設定に追加することでセットアップできます。これには、DigitalOceanのAPIトークンを~/.cursor/mcp.json設定ファイルに追加し、サーバー設定を構成することが含まれます。

5. DigitalOcean MCPサーバーで何ができますか?

DigitalOcean MCPサーバーを使用すると、Cursor IDEで自然言語コマンドを使用して、アプリケーションのデプロイ、リソースの管理、デプロイの状態の確認、ログの表示、問題のトラブルシューティングなど、さまざまな操作を実行できます。

6. MCPサーバーを使用する際、私のDigitalOcean APIトークンは安全ですか?

はい、あなたのDigitalOcean APIトークンはMCP設定ファイルにローカルに保存され、DigitalOcean APIへの認証されたリクエストにのみ使用されます。ただし、権限が制限されたトークンを使用し、定期的にローテーションすることが推奨されます。

7. MCPサーバーの問題をどのようにトラブルシューティングしますか?

MCPサーバーに問題が発生した場合は、Cursor IDEのログを確認し、APIトークンの権限を確認し、設定ファイルが正しくフォーマットされていることを確認し、MCPサーバーを再起動してみてください。また、「ステータスは何ですか?」や「ログを見せてください」といったコマンドを使用して問題を診断することもできます。

結論

あなたはStreamlitとPythonを使用して、包括的なAI画像プロンプトビルダーアプリケーションを成功裏に作成しました。このアプリケーションは、AI画像生成のための詳細なプロンプトを構築するための直感的なインターフェースを提供しており、広範なパラメーターのカスタマイズ、創造的なインスピレーションのためのランダム化、そしてJSONエクスポート機能などの特徴があります。

アプリケーションをさらに強化するために、一般的なユースケースのためのプロンプトテンプレート、AI画像生成APIとの統合、または成功したプロンプト構成を保存および共有するためのギャラリーシステムのような機能を追加することを検討してください。

次のステップ

AIの開発と展開の旅を続けるために、これらの追加チュートリアルを参照してください:

  • クラウドコーダーでDigitalOcean MCPサーバーを設定する
  • Python MCPサーバー統合
  • MCPサーバーでアプリを制御する
  • モデルコンテキストプロトコルの紹介
  • JavaScriptを使ってAIアシスタントを訓練する方法:初心者向けガイド

これらのリソースは、あなたの知識を広げ、より洗練されたAI駆動アプリケーションを構築するのに役立ちます。

関連記事: