FLUX.1 Kontext Max as a custom tool for Discourse AI

Last week, Flux released a very impressive model called FLUX.1 Kontext.

Announcement Blog by Black Forest Labs

It is particularly interesting because it is slightly cheaper than the OpenAI models, which are available via the designer persona, and it has excellent results.

In Action

In this post, I wanted to share how you can add the tool to do so, and walk through some advanced features in Discourse AI.

The tool to do the job

To define the tool, you will need to sign up at https://bfl.ai, generate an API key, and purchase some credits.

With this in place:

Define a new custom tool in /admin/plugins/discourse-ai/ai-tools

Description

Advanced image creator and editor - capable of editing Discourse uploads denoted as upload://…

Summary

Edits or creates images using FLUX Kontext

Parameters

  • prompt: string: Describe what you want to generate. 2-3 sentences, be detailed for best results (required)
  • input_image: string: an upload://… which you wish to modify
  • seed: number: The random seed. If you wish to keep outputs in the same style, keep the number the same
  • aspect_ratio: string: The aspect ratio of the image, must be between 21:9 and 9:21. For square images, use 1:1. Defaults to 16:9

Script

const apiKey = YOUR_API_KEY;
const apiUrl = "https://api.us1.bfl.ai/v1/flux-kontext-max"; 

function invoke(params) {
  let seed = parseInt(params.seed);
  if (!(seed > 0)) {
    seed = Math.floor(Math.random() * 1000000) + 1;
  }

  const body = {
    prompt: params.prompt,
    seed: seed,
    aspect_ratio: params.aspect_ratio || "16:9"
  };

  // Add input_image if provided
  if (params.input_image) {
    body.input_image = upload.getBase64(params.input_image);
  }

  const result = http.post(apiUrl, {
    headers: {
      "x-key": apiKey,
      "Content-Type": "application/json"
    },
    body: JSON.stringify(body)
  });

  if (result.status !== 200) {
    return { error: `API request failed with status ${result.status}`, body: body };
  }
  
  const parsed = JSON.parse(result.body);
  const pollingUrl = parsed.polling_url;
  
  let pollResult = JSON.parse(http.get(pollingUrl).body);
  let checks = 0;
  
  while (pollResult.status === "Pending" && checks < 30) {
      sleep(1000);
      pollResult = JSON.parse(http.get(pollingUrl).body);
      checks++;
  } 
  
  let image;
  
  if (pollResult.status === "Ready") {
      const imageUrl = pollResult.result.sample;
      const base64 = http.get(imageUrl, { base64Encode: true }).body;
      image = upload.create("generated_image.jpg", base64);
      
      const raw = `\n\n![${params.prompt}](${image.short_url})`;
  
      chain.setCustomRaw(raw);
   }
  
  return { 
    result: "Image generated successfully", 
    seed: seed,
    aspect_ratio: params.aspect_ratio || "16:9",
    output_image: image?.short_url
  };
}

function details() {
  return "Generated image using Segmind's Flux Kontext Max model";
}

Commentary

This showcases some of the more advanced tool facilities, including quite a few added in https://github.com/discourse/discourse-ai/pull/1391, which will be required prior to this working.

  1. Making POST requests with http.post — custom tools can post to any URL!
const result = http.post(apiUrl, {
  headers: {
    "x-key": apiKey,
    "Content-Type": "application/json"
  },
  body: JSON.stringify(body)
});
  1. Support for base64-encoded payloads in the API

Get Base64 encoded upload:

body.input_image = upload.getBase64(params.input_image);

Get the result of an HTTP request in Base64:

const base64 = http.get(imageUrl, { base64Encode: true }).body;

Create an upload from a base64 string:

image = upload.create("generated_image.jpg", base64);
  1. Forcing rendering on a post to avoid guesswork and save tokens:
chain.setCustomRaw(raw);
  1. The API involves polling; Discourse AI provides a sleep primitive to wait between polls:
while (pollResult.status === "Pending" && checks < 30) {
  sleep(1000);
  pollResult = JSON.parse(http.get(pollingUrl).body);
  checks++;
}

Hope you find this helpful! Feel free to ask questions or share ideas!

4 Likes