Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
2516242
add workflow to publish to registry (#121)
eliteprox Sep 30, 2025
059d69c
fix(byoc): Use correct capability url for registration (#460)
eliteprox Oct 1, 2025
e51e7cb
ui: fix deprecated husky install command (#445)
eliteprox Oct 6, 2025
082d135
Fix text output panel visibility - hide by default, show on first tex…
Copilot Oct 6, 2025
b0f7476
chore(deps): bump actions/checkout from 4 to 5 (#355)
dependabot[bot] Oct 28, 2025
8ccf37f
chore(deps): bump actions/setup-node from 5 to 6 (#483)
dependabot[bot] Oct 28, 2025
129e82c
refactor: load pipeline using pytrickle model loader, add default pas…
eliteprox Oct 28, 2025
59b723c
chore(deps): update pytrickle dependency to latest commit and improve…
eliteprox Oct 28, 2025
2d6f2d1
feat: enhance ComfyStream client prompt management and frame processing
eliteprox Oct 29, 2025
50fdac1
Merge branch 'main' into feat/warmup-overlay-refactor
eliteprox Oct 29, 2025
400c652
byoc(frame_processor): add on_stream_start callback, bump pytrickle
eliteprox Oct 8, 2025
86975ef
feat(frame_processor): add loading screen during warmup
eliteprox Oct 8, 2025
e929b96
feat(frame_processor): play loading overlay during warmup and prompt …
eliteprox Oct 29, 2025
cf22583
remove git submodules added on accidental commit
eliteprox Oct 29, 2025
a7f89e6
remove broken force passthrough logic in favor of overlay
eliteprox Oct 29, 2025
a536863
dockerfile: add entrypoint and cmd for byoc
eliteprox Oct 7, 2025
2cdea10
fix blacklist_custom_nodes parameter name, fix logging setting for co…
eliteprox Oct 8, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/docker.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
runs-on: [self-hosted, linux, gpu]
steps:
- name: Check out code
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }}
Expand Down Expand Up @@ -93,7 +93,7 @@ jobs:
runs-on: [self-hosted, linux, amd64]
steps:
- name: Check out code
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }}
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/opencv-cuda-artifact.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:

steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha || github.sha }}
Expand Down Expand Up @@ -155,7 +155,7 @@ jobs:

steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v5

- name: Download artifacts
uses: actions/download-artifact@v4
Expand Down
26 changes: 26 additions & 0 deletions .github/workflows/publish-comfyui-node.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Publish ComfyUI Custom Node

on:
workflow_dispatch:

permissions:
contents: read
issues: write

jobs:
publish-comfyui-node:
name: Publish Custom Node to ComfyUI registry
runs-on: ubuntu-latest
# Ensure this only runs on main branch
if: ${{ github.ref == 'refs/heads/main' }}
steps:
- name: Check out code
uses: actions/checkout@v5
with:
submodules: true

- name: Publish Custom Node
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 }}
4 changes: 2 additions & 2 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v5

- uses: actions/setup-node@v5
- uses: actions/setup-node@v6
with:
node-version: 18
cache: npm
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }}
Expand All @@ -40,7 +40,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
# Check https://github.com/livepeer/go-livepeer/pull/1891
# for ref value discussion
Expand All @@ -59,7 +59,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
# Check https://github.com/livepeer/go-livepeer/pull/1891
# for ref value discussion
Expand Down
5 changes: 5 additions & 0 deletions docker/Dockerfile.base
Original file line number Diff line number Diff line change
Expand Up @@ -110,3 +110,8 @@ RUN conda config --set auto_activate_base false && \
RUN echo "conda activate comfystream" >> ~/.bashrc

WORKDIR /workspace/comfystream

