DEV Community

Cover image for Part 3: AI Art at Scale: Generating Fantasy Images with Bedrock, Stability AI, and Amazon S3
Ashley Armstrong
Ashley Armstrong

Posted on

Part 3: AI Art at Scale: Generating Fantasy Images with Bedrock, Stability AI, and Amazon S3

The bot could think. The bot could write. The bot could even publish. But in a social media landscape dominated by visuals, words alone weren't enough.


The Missing Piece

By this point, WizardThoughts had evolved significantly.

The platform could:

✅ Generate original content

✅ Create engagement-focused posts

✅ Store everything in DynamoDB

✅ Publish automatically to X

From a technical perspective, things were working.

From a social media perspective, something was missing.

The posts looked empty.

I had built a content engine.

What I hadn't built was a visual identity.

And on modern social platforms, visuals often determine whether people stop scrolling long enough to read the content.

The next challenge became obvious:

Every post needed its own unique piece of artwork.


Why Images Matter

Take these two posts:

Version One

Every great wizard begins as a student.
Enter fullscreen mode Exit fullscreen mode

Version Two

Every great wizard begins as a student.
Enter fullscreen mode Exit fullscreen mode

Accompanied by:

  • An enchanted library
  • Floating spell books
  • Golden magical lighting
  • A student surrounded by ancient knowledge

The words haven't changed.

The experience has.

Images create context.

They create atmosphere.

Most importantly, they create attention.


Exploring Image Generation

Since text generation was already running through Amazon Bedrock, my first instinct was to stay inside the Bedrock ecosystem.

The ideal workflow looked like:

Generate Quote
       ↓
Generate Image Prompt
       ↓
Generate Artwork
       ↓
Publish Together
Enter fullscreen mode Exit fullscreen mode

Simple.

At least in theory.


The Model Hunt

The first surprise came from discovering that not all image models are available everywhere.

While experimenting, I discovered models that:

  • Existed in one AWS region
  • Didn't exist in another
  • Were marked as legacy
  • Required different API formats

Something as simple as changing AWS regions suddenly became important.

I found myself bouncing between:

London
Ireland
US East
US West
Enter fullscreen mode Exit fullscreen mode

trying to discover which models were actually available.

For a while, my most common error looked like this:

The provided model identifier is invalid.
Enter fullscreen mode Exit fullscreen mode

Nothing was wrong with the code.

The model simply didn't exist in that region.


The Nova Canvas Detour

Initially, I experimented with Amazon Nova Canvas.

On paper, it seemed perfect.

An AWS-native image generation service integrated directly into Bedrock.

Then reality arrived.

The model was marked as legacy.

Attempts to invoke it resulted in messages like:

Access denied.
This model is marked as Legacy.
Enter fullscreen mode Exit fullscreen mode

The lesson was frustrating but useful:

Just because a service appears in a catalogue doesn't mean it is the right service for your account.


Enter Stability AI

Eventually I shifted towards Stability AI's image models through Bedrock.

These were actively supported and capable of generating entirely original artwork from text prompts.

This introduced a new architecture:

GenerateContent
        ↓
Bedrock
        ↓
Quote + Image Prompt
        ↓
GenerateImage
        ↓
Stability AI
        ↓
PNG Image
Enter fullscreen mode Exit fullscreen mode

The workflow was finally beginning to resemble the original vision.


Building the GenerateImage Lambda

The GenerateContent Lambda already produced output like:

{
  "quote": "Every wizard begins as a student.",
  "imagePrompt": "Young wizard studying glowing spell books inside an enchanted library"
}
Enter fullscreen mode Exit fullscreen mode

Now I needed a second Lambda.

Its job was simple:

  1. Read pending content from DynamoDB
  2. Use the image prompt
  3. Generate artwork
  4. Save the result

The process looked like this:

DynamoDB
        ↓
Image Prompt
        ↓
Stability AI
        ↓
Base64 Image
        ↓
PNG File
        ↓
S3
Enter fullscreen mode Exit fullscreen mode

