awslabs.nova-canvas-mcp-server 0.1.10652__tar.gz → 0.1.62303__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (19) hide show
  1. awslabs_nova_canvas_mcp_server-0.1.62303/.python-version +1 -0
  2. awslabs_nova_canvas_mcp_server-0.1.62303/Dockerfile +29 -0
  3. awslabs_nova_canvas_mcp_server-0.1.62303/PKG-INFO +91 -0
  4. awslabs_nova_canvas_mcp_server-0.1.62303/README.md +80 -0
  5. {awslabs_nova_canvas_mcp_server-0.1.10652 → awslabs_nova_canvas_mcp_server-0.1.62303}/awslabs/nova_canvas_mcp_server/__init__.py +1 -1
  6. {awslabs_nova_canvas_mcp_server-0.1.10652 → awslabs_nova_canvas_mcp_server-0.1.62303}/awslabs/nova_canvas_mcp_server/consts.py +3 -3
  7. {awslabs_nova_canvas_mcp_server-0.1.10652 → awslabs_nova_canvas_mcp_server-0.1.62303}/awslabs/nova_canvas_mcp_server/models.py +23 -27
  8. {awslabs_nova_canvas_mcp_server-0.1.10652 → awslabs_nova_canvas_mcp_server-0.1.62303}/awslabs/nova_canvas_mcp_server/novacanvas.py +50 -70
  9. {awslabs_nova_canvas_mcp_server-0.1.10652 → awslabs_nova_canvas_mcp_server-0.1.62303}/awslabs/nova_canvas_mcp_server/server.py +56 -70
  10. {awslabs_nova_canvas_mcp_server-0.1.10652 → awslabs_nova_canvas_mcp_server-0.1.62303}/pyproject.toml +5 -2
  11. awslabs_nova_canvas_mcp_server-0.1.62303/smithery.yaml +58 -0
  12. {awslabs_nova_canvas_mcp_server-0.1.10652 → awslabs_nova_canvas_mcp_server-0.1.62303}/uv.lock +175 -3
  13. awslabs_nova_canvas_mcp_server-0.1.10652/.python-version +0 -1
  14. awslabs_nova_canvas_mcp_server-0.1.10652/PKG-INFO +0 -74
  15. awslabs_nova_canvas_mcp_server-0.1.10652/README.md +0 -63
  16. {awslabs_nova_canvas_mcp_server-0.1.10652 → awslabs_nova_canvas_mcp_server-0.1.62303}/.gitignore +0 -0
  17. {awslabs_nova_canvas_mcp_server-0.1.10652 → awslabs_nova_canvas_mcp_server-0.1.62303}/.pre-commit-config.yaml +0 -0
  18. {awslabs_nova_canvas_mcp_server-0.1.10652 → awslabs_nova_canvas_mcp_server-0.1.62303}/CHANGELOG.md +0 -0
  19. {awslabs_nova_canvas_mcp_server-0.1.10652 → awslabs_nova_canvas_mcp_server-0.1.62303}/awslabs/__init__.py +0 -0
