Skip to content

Commit

Permalink
move dream to its own module, increase variety of prompts
Browse files Browse the repository at this point in the history
  • Loading branch information
aayars committed Aug 13, 2023
1 parent adc1bec commit 0b113b9
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 83 deletions.
63 changes: 10 additions & 53 deletions noisemaker/ai.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import base64
import os
import random
import time

import noisemaker.util as util

Expand All @@ -32,22 +31,13 @@
# Adapted from stability.ai API usage example
# https://platform.stability.ai/rest-api#tag/v1generation/operation/imageToImage
def apply(settings, seed, input_filename, stability_model):
api_key = None
api_key_path = util.get_noisemaker_dir() + "/.creds/.stability"
if os.path.exists(api_key_path):
with open(api_key_path, 'r') as fh:
api_key = fh.read().strip()

if api_key is None:
raise Exception(f"Missing Stability API key at {api_key_path}.")

model = stability_model if stability_model else settings['model']

response = requests.post(
f"{STABILITY_API_HOST}/v1/generation/{model}/image-to-image",
headers={
"Accept": "application/json",
"Authorization": f"Bearer {api_key}"
"Authorization": f"Bearer {_api_key('stability')}"
},
files={
"init_image": open(input_filename, "rb")
Expand Down Expand Up @@ -76,23 +66,11 @@ def apply(settings, seed, input_filename, stability_model):


def x2_upscale(input_filename):
api_key = None
api_key_path = util.get_noisemaker_dir() + "/.creds/.stability"
if os.path.exists(api_key_path):
with open(api_key_path, 'r') as fh:
api_key = fh.read().strip()

if api_key is None:
raise Exception(f"Missing Stability API key at {api_key_path}.")

if not input_filename.endswith(".png"):
raise Exception("Only PNG images are supported for upscale.")

response = requests.post(
f"{STABILITY_API_HOST}/v1/generation/esrgan-v1-x2plus/image-to-image/upscale",
headers={
"Accept": "image/png",
"Authorization": f"Bearer {api_key}"
"Authorization": f"Bearer {_api_key('stability')}"
},
files={
"image": open(input_filename, "rb")
Expand All @@ -108,16 +86,7 @@ def x2_upscale(input_filename):


def describe(preset_name, prompt, filename):
api_key = None
api_key_path = util.get_noisemaker_dir() + "/.creds/.openai"
if os.path.exists(api_key_path):
with open(api_key_path, 'r') as fh:
api_key = fh.read().strip()

try:
if api_key is None:
raise Exception(f"Missing OpenAI API key at {api_key_path}.")

#
#
#
Expand Down Expand Up @@ -147,7 +116,7 @@ def describe(preset_name, prompt, filename):
f"to see the image. The name of the composition is \"{preset_name}\", " \
f"and the list of terms is: \"{prompt}\""

summary = _openai_query(api_key, system_prompt, user_prompt)
summary = _openai_query(system_prompt, user_prompt)

#
#
Expand All @@ -164,7 +133,7 @@ def describe(preset_name, prompt, filename):
"grammar and tone of the summary, and make sure it doesn't sound too " \
"pretentious or repetitive."

summary = _openai_query(api_key, system_prompt, summary)
summary = _openai_query(system_prompt, summary)

except Exception:
summary = f"\"{preset_name}\" is an abstract generative art composition. " \
Expand All @@ -173,36 +142,24 @@ def describe(preset_name, prompt, filename):
return summary


def dream():
def _api_key(api):
api_key = None
api_key_path = util.get_noisemaker_dir() + "/.creds/.openai"
api_key_path = f"{util.get_noisemaker_dir()}/.creds/.{api}"
if os.path.exists(api_key_path):
with open(api_key_path, 'r') as fh:
api_key = fh.read().strip()

if api_key is None:
raise Exception(f"Missing OpenAI API key at {api_key_path}.")

for _ in range(5):
system_prompt = f"Imagine a system that generates images from a text prompt, and come up with a prompt from the deepest reaches of your synthetic imagination. This is intended to be machine-readable, so do not litter the answers with labels like \"Name\" or \"Description\" or \"the name is\" or \"the description is\" or \"the name and description are as follows\". The description may not exceed 250 characters."

user_prompt = "What is the name and description of the composition? Provide the name and description in semicolon-delimited format."

generated_prompt = _openai_query(api_key, system_prompt, user_prompt)

if not any(string in generated_prompt.lower() for string in ['"', 'name', 'description']):
break

time.sleep(1)
raise Exception(f"Missing {api} API key at {api_key_path}.")

return [a.strip() for a in generated_prompt.split(';')]
return api_key


def _openai_query(api_key, system_prompt, user_prompt):
def _openai_query(system_prompt, user_prompt):
response = requests.post(
f"{OPENAI_API_HOST}/v1/chat/completions",
headers={
"Authorization": f"Bearer {api_key}",
"Authorization": f"Bearer {_api_key('openai')}",
"Content-Type": "application/json",
},
json={
Expand Down
95 changes: 95 additions & 0 deletions noisemaker/dreamer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
"""Dynamic prompt and image generator"""

import random
import tempfile
import time

from noisemaker.constants import ColorSpace

import noisemaker.ai as ai
import noisemaker.composer as composer
import noisemaker.generators as generators
import noisemaker.util as util


_ADJECTIVES = [
"abstract",
"art deco",
"art noveau",
"artistic",
"conceptual",
"contemporary",
"cubist",
"expressionist",
"fantasy",
"fauvist",
"futuristic",
"impossible",
"impressionist",
"macro",
"magical",
"minimalist",
"modern",
"peaceful",
"photographic",
"post-impressionist",
"psychedelic",
"realistic",
"restful",
"retro",
"rustic",
"sci-fi",
"soothing",
"still life",
"surrealist",
"visionary",
"vintage",
"whimsical",
]

def dream(width, height, seed, filename):
adjective = composer.random_member(_ADJECTIVES)

for _ in range(5):
system_prompt = f"Imagine a system that generates images from a text prompt, and come up with a prompt for an image in a {adjective} style. Your answer is intended to be machine-readable, so do not litter the answers with labels like \"Name\" or \"Description\" or \"the name is\" or \"the description is\" or \"the name and description are as follows\". The description may not exceed 250 characters."

user_prompt = "What is the name and description of the composition? Provide the name and description in semicolon-delimited format."

generated_prompt = ai._openai_query(system_prompt, user_prompt)

# Brute force it when GPT doesn't follow directions
if len(generated_prompt.split(';')) == 2 and not any(string in generated_prompt.lower() for string in ['"', 'name', 'description']):
break

time.sleep(1)

name, prompt = [a.strip() for a in generated_prompt.split(';')]

if seed is None:
seed = random.randint(1, 2 ** 32 - 1)

shape = [height, width, 3]

tensor = generators.basic(seed=seed, freq=[height, width], shape=shape, color_space=composer.random_member(ColorSpace),
hue_range=0.125 + random.random() * 1.5)

settings = {
"image_strength": 0.125,
"cfg_scale": 20,
"prompt": prompt,
"style_preset": "photographic",
"model": "stable-diffusion-xl-1024-v1-0",
}

with tempfile.TemporaryDirectory() as tmp:
tmp_filename = f"{tmp}/noise.png"

util.save(tensor, tmp_filename)

tensor = ai.apply(settings, seed, tmp_filename, None)

description = ai.describe(name, prompt, tmp_filename)

composer.EFFECT_PRESETS["lens"].render(seed=seed, tensor=tensor, shape=shape, filename=filename)

return name, prompt, description
33 changes: 3 additions & 30 deletions noisemaker/scripts/noisemaker.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@
import click
import tensorflow as tf

from noisemaker.composer import EFFECT_PRESETS, GENERATOR_PRESETS, random_member, reload_presets
from noisemaker.composer import EFFECT_PRESETS, GENERATOR_PRESETS, reload_presets
from noisemaker.constants import ColorSpace, ValueDistribution
from noisemaker.presets import PRESETS

import noisemaker.ai as ai
import noisemaker.dreamer as dreamer
import noisemaker.cli as cli
import noisemaker.generators as generators
import noisemaker.effects as effects
Expand Down Expand Up @@ -397,36 +398,8 @@ def _use_reasonable_speed(preset, frame_count):
@cli.seed_option()
@cli.filename_option(default='dream.png')
def dream(width, height, seed, filename):
if seed is None:
seed = random.randint(1, MAX_SEED_VALUE)

name, prompt = ai.dream()

shape = [height, width, 3]

color_space = random_member([ColorSpace.hsv, ColorSpace.rgb, ColorSpace.oklab])

tensor = generators.basic(freq=[height, width], shape=shape, color_space=color_space, hue_range=0.5 + random.random())

settings = {
"image_strength": 0.05,
"cfg_scale": 35,
"prompt": prompt,
"style_preset": "photographic",
"model": "stable-diffusion-xl-1024-v1-0",
}

with tempfile.TemporaryDirectory() as tmp:
tmp_filename = f"{tmp}/noise.png"

util.save(tensor, tmp_filename)

tensor = ai.apply(settings, seed, tmp_filename, None)
description = ai.describe(name, prompt, tmp_filename)
name, prompt, description = dreamer.dream(width, height, seed, filename)

print(name)
print(prompt)
print(description)

preset = EFFECT_PRESETS["lens"]
tensor = preset.render(seed=seed, tensor=tensor, shape=shape, filename=filename)

0 comments on commit 0b113b9

Please sign in to comment.