DEV Community

Mari for Fiberplane

Posted on • Originally published at fiberplane.com

Building Honcanator: The AI Goose Generator

🪿 Register for November's HONCathon here - ship apps, win prizes - sponsored by Cloudflare, Drizzle, Fiberplane, and Neon


Recently we needed some example apps to showcase how to build a HONC app with Fiberplane Studio for our November Honcathon, so I decided to build Honcanator: The AI goose generator.

The example app is pretty simple and uses a standard HONC setup (Hono, Drizzle, Neon, and Cloudflare Workers).

To create and store images, we also needed to use two Cloudflare services:

  • Cloudflare R2 as object storage (like AWS S3)
  • Cloudflare AI to generate images

Let's take a quick look at how I've built this app.

Configuring the basics

In order to use Cloudflare services like R2 and AI, we have to configure some additional Cloudflare bindings in our Worker.
That is as simple as editing the wrangler.toml:

name = "honc-neon-template"
compatibility_date = "2024-10-28"
compatibility_flags = [ "nodejs_compat" ]

[observability]
enabled = true

[[r2_buckets]]
binding = "R2_BUCKET"
bucket_name = "geese"

[ai]
binding = "AI"
Enter fullscreen mode Exit fullscreen mode

Then we can add it to our bindings in Hono:

type Bindings = {
  DATABASE_URL: string;
  R2_BUCKET: R2Bucket;
  AI: Ai;
};
Enter fullscreen mode Exit fullscreen mode

The R2Bucket and Ai types are Cloudflare special types which will give you a typed interface for interacting with these services.

Routes

The majority of our routes were simple CRUD routes which simply query the database and return some stuff from it so I won't bore you with the boring part, lets get to the actual interesting route: The creation endpoint.

The first few lines of the POST /api/geese/:name route are simply a check to see whenever a goose with that name already exists.

app.get("/api/geese/:name", async (c) => {
  const { name } = c.req.param();

  const sql = neon(c.env.DATABASE_URL);
  const db = drizzle(sql);

  const goose = await db.select().from(geese).where(eq(geese.name, name));

  if (goose.length === 0) {
    return c.json({ error: "doesnt_exist" }, 404);
  }
  //...
})
Enter fullscreen mode Exit fullscreen mode

After those checks are done, we get to the really interesting part: Making geese!

Image generation

This is where Cloudflare really shines. Creating an image is as simple
as three lines of code:

const model = "@cf/black-forest-labs/flux-1-schnell" as BaseAiTextToImageModels;
const prompt = `Please generate a image of a goose. Its name is ${name}. Make it in the style of comic or anime please`;

const response = await c.env.AI.run(model, {
  prompt,
});
Enter fullscreen mode Exit fullscreen mode

The list of models available on Cloudflare AI can be found here. The list of image
generation models is pretty small at the moment, there is currently a few Stable Diffusion models and Flux-1-Schnell model, which we are using in this example.

The response from the AI call comes back as a base64 encoded string, so we'll use the built-in Node.js Buffer to get something that we can work with:

const base64image = response.image;
const buffer = Buffer.from(base64image, "base64");
Enter fullscreen mode Exit fullscreen mode

⚠️ Note: Cloudflare Workers's types are a little funky at the moment for AI models, so the code above might show a red squiggly error line in your IDE. The issue is being tracked here.

Saving to object storage

With our generated image now available to us as a Buffer, putting it into R2 is as simple as writing one line of code:

await c.env.R2_BUCKET.put(`${name}.png`, buffer);
Enter fullscreen mode Exit fullscreen mode

This shows how powerful the Hono bindings for Cloudflare are, we have just generated an image and stored it in object storage with like 6 lines of code.

Retrieving it is as simple as:

const image = await c.env.R2_BUCKET.get(`${name}.png`);
Enter fullscreen mode Exit fullscreen mode

which comes in handy for our GET /api/geese/:name route.

Using Fiberplane Studio, we can inspect the generated image for any of our geese and see a trace of the request, with the Neon database call and the call to R2, in the timeline.

Fiberplane Studio trace of the Honcanator app

Parting words

In conclusion, making a small app which generates images and stores them in object storage and a database really is no big feat with the HONC stack, which means you'll be able to build powerful goose-themed apps in no time.

To wrap things up, the code for everything discussed in this blog post can be found on GitHub, available for you to adapt and build upon how you wish:

🔗 Check out the code on GitHub

Top comments (0)