Compare commits

...
Author SHA1 Message Date
mabualrob1997 725868a7eb Update Readme.md 2025-12-01 16:46:53 +02:00
Yazan Numoor a5a88e2dbd Merge pull request #32 from Bria-AI/WAI-4174
WAI-4174
2025-11-20 11:43:06 +02:00
Ubuntu 64ab007f27 WAI-4174 2025-11-20 07:43:01 +00:00
Yazan Numoor 3ac0209193 Merge pull request #31 from Bria-AI/fix-invalid-token-error-message
fix invalid token error message
2025-11-12 14:31:14 +02:00
Ubuntu b5d4d41bb8 update version 2025-11-12 12:03:13 +00:00
Ubuntu 0f2b1115c5 fix invalid token error message 2025-11-12 09:44:45 +00:00
Yazan Numoor b408c8781a Update pyproject.toml 2025-11-11 15:50:02 +02:00
Yazan Numoor f6e134cfd3 Merge pull request #30 from Bria-AI/WAI-4030
WAI-4030
2025-11-11 15:39:44 +02:00
Ubuntu 7855c4dba2 WAI-4030 2025-11-09 06:51:29 +00:00
galbria c1f67dd4fb remove FIBO Workflow.json file 2025-10-30 15:41:37 +02:00
ליזה ירושבסקי c1a77106b4 adding fibo workflow 2025-10-30 15:39:49 +02:00
Yazan Numoor 0f170bfc6b Merge pull request #29 from Bria-AI/fix_comfy_refine_to_support_generate
fix_comfy_refine_to_support_generate
2025-10-29 18:27:06 +02:00
Ubuntu 6b4b9e2dee update version 2025-10-29 16:26:29 +00:00
Ubuntu 4385a8c429 fix_comfy_refine_to_support_generate 2025-10-29 16:18:44 +00:00
Yazan Numoor dd8d70000f Merge pull request #27 from Bria-AI/WAI-4116
WAI-4116
2025-10-29 17:08:48 +02:00
Ubuntu 582e16600e Merge branch 'WAI-4116' of https://github.com/Bria-AI/ComfyUI-BRIA-API into WAI-4116 2025-10-29 12:12:53 +00:00
Ubuntu 33f657ccbd update version 2025-10-29 12:12:29 +00:00
mabualrob1997 f8a6650b4b Update Readme.md 2025-10-29 14:10:43 +02:00
Ubuntu 493d23bdcb remove pro nodes 2025-10-29 11:24:22 +00:00
Ubuntu ecf52dd764 fix images paramter 2025-10-28 15:08:16 +00:00
Ubuntu a9f894102d remmove duplicate import 2025-10-28 07:06:24 +00:00
Ubuntu e50dd5dd63 remmove duplicate import 2025-10-28 07:04:34 +00:00
Ubuntu 00ce39dae5 Merge branch 'main' of https://github.com/Bria-AI/ComfyUI-BRIA-API into WAI-4116 2025-10-28 07:01:47 +00:00
Ubuntu 270128d32a add fibo pro nodes 2025-10-27 20:19:53 +00:00
Ubuntu 43893286cc update Gaia model name to Fibo 2025-10-16 09:27:30 +00:00
Ubuntu 96d2924dfc WAI-4116 2025-10-14 12:30:13 +00:00
Ubuntu 327ace887b WAI-4116 2025-10-14 08:57:45 +00:00
22 changed files with 970 additions and 32 deletions
+46 -7
View File
@@ -30,14 +30,53 @@ To load a workflow, import the compatible workflow.json files from this [folder]
# Available Nodes
## Image Generation Nodes
These nodes create high-quality images from text or image prompts, generating photorealistic or artistic results with support for various aspect ratios.
| Node | Description |
|------------------------|--------------------------------------------------------------------|
| **Text2Image Base** | Generates images from text prompts, serving as the foundation for text-based image creation. |
| **Text2Image Fast** | Optimized for speed, this node generates images from text prompts with faster results while maintaining quality. |
| **Text2Image HD** | Optimized for high-resolution outputs, this node generates detailed and sharp visuals from text prompts. |
| **Reimagine** | Guides image generation using both prompts and an input image. Preserve the original structure and depth while introducing new materials, colors, and textures. |
These nodes allow you to leverage Bria's image generation capabilities within ComfyUI. We offer our latest **V2 nodes** (powered by the **FIBO** model) for precise control via structured prompts, alongside our legacy **V1 nodes**.
### V2 Generation Nodes (FIBO)
Our V2 nodes utilize a state-of-the-art **two-step process** for enhanced control and consistency:
- **Translation**: A VLM Bridge translates your input (prompt/images) into a machine-readable `structured_prompt` (JSON).
- **Generation**: The FIBO model generates the final image based on that specific JSON.
**Available Versions:**
- **Regular**: Uses **Gemini 2.5 Flash** as the bridge for state-of-the-art, detailed prompt creation.
- **Lite**: Uses **FIBO-VLM** (Bria's open-source bridge) for faster, flexible, or on-prem deployment.
**Available V2 Nodes & Input Rules**
We offer three distinct nodes to give you full control over this pipeline:
1. **Structured Prompt Bridge**
- Outputs a JSON string only (no image).
- This node decouples the "intent translation" step from generation. It is ideal for "human-in-the-loop" workflows where you want to inspect, audit, or version-control the JSON instructions before generating.
- **Supported Input Combinations:**
- `prompt`: Generates a structured prompt from text.
- `images`: Generates a structured prompt based on an input image.
- `images + prompt`: Generates a structured prompt based on an image, guided by text.
- `structured_prompt + prompt`: Updates an existing structured prompt using new text instructions (outputs updated JSON).
2. **Generate Image**
- Outputs an Image.
- The primary node for generation. It automatically handles translation and generation in one go, or accepts a pre-made structured prompt for reproducible results.
- **Supported Input Combinations:**
- `prompt`: Generates a new image from text.
- `images`: Generates a new image inspired by a reference image.
- `images + prompt`: Generates a new image inspired by an image and guided by text.
- `structured_prompt`: Recreates a previous image exactly (when combined with a seed).
3. **Refine and Regenerate**
- Outputs a Refined Image.
- This node allows you to take a result you like and tweak it without losing the original composition.
- **Supported Input Combination:**
- `structured_prompt + prompt`: Refines a previous image using new text instructions (combined with a seed) to adjust details while maintaining consistency.
### V1 Generation Nodes (Legacy)
These nodes utilize Bria's previous generation pipeline. While V2 is recommended for the highest control and quality, V1 remains available for backward compatibility with established workflows.
These nodes create high-quality images using Bria's V1 pipelines, supporting various aspect ratios and styles.
## Tailored Generation Nodes
These nodes use pre-trained tailored models to generate images that faithfully reproduce specific visual IP elements or guidelines.
+8 -2
View File
@@ -14,6 +14,8 @@ from .nodes import (
Text2ImageHDNode,
TailoredPortraitNode,
ReimagineNode,
GenerateImageNodeV2,
RefineImageNodeV2,
ShotByTextAutomaticNode,
ShotByImageManualPaddingNode,
ShotByImageAutomaticAspectRatioNode,
@@ -54,7 +56,9 @@ NODE_CLASS_MAPPINGS = {
"Text2ImageFastNode": Text2ImageFastNode,
"Text2ImageHDNode": Text2ImageHDNode,
"ReimagineNode": ReimagineNode,
"AttributionByImageNode":AttributionByImageNode
"AttributionByImageNode": AttributionByImageNode,
"GenerateImageNodeV2": GenerateImageNodeV2,
"RefineImageNodeV2": RefineImageNodeV2,
}
# Map the node display name to the one shown in the ComfyUI node interface
NODE_DISPLAY_NAME_MAPPINGS = {
@@ -83,5 +87,7 @@ NODE_DISPLAY_NAME_MAPPINGS = {
"Text2ImageFastNode": "Bria Text2Image Fast",
"Text2ImageHDNode": "Bria Text2Image HD",
"ReimagineNode": "Bria Reimagine",
"AttributionByImageNode":"Attribution By Image Node"
"AttributionByImageNode": "Attribution By Image Node",
"GenerateImageNodeV2": "Generate Image",
"RefineImageNodeV2": "Refine and Regenerate Image",
}
+2
View File
@@ -11,6 +11,8 @@ from .text_2_image_base_node import Text2ImageBaseNode
from .text_2_image_fast_node import Text2ImageFastNode
from .text_2_image_hd_node import Text2ImageHDNode
from .reimagine_node import ReimagineNode
from .generate_image_node_v2 import GenerateImageNodeV2
from .refine_image_node_v2 import RefineImageNodeV2
from .shot_by_text_node import ShotByTextOriginalNode
from .shot_by_text_automatic_aspect_ratio_node import ShotByTextAutomaticAspectRatioNode
from .shot_by_text_automatic_node import ShotByTextAutomaticNode
+2 -1
View File
@@ -1,7 +1,7 @@
import requests
import torch
from .common import preprocess_image, image_to_base64, poll_status_until_completed
from .common import deserialize_and_get_comfy_key, preprocess_image, image_to_base64, poll_status_until_completed
class AttributionByImageNode():
@classmethod
@@ -26,6 +26,7 @@ class AttributionByImageNode():
def execute(self, image, model_version, api_key):
if api_key.strip() == "" or api_key.strip() == "BRIA_API_TOKEN":
raise Exception("Please insert a valid API key.")
api_key = deserialize_and_get_comfy_key(api_key)
# Check if image is tensor, if so, convert to NumPy array
if isinstance(image, torch.Tensor):
+28
View File
@@ -6,6 +6,15 @@ import base64
from torchvision.transforms import ToPILImage
import requests
import time
import json
COMFY_KEY_ERROR = (
"Invalid Token Type\n\n"
"The API token you’ve entered is not a ComfyUI token.\n"
"Please use the valid token from your BRIA Account API Keys page:\n"
"https://platform.bria.ai/console/account/api-keys"
)
def postprocess_image(image):
result_image = Image.open(io.BytesIO(image))
@@ -48,6 +57,7 @@ def preprocess_mask(mask):
def process_request(api_url, image, mask, api_key, visual_input_content_moderation, visual_output_content_moderation):
if api_key.strip() == "" or api_key.strip() == "BRIA_API_TOKEN":
raise Exception("Please insert a valid API key.")
api_key = deserialize_and_get_comfy_key(api_key)
# Check if image and mask are tensors, if so, convert to NumPy arrays
if isinstance(image, torch.Tensor):
@@ -145,3 +155,21 @@ def poll_status_until_completed(status_url, api_key, timeout=360, check_interval
raise Exception(f"Error checking status: {e}")
raise Exception(f"Timeout reached after {timeout} seconds")
def deserialize_and_get_comfy_key(encoded: str) -> str:
"""
Decodes a base64-encoded JSON token and returns the ComfyUI API key.
"""
try:
decoded = base64.b64decode(encoded).decode("utf-8")
payload = json.loads(decoded)
if payload.get("type") != "comfy":
raise Exception(COMFY_KEY_ERROR)
return payload.get("apiKey")
except Exception as e:
raise Exception(COMFY_KEY_ERROR)
+143
View File
@@ -0,0 +1,143 @@
import requests
import torch
from .common import (
deserialize_and_get_comfy_key,
postprocess_image,
preprocess_image,
image_to_base64,
poll_status_until_completed,
)
class _BaseGenerateImageNodeV2:
"""Base class for image generation nodes (standard & pro)."""
api_url = None # Each subclass must define its API endpoint
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"api_token": ("STRING", {"default": "BRIA_API_TOKEN"}),
"prompt": ("STRING",),
},
"optional": {
"model_version": (["FIBO"], {"default": "FIBO"}),
"negative_prompt": ("STRING", {"default": ""}),
"images": ("IMAGE",),
"aspect_ratio": (
["1:1", "2:3", "3:2", "3:4", "4:3", "4:5", "5:4", "9:16", "16:9"],
{"default": "1:1"},
),
"steps_num": ("INT", {"default": 50, "min": 20, "max": 50}),
"guidance_scale": ("INT", {"default": 5, "min": 3, "max": 5}),
"seed": ("INT", {"default": 123456}),
},
}
RETURN_TYPES = ("IMAGE", "STRING", "INT")
RETURN_NAMES = ("image", "structured_prompt", "seed")
CATEGORY = "API Nodes"
FUNCTION = "execute"
def _validate_token(self, api_token: str):
if api_token.strip() == "" or api_token.strip() == "BRIA_API_TOKEN":
raise Exception("Please insert a valid API token.")
def _build_payload(
self,
prompt,
model_version,
negative_prompt,
aspect_ratio,
steps_num,
guidance_scale,
seed,
images=None,
):
payload = {
"prompt": prompt,
"model_version": model_version,
"negative_prompt": negative_prompt,
"aspect_ratio": aspect_ratio,
"steps_num": steps_num,
"guidance_scale": guidance_scale,
"seed": seed,
}
if images is not None:
if isinstance(images, torch.Tensor):
preprocess_images = preprocess_image(images)
payload["images"] = [image_to_base64(preprocess_images)]
return payload
def execute(
self,
api_token,
prompt,
model_version,
negative_prompt,
aspect_ratio,
steps_num,
guidance_scale,
seed,
images=None,
):
self._validate_token(api_token)
payload = self._build_payload(
prompt,
model_version,
negative_prompt,
aspect_ratio,
steps_num,
guidance_scale,
seed,
images,
)
api_token = deserialize_and_get_comfy_key(api_token)
headers = {"Content-Type": "application/json", "api_token": api_token}
try:
response = requests.post(self.api_url, json=payload, headers=headers)
if response.status_code in (200, 202):
print(
f"Initial request successful to {self.api_url}, polling for completion..."
)
response_dict = response.json()
status_url = response_dict.get("status_url")
request_id = response_dict.get("request_id")
if not status_url:
raise Exception("No status_url returned from API")
print(f"Request ID: {request_id}, Status URL: {status_url}")
final_response = poll_status_until_completed(status_url, api_token)
result = final_response.get("result", {})
result_image_url = result.get("image_url")
structured_prompt = result.get("structured_prompt", "")
used_seed = result.get("seed")
image_response = requests.get(result_image_url)
result_image = postprocess_image(image_response.content)
return (result_image, structured_prompt, used_seed)
raise Exception(
f"Error: API request failed with status code {response.status_code} {response.text}"
)
except Exception as e:
raise Exception(f"{e}")
class GenerateImageNodeV2(_BaseGenerateImageNodeV2):
"""Standard Image Generation Node"""
def __init__(self):
self.api_url = "https://engine.prod.bria-api.com/v2/image/generate"
+4 -2
View File
@@ -4,7 +4,7 @@ from PIL import Image
import io
import torch
from .common import preprocess_image, preprocess_mask, image_to_base64, poll_status_until_completed
from .common import deserialize_and_get_comfy_key, preprocess_image, preprocess_mask, image_to_base64, poll_status_until_completed
class GenFillNode():
@@ -39,6 +39,7 @@ class GenFillNode():
def execute(self, image, mask, prompt, api_key, seed, prompt_content_moderation, visual_input_content_moderation, visual_output_content_moderation):
if api_key.strip() == "" or api_key.strip() == "BRIA_API_TOKEN":
raise Exception("Please insert a valid API key.")
api_key = deserialize_and_get_comfy_key(api_key)
# Check if image and mask are tensors, if so, convert to NumPy arrays
if isinstance(image, torch.Tensor):
@@ -59,7 +60,8 @@ class GenFillNode():
"seed": seed,
"prompt_content_moderation":prompt_content_moderation,
"visual_input_content_moderation":visual_input_content_moderation,
"visual_output_content_moderation":visual_output_content_moderation
"visual_output_content_moderation":visual_output_content_moderation,
"version": 2
}
headers = {
+2 -1
View File
@@ -4,7 +4,7 @@ from PIL import Image
import io
import torch
from .common import image_to_base64, preprocess_image, poll_status_until_completed
from .common import deserialize_and_get_comfy_key, image_to_base64, preprocess_image, poll_status_until_completed
class ImageExpansionNode():
@@ -55,6 +55,7 @@ class ImageExpansionNode():
api_key):
if api_key.strip() == "" or api_key.strip() == "BRIA_API_TOKEN":
raise Exception("Please insert a valid API key.")
api_key = deserialize_and_get_comfy_key(api_key)
original_image_size = [int(x.strip()) for x in original_image_size.split(",")] if original_image_size else ()
original_image_location = [int(x.strip()) for x in original_image_location.split(",")] if original_image_location else ()
canvas_size = [int(x.strip()) for x in canvas_size.split(",")] if canvas_size else ()
+161
View File
@@ -0,0 +1,161 @@
import requests
from .common import deserialize_and_get_comfy_key, poll_status_until_completed, postprocess_image
class _BaseRefineImageNodeV2:
"""Base class for refine image nodes (standard & pro)."""
api_url = None # Must be overridden by subclasses
generate_api_url = None
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"api_token": ("STRING", {"default": "BRIA_API_TOKEN"}),
"prompt": ("STRING",),
"structured_prompt": ("STRING",),
},
"optional": {
"model_version": (["FIBO"], {"default": "FIBO"}),
"negative_prompt": ("STRING", {"default": ""}),
"aspect_ratio": (
["1:1", "2:3", "3:2", "3:4", "4:3", "4:5", "5:4", "9:16", "16:9"],
{"default": "1:1"},
),
"steps_num": ("INT", {"default": 50, "min": 20, "max": 50}),
"guidance_scale": ("INT", {"default": 5, "min": 3, "max": 5}),
"seed": ("INT", {"default": 123456}),
},
}
RETURN_TYPES = ("IMAGE", "STRING", "INT")
RETURN_NAMES = ("image", "structured_prompt", "seed")
CATEGORY = "API Nodes"
FUNCTION = "execute"
def _validate_token(self, api_token: str):
if api_token.strip() == "" or api_token.strip() == "BRIA_API_TOKEN":
raise Exception("Please insert a valid API token.")
def _build_payload(
self,
prompt,
structured_prompt,
model_version,
negative_prompt,
aspect_ratio,
steps_num,
guidance_scale,
seed,
):
return {
"prompt": prompt,
"model_version": model_version,
"negative_prompt": negative_prompt,
"aspect_ratio": aspect_ratio,
"steps_num": steps_num,
"guidance_scale": guidance_scale,
"seed": seed,
"structured_prompt": structured_prompt,
}
def execute(
self,
api_token,
prompt,
structured_prompt,
model_version,
negative_prompt,
aspect_ratio,
steps_num,
guidance_scale,
seed,
):
self._validate_token(api_token)
payload = self._build_payload(
prompt,
structured_prompt,
model_version,
negative_prompt,
aspect_ratio,
steps_num,
guidance_scale,
seed,
)
api_token = deserialize_and_get_comfy_key(api_token)
headers = {"Content-Type": "application/json", "api_token": api_token}
try:
response = requests.post(self.api_url, json=payload, headers=headers)
if response.status_code in (200, 202):
print(f"Initial refine request successful to {self.api_url}, polling for completion...")
response_dict = response.json()
status_url = response_dict.get("status_url")
request_id = response_dict.get("request_id")
if not status_url:
raise Exception("No status_url returned from API")
print(f"Request ID: {request_id}, Status URL: {status_url}")
final_response = poll_status_until_completed(status_url, api_token)
result = final_response.get("result", {})
structured_prompt = result.get("structured_prompt", "")
used_seed = result.get("seed", seed)
# Step 2 to call genearte image
payloadForImageGenetrate = {
"prompt": prompt,
"structured_prompt":structured_prompt,
"model_version": model_version,
"negative_prompt": negative_prompt,
"aspect_ratio": aspect_ratio,
"steps_num": steps_num,
"guidance_scale": guidance_scale,
"seed": used_seed,
}
headers = {"Content-Type": "application/json", "api_token": api_token}
response = requests.post(self.generate_api_url, json=payloadForImageGenetrate, headers=headers)
if response.status_code in (200, 202):
print(
f"Initial request successful to {self.generate_api_url}, polling for completion..."
)
response_dict = response.json()
status_url = response_dict.get("status_url")
request_id = response_dict.get("request_id")
if not status_url:
raise Exception("No status_url returned from API")
print(f"Request ID: {request_id}, Status URL: {status_url}")
final_response = poll_status_until_completed(status_url, api_token)
result = final_response.get("result", {})
result_image_url = result.get("image_url")
structured_prompt = result.get("structured_prompt", "")
used_seed = result.get("seed")
image_response = requests.get(result_image_url)
result_image = postprocess_image(image_response.content)
return (result_image, structured_prompt, used_seed)
raise Exception(
f"Error: API request failed with status code {response.status_code} {response.text}"
)
except Exception as e:
raise Exception(f"{e}")
class RefineImageNodeV2(_BaseRefineImageNodeV2):
"""Standard Refine Image Node"""
def __init__(self):
self.api_url = "https://engine.prod.bria-api.com/v2/structured_prompt/generate"
self.generate_api_url = "https://engine.prod.bria-api.com/v2/image/generate"
+3 -2
View File
@@ -1,6 +1,6 @@
import requests
from .common import postprocess_image, preprocess_image, image_to_base64
from .common import deserialize_and_get_comfy_key, postprocess_image, preprocess_image, image_to_base64
class ReimagineNode():
@@ -37,7 +37,8 @@ class ReimagineNode():
steps_num, fast, structure_ref_influence, structure_image=None,
tailored_model_id=None, tailored_model_influence=None, tailored_generation_prefix=None,
content_moderation=0,
):
):
api_key = deserialize_and_get_comfy_key(api_key)
payload = {
"prompt": tailored_generation_prefix + prompt,
"num_results": 1,
+2 -1
View File
@@ -4,7 +4,7 @@ from PIL import Image
import io
import torch
from .common import preprocess_image, image_to_base64, poll_status_until_completed
from .common import deserialize_and_get_comfy_key, preprocess_image, image_to_base64, poll_status_until_completed
class RemoveForegroundNode():
@@ -34,6 +34,7 @@ class RemoveForegroundNode():
def execute(self, image, visual_input_content_moderation, visual_output_content_moderation, preserve_alpha, api_key):
if api_key.strip() == "" or api_key.strip() == "BRIA_API_TOKEN":
raise Exception("Please insert a valid API key.")
api_key = deserialize_and_get_comfy_key(api_key)
# Check if image is tensor, if so, convert to NumPy array
if isinstance(image, torch.Tensor):
+2 -1
View File
@@ -4,7 +4,7 @@ from PIL import Image
import io
import torch
from .common import image_to_base64, preprocess_image, preprocess_mask, poll_status_until_completed
from .common import deserialize_and_get_comfy_key, image_to_base64, preprocess_image, preprocess_mask, poll_status_until_completed
class ReplaceBgNode():
@@ -53,6 +53,7 @@ class ReplaceBgNode():
ref_images=None,):
if api_key.strip() == "" or api_key.strip() == "BRIA_API_TOKEN":
raise Exception("Please insert a valid API key.")
api_key = deserialize_and_get_comfy_key(api_key)
# Check if image and mask are tensors, if so, convert to NumPy arrays
if isinstance(image, torch.Tensor):
+2 -2
View File
@@ -4,7 +4,7 @@ from PIL import Image
import io
import torch
from .common import preprocess_image, image_to_base64, poll_status_until_completed
from .common import deserialize_and_get_comfy_key, preprocess_image, image_to_base64, poll_status_until_completed
class RmbgNode():
@classmethod
@@ -34,7 +34,7 @@ class RmbgNode():
def execute(self, image, visual_input_content_moderation, visual_output_content_moderation, preserve_alpha, api_key):
if api_key.strip() == "" or api_key.strip() == "BRIA_API_TOKEN":
raise Exception("Please insert a valid API key.")
api_key = deserialize_and_get_comfy_key(api_key)
# Check if image is tensor, if so, convert to NumPy array
if isinstance(image, torch.Tensor):
image = preprocess_image(image)
+2 -1
View File
@@ -1,6 +1,6 @@
import requests
from .common import postprocess_image, preprocess_image, image_to_base64
from .common import deserialize_and_get_comfy_key, postprocess_image, preprocess_image, image_to_base64
class TailoredGenNode():
@@ -45,6 +45,7 @@ class TailoredGenNode():
guidance_method_2=None, guidance_method_2_scale=None, guidance_method_2_image=None,
content_moderation=0,
):
api_key = deserialize_and_get_comfy_key(api_key)
payload = {
"prompt": generation_prefix + prompt,
"num_results": 1,
+2 -1
View File
@@ -1,5 +1,5 @@
import requests
from .common import deserialize_and_get_comfy_key
class TailoredModelInfoNode():
@classmethod
@@ -21,6 +21,7 @@ class TailoredModelInfoNode():
# Define the execute method as expected by ComfyUI
def execute(self, model_id, api_key):
api_key = deserialize_and_get_comfy_key(api_key)
response = requests.get(
self.api_url + model_id,
headers={"api_token": api_key}
+5 -4
View File
@@ -4,7 +4,7 @@ from PIL import Image
import io
import torch
from .common import image_to_base64, preprocess_image
from .common import deserialize_and_get_comfy_key, image_to_base64, preprocess_image
class TailoredPortraitNode():
@classmethod
@@ -12,7 +12,7 @@ class TailoredPortraitNode():
return {
"required": {
"image": ("IMAGE",), # Input image from another node
"tailored_model_id": ("INT",),
"tailored_model_id": ("STRING",), # API Key input with a default value
"api_key": ("STRING", {"default": "BRIA_API_TOKEN"}), # API Key input with a default value
},
"optional": {
@@ -34,6 +34,7 @@ class TailoredPortraitNode():
def execute(self, image, tailored_model_id, api_key, seed, tailored_model_influence, id_strength):
if api_key.strip() == "" or api_key.strip() == "BRIA_API_TOKEN":
raise Exception("Please insert a valid API key.")
api_key = deserialize_and_get_comfy_key(api_key)
# Convert the image and mask directly to if isinstance(image, torch.Tensor):
if isinstance(image, torch.Tensor):
@@ -44,7 +45,7 @@ class TailoredPortraitNode():
# Prepare the API request payload
payload = {
"id_image_file": f"{image_base64}",
"tailored_model_id": tailored_model_id,
"tailored_model_id": int(tailored_model_id),
"tailored_model_influence": tailored_model_influence,
"id_strength": id_strength,
"seed": seed
@@ -69,7 +70,7 @@ class TailoredPortraitNode():
result_image = torch.from_numpy(result_image)[None,]
return (result_image,)
else:
raise Exception(f"Error: API request failed with status code {response.status_code}")
raise Exception(f"Error: API request failed with status code {response.status_code} {response.text}")
except Exception as e:
raise Exception(f"{e}")
+2 -1
View File
@@ -1,6 +1,6 @@
import requests
from .common import postprocess_image, preprocess_image, image_to_base64
from .common import deserialize_and_get_comfy_key, postprocess_image, preprocess_image, image_to_base64
class Text2ImageBaseNode():
@@ -48,6 +48,7 @@ class Text2ImageBaseNode():
image_prompt_mode=None, image_prompt_image=None, image_prompt_scale=None,
content_moderation=0,
):
api_key = deserialize_and_get_comfy_key(api_key)
payload = {
"prompt": prompt,
"num_results": 1,
+2 -1
View File
@@ -1,6 +1,6 @@
import requests
from .common import postprocess_image, preprocess_image, image_to_base64
from .common import deserialize_and_get_comfy_key, postprocess_image, preprocess_image, image_to_base64
class Text2ImageFastNode():
@@ -45,6 +45,7 @@ class Text2ImageFastNode():
image_prompt_mode=None, image_prompt_image=None, image_prompt_scale=None,
content_moderation=0,
):
api_key = deserialize_and_get_comfy_key(api_key)
payload = {
"prompt": prompt,
"num_results": 1,
+3 -2
View File
@@ -1,6 +1,6 @@
import requests
from .common import postprocess_image
from .common import deserialize_and_get_comfy_key, postprocess_image
class Text2ImageHDNode():
@@ -29,12 +29,13 @@ class Text2ImageHDNode():
FUNCTION = "execute"
def __init__(self):
self.api_url = "https://engine.prod.bria-api.com/v1/text-to-image/hd/2.3" #"http://0.0.0.0:5000/v1/text-to-image/hd/2.3"
self.api_url = "https://engine.prod.bria-api.com/v1/text-to-image/hd/2.2" #"http://0.0.0.0:5000/v1/text-to-image/hd/2.3"
def execute(
self, api_key, prompt, aspect_ratio, seed, negative_prompt,
steps_num, prompt_enhancement, text_guidance_scale, medium, content_moderation=0,
):
api_key = deserialize_and_get_comfy_key(api_key)
payload = {
"prompt": prompt,
"num_results": 1,
+5 -2
View File
@@ -1,6 +1,6 @@
import requests
import torch
from ..common import postprocess_image, preprocess_image, image_to_base64
from ..common import deserialize_and_get_comfy_key, postprocess_image, preprocess_image, image_to_base64
shot_by_text_api_url = (
"https://engine.prod.bria-api.com/v1/product/lifestyle_shot_by_text"
@@ -68,6 +68,7 @@ def create_text_payload(
validate_api_key(api_key)
# Process image
if isinstance(image, torch.Tensor):
image = preprocess_image(image)
@@ -126,9 +127,11 @@ def create_image_payload(image, ref_image, api_key, placement_type, **kwargs):
def make_api_request(api_url, payload, api_key, Placement_type = None):
"""Make API request and return processed image"""
headers = {"Content-Type": "application/json", "api_token": f"{api_key}"}
try:
api_key = deserialize_and_get_comfy_key(api_key)
headers = {"Content-Type": "application/json", "api_token": f"{api_key}"}
response = requests.post(api_url, json=payload, headers=headers)
if response.status_code == 200:
+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.3"
version = "2.1.8"
license = {file = "LICENSE"}
[project.urls]
+543
View File
@@ -0,0 +1,543 @@
{
"id": "3875cd62-7a0e-4c8c-8951-22ec8a63dd8d",
"revision": 0,
"last_node_id": 14,
"last_link_id": 8,
"nodes": [
{
"id": 3,
"type": "PreviewImage",
"pos": [
632.3427124023438,
32.13115310668945
],
"size": [
140,
26
],
"flags": {},
"order": 4,
"mode": 0,
"inputs": [
{
"name": "images",
"type": "IMAGE",
"link": 1
}
],
"outputs": [],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.62",
"Node name for S&R": "PreviewImage"
}
},
{
"id": 2,
"type": "RefineImageNodeV2",
"pos": [
704.8090209960938,
218.65850830078125
],
"size": [
287.4712829589844,
314
],
"flags": {},
"order": 5,
"mode": 0,
"inputs": [
{
"name": "structured_prompt",
"type": "STRING",
"widget": {
"name": "structured_prompt"
},
"link": 3
},
{
"name": "seed",
"shape": 7,
"type": "INT",
"widget": {
"name": "seed"
},
"link": 2
}
],
"outputs": [
{
"name": "image",
"type": "IMAGE",
"links": [
4
]
},
{
"name": "structured_prompt",
"type": "STRING",
"links": null
},
{
"name": "seed",
"type": "INT",
"links": null
}
],
"properties": {
"cnr_id": "comfyui-bria-api",
"ver": "2.1.4",
"Node name for S&R": "RefineImageNodeV2",
"ue_properties": {
"widget_ue_connectable": {
"api_token": true,
"prompt": true,
"structured_prompt": true,
"model_version": true,
"negative_prompt": true,
"aspect_ratio": true,
"steps_num": true,
"guidance_scale": true,
"seed": true
},
"version": "7.1",
"input_ue_unconnectable": {}
}
},
"widgets_values": [
"BRIA_API_TOKEN",
"",
"",
"FIBO",
"",
"1:1",
50,
5,
123456,
"randomize"
]
},
{
"id": 4,
"type": "PreviewImage",
"pos": [
1153.29345703125,
270.2264404296875
],
"size": [
140,
26
],
"flags": {},
"order": 8,
"mode": 0,
"inputs": [
{
"name": "images",
"type": "IMAGE",
"link": 4
}
],
"outputs": [],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.62",
"Node name for S&R": "PreviewImage"
}
},
{
"id": 1,
"type": "GenerateImageNodeV2",
"pos": [
272.6366882324219,
227.9468231201172
],
"size": [
270,
290
],
"flags": {},
"order": 0,
"mode": 0,
"inputs": [
{
"name": "images",
"shape": 7,
"type": "IMAGE",
"link": null
}
],
"outputs": [
{
"name": "image",
"type": "IMAGE",
"links": [
1
]
},
{
"name": "structured_prompt",
"type": "STRING",
"links": [
3
]
},
{
"name": "seed",
"type": "INT",
"links": [
2
]
}
],
"properties": {
"cnr_id": "comfyui-bria-api",
"ver": "2.1.4",
"Node name for S&R": "GenerateImageNodeV2",
"ue_properties": {
"widget_ue_connectable": {
"api_token": true,
"prompt": true,
"model_version": true,
"negative_prompt": true,
"aspect_ratio": true,
"steps_num": true,
"guidance_scale": true,
"seed": true
},
"version": "7.1",
"input_ue_unconnectable": {}
}
},
"widgets_values": [
"BRIA_API_TOKEN",
"",
"FIBO",
"",
"1:1",
50,
5,
123456,
"randomize"
]
},
{
"id": 5,
"type": "Note",
"pos": [
-43.613197326660156,
324.2381896972656
],
"size": [
210,
88
],
"flags": {},
"order": 1,
"mode": 0,
"inputs": [],
"outputs": [],
"properties": {},
"widgets_values": [
"If you would like to start with prompt"
],
"color": "#c09430",
"bgcolor": "rgba(24,24,27,.9)"
},
{
"id": 10,
"type": "PreviewImage",
"pos": [
1182.5216064453125,
1006.7373657226562
],
"size": [
140,
26
],
"flags": {},
"order": 9,
"mode": 0,
"inputs": [
{
"name": "images",
"type": "IMAGE",
"link": 7
}
],
"outputs": [],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.62",
"Node name for S&R": "PreviewImage"
}
},
{
"id": 9,
"type": "RefineImageNodeV2",
"pos": [
703.2684326171875,
1034.9910888671875
],
"size": [
287.4712829589844,
314
],
"flags": {},
"order": 7,
"mode": 0,
"inputs": [
{
"name": "structured_prompt",
"type": "STRING",
"widget": {
"name": "structured_prompt"
},
"link": 5
},
{
"name": "seed",
"shape": 7,
"type": "INT",
"widget": {
"name": "seed"
},
"link": 6
}
],
"outputs": [
{
"name": "image",
"type": "IMAGE",
"links": [
7
]
},
{
"name": "structured_prompt",
"type": "STRING",
"links": null
},
{
"name": "seed",
"type": "INT",
"links": null
}
],
"properties": {
"cnr_id": "comfyui-bria-api",
"ver": "2.1.5",
"Node name for S&R": "RefineImageNodeV2"
},
"widgets_values": [
"BRIA_API_TOKEN",
"",
"",
"FIBO",
"",
"1:1",
50,
5,
123456,
"randomize"
]
},
{
"id": 6,
"type": "Note",
"pos": [
-47.50065612792969,
1042.9178466796875
],
"size": [
210,
95.76702880859375
],
"flags": {},
"order": 2,
"mode": 0,
"inputs": [],
"outputs": [],
"properties": {},
"widgets_values": [
"If you would like to start with reference image + prompt"
],
"color": "#c09430",
"bgcolor": "rgba(24,24,27,.9)"
},
{
"id": 14,
"type": "PreviewImage",
"pos": [
593.5224609375,
844.5531616210938
],
"size": [
140,
26
],
"flags": {},
"order": 6,
"mode": 0,
"inputs": [
{
"name": "images",
"type": "IMAGE",
"link": 8
}
],
"outputs": [],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.62",
"Node name for S&R": "PreviewImage"
}
},
{
"id": 7,
"type": "GenerateImageNodeV2",
"pos": [
262.3690490722656,
1041.67431640625
],
"size": [
270,
290
],
"flags": {},
"order": 3,
"mode": 0,
"inputs": [
{
"name": "images",
"shape": 7,
"type": "IMAGE",
"link": null
}
],
"outputs": [
{
"name": "image",
"type": "IMAGE",
"links": [
8
]
},
{
"name": "structured_prompt",
"type": "STRING",
"links": [
5
]
},
{
"name": "seed",
"type": "INT",
"links": [
6
]
}
],
"properties": {
"cnr_id": "comfyui-bria-api",
"ver": "2.1.5",
"Node name for S&R": "GenerateImageNodeV2"
},
"widgets_values": [
"BRIA_API_TOKEN",
"",
"FIBO",
"",
"1:1",
50,
5,
123456,
"randomize"
]
}
],
"links": [
[
1,
1,
0,
3,
0,
"IMAGE"
],
[
2,
1,
2,
2,
1,
"INT"
],
[
3,
1,
1,
2,
0,
"STRING"
],
[
4,
2,
0,
4,
0,
"IMAGE"
],
[
5,
7,
1,
9,
0,
"STRING"
],
[
6,
7,
2,
9,
1,
"INT"
],
[
7,
9,
0,
10,
0,
"IMAGE"
],
[
8,
7,
0,
14,
0,
"IMAGE"
]
],
"groups": [],
"config": {},
"extra": {
"ue_links": [],
"ds": {
"scale": 0.3897342147473183,
"offset": [
658.5745748406673,
99.37411299539059
]
},
"frontendVersion": "1.28.4",
"VHS_latentpreview": false,
"VHS_latentpreviewrate": 0,
"VHS_MetadataImage": true,
"VHS_KeepIntermediate": true
},
"version": 0.4
}