Skip to content

Commit 22d8a35

Browse files
committed
2 parents 0d7f79b + 478338d commit 22d8a35

4 files changed

Lines changed: 93 additions & 36 deletions

File tree

README.md

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
# FLUX
22

33
by Black Forest Labs: https://blackforestlabs.ai
4+
by Black Forest Labs: https://blackforestlabs.ai. Documentation for our API can be found here: [docs.bfl.ml](https://docs.bfl.ml/).
45

56
![grid](assets/grid.jpg)
67

78
This repo contains minimal inference code to run text-to-image and image-to-image with our Flux latent rectified flow transformers.
89

910
### Inference partners
1011

11-
We are happy to partner with [Replicate](https://replicate.com/), [FAL](https://fal.ai/) and [Mystic](https://www.mystic.ai). You can sample our models using their services.
12+
We are happy to partner with [Replicate](https://replicate.com/), [FAL](https://fal.ai/), [Mystic](https://www.mystic.ai), and [Together](https://www.together.ai/). You can sample our models using their services.
1213
Below we list relevant links.
1314

1415
Replicate:
@@ -32,6 +33,13 @@ Mystic:
3233
- https://www.mystic.ai/black-forest-labs/flux1-dev
3334
- https://www.mystic.ai/black-forest-labs/flux1-schnell
3435

36+
Together:
37+
38+
- https://api.together.xyz/playground/image/black-forest-labs/FLUX.1-schnell-Free (ends December 31, 2024)
39+
- https://api.together.xyz/playground/image/black-forest-labs/FLUX.1-schnell
40+
- https://api.together.xyz/playground/image/black-forest-labs/FLUX.1.1-pro
41+
- https://api.together.xyz/playground/image/black-forest-labs/FLUX.1-pro
42+
3543
## Local installation
3644

3745
```bash
@@ -46,7 +54,8 @@ pip install -e ".[all]"
4654

4755
We are offering three models:
4856

49-
- `FLUX.1 [pro]` the base model, available via API
57+
- `FLUX1.1 [pro]` available via API only
58+
- `FLUX.1 [pro]` available via API only
5059
- `FLUX.1 [dev]` guidance-distilled variant
5160
- `FLUX.1 [schnell]` guidance and step-distilled variant
5261

@@ -55,6 +64,7 @@ We are offering three models:
5564
| `FLUX.1 [schnell]` | https://huggingface.co/black-forest-labs/FLUX.1-schnell | [apache-2.0](model_licenses/LICENSE-FLUX1-schnell) | a9e1e277b9b16add186f38e3f5a34044 |
5665
| `FLUX.1 [dev]` | https://huggingface.co/black-forest-labs/FLUX.1-dev | [FLUX.1-dev Non-Commercial License](model_licenses/LICENSE-FLUX1-dev) | a6bd8c16dfc23db6aee2f63a2eba78c0 |
5766
| `FLUX.1 [pro]` | Only available in our API. |
67+
| `FLUX1.1 [pro]` | Only available in our API. |
5868

5969
The weights of the autoencoder are also released under [apache-2.0](https://huggingface.co/datasets/choosealicense/licenses/blob/main/markdown/apache-2.0.md) and can be found in either of the two HuggingFace repos above. They are the same for both models.
6070

@@ -158,7 +168,7 @@ To learn more check out the [diffusers](https://huggingface.co/docs/diffusers/ma
158168

159169
## API usage
160170

161-
Our API offers access to the pro model. It is documented here:
171+
Our API offers access to our models. It is documented here:
162172
[docs.bfl.ml](https://docs.bfl.ml/).
163173

164174
In this repository we also offer an easy python interface. To use this, you
@@ -175,8 +185,8 @@ Usage from python:
175185
from flux.api import ImageRequest
176186

177187
# this will create an api request directly but not block until the generation is finished
178-
request = ImageRequest("A beautiful beach")
179-
# or: request = ImageRequest("A beautiful beach", api_key="your_key_here")
188+
request = ImageRequest("A beautiful beach", name="flux.1.1-pro")
189+
# or: request = ImageRequest("A beautiful beach", name="flux.1.1-pro", api_key="your_key_here")
180190

181191
# any of the following will block until the generation is finished
182192
request.url

demo_gr.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import os
22
import time
3-
from io import BytesIO
43
import uuid
54

65
import torch

src/flux/api.py

Lines changed: 77 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,12 @@
66
import requests
77
from PIL import Image
88

9-
API_ENDPOINT = "https://api.bfl.ml"
9+
API_URL = "https://api.bfl.ml"
10+
API_ENDPOINTS = {
11+
"flux.1-pro": "flux-pro",
12+
"flux.1-dev": "flux-dev",
13+
"flux.1.1-pro": "flux-pro-1.1",
14+
}
1015

1116

1217
class ApiException(Exception):
@@ -31,60 +36,97 @@ def __repr__(self) -> str:
3136
class ImageRequest:
3237
def __init__(
3338
self,
39+
# api inputs
3440
prompt: str,
35-
width: int = 1024,
36-
height: int = 1024,
37-
name: str = "flux.1-pro",
38-
num_steps: int = 50,
39-
prompt_upsampling: bool = False,
41+
name: str = "flux.1.1-pro",
42+
width: int | None = None,
43+
height: int | None = None,
44+
num_steps: int | None = None,
45+
prompt_upsampling: bool | None = None,
4046
seed: int | None = None,
47+
guidance: float | None = None,
48+
interval: float | None = None,
49+
safety_tolerance: int | None = None,
50+
# behavior of this class
4151
validate: bool = True,
4252
launch: bool = True,
4353
api_key: str | None = None,
4454
):
4555
"""
4656
Manages an image generation request to the API.
4757
58+
All parameters not specified will use the API defaults.
59+
4860
Args:
49-
prompt: Prompt to sample
50-
width: Width of the image in pixel
51-
height: Height of the image in pixel
52-
name: Name of the model
53-
num_steps: Number of network evaluations
54-
prompt_upsampling: Use prompt upsampling
55-
seed: Fix the generation seed
61+
prompt: Text prompt for image generation.
62+
width: Width of the generated image in pixels. Must be a multiple of 32.
63+
height: Height of the generated image in pixels. Must be a multiple of 32.
64+
name: Which model version to use
65+
num_steps: Number of steps for the image generation process.
66+
prompt_upsampling: Whether to perform upsampling on the prompt.
67+
seed: Optional seed for reproducibility.
68+
guidance: Guidance scale for image generation.
69+
safety_tolerance: Tolerance level for input and output moderation.
70+
Between 0 and 6, 0 being most strict, 6 being least strict.
5671
validate: Run input validation
5772
launch: Directly launches request
5873
api_key: Your API key if not provided by the environment
5974
6075
Raises:
61-
ValueError: For invalid input
76+
ValueError: For invalid input, when `validate`
6277
ApiException: For errors raised from the API
6378
"""
6479
if validate:
65-
if name not in ["flux.1-pro"]:
80+
if name not in API_ENDPOINTS.keys():
6681
raise ValueError(f"Invalid model {name}")
67-
elif width % 32 != 0:
82+
elif width is not None and width % 32 != 0:
6883
raise ValueError(f"width must be divisible by 32, got {width}")
69-
elif not (256 <= width <= 1440):
84+
elif width is not None and not (256 <= width <= 1440):
7085
raise ValueError(f"width must be between 256 and 1440, got {width}")
71-
elif height % 32 != 0:
86+
elif height is not None and height % 32 != 0:
7287
raise ValueError(f"height must be divisible by 32, got {height}")
73-
elif not (256 <= height <= 1440):
88+
elif height is not None and not (256 <= height <= 1440):
7489
raise ValueError(f"height must be between 256 and 1440, got {height}")
75-
elif not (1 <= num_steps <= 50):
90+
elif num_steps is not None and not (1 <= num_steps <= 50):
7691
raise ValueError(f"steps must be between 1 and 50, got {num_steps}")
77-
92+
elif guidance is not None and not (1.5 <= guidance <= 5.0):
93+
raise ValueError(f"guidance must be between 1.5 and 4, got {guidance}")
94+
elif interval is not None and not (1.0 <= interval <= 4.0):
95+
raise ValueError(f"interval must be between 1 and 4, got {interval}")
96+
elif safety_tolerance is not None and not (0 <= safety_tolerance <= 6.0):
97+
raise ValueError(
98+
f"safety_tolerance must be between 0 and 6, got {interval}"
99+
)
100+
101+
if name == "flux.1-dev":
102+
if interval is not None:
103+
raise ValueError("Interval is not supported for flux.1-dev")
104+
if name == "flux.1.1-pro":
105+
if (
106+
interval is not None
107+
or num_steps is not None
108+
or guidance is not None
109+
):
110+
raise ValueError(
111+
"Interval, num_steps and guidance are not supported for "
112+
"flux.1.1-pro"
113+
)
114+
115+
self.name = name
78116
self.request_json = {
79117
"prompt": prompt,
80118
"width": width,
81119
"height": height,
82-
"variant": name,
83120
"steps": num_steps,
84121
"prompt_upsampling": prompt_upsampling,
122+
"seed": seed,
123+
"guidance": guidance,
124+
"interval": interval,
125+
"safety_tolerance": safety_tolerance,
126+
}
127+
self.request_json = {
128+
key: value for key, value in self.request_json.items() if value is not None
85129
}
86-
if seed is not None:
87-
self.request_json["seed"] = seed
88130

89131
self.request_id: str | None = None
90132
self.result: dict | None = None
@@ -105,7 +147,7 @@ def request(self):
105147
if self.request_id is not None:
106148
return
107149
response = requests.post(
108-
f"{API_ENDPOINT}/v1/image",
150+
f"{API_URL}/v1/{API_ENDPOINTS[self.name]}",
109151
headers={
110152
"accept": "application/json",
111153
"x-key": self.api_key,
@@ -115,7 +157,9 @@ def request(self):
115157
)
116158
result = response.json()
117159
if response.status_code != 200:
118-
raise ApiException(status_code=response.status_code, detail=result.get("detail"))
160+
raise ApiException(
161+
status_code=response.status_code, detail=result.get("detail")
162+
)
119163
self.request_id = response.json()["id"]
120164

121165
def retrieve(self) -> dict:
@@ -126,7 +170,7 @@ def retrieve(self) -> dict:
126170
self.request()
127171
while self.result is None:
128172
response = requests.get(
129-
f"{API_ENDPOINT}/v1/get_result",
173+
f"{API_URL}/v1/get_result",
130174
headers={
131175
"accept": "application/json",
132176
"x-key": self.api_key,
@@ -137,13 +181,17 @@ def retrieve(self) -> dict:
137181
)
138182
result = response.json()
139183
if "status" not in result:
140-
raise ApiException(status_code=response.status_code, detail=result.get("detail"))
184+
raise ApiException(
185+
status_code=response.status_code, detail=result.get("detail")
186+
)
141187
elif result["status"] == "Ready":
142188
self.result = result["result"]
143189
elif result["status"] == "Pending":
144190
time.sleep(0.5)
145191
else:
146-
raise ApiException(status_code=200, detail=f"API returned status '{result['status']}'")
192+
raise ApiException(
193+
status_code=200, detail=f"API returned status '{result['status']}'"
194+
)
147195
return self.result
148196

149197
@property

src/flux/cli.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ def parse_prompt(options: SamplingOptions) -> SamplingOptions | None:
8080
continue
8181
_, steps = prompt.split()
8282
options.num_steps = int(steps)
83-
print(f"Setting seed to {options.num_steps}")
83+
print(f"Setting number of steps to {options.num_steps}")
8484
elif prompt.startswith("/q"):
8585
print("Quitting")
8686
return None

0 commit comments

Comments
 (0)