Compare commits

..
Author SHA1 Message Date
Cursor AgentandGilad-brudner-bria 11c60b5558 Use versioned User-Agent on all HTTP requests to Bria APIs
- Build User-Agent from installed comfyui-bria-api package version
- Add bria_asset_headers for CDN/S3 and preview downloads without api_token
- Include User-Agent on presigned S3 PUT uploads

Co-authored-by: Gilad-brudner-bria <Gilad-brudner-bria@users.noreply.github.com>
2026-04-16 09:35:39 +00:00
Yazan Numoor c5468b2525 Merge pull request #41 from Bria-AI/update_fibo_edit_node_default_steps_num
update_fibo_edit_node_default_steps_num
2026-04-15 10:01:55 +03:00
Yazan Numoor 22d4cf5ba1 Merge branch 'main' into update_fibo_edit_node_default_steps_num 2026-04-15 10:01:48 +03:00
Yazan Numoor 525938a740 Merge pull request #43 from Bria-AI/WAI-4698
WAI-4698:set User-Agent header
2026-04-15 10:00:55 +03:00
Ubuntu a3451b6b86 update_fibo_edit_node_default_steps_num 2026-02-12 16:43:29 +00:00
23 changed files with 136 additions and 30 deletions
+14 -2
View File
@@ -7,8 +7,20 @@ from torchvision.transforms import ToPILImage
import requests
import time
from importlib.metadata import PackageNotFoundError, version as _package_version
try:
_BRIA_COMFYUI_PACKAGE_VERSION = _package_version("comfyui-bria-api")
except PackageNotFoundError:
_BRIA_COMFYUI_PACKAGE_VERSION = "dev"
BRIA_COMFYUI_USER_AGENT = f"bria/ComfyUI-BRIA-API/{_BRIA_COMFYUI_PACKAGE_VERSION}"
def bria_asset_headers() -> dict:
"""Headers for asset fetches (CDN/S3 URLs) where api_token is not sent."""
return {"User-Agent": BRIA_COMFYUI_USER_AGENT}
BRIA_COMFYUI_USER_AGENT = "bria/ComfyUI"
def bria_json_headers(api_token: str) -> dict:
"""Headers for JSON POST requests to Bria API."""
@@ -125,7 +137,7 @@ def process_request(api_url, image, mask, api_key, visual_input_content_moderati
result_image_url = final_response['result']['image_url']
# Download and process the result image
image_response = requests.get(result_image_url)
image_response = requests.get(result_image_url, headers=bria_asset_headers())
result_image = Image.open(io.BytesIO(image_response.content))
result_image = result_image.convert("RGBA")
result_image = np.array(result_image).astype(np.float32) / 255.0
+6 -2
View File
@@ -2,6 +2,7 @@ import requests
import torch
from .common import (
bria_asset_headers,
bria_json_headers,
image_to_base64,
poll_status_until_completed,
@@ -31,7 +32,7 @@ class FIBOEditNode:
"steps_num": (
"INT",
{
"default": 50,
"default": 30,
"min": 1,
"max": 100,
},
@@ -149,7 +150,10 @@ class FIBOEditNode:
structured_prompt = result.get("structured_prompt", "")
used_seed = result.get("seed")
image_response = requests.get(result_image_url)
image_response = requests.get(
result_image_url,
headers=bria_asset_headers(),
)
result_image = postprocess_image(image_response.content)
return (result_image, structured_prompt, used_seed)
+5 -1
View File
@@ -1,6 +1,7 @@
import requests
import torch
from .common import (
bria_asset_headers,
bria_json_headers,
image_to_base64,
normalize_images_input,
@@ -137,7 +138,10 @@ class GenerateImageLiteNodeV2:
structured_prompt_result = result.get("structured_prompt", "")
used_seed = result.get("seed", seed_values[idx])
image_response = requests.get(result_image_url)
image_response = requests.get(
result_image_url,
headers=bria_asset_headers(),
)
result_image = postprocess_image(image_response.content)
batch_results.append(result_image)
+5 -1
View File
@@ -2,6 +2,7 @@ import requests
import torch
from .common import (
bria_asset_headers,
bria_json_headers,
image_to_base64,
normalize_images_input,
@@ -145,7 +146,10 @@ class GenerateImageNodeV2:
structured_prompt_result = result.get("structured_prompt", "")
used_seed = result.get("seed", seed_values[idx])
image_response = requests.get(result_image_url)
image_response = requests.get(
result_image_url,
headers=bria_asset_headers(),
)
result_image = postprocess_image(image_response.content)
batch_results.append(result_image)
+5 -1
View File
@@ -5,6 +5,7 @@ import io
import torch
from .common import (
bria_asset_headers,
bria_json_headers,
image_to_base64,
poll_status_until_completed,
@@ -87,7 +88,10 @@ class GenFillNode():
final_response = poll_status_until_completed(status_url, api_key)
result_image_url = final_response['result']['image_url']
image_response = requests.get(result_image_url)
image_response = requests.get(
result_image_url,
headers=bria_asset_headers(),
)
result_image = Image.open(io.BytesIO(image_response.content))
result_image = result_image.convert("RGB")
result_image = np.array(result_image).astype(np.float32) / 255.0
+5 -1
View File
@@ -5,6 +5,7 @@ from PIL import Image
import torch
from .common import (
bria_asset_headers,
bria_json_headers,
image_to_base64,
normalize_images_input,
@@ -90,7 +91,10 @@ class ImageEnhanceNode():
used_seed = final_response["result"].get("seed", seed)
# Download and process image
image_response = requests.get(result_image_url)
image_response = requests.get(
result_image_url,
headers=bria_asset_headers(),
)
result_image = Image.open(io.BytesIO(image_response.content)).convert("RGB")
result_array = np.array(result_image).astype(np.float32) / 255.0
result_tensor = torch.from_numpy(result_array) # shape: (H,W,C)
+5 -1
View File
@@ -5,6 +5,7 @@ from PIL import Image
import torch
from .common import (
bria_asset_headers,
bria_json_headers,
image_to_base64,
normalize_images_input,
@@ -119,7 +120,10 @@ class ImageExpansionNode():
final_response = poll_status_until_completed(status_url, api_key)
result_image_url = final_response["result"]["image_url"]
image_response = requests.get(result_image_url)
image_response = requests.get(
result_image_url,
headers=bria_asset_headers(),
)
result_image = Image.open(io.BytesIO(image_response.content)).convert("RGB")
result_tensor = torch.from_numpy(np.array(result_image).astype(np.float32) / 255.0)
+5 -1
View File
@@ -2,6 +2,7 @@ import requests
import torch
from .common import (
bria_asset_headers,
bria_json_headers,
image_to_base64,
poll_status_until_completed,
@@ -121,7 +122,10 @@ class ProductIntegrateNode:
result_image_url = result.get("image_url")
used_seed = result.get("seed", seed)
image_response = requests.get(result_image_url)
image_response = requests.get(
result_image_url,
headers=bria_asset_headers(),
)
result_image = postprocess_image(image_response.content)
return (result_image, used_seed)
+10 -2
View File
@@ -1,6 +1,11 @@
import requests
from .common import bria_json_headers, poll_status_until_completed, postprocess_image
from .common import (
bria_asset_headers,
bria_json_headers,
poll_status_until_completed,
postprocess_image,
)
@@ -154,7 +159,10 @@ class RefineImageLiteNodeV2:
structured_prompt = result.get("structured_prompt", "")
used_seed = result.get("seed")
image_response = requests.get(result_image_url)
image_response = requests.get(
result_image_url,
headers=bria_asset_headers(),
)
result_image = postprocess_image(image_response.content)
return (result_image, structured_prompt, used_seed)
+10 -2
View File
@@ -1,6 +1,11 @@
import requests
from .common import bria_json_headers, poll_status_until_completed, postprocess_image
from .common import (
bria_asset_headers,
bria_json_headers,
poll_status_until_completed,
postprocess_image,
)
class RefineImageNodeV2:
@@ -156,7 +161,10 @@ class RefineImageNodeV2:
structured_prompt = result.get("structured_prompt", "")
used_seed = result.get("seed")
image_response = requests.get(result_image_url)
image_response = requests.get(
result_image_url,
headers=bria_asset_headers(),
)
result_image = postprocess_image(image_response.content)
return (result_image, structured_prompt, used_seed)
+5 -1
View File
@@ -1,6 +1,7 @@
import requests
from .common import (
bria_asset_headers,
bria_json_headers,
image_to_base64,
postprocess_image,
@@ -67,7 +68,10 @@ class ReimagineNode():
)
if response.status_code == 200:
response_dict = response.json()
image_response = requests.get(response_dict['result'][0]["urls"][0])
image_response = requests.get(
response_dict['result'][0]["urls"][0],
headers=bria_asset_headers(),
)
result_image = postprocess_image(image_response.content)
return (result_image,)
else:
+5 -1
View File
@@ -5,6 +5,7 @@ from PIL import Image
import torch
from .common import (
bria_asset_headers,
bria_json_headers,
image_to_base64,
normalize_images_input,
@@ -74,7 +75,10 @@ class RemoveForegroundNode():
result_image_url = final_response["result"]["image_url"]
# Download result
image_response = requests.get(result_image_url)
image_response = requests.get(
result_image_url,
headers=bria_asset_headers(),
)
result_image = Image.open(io.BytesIO(image_response.content)).convert("RGB")
# Convert to float32 tensor (H, W, C)
+5 -1
View File
@@ -5,6 +5,7 @@ from PIL import Image
import torch
from .common import (
bria_asset_headers,
bria_json_headers,
image_to_base64,
normalize_images_input,
@@ -108,7 +109,10 @@ class ReplaceBgNode():
final_response = poll_status_until_completed(status_url, api_key)
result_image_url = final_response["result"]["image_url"]
image_response = requests.get(result_image_url)
image_response = requests.get(
result_image_url,
headers=bria_asset_headers(),
)
result_image = Image.open(io.BytesIO(image_response.content)).convert("RGB")
result_tensor = torch.from_numpy(np.array(result_image).astype(np.float32) / 255.0)
+5 -1
View File
@@ -5,6 +5,7 @@ from PIL import Image
import torch
from .common import (
bria_asset_headers,
bria_json_headers,
image_to_base64,
normalize_images_input,
@@ -71,7 +72,10 @@ class RmbgNode():
result_image_url = final_response['result']['image_url']
# Download result
image_response = requests.get(result_image_url)
image_response = requests.get(
result_image_url,
headers=bria_asset_headers(),
)
result_image = Image.open(io.BytesIO(image_response.content))
# Convert to float32 tensor (H, W, C), 0-1
+5 -1
View File
@@ -1,6 +1,7 @@
import requests
from .common import (
bria_asset_headers,
bria_json_headers,
image_to_base64,
postprocess_image,
@@ -82,7 +83,10 @@ class TailoredGenNode():
)
if response.status_code == 200:
response_dict = response.json()
image_response = requests.get(response_dict['result'][0]["urls"][0])
image_response = requests.get(
response_dict['result'][0]["urls"][0],
headers=bria_asset_headers(),
)
result_image = postprocess_image(image_response.content)
return (result_image,)
else:
+5 -1
View File
@@ -5,6 +5,7 @@ from PIL import Image
import torch
from .common import (
bria_asset_headers,
bria_json_headers,
image_to_base64,
normalize_images_input,
@@ -70,7 +71,10 @@ class TailoredPortraitNode():
raise Exception(f"API request failed with status {response.status_code}: {response.text}")
response_dict = response.json()
image_response = requests.get(response_dict["image_res"])
image_response = requests.get(
response_dict["image_res"],
headers=bria_asset_headers(),
)
result_image = Image.open(io.BytesIO(image_response.content)).convert("RGB")
# Convert to float32 tensor (H,W,C), 0-1
+5 -1
View File
@@ -1,6 +1,7 @@
import requests
from .common import (
bria_asset_headers,
bria_json_headers,
image_to_base64,
postprocess_image,
@@ -92,7 +93,10 @@ class Text2ImageBaseNode():
)
if response.status_code == 200:
response_dict = response.json()
image_response = requests.get(response_dict['result'][0]["urls"][0])
image_response = requests.get(
response_dict['result'][0]["urls"][0],
headers=bria_asset_headers(),
)
result_image = postprocess_image(image_response.content)
return (result_image,)
else:
+5 -1
View File
@@ -1,6 +1,7 @@
import requests
from .common import (
bria_asset_headers,
bria_json_headers,
image_to_base64,
postprocess_image,
@@ -85,7 +86,10 @@ class Text2ImageFastNode():
)
if response.status_code == 200:
response_dict = response.json()
image_response = requests.get(response_dict['result'][0]["urls"][0])
image_response = requests.get(
response_dict['result'][0]["urls"][0],
headers=bria_asset_headers(),
)
result_image = postprocess_image(image_response.content)
return (result_image,)
else:
+5 -2
View File
@@ -1,6 +1,6 @@
import requests
from .common import bria_json_headers, postprocess_image
from .common import bria_asset_headers, bria_json_headers, postprocess_image
class Text2ImageHDNode():
@@ -56,7 +56,10 @@ class Text2ImageHDNode():
)
if response.status_code == 200:
response_dict = response.json()
image_response = requests.get(response_dict['result'][0]["urls"][0])
image_response = requests.get(
response_dict['result'][0]["urls"][0],
headers=bria_asset_headers(),
)
result_image = postprocess_image(image_response.content)
return (result_image,)
else:
+9 -2
View File
@@ -1,6 +1,7 @@
import requests
import torch
from ..common import (
bria_asset_headers,
bria_json_headers,
image_to_base64,
postprocess_image,
@@ -145,7 +146,10 @@ def make_api_request(api_url, payload, api_key, Placement_type = None):
result_images = []
for i, result in enumerate(response_dict.get("result", [])[:7]):
image_url = result[0]
image_response = requests.get(image_url)
image_response = requests.get(
image_url,
headers=bria_asset_headers(),
)
processed = postprocess_image(image_response.content)
result_images.append(processed)
@@ -156,7 +160,10 @@ def make_api_request(api_url, payload, api_key, Placement_type = None):
return tuple(result_images)
image_response = requests.get(response_dict["result"][0][0])
image_response = requests.get(
response_dict["result"][0][0],
headers=bria_asset_headers(),
)
result_image = postprocess_image(image_response.content)
return (result_image,)
else:
@@ -3,6 +3,8 @@ import uuid
import folder_paths
import requests
from ..common import bria_asset_headers
class PreviewVideoURLNode:
"""
Bria Preview Video URL Node
@@ -62,7 +64,12 @@ class PreviewVideoURLNode:
# Download video from URL
try:
response = requests.get(video_url, stream=True, timeout=60)
response = requests.get(
video_url,
stream=True,
timeout=60,
headers=bria_asset_headers(),
)
response.raise_for_status()
# Determine file extension from URL or Content-Type
+3 -2
View File
@@ -1,7 +1,7 @@
import os
import requests
from ..common import BRIA_COMFYUI_USER_AGENT
from ..common import BRIA_COMFYUI_USER_AGENT, bria_asset_headers
def upload_video_to_s3(video_path, filename, api_token):
@@ -55,7 +55,8 @@ def upload_video_to_s3(video_path, filename, api_token):
# Determine content type based on file extension
upload_headers = {
"Content-Type": content_type
"Content-Type": content_type,
**bria_asset_headers(),
}
upload_response = requests.put(upload_url, data=video_data, headers=upload_headers)
+1 -1
View File
@@ -1,7 +1,7 @@
[project]
name = "comfyui-bria-api"
description = "Custom nodes for ComfyUI using BRIA's API."
version = "2.1.16"
version = "2.1.17"
license = {file = "LICENSE"}
[project.urls]