Skip to content
FLORA DocsGo to app

Iterate on outputs

Re-run a Technique using previous outputs as image references.

After generating a grid, the natural next step is “give me more like #4 and #7.” FLORA Techniques accept image URLs as inputs, so prior outputs can drive new runs — no re-uploading required.

What you’ll build: a function that takes a list of “favorite” output URLs and generates N new variants anchored to them.

import Flora from '@flora-ai/flora';
const client = new Flora({ apiKey: process.env.FLORA_API_KEY });
async function iterate(
slug: string,
favorites: string[], // URLs from a previous run
directive: string,
count = 5,
) {
const run = await client.techniques.runs.create(slug, {
inputs: [
{ id: 'directive', type: 'text', value: directive },
...favorites.map((url, i) => ({
id: `reference_${i}`,
type: 'imageUrl' as const,
value: url,
})),
{ id: 'count', type: 'text', value: String(count) },
],
mode: 'async',
});
return pollUntilDone(run.runId, slug);
}
async function pollUntilDone(runId: string, slug: string) {
while (true) {
const result = await client.techniques.runs.retrieve(runId, { techniqueId: slug });
if (result.status === 'completed') return result.outputs.map((o: any) => o.url);
if (result.status === 'failed') throw new Error(result.errorMessage);
await new Promise((r) => setTimeout(r, 2000));
}
}
// Use it
const previousGrid = [
'https://ik.imagekit.io/flora/run_abc/output_3.png', // #4
'https://ik.imagekit.io/flora/run_abc/output_6.png', // #7
];
const moreLikeThese = await iterate(
'thumbnail-v3',
previousGrid,
'Lock the lighting and composition from the references. Explore copy and color.',
10,
);
func iterate(
ctx context.Context,
c *flora.Client,
slug string,
favorites []string,
directive string,
count int,
) ([]string, error) {
inputs := []flora.TechniqueRunNewParamsInput{
{ID: "directive", Type: "text", Value: directive},
{ID: "count", Type: "text", Value: fmt.Sprint(count)},
}
for i, url := range favorites {
inputs = append(inputs, flora.TechniqueRunNewParamsInput{
ID: fmt.Sprintf("reference_%d", i), Type: "imageUrl", Value: url,
})
}
run, err := c.Techniques.Runs.New(ctx, slug, flora.TechniqueRunNewParams{
Inputs: inputs,
Mode: flora.TechniqueRunNewParamsModeAsync,
})
if err != nil {
return nil, err
}
return pollUntilDone(ctx, c, slug, run.RunID)
}

The input IDs above (directive, reference_0, reference_1, count) are illustrative. Real Techniques expose their own input schema. Always inspect first:

const technique = await client.techniques.retrieve('thumbnail-v3');
console.log(technique.inputs);
// [
// { id: 'brief', type: 'text', name: 'Brief' },
// { id: 'image_references', type: 'imageUrl[]', name: 'Reference images', multiple: true },
// { id: 'count', type: 'text', name: 'Number of outputs' },
// ]

If a Technique accepts an array input (type: 'imageUrl[]'), pass all references under one input:

inputs: [
{ id: 'image_references', type: 'imageUrl[]', value: favorites },
]

If it accepts individual reference slots (reference_0, reference_1), pass each separately as in the example above.

This pattern composes cleanly with itself. Iterate, pick new favorites, iterate again:

let pool = await generateGrid('Smart living, simple. Warm minimalism.', 9);
for (let round = 0; round < 3; round++) {
const favorites = await pickFavorites(pool); // your own UI / CLI prompt
pool = await iterate('thumbnail-v3', favorites, 'tighten composition', 6);
}

Output URLs are long-lived but not permanent — re-running this script weeks later with the same URLs may fail. For long-lived workflows, either:

  1. Re-generate from the original brief.
  2. Download favorites and re-upload as permanent assets, then reference those URLs.