Build Flair AI

KINDAreplaces $8/mosaves $96/yrback to the verdict

0%0 of 17 items done

Saved on this device only. Tick prerequisites first, then work the phases in order · do not start one until the checks above it pass.

A local workspace for product scenes that drives your own model server, whose hard problems are keeping the real product pixels untouched, recording enough of each job that next month's rerun produces the same picture, and never letting a licence you did not read decide whether you can sell the result.

estimated effort weekendthe files for this build are in the project pack

RuntimeA local service with a small frontend, bound to localhost, no accountsBackendYour own model server called over its HTTP API, one endpoint in configurationCompositingThe masked product pasted back over the generated scene at full resolutionProvenanceWorkflow graph, seed, sampler settings and model file hashes stored with every outputRegistryEvery model file recorded with its licence, source and a commercial flagStorageOutputs on local disk with a sidecar per image, a ceiling and a retention rule

Before step 1

Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.

  1. installfree

    Why Runs the service, the job queue and the compositing.

    Get it python.org or your package manager. open ↗

    Verify python3 --version prints 3.12 or higher

  2. installfree

    Why This build submits jobs and stores provenance; it does not implement diffusion, and the backend is the one dependency it cannot work without.

    Get it Install ComfyUI or an equivalent server that exposes a job API on your own machine. open ↗

    Verify A minimal workflow submitted over HTTP returns an image

  3. have readyfree if you own it, hourly if rented

    Why The memory estimate feature exists because the alternative is discovering the limit during a two hundred image batch.

    Get it A card with the memory your chosen checkpoint needs, or a rented machine you control.

    Verify A single generation at your target resolution completes without swapping

  4. have readyfree, subject to the licence

    Why The licence determines whether the output can be used commercially, and the terms for some popular weights have been revised more than once.

    Get it Download the weights and save the licence text and URL beside each file.

    Verify Every model in the registry has a licence, a source URL and a commercial flag

  5. decidefree

    Why These three decide what is shippable, what is deleted and what can run, and each is enforced in code.

    Get it Write down the permitted mask difference, how long non-favourites are kept, and which projects are commercial.

    Verify All three appear in the configuration and in tests

Data model

Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.

- models(id, filename, sha256, kind, licence, licence_url, commercial_ok, added_at) · kind is checkpoint, lora, vae or upscaler
- projects(id, name, commercial, product_asset_id, created_at) · the commercial flag is what the licence gate reads
- assets(id, project_id, kind, path, sha256, width, height) · kind is source_photo, mask, prop or reference
- jobs(id, project_id, workflow_sha256, workflow_json, seed, sampler, steps, cfg, model_ids_json, backend_version, state, attempts, started_at, finished_at, last_error)
- outputs(id, job_id, path, sha256, width, height, mask_diff_pct, sidecar_path, favourite, note)
- batches(id, project_id, plan_json, total, completed, failed, created_at) · so a run that dies at image sixty knows which sixty exist
- An output is shippable only when every model in its job is permitted for that project's commercial flag and its mask difference is under the stated threshold.

Environment variables

These go in a .env file the app reads at startup. The pack's .env.example is this table as a file · copy it, never commit the filled-in version.

VariableNeededExampleWhere the value comes from
APP_PORTrequired8020Localhost only. There is no account system and there should not be.
BACKEND_URLrequiredhttp://127.0.0.1:8188Your own generation server. The only place jobs are ever submitted.
DATABASE_PATHrequired./data/studio.dbProjects, models, jobs, outputs and batch plans.
OUTPUT_DIRrequired./data/outputsImages and their sidecars, kept together.
OUTPUT_MAX_BYTESrequired214748364800The disk ceiling. Retention runs against it rather than against hope.
MASK_DIFF_THRESHOLD_PCTrequired0.5Above this, the product pixels moved and the output is not shippable.
JOB_TIMEOUT_SECONDSrequired600One variant fails and the batch continues.
RETAIN_NON_FAVOURITE_DAYSrequired30Favourites are kept. The other thousands are not.

The build, in order

  1. A cutout that keeps the actual product

    The generated scene changes everything except the item being sold.

    1. Every rerun months later needs exactly this mask.

      Files src/masking.py

    2. The generated frame is a background, not a photograph of your goods.

      Files src/composite.py

    3. This is the automated version of a second pair of eyes.

      Files src/composite.pytests/test_mask_diff.py

    done when · tick each as it passes
    watch out
    • Running image-to-image over the whole frame at a strength high enough to make the background interesting also redraws the label, invents a plausible logo and smooths the texture of the material, and the result is a photograph of a product that does not exist. Generate the background, composite the real pixels back, and let the mask difference measurement be the thing that catches you rather than a customer.
  2. Jobs you can actually run again

    An output records everything needed to reproduce it, and says so when it cannot.

    1. The graph is the recipe and the seed is one ingredient.

      Files src/jobs.pysrc/backend.py

    2. Names are reused; contents are not.

      Files src/registry.pytests/test_rerun.py

    3. An honest mismatch is far more useful than a silent one.

      Files src/rerun.py

    done when · tick each as it passes
    watch out
    • Recording the seed and the prompt but not the workflow graph or the model file hashes gives you a rerun that looks like it should work and produces a different picture, because a node was updated, a LoRA was replaced with a same-named file, or the sampler default changed underneath you. Store the graph and the hashes, and treat a differing rerun as information rather than a failure to hide.
  3. The licence gate and the missing-file problem

    A model cannot run in a project its licence forbids, and a missing file is never a silent substitution.

    1. A blank licence field is how a legal problem is stored.

      Files src/registry.py

    2. The warning is read once and dismissed forever.

      Files src/gate.pytests/test_licence_gate.py

    3. The backend's helpfulness is the problem here.

      Files src/jobs.py

    done when · tick each as it passes
    watch out
    • A workflow referencing a LoRA that is not installed often runs anyway, because the backend skips the node or falls back to the base model, so two hundred images are produced in the wrong style and nobody notices until they are compared against the first test image. Check every referenced model exists by hash before submitting, and refuse the job rather than letting the backend improvise.
  4. Batches that survive the hardware

    A run of two hundred variants can fail at sixty and continue from sixty.

    1. The plan is what makes resume possible at all.

      Files src/batch.py

    2. One card, one job, and a stall that ends.

      Files src/batch.pytests/test_resume.py

    3. Out of memory is a normal Tuesday, not an exception.

      Files src/backend.py

    done when · tick each as it passes
    watch out
    • Firing the whole batch at the backend at once means an out-of-memory failure halfway through takes the process with it, and since nothing recorded which variants had already been produced the only option is to run all two hundred again, several hours of a card you are paying for one way or another. Persist the plan first, execute one at a time, and make resume the default.
what this build does not replace
after v1, if you want it

Need the files? The project pack on the verdict page hands your agent the whole brief · more generative media.