The Future is Here: Exploring the Possibilities of Doing Business with AI (Part 4)

Today we would like to finish the web application (without SEO and advertisments), so that we have a product that actually works.

The following needs to be fixed:

  • SSL for www.usmalbilder.ch
  • Improve the layout / grid
  • Handle image thumbnails of the generated AI images

SSL

I’m hosting my website with hosttech.ch, they provide a typical plesk admin UI. Enabling proper SSL is actually quite straight forward: click on the free let’s encrypt configuration and fill in which parts / domains you want to protect – that’s it!

After these steps the website is having a proper SSL configuration:

We can also check the actual certificate in the browser:

All good!

HTTP vs HTTPS

If we would now visit http://www.usmalbilder.ch, we would still not get an SSL connection. We should also configure forwarding all requests to HTTP to HTTPS. This is done by a simple switch in plesk as well:

Done!

Improving the website

Configuring SSL isn’t a lot of fun, but highly recommended, and not that hard if you use a hosting provider (usually).

Having a simple black / white layout with only few colors seems to be a good choice for a page that provides coloring picture – I think. But we should make better use of the real estate. I also noticed the default behavior for the SimpleGrid is not doing any auto-wrapping – it just scales the content and it looks pretty unusable on a mobile device.

In the last blog post I positively mentioned the built in styling system, that allows me to seamlessly set margins, paddings and stuff. I think it is really simple, but exactly this makes it so powerful.

This is how you can set the padding on a component, easily:

<SimpleGrid columns={4} spacing={10} padding={10}>

Responsive Layout

It turns out that having a better and more responsive layout is really easy too. We can just define on the component, how it should behave. For instance we can pass different configurations for the various layouts from xs (extra small) to xl (extra large). Best consoult the documentation for the details, but for us this works well enough:

   <SimpleGrid columns={{lg: 4, md: 3, sm: 1}} spacing={10} padding={10}>

This tells the browser in the end to only use 1 column on a small screen (or smaller). On a medium sized we use 3 and on a large (or larger) 4 columns.

Automatically create thumbnails

We will generate images using generative AI (more on that later). But on the overview page, we need a smaller file / a thumbnail to load the page quicker. We wanted to automate this step and wrote a little script for that (with some help of ChatGPT)

  • We can basically have all our full size images in the public folder, ready to be downloaded
  • We generate the thumbnails using a script
  • We let the script also generate the JSON used by React to render the grid

This way we can just add images to our images folder and let the script do the rest.

We are using sharp to resize the images. 🙂 Works like a charm and we integrated it as well into our build pipeline.

const fs = require("fs");
const sharp = require("sharp");

const sourceDir = "./public/images";
const targetDir = "./public/images/thumbnails";

if (!fs.existsSync(targetDir)) {
  fs.mkdirSync(targetDir);
}

const db = [];

fs.readdirSync(sourceDir).forEach((file) => {
  if (/\.(jpg|jpeg|png|gif)$/i.test(file)) {
    // Generate the thumbnail file name and URL
    const thumbnailName = file.replace(/\.[^/.]+$/, "") + "_thumb.png";
    const thumbnailUrl = `images/thumbnails/${thumbnailName}`;
    // Generate the download URL
    const downloadUrl = `images/${file}`;
    // Generate the full paths for the source and target files
    const sourcePath = `${sourceDir}/${file}`;
    const targetPath = `${targetDir}/${thumbnailName}`;
    // Create the thumbnail and save it to the target directory
    sharp(sourcePath)
      .resize(200)
      .toFile(targetPath, (err, info) => {
        if (err) {
          console.error(err);
        } else {
          console.log(`${sourcePath} -> ${targetPath}`);
          // Add the image info to the database array
          db.push({ downloadUrl, thumbnailUrl });
          // Write the database to a JSON file
          const dbJson = JSON.stringify({ images: db }, null, 2);
          fs.writeFileSync("public/db.json", dbJson);
        }
      });
  }
});

This will generate us all the images we need..

..and we get the db.json ready to use!

That’s it for today, next time we can focus on generating nice content (we would like to start with around 50 images).

Leave a comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.