Integrating fal.ai

fal.ai is an AI inference platform with popular models such as Stable Diffusion XL, ControlNet, Whisper available as ready-to-use APIs so that you can easily integrate them into your applications.

This tutorial will guide you through the process of setting up the fal.ai API to generate an image using the SDXL model and integrating it into your Appwrite project.

Prerequisites

1

Create new function

Head to the Appwrite Console then click on Functions in the left sidebar and then click on the Create Function button.

Create function screen

Create function screen

  1. In the Appwrite Console's sidebar, click Functions.

  2. Click Create function.

  3. Under Connect Git repository, select your provider.

  4. After connecting to GitHub, under Quick start, select the Node.js starter template.

  5. In the Variables step, add the FAL_API_KEY, generate it here.

  6. Follow the step-by-step wizard and create the function.

2

Add fal.ai SDK

Once the function is created, clone the function and open it in your development environment.

Once you have the repository open, you can install the fal.ai SDK by running the following command in your terminal:

Bash
npm install @fal-ai/serverless-client
3

Create utility function

In this example, the function will be able to accept both GET and POST requests.

For the GET request, return a static HTML page. It will use AlpineJS to make a POST request to the function. The POST request will use the fal.ai SDK to make a request to the fal.ai API.

Write the code to return a static HTML page. Create a new src/utils.js file with the following code:

JavaScript
import path from 'path';
import { fileURLToPath } from 'url';
import fs from 'fs';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const staticFolder = path.join(__dirname, '../static');

export function getStaticFile(fileName) {
  return fs.readFileSync(path.join(staticFolder, fileName)).toString();
}
4

Handle GET request

Write our GET request handler in the src/main.js file. This handler will return the static HTML page.

JavaScript
import { getStaticFile } from './utils.js';

export default async ({ req, res, error }) => {
  if (req.method === 'GET') {
    return res.send(getStaticFile('index.html'), 200, {
      'Content-Type': 'text/html; charset=utf-8',
    });
  }
};
5

Create static page

Create the static HTML page that the function will serve. Create a new file at static/index.html with some HTML boilerplate:

HTML
<!doctype html>
<html lang="en">
</html>

Within the <html> tag, add a <head> tag with the necessary meta tags, stylesheets, and scripts:

HTML
<head>
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>fal.ai Demo</title>

  <script>
    async function onSubmit(prompt, type) {
      const response = await fetch('/', {
        method: 'POST',
        body: JSON.stringify({ prompt, type }),
        headers: {
          'Content-Type': 'application/json',
        },
      });

      const json = await response.json();

      if (!json.ok || json.error) {
        alert(json.error);
      }

      return json;
    }
  </script>

  <script src="//unpkg.com/alpinejs" defer></script>

  <link rel="stylesheet" href="https://unpkg.com/@appwrite.io/pink" />
  <link rel="stylesheet" href="https://unpkg.com/@appwrite.io/pink-icons" />
</head>

And after the </head> tag, add our <body> tag with the following content:

HTML
<body class="theme-dark">
  <main class="main-content">
    <div class="top-cover u-padding-block-end-56">
      <div class="container">
        <div class="u-flex u-gap-16 u-flex-justify-center u-margin-block-start-16">
          <h1 class="heading-level-1">fal.ai demo</h1>
          <code class="u-un-break-text"></code>
        </div>
        <p class="body-text-1 u-normal u-margin-block-start-8" style="max-width: 50rem">
          Use this page to test your implementation with fal.ai. Enter
          text and receive the model output as a response.
        </p>
      </div>
    </div>
    <div class="container u-margin-block-start-negative-56"
      x-data="{ prompt: '', result: { src: '' }, loading: false }">
      <div class="card u-flex u-gap-24 u-flex-vertical">
        <div class="u-flex u-cross-center u-gap-8">
          <div class="input-text-wrapper is-with-end-button u-width-full-line">
            <input x-model="prompt" type="search" placeholder="Prompt" />
            <div class="icon-search" aria-hidden="true"></div>
          </div>
          <button class="button" x-bind:disabled="loading"
            x-on:click="async () => { loading = true; result = { src: '' }; try { result = await onSubmit(prompt) } catch(err) { console.error(err); } finally { loading = false; } }">
            <span class="text">Generate</span>
          </button>
        </div>
        <template x-if="answer.type">
          <div class="u-flex u-flex-vertical u-gap-12">
            <div class="u-flex u-flex-vertical u-gap-12 card">
              <div class="u-flex u-gap-12">
                <h5 class="eyebrow-heading-2">Result:</h5>
              </div>
              <img class="u-max-width-400" x-bind:src="result.src" alt="fal.ai output" />
            </div>
          </div>
        </template>
      </div>
    </div>
  </main>
</body>

This HTML form will allow users to input a prompt and generate an image using the fal.ai API. The AlpineJS script handles the form submission and display the result.

6

Handle POST Request

Add methods necessary to integrate with fal.ai's API.

Import the fal.ai SDK at the top of the main.js file:

JavaScript
import * as fal from '@fal-ai/serverless-client';

Handle the POST requests to the function. Initialize the fal.ai SDK at the end of the handler function:

JavaScript
fal.config({ credentials: process.env.FAL_API_KEY });

Make the request to generate an image using the SDXL model, and return the result:

JavaScript
const result = await fal.subscribe('fal-ai/fast-sdxl', {
  input: {
    prompt: req.body.prompt,
  },
});
return res.json({ ok: true, src: result.images[0].url });

With the function complete, deploy it to Appwrite by pushing the changes to your repository.

Additional models can be found in the fal.ai model catalogue.

7

Test the function

Now that the function is deployed, test it by visiting the function URL in a browser. The UI created earlier will be visible. To test it, write a prompt and click the submit button, after a brief the completion should appear below the input.

Testing the function