hatmanstack commited on
Commit
1963e4b
1 Parent(s): 76f94b4

Fixed tabs

Browse files
Files changed (3) hide show
  1. README.md +27 -21
  2. app.py +387 -61
  3. requirements.txt +1 -2
README.md CHANGED
@@ -1,3 +1,4 @@
 
1
  title: AWS Nova Canvas
2
  emoji: 🖼️
3
  colorFrom: blue
@@ -6,35 +7,40 @@ sdk: gradio
6
  sdk_version: 5.6.0
7
  app_file: app.py
8
  pinned: false
9
- license: apache2.0
10
  short_description: Generate image variations
 
11
 
12
 
13
- # Amazon Nova Canvas Image Generation
14
 
15
- This Gradio application demonstrates various image generation capabilities using the Amazon Nova Canvas model. The application provides multiple functionalities, each accessible through its own tab, allowing users to generate and manipulate images based on text prompts and other inputs.
16
 
17
- ## Features
18
 
19
- - **Text to Image**: Generate an image from a text prompt using the Amazon Nova Canvas model.
20
- - **Inpainting**: Modify specific areas of an image based on a text prompt.
21
- - **Outpainting**: Extend an image beyond its original borders using a mask and text prompt.
22
- - **Image Variation**: Create variations of an image based on a text description.
23
- - **Image Conditioning**: Generate an image conditioned on an input image and a text prompt.
24
- - **Color Guided Content**: Generate an image using a color palette from a reference image and a text prompt.
25
- - **Background Removal**: Remove the background from an image.
26
 
27
- ## Usage
28
 
29
- 1. **Text to Image**: Enter a descriptive text prompt and click "Generate" to create an image.
30
- 2. **Inpainting**: Upload an image, provide a mask prompt, and click "Generate" to modify specific areas.
31
- 3. **Outpainting**: Upload an image and a mask image, provide a text prompt, and click "Generate" to extend the image.
32
- 4. **Image Variation**: Upload an image, provide a text description, and click "Generate" to create variations.
33
- 5. **Image Conditioning**: Upload an image, provide a text prompt, and click "Generate" to condition the image.
34
- 6. **Color Guided Content**: Upload an image, provide a text prompt and color palette, and click "Generate" to guide content generation.
35
- 7. **Background Removal**: Upload an image and click "Generate" to remove the background.
36
 
37
- ## Excellent Documentation
38
 
39
- <p>For more information, visit <a href="https://docs.aws.amazon.com/nova/latest/userguide/what-is-nova.html">AWS Nova documentation</a>.</p>
 
 
 
 
 
40
 
 
 
 
 
1
+ ---
2
  title: AWS Nova Canvas
3
  emoji: 🖼️
4
  colorFrom: blue
 
7
  sdk_version: 5.6.0
8
  app_file: app.py
9
  pinned: false
10
+ license: apache-2.0
11
  short_description: Generate image variations
12
+ ---
13
 
14
 
15
+ # AWS Nova Canvas Image Generation
16
 
17
+ A Gradio application for advanced image generation using Amazon Nova Canvas, offering comprehensive image manipulation capabilities.
18
 
19
+ ## Capabilities
20
 
21
+ - **Text to Image**: Generate images from text prompts
22
+ - **Inpainting**: Modify specific image areas
23
+ - **Outpainting**: Extend image boundaries
24
+ - **Image Variation**: Create image variations
25
+ - **Image Conditioning**: Generate images based on input image and text
26
+ - **Color Guided Content**: Create images using reference color palettes
27
+ - **Background Removal**: Remove image backgrounds
28
 
29
+ ## Prerequisites
30
 
31
+ - AWS credentials configured
32
+ - Boto3 Python library
33
+ - Gradio 5.6.0
 
 
 
 
34
 
35
+ ## Technical Details
36
 
37
+ - Model: Amazon Nova Canvas (amazon.nova-canvas-v1:0)
38
+ - Image Generation Parameters:
39
+ - Default resolution: 1024x1024
40
+ - Quality: Standard
41
+ - CFG Scale: 8.0
42
+ - Configurable seed
43
 
