Skip to content

Commit 8d22d0d

Browse files
committed
Merge branch 'main' into feat/custom-nodes-config
2 parents 9799c1b + 7accfef commit 8d22d0d

File tree

11 files changed

+109
-487
lines changed

11 files changed

+109
-487
lines changed

.devcontainer/post-create.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ cd /workspace/comfystream
55

66
# Install Comfystream in editable mode.
77
echo -e "\e[32mInstalling Comfystream in editable mode...\e[0m"
8-
/workspace/miniconda3/envs/comfystream/bin/python3 -m pip install -e . -c src/comfystream/scripts/constraints.txt --root-user-action=ignore > /dev/null
8+
/workspace/miniconda3/envs/comfystream/bin/python3 -m pip install -e .[server] -c src/comfystream/scripts/constraints.txt --root-user-action=ignore > /dev/null
99

1010
# Install npm packages if needed
1111
if [ ! -d "/workspace/comfystream/ui/node_modules" ]; then

docker/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
ARG BASE_IMAGE=livepeer/comfyui-base:latest
22

3-
FROM ${BASE_IMAGE}
3+
FROM ${BASE_IMAGE}
44

55
ENV PATH="/workspace/miniconda3/bin:${PATH}" \
66
NVM_DIR=/root/.nvm \

docker/Dockerfile.base

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ RUN conda run -n comfystream pip install --no-cache-dir \
8080
${TensorRT_ROOT}/python/tensorrt-10.12.0.36-cp312-none-linux_x86_64.whl
8181

8282
# Clone ComfyUI
83-
RUN git clone --branch v0.3.60 --depth 1 https://github.com/comfyanonymous/ComfyUI.git /workspace/ComfyUI
83+
RUN git clone --branch v0.3.76 --depth 1 https://github.com/comfyanonymous/ComfyUI.git /workspace/ComfyUI
8484
RUN git clone https://github.com/Comfy-Org/ComfyUI-Manager.git /workspace/ComfyUI/custom_nodes/ComfyUI-Manager
8585

8686
# Copy ComfyStream files into ComfyUI
@@ -98,7 +98,7 @@ RUN conda run -n comfystream --no-capture-output --cwd /workspace/ComfyUI pip in
9898

9999
# Install ComfyStream requirements
100100
RUN ln -s /workspace/comfystream /workspace/ComfyUI/custom_nodes/comfystream
101-
RUN conda run -n comfystream --no-capture-output --cwd /workspace/comfystream pip install -e . --constraint src/comfystream/scripts/constraints.txt --root-user-action=ignore
101+
RUN conda run -n comfystream --no-capture-output --cwd /workspace/comfystream pip install -e .[server] --constraint src/comfystream/scripts/constraints.txt --root-user-action=ignore
102102
RUN conda run -n comfystream --no-capture-output --cwd /workspace/comfystream python install.py --workspace /workspace/ComfyUI
103103

104104
# Accept a build-arg that lets CI force-invalidate setup_nodes.py

docker/supervisord.conf

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ stdout_logfile_maxbytes=0
1919
loglevel=debug
2020

2121
[program:comfystream-api]
22-
command=bash -c "source /workspace/miniconda3/bin/activate comfystream && python app.py --workspace=/workspace/ComfyUI --media-ports=5678,5679,5680 --host=0.0.0.0 --port=8889 --log-level=DEBUG"
23-
directory=/workspace/comfystream/server
22+
command=bash -c "source /workspace/miniconda3/bin/activate comfystream && python /workspace/comfystream/server/app.py --workspace=/workspace/ComfyUI --media-ports=5678,5679,5680 --host=0.0.0.0 --port=8889 --log-level=DEBUG"
23+
directory=/workspace/ComfyUI
2424
autostart=false
2525
autorestart=true
2626
stderr_logfile=/dev/fd/1