# Run ComfyStream BYOC server from /workspace/ComfyUI within the comfystream conda env
ENTRYPOINT ["conda", "run", "--no-capture-output", "-n", "comfystream", "--cwd", "/workspace/ComfyUI", "python", "/workspace/comfystream/server/byoc.py"]
# Default args; can be overridden/appended at runtime
CMD ["--workspace", "/workspace/ComfyUI", "--host", "0.0.0.0", "--port", "8000"]
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ version = "0.1.6"
license = { file = "LICENSE" }
dependencies = [
"asyncio",
"pytrickle @ git+https://github.com/livepeer/pytrickle.git@v0.1.4",
"pytrickle @ git+https://github.com/livepeer/pytrickle.git@393ce79eb1413dc97acafd3eb3ed4b868a891b3a",
"comfyui @ git+https://github.com/hiddenswitch/ComfyUI.git@e62df3a8811d8c652a195d4669f4fb27f6c9a9ba",
"aiortc",
"aiohttp",
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
asyncio
pytrickle @ git+https://github.com/livepeer/pytrickle.git@v0.1.4
pytrickle @ git+https://github.com/livepeer/pytrickle.git@393ce79eb1413dc97acafd3eb3ed4b868a891b3a
comfyui @ git+https://github.com/hiddenswitch/ComfyUI.git@e62df3a8811d8c652a195d4669f4fb27f6c9a9ba
aiortc
aiohttp
Expand Down
12 changes: 6 additions & 6 deletions server/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -556,12 +556,12 @@ async def on_startup(app: web.Application):
app["pipeline"] = Pipeline(
width=512,
height=512,
cwd=app["workspace"],
disable_cuda_malloc=True,
gpu_only=True,
cwd=app["workspace"],
disable_cuda_malloc=True,
gpu_only=True,
preview_method='none',
comfyui_inference_log_level=app.get("comfui_inference_log_level", None),
blacklist_nodes=["ComfyUI-Manager"]
comfyui_inference_log_level=app.get("comfyui_inference_log_level", None),
blacklist_custom_nodes=["ComfyUI-Manager"],
)
app["pcs"] = set()
app["video_tracks"] = {}
Expand Down Expand Up @@ -671,6 +671,6 @@ def force_print(*args, **kwargs):
# Add ComfyStream timeout filter to suppress verbose execution logging
logging.getLogger("comfy.cmd.execution").addFilter(ComfyStreamTimeoutFilter())
if args.comfyui_inference_log_level:
app["comfui_inference_log_level"] = args.comfyui_inference_log_level
app["comfyui_inference_log_level"] = args.comfyui_inference_log_level

web.run_app(app, host=args.host, port=int(args.port), print=force_print)
110 changes: 43 additions & 67 deletions server/byoc.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,41 +19,14 @@
logger = logging.getLogger(__name__)


async def register_orchestrator(orch_url=None, orch_secret=None, capability_name=None, host="127.0.0.1", port=8889):
"""Register capability with orchestrator if configured."""
try:
orch_url = orch_url or os.getenv("ORCH_URL")
orch_secret = orch_secret or os.getenv("ORCH_SECRET")

if orch_url and orch_secret:
os.environ.update({
"CAPABILITY_NAME": capability_name or os.getenv("CAPABILITY_NAME") or "comfystream-processor",
"CAPABILITY_DESCRIPTION": "ComfyUI streaming processor",
"CAPABILITY_URL": f"http://{host}:{port}",
"CAPABILITY_CAPACITY": "1",
"ORCH_URL": orch_url,
"ORCH_SECRET": orch_secret
})

# Pass through explicit capability_name to ensure CLI/env override takes effect
result = await RegisterCapability.register(
logger=logger,
capability_name=capability_name
)
if result:
logger.info(f"Registered capability: {result.geturl()}")
except Exception as e:
logger.error(f"Orchestrator registration failed: {e}")


def main():
parser = argparse.ArgumentParser(
description="Run comfystream server in BYOC (Bring Your Own Compute) mode using pytrickle."
)
parser.add_argument("--port", default=8889, help="Set the server port")
parser.add_argument("--host", default="127.0.0.1", help="Set the host")
parser.add_argument("--port", default=8000, help="Set the server port")
parser.add_argument("--host", default="0.0.0.0", help="Set the host")
parser.add_argument(
"--workspace", default=None, required=True, help="Set Comfy workspace"
"--workspace", default=os.getcwd() + "/../ComfyUI", help="Set Comfy workspace (Default: ../ComfyUI)"
)
parser.add_argument(
"--log-level",
Expand All @@ -73,21 +46,6 @@ def main():
choices=logging._nameToLevel.keys(),
help="Set the logging level for ComfyUI inference",
)
parser.add_argument(
"--orch-url",
default=None,
help="Orchestrator URL for capability registration",
)
parser.add_argument(
"--orch-secret",
default=None,
help="Orchestrator secret for capability registration",
)
parser.add_argument(
"--capability-name",
default=None,
help="Name for this capability (default: comfystream-processor)",
)
parser.add_argument(
"--disable-frame-skip",
default=False,
Expand Down Expand Up @@ -118,7 +76,7 @@ def main():
if args.comfyui_log_level:
log_level = logging._nameToLevel.get(args.comfyui_log_level.upper())
logging.getLogger("comfy").setLevel(log_level)

# Add ComfyStream timeout filter to suppress verbose execution logging
logging.getLogger("comfy.cmd.execution").addFilter(ComfyStreamTimeoutFilter())

Expand All @@ -127,7 +85,7 @@ def force_print(*args, **kwargs):
sys.stdout.flush()

logger.info("Starting ComfyStream BYOC server with pytrickle StreamProcessor...")

# Create frame processor with configuration
frame_processor = ComfyStreamFrameProcessor(
width=args.width,
Expand All @@ -136,52 +94,70 @@ def force_print(*args, **kwargs):
disable_cuda_malloc=True,
gpu_only=True,
preview_method='none',
blacklist_nodes=["ComfyUI-Manager"],
logging_level=args.comfyui_log_level,
comfyui_inference_log_level=args.comfyui_inference_log_level
)

# Create frame skip configuration only if enabled
frame_skip_config = None
if args.disable_frame_skip:
logger.info("Frame skipping disabled")
else:
frame_skip_config = FrameSkipConfig()
logger.info("Frame skipping enabled: adaptive skipping based on queue sizes")

# Create StreamProcessor with frame processor
processor = StreamProcessor(
video_processor=frame_processor.process_video_async,
audio_processor=frame_processor.process_audio_async,
model_loader=frame_processor.load_model,
param_updater=frame_processor.update_params,
on_stream_start=frame_processor.on_stream_start,
on_stream_stop=frame_processor.on_stream_stop,
# Align processor name with capability for consistent logs
name=(args.capability_name or os.getenv("CAPABILITY_NAME") or "comfystream-processor"),
name=(os.getenv("CAPABILITY_NAME") or "comfystream"),
port=int(args.port),
host=args.host,
frame_skip_config=frame_skip_config,
# Ensure server metadata reflects the desired capability name
capability_name=(args.capability_name or os.getenv("CAPABILITY_NAME") or "comfystream-processor")
capability_name=(os.getenv("CAPABILITY_NAME") or "comfystream"),
#server_kwargs...
route_prefix="/",
)

# Set the stream processor reference for text data publishing
frame_processor.set_stream_processor(processor)

# Create async startup function to load model
async def load_model_on_startup(app):
await processor._frame_processor.load_model()


# Create async startup function for orchestrator registration
async def register_orchestrator_startup(app):
await register_orchestrator(
orch_url=args.orch_url,
orch_secret=args.orch_secret,
capability_name=args.capability_name,
host=args.host,
port=args.port
)

# Add model loading and registration to startup hooks
processor.server.app.on_startup.append(load_model_on_startup)
try:
orch_url = os.getenv("ORCH_URL")
orch_secret = os.getenv("ORCH_SECRET")

if orch_url and orch_secret:
# CAPABILITY_URL always overrides host:port from args
capability_url = os.getenv("CAPABILITY_URL") or f"http://{args.host}:{args.port}"

os.environ.update({
"CAPABILITY_NAME": os.getenv("CAPABILITY_NAME") or "comfystream",
"CAPABILITY_DESCRIPTION": "ComfyUI streaming processor",
"CAPABILITY_URL": capability_url,
"CAPABILITY_CAPACITY": "1",
"ORCH_URL": orch_url,
"ORCH_SECRET": orch_secret
})

result = await RegisterCapability.register(
logger=logger,
capability_name=os.getenv("CAPABILITY_NAME") or "comfystream"
)
if result:
logger.info(f"Registered capability: {result.geturl()}")
except Exception as e:
logger.error(f"Orchestrator registration failed: {e}")

# Add registration to startup hooks
processor.server.app.on_startup.append(register_orchestrator_startup)

# Add warmup endpoint: accepts same body as prompts update
Expand All @@ -206,7 +182,7 @@ async def warmup_handler(request):

# Mount at same API namespace as StreamProcessor defaults
processor.server.add_route("POST", "/api/stream/warmup", warmup_handler)

# Run the processor
processor.run()

Expand Down
Loading