44
+ ## Documentation
45
+
46
+ For detailed usage, visit [AWS Nova documentation](https://docs.aws.amazon.com/nova/latest/userguide/what-is-nova.html).
app.py CHANGED
@@ -4,7 +4,10 @@ import json
4
  import logging
5
  import boto3
6
  from PIL import Image
 
 
7
  import gradio as gr
 
8
 
9
  # Set up logging
10
  logger = logging.getLogger(__name__)
@@ -16,27 +19,96 @@ class ImageError(Exception):
16
  self.message = message
17
 
18
  model_id = 'amazon.nova-canvas-v1:0'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  # Function to generate an image using Amazon Nova Canvas model
20
  def generate_image(body):
21
  logger.info("Generating image with Amazon Nova Canvas model %s", model_id)
22
- session = boto3.Session(aws_access_key_id=aws_id, aws_secret_access_key=aws_secret, region_name='us-east-1')
23
- bedrock = session.client('bedrock-runtime')
24
- accept = "application/json"
25
- content_type = "application/json"
26
 
27
- response = bedrock.invoke_model(body=body, modelId=model_id, accept=accept, contentType=content_type)
28
- response_body = json.loads(response.get("body").read())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
 
30
- base64_image = response_body.get("images")[0]
31
- base64_bytes = base64_image.encode('ascii')
32
- image_bytes = base64.b64decode(base64_bytes)
33
 
34
- finish_reason = response_body.get("error")
35
- if finish_reason is not None:
36
- raise ImageError(f"Image generation error. Error is {finish_reason}")
37
 
38
- logger.info("Successfully generated image with Amazon Nova Canvas model %s", model_id)
39
- return image_bytes
 
 
 
 
 
40
 
41
  # Function to display image from bytes
42
  def display_image(image_bytes):
@@ -44,68 +116,229 @@ def display_image(image_bytes):
44
  return image
45
 
46
  # Gradio functions for each task
47
- def text_to_image(prompt):
 
 
 
 
 
 
 
 
 
48
  body = json.dumps({
49
  "taskType": "TEXT_IMAGE",
50
- "textToImageParams": {"text": prompt},
51
- "imageGenerationConfig": {"numberOfImages": 1, "height": 1024, "width": 1024, "cfgScale": 8.0, "seed": 0}
 
 
 
 
 
 
 
52
  })
53
  image_bytes = generate_image(body)
54
  return display_image(image_bytes)
55
 
56
- def inpainting(image, mask_prompt):
57
- input_image = base64.b64encode(image.read()).decode('utf8')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
  body = json.dumps({
59
  "taskType": "INPAINTING",
60
- "inPaintingParams": {"text": mask_prompt, "image": input_image, "maskPrompt": "windows"},
61
- "imageGenerationConfig": {"numberOfImages": 1, "height": 512, "width": 512, "cfgScale": 8.0}
 
 
 
 
 
 
 
62
  })
63
  image_bytes = generate_image(body)
64
  return display_image(image_bytes)
65
 
66
- def outpainting(image, mask_image, text):
67
- input_image = base64.b64encode(image.read()).decode('utf8')
68
- input_mask_image = base64.b64encode(mask_image.read()).decode('utf8')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
  body = json.dumps({
70
  "taskType": "OUTPAINTING",
71
- "outPaintingParams": {"text": text, "image": input_image, "maskImage": input_mask_image, "outPaintingMode": "DEFAULT"},
72
- "imageGenerationConfig": {"numberOfImages": 1, "height": 512, "width": 512, "cfgScale": 8.0}
 
 
 
 
 
 
 
73
  })
74
  image_bytes = generate_image(body)
75
  return display_image(image_bytes)
76
 
77
- def image_variation(image, text):
78
- input_image = base64.b64encode(image.read()).decode('utf8')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  body = json.dumps({
80
  "taskType": "IMAGE_VARIATION",
81
- "imageVariationParams": {"text": text, "images": [input_image], "similarityStrength": 0.7},
82
- "imageGenerationConfig": {"numberOfImages": 1, "height": 512, "width": 512, "cfgScale": 8.0}
 
 
 
 
 
 
 
83
  })
84
  image_bytes = generate_image(body)
85
  return display_image(image_bytes)
86
 
87
- def image_conditioning(image, text):
88
- input_image = base64.b64encode(image.read()).decode('utf8')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
  body = json.dumps({
90
  "taskType": "TEXT_IMAGE",
91
- "textToImageParams": {"text": text, "conditionImage": input_image, "controlMode": "CANNY_EDGE"},
92
- "imageGenerationConfig": {"numberOfImages": 1, "height": 512, "width": 512, "cfgScale": 8.0}
 
 
 
 
 
 
 
93
  })
94
  image_bytes = generate_image(body)
95
  return display_image(image_bytes)
96
 
97
- def color_guided_content(image, text, colors):
98
- input_image = base64.b64encode(image.read()).decode('utf8')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99
  body = json.dumps({
100
  "taskType": "COLOR_GUIDED_GENERATION",
101
- "colorGuidedGenerationParams": {"text": text, "referenceImage": input_image, "colors": colors},
102
- "imageGenerationConfig": {"numberOfImages": 1, "height": 512, "width": 512, "cfgScale": 8.0}
 
 
 
 
 
 
 
103
  })
104
  image_bytes = generate_image(body)
105
  return display_image(image_bytes)
106
 
107
  def background_removal(image):
108
- input_image = base64.b64encode(image.read()).decode('utf8')
109
  body = json.dumps({
110
  "taskType": "BACKGROUND_REMOVAL",
111
  "backgroundRemovalParams": {"image": input_image}
@@ -115,60 +348,153 @@ def background_removal(image):
115
 
116
  # Gradio Interface
117
  with gr.Blocks() as demo:
 
 
 
 
 
 
 
 
118
  gr.Markdown("# Amazon Nova Canvas Image Generation")
119
 
120
  with gr.Tab("Text to Image"):
121
  with gr.Column():
122
  gr.Markdown("Generate an image from a text prompt using the Amazon Nova Canvas model.")
123
- prompt = gr.Textbox(label="Prompt")
124
  output = gr.Image()
125
- gr.Button("Generate").click(text_to_image, inputs=prompt, outputs=output)
 
 
 
 
 
 
 
 
126
 
127
  with gr.Tab("Inpainting"):
128
  with gr.Column():
129
- gr.Markdown("Use inpainting to modify specific areas of an image based on a text prompt.")
 
 
 
 
 
130
  image = gr.Image(type='pil', label="Input Image")
131
- mask_prompt = gr.Textbox(label="Mask Prompt")
 
 
 
132
  output = gr.Image()
133
- gr.Button("Generate").click(inpainting, inputs=[image, mask_prompt], outputs=output)
 
 
 
 
 
 
 
 
134
 
135
  with gr.Tab("Outpainting"):
136
  with gr.Column():
137
  gr.Markdown("Extend an image beyond its original borders using a mask and text prompt.")
 
 
 
 
 
 
 
138
  image = gr.Image(type='pil', label="Input Image")
139
- mask_image = gr.Image(type='pil', label="Mask Image")
140
- text = gr.Textbox(label="Text")
 
 
141
  output = gr.Image()
142
- gr.Button("Generate").click(outpainting, inputs=[image, mask_image, text], outputs=output)
 
 
 
 
 
 
 
 
 
143
 
144
  with gr.Tab("Image Variation"):
145
  with gr.Column():
146
- gr.Markdown("Create variations of an image based on a text description.")
147
- image = gr.Image(type='pil', label="Input Image")
148
- text = gr.Textbox(label="Text")
 
 
 
 
149
  output = gr.Image()
150
- gr.Button("Generate").click(image_variation, inputs=[image, text], outputs=output)
 
 
 
 
 
 
 
 
 
151
 
152
  with gr.Tab("Image Conditioning"):
153
  with gr.Column():
154
- gr.Markdown("Generate an image conditioned on an input image and a text prompt.")
155
- image = gr.Image(type='pil', label="Input Image")
156
- text = gr.Textbox(label="Text")
 
 
 
 
157
  output = gr.Image()
158
- gr.Button("Generate").click(image_conditioning, inputs=[image, text], outputs=output)
 
 
 
 
 
 
 
 
 
 
159
 
160
  with gr.Tab("Color Guided Content"):
161
  with gr.Column():
162
- gr.Markdown("Generate an image using a color palette from a reference image and a text prompt.")
163
- image = gr.Image(type='pil', label="Input Image")
164
- text = gr.Textbox(label="Text")
165
- colors = gr.Textbox(label="Colors (comma-separated hex values)")
 
 
 
 
166
  output = gr.Image()
167
- gr.Button("Generate").click(color_guided_content, inputs=[image, text, colors], outputs=output)
 
 
 
 
 
 
 
 
168
 
169
  with gr.Tab("Background Removal"):
170
  with gr.Column():
171
- gr.Markdown("Remove the background from an image.")
 
 
 
 
172
  image = gr.Image(type='pil', label="Input Image")
173
  output = gr.Image()
174
  gr.Button("Generate").click(background_removal, inputs=image, outputs=output)
 
4
  import logging
5
  import boto3
6
  from PIL import Image
7
+ from botocore.config import Config
8
+ from botocore.exceptions import ClientError
9
  import gradio as gr
10
+ import os
11
 
12
  # Set up logging
13
  logger = logging.getLogger(__name__)
 
19
  self.message = message
20
 
21
  model_id = 'amazon.nova-canvas-v1:0'
22
+ aws_id = os.getenv('AWS_ID')
23
+ aws_secret = os.getenv('AWS_SECRET')
24
+
25
+ def process_and_encode_image(image, min_size=320, max_size=4096, max_pixels=4194304):
26
+ if image is None:
27
+ raise ValueError("Input image is required.")
28
+ if not isinstance(image, Image.Image):
29
+ image = Image.open(image)
30
+
31
+ # Convert to RGB mode if necessary
32
+ if image.mode not in ('RGB', 'RGBA'):
33
+ image = image.convert('RGB')
34
+ elif image.mode == 'RGBA':
35
+ # Convert RGBA to RGB by compositing on white background
36
+ background = Image.new('RGB', image.size, (255, 255, 255))
37
+ background.paste(image, mask=image.split()[3]) # Use alpha channel as mask
38
+ image = background
39
+
40
+ # Ensure 8-bit color depth
41
+ if image.mode == 'RGB' and isinstance(image.getpixel((0,0)), tuple) and len(image.getpixel((0,0))) == 3:
42
+ if not all(0 <= x <= 255 for x in image.getpixel((0,0))):
43
+ image = image.convert('RGB')
44
+
45
+ current_pixels = image.width * image.height
46
+ # If image exceeds max pixels, scale it down while maintaining aspect ratio
47
+ if current_pixels > max_pixels:
48
+ aspect_ratio = image.width / image.height
49
+ if aspect_ratio > 1: # Width > Height
50
+ new_width = int((max_pixels * aspect_ratio) ** 0.5)
51
+ new_height = int(new_width / aspect_ratio)
52
+ else: # Height >= Width
53
+ new_height = int((max_pixels / aspect_ratio) ** 0.5)
54
+ new_width = int(new_height * aspect_ratio)
55
+
56
+ image = image.resize((new_width, new_height), Image.LANCZOS)
57
+
58
+ # Ensure dimensions are within valid range
59
+ if image.width < min_size or image.width > max_size or image.height < min_size or image.height > max_size:
60
+ new_width = min(max(image.width, min_size), max_size)
61
+ new_height = min(max(image.height, min_size), max_size)
62
+ image = image.resize((new_width, new_height), Image.LANCZOS)
63
+
64
+ # Convert to bytes and encode to base64
65
+ image_bytes = io.BytesIO()
66
+ # Save as PNG with maximum compatibility
67
+ image.save(image_bytes, format='PNG', optimize=True)
68
+ encoded_image = base64.b64encode(image_bytes.getvalue()).decode('utf8')
69
+
70
+ return encoded_image
71
+
72
  # Function to generate an image using Amazon Nova Canvas model
73
  def generate_image(body):
74
  logger.info("Generating image with Amazon Nova Canvas model %s", model_id)
 
 
 
 
75
 
76
+ # Configure the client with a longer timeout
77
+ bedrock = boto3.client(
78
+ service_name='bedrock-runtime',
79
+ aws_access_key_id=aws_id,
80
+ aws_secret_access_key=aws_secret,
81
+ region_name='us-east-1',
82
+ config=Config(read_timeout=300) # Add 5-minute timeout
83
+ )
84
+
85
+ print(body)
86
+
87
+ try:
88
+ response = bedrock.invoke_model(
89
+ body=body,
90
+ modelId=model_id,
91
+ accept="application/json",
92
+ contentType="application/json"
93
+ )
94
+
95
+ response_body = json.loads(response.get("body").read())
96
 
97
+ # Check for error before processing the image
98
+ if "error" in response_body:
99
+ raise ImageError(f"Image generation error. Error is {response_body['error']}")
100
 
101
+ base64_image = response_body.get("images")[0]
102
+ base64_bytes = base64_image.encode('ascii')
103
+ image_bytes = base64.b64decode(base64_bytes)
104
 
105
+ logger.info("Successfully generated image with Amazon Nova Canvas model %s", model_id)
106
+ return image_bytes
107
+
108
+ except ClientError as err:
109
+ message = err.response["Error"]["Message"]
110
+ logger.error("A client error occurred: %s", message)
111
+ raise ImageError(f"Client error during image generation: {message}")
112
 
113
  # Function to display image from bytes
114
  def display_image(image_bytes):
 
116
  return image
117
 
118
  # Gradio functions for each task
119
+ def text_to_image(prompt, negative_text=None, height=1024, width=1024, quality="standard", cfg_scale=8.0, seed=0):
120
+ # Prepare the textToImageParams dictionary
121
+ text_to_image_params = {
122
+ "text": prompt
123
+ }
124
+
125
+ # Conditionally add negativeText if it is not None and not empty
126
+ if negative_text:
127
+ text_to_image_params["negativeText"] = negative_text
128
+
129
  body = json.dumps({
130
  "taskType": "TEXT_IMAGE",
131
+ "textToImageParams": text_to_image_params,
132
+ "imageGenerationConfig": {
133
+ "numberOfImages": 1,
134
+ "height": height,
135
+ "width": width,
136
+ "quality": quality,
137
+ "cfgScale": cfg_scale,
138
+ "seed": seed
139
+ }
140
  })
141
  image_bytes = generate_image(body)
142
  return display_image(image_bytes)
143
 
144
+ def inpainting(image, mask_prompt=None, mask_image=None, text=None, negative_text=None, height=1024, width=1024, quality="standard", cfg_scale=8.0, seed=0):
145
+ if image is not None:
146
+ input_image = process_and_encode_image(image)
147
+ else:
148
+ raise ValueError("Input image is required.")
149
+
150
+ if mask_image is not None:
151
+ mask_image_encoded = process_and_encode_image(image)
152
+ else:
153
+ mask_image_encoded = None
154
+
155
+ if not mask_prompt and not mask_image:
156
+ raise ValueError("You must specify either maskPrompt or maskImage.")
157
+
158
+ # Prepare the inPaintingParams dictionary
159
+ if mask_prompt and mask_image_encoded:
160
+ raise ValueError("You must specify either maskPrompt or maskImage, but not both.")
161
+ if not mask_prompt and not mask_image_encoded:
162
+ raise ValueError("You must specify either maskPrompt or maskImage.")
163
+
164
+ # Prepare the inPaintingParams dictionary with the appropriate mask parameter
165
+ in_painting_params = {
166
+ "image": input_image
167
+ }
168
+
169
+ if mask_prompt:
170
+ in_painting_params["maskPrompt"] = mask_prompt
171
+ elif mask_image_encoded:
172
+ in_painting_params["maskImage"] = mask_image_encoded
173
+ if text:
174
+ in_painting_params["text"] = text
175
+ if negative_text:
176
+ in_painting_params["negativeText"] = negative_text
177
+
178
  body = json.dumps({
179
  "taskType": "INPAINTING",
180
+ "inPaintingParams": in_painting_params,
181
+ "imageGenerationConfig": {
182
+ "numberOfImages": 1,
183
+ "height": height,
184
+ "width": width,
185
+ "quality": quality,
186
+ "cfgScale": cfg_scale,
187
+ "seed": seed
188
+ }
189
  })
190
  image_bytes = generate_image(body)
191
  return display_image(image_bytes)
192
 
193
+ def outpainting(image, mask_prompt=None, mask_image=None, text=None, negative_text=None, outpainting_mode="DEFAULT", height=1024, width=1024, quality="standard", cfg_scale=8.0, seed=0):
194
+ if image is not None:
195
+ input_image = process_and_encode_image(image)
196
+ else:
197
+ raise ValueError("Input image is required.")
198
+
199
+ if mask_image is not None:
200
+ mask_bytes = io.BytesIO()
201
+ mask_image.save(mask_bytes, format='PNG')
202
+ mask_image_encoded = base64.b64encode(mask_bytes.getvalue()).decode('utf8')
203
+ else:
204
+ mask_image_encoded = None
205
+
206
+ if not mask_prompt and not mask_image:
207
+ raise ValueError("You must specify either maskPrompt or maskImage.")
208
+
209
+ # Prepare the outPaintingParams dictionary
210
+ out_painting_params = {
211
+ "image": input_image,
212
+ "outPaintingMode": outpainting_mode,
213
+ "maskPrompt": mask_prompt or "" # Ensure maskPrompt is always included
214
+ }
215
+
216
+ # Conditionally add parameters if they are not None
217
+ if mask_image_encoded:
218
+ out_painting_params["maskImage"] = mask_image_encoded
219
+ if text:
220
+ out_painting_params["text"] = text
221
+ if negative_text:
222
+ out_painting_params["negativeText"] = negative_text
223
+
224
  body = json.dumps({
225
  "taskType": "OUTPAINTING",
226
+ "outPaintingParams": out_painting_params,
227
+ "imageGenerationConfig": {
228
+ "numberOfImages": 1,
229
+ "height": height,
230
+ "width": width,
231
+ "quality": quality,
232
+ "cfgScale": cfg_scale,
233
+ "seed": seed
234
+ }
235
  })
236
  image_bytes = generate_image(body)
237
  return display_image(image_bytes)
238
 
239
+ def image_variation(images, text=None, negative_text=None, similarity_strength=0.5, height=1024, width=1024, quality="standard", cfg_scale=8.0, seed=0):
240
+ encoded_images = []
241
+ for image_path in images:
242
+ with open(image_path, "rb") as image_file:
243
+ encoded_images.append(process_and_encode_image(image_file))
244
+
245
+ # Prepare the imageVariationParams dictionary
246
+ image_variation_params = {
247
+ "images": encoded_images,
248
+ "similarityStrength": similarity_strength
249
+ }
250
+
251
+ # Conditionally add parameters if they are not None
252
+ if text:
253
+ image_variation_params["text"] = text
254
+ if negative_text:
255
+ image_variation_params["negativeText"] = negative_text
256
+
257
  body = json.dumps({
258
  "taskType": "IMAGE_VARIATION",
259
+ "imageVariationParams": image_variation_params,
260
+ "imageGenerationConfig": {
261
+ "numberOfImages": 1,
262
+ "height": height,
263
+ "width": width,
264
+ "quality": quality,
265
+ "cfgScale": cfg_scale,
266
+ "seed": seed
267
+ }
268
  })
269
  image_bytes = generate_image(body)
270
  return display_image(image_bytes)
271
 
272
+ def image_conditioning(condition_image, text, negative_text=None, control_mode="CANNY_EDGE", control_strength=0.7, height=1024, width=1024, quality="standard", cfg_scale=8.0, seed=0):
273
+ if condition_image is not None:
274
+ condition_image_encoded = process_and_encode_image(condition_image)
275
+ else:
276
+ raise ValueError("Input image is required.")
277
+
278
+ # Prepare the textToImageParams dictionary
279
+ text_to_image_params = {
280
+ "text": text,
281
+ "conditionImage": condition_image_encoded,
282
+ "controlMode": control_mode,
283
+ "controlStrength": control_strength
284
+ }
285
+
286
+ # Conditionally add negativeText if it is not None
287
+ if negative_text:
288
+ text_to_image_params["negativeText"] = negative_text
289
+
290
  body = json.dumps({
291
  "taskType": "TEXT_IMAGE",
292
+ "textToImageParams": text_to_image_params,
293
+ "imageGenerationConfig": {
294
+ "numberOfImages": 1,
295
+ "height": height,
296
+ "width": width,
297
+ "quality": quality,
298
+ "cfgScale": cfg_scale,
299
+ "seed": seed
300
+ }
301
  })
302
  image_bytes = generate_image(body)
303
  return display_image(image_bytes)
304
 
305
+ def color_guided_content(text=None, reference_image=None, negative_text=None, colors=None, height=1024, width=1024, quality="standard", cfg_scale=8.0, seed=0):
306
+ # Encode the reference image if provided
307
+ if reference_image is not None:
308
+ reference_image_encoded = process_and_encode_image(reference_image)
309
+ else:
310
+ reference_image_encoded = None
311
+ if not colors:
312
+ colors = "#FF5733,#33FF57,#3357FF,#FF33A1,#33FFF5,#FF8C33,#8C33FF,#33FF8C,#FF3333,#33A1FF"
313
+ # Prepare the colorGuidedGenerationParams dictionary
314
+ color_guided_generation_params = {
315
+ "text": text,
316
+ "colors": colors.split(',')
317
+ }
318
+
319
+ # Conditionally add parameters if they are not None
320
+ if negative_text:
321
+ color_guided_generation_params["negativeText"] = negative_text
322
+ if reference_image_encoded:
323
+ color_guided_generation_params["referenceImage"] = reference_image_encoded
324
+
325
  body = json.dumps({
326
  "taskType": "COLOR_GUIDED_GENERATION",
327
+ "colorGuidedGenerationParams": color_guided_generation_params,
328
+ "imageGenerationConfig": {
329
+ "numberOfImages": 1,
330
+ "height": height,
331
+ "width": width,
332
+ "quality": quality,
333
+ "cfgScale": cfg_scale,
334
+ "seed": seed
335
+ }
336
  })
337
  image_bytes = generate_image(body)
338
  return display_image(image_bytes)
339
 
340
  def background_removal(image):
341
+ input_image = process_and_encode_image(image)
342
  body = json.dumps({
343
  "taskType": "BACKGROUND_REMOVAL",
344
  "backgroundRemovalParams": {"image": input_image}
 
348
 
349
  # Gradio Interface
350
  with gr.Blocks() as demo:
351
+ gr.HTML("""
352
+ <style>
353
+ #component-0 {
354
+ max-width: 800px;
355
+ margin: 0 auto;
356
+ }
357
+ </style>
358
+ """)
359
  gr.Markdown("# Amazon Nova Canvas Image Generation")
360
 
361
  with gr.Tab("Text to Image"):
362
  with gr.Column():
363
  gr.Markdown("Generate an image from a text prompt using the Amazon Nova Canvas model.")
364
+ prompt = gr.Textbox(label="Prompt", placeholder="Enter a text prompt (1-1024 characters)", max_lines=1)
365
  output = gr.Image()
366
+ with gr.Accordion("Advanced Options", open=False):
367
+ negative_text = gr.Textbox(label="Negative Prompt", placeholder="Enter text to exclude (1-1024 characters)", max_lines=1)
368
+ height = gr.Slider(minimum=256, maximum=2048, step=64, value=1024, label="Height")
369
+ width = gr.Slider(minimum=256, maximum=2048, step=64, value=1024, label="Width")
370
+ quality = gr.Radio(choices=["standard", "premium"], value="standard", label="Quality")
371
+ cfg_scale = gr.Slider(minimum=1.0, maximum=20.0, step=0.1, value=8.0, label="CFG Scale")
372
+ seed = gr.Slider(minimum=1, maximum=2000, step=1, value=8, label="Seed")
373
+
374
+ gr.Button("Generate").click(text_to_image, inputs=[prompt, negative_text, height, width, quality, cfg_scale, seed], outputs=output)
375
 
376
  with gr.Tab("Inpainting"):
377
  with gr.Column():
378
+ gr.Markdown("""
379
+ <div style="text-align: center;">
380
+ Modify specific areas of your image using inpainting. Upload your image and choose one of two ways to specify the areas you want to edit:
381
+ You can use a photo editing tool to draw masks (using pure black for areas to edit and pure white for areas to preserve) or use the Mask Prompt field to allow the model to infer the mask.
382
+ </div>
383
+ """)
384
  image = gr.Image(type='pil', label="Input Image")
385
+ mask_prompt = gr.Textbox(label="Mask Prompt", placeholder="Describe regions to edit", max_lines=1)
386
+ with gr.Accordion("Mask Image", open=False):
387
+ text = gr.Textbox(label="Text", placeholder="Describe what to generate (1-1024 characters)", max_lines=1)
388
+ mask_image = gr.Image(type='pil', label="Mask Image")
389
  output = gr.Image()
390
+ with gr.Accordion("Advanced Options", open=False):
391
+ negative_text = gr.Textbox(label="Negative Prompt", placeholder="Describe what not to include (1-1024 characters)", max_lines=1)
392
+ width = gr.Slider(minimum=256, maximum=2048, step=64, value=1024, label="Width")
393
+ height = gr.Slider(minimum=256, maximum=2048, step=64, value=1024, label="Height")
394
+ quality = gr.Radio(choices=["standard", "premium"], value="standard", label="Quality")
395
+ cfg_scale = gr.Slider(minimum=1.0, maximum=20.0, step=0.1, value=8.0, label="CFG Scale")
396
+ seed = gr.Slider(minimum=1, maximum=2000, step=1, value=8, label="Seed")
397
+
398
+ gr.Button("Generate").click(inpainting, inputs=[image, mask_prompt, mask_image, text, negative_text, height, width, quality, cfg_scale, seed], outputs=output)
399
 
400
  with gr.Tab("Outpainting"):
401
  with gr.Column():
402
  gr.Markdown("Extend an image beyond its original borders using a mask and text prompt.")
403
+ gr.Markdown("""
404
+ <div style="text-align: center;">
405
+ Modify areas outside of your image using outpainting. Upload your image and choose one of two ways to specify the areas you want to edit:
406
+ You can use a photo editing tool to draw masks extended outside of an images original borders (using pure black for areas to edit and pure
407
+ white for areas to preserve) or use the Mask Prompt field to allow the model to infer the mask.
408
+ </div>
409
+ """)
410
  image = gr.Image(type='pil', label="Input Image")
411
+ mask_prompt = gr.Textbox(label="Mask Prompt", placeholder="Describe regions to edit", max_lines=1)
412
+ with gr.Accordion("Mask Image", open=False):
413
+ text = gr.Textbox(label="Text", placeholder="Describe what to generate (1-1024 characters)", max_lines=1)
414
+ mask_image = gr.Image(type='pil', label="Mask Image")
415
  output = gr.Image()
416
+ with gr.Accordion("Advanced Options", open=False):
417
+ negative_text = gr.Textbox(label="Negative Prompt", placeholder="Describe what not to include (1-1024 characters)", max_lines=1)
418
+ outpainting_mode = gr.Radio(choices=["DEFAULT", "PRECISE"], value="DEFAULT", label="Outpainting Mode")
419
+ width = gr.Slider(minimum=256, maximum=2048, step=64, value=1024, label="Width")
420
+ height = gr.Slider(minimum=256, maximum=2048, step=64, value=1024, label="Height")
421
+ quality = gr.Radio(choices=["standard", "premium"], value="standard", label="Quality")
422
+ cfg_scale = gr.Slider(minimum=1.0, maximum=20.0, step=0.1, value=8.0, label="CFG Scale")
423
+ seed = gr.Slider(minimum=1, maximum=2000, step=1, value=8, label="Seed")
424
+
425
+ gr.Button("Generate").click(outpainting, inputs=[image, mask_prompt, mask_image, text, negative_text, outpainting_mode, height, width, quality, cfg_scale, seed], outputs=output)
426
 
427
  with gr.Tab("Image Variation"):
428
  with gr.Column():
429
+ gr.Markdown("""
430
+ <div style="text-align: center;">
431
+ Create a variation image based on up to 5 other images and a text description (optional).
432
+ </div>
433
+ """)
434
+ images = gr.File(type='filepath', label="Input Images", file_count="multiple", file_types=["image"])
435
+ text = gr.Textbox(label="Text", placeholder="Enter a text prompt (1-1024 characters)", max_lines=1)
436
  output = gr.Image()
437
+ with gr.Accordion("Advanced Options", open=False):
438
+ negative_text = gr.Textbox(label="Negative Prompt", placeholder="Enter text to exclude (1-1024 characters)", max_lines=1)
439
+ similarity_strength = gr.Slider(minimum=0.2, maximum=1.0, step=0.1, value=0.7, label="Similarity Strength")
440
+ width = gr.Slider(minimum=256, maximum=2048, step=64, value=1024, label="Width")
441
+ height = gr.Slider(minimum=256, maximum=2048, step=64, value=1024, label="Height")
442
+ quality = gr.Radio(choices=["standard", "premium"], value="standard", label="Quality")
443
+ cfg_scale = gr.Slider(minimum=1.0, maximum=20.0, step=0.1, value=8.0, label="CFG Scale")
444
+ seed = gr.Slider(minimum=1, maximum=2000, step=1, value=8, label="Seed")
445
+
446
+ gr.Button("Generate").click(image_variation, inputs=[images, text, negative_text, similarity_strength, height, width, quality, cfg_scale, seed], outputs=output)
447
 
448
  with gr.Tab("Image Conditioning"):
449
  with gr.Column():
450
+ gr.Markdown("""
451
+ <div style="text-align: center;">
452
+ Generate an image conditioned on an input image and a text prompt (required).
453
+ </div>
454
+ """)
455
+ condition_image = gr.Image(type='pil', label="Condition Image")
456
+ text = gr.Textbox(label="Text", placeholder="Enter a text prompt (1-1024 characters)", max_lines=1)
457
  output = gr.Image()
458
+ with gr.Accordion("Advanced Options", open=False):
459
+ negative_text = gr.Textbox(label="Negative Prompt", placeholder="Describe what not to include (1-1024 characters)", max_lines=1)
460
+ control_mode = gr.Radio(choices=["CANNY_EDGE", "SEGMENTATION"], value="CANNY_EDGE", label="Control Mode")
461
+ control_strength = gr.Slider(minimum=0.0, maximum=1.0, step=0.1, value=0.7, label="Control Strength")
462
+ width = gr.Slider(minimum=256, maximum=2048, step=64, value=1024, label="Width")
463
+ height = gr.Slider(minimum=256, maximum=2048, step=64, value=1024, label="Height")
464
+ quality = gr.Radio(choices=["standard", "premium"], value="standard", label="Quality")
465
+ cfg_scale = gr.Slider(minimum=1.0, maximum=20.0, step=0.1, value=8.0, label="CFG Scale")
466
+ seed = gr.Slider(minimum=1, maximum=2000, step=1, value=8, label="Seed")
467
+
468
+ gr.Button("Generate").click(image_conditioning, inputs=[condition_image, text, negative_text, control_mode, control_strength, height, width, quality, cfg_scale, seed], outputs=output)
469
 
470
  with gr.Tab("Color Guided Content"):
471
  with gr.Column():
472
+ gr.Markdown("""
473
+ <div style="text-align: center;">
474
+ Generate an image using a color palette from a reference image or a text prompt. Starter colors are provided.
475
+ </div>
476
+ """)
477
+ reference_image = gr.Image(type='pil', label="Reference Image")
478
+ colors = gr.Textbox(label="Colors", placeholder="Enter up to 10 colors as hex values, e.g., #00FF00,#FCF2AB", max_lines=1)
479
+ text = gr.Textbox(label="Text", placeholder="Enter a text prompt (1-1024 characters)", max_lines=1)
480
  output = gr.Image()
481
+ with gr.Accordion("Advanced Options", open=False):
482
+ negative_text = gr.Textbox(label="Negative Prompt", placeholder="Enter text to exclude (1-1024 characters)", max_lines=1)
483
+ width = gr.Slider(minimum=256, maximum=2048, step=64, value=1024, label="Width")
484
+ height = gr.Slider(minimum=256, maximum=2048, step=64, value=1024, label="Height")
485
+ quality = gr.Radio(choices=["standard", "premium"], value="standard", label="Quality")
486
+ cfg_scale = gr.Slider(minimum=1.0, maximum=20.0, step=0.1, value=8.0, label="CFG Scale")
487
+ seed = gr.Slider(minimum=1, maximum=2000, step=1, value=8, label="Seed")
488
+
489
+ gr.Button("Generate").click(color_guided_content, inputs=[text, reference_image, negative_text, colors, height, width, quality, cfg_scale, seed], outputs=output)
490
 
491
  with gr.Tab("Background Removal"):
492
  with gr.Column():
493
+ gr.Markdown("""
494
+ <div style="text-align: center;">
495
+ Remove the background from an image.
496
+ </div>
497
+ """)
498
  image = gr.Image(type='pil', label="Input Image")
499
  output = gr.Image()
500
  gr.Button("Generate").click(background_removal, inputs=image, outputs=output)
requirements.txt CHANGED
@@ -1,3 +1,2 @@
1
- spaces
2
- gradio
3
  boto3
 
1
+ Pillow
 
2
  boto3