Prompt Engineering, Part Two

Creating image prompts required a different mindset from creating text.

A poor image prompt looked like:

Wizard library
Enter fullscreen mode Exit fullscreen mode

Technically valid.

Visually boring.

A stronger prompt looked like:

Ancient enchanted library, floating spell books,
golden magical lighting, cinematic fantasy artwork,
rich colours, volumetric light, highly detailed,
social media quality, no text
Enter fullscreen mode Exit fullscreen mode

The difference was dramatic.

The more descriptive the prompt became, the more consistent the results became.


Another Unexpected Problem

The image generation worked.

The upload didn't.

After successfully creating images, I suddenly started receiving:

PermanentRedirect
Enter fullscreen mode Exit fullscreen mode

errors from S3.

At first I assumed permissions were broken.

They weren't.

The issue was embarrassingly simple.

My bucket was located in:

eu-west-2
Enter fullscreen mode Exit fullscreen mode

while the code was trying to access:

eu-west-1
Enter fullscreen mode Exit fullscreen mode

One region mismatch.

Hours of debugging.

A classic cloud engineering lesson.


The S3 Layer

Once the region mismatch was fixed, every generated image flowed into an S3 bucket.

The storage structure looked like:

wizardthoughts-images/
       ├── post-123.png
       ├── post-124.png
       ├── post-125.png
Enter fullscreen mode Exit fullscreen mode

Each image became its own reusable asset.

This provided several benefits:

  • Durable storage
  • Easy retrieval
  • Lower complexity
  • Simpler workflow management

Most importantly, it separated content generation from content publishing.


Updating DynamoDB

The image generation process wasn't complete until DynamoDB knew about it.

A successful image generation updated the record:

{
  "PostId": "post-123",
  "Status": "Pending",
  "ImageStatus": "Complete",
  "ImageUrl": "https://bucket.s3.amazonaws.com/post-123.png"
}
Enter fullscreen mode Exit fullscreen mode

This allowed downstream services to know exactly what stage every post had reached.

The database effectively became a workflow engine.


Building a State-Driven System

As more functionality was added, an interesting pattern emerged.

Every component only needed to know one thing:

What is the current state?

The workflow became:

Pending
       ↓
Image Pending
       ↓
Image Complete
       ↓
Published
Enter fullscreen mode Exit fullscreen mode

No service needed to know what happened before.

No service needed to care what happened next.

Everything was driven entirely by state transitions.

That dramatically simplified the architecture.


Seeing the First Results

The most satisfying moment came when the first generated image appeared.

Not downloaded.

Not manually uploaded.

Not created in a design tool.

Generated automatically.

Stored automatically.

Ready for publishing.

The project suddenly felt real.

The content wasn't just being written anymore.

It was being illustrated.

Every quote now had a matching visual story.


Lessons Learned

Three lessons stood out more than anything else.

1. Images Are a Force Multiplier

Good content becomes significantly more engaging when paired with relevant visuals.

The artwork amplified the message.

It didn't replace it.


2. AI Image Generation Is Prompt Engineering

The same lesson from text generation applied to images.

Better prompts produced better outcomes.

The model wasn't the limiting factor.

The instructions were.


3. Regions Matter

Cloud services are rarely as universal as they appear.

Always verify:

  • Region support
  • Model availability
  • Service limitations

before writing code.

It will save hours of debugging.


What's Next?

By this point, WizardThoughts could:

✅ Generate content

✅ Generate image prompts

✅ Create original artwork

✅ Store assets in S3

✅ Track workflow state in DynamoDB

The system was finally capable of producing complete content packages.

But one final challenge remained.

Everything still required orchestration.

The content engine needed a conductor.

In Part 4, we'll complete the journey by introducing EventBridge scheduling, automated publishing, workflow orchestration, and the architecture that transformed WizardThoughts into a fully autonomous social media platform.


Next: Part 4 — Going Fully Autonomous: EventBridge, DynamoDB, and Automated Publishing

Top comments (0)