AI 生成圖片:Stable Diffusion - Stability AI

stability platform

說明文件 & 功能介紹:

(有空再補充說明)

  • Parameters:參數說明文件

  • Text-to-Image

  • Image-to-Image

  • Inpainting + Masking

  • CLIP Guidance

  • Animation

  • Image Upscaling

  • Multi-prompting

  • Variants



資料來源:Stability AI Document

取得 API keys 的連結:DreamStudio by stability.ai


安裝

pip install stability_sdk

import

from stability_sdk import client
import stability_sdk.interfaces.gooseai.generation.generation_pb2 as generation
# 其他 import...

程式範例

已移除部分備註

answers = stability_api.generate(
    prompt="Oil painting ...",
    seed=992446758,
    steps=50,  # Defaults to 30
    cfg_scale=8.0,  # Defaults to 7.0
    width=1024  # Defaults to 512 or 1024 depending on the engine
    height=1024,  # Defaults to 512 or 1024 depending on the engine
    samples=1,  # Defaults to 1
    sampler=generation.SAMPLER_K_DPMPP_2M  # Defaults to k_dpmpp_2m
)

for resp in answers:
    for artifact in resp.artifacts:
        if artifact.finish_reason == generation.FILTER:
            warnings.warn(
                "Your request activated the API's safety filters and could not be processed."
                "Please modify the prompt and try again.")
        if artifact.type == generation.ARTIFACT_IMAGE:
            img = Image.open(io.BytesIO(artifact.binary))
            img.save(str(artifact.seed)+ ".png") 

文字冒險遊戲

CYOA:Create Your Own Adventure Game

老師用 Flask 架站,而非 Node.js。

system_directive = """
You, 'assistant', are telling me, 'user', an interactive choose-your-own-adventure story. 
...
""".strip()

def get_caption_from_chat_response(chat_response_object: Mapping) -> str:
    """
    :raises: AttributeError if no caption is found
    """
    return re.search(r"Caption:(.*)(?:\n|$)", chat_response_object["content"]).group(1).strip()


def is_valid_cyoa(chat_response_object) -> bool:
    try:
        get_caption_from_chat_response(chat_response_object)
    except AttributeError:
        return False
    return (
        bool(re.search(r"Story:(.*)(?:\n|$)", chat_response_object["content"]))
        and bool(re.search(r"Choice1:(.*)(?:\n|$)", chat_response_object["content"]))
        and bool(re.search(r"Choice2:(.*)(?:\n|$)", chat_response_object["content"]))
    )

@retry(
    stop=stop_after_attempt(3),
    retry=retry_if_not_result(is_valid_cyoa) | retry_if_exception_type(
        APIConnectionError) | retry_if_exception_type(APIError) | retry_if_exception_type(RateLimitError),
)
def generate_cyoa_next_message(messages) -> Mapping:
    messages_payload = [{"role": "system", "content": system_directive}]

    # Filter out our image_url we sneak into their API call
    messages_payload.extend([{k: v for k, v in message.items(
    ) if k != "cyoa_image_base64"} for message in messages])

    print("************************************")
    print("************************************")
    print("************************************")
    print(messages_payload)

    # The ChatCompletion API has the gpt-3.5-turbo model available to it. As of Q1 2023, it's 1/10th the cost of text-davinci-003 at $0.002/1K tokens.
    chat_response = openai.ChatCompletion.create(
        model="gpt-4",
        messages=messages_payload,
        frequency_penalty=1.0,
        temperature=0.8,
    )
    log.info(f"Chat generated in {chat_response.response_ms} milliseconds")
    log.debug(f"Chat Response: {chat_response}")

    return chat_response.choices[0].message.to_dict()
def generate_image_base64_dalle(image_caption, dimensions=(512, 512)):
    try:
        image_response = openai.Image.create(
            prompt=(image_caption[:1000]),
            n=1,
            size=f"{dimensions[0]}x{dimensions[1]}",
            response_format="b64_json",
        )
        log.debug(f"Image Response: {image_response}")
        base64_image = image_response["data"][0]["b64_json"]
    except openai.InvalidRequestError as e:
        log.warn(
            f"Skipping image generation. Image prompt was rejected by OpenAI: {e.args}")
        return None
    except (APIConnectionError, APIError, RateLimitError, ServiceUnavailableError) as e:
        # We don't retry these because the story is more important than the images. Don't slow the story down
        # if we simply miss a single image.
        log.warn(f"Temporary API error. Skipping image generation: {e.args}")
        return None
    else:
        return base64_image
def generate_image_base64_stability(image_caption, dimensions=(512, 512)):
    STABILITY_ENGINE_ID = "stable-diffusion-512-v2-1"  # "stable-diffusion-v1-5"
    # The latter arg is a default
    STABILITY_API_HOST = os.getenv("API_HOST", "https://api.stability.ai")
    STABILITY_API_KEY = os.environ["STABILITY_API_KEY"]

    print(f"Generating image with caption: {image_caption[:1000]}")

    response = requests.post(
        f"{STABILITY_API_HOST}/v1/generation/{STABILITY_ENGINE_ID}/text-to-image",
        headers={"Content-Type": "application/json", "Accept": "application/json",
                 "Authorization": f"Bearer {STABILITY_API_KEY}"},
        json={
            "text_prompts": [{"text": image_caption[:1000]}],
            "cfg_scale": 7,
            "clip_guidance_preset": "FAST_BLUE",
            "height": dimensions[1],
            "width": dimensions[1],
            "samples": 1,
            "steps": 50,
        },
    )
    if response.status_code != 200:
        log.warn(
            f"Skipping image generation. Stability response was {response.status_code}: {response.text}")
        return None
    else:
        data = response.json()
        return data["artifacts"][0]["base64"]
@app.route("/cyoa", methods=["POST"])
def cyoa():
    request_json = request.get_json()

    assert "messages" in request_json
    if len(request_json["messages"]) != 0:
        assert request_json["messages"][0]["role"] == "user"
        assert request_json["messages"][-1]["role"] == "user"

    # Note: In a production context, you should validate this input.
    messages = request_json["messages"].copy()

    chat_response_object = generate_cyoa_next_message(messages)

    messages.append(chat_response_object)

    t_image = time.time()

    try:
        image_caption = get_caption_from_chat_response(chat_response_object)
    except AttributeError:
        log.warn("Skipping image generation. GPT response did not have a caption.")
        return {"messages": messages}

    # Continue on to generate an image and affix it to the last message

    # image_base64 = generate_image_base64_dalle(image_caption)
    image_base64 = generate_image_base64_stability(
        "A first person view in the style of detailed fantasy art: " + image_caption)

    if image_base64:
        # ...
        # Optionally, store the image locally
        # ...
        messages[-1]["cyoa_image_base64"] = image_base64
        log.info(
            f"Image generated and saved in {time.time() - t_image} seconds")

    return {"messages": messages}