pyproject.toml

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@ version = "0.1.7"
99
license = { file = "LICENSE" }
1010
dependencies = [
1111
"asyncio",
12-
"pytrickle @ git+https://github.com/livepeer/pytrickle.git@v0.1.5",
13-
"comfyui @ git+https://github.com/hiddenswitch/ComfyUI.git@e62df3a8811d8c652a195d4669f4fb27f6c9a9ba",
12+
"comfyui @ git+https://github.com/hiddenswitch/ComfyUI.git@7259c252ad745c12dd2412cc67f8e8163d0bbad1",
1413
"aiortc",
1514
"aiohttp",
1615
"aiohttp_cors",
@@ -22,6 +21,9 @@ dependencies = [
2221

2322
[project.optional-dependencies]
2423
dev = ["pytest", "pytest-cov", "ruff"]
24+
server = [
25+
"pytrickle @ git+https://github.com/livepeer/pytrickle.git@v0.1.5"
26+
]
2527

2628
[project.urls]
2729
Repository = "https://github.com/yondonfu/comfystream"
@@ -35,9 +37,6 @@ Icon = "https://raw.githubusercontent.com/livepeer/comfystream-docs/main/logo/ic
3537
package-dir = {"" = "src"}
3638
packages = {find = {where = ["src", "nodes"]}}
3739

38-
[tool.setuptools.dynamic]
39-
dependencies = {file = ["requirements.txt"]}
40-
4140
[tool.ruff]
4241
line-length = 100
4342
target-version = "py312"

requirements.txt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
asyncio
2-
pytrickle @ git+https://github.com/livepeer/pytrickle.git@v0.1.5
3-
comfyui @ git+https://github.com/hiddenswitch/ComfyUI.git@e62df3a8811d8c652a195d4669f4fb27f6c9a9ba
2+
comfyui @ git+https://github.com/hiddenswitch/ComfyUI.git@7259c252ad745c12dd2412cc67f8e8163d0bbad1
43
aiortc
54
aiohttp
65
aiohttp_cors

server/frame_processor.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,11 @@
77
from pytrickle.frame_processor import FrameProcessor
88
from pytrickle.frames import AudioFrame, VideoFrame
99
from pytrickle.stream_processor import VideoProcessingResult
10+
from utils_byoc import ComfyStreamParamsUpdateRequest, normalize_stream_params
1011

1112
from comfystream.pipeline import Pipeline
1213
from comfystream.pipeline_state import PipelineState
13-
from comfystream.utils import (
14-
ComfyStreamParamsUpdateRequest,
15-
convert_prompt,
16-
normalize_stream_params,
17-
)
14+
from comfystream.utils import convert_prompt
1815

1916
logger = logging.getLogger(__name__)
2017

server/utils_byoc.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
"""BYOC-specific utilities that depend on pytrickle.
2+
3+
This module contains utilities that are only needed for the BYOC (Bring Your Own Compute)
4+
server implementation and require pytrickle as a dependency.
5+
"""
6+
7+
import json
8+
9+
# Import from core utils to avoid duplication
10+
import sys
11+
from pathlib import Path
12+
from typing import Any, Dict
13+
14+
from pytrickle.api import StreamParamsUpdateRequest
15+
16+
# Add src to path for imports
17+
src_path = Path(__file__).parent.parent / "src"
18+
sys.path.insert(0, str(src_path))
19+
20+
from comfystream.utils import convert_prompt
21+
22+
23+
class ComfyStreamParamsUpdateRequest(StreamParamsUpdateRequest):
24+
"""ComfyStream parameter validation."""
25+
26+
def __init__(self, **data):
27+
# Handle prompts parameter
28+
if "prompts" in data:
29+
prompts = data["prompts"]
30+
31+
# Parse JSON string if needed
32+
if isinstance(prompts, str) and prompts.strip():
33+
try:
34+
prompts = json.loads(prompts)
35+
except json.JSONDecodeError:
36+
data.pop("prompts")
37+
38+
# Handle list - use first valid dict
39+
elif isinstance(prompts, list):
40+
prompts = next((p for p in prompts if isinstance(p, dict)), None)
41+
if not prompts:
42+
data.pop("prompts")
43+
44+
# Validate prompts
45+
if "prompts" in data and isinstance(prompts, dict):
46+
try:
47+
data["prompts"] = convert_prompt(prompts, return_dict=True)
48+
except Exception:
49+
data.pop("prompts")
50+
51+
# Call parent constructor
52+
super().__init__(**data)
53+
54+
@classmethod
55+
def model_validate(cls, obj):
56+
return cls(**obj)
57+
58+
def model_dump(self):
59+
return super().model_dump()
60+
61+
62+
def normalize_stream_params(params: Any) -> Dict[str, Any]:
63+
"""Normalize stream parameters from various formats to a dict.
64+
65+
Args:
66+
params: Parameters in dict, list, or other format
67+
68+
Returns:
69+
Dict containing normalized parameters, empty dict if invalid
70+
"""
71+
if params is None:
72+
return {}
73+
if isinstance(params, dict):
74+
return dict(params)
75+
if isinstance(params, list):
76+
for candidate in params:
77+
if isinstance(candidate, dict):
78+
return dict(candidate)
79+
return {}
80+
return {}

src/comfystream/utils.py

Lines changed: 0 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
from typing import Any, Dict
55

66
from comfy.api.components.schema.prompt import Prompt, PromptDictInput
7-
from pytrickle.api import StreamParamsUpdateRequest
87

98
from .modalities import (
109
get_convertible_node_keys,
@@ -86,66 +85,6 @@ def convert_prompt(prompt: PromptDictInput, return_dict: bool = False) -> Prompt
8685
return Prompt.validate(prompt)
8786

8887

89-
class ComfyStreamParamsUpdateRequest(StreamParamsUpdateRequest):
90-
"""ComfyStream parameter validation."""
91-
92-
def __init__(self, **data):
93-
# Handle prompts parameter
94-
if "prompts" in data:
95-
prompts = data["prompts"]
96-
97-
# Parse JSON string if needed
98-
if isinstance(prompts, str) and prompts.strip():
99-
try:
100-
prompts = json.loads(prompts)
101-
except json.JSONDecodeError:
102-
data.pop("prompts")
103-
104-
# Handle list - use first valid dict
105-
elif isinstance(prompts, list):
106-
prompts = next((p for p in prompts if isinstance(p, dict)), None)
107-
if not prompts:
108-
data.pop("prompts")
109-
110-
# Validate prompts
111-
if "prompts" in data and isinstance(prompts, dict):
112-
try:
113-
data["prompts"] = convert_prompt(prompts, return_dict=True)
114-
except Exception:
115-
data.pop("prompts")
116-
117-
# Call parent constructor
118-
super().__init__(**data)
119-
120-
@classmethod
121-
def model_validate(cls, obj):
122-
return cls(**obj)
123-
124-
def model_dump(self):
125-
return super().model_dump()
126-
127-
128-
def normalize_stream_params(params: Any) -> Dict[str, Any]:
129-
"""Normalize stream parameters from various formats to a dict.
130-
131-
Args:
132-
params: Parameters in dict, list, or other format
133-
134-
Returns:
135-
Dict containing normalized parameters, empty dict if invalid
136-
"""
137-
if params is None:
138-
return {}
139-
if isinstance(params, dict):
140-
return dict(params)
141-
if isinstance(params, list):
142-
for candidate in params:
143-
if isinstance(candidate, dict):
144-
return dict(candidate)
145-
return {}
146-
return {}
147-
148-
14988
def get_default_workflow() -> dict:
15089
"""Return the default workflow as a dictionary for warmup.
15190

0 commit comments

Comments
 (0)