mirror of
https://github.com/comfyanonymous/ComfyUI.git
synced 2025-12-16 01:37:04 +08:00
Compare commits
24 Commits
25567a82bf
...
fe310b181d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fe310b181d | ||
|
|
6592bffc60 | ||
|
|
971cefe7d4 | ||
|
|
d94b0315ee | ||
|
|
4d4133bde0 | ||
|
|
a5d8933ca2 | ||
|
|
d2ed468e80 | ||
|
|
9cbe8f13d1 | ||
|
|
7e70f2d3b0 | ||
|
|
49037e49b9 | ||
|
|
487b3cd4e2 | ||
|
|
44e5c380ee | ||
|
|
a4c41a7bab | ||
|
|
745fbb34f2 | ||
|
|
adfff60437 | ||
|
|
b9db75631c | ||
|
|
a1cbb66083 | ||
|
|
5c3408980a | ||
|
|
ef92024b55 | ||
|
|
25b5a8d7e4 | ||
|
|
9537b96121 | ||
|
|
1b6821edcf | ||
|
|
1d5b9bc4fa | ||
|
|
2505cc4bc9 |
23
.env.example
Normal file
23
.env.example
Normal file
@ -0,0 +1,23 @@
|
||||
# ComfyUI Environment Variables
|
||||
|
||||
# Google AI API Key for Nano Banana nodes
|
||||
# Get your API key from: https://aistudio.google.com/app/apikey
|
||||
GOOGLE_API_KEY=your_google_api_key_here
|
||||
|
||||
# Optional: Vertex AI configuration (alternative to GOOGLE_API_KEY)
|
||||
# If using Vertex AI with Application Default Credentials (ADC)
|
||||
# PROJECT_ID=your-gcp-project-id
|
||||
# LOCATION=us-central1
|
||||
|
||||
# Timezone
|
||||
TZ=America/Chicago
|
||||
|
||||
# User/Group IDs (for file permissions)
|
||||
PUID=1000
|
||||
PGID=1000
|
||||
|
||||
# Optional: OpenTelemetry configuration (for observability)
|
||||
# Uncomment and configure these if you want to enable OpenTelemetry instrumentation
|
||||
# OTEL_EXPORTER_OTLP_ENDPOINT=http://your-otel-collector:4317
|
||||
# OTEL_SERVICE_NAME=comfyui
|
||||
# OTEL_RESOURCE_ATTRIBUTES=service.name=comfyui
|
||||
8
.gitignore
vendored
8
.gitignore
vendored
@ -24,3 +24,11 @@ web_custom_versions/
|
||||
openapi.yaml
|
||||
filtered-openapi.yaml
|
||||
uv.lock
|
||||
|
||||
# Docker
|
||||
.dockerignore
|
||||
docker-compose.override.yml
|
||||
|
||||
# Environment variables
|
||||
.env
|
||||
!.env.example
|
||||
|
||||
37
Dockerfile
Normal file
37
Dockerfile
Normal file
@ -0,0 +1,37 @@
|
||||
# Build argument for base image selection
|
||||
ARG BASE_IMAGE=nvidia/cuda:12.6.3-cudnn-runtime-ubuntu24.04
|
||||
|
||||
# ----------------------
|
||||
# Stage: Base Runtime
|
||||
# ----------------------
|
||||
FROM ${BASE_IMAGE} AS base
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
ENV PIP_PREFER_BINARY=1
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
|
||||
# Install system dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
python3.12 python3.12-venv python3-pip git git-lfs wget \
|
||||
libgl1 libglib2.0-0 libsm6 libxext6 libxrender1 \
|
||||
ffmpeg \
|
||||
espeak-ng libespeak-ng1 \
|
||||
build-essential \
|
||||
&& git lfs install \
|
||||
&& ln -sf /usr/bin/python3.12 /usr/bin/python \
|
||||
&& ln -sf /usr/bin/pip3 /usr/bin/pip \
|
||||
&& apt-get autoremove -y && apt-get clean -y && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# OpenTelemetry packages will be installed in the venv by entrypoint script if needed
|
||||
|
||||
WORKDIR /app/ComfyUI
|
||||
|
||||
# Copy entrypoint and helper scripts
|
||||
COPY scripts/docker-entrypoint.sh /app/ComfyUI/scripts/docker-entrypoint.sh
|
||||
COPY scripts/comfy-node-install.sh /usr/local/bin/comfy-node-install
|
||||
RUN chmod +x /app/ComfyUI/scripts/docker-entrypoint.sh && \
|
||||
chmod +x /usr/local/bin/comfy-node-install
|
||||
|
||||
# Set entrypoint
|
||||
ENTRYPOINT ["/app/ComfyUI/scripts/docker-entrypoint.sh"]
|
||||
|
||||
338
PLAN.md
Normal file
338
PLAN.md
Normal file
@ -0,0 +1,338 @@
|
||||
# Nano Banana Environment Configuration
|
||||
|
||||
## Issues Identified
|
||||
|
||||
1. **ComfyUI-Manager Security Alert**: ComfyUI version outdated; Manager in frozen mode (installations blocked). Defer to separate branch.
|
||||
2. **API Key Missing**: `GOOGLE_API_KEY` not configured; Nano Banana fails with "No valid credentials found."
|
||||
|
||||
## Design Decisions
|
||||
|
||||
- **Local Docker**: Use `.env` file loaded via `docker-compose.yml` `env_file` directive
|
||||
- **RunPod Serverless**: Environment variables set in template interface (per [RunPod docs](https://docs.runpod.io/serverless/development/environment-variables)); code reads `os.environ`
|
||||
- **Nano Banana Auth**: Supports two methods:
|
||||
- API approach: `GOOGLE_API_KEY` env var (simpler, primary)
|
||||
- Vertex AI: `PROJECT_ID` + `LOCATION` + ADC (optional, document only)
|
||||
- **Container Rebuild Strategy**: Clean and rebuild containers before testing to ensure fresh state
|
||||
|
||||
## Implementation Steps
|
||||
|
||||
### Pre-Hook: Clean and Rebuild Container (Before Testing)
|
||||
|
||||
**IMPLEMENTATION:**
|
||||
|
||||
- Stop and remove existing containers: `docker compose down` or `docker stop comfy && docker rm comfy`
|
||||
- Remove old images (optional, for clean rebuild): `docker compose build --no-cache` or `docker rmi [image-name]`
|
||||
- Rebuild Docker image from root `Dockerfile`: `docker compose build`
|
||||
- Expected outcome: Fresh container image built from latest Dockerfile
|
||||
- Success criteria: Build completes without errors; image ready for testing
|
||||
|
||||
**WHEN TO RUN:**
|
||||
|
||||
- Before Step 4 (Local validation) - critical
|
||||
- Before any testing/validation steps
|
||||
- When Dockerfile or entrypoint scripts change
|
||||
|
||||
**GIT TRACKING:**
|
||||
|
||||
- No commit needed (pre-hook step)
|
||||
- Document in PR description as testing prerequisite
|
||||
|
||||
**CHECKPOINT:**
|
||||
|
||||
- Natural stopping point: After successful build
|
||||
- Rollback: Use previous image if build fails
|
||||
|
||||
---
|
||||
|
||||
### Step 1: Create PLAN.md and .env.example
|
||||
|
||||
**IMPLEMENTATION:**
|
||||
|
||||
- Create `PLAN.md` at repo root with this plan (living document)
|
||||
- Create `.env.example` with `GOOGLE_API_KEY` placeholder and commented Vertex AI vars
|
||||
- Expected outcome: Planning artifact tracked; env template ready
|
||||
- Success criteria: Both files committed; `.env.example` has clear comments
|
||||
|
||||
**GIT TRACKING:**
|
||||
|
||||
- Commit after both files created
|
||||
- Message: `[ENV-1] Add plan and env example for Nano Banana API keys`
|
||||
- Branch: `feature/comfy-nano-banana-setup` (existing)
|
||||
- Push: After commit for visibility
|
||||
- PR: Update draft PR description with checklist
|
||||
|
||||
**USER FEEDBACK TOUCHPOINT:**
|
||||
|
||||
- Who: {users}
|
||||
- What to show: PR diff showing `.env.example` content
|
||||
- Feedback needed: "Does `.env.example` cover your needs? Any additional vars?"
|
||||
- Blocking: Non-blocking (proceed if no response)
|
||||
|
||||
**CHECKPOINT:**
|
||||
|
||||
- Natural stopping point: After commit
|
||||
- Rollback: Delete files and revert commit
|
||||
|
||||
---
|
||||
|
||||
### Step 2: Wire .env into docker-compose.yml
|
||||
|
||||
**IMPLEMENTATION:**
|
||||
|
||||
- Add `env_file: .env` to `comfyui` service
|
||||
- Add `GOOGLE_API_KEY` to `environment` section (passes through from `.env`)
|
||||
- Expected outcome: Container receives env vars from `.env` file
|
||||
- Success criteria: `docker compose config` shows env_file and environment vars
|
||||
|
||||
**GIT TRACKING:**
|
||||
|
||||
- Commit after docker-compose.yml change
|
||||
- Message: `[ENV-2] Wire .env file into docker-compose for Nano Banana`
|
||||
- Branch: Same feature branch
|
||||
- Push: After commit
|
||||
- PR: Update checklist, add compose snippet to PR description
|
||||
|
||||
**USER FEEDBACK TOUCHPOINT:**
|
||||
|
||||
- Who: {users}
|
||||
- What to show: Diff of docker-compose.yml changes
|
||||
- Feedback needed: "Confirm env_file approach works for your local setup"
|
||||
- Blocking: Non-blocking
|
||||
|
||||
**CHECKPOINT:**
|
||||
|
||||
- Natural stopping point: After commit
|
||||
- Rollback: Revert docker-compose.yml change
|
||||
|
||||
---
|
||||
|
||||
### Step 3: Protect secrets in Git
|
||||
|
||||
**IMPLEMENTATION:**
|
||||
|
||||
- Add `.env` to `.gitignore`
|
||||
- Ensure `.env.example` remains tracked (not ignored)
|
||||
- Expected outcome: Secrets never committed
|
||||
- Success criteria: `git status` shows `.env` ignored; `.env.example` tracked
|
||||
|
||||
**GIT TRACKING:**
|
||||
|
||||
- Commit after .gitignore update
|
||||
- Message: `[ENV-3] Ignore .env file, keep example tracked`
|
||||
- Branch: Same feature branch
|
||||
- Push: After commit
|
||||
- PR: Update checklist
|
||||
|
||||
**USER FEEDBACK TOUCHPOINT:**
|
||||
|
||||
- Who: {users}
|
||||
- What to show: .gitignore diff
|
||||
- Feedback needed: "Confirm .env should be ignored"
|
||||
- Blocking: Non-blocking
|
||||
|
||||
**CHECKPOINT:**
|
||||
|
||||
- Natural stopping point: After commit
|
||||
- Rollback: Revert .gitignore change
|
||||
|
||||
---
|
||||
|
||||
### Step 4: Local validation with real API key
|
||||
|
||||
**PREREQUISITE: Run Pre-Hook (Clean and Rebuild Container)**
|
||||
|
||||
**IMPLEMENTATION:**
|
||||
|
||||
- Run pre-hook: Clean containers and rebuild image
|
||||
- Create local `.env` file (not committed) with user's `GOOGLE_API_KEY`
|
||||
- Start container: `docker compose up -d` (or `docker compose up` for logs)
|
||||
- Verify in logs: No "No valid credentials found" error
|
||||
- Test in UI: Nano Banana nodes visible and functional
|
||||
- Expected outcome: Node authenticates successfully
|
||||
- Success criteria: Logs show successful auth; nodes work in ComfyUI UI
|
||||
|
||||
**GIT TRACKING:**
|
||||
|
||||
- Commit (empty or documentation) after validation
|
||||
- Message: `[ENV-4] Validate Nano Banana with env-based API key - validates auth`
|
||||
- Branch: Same feature branch
|
||||
- Push: After commit
|
||||
- PR: Update checklist, attach log snippet showing successful auth
|
||||
|
||||
**USER FEEDBACK TOUCHPOINT:**
|
||||
|
||||
- Who: {users}
|
||||
- What to show: Log snippet showing successful auth; screenshot of nodes in UI
|
||||
- Feedback needed: "Confirm API key authentication works; nodes functional?"
|
||||
- Blocking: Non-blocking (preferred before merge)
|
||||
|
||||
**CHECKPOINT:**
|
||||
|
||||
- Natural stopping point: After validation commit
|
||||
- Rollback: Remove `.env`, restart container, verify error returns
|
||||
|
||||
---
|
||||
|
||||
### Step 5: Document RunPod configuration
|
||||
|
||||
**IMPLEMENTATION:**
|
||||
|
||||
- Update PR description with RunPod env var setup instructions
|
||||
- Add note: Set `GOOGLE_API_KEY` in RunPod template env vars (no `.env` file needed)
|
||||
- RunPod specific configuration instructions:
|
||||
- Go to RunPod console -> Templates -> [Your Template] -> Edit
|
||||
- Scroll to Environment Variables
|
||||
- Key: `GOOGLE_API_KEY`, Value: [Your API Key]
|
||||
- No need for `.env` file in the container image
|
||||
- Code reads `os.environ` which works for both methods
|
||||
- Expected outcome: Clear instructions for RunPod deployment
|
||||
- Success criteria: PR description has RunPod section with env var guidance
|
||||
|
||||
**GIT TRACKING:**
|
||||
|
||||
- Commit (empty or documentation)
|
||||
- Message: `[ENV-5] Document RunPod env configuration for Nano Banana`
|
||||
- Branch: Same feature branch
|
||||
- Push: After commit
|
||||
- PR: Update PR description with RunPod section
|
||||
|
||||
**USER FEEDBACK TOUCHPOINT:**
|
||||
|
||||
- Who: {users}
|
||||
- What to show: PR description RunPod section
|
||||
- Feedback needed: "Does RunPod env var guidance match your setup?"
|
||||
- Blocking: Non-blocking
|
||||
|
||||
**CHECKPOINT:**
|
||||
|
||||
- Natural stopping point: After commit
|
||||
- Rollback: Edit PR description
|
||||
|
||||
---
|
||||
|
||||
### Step 6: Cleanup planning artifact (pre-merge)
|
||||
|
||||
**IMPLEMENTATION:**
|
||||
|
||||
- Copy final `PLAN.md` content to PR description
|
||||
- Delete `PLAN.md` file
|
||||
- Expected outcome: Clean main branch; plan preserved in PR
|
||||
- Success criteria: `PLAN.md` removed; PR description has complete plan
|
||||
|
||||
**GIT TRACKING:**
|
||||
|
||||
- Final commit before merge
|
||||
- Message: `[ENV-6] Cleanup planning artifact - plan moved to PR description`
|
||||
- Branch: Same feature branch
|
||||
- Push: After commit
|
||||
- PR: Final PR description update
|
||||
|
||||
**USER FEEDBACK TOUCHPOINT:**
|
||||
|
||||
- Who: {users}
|
||||
- What to show: Final PR ready for review
|
||||
- Feedback needed: "Ready for final review and merge?"
|
||||
- Blocking: Non-blocking
|
||||
|
||||
**CHECKPOINT:**
|
||||
|
||||
- Natural stopping point: Before merge
|
||||
- Rollback: Restore `PLAN.md` if needed
|
||||
|
||||
---
|
||||
|
||||
## Communication Templates
|
||||
|
||||
### After Step 1 (Initial Setup)
|
||||
|
||||
**Notify {users} via PR comment:**
|
||||
|
||||
```
|
||||
✅ Step 1 Complete: Plan and .env.example created
|
||||
|
||||
What's done:
|
||||
- Added PLAN.md (living plan document)
|
||||
- Created .env.example template with GOOGLE_API_KEY
|
||||
|
||||
What you can try:
|
||||
- Review .env.example: [link to file in PR]
|
||||
|
||||
Specific feedback needed:
|
||||
- Does .env.example cover your needs?
|
||||
- Any additional environment variables needed?
|
||||
|
||||
What's next:
|
||||
- Will proceed with docker-compose.yml integration while waiting for feedback
|
||||
```
|
||||
|
||||
### After Step 4 (Validation)
|
||||
|
||||
**Notify {users} via PR comment:**
|
||||
|
||||
```
|
||||
✅ Step 4 Complete: Local validation successful
|
||||
|
||||
What's done:
|
||||
- Cleaned and rebuilt container (pre-hook)
|
||||
- Wired .env into docker-compose.yml
|
||||
- Validated with real API key
|
||||
- Nano Banana nodes authenticating successfully
|
||||
|
||||
What you can try:
|
||||
- Test at http://localhost:8188
|
||||
- Log snippet: [attach log showing successful auth]
|
||||
- Screenshot: [attach UI showing nodes]
|
||||
|
||||
Specific feedback needed:
|
||||
- Confirm API key authentication works for you?
|
||||
- Nodes functional in UI?
|
||||
|
||||
What's next:
|
||||
- Will document RunPod configuration while waiting for feedback
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Rollback Strategy
|
||||
|
||||
**If env config breaks container:**
|
||||
|
||||
```bash
|
||||
# Remove .env
|
||||
rm .env
|
||||
# Stop and remove container
|
||||
docker compose down
|
||||
# Rebuild and restart
|
||||
docker compose build && docker compose up -d
|
||||
# Revert docker-compose.yml if needed
|
||||
git revert [commit-hash]
|
||||
```
|
||||
|
||||
**If validation fails:**
|
||||
|
||||
- Keep error logs in commit message
|
||||
- Document in PR description
|
||||
- Branch from last good commit if major changes needed
|
||||
|
||||
---
|
||||
|
||||
## Backlog Items (Separate Branch)
|
||||
|
||||
- [ ] ComfyUI version update to resolve Manager frozen mode
|
||||
- [ ] OpenTelemetry tracing for Nano Banana errors
|
||||
|
||||
## Potential Blockers & Constraints
|
||||
|
||||
### Identified Blockers
|
||||
|
||||
1. **Container State**: Existing `comfy` container may have stale state - addressed by pre-hook cleanup
|
||||
2. **GPU Driver Issues**: Previous `docker compose up` failure due to GPU driver problems - needs investigation
|
||||
3. **Nano Banana Installation Status**: Unclear if node is already installed or needs installation
|
||||
4. **Container Strategy**: Two containers mentioned (`comfy` vs `comfyui`) - need to standardize approach
|
||||
|
||||
### Questions Requiring Clarification
|
||||
|
||||
1. **Container Management**: Should we always use `docker compose` commands, or handle standalone `comfy` container?
|
||||
2. **GPU Configuration**: What was the specific GPU driver error? May need nvidia-container-toolkit setup.
|
||||
3. **Nano Banana Node**: Is ComfyUI_Nano_Banana already installed, or do we need to add installation step?
|
||||
4. **Testing Environment**: Are there any constraints on when/how containers can be rebuilt (e.g., data persistence concerns)?
|
||||
69
RUNPOD_SETUP.md
Normal file
69
RUNPOD_SETUP.md
Normal file
@ -0,0 +1,69 @@
|
||||
# RunPod Deployment Configuration
|
||||
|
||||
This document describes how to configure environment variables for ComfyUI when deploying to RunPod Serverless.
|
||||
|
||||
## Environment Variables Setup
|
||||
|
||||
### Required: Google API Key for Nano Banana
|
||||
|
||||
1. Go to [RunPod Console](https://www.runpod.io/console/serverless)
|
||||
2. Navigate to **Templates** → Select your ComfyUI template → **Edit**
|
||||
3. Scroll to **Environment Variables** section
|
||||
4. Add the following variable:
|
||||
- **Key**: `GOOGLE_API_KEY`
|
||||
- **Value**: Your Google AI API key (get one from [Google AI Studio](https://aistudio.google.com/app/apikey))
|
||||
|
||||
### Optional: Vertex AI Configuration
|
||||
|
||||
If you prefer to use Vertex AI instead of the Google AI API:
|
||||
|
||||
- **Key**: `PROJECT_ID`
|
||||
- **Value**: Your GCP project ID
|
||||
- **Key**: `LOCATION`
|
||||
- **Value**: `us-central1` (or your preferred region)
|
||||
|
||||
**Note:** Vertex AI requires Application Default Credentials (ADC) to be configured in your container image.
|
||||
|
||||
### Optional: OpenTelemetry Configuration
|
||||
|
||||
For observability and monitoring:
|
||||
|
||||
- **Key**: `OTEL_EXPORTER_OTLP_ENDPOINT`
|
||||
- **Value**: `http://your-otel-collector:4317`
|
||||
- **Key**: `OTEL_SERVICE_NAME`
|
||||
- **Value**: `comfyui`
|
||||
- **Key**: `OTEL_RESOURCE_ATTRIBUTES`
|
||||
- **Value**: `service.name=comfyui`
|
||||
|
||||
## How It Works
|
||||
|
||||
The ComfyUI Docker image is configured to read environment variables directly from `os.environ`, which means:
|
||||
|
||||
1. **Local Development**: Variables are loaded from `.env` file via `docker-compose.yml`
|
||||
2. **RunPod Deployment**: Variables are set in the RunPod template interface
|
||||
3. **Code Compatibility**: No code changes needed—both methods use `os.environ`
|
||||
|
||||
## Verification
|
||||
|
||||
After setting the environment variables in RunPod:
|
||||
|
||||
1. Deploy or restart your serverless endpoint
|
||||
2. Check the logs for "GOOGLE_API_KEY" to verify it's set
|
||||
3. Test Nano Banana nodes to confirm authentication works
|
||||
|
||||
## Differences from Local Setup
|
||||
|
||||
| Aspect | Local (Docker Compose) | RunPod Serverless |
|
||||
|--------|----------------------|-------------------|
|
||||
| **Config Method** | `.env` file | RunPod template UI |
|
||||
| **GPU Support** | Optional (can run CPU mode) | Typically GPU-enabled |
|
||||
| **Persistence** | Docker volumes | RunPod storage |
|
||||
| **API Key Storage** | Local `.env` (gitignored) | RunPod environment vars |
|
||||
|
||||
## Security Notes
|
||||
|
||||
- Environment variables in RunPod are encrypted at rest
|
||||
- Never commit `.env` files with real API keys to Git
|
||||
- Rotate your API keys periodically
|
||||
- Use different API keys for development vs production if possible
|
||||
|
||||
@ -1557,10 +1557,13 @@ def sample_er_sde(model, x, sigmas, extra_args=None, callback=None, disable=None
|
||||
|
||||
|
||||
@torch.no_grad()
|
||||
def sample_seeds_2(model, x, sigmas, extra_args=None, callback=None, disable=None, eta=1., s_noise=1., noise_sampler=None, r=0.5):
|
||||
def sample_seeds_2(model, x, sigmas, extra_args=None, callback=None, disable=None, eta=1., s_noise=1., noise_sampler=None, r=0.5, solver_type="phi_1"):
|
||||
"""SEEDS-2 - Stochastic Explicit Exponential Derivative-free Solvers (VP Data Prediction) stage 2.
|
||||
arXiv: https://arxiv.org/abs/2305.14267 (NeurIPS 2023)
|
||||
"""
|
||||
if solver_type not in {"phi_1", "phi_2"}:
|
||||
raise ValueError("solver_type must be 'phi_1' or 'phi_2'")
|
||||
|
||||
extra_args = {} if extra_args is None else extra_args
|
||||
seed = extra_args.get("seed", None)
|
||||
noise_sampler = default_noise_sampler(x, seed=seed) if noise_sampler is None else noise_sampler
|
||||
@ -1600,8 +1603,14 @@ def sample_seeds_2(model, x, sigmas, extra_args=None, callback=None, disable=Non
|
||||
denoised_2 = model(x_2, sigma_s_1 * s_in, **extra_args)
|
||||
|
||||
# Step 2
|
||||
denoised_d = torch.lerp(denoised, denoised_2, fac)
|
||||
x = sigmas[i + 1] / sigmas[i] * (-h * eta).exp() * x - alpha_t * ei_h_phi_1(-h_eta) * denoised_d
|
||||
if solver_type == "phi_1":
|
||||
denoised_d = torch.lerp(denoised, denoised_2, fac)
|
||||
x = sigmas[i + 1] / sigmas[i] * (-h * eta).exp() * x - alpha_t * ei_h_phi_1(-h_eta) * denoised_d
|
||||
elif solver_type == "phi_2":
|
||||
b2 = ei_h_phi_2(-h_eta) / r
|
||||
b1 = ei_h_phi_1(-h_eta) - b2
|
||||
x = sigmas[i + 1] / sigmas[i] * (-h * eta).exp() * x - alpha_t * (b1 * denoised + b2 * denoised_2)
|
||||
|
||||
if inject_noise:
|
||||
segment_factor = (r - 1) * h * eta
|
||||
sde_noise = sde_noise * segment_factor.exp()
|
||||
|
||||
@ -592,7 +592,7 @@ def mixed_precision_ops(quant_config={}, compute_dtype=torch.bfloat16, full_prec
|
||||
quant_conf = {"format": self.quant_format}
|
||||
if self._full_precision_mm:
|
||||
quant_conf["full_precision_matrix_mult"] = True
|
||||
sd["{}comfy_quant".format(prefix)] = torch.frombuffer(json.dumps(quant_conf).encode('utf-8'), dtype=torch.uint8)
|
||||
sd["{}comfy_quant".format(prefix)] = torch.tensor(list(json.dumps(quant_conf).encode('utf-8')), dtype=torch.uint8)
|
||||
return sd
|
||||
|
||||
def _forward(self, input, weight, bias):
|
||||
|
||||
@ -1262,6 +1262,6 @@ def convert_old_quants(state_dict, model_prefix="", metadata={}):
|
||||
if quant_metadata is not None:
|
||||
layers = quant_metadata["layers"]
|
||||
for k, v in layers.items():
|
||||
state_dict["{}.comfy_quant".format(k)] = torch.frombuffer(json.dumps(v).encode('utf-8'), dtype=torch.uint8)
|
||||
state_dict["{}.comfy_quant".format(k)] = torch.tensor(list(json.dumps(v).encode('utf-8')), dtype=torch.uint8)
|
||||
|
||||
return state_dict, metadata
|
||||
|
||||
@ -659,6 +659,31 @@ class SamplerSASolver(io.ComfyNode):
|
||||
get_sampler = execute
|
||||
|
||||
|
||||
class SamplerSEEDS2(io.ComfyNode):
|
||||
@classmethod
|
||||
def define_schema(cls):
|
||||
return io.Schema(
|
||||
node_id="SamplerSEEDS2",
|
||||
category="sampling/custom_sampling/samplers",
|
||||
inputs=[
|
||||
io.Combo.Input("solver_type", options=["phi_1", "phi_2"]),
|
||||
io.Float.Input("eta", default=1.0, min=0.0, max=100.0, step=0.01, round=False, tooltip="Stochastic strength"),
|
||||
io.Float.Input("s_noise", default=1.0, min=0.0, max=100.0, step=0.01, round=False, tooltip="SDE noise multiplier"),
|
||||
io.Float.Input("r", default=0.5, min=0.01, max=1.0, step=0.01, round=False, tooltip="Relative step size for the intermediate stage (c2 node)"),
|
||||
],
|
||||
outputs=[io.Sampler.Output()]
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def execute(cls, solver_type, eta, s_noise, r) -> io.NodeOutput:
|
||||
sampler_name = "seeds_2"
|
||||
sampler = comfy.samplers.ksampler(
|
||||
sampler_name,
|
||||
{"eta": eta, "s_noise": s_noise, "r": r, "solver_type": solver_type},
|
||||
)
|
||||
return io.NodeOutput(sampler)
|
||||
|
||||
|
||||
class Noise_EmptyNoise:
|
||||
def __init__(self):
|
||||
self.seed = 0
|
||||
@ -996,6 +1021,7 @@ class CustomSamplersExtension(ComfyExtension):
|
||||
SamplerDPMAdaptative,
|
||||
SamplerER_SDE,
|
||||
SamplerSASolver,
|
||||
SamplerSEEDS2,
|
||||
SplitSigmas,
|
||||
SplitSigmasDenoise,
|
||||
FlipSigmas,
|
||||
|
||||
12
docker-compose.override.yml.example
Normal file
12
docker-compose.override.yml.example
Normal file
@ -0,0 +1,12 @@
|
||||
# Example override file to disable GPU for testing
|
||||
# Copy this to docker-compose.override.yml to use CPU-only mode
|
||||
services:
|
||||
comfyui:
|
||||
deploy:
|
||||
resources:
|
||||
reservations:
|
||||
devices: []
|
||||
# Remove ipc: host if not using GPU
|
||||
# ipc: host
|
||||
|
||||
|
||||
48
docker-compose.yml
Normal file
48
docker-compose.yml
Normal file
@ -0,0 +1,48 @@
|
||||
services:
|
||||
comfyui:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
container_name: comfyui
|
||||
ports:
|
||||
- "8189:8188"
|
||||
# Temporarily disabled for testing without GPU
|
||||
# deploy:
|
||||
# resources:
|
||||
# reservations:
|
||||
# devices:
|
||||
# - driver: nvidia
|
||||
# count: all
|
||||
# capabilities: [gpu]
|
||||
# ipc: host
|
||||
env_file:
|
||||
- .env
|
||||
volumes:
|
||||
- .:/app/ComfyUI # Mount local repo (for git checkout updates)
|
||||
- comfyui-models:/app/ComfyUI/models # Persist models
|
||||
- comfyui-output:/app/ComfyUI/output # Persist outputs
|
||||
- comfyui-input:/app/ComfyUI/input # Persist inputs
|
||||
- comfyui-custom-nodes:/app/ComfyUI/custom_nodes # Persist custom nodes
|
||||
- comfyui-user:/app/ComfyUI/user # Persist user settings/workflows
|
||||
- comfyui-venv:/app/venv # Cache virtualenv
|
||||
environment:
|
||||
- GOOGLE_API_KEY=${GOOGLE_API_KEY}
|
||||
- TZ=America/Chicago
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- COMFYUI_ARGS=--cpu
|
||||
- INSTALL_NANO_BANANA=true
|
||||
# OpenTelemetry environment variables (optional - set if you want OTEL)
|
||||
# - OTEL_EXPORTER_OTLP_ENDPOINT=http://your-otel-collector:4317
|
||||
# - OTEL_SERVICE_NAME=comfyui
|
||||
# - OTEL_RESOURCE_ATTRIBUTES=service.name=comfyui
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
comfyui-models:
|
||||
comfyui-output:
|
||||
comfyui-input:
|
||||
comfyui-custom-nodes:
|
||||
comfyui-user:
|
||||
comfyui-venv:
|
||||
|
||||
52
scripts/comfy-node-install.sh
Normal file
52
scripts/comfy-node-install.sh
Normal file
@ -0,0 +1,52 @@
|
||||
#!/bin/bash
|
||||
# comfy-node-install - Install ComfyUI custom nodes from GitHub repositories
|
||||
# Usage: comfy-node-install <repo-url> [repo-url2 ...]
|
||||
|
||||
set -e
|
||||
|
||||
COMFYUI_DIR="${COMFYUI_DIR:-/app/ComfyUI}"
|
||||
CUSTOM_NODES_DIR="${COMFYUI_DIR}/custom_nodes"
|
||||
|
||||
# Ensure custom_nodes directory exists
|
||||
mkdir -p "${CUSTOM_NODES_DIR}"
|
||||
|
||||
install_node() {
|
||||
local repo_url="$1"
|
||||
if [ -z "$repo_url" ]; then
|
||||
echo "Error: Repository URL is required"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Extract repository name from URL
|
||||
local repo_name=$(basename "${repo_url}" .git)
|
||||
|
||||
# Handle full GitHub URLs or just repo paths
|
||||
if [[ "$repo_url" != http* ]]; then
|
||||
repo_url="https://github.com/${repo_url}"
|
||||
fi
|
||||
|
||||
local target_dir="${CUSTOM_NODES_DIR}/${repo_name}"
|
||||
|
||||
echo "Installing custom node: ${repo_name} from ${repo_url}"
|
||||
|
||||
# Remove existing installation if it exists
|
||||
if [ -d "${target_dir}" ]; then
|
||||
echo " Removing existing installation..."
|
||||
rm -rf "${target_dir}"
|
||||
fi
|
||||
|
||||
# Clone the repository
|
||||
if [ -n "${GIT_LFS_SKIP_SMUDGE}" ]; then
|
||||
GIT_TERMINAL_PROMPT=0 GIT_LFS_SKIP_SMUDGE=1 git clone --depth 1 "${repo_url}" "${target_dir}"
|
||||
else
|
||||
GIT_TERMINAL_PROMPT=0 git clone --depth 1 "${repo_url}" "${target_dir}"
|
||||
fi
|
||||
|
||||
echo " Successfully installed ${repo_name}"
|
||||
}
|
||||
|
||||
# Install all provided repositories
|
||||
for repo_url in "$@"; do
|
||||
install_node "${repo_url}"
|
||||
done
|
||||
|
||||
86
scripts/docker-entrypoint.sh
Executable file
86
scripts/docker-entrypoint.sh
Executable file
@ -0,0 +1,86 @@
|
||||
#!/bin/bash
|
||||
# Docker entrypoint script for ComfyUI
|
||||
# Handles virtual environment setup, dependency installation, custom nodes, and optional OTEL instrumentation
|
||||
|
||||
set -e
|
||||
|
||||
COMFYUI_DIR="/app/ComfyUI"
|
||||
VENV_DIR="/app/venv"
|
||||
WORKDIR="${COMFYUI_DIR}"
|
||||
CUSTOM_NODES_DIR="${COMFYUI_DIR}/custom_nodes"
|
||||
|
||||
cd "${WORKDIR}"
|
||||
|
||||
# Create virtual environment if it doesn't exist
|
||||
if [ ! -f "${VENV_DIR}/bin/activate" ]; then
|
||||
echo "Creating virtual environment..."
|
||||
python -m venv "${VENV_DIR}"
|
||||
fi
|
||||
|
||||
# Activate virtual environment
|
||||
source "${VENV_DIR}/bin/activate"
|
||||
|
||||
# Upgrade pip
|
||||
pip install --upgrade pip setuptools wheel
|
||||
|
||||
# Install PyTorch with CUDA 12.6 support
|
||||
echo "Installing PyTorch with CUDA 12.6..."
|
||||
pip install --no-cache-dir torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu126
|
||||
|
||||
# Install ComfyUI requirements (upgrade ensures packages match requirements.txt)
|
||||
echo "Installing ComfyUI requirements..."
|
||||
pip install --upgrade --no-cache-dir -r requirements.txt
|
||||
|
||||
# Install OpenTelemetry packages if OTEL endpoint is configured
|
||||
if [ -n "${OTEL_EXPORTER_OTLP_ENDPOINT}" ]; then
|
||||
echo "Installing OpenTelemetry packages..."
|
||||
pip install --no-cache-dir opentelemetry-distro opentelemetry-exporter-otlp
|
||||
fi
|
||||
|
||||
# Explicitly ensure frontend package matches requirements.txt version
|
||||
echo "Verifying frontend package version..."
|
||||
REQUIRED_FRONTEND_VERSION=$(grep "^comfyui-frontend-package==" requirements.txt | cut -d'=' -f3)
|
||||
if [ -n "$REQUIRED_FRONTEND_VERSION" ]; then
|
||||
echo "Installing frontend package version: $REQUIRED_FRONTEND_VERSION"
|
||||
pip install --upgrade --force-reinstall --no-cache-dir "comfyui-frontend-package==${REQUIRED_FRONTEND_VERSION}"
|
||||
else
|
||||
echo "Warning: Could not determine required frontend version from requirements.txt"
|
||||
fi
|
||||
|
||||
# Optional: Install curated custom nodes (can be enabled via environment variable)
|
||||
if [ "${INSTALL_CURATED_NODES:-false}" = "true" ]; then
|
||||
echo "Installing curated custom nodes..."
|
||||
export COMFYUI_DIR="${COMFYUI_DIR}"
|
||||
comfy-node-install \
|
||||
https://github.com/city96/ComfyUI-GGUF \
|
||||
https://github.com/rgthree/rgthree-comfy \
|
||||
https://github.com/ClownsharkBatwing/RES4LYF \
|
||||
https://github.com/giriss/comfy-image-saver || echo "Warning: Some custom nodes failed to install"
|
||||
fi
|
||||
|
||||
# Optional: Install Nano Banana node (can be enabled via environment variable)
|
||||
if [ "${INSTALL_NANO_BANANA:-false}" = "true" ]; then
|
||||
echo "Installing Nano Banana custom node..."
|
||||
export COMFYUI_DIR="${COMFYUI_DIR}"
|
||||
comfy-node-install https://github.com/ru4ls/ComfyUI_Nano_Banana || echo "Warning: Nano Banana clone failed"
|
||||
|
||||
# Install Nano Banana dependencies if requirements.txt exists
|
||||
if [ -f "${CUSTOM_NODES_DIR}/ComfyUI_Nano_Banana/requirements.txt" ]; then
|
||||
echo "Installing Nano Banana dependencies..."
|
||||
pip install --no-cache-dir -r "${CUSTOM_NODES_DIR}/ComfyUI_Nano_Banana/requirements.txt" || echo "Warning: Nano Banana dependencies installation failed"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check if OpenTelemetry endpoint is configured
|
||||
if [ -n "${OTEL_EXPORTER_OTLP_ENDPOINT}" ]; then
|
||||
echo "OpenTelemetry endpoint detected, enabling instrumentation..."
|
||||
exec opentelemetry-instrument \
|
||||
--traces_exporter otlp \
|
||||
--metrics_exporter otlp \
|
||||
--logs_exporter otlp \
|
||||
python main.py --listen 0.0.0.0 --port 8188 ${COMFYUI_ARGS:-} "$@"
|
||||
else
|
||||
echo "Starting ComfyUI without OpenTelemetry instrumentation..."
|
||||
exec python main.py --listen 0.0.0.0 --port 8188 ${COMFYUI_ARGS:-} "$@"
|
||||
fi
|
||||
|
||||
74
scripts/verify-env.sh
Executable file
74
scripts/verify-env.sh
Executable file
@ -0,0 +1,74 @@
|
||||
#!/bin/bash
|
||||
# Verification script to ensure .env file is properly loaded into container
|
||||
# This script verifies that GOOGLE_API_KEY is accessible in the ComfyUI container
|
||||
|
||||
set -e
|
||||
|
||||
echo "=== Environment Variable Verification ==="
|
||||
echo ""
|
||||
|
||||
# Check if .env file exists
|
||||
if [ ! -f ".env" ]; then
|
||||
echo "ERROR: .env file not found in current directory"
|
||||
exit 1
|
||||
fi
|
||||
echo "PASS: .env file exists"
|
||||
|
||||
# Check if GOOGLE_API_KEY is in .env file
|
||||
if ! grep -q "^GOOGLE_API_KEY=" .env; then
|
||||
echo "ERROR: GOOGLE_API_KEY not found in .env file"
|
||||
exit 1
|
||||
fi
|
||||
echo "PASS: GOOGLE_API_KEY found in .env file"
|
||||
|
||||
# Check docker-compose config
|
||||
echo ""
|
||||
echo "=== Docker Compose Configuration ==="
|
||||
if docker compose config 2>/dev/null | grep -q "GOOGLE_API_KEY"; then
|
||||
echo "PASS: GOOGLE_API_KEY found in docker-compose config"
|
||||
docker compose config | grep -A 2 "GOOGLE_API_KEY" | head -3
|
||||
else
|
||||
echo "ERROR: GOOGLE_API_KEY not found in docker-compose config"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if container is running
|
||||
if ! docker compose ps | grep -q "Up"; then
|
||||
echo ""
|
||||
echo "WARNING: Container is not running. Start it with: docker compose up -d"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "=== Container Environment Verification ==="
|
||||
|
||||
# Check environment variable in container
|
||||
if docker compose exec -T comfyui env | grep -q "GOOGLE_API_KEY="; then
|
||||
echo "PASS: GOOGLE_API_KEY is set in container environment"
|
||||
# Show first few characters for verification (don't expose full key)
|
||||
API_KEY_PREVIEW=$(docker compose exec -T comfyui env | grep "GOOGLE_API_KEY=" | cut -d'=' -f2 | cut -c1-10)
|
||||
echo " Preview: GOOGLE_API_KEY=${API_KEY_PREVIEW}..."
|
||||
else
|
||||
echo "ERROR: GOOGLE_API_KEY not found in container environment"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Verify Python can access it
|
||||
echo ""
|
||||
echo "=== Python Environment Access ==="
|
||||
if docker compose exec -T comfyui python -c "import os; key = os.environ.get('GOOGLE_API_KEY'); print('PASS: Python can access GOOGLE_API_KEY:', 'YES' if key else 'NO')" 2>/dev/null | grep -q "YES"; then
|
||||
echo "PASS: Python can access GOOGLE_API_KEY via os.environ"
|
||||
else
|
||||
echo "ERROR: Python cannot access GOOGLE_API_KEY"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "=== Verification Complete ==="
|
||||
echo "PASS: All checks passed! GOOGLE_API_KEY is properly configured."
|
||||
echo ""
|
||||
echo "To test Nano Banana authentication:"
|
||||
echo " 1. Ensure Nano Banana is installed in custom_nodes/"
|
||||
echo " 2. Access ComfyUI at http://localhost:8189"
|
||||
echo " 3. Check logs: docker compose logs comfyui | grep -i 'nano\|banana\|credentials'"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user