adamelliotfields
commited on
Add Together.ai API
Browse files- 0_π _Home.py +2 -1
- README.md +1 -0
- lib/api.py +37 -22
- lib/config.py +5 -0
- lib/presets.py +8 -0
- pages/1_π¬_Text_Generation.py +1 -1
- pages/2_π¨_Text_to_Image.py +19 -6
0_π _Home.py
CHANGED
@@ -49,9 +49,10 @@ st.markdown("""
|
|
49 |
## Services
|
50 |
|
51 |
- [Black Forest Labs](https://docs.bfl.ml)
|
52 |
-
- [fal](https://fal.ai/docs)
|
53 |
- [Hugging Face](https://huggingface.co/docs/api-inference/index)
|
54 |
- [Perplexity](https://docs.perplexity.ai/home)
|
|
|
55 |
""")
|
56 |
|
57 |
st.markdown("""
|
|
|
49 |
## Services
|
50 |
|
51 |
- [Black Forest Labs](https://docs.bfl.ml)
|
52 |
+
- [fal.ai](https://fal.ai/docs)
|
53 |
- [Hugging Face](https://huggingface.co/docs/api-inference/index)
|
54 |
- [Perplexity](https://docs.perplexity.ai/home)
|
55 |
+
- [together.ai](https://docs.together.ai/docs/introduction)
|
56 |
""")
|
57 |
|
58 |
st.markdown("""
|
README.md
CHANGED
@@ -31,6 +31,7 @@ BFL_API_KEY=...
|
|
31 |
FAL_KEY=...
|
32 |
HF_TOKEN=...
|
33 |
PPLX_API_KEY=...
|
|
|
34 |
```
|
35 |
|
36 |
## Installation
|
|
|
31 |
FAL_KEY=...
|
32 |
HF_TOKEN=...
|
33 |
PPLX_API_KEY=...
|
34 |
+
TOGETHER_API_KEY=...
|
35 |
```
|
36 |
|
37 |
## Installation
|
lib/api.py
CHANGED
@@ -29,50 +29,47 @@ def txt2txt_generate(api_key, service, model, parameters, **kwargs):
|
|
29 |
|
30 |
def txt2img_generate(api_key, service, model, inputs, parameters, **kwargs):
|
31 |
headers = {}
|
|
|
|
|
|
|
|
|
|
|
|
|
32 |
if service == "Hugging Face":
|
33 |
headers["Authorization"] = f"Bearer {api_key}"
|
34 |
headers["X-Wait-For-Model"] = "true"
|
35 |
headers["X-Use-Cache"] = "false"
|
36 |
|
37 |
-
if service == "
|
38 |
-
headers["Authorization"] = f"
|
39 |
|
|
|
40 |
if service == "Black Forest Labs":
|
41 |
-
|
|
|
|
|
|
|
|
|
|
|
42 |
|
43 |
-
json = {}
|
44 |
if service == "Hugging Face":
|
45 |
json = {
|
46 |
"inputs": inputs,
|
47 |
"parameters": {**parameters, **kwargs},
|
48 |
}
|
49 |
|
50 |
-
if service == "
|
51 |
json = {**parameters, **kwargs}
|
52 |
json["prompt"] = inputs
|
53 |
|
54 |
-
|
55 |
-
json = {**parameters, **kwargs}
|
56 |
-
json["prompt"] = inputs
|
57 |
|
58 |
-
|
|
|
59 |
|
60 |
try:
|
61 |
response = httpx.post(base_url, headers=headers, json=json, timeout=Config.TXT2IMG_TIMEOUT)
|
62 |
if response.status_code // 100 == 2: # 2xx
|
63 |
-
if service == "Hugging Face":
|
64 |
-
return Image.open(io.BytesIO(response.content))
|
65 |
-
|
66 |
-
if service == "Fal":
|
67 |
-
# Sync mode means wait for image base64 string instead of CDN link
|
68 |
-
if parameters.get("sync_mode", True):
|
69 |
-
bytes = base64.b64decode(response.json()["images"][0]["url"].split(",")[-1])
|
70 |
-
return Image.open(io.BytesIO(bytes))
|
71 |
-
else:
|
72 |
-
url = response.json()["images"][0]["url"]
|
73 |
-
image = httpx.get(url, headers=headers, timeout=Config.TXT2IMG_TIMEOUT)
|
74 |
-
return Image.open(io.BytesIO(image.content))
|
75 |
-
|
76 |
# BFL is async so we need to poll for result
|
77 |
# https://api.bfl.ml/docs
|
78 |
if service == "Black Forest Labs":
|
@@ -98,6 +95,24 @@ def txt2img_generate(api_key, service, model, inputs, parameters, **kwargs):
|
|
98 |
|
99 |
return "Error: API timeout"
|
100 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
101 |
else:
|
102 |
return f"Error: {response.status_code} {response.text}"
|
103 |
except Exception as e:
|
|
|
29 |
|
30 |
def txt2img_generate(api_key, service, model, inputs, parameters, **kwargs):
|
31 |
headers = {}
|
32 |
+
if service == "Black Forest Labs":
|
33 |
+
headers["x-key"] = api_key
|
34 |
+
|
35 |
+
if service == "Fal":
|
36 |
+
headers["Authorization"] = f"Key {api_key}"
|
37 |
+
|
38 |
if service == "Hugging Face":
|
39 |
headers["Authorization"] = f"Bearer {api_key}"
|
40 |
headers["X-Wait-For-Model"] = "true"
|
41 |
headers["X-Use-Cache"] = "false"
|
42 |
|
43 |
+
if service == "Together":
|
44 |
+
headers["Authorization"] = f"Bearer {api_key}"
|
45 |
|
46 |
+
json = {}
|
47 |
if service == "Black Forest Labs":
|
48 |
+
json = {**parameters, **kwargs}
|
49 |
+
json["prompt"] = inputs
|
50 |
+
|
51 |
+
if service == "Fal":
|
52 |
+
json = {**parameters, **kwargs}
|
53 |
+
json["prompt"] = inputs
|
54 |
|
|
|
55 |
if service == "Hugging Face":
|
56 |
json = {
|
57 |
"inputs": inputs,
|
58 |
"parameters": {**parameters, **kwargs},
|
59 |
}
|
60 |
|
61 |
+
if service == "Together":
|
62 |
json = {**parameters, **kwargs}
|
63 |
json["prompt"] = inputs
|
64 |
|
65 |
+
base_url = Config.SERVICES[service]
|
|
|
|
|
66 |
|
67 |
+
if service not in ["Together"]:
|
68 |
+
base_url = f"{base_url}/{model}"
|
69 |
|
70 |
try:
|
71 |
response = httpx.post(base_url, headers=headers, json=json, timeout=Config.TXT2IMG_TIMEOUT)
|
72 |
if response.status_code // 100 == 2: # 2xx
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
73 |
# BFL is async so we need to poll for result
|
74 |
# https://api.bfl.ml/docs
|
75 |
if service == "Black Forest Labs":
|
|
|
95 |
|
96 |
return "Error: API timeout"
|
97 |
|
98 |
+
if service == "Fal":
|
99 |
+
# Sync mode means wait for image base64 string instead of CDN link
|
100 |
+
if parameters.get("sync_mode", True):
|
101 |
+
bytes = base64.b64decode(response.json()["images"][0]["url"].split(",")[-1])
|
102 |
+
return Image.open(io.BytesIO(bytes))
|
103 |
+
else:
|
104 |
+
url = response.json()["images"][0]["url"]
|
105 |
+
image = httpx.get(url, headers=headers, timeout=Config.TXT2IMG_TIMEOUT)
|
106 |
+
return Image.open(io.BytesIO(image.content))
|
107 |
+
|
108 |
+
if service == "Hugging Face":
|
109 |
+
return Image.open(io.BytesIO(response.content))
|
110 |
+
|
111 |
+
if service == "Together":
|
112 |
+
url = response.json()["data"][0]["url"]
|
113 |
+
image = httpx.get(url, headers=headers, timeout=Config.TXT2IMG_TIMEOUT)
|
114 |
+
return Image.open(io.BytesIO(image.content))
|
115 |
+
|
116 |
else:
|
117 |
return f"Error: {response.status_code} {response.text}"
|
118 |
except Exception as e:
|
lib/config.py
CHANGED
@@ -9,6 +9,7 @@ Config = SimpleNamespace(
|
|
9 |
"Fal": "https://fal.run",
|
10 |
"Hugging Face": "https://api-inference.huggingface.co/models",
|
11 |
"Perplexity": "https://api.perplexity.ai",
|
|
|
12 |
},
|
13 |
TXT2IMG_TIMEOUT=60,
|
14 |
TXT2IMG_HIDDEN_PARAMETERS=[
|
@@ -31,6 +32,7 @@ Config = SimpleNamespace(
|
|
31 |
"Black Forest Labs": 2,
|
32 |
"Fal": 0,
|
33 |
"Hugging Face": 2,
|
|
|
34 |
},
|
35 |
TXT2IMG_MODELS={
|
36 |
# Model IDs referenced in Text_to_Image.py
|
@@ -54,6 +56,9 @@ Config = SimpleNamespace(
|
|
54 |
"black-forest-labs/flux.1-schnell",
|
55 |
"stabilityai/stable-diffusion-xl-base-1.0",
|
56 |
],
|
|
|
|
|
|
|
57 |
},
|
58 |
TXT2IMG_DEFAULT_IMAGE_SIZE="square_hd", # fal image sizes
|
59 |
TXT2IMG_IMAGE_SIZES=[
|
|
|
9 |
"Fal": "https://fal.run",
|
10 |
"Hugging Face": "https://api-inference.huggingface.co/models",
|
11 |
"Perplexity": "https://api.perplexity.ai",
|
12 |
+
"Together": "https://api.together.xyz/v1/images/generations",
|
13 |
},
|
14 |
TXT2IMG_TIMEOUT=60,
|
15 |
TXT2IMG_HIDDEN_PARAMETERS=[
|
|
|
32 |
"Black Forest Labs": 2,
|
33 |
"Fal": 0,
|
34 |
"Hugging Face": 2,
|
35 |
+
"Together": 0,
|
36 |
},
|
37 |
TXT2IMG_MODELS={
|
38 |
# Model IDs referenced in Text_to_Image.py
|
|
|
56 |
"black-forest-labs/flux.1-schnell",
|
57 |
"stabilityai/stable-diffusion-xl-base-1.0",
|
58 |
],
|
59 |
+
"Together": [
|
60 |
+
"black-forest-labs/FLUX.1-schnell-Free",
|
61 |
+
],
|
62 |
},
|
63 |
TXT2IMG_DEFAULT_IMAGE_SIZE="square_hd", # fal image sizes
|
64 |
TXT2IMG_IMAGE_SIZES=[
|
lib/presets.py
CHANGED
@@ -116,6 +116,14 @@ ModelPresets = SimpleNamespace(
|
|
116 |
"parameters": ["width", "height", "num_inference_steps"],
|
117 |
"kwargs": {"guidance_scale": 0.0, "max_sequence_length": 256},
|
118 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
119 |
FOOOCUS={
|
120 |
"name": "Fooocus",
|
121 |
"guidance_scale": 4.0,
|
|
|
116 |
"parameters": ["width", "height", "num_inference_steps"],
|
117 |
"kwargs": {"guidance_scale": 0.0, "max_sequence_length": 256},
|
118 |
},
|
119 |
+
FLUX_SCHNELL_FREE_TOGETHER={
|
120 |
+
"name": "FLUX.1 Schnell Free",
|
121 |
+
"num_inference_steps": 4,
|
122 |
+
"num_inference_steps_min": 1,
|
123 |
+
"num_inference_steps_max": 12,
|
124 |
+
"parameters": ["model", "seed", "width", "height", "steps"],
|
125 |
+
"kwargs": {"n": 1},
|
126 |
+
},
|
127 |
FOOOCUS={
|
128 |
"name": "Fooocus",
|
129 |
"guidance_scale": 4.0,
|
pages/1_π¬_Text_Generation.py
CHANGED
@@ -12,7 +12,7 @@ SERVICE_SESSION = {
|
|
12 |
|
13 |
SESSION_TOKEN = {
|
14 |
"api_key_hugging_face": os.environ.get("HF_TOKEN") or None,
|
15 |
-
"api_key_perplexity": os.environ.get("
|
16 |
}
|
17 |
|
18 |
# config
|
|
|
12 |
|
13 |
SESSION_TOKEN = {
|
14 |
"api_key_hugging_face": os.environ.get("HF_TOKEN") or None,
|
15 |
+
"api_key_perplexity": os.environ.get("PPLX_API_KEY") or None,
|
16 |
}
|
17 |
|
18 |
# config
|
pages/2_π¨_Text_to_Image.py
CHANGED
@@ -10,19 +10,24 @@ SERVICE_SESSION = {
|
|
10 |
"Black Forest Labs": "api_key_black_forest_labs",
|
11 |
"Fal": "api_key_fal",
|
12 |
"Hugging Face": "api_key_hugging_face",
|
|
|
13 |
}
|
14 |
|
15 |
SESSION_TOKEN = {
|
16 |
"api_key_black_forest_labs": os.environ.get("BFL_API_KEY") or None,
|
17 |
"api_key_fal": os.environ.get("FAL_KEY") or None,
|
18 |
"api_key_hugging_face": os.environ.get("HF_TOKEN") or None,
|
|
|
19 |
}
|
20 |
|
|
|
21 |
# Model IDs in lib/config.py
|
22 |
PRESET_MODEL = {
|
23 |
-
|
24 |
-
"
|
25 |
-
"
|
|
|
|
|
26 |
"fal-ai/aura-flow": ModelPresets.AURA_FLOW,
|
27 |
"fal-ai/flux/dev": ModelPresets.FLUX_DEV_FAL,
|
28 |
"fal-ai/flux/schnell": ModelPresets.FLUX_SCHNELL_FAL,
|
@@ -31,9 +36,12 @@ PRESET_MODEL = {
|
|
31 |
"fal-ai/fooocus": ModelPresets.FOOOCUS,
|
32 |
"fal-ai/kolors": ModelPresets.KOLORS,
|
33 |
"fal-ai/stable-diffusion-v3-medium": ModelPresets.STABLE_DIFFUSION_3,
|
34 |
-
|
35 |
-
"flux-
|
36 |
-
"flux-
|
|
|
|
|
|
|
37 |
}
|
38 |
|
39 |
st.set_page_config(
|
@@ -52,6 +60,9 @@ if "api_key_fal" not in st.session_state:
|
|
52 |
if "api_key_hugging_face" not in st.session_state:
|
53 |
st.session_state.api_key_hugging_face = ""
|
54 |
|
|
|
|
|
|
|
55 |
if "running" not in st.session_state:
|
56 |
st.session_state.running = False
|
57 |
|
@@ -98,6 +109,8 @@ st.html("""
|
|
98 |
parameters = {}
|
99 |
preset = PRESET_MODEL[model]
|
100 |
for param in preset["parameters"]:
|
|
|
|
|
101 |
if param == "seed":
|
102 |
parameters[param] = st.sidebar.number_input(
|
103 |
"Seed",
|
|
|
10 |
"Black Forest Labs": "api_key_black_forest_labs",
|
11 |
"Fal": "api_key_fal",
|
12 |
"Hugging Face": "api_key_hugging_face",
|
13 |
+
"Together": "api_key_together",
|
14 |
}
|
15 |
|
16 |
SESSION_TOKEN = {
|
17 |
"api_key_black_forest_labs": os.environ.get("BFL_API_KEY") or None,
|
18 |
"api_key_fal": os.environ.get("FAL_KEY") or None,
|
19 |
"api_key_hugging_face": os.environ.get("HF_TOKEN") or None,
|
20 |
+
"api_key_together": os.environ.get("TOGETHER_API_KEY") or None,
|
21 |
}
|
22 |
|
23 |
+
# TODO: group by service so we can have models with the same name
|
24 |
# Model IDs in lib/config.py
|
25 |
PRESET_MODEL = {
|
26 |
+
# bfl
|
27 |
+
"flux-pro-1.1": ModelPresets.FLUX_1_1_PRO_BFL,
|
28 |
+
"flux-pro": ModelPresets.FLUX_PRO_BFL,
|
29 |
+
"flux-dev": ModelPresets.FLUX_DEV_BFL,
|
30 |
+
# fal
|
31 |
"fal-ai/aura-flow": ModelPresets.AURA_FLOW,
|
32 |
"fal-ai/flux/dev": ModelPresets.FLUX_DEV_FAL,
|
33 |
"fal-ai/flux/schnell": ModelPresets.FLUX_SCHNELL_FAL,
|
|
|
36 |
"fal-ai/fooocus": ModelPresets.FOOOCUS,
|
37 |
"fal-ai/kolors": ModelPresets.KOLORS,
|
38 |
"fal-ai/stable-diffusion-v3-medium": ModelPresets.STABLE_DIFFUSION_3,
|
39 |
+
# hf
|
40 |
+
"black-forest-labs/flux.1-dev": ModelPresets.FLUX_DEV_HF,
|
41 |
+
"black-forest-labs/flux.1-schnell": ModelPresets.FLUX_SCHNELL_HF,
|
42 |
+
"stabilityai/stable-diffusion-xl-base-1.0": ModelPresets.STABLE_DIFFUSION_XL,
|
43 |
+
# together
|
44 |
+
"black-forest-labs/FLUX.1-schnell-Free": ModelPresets.FLUX_SCHNELL_FREE_TOGETHER,
|
45 |
}
|
46 |
|
47 |
st.set_page_config(
|
|
|
60 |
if "api_key_hugging_face" not in st.session_state:
|
61 |
st.session_state.api_key_hugging_face = ""
|
62 |
|
63 |
+
if "api_key_together" not in st.session_state:
|
64 |
+
st.session_state.api_key_together = ""
|
65 |
+
|
66 |
if "running" not in st.session_state:
|
67 |
st.session_state.running = False
|
68 |
|
|
|
109 |
parameters = {}
|
110 |
preset = PRESET_MODEL[model]
|
111 |
for param in preset["parameters"]:
|
112 |
+
if param == "model":
|
113 |
+
parameters[param] = model
|
114 |
if param == "seed":
|
115 |
parameters[param] = st.sidebar.number_input(
|
116 |
"Seed",
|