@@ -0,0 +1,29 @@
1
+ # Generated by https://smithery.ai. See: https://smithery.ai/docs/config#dockerfile
2
+ FROM python:3.10-alpine
3
+
4
+ # Install build dependencies
5
+ RUN apk add --no-cache gcc musl-dev linux-headers
6
+
7
+ WORKDIR /app
8
+
9
+ # Copy the entire repository (monorepo context)
10
+ COPY . .
11
+
12
+ # Set working directory to the MCP server subdirectory
13
+ WORKDIR /app/src/nova-canvas-mcp-server
14
+
15
+ # Create dummy AWS credentials to satisfy boto3 when using the default profile
16
+ RUN mkdir -p /root/.aws && \
17
+ echo "[default]" > /root/.aws/credentials && \
18
+ echo "aws_access_key_id = dummy" >> /root/.aws/credentials && \
19
+ echo "aws_secret_access_key = dummy" >> /root/.aws/credentials
20
+
21
+ # Upgrade pip and install the package
22
+ RUN pip install --no-cache-dir --upgrade pip && \
23
+ pip install --no-cache-dir .
24
+
25
+ # Expose port if using SSE transport (optional)
26
+ EXPOSE 8888
27
+
28
+ # Start the MCP server (entrypoint provided by project.scripts in pyproject.toml)
29
+ CMD ["awslabs.nova-canvas-mcp-server"]
@@ -0,0 +1,91 @@
1
+ Metadata-Version: 2.4
2
+ Name: awslabs.nova-canvas-mcp-server
3
+ Version: 0.1.62303
4
+ Summary: An AWS Labs Model Context Protocol (MCP) server for Amazon Nova Canvas
5
+ Requires-Python: >=3.10
6
+ Requires-Dist: boto3>=1.37.24
7
+ Requires-Dist: loguru>=0.7.3
8
+ Requires-Dist: mcp[cli]>=1.6.0
9
+ Requires-Dist: pydantic>=2.11.1
10
+ Description-Content-Type: text/markdown
11
+
12
+ # Amazon Nova Canvas MCP Server
13
+
14
+ [![smithery badge](https://smithery.ai/badge/@awslabs/nova-canvas-mcp-server)](https://smithery.ai/server/@awslabs/nova-canvas-mcp-server)
15
+
16
+ MCP server for generating images using Amazon Nova Canvas
17
+
18
+ ## Features
19
+
20
+ ### Text-based image generation
21
+
22
+ - Create images from text prompts with `generate_image`
23
+ - Customizable dimensions (320-4096px), quality options, and negative prompting
24
+ - Supports multiple image generation (1-5) in single request
25
+ - Adjustable parameters like cfg_scale (1.1-10.0) and seeded generation
26
+
27
+ ### Color-guided image generation
28
+
29
+ - Generate images with specific color palettes using `generate_image_with_colors`
30
+ - Define up to 10 hex color values to influence the image style and mood
31
+ - Same customization options as text-based generation
32
+
33
+ ### Workspace integration
34
+
35
+ - Images saved to user-specified workspace directories with automatic folder creation
36
+
37
+ ### AWS authentication
38
+
39
+ - Uses AWS profiles for secure access to Amazon Nova Canvas services
40
+
41
+ ## Prerequisites
42
+
43
+ 1. Install `uv` from [Astral](https://docs.astral.sh/uv/getting-started/installation/) or the [GitHub README](https://github.com/astral-sh/uv#installation)
44
+ 2. Install Python using `uv python install 3.10`
45
+ 3. Set up AWS credentials with access to Amazon Bedrock and Nova Canvas
46
+ - You need an AWS account with Amazon Bedrock and Amazon Nova Canvas enabled
47
+ - Configure AWS credentials with `aws configure` or environment variables
48
+ - Ensure your IAM role/user has permissions to use Amazon Bedrock and Nova Canvas
49
+
50
+ ## Installation
51
+
52
+ Here are some ways you can work with MCP across AWS, and we'll be adding support to more products including Amazon Q Developer CLI soon: (e.g. for Amazon Q Developer CLI MCP, `~/.aws/amazonq/mcp.json`):
53
+
54
+ ```json
55
+ {
56
+ "mcpServers": {
57
+ "awslabs.nova-canvas-mcp-server": {
58
+ "command": "uvx",
59
+ "args": ["awslabs.nova-canvas-mcp-server@latest"],
60
+ "env": {
61
+ "AWS_PROFILE": "your-aws-profile",
62
+ "AWS_REGION": "us-east-1",
63
+ "FASTMCP_LOG_LEVEL": "ERROR"
64
+ },
65
+ "disabled": false,
66
+ "autoApprove": []
67
+ }
68
+ }
69
+ }
70
+ ```
71
+
72
+ ### Installing via Smithery
73
+
74
+ To install Amazon Nova Canvas MCP Server for Claude Desktop automatically via [Smithery](https://smithery.ai/server/@awslabs/nova-canvas-mcp-server):
75
+
76
+ ```bash
77
+ npx -y @smithery/cli install @awslabs/nova-canvas-mcp-server --client claude
78
+ ```
79
+
80
+ ### AWS Authentication
81
+
82
+ The MCP server uses the AWS profile specified in the `AWS_PROFILE` environment variable. If not provided, it defaults to the "default" profile in your AWS configuration file.
83
+
84
+ ```json
85
+ "env": {
86
+ "AWS_PROFILE": "your-aws-profile",
87
+ "AWS_REGION": "us-east-1"
88
+ }
89
+ ```
90
+
91
+ Make sure the AWS profile has permissions to access Amazon Bedrock and Amazon Nova Canvas. The MCP server creates a boto3 session using the specified profile to authenticate with AWS services. Your AWS IAM credentials remain on your local machine and are strictly used for using the Amazon Bedrock model APIs.
@@ -0,0 +1,80 @@
1
+ # Amazon Nova Canvas MCP Server
2
+
3
+ [![smithery badge](https://smithery.ai/badge/@awslabs/nova-canvas-mcp-server)](https://smithery.ai/server/@awslabs/nova-canvas-mcp-server)
4
+
5
+ MCP server for generating images using Amazon Nova Canvas
6
+
7
+ ## Features
8
+
9
+ ### Text-based image generation
10
+
11
+ - Create images from text prompts with `generate_image`
12
+ - Customizable dimensions (320-4096px), quality options, and negative prompting
13
+ - Supports multiple image generation (1-5) in single request
14
+ - Adjustable parameters like cfg_scale (1.1-10.0) and seeded generation
15
+
16
+ ### Color-guided image generation
17
+
18
+ - Generate images with specific color palettes using `generate_image_with_colors`
19
+ - Define up to 10 hex color values to influence the image style and mood
20
+ - Same customization options as text-based generation
21
+
22
+ ### Workspace integration
23
+
24
+ - Images saved to user-specified workspace directories with automatic folder creation
25
+
26
+ ### AWS authentication
27
+
28
+ - Uses AWS profiles for secure access to Amazon Nova Canvas services
29
+
30
+ ## Prerequisites
31
+
32
+ 1. Install `uv` from [Astral](https://docs.astral.sh/uv/getting-started/installation/) or the [GitHub README](https://github.com/astral-sh/uv#installation)
33
+ 2. Install Python using `uv python install 3.10`
34
+ 3. Set up AWS credentials with access to Amazon Bedrock and Nova Canvas
35
+ - You need an AWS account with Amazon Bedrock and Amazon Nova Canvas enabled
36
+ - Configure AWS credentials with `aws configure` or environment variables
37
+ - Ensure your IAM role/user has permissions to use Amazon Bedrock and Nova Canvas
38
+
39
+ ## Installation
40
+
41
+ Here are some ways you can work with MCP across AWS, and we'll be adding support to more products including Amazon Q Developer CLI soon: (e.g. for Amazon Q Developer CLI MCP, `~/.aws/amazonq/mcp.json`):
42
+
43
+ ```json
44
+ {
45
+ "mcpServers": {
46
+ "awslabs.nova-canvas-mcp-server": {
47
+ "command": "uvx",
48
+ "args": ["awslabs.nova-canvas-mcp-server@latest"],
49
+ "env": {
50
+ "AWS_PROFILE": "your-aws-profile",
51
+ "AWS_REGION": "us-east-1",
52
+ "FASTMCP_LOG_LEVEL": "ERROR"
53
+ },
54
+ "disabled": false,
55
+ "autoApprove": []
56
+ }
57
+ }
58
+ }
59
+ ```
60
+
61
+ ### Installing via Smithery
62
+
63
+ To install Amazon Nova Canvas MCP Server for Claude Desktop automatically via [Smithery](https://smithery.ai/server/@awslabs/nova-canvas-mcp-server):
64
+
65
+ ```bash
66
+ npx -y @smithery/cli install @awslabs/nova-canvas-mcp-server --client claude
67
+ ```
68
+
69
+ ### AWS Authentication
70
+
71
+ The MCP server uses the AWS profile specified in the `AWS_PROFILE` environment variable. If not provided, it defaults to the "default" profile in your AWS configuration file.
72
+
73
+ ```json
74
+ "env": {
75
+ "AWS_PROFILE": "your-aws-profile",
76
+ "AWS_REGION": "us-east-1"
77
+ }
78
+ ```
79
+
80
+ Make sure the AWS profile has permissions to access Amazon Bedrock and Amazon Nova Canvas. The MCP server creates a boto3 session using the specified profile to authenticate with AWS services. Your AWS IAM credentials remain on your local machine and are strictly used for using the Amazon Bedrock model APIs.
@@ -1,3 +1,3 @@
1
1
  """awslabs.nova-canvas-mcp-server"""
2
2
 
3
- __version__ = "0.1.6"
3
+ __version__ = '0.1.6'
@@ -1,11 +1,11 @@
1
1
  # Constants
2
- NOVA_CANVAS_MODEL_ID = "amazon.nova-canvas-v1:0"
2
+ NOVA_CANVAS_MODEL_ID = 'amazon.nova-canvas-v1:0'
3
3
  DEFAULT_WIDTH = 1024
4
4
  DEFAULT_HEIGHT = 1024
5
- DEFAULT_QUALITY = "standard"
5
+ DEFAULT_QUALITY = 'standard'
6
6
  DEFAULT_CFG_SCALE = 6.5
7
7
  DEFAULT_NUMBER_OF_IMAGES = 1
8
- DEFAULT_OUTPUT_DIR = "output" # Default directory inside workspace_dir
8
+ DEFAULT_OUTPUT_DIR = 'output' # Default directory inside workspace_dir
9
9
 
10
10
 
11
11
  # Nova Canvas Prompt Best Practices
@@ -15,8 +15,8 @@ class Quality(str, Enum):
15
15
  PREMIUM: Premium quality image generation with enhanced details.
16
16
  """
17
17
 
18
- STANDARD = "standard"
19
- PREMIUM = "premium"
18
+ STANDARD = 'standard'
19
+ PREMIUM = 'premium'
20
20
 
21
21
 
22
22
  class TaskType(str, Enum):
@@ -27,8 +27,8 @@ class TaskType(str, Enum):
27
27
  COLOR_GUIDED_GENERATION: Generate an image guided by both text and color palette.
28
28
  """
29
29
 
30
- TEXT_IMAGE = "TEXT_IMAGE"
31
- COLOR_GUIDED_GENERATION = "COLOR_GUIDED_GENERATION"
30
+ TEXT_IMAGE = 'TEXT_IMAGE'
31
+ COLOR_GUIDED_GENERATION = 'COLOR_GUIDED_GENERATION'
32
32
 
33
33
 
34
34
  class ImageGenerationConfig(BaseModel):
@@ -50,12 +50,10 @@ class ImageGenerationConfig(BaseModel):
50
50
  height: int = Field(default=1024, ge=320, le=4096)
51
51
  quality: Quality = Quality.STANDARD
52
52
  cfgScale: float = Field(default=6.5, ge=1.1, le=10.0)
53
- seed: int = Field(
54
- default_factory=lambda: random.randint(0, 858993459), ge=0, le=858993459
55
- )
53
+ seed: int = Field(default_factory=lambda: random.randint(0, 858993459), ge=0, le=858993459)
56
54
  numberOfImages: int = Field(default=1, ge=1, le=5)
57
55
 
58
- @field_validator("width", "height")
56
+ @field_validator('width', 'height')
59
57
  @classmethod
60
58
  def must_be_divisible_by_16(cls, v: int) -> int:
61
59
  """Validate that width and height are divisible by 16.
@@ -70,10 +68,10 @@ class ImageGenerationConfig(BaseModel):
70
68
  ValueError: If the value is not divisible by 16.
71
69
  """
72
70
  if v % 16 != 0:
73
- raise ValueError("Value must be divisible by 16")
71
+ raise ValueError('Value must be divisible by 16')
74
72
  return v
75
73
 
76
- @model_validator(mode="after")
74
+ @model_validator(mode='after')
77
75
  def validate_aspect_ratio_and_total_pixels(self):
78
76
  """Validate aspect ratio and total pixel count.
79
77
 
@@ -93,12 +91,12 @@ class ImageGenerationConfig(BaseModel):
93
91
  # Check aspect ratio between 1:4 and 4:1
94
92
  aspect_ratio = width / height
95
93
  if aspect_ratio < 0.25 or aspect_ratio > 4.0:
96
- raise ValueError("Aspect ratio must be between 1:4 and 4:1")
94
+ raise ValueError('Aspect ratio must be between 1:4 and 4:1')
97
95
 
98
96
  # Check total pixel count
99
97
  total_pixels = width * height
100
98
  if total_pixels >= 4194304:
101
- raise ValueError("Total pixel count must be less than 4,194,304")
99
+ raise ValueError('Total pixel count must be less than 4,194,304')
102
100
 
103
101
  return self
104
102
 
@@ -132,7 +130,7 @@ class ColorGuidedGenerationParams(BaseModel):
132
130
  text: str = Field(..., min_length=1, max_length=1024)
133
131
  negativeText: Optional[str] = Field(default=None, min_length=1, max_length=1024)
134
132
 
135
- @field_validator("colors")
133
+ @field_validator('colors')
136
134
  @classmethod
137
135
  def validate_hex_colors(cls, v: List[str]) -> List[str]:
138
136
  """Validate that colors are in the correct hexadecimal format.
@@ -146,7 +144,7 @@ class ColorGuidedGenerationParams(BaseModel):
146
144
  Raises:
147
145
  ValueError: If any color is not a valid hexadecimal color in the format '#RRGGBB'.
148
146
  """
149
- hex_pattern = re.compile(r"^#[0-9A-Fa-f]{6}$")
147
+ hex_pattern = re.compile(r'^#[0-9A-Fa-f]{6}$')
150
148
  for color in v:
151
149
  if not hex_pattern.match(color):
152
150
  raise ValueError(
@@ -182,13 +180,13 @@ class TextImageRequest(BaseModel):
182
180
  """
183
181
  text_to_image_params = self.textToImageParams.model_dump()
184
182
  # Remove negativeText if it's None
185
- if text_to_image_params.get("negativeText") is None:
186
- text_to_image_params.pop("negativeText", None)
183
+ if text_to_image_params.get('negativeText') is None:
184
+ text_to_image_params.pop('negativeText', None)
187
185
 
188
186
  return {
189
- "taskType": self.taskType,
190
- "textToImageParams": text_to_image_params,
191
- "imageGenerationConfig": self.imageGenerationConfig.model_dump()
187
+ 'taskType': self.taskType,
188
+ 'textToImageParams': text_to_image_params,
189
+ 'imageGenerationConfig': self.imageGenerationConfig.model_dump()
192
190
  if self.imageGenerationConfig
193
191
  else None,
194
192
  }
@@ -206,9 +204,7 @@ class ColorGuidedRequest(BaseModel):
206
204
  imageGenerationConfig: Configuration for image generation.
207
205
  """
208
206
 
209
- taskType: Literal[
210
- TaskType.COLOR_GUIDED_GENERATION
211
- ] = TaskType.COLOR_GUIDED_GENERATION
207
+ taskType: Literal[TaskType.COLOR_GUIDED_GENERATION] = TaskType.COLOR_GUIDED_GENERATION
212
208
  colorGuidedGenerationParams: ColorGuidedGenerationParams
213
209
  imageGenerationConfig: Optional[ImageGenerationConfig] = Field(
214
210
  default_factory=ImageGenerationConfig
@@ -223,13 +219,13 @@ class ColorGuidedRequest(BaseModel):
223
219
  """
224
220
  color_guided_params = self.colorGuidedGenerationParams.model_dump()
225
221
  # Remove negativeText if it's None
226
- if color_guided_params.get("negativeText") is None:
227
- color_guided_params.pop("negativeText", None)
222
+ if color_guided_params.get('negativeText') is None:
223
+ color_guided_params.pop('negativeText', None)
228
224
 
229
225
  return {
230
- "taskType": self.taskType,
231
- "colorGuidedGenerationParams": color_guided_params,
232
- "imageGenerationConfig": self.imageGenerationConfig.model_dump()
226
+ 'taskType': self.taskType,
227
+ 'colorGuidedGenerationParams': color_guided_params,
228
+ 'imageGenerationConfig': self.imageGenerationConfig.model_dump()
233
229
  if self.imageGenerationConfig
234
230
  else None,
235
231
  }
@@ -41,7 +41,7 @@ def save_generated_images(
41
41
  base64_images: List[str],
42
42
  filename: Optional[str] = None,
43
43
  number_of_images: int = DEFAULT_NUMBER_OF_IMAGES,
44
- prefix: str = "nova_canvas",
44
+ prefix: str = 'nova_canvas',
45
45
  workspace_dir: Optional[str] = None,
46
46
  ) -> Dict[str, List]:
47
47
  """Save base64-encoded images to files.
@@ -56,7 +56,7 @@ def save_generated_images(
56
56
  Returns:
57
57
  Dictionary with lists of paths to the saved image files and PIL Image objects.
58
58
  """
59
- logger.debug(f"Saving {len(base64_images)} images")
59
+ logger.debug(f'Saving {len(base64_images)} images')
60
60
  # Determine the output directory
61
61
  if workspace_dir:
62
62
  output_dir = os.path.join(workspace_dir, DEFAULT_OUTPUT_DIR)
@@ -73,27 +73,25 @@ def save_generated_images(
73
73
  # Generate filename if not provided
74
74
  if filename:
75
75
  image_filename = (
76
- f"{filename}_{i + 1}.png" if number_of_images > 1 else f"{filename}.png"
76
+ f'{filename}_{i + 1}.png' if number_of_images > 1 else f'{filename}.png'
77
77
  )
78
78
  else:
79
79
  # Generate a random filename
80
- random_id = "".join(
81
- random.choices("abcdefghijklmnopqrstuvwxyz0123456789", k=8)
82
- )
83
- image_filename = f"{prefix}_{random_id}_{i + 1}.png"
80
+ random_id = ''.join(random.choices('abcdefghijklmnopqrstuvwxyz0123456789', k=8))
81
+ image_filename = f'{prefix}_{random_id}_{i + 1}.png'
84
82
 
85
83
  # Decode the base64 image data
86
84
  image_data = base64.b64decode(base64_image_data)
87
85
 
88
86
  # Save the image
89
87
  image_path = os.path.join(output_dir, image_filename)
90
- with open(image_path, "wb") as file:
88
+ with open(image_path, 'wb') as file:
91
89
  file.write(image_data)
92
90
  # Convert to absolute path
93
91
  abs_image_path = os.path.abspath(image_path)
94
92
  saved_paths.append(abs_image_path)
95
93
 
96
- return {"paths": saved_paths}
94
+ return {'paths': saved_paths}
97
95
 
98
96
 
99
97
  async def invoke_nova_canvas(
@@ -112,24 +110,22 @@ async def invoke_nova_canvas(
112
110
  Raises:
113
111
  Exception: If the API call fails.
114
112
  """
115
- logger.debug("Invoking Nova Canvas API")
113
+ logger.debug('Invoking Nova Canvas API')
116
114
 
117
115
  # Convert the request payload to JSON
118
116
  request = json.dumps(request_model_dict)
119
117
 
120
118
  try:
121
119
  # Invoke the model
122
- logger.info(f"Sending request to Nova Canvas model: {NOVA_CANVAS_MODEL_ID}")
123
- response = bedrock_runtime_client.invoke_model(
124
- modelId=NOVA_CANVAS_MODEL_ID, body=request
125
- )
120
+ logger.info(f'Sending request to Nova Canvas model: {NOVA_CANVAS_MODEL_ID}')
121
+ response = bedrock_runtime_client.invoke_model(modelId=NOVA_CANVAS_MODEL_ID, body=request)
126
122
 
127
123
  # Decode the response body
128
- result = json.loads(response["body"].read())
129
- logger.info("Nova Canvas API call successful")
124
+ result = json.loads(response['body'].read())
125
+ logger.info('Nova Canvas API call successful')
130
126
  return result
131
127
  except Exception as e:
132
- logger.error(f"Nova Canvas API call failed: {str(e)}")
128
+ logger.error(f'Nova Canvas API call failed: {str(e)}')
133
129
  raise
134
130
 
135
131
 
@@ -169,22 +165,18 @@ async def generate_image_with_text(
169
165
  ImageGenerationResponse: An object containing the paths to the generated images,
170
166
  PIL Image objects, and status information.
171
167
  """
172
- logger.debug(
173
- f"Generating text-to-image with prompt: '{prompt[:30]}...' ({width}x{height})"
174
- )
168
+ logger.debug(f"Generating text-to-image with prompt: '{prompt[:30]}...' ({width}x{height})")
175
169
 
176
170
  try:
177
171
  # Validate input parameters using Pydantic
178
172
  try:
179
- logger.debug("Validating parameters and creating request model")
173
+ logger.debug('Validating parameters and creating request model')
180
174
 
181
175
  # Create image generation config
182
176
  config = ImageGenerationConfig(
183
177
  width=width,
184
178
  height=height,
185
- quality=Quality.STANDARD
186
- if quality == DEFAULT_QUALITY
187
- else Quality.PREMIUM,
179
+ quality=Quality.STANDARD if quality == DEFAULT_QUALITY else Quality.PREMIUM,
188
180
  cfgScale=cfg_scale,
189
181
  seed=seed if seed is not None else random.randint(0, 858993459),
190
182
  numberOfImages=number_of_images,
@@ -193,9 +185,7 @@ async def generate_image_with_text(
193
185
  # Create text-to-image params
194
186
  # The Nova Canvas API doesn't accept null for negativeText
195
187
  if negative_prompt is not None:
196
- text_params = TextToImageParams(
197
- text=prompt, negativeText=negative_prompt
198
- )
188
+ text_params = TextToImageParams(text=prompt, negativeText=negative_prompt)
199
189
  else:
200
190
  text_params = TextToImageParams(text=prompt)
201
191
 
@@ -206,13 +196,13 @@ async def generate_image_with_text(
206
196
 
207
197
  # Convert model to dictionary
208
198
  request_model_dict = request_model.to_api_dict()
209
- logger.info("Request validation successful")
199
+ logger.info('Request validation successful')
210
200
 
211
201
  except Exception as e:
212
- logger.error(f"Parameter validation failed: {str(e)}")
202
+ logger.error(f'Parameter validation failed: {str(e)}')
213
203
  return ImageGenerationResponse(
214
- status="error",
215
- message=f"Validation error: {str(e)}",
204
+ status='error',
205
+ message=f'Validation error: {str(e)}',
216
206
  paths=[],
217
207
  prompt=prompt,
218
208
  negative_prompt=negative_prompt,
@@ -220,36 +210,34 @@ async def generate_image_with_text(
220
210
 
221
211
  try:
222
212
  # Invoke the Nova Canvas API
223
- logger.debug("Sending request to Nova Canvas API")
224
- model_response = await invoke_nova_canvas(
225
- request_model_dict, bedrock_runtime_client
226
- )
213
+ logger.debug('Sending request to Nova Canvas API')
214
+ model_response = await invoke_nova_canvas(request_model_dict, bedrock_runtime_client)
227
215
 
228
216
  # Extract the image data
229
- base64_images = model_response["images"]
230
- logger.info(f"Received {len(base64_images)} images from Nova Canvas API")
217
+ base64_images = model_response['images']
218
+ logger.info(f'Received {len(base64_images)} images from Nova Canvas API')
231
219
 
232
220
  # Save the generated images
233
221
  result = save_generated_images(
234
222
  base64_images,
235
223
  filename,
236
224
  number_of_images,
237
- prefix="nova_canvas",
225
+ prefix='nova_canvas',
238
226
  workspace_dir=workspace_dir,
239
227
  )
240
228
 
241
229
  logger.info(f'Successfully generated {len(result["paths"])} image(s)')
242
230
  return ImageGenerationResponse(
243
- status="success",
231
+ status='success',
244
232
  message=f'Generated {len(result["paths"])} image(s)',
245
- paths=result["paths"],
233
+ paths=result['paths'],
246
234
  prompt=prompt,
247
235
  negative_prompt=negative_prompt,
248
236
  )
249
237
  except Exception as e:
250
- logger.error(f"Image generation failed: {str(e)}")
238
+ logger.error(f'Image generation failed: {str(e)}')
251
239
  return ImageGenerationResponse(
252
- status="error",
240
+ status='error',
253
241
  message=str(e),
254
242
  paths=[],
255
243
  prompt=prompt,
@@ -257,9 +245,9 @@ async def generate_image_with_text(
257
245
  )
258
246
 
259
247
  except Exception as e:
260
- logger.error(f"Unexpected error in generate_image_with_text: {str(e)}")
248
+ logger.error(f'Unexpected error in generate_image_with_text: {str(e)}')
261
249
  return ImageGenerationResponse(
262
- status="error",
250
+ status='error',
263
251
  message=str(e),
264
252
  paths=[],
265
253
  prompt=prompt,
@@ -312,17 +300,13 @@ async def generate_image_with_colors(
312
300
  try:
313
301
  # Validate input parameters using Pydantic
314
302
  try:
315
- logger.debug(
316
- "Validating parameters and creating color-guided request model"
317
- )
303
+ logger.debug('Validating parameters and creating color-guided request model')
318
304
 
319
305
  # Create image generation config
320
306
  config = ImageGenerationConfig(
321
307
  width=width,
322
308
  height=height,
323
- quality=Quality.STANDARD
324
- if quality == DEFAULT_QUALITY
325
- else Quality.PREMIUM,
309
+ quality=Quality.STANDARD if quality == DEFAULT_QUALITY else Quality.PREMIUM,
326
310
  cfgScale=cfg_scale,
327
311
  seed=seed if seed is not None else random.randint(0, 858993459),
328
312
  numberOfImages=number_of_images,
@@ -349,13 +333,13 @@ async def generate_image_with_colors(
349
333
 
350
334
  # Convert model to dictionary
351
335
  request_model_dict = request_model.to_api_dict()
352
- logger.info("Color-guided request validation successful")
336
+ logger.info('Color-guided request validation successful')
353
337
 
354
338
  except Exception as e:
355
- logger.error(f"Color-guided parameter validation failed: {str(e)}")
339
+ logger.error(f'Color-guided parameter validation failed: {str(e)}')
356
340
  return ImageGenerationResponse(
357
- status="error",
358
- message=f"Validation error: {str(e)}",
341
+ status='error',
342
+ message=f'Validation error: {str(e)}',
359
343
  paths=[],
360
344
  prompt=prompt,
361
345
  negative_prompt=negative_prompt,
@@ -364,39 +348,35 @@ async def generate_image_with_colors(
364
348
 
365
349
  try:
366
350
  # Invoke the Nova Canvas API
367
- logger.debug("Sending color-guided request to Nova Canvas API")
368
- model_response = await invoke_nova_canvas(
369
- request_model_dict, bedrock_runtime_client
370
- )
351
+ logger.debug('Sending color-guided request to Nova Canvas API')
352
+ model_response = await invoke_nova_canvas(request_model_dict, bedrock_runtime_client)
371
353
 
372
354
  # Extract the image data
373
- base64_images = model_response["images"]
374
- logger.info(f"Received {len(base64_images)} images from Nova Canvas API")
355
+ base64_images = model_response['images']
356
+ logger.info(f'Received {len(base64_images)} images from Nova Canvas API')
375
357
 
376
358
  # Save the generated images
377
359
  result = save_generated_images(
378
360
  base64_images,
379
361
  filename,
380
362
  number_of_images,
381
- prefix="nova_canvas_color",
363
+ prefix='nova_canvas_color',
382
364
  workspace_dir=workspace_dir,
383
365
  )
384
366
 
385
- logger.info(
386
- f'Successfully generated {len(result["paths"])} color-guided image(s)'
387
- )
367
+ logger.info(f'Successfully generated {len(result["paths"])} color-guided image(s)')
388
368
  return ImageGenerationResponse(
389
- status="success",
369
+ status='success',
390
370
  message=f'Generated {len(result["paths"])} image(s)',
391
- paths=result["paths"],
371
+ paths=result['paths'],
392
372
  prompt=prompt,
393
373
  negative_prompt=negative_prompt,
394
374
  colors=colors,
395
375
  )
396
376
  except Exception as e:
397
- logger.error(f"Color-guided image generation failed: {str(e)}")
377
+ logger.error(f'Color-guided image generation failed: {str(e)}')
398
378
  return ImageGenerationResponse(
399
- status="error",
379
+ status='error',
400
380
  message=str(e),
401
381
  paths=[],
402
382
  prompt=prompt,
@@ -405,9 +385,9 @@ async def generate_image_with_colors(
405
385
  )
406
386
 
407
387
  except Exception as e:
408
- logger.error(f"Unexpected error in generate_image_with_colors: {str(e)}")
388
+ logger.error(f'Unexpected error in generate_image_with_colors: {str(e)}')
409
389
  return ImageGenerationResponse(
410
- status="error",
390
+ status='error',
411
391
  message=str(e),
412
392
  paths=[],
413
393
  prompt=prompt,