Compare commits
66
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9b3f15b7bd | ||
|
|
f7c9ed12b0 | ||
|
|
bdd053a81b | ||
|
|
2913a9eb6b | ||
|
|
080c17f4a4 | ||
|
|
711080ffb0 | ||
|
|
69f111bfe9 | ||
|
|
011f728b0d | ||
|
|
ac9678cd23 | ||
|
|
daede982ac | ||
|
|
e716e585df | ||
|
|
1296b6a27c | ||
|
|
19f15f4ba4 | ||
|
|
30d0154caf | ||
|
|
283665f654 | ||
|
|
03e3bec952 | ||
|
|
f1793ba9ad | ||
|
|
eda093ea66 | ||
|
|
165a103f0c | ||
|
|
ad2f4a5853 | ||
|
|
43f858dca4 | ||
|
|
538cd53ac8 | ||
|
|
bae0ed3842 | ||
|
|
a164f8ec45 | ||
|
|
ebe9e2e6b1 | ||
|
|
429c51ac6d | ||
|
|
aed4832984 | ||
|
|
a78aff0fb2 | ||
|
|
6edfc55109 | ||
|
|
00dccbb17a | ||
|
|
1cb9ce4394 | ||
|
|
b2f8b8d0e3 | ||
|
|
129bc599d0 | ||
|
|
28c2631581 | ||
|
|
baadbc02bc | ||
|
|
a73045f8e6 | ||
|
|
dd74d03fd0 | ||
|
|
bfc83da41f | ||
|
|
499ec5d104 | ||
|
|
fef2e49902 | ||
|
|
2eae6dae46 | ||
|
|
28c0cdf8d5 | ||
|
|
54f380f1f0 | ||
|
|
4f7691ff93 | ||
|
|
1781beff09 | ||
|
|
502206f518 | ||
|
|
da8adda281 | ||
|
|
1c02dea96b | ||
|
|
5b77fd90a8 | ||
|
|
246e05ac3e | ||
|
|
b6f2f8b297 | ||
|
|
5052a7bf94 | ||
|
|
afc9599c63 | ||
|
|
13a3dfb2bb | ||
|
|
6573f2e43d | ||
|
|
ac7e97c348 | ||
|
|
c6fe701115 | ||
|
|
ab17ee227d | ||
|
|
2fa966e887 | ||
|
|
3b5cca2dc8 | ||
|
|
aaf0729f78 | ||
|
|
1a37414fe4 | ||
|
|
2fbbce0d1b | ||
|
|
23f9e46eff | ||
|
|
a4855c1a1a | ||
|
|
709d16cb72 |
@@ -7,17 +7,19 @@ on:
|
||||
paths:
|
||||
- "pyproject.toml"
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
|
||||
jobs:
|
||||
publish-node:
|
||||
name: Publish Custom Node to registry
|
||||
runs-on: ubuntu-latest
|
||||
# if this is a forked repository. Skipping the workflow.
|
||||
if: github.event.repository.fork == false
|
||||
if: ${{ github.repository_owner == 'Bria-AI' }}
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
- name: Publish Custom Node
|
||||
uses: Comfy-Org/publish-node-action@main
|
||||
uses: Comfy-Org/publish-node-action@v1
|
||||
with:
|
||||
## Add your own personal access token to your Github Repository secrets and reference it here.
|
||||
personal_access_token: ${{ secrets.REGISTRY_ACCESS_TOKEN }}
|
||||
|
||||
+2
-1
@@ -1 +1,2 @@
|
||||
*.pyc
|
||||
*.pyc
|
||||
.idea
|
||||
@@ -4,14 +4,22 @@
|
||||
<img src="./images/Bria Logo.svg" alt="BRIA Logo" width="200"/>
|
||||
</p>
|
||||
|
||||
This repository provides custom nodes for ComfyUI, enabling direct access to **BRIA's API endpoints** for image generation workflows. **API documentation** is available [**here**](https://bria-ai-api-docs.redoc.ly/#operation//generation/bria-v2/text-to-image).
|
||||
This repository provides custom nodes for ComfyUI, enabling direct access to **BRIA's API endpoints** for image generation and editing workflows. **API documentation** is available [**here**](https://docs.bria.ai/).
|
||||
|
||||
BRIA's APIs and models are built for commercial use and trained on 100% licensed data and does not contain copyrighted materials, such as fictional characters, logos, trademarks, public figures, harmful content, or privacy-infringing content.
|
||||
|
||||
An API token is required to use the nodes in your workflows. Get started quickly here
|
||||
<a href="https://bria.ai/api/" style="text-decoration:none; vertical-align:middle;">
|
||||
<img src="https://img.shields.io/badge/GET%20YOUR%20TOKEN-1000%20Free%20Calls-blue?style=flat-square" alt="Get Your Token" height="20">
|
||||
</a>.
|
||||
|
||||
for direct API endpoint use, you can find our APIs through partners like [**fal.ai**](https://fal.ai/models?keywords=bria).
|
||||
For source code and weigths access, go to our [**Hugging Face**](https://huggingface.co/briaai) space.
|
||||
|
||||
To load a workflow, import the compatible workflow.json files from this [folder](workflows).
|
||||
<p align="center">
|
||||
<img src="./images/background_workflow.png" width="1200"/>
|
||||
</p>
|
||||
|
||||
|
||||
<!-- Placeholder image of cool workflows. -->
|
||||
@@ -19,43 +27,46 @@ To load a workflow, import the compatible workflow.json files from this [folder]
|
||||
|
||||
<!-- <img src="./images/bria_api_nodes_workflow_diagram.png" alt="all workflows example" width="400"/> <img src="./images/bria_api_nodes_workflow_diagram_2.png" alt="all workflows example" width="400"/> -->
|
||||
|
||||
# Coming soon
|
||||
|
||||
- [ ] Video Editing
|
||||
|
||||
# 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.
|
||||
|
||||
### **Text2Image Base Node**
|
||||
This node generates images from text prompts, serving as the foundation for creating visuals based on descriptive input. [[🤗model card](https://huggingface.co/briaai/BRIA-2.3)]
|
||||
| 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. |
|
||||
|
||||
## Tailored Generation Nodes
|
||||
These nodes use pre-trained tailored models to generate images that faithfully reproduce specific visual IP elements or guidelines. [[API docs](https://bria-ai-api-docs.redoc.ly/tag/Tailored-Generation)].
|
||||
These nodes use pre-trained tailored models to generate images that faithfully reproduce specific visual IP elements or guidelines.
|
||||
|
||||
### **Tailored Gen**
|
||||
This node generates images using a trained tailored model, faithfully reproducing specific visual IP elements or guidelines established during model training.
|
||||
|
||||
### **Tailored Model Info**
|
||||
This node retrieves the **default settings** and **prompt prefix** of a **trained tailored model**. It provides the necessary information to configure and run the model in the **Tailored Gen node**, ensuring consistency with the model's intended behavior.
|
||||
| Node | Description |
|
||||
|------------------------|--------------------------------------------------------------------|
|
||||
| **Tailored Gen** | Generates images using a trained tailored model, reproducing specific visual IP elements or guidelines. Use the Tailored Model Info node to load the model's default settings. |
|
||||
| **Tailored Model Info**| Retrieves the default settings and prompt prefix of a trained tailored model, which can be used to configure the Tailored Gen node. |
|
||||
| **Restyle Portrait** | Transforms the style of a portrait while preserving the person's facial features. |
|
||||
|
||||
## Image Editing Nodes
|
||||
These nodes modify specific parts of images, enabling adjustments, while maintaining the integrity of the rest of the image.[[API docs](https://bria-ai-api-docs.redoc.ly/tag/Image-Editing)]
|
||||
These nodes modify specific parts of images, enabling adjustments while maintaining the integrity of the rest of the image.
|
||||
|
||||
### **Eraser**
|
||||
This node is used to remove specific objects or areas from an image by providing a mask. Powered by BRIA's ControlNet inpainting [[🤗model card](https://huggingface.co/briaai/BRIA-2.3-ControlNet-Inpainting)] [[🤗HF demo](https://huggingface.co/spaces/briaai/BRIA-Eraser-API)].
|
||||
| Node | Description |
|
||||
|------------------------|--------------------------------------------------------------------|
|
||||
| **RMBG 2.0 (Remove Background)** | Removes the background from an image, isolating the foreground subject. |
|
||||
| **Replace Background** | Replaces an image’s background with a new one, guided by either a reference image or a prompt. |
|
||||
| **Expand Image** | Expands the dimensions of an image, generating new content to fill the extended areas. |
|
||||
| **Eraser** | Removes specific objects or areas from an image by providing a mask. |
|
||||
| **GenFill** | Generates objects by prompt in a specific region of an image. |
|
||||
| **Erase Foreground** | Removes the foreground from an image, isolating the background. |
|
||||
|
||||
### **GenFill**
|
||||
This node is used to generate objects by prompt in a specific region of an image. This functionality is powered by BRIA's ControlNet Generative Fill. [[🤗model card](https://huggingface.co/briaai/BRIA-2.3-ControlNet-Generative-Fill)] [[🤗HF demo](https://huggingface.co/spaces/briaai/BRIA-Generative-Fill-API)]
|
||||
## Product Shot Editing Nodes
|
||||
These nodes create high-quality product images for eCommerce workflows.
|
||||
|
||||
## Product Shot Generation Nodes
|
||||
These nodes create high-quality product images for eCommerce workflows. [[API docs](https://bria-ai-api-docs.redoc.ly/tag/Product-Shots-Generation)]
|
||||
|
||||
### **ShotByText**
|
||||
This node is used to modify the background in an image by providing a prompt, This functionality is powered by BRIA's ControlNet Background-Generation.[[🤗ContrlNet model card](https://huggingface.co/briaai/BRIA-2.3-ControlNet-BG-Gen)] [[🤗HF demo](https://huggingface.co/spaces/briaai/Product-Shot-Generation)].
|
||||
|
||||
### **ShotByImage**
|
||||
This node is used to modify the background in an image by providing a reference image. This functionality is powered by BRIA's ControlNet Background-Generation and BRIA's Image-Prompt. [[🤗ContrlNet model card](https://huggingface.co/briaai/BRIA-2.3-ControlNet-Inpainting)] [[🤗IP-Adapter model card](https://huggingface.co/briaai/Image-Prompt)] [[🤗HF demo](https://huggingface.co/spaces/briaai/Product-Shot-Generation)].
|
||||
| Node | Description |
|
||||
|------------------------|--------------------------------------------------------------------|
|
||||
| **ShotByText** | Modifies an image's background by providing a text prompt. Powered by BRIA's ControlNet Background-Generation. |
|
||||
| **ShotByImage** | Modifies an image's background by providing a reference image. Uses BRIA's ControlNet Background-Generation and Image-Prompt. |
|
||||
|
||||
# Installation
|
||||
There are two methods to install the BRIA ComfyUI API nodes:
|
||||
|
||||
+12
-2
@@ -1,14 +1,19 @@
|
||||
from .nodes import (EraserNode, GenFillNode, ShotByTextNode, ShotByImageNode, TailoredGenNode,
|
||||
TailoredModelInfoNode, Text2ImageBaseNode, Text2ImageFastNode, Text2ImageHDNode,
|
||||
from .nodes import (EraserNode, GenFillNode, ImageExpansionNode, ReplaceBgNode, RmbgNode, RemoveForegroundNode, ShotByTextNode, ShotByImageNode, TailoredGenNode,
|
||||
TailoredModelInfoNode, Text2ImageBaseNode, Text2ImageFastNode, Text2ImageHDNode, TailoredPortraitNode,
|
||||
ReimagineNode)
|
||||
# Map the node class to a name used internally by ComfyUI
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"BriaEraser": EraserNode, # Return the class, not an instance
|
||||
"BriaGenFill": GenFillNode,
|
||||
"ImageExpansionNode": ImageExpansionNode,
|
||||
"ReplaceBgNode": ReplaceBgNode,
|
||||
"RmbgNode": RmbgNode,
|
||||
"RemoveForegroundNode": RemoveForegroundNode,
|
||||
"ShotByTextNode": ShotByTextNode,
|
||||
"ShotByImageNode": ShotByImageNode,
|
||||
"BriaTailoredGen": TailoredGenNode,
|
||||
"TailoredModelInfoNode": TailoredModelInfoNode,
|
||||
"TailoredPortraitNode": TailoredPortraitNode,
|
||||
"Text2ImageBaseNode": Text2ImageBaseNode,
|
||||
"Text2ImageFastNode": Text2ImageFastNode,
|
||||
"Text2ImageHDNode": Text2ImageHDNode,
|
||||
@@ -18,10 +23,15 @@ NODE_CLASS_MAPPINGS = {
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"BriaEraser": "Bria Eraser",
|
||||
"BriaGenFill": "Bria GenFill",
|
||||
"ImageExpansionNode": "Bria Image Expansion",
|
||||
"ReplaceBgNode": "Bria Replace Background",
|
||||
"RmbgNode": "Bria RMBG",
|
||||
"RemoveForegroundNode": "Bria Remove Foreground",
|
||||
"ShotByTextNode": "Bria Shot By Text",
|
||||
"ShotByImageNode": "Bria Shot By Image",
|
||||
"BriaTailoredGen": "Bria Tailored Gen",
|
||||
"TailoredModelInfoNode": "Bria Tailored Model Info",
|
||||
"TailoredPortraitNode": "Bria Restyle Portrait",
|
||||
"Text2ImageBaseNode": "Bria Text2Image Base",
|
||||
"Text2ImageFastNode": "Bria Text2Image Fast",
|
||||
"Text2ImageHDNode": "Bria Text2Image HD",
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 634 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 714 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.5 MiB |
@@ -1,9 +1,14 @@
|
||||
from .eraser_node import EraserNode
|
||||
from .generative_fill_node import GenFillNode
|
||||
from .image_expansion_node import ImageExpansionNode
|
||||
from .replace_bg_node import ReplaceBgNode
|
||||
from .rmbg_node import RmbgNode
|
||||
from .remove_foreground_node import RemoveForegroundNode
|
||||
from .shot_by_text_node import ShotByTextNode
|
||||
from .shot_by_image_node import ShotByImageNode
|
||||
from .tailored_gen_node import TailoredGenNode
|
||||
from .tailored_model_info_node import TailoredModelInfoNode
|
||||
from .tailored_portrait_node import TailoredPortraitNode
|
||||
from .text_2_image_base_node import Text2ImageBaseNode
|
||||
from .text_2_image_fast_node import Text2ImageFastNode
|
||||
from .text_2_image_hd_node import Text2ImageHDNode
|
||||
|
||||
+67
-12
@@ -5,6 +5,7 @@ import torch
|
||||
import base64
|
||||
from torchvision.transforms import ToPILImage
|
||||
import requests
|
||||
import time
|
||||
|
||||
def postprocess_image(image):
|
||||
result_image = Image.open(io.BytesIO(image))
|
||||
@@ -44,7 +45,7 @@ def preprocess_mask(mask):
|
||||
return mask
|
||||
|
||||
|
||||
def process_request(api_url, image, mask, api_key):
|
||||
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.")
|
||||
|
||||
@@ -58,10 +59,12 @@ def process_request(api_url, image, mask, api_key):
|
||||
image_base64 = image_to_base64(image)
|
||||
mask_base64 = image_to_base64(mask)
|
||||
|
||||
# Prepare the API request payload
|
||||
# Prepare the API request payload for v2 API
|
||||
payload = {
|
||||
"file": f"{image_base64}",
|
||||
"mask_file": f"{mask_base64}"
|
||||
"image": image_base64,
|
||||
"mask": mask_base64,
|
||||
"visual_input_content_moderation":visual_input_content_moderation,
|
||||
"visual_output_content_moderation":visual_output_content_moderation
|
||||
}
|
||||
|
||||
headers = {
|
||||
@@ -70,13 +73,23 @@ def process_request(api_url, image, mask, api_key):
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.post(api_url, json=payload, headers=headers)
|
||||
# Check for successful response
|
||||
if response.status_code == 200:
|
||||
print('response is 200')
|
||||
# Process the output image from API response
|
||||
response = requests.post(api_url, json=payload, headers=headers)
|
||||
if response.status_code == 200 or response.status_code == 202:
|
||||
print('Initial request successful, polling for completion...')
|
||||
response_dict = response.json()
|
||||
image_response = requests.get(response_dict['result_url'])
|
||||
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_key)
|
||||
result_image_url = final_response['result']['image_url']
|
||||
|
||||
# Download and process the result image
|
||||
image_response = requests.get(result_image_url)
|
||||
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
|
||||
@@ -84,9 +97,51 @@ def process_request(api_url, image, mask, api_key):
|
||||
# image_tensor = image_tensor = ToTensor()(output_image)
|
||||
# image_tensor = image_tensor.permute(1, 2, 0) / 255.0 # Shape now becomes [1, 2200, 1548, 3]
|
||||
# print(f"output tensor shape is: {image_tensor.shape}")
|
||||
return (result_image,)
|
||||
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}")
|
||||
|
||||
|
||||
def poll_status_until_completed(status_url, api_key, timeout=360, check_interval=2):
|
||||
"""
|
||||
Poll a status URL until the status is COMPLETED or timeout is reached.
|
||||
|
||||
Args:
|
||||
status_url (str): The status URL to poll
|
||||
api_key (str): API token for authentication
|
||||
timeout (int): Maximum time to wait in seconds (default: 360)
|
||||
check_interval (int): Time between checks in seconds (default: 2)
|
||||
|
||||
Returns:
|
||||
dict: The final response containing the result
|
||||
|
||||
Raises:
|
||||
Exception: If timeout is reached or API request fails
|
||||
"""
|
||||
start_time = time.time()
|
||||
headers = {"api_token": api_key}
|
||||
|
||||
while time.time() - start_time < timeout:
|
||||
try:
|
||||
response = requests.get(status_url, headers=headers)
|
||||
if response.status_code == 200 or response.status_code == 202:
|
||||
response_dict = response.json()
|
||||
status = response_dict.get("status", "").upper()
|
||||
|
||||
if status == "COMPLETED":
|
||||
return response_dict
|
||||
elif status == "ERROR":
|
||||
raise Exception(f"Request failed: {response_dict}")
|
||||
else:
|
||||
print(f"Status: {status}, waiting...")
|
||||
time.sleep(check_interval)
|
||||
else:
|
||||
raise Exception(f"Status check failed with status code {response.status_code}")
|
||||
|
||||
except requests.exceptions.RequestException as e:
|
||||
raise Exception(f"Error checking status: {e}")
|
||||
|
||||
raise Exception(f"Timeout reached after {timeout} seconds")
|
||||
|
||||
@@ -8,6 +8,10 @@ class EraserNode():
|
||||
"image": ("IMAGE",), # Input image from another node
|
||||
"mask": ("MASK",), # Binary mask input
|
||||
"api_key": ("STRING", {"default": "BRIA_API_TOKEN"}) # API Key input with a default value
|
||||
},
|
||||
"optional": {
|
||||
"visual_input_content_moderation": ("BOOLEAN", {"default": False}),
|
||||
"visual_output_content_moderation": ("BOOLEAN", {"default": False}),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,9 +21,9 @@ class EraserNode():
|
||||
FUNCTION = "execute" # This is the method that will be executed
|
||||
|
||||
def __init__(self):
|
||||
self.api_url = "https://engine.prod.bria-api.com/v1/eraser" # Eraser API URL
|
||||
self.api_url = "https://engine.prod.bria-api.com/v2/image/edit/erase" # Eraser API URL
|
||||
|
||||
# Define the execute method as expected by ComfyUI
|
||||
def execute(self, image, mask, api_key):
|
||||
return process_request(self.api_url, image, mask, api_key)
|
||||
def execute(self, image, mask, api_key, visual_input_content_moderation, visual_output_content_moderation):
|
||||
return process_request(self.api_url, image, mask, api_key, visual_input_content_moderation, visual_output_content_moderation)
|
||||
|
||||
@@ -4,7 +4,7 @@ from PIL import Image
|
||||
import io
|
||||
import torch
|
||||
|
||||
from .common import image_to_base64, preprocess_image, preprocess_mask
|
||||
from .common import preprocess_image, preprocess_mask, image_to_base64, poll_status_until_completed
|
||||
|
||||
|
||||
class GenFillNode():
|
||||
@@ -17,6 +17,14 @@ class GenFillNode():
|
||||
"prompt": ("STRING",),
|
||||
"api_key": ("STRING", {"default": "BRIA_API_TOKEN"}), # API Key input with a default value
|
||||
},
|
||||
"optional": {
|
||||
"seed": ("INT", {"default": 123456}),
|
||||
"prompt_content_moderation": ("BOOLEAN", {"default": True}),
|
||||
"visual_input_content_moderation": ("BOOLEAN", {"default": False}),
|
||||
"visual_output_content_moderation": ("BOOLEAN", {"default": False}),
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
@@ -25,10 +33,10 @@ class GenFillNode():
|
||||
FUNCTION = "execute" # This is the method that will be executed
|
||||
|
||||
def __init__(self):
|
||||
self.api_url = "https://engine.prod.bria-api.com/v1/gen_fill" # Eraser API URL
|
||||
self.api_url = "https://engine.prod.bria-api.com/v2/image/edit/gen_fill"
|
||||
|
||||
# Define the execute method as expected by ComfyUI
|
||||
def execute(self, image, mask, prompt, api_key):
|
||||
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.")
|
||||
|
||||
@@ -44,11 +52,14 @@ class GenFillNode():
|
||||
|
||||
# Prepare the API request payload
|
||||
payload = {
|
||||
"file": f"{image_base64}",
|
||||
"mask_file": f"{mask_base64}",
|
||||
"image": image_base64,
|
||||
"mask": mask_base64,
|
||||
"prompt": prompt,
|
||||
"negative_prompt": "blurry",
|
||||
"sync": True
|
||||
"seed": seed,
|
||||
"prompt_content_moderation":prompt_content_moderation,
|
||||
"visual_input_content_moderation":visual_input_content_moderation,
|
||||
"visual_output_content_moderation":visual_output_content_moderation
|
||||
}
|
||||
|
||||
headers = {
|
||||
@@ -57,20 +68,30 @@ class GenFillNode():
|
||||
}
|
||||
|
||||
try:
|
||||
# Send initial request to get status URL
|
||||
response = requests.post(self.api_url, json=payload, headers=headers)
|
||||
# Check for successful response
|
||||
if response.status_code == 200:
|
||||
print('response is 200')
|
||||
# Process the output image from API response
|
||||
|
||||
if response.status_code == 200 or response.status_code == 202:
|
||||
print('Initial genfill request successful, polling for completion...')
|
||||
response_dict = response.json()
|
||||
image_response = requests.get(response_dict['urls'][0])
|
||||
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_key)
|
||||
result_image_url = final_response['result']['image_url']
|
||||
image_response = requests.get(result_image_url)
|
||||
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
|
||||
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}")
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
import numpy as np
|
||||
import requests
|
||||
from PIL import Image
|
||||
import io
|
||||
import torch
|
||||
|
||||
from .common import image_to_base64, preprocess_image, poll_status_until_completed
|
||||
|
||||
|
||||
class ImageExpansionNode():
|
||||
@classmethod
|
||||
def INPUT_TYPES(self):
|
||||
return {
|
||||
"required": {
|
||||
"image": ("IMAGE",), # Input image from another node
|
||||
"api_key": ("STRING", {"default": "BRIA_API_TOKEN"}), # API Key input with a default value
|
||||
},
|
||||
|
||||
"optional": {
|
||||
"original_image_size": ("STRING",),
|
||||
"original_image_location": ("STRING",),
|
||||
"canvas_size": ("STRING", {"default": "1000, 1000"}),
|
||||
"aspect_ratio": (["1:1", "2:3", "3:2", "3:4", "4:3", "4:5", "5:4", "9:16", "16:9","None"], {"default": "None"}),
|
||||
"prompt": ("STRING", {"default": ""}),
|
||||
"seed": ("INT", {"default": 681794}),
|
||||
"negative_prompt": ("STRING", {"default": "Ugly, mutated"}),
|
||||
"prompt_content_moderation": ("BOOLEAN", {"default": False}),
|
||||
"preserve_alpha": ("BOOLEAN", {"default": True}),
|
||||
"visual_input_content_moderation": ("BOOLEAN", {"default": False}),
|
||||
"visual_output_content_moderation": ("BOOLEAN", {"default": False}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
RETURN_NAMES = ("output_image",)
|
||||
CATEGORY = "API Nodes"
|
||||
FUNCTION = "execute" # This is the method that will be executed
|
||||
|
||||
def __init__(self):
|
||||
self.api_url = "https://engine.prod.bria-api.com/v2/image/edit/expand" # Image Expansion API URL
|
||||
|
||||
# Define the execute method as expected by ComfyUI
|
||||
def execute(self, image,
|
||||
original_image_size,
|
||||
original_image_location,
|
||||
canvas_size,
|
||||
aspect_ratio,
|
||||
prompt,
|
||||
seed,
|
||||
negative_prompt,
|
||||
prompt_content_moderation,
|
||||
preserve_alpha,
|
||||
visual_input_content_moderation,
|
||||
visual_output_content_moderation,
|
||||
api_key):
|
||||
if api_key.strip() == "" or api_key.strip() == "BRIA_API_TOKEN":
|
||||
raise Exception("Please insert a valid 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 ()
|
||||
|
||||
if negative_prompt == "":
|
||||
negative_prompt = " " # hack to avoid error in triton which expects non-empty string
|
||||
|
||||
# Check if image and mask are tensors, if so, convert to NumPy arrays
|
||||
if isinstance(image, torch.Tensor):
|
||||
image = preprocess_image(image)
|
||||
|
||||
# Convert the image directly to Base64 string
|
||||
image_base64 = image_to_base64(image)
|
||||
if aspect_ratio and aspect_ratio != "None":
|
||||
payload = {
|
||||
"image": image_base64,
|
||||
"aspect_ratio": aspect_ratio,
|
||||
"prompt": prompt,
|
||||
"negative_prompt": negative_prompt,
|
||||
"seed": seed,
|
||||
"prompt_content_moderation": prompt_content_moderation,
|
||||
"preserve_alpha": preserve_alpha,
|
||||
"visual_input_content_moderation": visual_input_content_moderation,
|
||||
"visual_output_content_moderation": visual_output_content_moderation
|
||||
}
|
||||
else:
|
||||
payload = {
|
||||
"image": image_base64,
|
||||
"original_image_size": original_image_size,
|
||||
"original_image_location": original_image_location,
|
||||
"canvas_size": canvas_size,
|
||||
"prompt": prompt,
|
||||
"negative_prompt": negative_prompt,
|
||||
"seed": seed,
|
||||
"prompt_content_moderation": prompt_content_moderation,
|
||||
"preserve_alpha": preserve_alpha,
|
||||
"visual_input_content_moderation": visual_input_content_moderation,
|
||||
"visual_output_content_moderation": visual_output_content_moderation
|
||||
}
|
||||
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
"api_token": f"{api_key}"
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.post(self.api_url, json=payload, headers=headers)
|
||||
|
||||
if response.status_code == 200 or response.status_code == 202:
|
||||
print('Initial image expansion request successful, 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}")
|
||||
|
||||
# Poll status URL until completion
|
||||
final_response = poll_status_until_completed(status_url, api_key)
|
||||
|
||||
# Get the result image URL
|
||||
result_image_url = final_response['result']['image_url']
|
||||
|
||||
# Download and process the result image
|
||||
image_response = requests.get(result_image_url)
|
||||
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
|
||||
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}: {response.text}")
|
||||
|
||||
except Exception as e:
|
||||
raise Exception(f"{e}")
|
||||
@@ -20,6 +20,7 @@ class ReimagineNode():
|
||||
"tailored_model_id": ("STRING", ),
|
||||
"tailored_model_influence": ("FLOAT", {"default": 0.5}),
|
||||
"tailored_generation_prefix": ("STRING",), # if used with tailored, possibly get this from the tailored model info node
|
||||
"content_moderation": ("INT", {"default": 0}),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,8 +36,8 @@ class ReimagineNode():
|
||||
self, api_key, prompt, seed,
|
||||
steps_num, fast, structure_ref_influence, structure_image=None,
|
||||
tailored_model_id=None, tailored_model_influence=None, tailored_generation_prefix=None,
|
||||
):
|
||||
fast = bool(fast)
|
||||
content_moderation=0,
|
||||
):
|
||||
payload = {
|
||||
"prompt": tailored_generation_prefix + prompt,
|
||||
"num_results": 1,
|
||||
@@ -44,6 +45,7 @@ class ReimagineNode():
|
||||
"seed": seed,
|
||||
"steps_num": steps_num,
|
||||
"include_generation_prefix": False,
|
||||
"content_moderation": content_moderation,
|
||||
}
|
||||
if structure_image is not None:
|
||||
structure_image = preprocess_image(structure_image)
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
import numpy as np
|
||||
import requests
|
||||
from PIL import Image
|
||||
import io
|
||||
import torch
|
||||
|
||||
from .common import preprocess_image, image_to_base64, poll_status_until_completed
|
||||
|
||||
|
||||
class RemoveForegroundNode():
|
||||
@classmethod
|
||||
def INPUT_TYPES(self):
|
||||
return {
|
||||
"required": {
|
||||
"image": ("IMAGE",), # Input image from another node
|
||||
"api_key": ("STRING", {"default": "BRIA_API_TOKEN"}), # API Key input with a default value
|
||||
},
|
||||
"optional": {
|
||||
"visual_input_content_moderation": ("BOOLEAN", {"default": False}),
|
||||
"visual_output_content_moderation": ("BOOLEAN", {"default": False}),
|
||||
"preserve_alpha": ("BOOLEAN", {"default": True}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
RETURN_NAMES = ("output_image",)
|
||||
CATEGORY = "API Nodes"
|
||||
FUNCTION = "execute" # This is the method that will be executed
|
||||
|
||||
def __init__(self):
|
||||
self.api_url = "https://engine.prod.bria-api.com/v2/image/edit/erase_foreground" # remove foreground API URL
|
||||
|
||||
# Define the execute method as expected by ComfyUI
|
||||
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.")
|
||||
|
||||
# Check if image is tensor, if so, convert to NumPy array
|
||||
if isinstance(image, torch.Tensor):
|
||||
image = preprocess_image(image)
|
||||
|
||||
# Prepare the API request payload
|
||||
# temporary save the image to /tmp
|
||||
# temp_img_path = "/tmp/temp_img.jpeg"
|
||||
# image.save(temp_img_path, format="JPEG")
|
||||
|
||||
# files=[('file',('temp_img.jpeg', open(temp_img_path, 'rb'),'image/jpeg'))
|
||||
# ]
|
||||
payload = {
|
||||
"image": image_to_base64(image),
|
||||
"visual_input_content_moderation": visual_input_content_moderation,
|
||||
"visual_output_content_moderation":visual_output_content_moderation,
|
||||
"preserve_alpha": preserve_alpha
|
||||
}
|
||||
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
"api_token": f"{api_key}"
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.post(self.api_url, json=payload, headers=headers)
|
||||
|
||||
if response.status_code == 200 or response.status_code == 202:
|
||||
print('Initial request successful, 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}")
|
||||
|
||||
# Poll status URL until completion
|
||||
final_response = poll_status_until_completed(status_url, api_key)
|
||||
|
||||
# Get the result image URL
|
||||
result_image_url = final_response['result']['image_url']
|
||||
|
||||
image_response = requests.get(result_image_url)
|
||||
result_image = Image.open(io.BytesIO(image_response.content))
|
||||
result_image = np.array(result_image).astype(np.float32) / 255.0
|
||||
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} {response.text}")
|
||||
|
||||
except Exception as e:
|
||||
raise Exception(f"{e}")
|
||||
@@ -0,0 +1,123 @@
|
||||
import numpy as np
|
||||
import requests
|
||||
from PIL import Image
|
||||
import io
|
||||
import torch
|
||||
|
||||
from .common import image_to_base64, preprocess_image, preprocess_mask, poll_status_until_completed
|
||||
|
||||
|
||||
class ReplaceBgNode():
|
||||
@classmethod
|
||||
def INPUT_TYPES(self):
|
||||
return {
|
||||
"required": {
|
||||
"image": ("IMAGE",), # Input image from another node
|
||||
"api_key": ("STRING", {"default": "BRIA_API_TOKEN"}), # API Key input with a default value
|
||||
},
|
||||
"optional": {
|
||||
"mode": (["base", "fast", "high_control"], {"default": "base"}),
|
||||
"prompt": ("STRING",),
|
||||
"ref_images": ("IMAGE",),
|
||||
"refine_prompt": ("BOOLEAN", {"default": True}),
|
||||
"enhance_ref_images": ("BOOLEAN", {"default": True}),
|
||||
"original_quality": ("BOOLEAN", {"default": False}),
|
||||
"negative_prompt": ("STRING", {"default": None}),
|
||||
"seed": ("INT", {"default": 681794}),
|
||||
"visual_output_content_moderation": ("BOOLEAN", {"default": False}),
|
||||
"prompt_content_moderation": ("BOOLEAN", {"default": False}),
|
||||
"force_background_detection": ("BOOLEAN", {"default": False}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
RETURN_NAMES = ("output_image",)
|
||||
CATEGORY = "API Nodes"
|
||||
FUNCTION = "execute" # This is the method that will be executed
|
||||
|
||||
def __init__(self):
|
||||
self.api_url = "https://engine.prod.bria-api.com/v2/image/edit/replace_background" # Replace BG API URL
|
||||
|
||||
# Define the execute method as expected by ComfyUI
|
||||
def execute(self, image, mode,
|
||||
refine_prompt,
|
||||
original_quality,
|
||||
negative_prompt,
|
||||
seed,
|
||||
api_key,
|
||||
visual_output_content_moderation,
|
||||
prompt_content_moderation,
|
||||
enhance_ref_images,
|
||||
force_background_detection,
|
||||
prompt=None,
|
||||
ref_images=None,):
|
||||
if api_key.strip() == "" or api_key.strip() == "BRIA_API_TOKEN":
|
||||
raise Exception("Please insert a valid API key.")
|
||||
|
||||
# Check if image and mask are tensors, if so, convert to NumPy arrays
|
||||
if isinstance(image, torch.Tensor):
|
||||
image = preprocess_image(image)
|
||||
|
||||
# Convert the image to Base64 string
|
||||
image_base64 = image_to_base64(image)
|
||||
|
||||
if ref_images is not None:
|
||||
ref_images = preprocess_image(ref_images)
|
||||
ref_images = [image_to_base64(ref_images)]
|
||||
else:
|
||||
ref_images=[]
|
||||
|
||||
# Prepare the API request payload for v2 API
|
||||
payload = {
|
||||
"image": image_base64,
|
||||
"mode": mode,
|
||||
"prompt": prompt,
|
||||
"ref_images":ref_images,
|
||||
"refine_prompt": refine_prompt,
|
||||
"original_quality": original_quality,
|
||||
"negative_prompt": negative_prompt,
|
||||
"seed": seed,
|
||||
"prompt_content_moderation": prompt_content_moderation,
|
||||
"visual_output_content_moderation":visual_output_content_moderation,
|
||||
"enhance_ref_images":enhance_ref_images,
|
||||
"force_background_detection": force_background_detection
|
||||
}
|
||||
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
"api_token": f"{api_key}"
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.post(self.api_url, json=payload, headers=headers)
|
||||
|
||||
if response.status_code == 200 or response.status_code == 202:
|
||||
print('Initial replace background request successful, 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}")
|
||||
|
||||
# Poll status URL until completion
|
||||
final_response = poll_status_until_completed(status_url, api_key)
|
||||
|
||||
# Get the result image URL
|
||||
result_image_url = final_response['result']['image_url']
|
||||
|
||||
# Download and process the result image
|
||||
image_response = requests.get(result_image_url)
|
||||
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
|
||||
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}{response.text}")
|
||||
|
||||
except Exception as e:
|
||||
raise Exception(f"{e}")
|
||||
@@ -0,0 +1,87 @@
|
||||
import numpy as np
|
||||
import requests
|
||||
from PIL import Image
|
||||
import io
|
||||
import torch
|
||||
|
||||
from .common import preprocess_image, image_to_base64, poll_status_until_completed
|
||||
|
||||
class RmbgNode():
|
||||
@classmethod
|
||||
def INPUT_TYPES(self):
|
||||
return {
|
||||
"required": {
|
||||
"image": ("IMAGE",), # Input image from another node
|
||||
"api_key": ("STRING", {"default": "BRIA_API_TOKEN"}), # API Key input with a default value
|
||||
},
|
||||
"optional": {
|
||||
"visual_input_content_moderation": ("BOOLEAN", {"default": False}),
|
||||
"visual_output_content_moderation": ("BOOLEAN", {"default": False}),
|
||||
"preserve_alpha": ("BOOLEAN", {"default": True}),
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
RETURN_NAMES = ("output_image",)
|
||||
CATEGORY = "API Nodes"
|
||||
FUNCTION = "execute" # This is the method that will be executed
|
||||
|
||||
def __init__(self):
|
||||
self.api_url = "https://engine.prod.bria-api.com/v2/image/edit/remove_background" # RMBG API URL
|
||||
|
||||
# Define the execute method as expected by ComfyUI
|
||||
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.")
|
||||
|
||||
# Check if image is tensor, if so, convert to NumPy array
|
||||
if isinstance(image, torch.Tensor):
|
||||
image = preprocess_image(image)
|
||||
|
||||
# Convert image to base64 for the new API format
|
||||
image_base64 = image_to_base64(image)
|
||||
payload = {
|
||||
"image": image_base64,
|
||||
"visual_input_content_moderation": visual_input_content_moderation,
|
||||
"visual_output_content_moderation":visual_output_content_moderation,
|
||||
"preserve_alpha":preserve_alpha
|
||||
}
|
||||
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
"api_token": f"{api_key}"
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.post(self.api_url, json=payload, headers=headers)
|
||||
|
||||
if response.status_code == 200 or response.status_code == 202:
|
||||
print('Initial RMBG request successful, 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_key)
|
||||
|
||||
# Get the result image URL
|
||||
result_image_url = final_response['result']['image_url']
|
||||
|
||||
# Download and process the result image
|
||||
image_response = requests.get(result_image_url)
|
||||
result_image = Image.open(io.BytesIO(image_response.content))
|
||||
result_image = np.array(result_image).astype(np.float32) / 255.0
|
||||
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} {response.text}")
|
||||
|
||||
except Exception as e:
|
||||
raise Exception(f"{e}")
|
||||
@@ -12,7 +12,10 @@ class ShotByImageNode():
|
||||
"ref_image": ("IMAGE",), # ref image from another node
|
||||
"enhance_ref_image": ("INT", {"default": 1}),
|
||||
"api_key": ("STRING", {"default": "BRIA_API_TOKEN"}) # API Key input with a default value
|
||||
}
|
||||
},
|
||||
"optional": {
|
||||
"content_moderation": ("BOOLEAN", {"default": False}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
@@ -24,7 +27,7 @@ class ShotByImageNode():
|
||||
self.api_url = "https://engine.prod.bria-api.com/v1/product/lifestyle_shot_by_image" # Eraser API URL
|
||||
|
||||
# Define the execute method as expected by ComfyUI
|
||||
def execute(self, image, ref_image, api_key, enhance_ref_image, ):
|
||||
def execute(self, image, ref_image, api_key, enhance_ref_image, content_moderation):
|
||||
if api_key.strip() == "" or api_key.strip() == "BRIA_API_TOKEN":
|
||||
raise Exception("Please insert a valid API key.")
|
||||
|
||||
@@ -45,7 +48,8 @@ class ShotByImageNode():
|
||||
"enhance_ref_image": enhance_ref_image,
|
||||
"placement_type": "original",
|
||||
"original_quality": True,
|
||||
"sync": True
|
||||
"sync": True,
|
||||
"content_moderation": content_moderation
|
||||
}
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
|
||||
@@ -10,9 +10,12 @@ class ShotByTextNode():
|
||||
"required": {
|
||||
"image": ("IMAGE",), # Input image from another node
|
||||
"scene_description": ("STRING",),
|
||||
"optimize_description": ("INT", {"default": 1}),
|
||||
"mode": (["base", "fast", "high_control"], {"default": "high_control"}),
|
||||
"api_key": ("STRING", {"default": "BRIA_API_TOKEN"}) # API Key input with a default value
|
||||
}
|
||||
},
|
||||
"optional": {
|
||||
"content_moderation": ("BOOLEAN", {"default": False}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
@@ -24,7 +27,7 @@ class ShotByTextNode():
|
||||
self.api_url = "https://engine.prod.bria-api.com/v1/product/lifestyle_shot_by_text" # Eraser API URL
|
||||
|
||||
# Define the execute method as expected by ComfyUI
|
||||
def execute(self, image, api_key, scene_description, optimize_description, ):
|
||||
def execute(self, image, api_key, scene_description, mode, content_moderation):
|
||||
if api_key.strip() == "" or api_key.strip() == "BRIA_API_TOKEN":
|
||||
raise Exception("Please insert a valid API key.")
|
||||
|
||||
@@ -32,15 +35,16 @@ class ShotByTextNode():
|
||||
if isinstance(image, torch.Tensor):
|
||||
image = preprocess_image(image)
|
||||
|
||||
optimize_description = bool(optimize_description)
|
||||
image_base64 = image_to_base64(image)
|
||||
payload = {
|
||||
"file": image_base64,
|
||||
"scene_description": scene_description,
|
||||
"optimize_description": optimize_description,
|
||||
"mode": mode,
|
||||
"placement_type": "original",
|
||||
"original_quality": True,
|
||||
"sync": True
|
||||
"sync": True,
|
||||
"content_moderation": content_moderation
|
||||
|
||||
}
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
|
||||
@@ -26,6 +26,7 @@ class TailoredGenNode():
|
||||
"guidance_method_2": (["controlnet_canny", "controlnet_depth", "controlnet_recoloring", "controlnet_color_grid"], {"default": "controlnet_canny"}),
|
||||
"guidance_method_2_scale": ("FLOAT", {"default": 1.0}),
|
||||
"guidance_method_2_image": ("IMAGE", ),
|
||||
"content_moderation": ("INT", {"default": 0}),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,8 +43,8 @@ class TailoredGenNode():
|
||||
seed, model_influence, negative_prompt, fast, steps_num,
|
||||
guidance_method_1=None, guidance_method_1_scale=None, guidance_method_1_image=None,
|
||||
guidance_method_2=None, guidance_method_2_scale=None, guidance_method_2_image=None,
|
||||
content_moderation=0,
|
||||
):
|
||||
fast = bool(fast)
|
||||
payload = {
|
||||
"prompt": generation_prefix + prompt,
|
||||
"num_results": 1,
|
||||
@@ -55,6 +56,7 @@ class TailoredGenNode():
|
||||
"fast": fast,
|
||||
"steps_num": steps_num,
|
||||
"include_generation_prefix": False,
|
||||
"content_moderation": content_moderation,
|
||||
}
|
||||
if guidance_method_1_image is not None:
|
||||
guidance_method_1_image = preprocess_image(guidance_method_1_image)
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
import numpy as np
|
||||
import requests
|
||||
from PIL import Image
|
||||
import io
|
||||
import torch
|
||||
|
||||
from .common import image_to_base64, preprocess_image
|
||||
|
||||
class TailoredPortraitNode():
|
||||
@classmethod
|
||||
def INPUT_TYPES(self):
|
||||
return {
|
||||
"required": {
|
||||
"image": ("IMAGE",), # Input image from another node
|
||||
"tailored_model_id": ("INT",),
|
||||
"api_key": ("STRING", {"default": "BRIA_API_TOKEN"}), # API Key input with a default value
|
||||
},
|
||||
"optional": {
|
||||
"seed": ("INT", {"default": 123456}),
|
||||
"tailored_model_influence": ("FLOAT", {"default": 0.9}),
|
||||
"id_strength": ("FLOAT", {"default": 0.7}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
RETURN_NAMES = ("output_image",)
|
||||
CATEGORY = "API Nodes"
|
||||
FUNCTION = "execute" # This is the method that will be executed
|
||||
|
||||
def __init__(self):
|
||||
self.api_url = "https://engine.prod.bria-api.com/v1/tailored-gen/restyle_portrait" # Eraser API URL
|
||||
|
||||
# Define the execute method as expected by ComfyUI
|
||||
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.")
|
||||
|
||||
# Convert the image and mask directly to if isinstance(image, torch.Tensor):
|
||||
if isinstance(image, torch.Tensor):
|
||||
image = preprocess_image(image)
|
||||
|
||||
image_base64 = image_to_base64(image)
|
||||
|
||||
# Prepare the API request payload
|
||||
payload = {
|
||||
"id_image_file": f"{image_base64}",
|
||||
"tailored_model_id": tailored_model_id,
|
||||
"tailored_model_influence": tailored_model_influence,
|
||||
"id_strength": id_strength,
|
||||
"seed": seed
|
||||
}
|
||||
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
"api_token": f"{api_key}"
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.post(self.api_url, json=payload, headers=headers)
|
||||
# Check for successful response
|
||||
if response.status_code == 200:
|
||||
print('response is 200')
|
||||
# Process the output image from API response
|
||||
response_dict = response.json()
|
||||
image_response = requests.get(response_dict['image_res'])
|
||||
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
|
||||
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}")
|
||||
|
||||
except Exception as e:
|
||||
raise Exception(f"{e}")
|
||||
@@ -28,6 +28,7 @@ class Text2ImageBaseNode():
|
||||
"image_prompt_mode": (["regular", "style_only"], {"default": "regular"}),
|
||||
"image_prompt_image": ("IMAGE", ),
|
||||
"image_prompt_scale": ("FLOAT", {"default": 1.0}),
|
||||
"content_moderation": ("INT", {"default": 0}),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +38,7 @@ class Text2ImageBaseNode():
|
||||
FUNCTION = "execute" # This is the method that will be executed
|
||||
|
||||
def __init__(self):
|
||||
self.api_url = "https://engine.prod.bria-api.com/v1/text-to-image/base/2.3" #"http://0.0.0.0:5000/v1/text-to-image/base/2.3"
|
||||
self.api_url = "https://engine.prod.bria-api.com/v1/text-to-image/base/3.2"
|
||||
|
||||
def execute(
|
||||
self, api_key, prompt, aspect_ratio, seed, negative_prompt,
|
||||
@@ -45,8 +46,8 @@ class Text2ImageBaseNode():
|
||||
guidance_method_1=None, guidance_method_1_scale=None, guidance_method_1_image=None,
|
||||
guidance_method_2=None, guidance_method_2_scale=None, guidance_method_2_image=None,
|
||||
image_prompt_mode=None, image_prompt_image=None, image_prompt_scale=None,
|
||||
content_moderation=0,
|
||||
):
|
||||
prompt_enhancement = bool(prompt_enhancement)
|
||||
payload = {
|
||||
"prompt": prompt,
|
||||
"num_results": 1,
|
||||
@@ -57,6 +58,7 @@ class Text2ImageBaseNode():
|
||||
"steps_num": steps_num,
|
||||
"text_guidance_scale": text_guidance_scale,
|
||||
"prompt_enhancement": prompt_enhancement,
|
||||
"content_moderation": content_moderation,
|
||||
}
|
||||
if medium != "none":
|
||||
payload["medium"] = medium
|
||||
|
||||
@@ -25,6 +25,7 @@ class Text2ImageFastNode():
|
||||
"image_prompt_mode": (["regular", "style_only"], {"default": "regular"}),
|
||||
"image_prompt_image": ("IMAGE", ),
|
||||
"image_prompt_scale": ("FLOAT", {"default": 1.0}),
|
||||
"content_moderation": ("INT", {"default": 0}),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,8 +43,8 @@ class Text2ImageFastNode():
|
||||
guidance_method_1=None, guidance_method_1_scale=None, guidance_method_1_image=None,
|
||||
guidance_method_2=None, guidance_method_2_scale=None, guidance_method_2_image=None,
|
||||
image_prompt_mode=None, image_prompt_image=None, image_prompt_scale=None,
|
||||
content_moderation=0,
|
||||
):
|
||||
prompt_enhancement = bool(prompt_enhancement)
|
||||
payload = {
|
||||
"prompt": prompt,
|
||||
"num_results": 1,
|
||||
@@ -52,6 +53,7 @@ class Text2ImageFastNode():
|
||||
"seed": seed,
|
||||
"steps_num": steps_num,
|
||||
"prompt_enhancement": prompt_enhancement,
|
||||
"content_moderation": content_moderation,
|
||||
}
|
||||
if guidance_method_1_image is not None:
|
||||
guidance_method_1_image = preprocess_image(guidance_method_1_image)
|
||||
|
||||
@@ -19,6 +19,7 @@ class Text2ImageHDNode():
|
||||
"prompt_enhancement": ("INT", {"default": 0}),
|
||||
"text_guidance_scale": ("INT", {"default": 5}),
|
||||
"medium": (["photography", "art", "none"], {"default": "none"}),
|
||||
"content_moderation": ("INT", {"default": 0}),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,9 +33,8 @@ class Text2ImageHDNode():
|
||||
|
||||
def execute(
|
||||
self, api_key, prompt, aspect_ratio, seed, negative_prompt,
|
||||
steps_num, prompt_enhancement, text_guidance_scale, medium,
|
||||
steps_num, prompt_enhancement, text_guidance_scale, medium, content_moderation=0,
|
||||
):
|
||||
prompt_enhancement = bool(prompt_enhancement)
|
||||
payload = {
|
||||
"prompt": prompt,
|
||||
"num_results": 1,
|
||||
@@ -45,6 +45,7 @@ class Text2ImageHDNode():
|
||||
"steps_num": steps_num,
|
||||
"text_guidance_scale": text_guidance_scale,
|
||||
"prompt_enhancement": prompt_enhancement,
|
||||
"content_moderation": content_moderation,
|
||||
}
|
||||
if medium != "none":
|
||||
payload["medium"] = medium
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
[project]
|
||||
name = "comfyui-bria-api"
|
||||
description = "Custom nodes for ComfyUI using BRIA's API."
|
||||
version = "2.0.0"
|
||||
version = "2.1.0"
|
||||
license = {file = "LICENSE"}
|
||||
|
||||
[project.urls]
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
{"last_node_id":39,"last_link_id":65,"nodes":[{"id":34,"type":"LoadImage","pos":[19.94045066833496,1075.806640625],"size":[315,314],"flags":{},"order":0,"mode":0,"inputs":[],"outputs":[{"name":"IMAGE","type":"IMAGE","links":[61],"slot_index":0,"localized_name":"IMAGE"},{"name":"MASK","type":"MASK","links":null,"localized_name":"MASK"}],"properties":{"Node name for S&R":"LoadImage"},"widgets_values":["quirky-red-brick-brick-wallpaper.jpg","image"]},{"id":36,"type":"PreviewImage","pos":[468.7108154296875,1210.288818359375],"size":[210,246],"flags":{},"order":5,"mode":0,"inputs":[{"name":"images","type":"IMAGE","link":63,"localized_name":"images"}],"outputs":[],"properties":{"Node name for S&R":"PreviewImage"},"widgets_values":[]},{"id":33,"type":"PreviewImage","pos":[1317.4083251953125,1118.4864501953125],"size":[210,246],"flags":{},"order":8,"mode":0,"inputs":[{"name":"images","type":"IMAGE","link":59,"localized_name":"images"}],"outputs":[],"properties":{"Node name for S&R":"PreviewImage"},"widgets_values":[]},{"id":31,"type":"PreviewImage","pos":[1668.734619140625,796.7755737304688],"size":[210,246],"flags":{},"order":10,"mode":0,"inputs":[{"name":"images","type":"IMAGE","link":57,"localized_name":"images"}],"outputs":[],"properties":{"Node name for S&R":"PreviewImage"},"widgets_values":[]},{"id":29,"type":"PreviewImage","pos":[872.8858032226562,679.9429321289062],"size":[210,246],"flags":{},"order":6,"mode":0,"inputs":[{"name":"images","type":"IMAGE","link":55,"localized_name":"images"}],"outputs":[],"properties":{"Node name for S&R":"PreviewImage"},"widgets_values":[]},{"id":28,"type":"LoadImage","pos":[29.629886627197266,676.8370361328125],"size":[315,314],"flags":{},"order":1,"mode":0,"inputs":[],"outputs":[{"name":"IMAGE","type":"IMAGE","links":[54],"slot_index":0,"localized_name":"IMAGE"},{"name":"MASK","type":"MASK","links":null,"localized_name":"MASK"}],"properties":{"Node name for S&R":"LoadImage"},"widgets_values":["pexels-photo-1808399.jpeg","image"]},{"id":35,"type":"RemoveForegroundNode","pos":[414.2638854980469,1079.1705322265625],"size":[315,58],"flags":{},"order":3,"mode":0,"inputs":[{"name":"image","type":"IMAGE","link":61,"localized_name":"image"}],"outputs":[{"name":"output_image","type":"IMAGE","links":[62,63],"slot_index":0,"localized_name":"output_image"}],"properties":{"Node name for S&R":"RemoveForegroundNode"},"widgets_values":["BRIA_API_TOKEN"]},{"id":32,"type":"ReplaceBgNode","pos":[834.6115112304688,1063.0406494140625],"size":[315,294],"flags":{},"order":7,"mode":0,"inputs":[{"name":"image","type":"IMAGE","link":65,"localized_name":"image"},{"name":"ref_image","type":"IMAGE","link":62,"shape":7,"localized_name":"ref_image"}],"outputs":[{"name":"output_image","type":"IMAGE","links":[59,64],"slot_index":0,"localized_name":"output_image"}],"properties":{"Node name for S&R":"ReplaceBgNode"},"widgets_values":["BRIA_API_TOKEN",false,"",true,true,true,false,"",1978,"randomize"]},{"id":30,"type":"ImageExpansionNode","pos":[1265.001220703125,798.8323974609375],"size":[315,226],"flags":{},"order":9,"mode":0,"inputs":[{"name":"image","type":"IMAGE","link":64,"localized_name":"image"}],"outputs":[{"name":"output_image","type":"IMAGE","links":[57],"slot_index":0,"localized_name":"output_image"}],"properties":{"Node name for S&R":"ImageExpansionNode"},"widgets_values":["600,760","200, 0","BRIA_API_TOKEN","1200, 800","",1729,"randomize","Ugly, mutated"]},{"id":38,"type":"Note","pos":[436.7110900878906,566.2047119140625],"size":[306.28387451171875,58],"flags":{},"order":2,"mode":0,"inputs":[],"outputs":[],"properties":{},"widgets_values":["You can get your BRIA API token at:\nhttps://bria.ai/api/"],"color":"#432","bgcolor":"#653"},{"id":27,"type":"RmbgNode","pos":[430.8815002441406,678.7727661132812],"size":[315,58],"flags":{},"order":4,"mode":0,"inputs":[{"name":"image","type":"IMAGE","link":54,"localized_name":"image"}],"outputs":[{"name":"output_image","type":"IMAGE","links":[55,65],"slot_index":0,"localized_name":"output_image"}],"properties":{"Node name for S&R":"RmbgNode"},"widgets_values":["BRIA_API_TOKEN"]}],"links":[[51,5,0,15,2,"STRING"],[54,28,0,27,0,"IMAGE"],[55,27,0,29,0,"IMAGE"],[57,30,0,31,0,"IMAGE"],[59,32,0,33,0,"IMAGE"],[61,34,0,35,0,"IMAGE"],[62,35,0,32,1,"IMAGE"],[63,35,0,36,0,"IMAGE"],[64,32,0,30,0,"IMAGE"],[65,27,0,32,0,"IMAGE"]],"groups":[],"config":{},"extra":{"ds":{"scale":0.8140274938684037,"offset":[101.53311990208498,-477.0342684311694]},"node_versions":{"comfyui-bria-api":"c72754d15b53a13ee0c0419d70401232c56b7fdb","comfy-core":"v0.3.8-1-gc441048","ComfyUI-Jjk-Nodes":"b3c99bb78a99551776b5eab1a820e1cd58f84f31"}},"version":0.4}
|
||||
@@ -0,0 +1 @@
|
||||
{"last_node_id":41,"last_link_id":62,"nodes":[{"id":14,"type":"Note","pos":[478,444],"size":[396.80859375,61.8046875],"flags":{},"order":0,"mode":0,"inputs":[],"outputs":[],"properties":{},"widgets_values":["Right click, and choose \"Open in Mask Editor\" to draw a mask of areas you want to erase."],"color":"#432","bgcolor":"#653"},{"id":15,"type":"Note","pos":[1080.3062744140625,445.9654541015625],"size":[306.28387451171875,58],"flags":{},"order":1,"mode":0,"inputs":[],"outputs":[],"properties":{},"widgets_values":["You can get your BRIA API token at:\nhttps://bria.ai/api/"],"color":"#432","bgcolor":"#653"},{"id":30,"type":"LoadImage","pos":[479,572],"size":[395.7845153808594,352.8512268066406],"flags":{},"order":2,"mode":0,"inputs":[],"outputs":[{"name":"IMAGE","type":"IMAGE","links":[56],"slot_index":0,"shape":3,"localized_name":"IMAGE"},{"name":"MASK","type":"MASK","links":[57],"slot_index":1,"shape":3,"localized_name":"MASK"}],"properties":{"Node name for S&R":"LoadImage"},"widgets_values":["clipspace/clipspace-mask-4068974.800000012.png [input]","image"]},{"id":37,"type":"PreviewImage","pos":[1504.4755859375,568.9967651367188],"size":[438.50262451171875,376.8338317871094],"flags":{},"order":6,"mode":0,"inputs":[{"name":"images","type":"IMAGE","link":58,"localized_name":"images"}],"outputs":[],"properties":{"Node name for S&R":"PreviewImage"},"widgets_values":[]},{"id":33,"type":"PreviewImage","pos":[1502.785888671875,1078.3564453125],"size":[433.29193115234375,357.1255187988281],"flags":{},"order":7,"mode":0,"inputs":[{"name":"images","type":"IMAGE","link":54,"localized_name":"images"}],"outputs":[],"properties":{"Node name for S&R":"PreviewImage"},"widgets_values":[]},{"id":40,"type":"LoadImage","pos":[541.1226806640625,1079.39697265625],"size":[315,314],"flags":{},"order":3,"mode":0,"inputs":[],"outputs":[{"name":"IMAGE","type":"IMAGE","links":[61],"slot_index":0,"localized_name":"IMAGE"},{"name":"MASK","type":"MASK","links":[62],"slot_index":1,"localized_name":"MASK"}],"properties":{"Node name for S&R":"LoadImage"},"widgets_values":["clipspace/clipspace-mask-4411367.100000024.png [input]","image"]},{"id":34,"type":"BriaGenFill","pos":[1032.416748046875,1073.984619140625],"size":[315,102],"flags":{},"order":5,"mode":0,"inputs":[{"name":"image","type":"IMAGE","link":61,"localized_name":"image"},{"name":"mask","type":"MASK","link":62,"localized_name":"mask"}],"outputs":[{"name":"output_image","type":"IMAGE","links":[54],"slot_index":0,"shape":3,"localized_name":"output_image"}],"properties":{"Node name for S&R":"BriaGenFill"},"widgets_values":["a blue coffee mug","BRIA_API_TOKEN"]},{"id":36,"type":"BriaEraser","pos":[1068.6063232421875,574.6080322265625],"size":[315,78],"flags":{},"order":4,"mode":0,"inputs":[{"name":"image","type":"IMAGE","link":56,"localized_name":"image"},{"name":"mask","type":"MASK","link":57,"localized_name":"mask"}],"outputs":[{"name":"output_image","type":"IMAGE","links":[58],"slot_index":0,"localized_name":"output_image"}],"properties":{"Node name for S&R":"BriaEraser"},"widgets_values":["BRIA_API_TOKEN"]}],"links":[[54,34,0,33,0,"IMAGE"],[56,30,0,36,0,"IMAGE"],[57,30,1,36,1,"MASK"],[58,36,0,37,0,"IMAGE"],[61,40,0,34,0,"IMAGE"],[62,40,1,34,1,"MASK"]],"groups":[],"config":{},"extra":{"ds":{"scale":0.6727499949325677,"offset":[131.53042816003972,-419.53430403204317]}},"version":0.4}
|
||||
@@ -1,203 +0,0 @@
|
||||
{
|
||||
"last_node_id": 28,
|
||||
"last_link_id": 42,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 15,
|
||||
"type": "Note",
|
||||
"pos": {
|
||||
"0": 1021,
|
||||
"1": 280
|
||||
},
|
||||
"size": {
|
||||
"0": 311.8914794921875,
|
||||
"1": 153.69827270507812
|
||||
},
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [],
|
||||
"properties": {},
|
||||
"widgets_values": [
|
||||
"The default BRIA API key for ComfyUI (BRIA_ComfyUI_Key) offers 10,000 API calls for the entire community. \n\nGet your own token at:\nhttps://bria.ai/api/"
|
||||
],
|
||||
"color": "#432",
|
||||
"bgcolor": "#653"
|
||||
},
|
||||
{
|
||||
"id": 13,
|
||||
"type": "PreviewImage",
|
||||
"pos": {
|
||||
"0": 1410,
|
||||
"1": 160
|
||||
},
|
||||
"size": {
|
||||
"0": 474.7605895996094,
|
||||
"1": 303.117919921875
|
||||
},
|
||||
"flags": {},
|
||||
"order": 4,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 42
|
||||
}
|
||||
],
|
||||
"outputs": [],
|
||||
"properties": {
|
||||
"Node name for S&R": "PreviewImage"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 21,
|
||||
"type": "LoadImage",
|
||||
"pos": {
|
||||
"0": 477,
|
||||
"1": 156
|
||||
},
|
||||
"size": {
|
||||
"0": 408.4602355957031,
|
||||
"1": 333.19830322265625
|
||||
},
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
40
|
||||
],
|
||||
"slot_index": 0,
|
||||
"shape": 3
|
||||
},
|
||||
{
|
||||
"name": "MASK",
|
||||
"type": "MASK",
|
||||
"links": [
|
||||
41
|
||||
],
|
||||
"slot_index": 1,
|
||||
"shape": 3
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "LoadImage"
|
||||
},
|
||||
"widgets_values": [
|
||||
"clipspace/clipspace-mask-82245.69999998808.png [input]",
|
||||
"image"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 28,
|
||||
"type": "BriaEraser",
|
||||
"pos": {
|
||||
"0": 1022,
|
||||
"1": 159
|
||||
},
|
||||
"size": {
|
||||
"0": 315,
|
||||
"1": 78
|
||||
},
|
||||
"flags": {},
|
||||
"order": 3,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "image",
|
||||
"type": "IMAGE",
|
||||
"link": 40
|
||||
},
|
||||
{
|
||||
"name": "mask",
|
||||
"type": "MASK",
|
||||
"link": 41
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "output_image",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
42
|
||||
],
|
||||
"slot_index": 0,
|
||||
"shape": 3
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "BriaEraser"
|
||||
},
|
||||
"widgets_values": [
|
||||
"BRIA_ComfyUI_Key"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 14,
|
||||
"type": "Note",
|
||||
"pos": {
|
||||
"0": 483,
|
||||
"1": 39
|
||||
},
|
||||
"size": [
|
||||
396.80859375,
|
||||
61.8046875
|
||||
],
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [],
|
||||
"properties": {},
|
||||
"widgets_values": [
|
||||
"Right click, and choose \"Open in Mask Editor\" to draw a mask of areas you want animated more. "
|
||||
],
|
||||
"color": "#432",
|
||||
"bgcolor": "#653"
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[
|
||||
40,
|
||||
21,
|
||||
0,
|
||||
28,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
41,
|
||||
21,
|
||||
1,
|
||||
28,
|
||||
1,
|
||||
"MASK"
|
||||
],
|
||||
[
|
||||
42,
|
||||
28,
|
||||
0,
|
||||
13,
|
||||
0,
|
||||
"IMAGE"
|
||||
]
|
||||
],
|
||||
"groups": [],
|
||||
"config": {},
|
||||
"extra": {
|
||||
"ds": {
|
||||
"scale": 1,
|
||||
"offset": [
|
||||
-293.75,
|
||||
167.65625
|
||||
]
|
||||
}
|
||||
},
|
||||
"version": 0.4
|
||||
}
|
||||
@@ -1,204 +0,0 @@
|
||||
{
|
||||
"last_node_id": 35,
|
||||
"last_link_id": 55,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 33,
|
||||
"type": "PreviewImage",
|
||||
"pos": {
|
||||
"0": 1420,
|
||||
"1": 574
|
||||
},
|
||||
"size": {
|
||||
"0": 433.29193115234375,
|
||||
"1": 357.1255187988281
|
||||
},
|
||||
"flags": {},
|
||||
"order": 4,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 54
|
||||
}
|
||||
],
|
||||
"outputs": [],
|
||||
"properties": {
|
||||
"Node name for S&R": "PreviewImage"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 30,
|
||||
"type": "LoadImage",
|
||||
"pos": {
|
||||
"0": 479,
|
||||
"1": 572
|
||||
},
|
||||
"size": {
|
||||
"0": 395.7845153808594,
|
||||
"1": 352.8512268066406
|
||||
},
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
53
|
||||
],
|
||||
"slot_index": 0,
|
||||
"shape": 3
|
||||
},
|
||||
{
|
||||
"name": "MASK",
|
||||
"type": "MASK",
|
||||
"links": [
|
||||
55
|
||||
],
|
||||
"slot_index": 1,
|
||||
"shape": 3
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "LoadImage"
|
||||
},
|
||||
"widgets_values": [
|
||||
"clipspace/clipspace-mask-1438488.400000006.png [input]",
|
||||
"image"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 14,
|
||||
"type": "Note",
|
||||
"pos": {
|
||||
"0": 478,
|
||||
"1": 444
|
||||
},
|
||||
"size": {
|
||||
"0": 396.80859375,
|
||||
"1": 61.8046875
|
||||
},
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [],
|
||||
"properties": {},
|
||||
"widgets_values": [
|
||||
"Right click, and choose \"Open in Mask Editor\" to draw a mask of areas you want to erase."
|
||||
],
|
||||
"color": "#432",
|
||||
"bgcolor": "#653"
|
||||
},
|
||||
{
|
||||
"id": 15,
|
||||
"type": "Note",
|
||||
"pos": {
|
||||
"0": 983,
|
||||
"1": 440
|
||||
},
|
||||
"size": {
|
||||
"0": 306.28387451171875,
|
||||
"1": 58
|
||||
},
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [],
|
||||
"properties": {},
|
||||
"widgets_values": [
|
||||
"You can get your BRIA API token at:\nhttps://bria.ai/api/"
|
||||
],
|
||||
"color": "#432",
|
||||
"bgcolor": "#653"
|
||||
},
|
||||
{
|
||||
"id": 34,
|
||||
"type": "BriaGenFill",
|
||||
"pos": {
|
||||
"0": 992,
|
||||
"1": 572
|
||||
},
|
||||
"size": {
|
||||
"0": 315,
|
||||
"1": 102
|
||||
},
|
||||
"flags": {},
|
||||
"order": 3,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "image",
|
||||
"type": "IMAGE",
|
||||
"link": 53
|
||||
},
|
||||
{
|
||||
"name": "mask",
|
||||
"type": "MASK",
|
||||
"link": 55
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "output_image",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
54
|
||||
],
|
||||
"shape": 3,
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "BriaGenFill"
|
||||
},
|
||||
"widgets_values": [
|
||||
"a beautiful paint brush",
|
||||
"BRIA_API_TOKEN"
|
||||
]
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[
|
||||
53,
|
||||
30,
|
||||
0,
|
||||
34,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
54,
|
||||
34,
|
||||
0,
|
||||
33,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
55,
|
||||
30,
|
||||
1,
|
||||
34,
|
||||
1,
|
||||
"MASK"
|
||||
]
|
||||
],
|
||||
"groups": [],
|
||||
"config": {},
|
||||
"extra": {
|
||||
"ds": {
|
||||
"scale": 0.8264462809917364,
|
||||
"offset": [
|
||||
-266.96526103236687,
|
||||
114.47857424738714
|
||||
]
|
||||
}
|
||||
},
|
||||
"version": 0.4
|
||||
}
|
||||
+1
-1
@@ -293,4 +293,4 @@
|
||||
}
|
||||
},
|
||||
"version": 0.4
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
{
|
||||
"last_node_id": 13,
|
||||
"last_link_id": 11,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 12,
|
||||
"type": "LoadImage",
|
||||
"pos": [
|
||||
669.7035522460938,
|
||||
136.97129821777344
|
||||
],
|
||||
"size": [
|
||||
315,
|
||||
314
|
||||
],
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
10
|
||||
],
|
||||
"slot_index": 0
|
||||
},
|
||||
{
|
||||
"name": "MASK",
|
||||
"type": "MASK",
|
||||
"links": null
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "LoadImage"
|
||||
},
|
||||
"widgets_values": [
|
||||
"pexels-photo-3246665.png",
|
||||
"image"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 11,
|
||||
"type": "PreviewImage",
|
||||
"pos": [
|
||||
1587.27001953125,
|
||||
97.39167022705078
|
||||
],
|
||||
"size": [
|
||||
210,
|
||||
246
|
||||
],
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 11
|
||||
}
|
||||
],
|
||||
"outputs": [],
|
||||
"properties": {
|
||||
"Node name for S&R": "PreviewImage"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"type": "Text2ImageFastNode",
|
||||
"pos": [
|
||||
1058.320556640625,
|
||||
96.64427185058594
|
||||
],
|
||||
"size": [
|
||||
438.71258544921875,
|
||||
394.27716064453125
|
||||
],
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "guidance_method_1_image",
|
||||
"type": "IMAGE",
|
||||
"link": null,
|
||||
"shape": 7
|
||||
},
|
||||
{
|
||||
"name": "guidance_method_2_image",
|
||||
"type": "IMAGE",
|
||||
"link": null,
|
||||
"shape": 7
|
||||
},
|
||||
{
|
||||
"name": "image_prompt_image",
|
||||
"type": "IMAGE",
|
||||
"link": 10,
|
||||
"shape": 7
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "output_image",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
11
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Text2ImageFastNode"
|
||||
},
|
||||
"widgets_values": [
|
||||
"BRIA_API_TOKEN",
|
||||
"A drawing of a lion on a table.\t",
|
||||
"4:3",
|
||||
990,
|
||||
"randomize",
|
||||
8,
|
||||
0,
|
||||
"controlnet_canny",
|
||||
1,
|
||||
"controlnet_canny",
|
||||
1,
|
||||
"regular",
|
||||
1
|
||||
]
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[
|
||||
10,
|
||||
12,
|
||||
0,
|
||||
10,
|
||||
2,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
11,
|
||||
10,
|
||||
0,
|
||||
11,
|
||||
0,
|
||||
"IMAGE"
|
||||
]
|
||||
],
|
||||
"groups": [],
|
||||
"config": {},
|
||||
"extra": {
|
||||
"ds": {
|
||||
"scale": 0.7513148009015777,
|
||||
"offset": [
|
||||
11.112206386364164,
|
||||
66.47311795454547
|
||||
]
|
||||
},
|
||||
"node_versions": {
|
||||
"comfy-core": "v0.3.10-42-gff83865",
|
||||
"comfyui-bria-api": "499ec5d104cc5110407eafce468ce1d47ac168b3"
|
||||
},
|
||||
"VHS_latentpreview": false,
|
||||
"VHS_latentpreviewrate": 0
|
||||
},
|
||||
"version": 0.4
|
||||
}
|
||||
Reference in New Issue
Block a user