Compare commits
40
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9834dc0b25 | ||
|
|
1939ff4153 | ||
|
|
2b8272bd86 | ||
|
|
ccc9508664 | ||
|
|
b97e523e01 | ||
|
|
ec525e78ad | ||
|
|
4c32248d86 | ||
|
|
5ddbfdf44b | ||
|
|
5fcd43aa54 | ||
|
|
141d30aaa1 | ||
|
|
7e86c20383 | ||
|
|
3adf77617b | ||
|
|
1bc62a5fb4 | ||
|
|
d473a211d0 | ||
|
|
3aa239e58d | ||
|
|
223aa5e70b | ||
|
|
5eef60a4eb | ||
|
|
de750995cb | ||
|
|
0f58fbcebd | ||
|
|
6dc964c425 | ||
|
|
4171c08413 | ||
|
|
4348ab45dc | ||
|
|
df46e3a0e5 | ||
|
|
2772101bbf | ||
|
|
72fee51d32 | ||
|
|
ffe0f98360 | ||
|
|
68377a84bc | ||
|
|
50d4c399e9 | ||
|
|
5a3955dfcb | ||
|
|
03227b52c0 | ||
|
|
8a8fbccfaa | ||
|
|
018d9a7b8d | ||
|
|
774fd566d1 | ||
|
|
b81fcae6fb | ||
|
|
b6b34c9062 | ||
|
|
f73baa091a | ||
|
|
a838cb7ad4 | ||
|
|
2afcade4f2 | ||
|
|
d70333baa6 | ||
|
|
43cfebd97a |
@@ -12,11 +12,6 @@ RUN curl -L https://fly.io/install.sh | sh
|
|||||||
ENV FLYCTL_INSTALL="/root/.fly"
|
ENV FLYCTL_INSTALL="/root/.fly"
|
||||||
ENV PATH="$FLYCTL_INSTALL/bin:$PATH"
|
ENV PATH="$FLYCTL_INSTALL/bin:$PATH"
|
||||||
|
|
||||||
RUN sudo apt-get update
|
|
||||||
RUN sudo apt-get install python3-pip python3 -y
|
|
||||||
|
|
||||||
RUN pip3 install modal
|
|
||||||
|
|
||||||
# RUN echo 'export FLYCTL_INSTALL="/home/node/.fly"' >> ~/.bashrc
|
# RUN echo 'export FLYCTL_INSTALL="/home/node/.fly"' >> ~/.bashrc
|
||||||
# RUN echo 'export PATH="$FLYCTL_INSTALL/bin:$PATH"' >> ~/.bashrc
|
# RUN echo 'export PATH="$FLYCTL_INSTALL/bin:$PATH"' >> ~/.bashrc
|
||||||
|
|
||||||
|
|||||||
@@ -14,8 +14,7 @@
|
|||||||
"stivo.tailwind-fold",
|
"stivo.tailwind-fold",
|
||||||
"streetsidesoftware.code-spell-checker",
|
"streetsidesoftware.code-spell-checker",
|
||||||
"GitHub.copilot",
|
"GitHub.copilot",
|
||||||
"ms-azuretools.vscode-docker",
|
"ms-azuretools.vscode-docker"
|
||||||
"ms-python.python"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-2
@@ -1,3 +1,2 @@
|
|||||||
__pycache__
|
__pycache__
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.vercel
|
|
||||||
@@ -75,10 +75,11 @@ Major areas
|
|||||||
3. `bun i`
|
3. `bun i`
|
||||||
4. Start docker
|
4. Start docker
|
||||||
5. `cp .env.example .env.local`
|
5. `cp .env.example .env.local`
|
||||||
6. Repace `JWT_SECRET` with `openssl rand -hex 32`
|
6. Replace `JWT_SECRET` with `openssl rand -hex 32`
|
||||||
7. Get a local clerk dev key for `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY` and `CLERK_SECRET_KEY`
|
7. Get a local clerk dev key for `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY` and `CLERK_SECRET_KEY`
|
||||||
8. Keep a terminal live for `bun run db-dev`
|
8. Keep a terminal live for `bun run db-dev`
|
||||||
9. Finally start the next server with `bun dev`
|
9. Execute the local migration to create the initial data `bun run migrate-local`
|
||||||
|
10. Finally start the next server with `bun dev`
|
||||||
|
|
||||||
**Schema Changes**
|
**Schema Changes**
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
MODAL_TOKEN_ID=
|
MODAL_TOKEN_ID=
|
||||||
MODAL_TOKEN_SECRET=
|
MODAL_TOKEN_SECRET=
|
||||||
CIVITAI_API_KEY=
|
|
||||||
|
|
||||||
# On production set to False
|
# On production set to False
|
||||||
DEPLOY_TEST_FLAG=True
|
DEPLOY_TEST_FLAG=True
|
||||||
CIVITAI_API_KEY=
|
|
||||||
PUBLIC_MODEL_VOLUME_NAME=
|
|
||||||
@@ -13,4 +13,4 @@ RUN mkdir builds
|
|||||||
# CMD ["uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "80", "--lifespan", "on"]
|
# CMD ["uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "80", "--lifespan", "on"]
|
||||||
CMD ["python", "src/main.py"]
|
CMD ["python", "src/main.py"]
|
||||||
# If running behind a proxy like Nginx or Traefik add --proxy-headers
|
# If running behind a proxy like Nginx or Traefik add --proxy-headers
|
||||||
# CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80", "--proxy-headers"]
|
# CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80", "--proxy-headers"]
|
||||||
@@ -42,9 +42,6 @@ fly secrets set MODAL_TOKEN_SECRET=
|
|||||||
|
|
||||||
## To deploy
|
## To deploy
|
||||||
|
|
||||||
We have 2 `toml` files one for `production` and the other for `staging`
|
|
||||||
it will default to `staging` if you don't include the `-c` flag to choose your config file
|
|
||||||
|
|
||||||
```
|
```
|
||||||
// model-builder/fly.toml
|
// model-builder/fly.toml
|
||||||
app = <APP_NAME>
|
app = <APP_NAME>
|
||||||
@@ -56,5 +53,5 @@ fly launch
|
|||||||
```
|
```
|
||||||
if not, run this instead
|
if not, run this instead
|
||||||
```
|
```
|
||||||
fly deploy -c "toml file"
|
fly deploy
|
||||||
```
|
```
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
# fly.toml app configuration file generated for modal-builder on 2024-01-03T22:29:34+08:00
|
|
||||||
#
|
|
||||||
# See https://fly.io/docs/reference/configuration/ for information about how to use this file.
|
|
||||||
#
|
|
||||||
|
|
||||||
app = "modal-builder-production"
|
|
||||||
primary_region = "sea"
|
|
||||||
|
|
||||||
[build]
|
|
||||||
|
|
||||||
[http_service]
|
|
||||||
internal_port = 8080
|
|
||||||
force_https = true
|
|
||||||
auto_stop_machines = true
|
|
||||||
auto_start_machines = true
|
|
||||||
min_machines_running = 0
|
|
||||||
processes = ["app"]
|
|
||||||
|
|
||||||
[[vm]]
|
|
||||||
cpu_kind = 'shared'
|
|
||||||
cpus = 1
|
|
||||||
memory_mb = 1024
|
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
# fly.toml app configuration file generated for modal-builder-preview on 2024-01-25T09:26:31Z
|
# fly.toml app configuration file generated for modal-builder on 2024-01-03T22:29:34+08:00
|
||||||
#
|
#
|
||||||
# See https://fly.io/docs/reference/configuration/ for information about how to use this file.
|
# See https://fly.io/docs/reference/configuration/ for information about how to use this file.
|
||||||
#
|
#
|
||||||
|
|
||||||
app = 'modal-builder-preview'
|
app = "modal-builder"
|
||||||
primary_region = 'sea'
|
primary_region = "sea"
|
||||||
|
|
||||||
[build]
|
[build]
|
||||||
|
|
||||||
@@ -14,9 +14,4 @@ primary_region = 'sea'
|
|||||||
auto_stop_machines = true
|
auto_stop_machines = true
|
||||||
auto_start_machines = true
|
auto_start_machines = true
|
||||||
min_machines_running = 0
|
min_machines_running = 0
|
||||||
processes = ['app']
|
processes = ["app"]
|
||||||
|
|
||||||
[[vm]]
|
|
||||||
cpu_kind = 'shared'
|
|
||||||
cpus = 1
|
|
||||||
memory_mb = 1024
|
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ from enum import Enum
|
|||||||
import json
|
import json
|
||||||
import subprocess
|
import subprocess
|
||||||
import time
|
import time
|
||||||
from uuid import uuid4
|
|
||||||
from contextlib import asynccontextmanager
|
from contextlib import asynccontextmanager
|
||||||
import asyncio
|
import asyncio
|
||||||
import threading
|
import threading
|
||||||
@@ -19,7 +18,6 @@ import requests
|
|||||||
from urllib.parse import parse_qs
|
from urllib.parse import parse_qs
|
||||||
from starlette.middleware.base import BaseHTTPMiddleware
|
from starlette.middleware.base import BaseHTTPMiddleware
|
||||||
from starlette.types import ASGIApp, Scope, Receive, Send
|
from starlette.types import ASGIApp, Scope, Receive, Send
|
||||||
import modal
|
|
||||||
|
|
||||||
from concurrent.futures import ThreadPoolExecutor
|
from concurrent.futures import ThreadPoolExecutor
|
||||||
|
|
||||||
@@ -47,8 +45,6 @@ machine_id_websocket_dict = {}
|
|||||||
machine_id_status = {}
|
machine_id_status = {}
|
||||||
|
|
||||||
fly_instance_id = os.environ.get('FLY_ALLOC_ID', 'local').split('-')[0]
|
fly_instance_id = os.environ.get('FLY_ALLOC_ID', 'local').split('-')[0]
|
||||||
civitai_api_key = os.environ.get('FLY_ALLOC_ID', 'local')
|
|
||||||
public_model_volume_name = os.environ.get('PUBLIC_MODEL_VOLUME_NAME', 'local')
|
|
||||||
|
|
||||||
|
|
||||||
class FlyReplayMiddleware(BaseHTTPMiddleware):
|
class FlyReplayMiddleware(BaseHTTPMiddleware):
|
||||||
@@ -143,7 +139,6 @@ def read_root():
|
|||||||
class GitCustomNodes(BaseModel):
|
class GitCustomNodes(BaseModel):
|
||||||
hash: str
|
hash: str
|
||||||
disabled: bool
|
disabled: bool
|
||||||
pip: Optional[List[str]] = None
|
|
||||||
|
|
||||||
class FileCustomNodes(BaseModel):
|
class FileCustomNodes(BaseModel):
|
||||||
filename: str
|
filename: str
|
||||||
@@ -179,9 +174,6 @@ class Item(BaseModel):
|
|||||||
snapshot: Snapshot
|
snapshot: Snapshot
|
||||||
models: List[Model]
|
models: List[Model]
|
||||||
callback_url: str
|
callback_url: str
|
||||||
model_volume_name: str
|
|
||||||
run_timeout: Optional[int] = Field(default=60 * 5)
|
|
||||||
idle_timeout: Optional[int] = Field(default=60)
|
|
||||||
gpu: GPUType = Field(default=GPUType.T4)
|
gpu: GPUType = Field(default=GPUType.T4)
|
||||||
|
|
||||||
@field_validator('gpu')
|
@field_validator('gpu')
|
||||||
@@ -231,127 +223,6 @@ async def websocket_endpoint(websocket: WebSocket, machine_id: str):
|
|||||||
|
|
||||||
# return {"Hello": "World"}
|
# return {"Hello": "World"}
|
||||||
|
|
||||||
# definition based on web schema
|
|
||||||
class UploadType(str, Enum):
|
|
||||||
checkpoint = "checkpoint"
|
|
||||||
lora = "lora"
|
|
||||||
embedding = "embedding"
|
|
||||||
clip = "clip"
|
|
||||||
clip_vision = "clip_vision"
|
|
||||||
configs = "configs"
|
|
||||||
controlnet = "controlnet"
|
|
||||||
upscale_models = "upscale_models"
|
|
||||||
vae = "vae"
|
|
||||||
ipadapter = "ipadapter"
|
|
||||||
other = "other"
|
|
||||||
|
|
||||||
class UploadBody(BaseModel):
|
|
||||||
download_url: str
|
|
||||||
volume_name: str
|
|
||||||
volume_id: str
|
|
||||||
model_id: str
|
|
||||||
upload_type: UploadType
|
|
||||||
callback_url: str
|
|
||||||
|
|
||||||
|
|
||||||
# based on ComfyUI's model dir, and our mappings in ./src/template/data/extra_model_paths.yaml
|
|
||||||
UPLOAD_TYPE_DIR_MAP = {
|
|
||||||
UploadType.checkpoint: "checkpoints",
|
|
||||||
UploadType.lora: "loras",
|
|
||||||
UploadType.embedding: "embeddings",
|
|
||||||
UploadType.clip: "clip",
|
|
||||||
UploadType.clip_vision: "clip_vision",
|
|
||||||
UploadType.configs: "configs",
|
|
||||||
UploadType.controlnet: "controlnet",
|
|
||||||
UploadType.upscale_models: "upscale_models",
|
|
||||||
UploadType.vae: "vae",
|
|
||||||
UploadType.ipadapter: "ipadapter",
|
|
||||||
UploadType.other: "",
|
|
||||||
}
|
|
||||||
|
|
||||||
class DeleteBody(BaseModel):
|
|
||||||
volume_name: str
|
|
||||||
path: str
|
|
||||||
file_name: str
|
|
||||||
|
|
||||||
|
|
||||||
@app.post("/delete-volume-model")
|
|
||||||
async def delete_model(body: DeleteBody):
|
|
||||||
global last_activity_time
|
|
||||||
last_activity_time = time.time()
|
|
||||||
logger.info(f"Extended inactivity time to {global_timeout}")
|
|
||||||
|
|
||||||
full_path = f"{body.path.rstrip('/')}/{body.file_name}"
|
|
||||||
|
|
||||||
rm_process = await asyncio.subprocess.create_subprocess_exec("modal", "volume", "rm", body.volume_name, full_path,
|
|
||||||
stdout=asyncio.subprocess.PIPE,
|
|
||||||
stderr=asyncio.subprocess.PIPE,)
|
|
||||||
await rm_process.wait()
|
|
||||||
|
|
||||||
logger.info(f"Successfully deleted: {full_path} from volume: {body.volume_name}")
|
|
||||||
stdout, stderr = await rm_process.communicate()
|
|
||||||
if stdout:
|
|
||||||
logger.info(f"cp_process stdout: {stdout.decode()}")
|
|
||||||
if stderr:
|
|
||||||
logger.info(f"cp_process stderr: {stderr.decode()}")
|
|
||||||
|
|
||||||
if rm_process.returncode == 0:
|
|
||||||
return JSONResponse(status_code=200, content={"status":f"Successfully deleted {full_path} from volume {body.volume_name}"})
|
|
||||||
else:
|
|
||||||
return JSONResponse(status_code=500, content={"status": "error", "error": stderr.decode()})
|
|
||||||
|
|
||||||
@app.post("/upload-volume")
|
|
||||||
async def upload_model(body: UploadBody):
|
|
||||||
global last_activity_time
|
|
||||||
last_activity_time = time.time()
|
|
||||||
logger.info(f"Extended inactivity time to {global_timeout}")
|
|
||||||
|
|
||||||
asyncio.create_task(upload_logic(body))
|
|
||||||
|
|
||||||
# check that this
|
|
||||||
return JSONResponse(status_code=200, content={"message": "Volume uploading", "build_machine_instance_id": fly_instance_id})
|
|
||||||
|
|
||||||
|
|
||||||
async def upload_logic(body: UploadBody):
|
|
||||||
folder_path = f"/app/builds/{body.volume_id}-{uuid4()}"
|
|
||||||
|
|
||||||
cp_process = await asyncio.subprocess.create_subprocess_exec("cp", "-r", "/app/src/volume_builder", folder_path)
|
|
||||||
await cp_process.wait()
|
|
||||||
|
|
||||||
upload_path = UPLOAD_TYPE_DIR_MAP[body.upload_type]
|
|
||||||
if upload_path == "":
|
|
||||||
# TODO: deal with custom paths
|
|
||||||
pass
|
|
||||||
|
|
||||||
config = {
|
|
||||||
"volume_names": {
|
|
||||||
body.volume_name: {"download_url": body.download_url, "folder_path": upload_path}
|
|
||||||
},
|
|
||||||
"volume_paths": {
|
|
||||||
body.volume_name: f'/volumes/{uuid4()}'
|
|
||||||
},
|
|
||||||
"callback_url": body.callback_url,
|
|
||||||
"callback_body": {
|
|
||||||
"model_id": body.model_id,
|
|
||||||
"volume_id": body.volume_id,
|
|
||||||
"folder_path": upload_path,
|
|
||||||
},
|
|
||||||
"civitai_api_key": os.environ.get('CIVITAI_API_KEY'),
|
|
||||||
"app_name": f"vol_name_{uuid4()}"
|
|
||||||
}
|
|
||||||
with open(f"{folder_path}/config.py", "w") as f:
|
|
||||||
f.write("config = " + json.dumps(config))
|
|
||||||
|
|
||||||
process = await asyncio.subprocess.create_subprocess_shell(
|
|
||||||
f"python runner.py",
|
|
||||||
cwd=folder_path,
|
|
||||||
env={**os.environ, "COLUMNS": "10000"}
|
|
||||||
)
|
|
||||||
await process.wait()
|
|
||||||
|
|
||||||
# import modal
|
|
||||||
# modal.deploy_stub(stub)
|
|
||||||
# stub["download_model"].web_url
|
|
||||||
|
|
||||||
@app.post("/create")
|
@app.post("/create")
|
||||||
async def create_machine(item: Item):
|
async def create_machine(item: Item):
|
||||||
@@ -437,21 +308,12 @@ async def build_logic(item: Item):
|
|||||||
cp_process = await asyncio.subprocess.create_subprocess_exec("cp", "-r", "/app/src/template", folder_path)
|
cp_process = await asyncio.subprocess.create_subprocess_exec("cp", "-r", "/app/src/template", folder_path)
|
||||||
await cp_process.wait()
|
await cp_process.wait()
|
||||||
|
|
||||||
pip_modules = set()
|
|
||||||
for git_custom_node in item.snapshot.git_custom_nodes.values():
|
|
||||||
if git_custom_node.pip:
|
|
||||||
pip_modules.update(git_custom_node.pip)
|
|
||||||
|
|
||||||
# Write the config file
|
# Write the config file
|
||||||
config = {
|
config = {
|
||||||
"name": item.name,
|
"name": item.name,
|
||||||
"deploy_test": os.environ.get("DEPLOY_TEST_FLAG", "False"),
|
"deploy_test": os.environ.get("DEPLOY_TEST_FLAG", "False"),
|
||||||
"gpu": item.gpu,
|
"gpu": item.gpu,
|
||||||
"public_model_volume": public_model_volume_name,
|
"civitai_token": os.environ.get("CIVITAI_TOKEN", "")
|
||||||
"private_model_volume": item.model_volume_name,
|
|
||||||
"pip": list(pip_modules),
|
|
||||||
"run_timeout": item.run_timeout,
|
|
||||||
"idle_timeout": item.idle_timeout,
|
|
||||||
}
|
}
|
||||||
with open(f"{folder_path}/config.py", "w") as f:
|
with open(f"{folder_path}/config.py", "w") as f:
|
||||||
f.write("config = " + json.dumps(config))
|
f.write("config = " + json.dumps(config))
|
||||||
|
|||||||
@@ -1,16 +1,13 @@
|
|||||||
from config import config
|
from config import config
|
||||||
import modal
|
import modal
|
||||||
from modal import Image, Mount, web_endpoint, Stub, asgi_app, method, enter, exit
|
from modal import Image, Mount, web_endpoint, Stub, asgi_app
|
||||||
import json
|
import json
|
||||||
import urllib.request
|
import urllib.request
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from fastapi import FastAPI, Request, HTTPException
|
from fastapi import FastAPI, Request
|
||||||
from fastapi.responses import HTMLResponse
|
from fastapi.responses import HTMLResponse
|
||||||
from volume_setup import volumes
|
|
||||||
from datetime import datetime
|
|
||||||
import aiohttp
|
|
||||||
from aiohttp import TCPConnector
|
|
||||||
# deploy_test = False
|
# deploy_test = False
|
||||||
|
|
||||||
import os
|
import os
|
||||||
@@ -30,17 +27,18 @@ deploy_test = config["deploy_test"] == "True"
|
|||||||
web_app = FastAPI()
|
web_app = FastAPI()
|
||||||
print(config)
|
print(config)
|
||||||
print("deploy_test ", deploy_test)
|
print("deploy_test ", deploy_test)
|
||||||
print('volumes', volumes)
|
|
||||||
stub = Stub(name=config["name"])
|
stub = Stub(name=config["name"])
|
||||||
|
# print(stub.app_id)
|
||||||
|
|
||||||
if not deploy_test:
|
if not deploy_test:
|
||||||
# dockerfile_image = Image.from_dockerfile(f"{current_directory}/Dockerfile", context_mount=Mount.from_local_dir(f"{current_directory}/data", remote_path="/data"))
|
# dockerfile_image = Image.from_dockerfile(f"{current_directory}/Dockerfile", context_mount=Mount.from_local_dir(f"{current_directory}/data", remote_path="/data"))
|
||||||
# dockerfile_image = Image.from_dockerfile(f"{current_directory}/Dockerfile", context_mount=Mount.from_local_dir(f"{current_directory}/data", remote_path="/data"))
|
# dockerfile_image = Image.from_dockerfile(f"{current_directory}/Dockerfile", context_mount=Mount.from_local_dir(f"{current_directory}/data", remote_path="/data"))
|
||||||
|
|
||||||
dockerfile_image = (
|
dockerfile_image = (
|
||||||
modal.Image.debian_slim(
|
modal.Image.debian_slim()
|
||||||
python_version="3.11.1"
|
.env({
|
||||||
)
|
"CIVITAI_TOKEN": config["civitai_token"],
|
||||||
|
})
|
||||||
.apt_install("git", "wget")
|
.apt_install("git", "wget")
|
||||||
.pip_install(
|
.pip_install(
|
||||||
"git+https://github.com/modal-labs/asgiproxy.git", "httpx", "tqdm"
|
"git+https://github.com/modal-labs/asgiproxy.git", "httpx", "tqdm"
|
||||||
@@ -53,24 +51,20 @@ if not deploy_test:
|
|||||||
|
|
||||||
# Install comfyui manager
|
# Install comfyui manager
|
||||||
"cd /comfyui/custom_nodes && git clone https://github.com/ltdrdata/ComfyUI-Manager.git",
|
"cd /comfyui/custom_nodes && git clone https://github.com/ltdrdata/ComfyUI-Manager.git",
|
||||||
"cd /comfyui/custom_nodes/ComfyUI-Manager && git reset --hard 8dd801435bb75aa1d24b7e382bac070a4c18bc51",
|
"cd /comfyui/custom_nodes/ComfyUI-Manager && git reset --hard 9c86f62b912f4625fe2b929c7fc61deb9d16f6d3",
|
||||||
"cd /comfyui/custom_nodes/ComfyUI-Manager && pip install -r requirements.txt",
|
"cd /comfyui/custom_nodes/ComfyUI-Manager && pip install -r requirements.txt",
|
||||||
"cd /comfyui/custom_nodes/ComfyUI-Manager && mkdir startup-scripts",
|
"cd /comfyui/custom_nodes/ComfyUI-Manager && mkdir startup-scripts",
|
||||||
)
|
)
|
||||||
# .run_commands(f"cat /comfyui/server.py")
|
|
||||||
# .run_commands(f"ls /comfyui/app")
|
|
||||||
# .run_commands(
|
# .run_commands(
|
||||||
# # Install comfy deploy
|
# # Install comfy deploy
|
||||||
# "cd /comfyui/custom_nodes && git clone https://github.com/BennyKok/comfyui-deploy.git",
|
# "cd /comfyui/custom_nodes && git clone https://github.com/BennyKok/comfyui-deploy.git",
|
||||||
# )
|
# )
|
||||||
.copy_local_file(f"{current_directory}/data/extra_model_paths.yaml", "/comfyui")
|
# .copy_local_file(f"{current_directory}/data/extra_model_paths.yaml", "/comfyui")
|
||||||
|
|
||||||
.copy_local_file(f"{current_directory}/data/start.sh", "/start.sh")
|
.copy_local_file(f"{current_directory}/data/start.sh", "/start.sh")
|
||||||
.run_commands("chmod +x /start.sh")
|
.run_commands("chmod +x /start.sh")
|
||||||
|
|
||||||
# Restore the custom nodes first
|
# Restore the custom nodes first
|
||||||
.pip_install(config["pip"])
|
|
||||||
|
|
||||||
.copy_local_file(f"{current_directory}/data/restore_snapshot.py", "/")
|
.copy_local_file(f"{current_directory}/data/restore_snapshot.py", "/")
|
||||||
.copy_local_file(f"{current_directory}/data/snapshot.json", "/comfyui/custom_nodes/ComfyUI-Manager/startup-scripts/restore-snapshot.json")
|
.copy_local_file(f"{current_directory}/data/snapshot.json", "/comfyui/custom_nodes/ComfyUI-Manager/startup-scripts/restore-snapshot.json")
|
||||||
.run_commands("python restore_snapshot.py")
|
.run_commands("python restore_snapshot.py")
|
||||||
@@ -86,7 +80,7 @@ if not deploy_test:
|
|||||||
# Time to wait between API check attempts in milliseconds
|
# Time to wait between API check attempts in milliseconds
|
||||||
COMFY_API_AVAILABLE_INTERVAL_MS = 50
|
COMFY_API_AVAILABLE_INTERVAL_MS = 50
|
||||||
# Maximum number of API check attempts
|
# Maximum number of API check attempts
|
||||||
COMFY_API_AVAILABLE_MAX_RETRIES = 1000
|
COMFY_API_AVAILABLE_MAX_RETRIES = 500
|
||||||
# Time to wait between poll attempts in milliseconds
|
# Time to wait between poll attempts in milliseconds
|
||||||
COMFY_POLLING_INTERVAL_MS = 250
|
COMFY_POLLING_INTERVAL_MS = 250
|
||||||
# Maximum number of poll attempts
|
# Maximum number of poll attempts
|
||||||
@@ -95,34 +89,48 @@ COMFY_POLLING_MAX_RETRIES = 1000
|
|||||||
COMFY_HOST = "127.0.0.1:8188"
|
COMFY_HOST = "127.0.0.1:8188"
|
||||||
|
|
||||||
|
|
||||||
async def check_server(url, retries=50, delay=500):
|
def check_server(url, retries=50, delay=500):
|
||||||
import aiohttp
|
import requests
|
||||||
# for i in range(retries):
|
import time
|
||||||
while True:
|
"""
|
||||||
|
Check if a server is reachable via HTTP GET request
|
||||||
|
|
||||||
|
Args:
|
||||||
|
- url (str): The URL to check
|
||||||
|
- retries (int, optional): The number of times to attempt connecting to the server. Default is 50
|
||||||
|
- delay (int, optional): The time in milliseconds to wait between retries. Default is 500
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if the server is reachable within the given number of retries, otherwise False
|
||||||
|
"""
|
||||||
|
|
||||||
|
for i in range(retries):
|
||||||
try:
|
try:
|
||||||
async with aiohttp.ClientSession() as session:
|
response = requests.get(url)
|
||||||
async with session.get(url) as response:
|
|
||||||
# If the response status code is 200, the server is up and running
|
# If the response status code is 200, the server is up and running
|
||||||
if response.status == 200:
|
if response.status_code == 200:
|
||||||
print(f"comfy-modal - API is reachable")
|
print(f"runpod-worker-comfy - API is reachable")
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except requests.RequestException as e:
|
||||||
# If an exception occurs, the server may not be ready
|
# If an exception occurs, the server may not be ready
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# print(f"runpod-worker-comfy - trying")
|
||||||
|
|
||||||
# Wait for the specified delay before retrying
|
# Wait for the specified delay before retrying
|
||||||
await asyncio.sleep(delay / 1000)
|
time.sleep(delay / 1000)
|
||||||
|
|
||||||
print(
|
print(
|
||||||
f"comfy-modal - Failed to connect to server at {url} after {retries} attempts."
|
f"runpod-worker-comfy - Failed to connect to server at {url} after {retries} attempts."
|
||||||
)
|
)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
async def check_status(prompt_id):
|
def check_status(prompt_id):
|
||||||
async with aiohttp.ClientSession() as session:
|
req = urllib.request.Request(
|
||||||
async with session.get(f"http://{COMFY_HOST}/comfyui-deploy/check-status?prompt_id={prompt_id}") as response:
|
f"http://{COMFY_HOST}/comfyui-deploy/check-status?prompt_id={prompt_id}")
|
||||||
return await response.json()
|
return json.loads(urllib.request.urlopen(req).read())
|
||||||
|
|
||||||
|
|
||||||
class Input(BaseModel):
|
class Input(BaseModel):
|
||||||
@@ -132,12 +140,12 @@ class Input(BaseModel):
|
|||||||
file_upload_endpoint: str
|
file_upload_endpoint: str
|
||||||
|
|
||||||
|
|
||||||
async def queue_workflow_comfy_deploy(data: Input):
|
def queue_workflow_comfy_deploy(data: Input):
|
||||||
data_str = data.json()
|
data_str = data.json()
|
||||||
data_bytes = data_str.encode('utf-8')
|
data_bytes = data_str.encode('utf-8')
|
||||||
async with aiohttp.ClientSession() as session:
|
req = urllib.request.Request(
|
||||||
async with session.post(f"http://{COMFY_HOST}/comfyui-deploy/run", data=data_bytes) as response:
|
f"http://{COMFY_HOST}/comfyui-deploy/run", data=data_bytes)
|
||||||
return await response.json()
|
return json.loads(urllib.request.urlopen(req).read())
|
||||||
|
|
||||||
|
|
||||||
class RequestInput(BaseModel):
|
class RequestInput(BaseModel):
|
||||||
@@ -148,253 +156,90 @@ image = Image.debian_slim()
|
|||||||
|
|
||||||
target_image = image if deploy_test else dockerfile_image
|
target_image = image if deploy_test else dockerfile_image
|
||||||
|
|
||||||
run_timeout = config["run_timeout"]
|
|
||||||
idle_timeout = config["idle_timeout"]
|
|
||||||
|
|
||||||
import asyncio
|
@stub.function(image=target_image, gpu=config["gpu"])
|
||||||
|
def run(input: Input):
|
||||||
|
import subprocess
|
||||||
|
import time
|
||||||
|
# Make sure that the ComfyUI API is available
|
||||||
|
print(f"comfy-modal - check server")
|
||||||
|
|
||||||
@stub.cls(
|
command = ["python", "main.py",
|
||||||
image=target_image,
|
"--disable-auto-launch", "--disable-metadata"]
|
||||||
gpu=config["gpu"] ,
|
server_process = subprocess.Popen(command, cwd="/comfyui")
|
||||||
volumes=volumes,
|
|
||||||
timeout=(config["run_timeout"] + 20),
|
|
||||||
container_idle_timeout=config["idle_timeout"],
|
|
||||||
allow_concurrent_inputs=1,
|
|
||||||
)
|
|
||||||
class ComfyDeployRunner:
|
|
||||||
|
|
||||||
machine_logs = []
|
check_server(
|
||||||
|
f"http://{COMFY_HOST}",
|
||||||
|
COMFY_API_AVAILABLE_MAX_RETRIES,
|
||||||
|
COMFY_API_AVAILABLE_INTERVAL_MS,
|
||||||
|
)
|
||||||
|
|
||||||
async def read_stream(self, stream, isStderr):
|
job_input = input
|
||||||
import time
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
line = await stream.readline()
|
|
||||||
if line:
|
|
||||||
l = line.decode('utf-8').strip()
|
|
||||||
|
|
||||||
if l == "":
|
# print(f"comfy-modal - got input {job_input}")
|
||||||
continue
|
|
||||||
|
|
||||||
if not isStderr:
|
# Queue the workflow
|
||||||
print(l, flush=True)
|
try:
|
||||||
self.machine_logs.append({
|
# job_input is the json input
|
||||||
"logs": l,
|
queued_workflow = queue_workflow_comfy_deploy(
|
||||||
"timestamp": time.time()
|
job_input) # queue_workflow(workflow)
|
||||||
})
|
prompt_id = queued_workflow["prompt_id"]
|
||||||
|
print(f"comfy-modal - queued workflow with ID {prompt_id}")
|
||||||
|
except Exception as e:
|
||||||
|
import traceback
|
||||||
|
print(traceback.format_exc())
|
||||||
|
return {"error": f"Error queuing workflow: {str(e)}"}
|
||||||
|
|
||||||
else:
|
# Poll for completion
|
||||||
# is error
|
print(f"comfy-modal - wait until image generation is complete")
|
||||||
# logger.error(l)
|
retries = 0
|
||||||
print(l, flush=True)
|
status = ""
|
||||||
self.machine_logs.append({
|
try:
|
||||||
"logs": l,
|
print("getting request")
|
||||||
"timestamp": time.time()
|
while retries < COMFY_POLLING_MAX_RETRIES:
|
||||||
})
|
status_result = check_status(prompt_id=prompt_id)
|
||||||
else:
|
# history = get_history(prompt_id)
|
||||||
break
|
|
||||||
except asyncio.CancelledError:
|
|
||||||
# Handle the cancellation here if needed
|
|
||||||
break # Break out of the loop on cancellation
|
|
||||||
|
|
||||||
@enter()
|
# Exit the loop if we have found the history
|
||||||
async def setup(self):
|
# if prompt_id in history and history[prompt_id].get("outputs"):
|
||||||
import subprocess
|
# break
|
||||||
import time
|
|
||||||
|
|
||||||
# Make sure that the ComfyUI API is available
|
# Exit the loop if we have found the status both success or failed
|
||||||
print(f"comfy-modal - check server")
|
if 'status' in status_result and (status_result['status'] == 'success' or status_result['status'] == 'failed'):
|
||||||
|
status = status_result['status']
|
||||||
self.server_process = await asyncio.subprocess.create_subprocess_shell(
|
print(status)
|
||||||
f"python main.py --disable-auto-launch --disable-metadata",
|
break
|
||||||
stdout=asyncio.subprocess.PIPE,
|
else:
|
||||||
stderr=asyncio.subprocess.PIPE,
|
# Wait before trying again
|
||||||
cwd="/comfyui",
|
time.sleep(COMFY_POLLING_INTERVAL_MS / 1000)
|
||||||
# env={**os.environ, "COLUMNS": "10000"}
|
retries += 1
|
||||||
)
|
|
||||||
|
|
||||||
@exit()
|
|
||||||
async def cleanup(self, exc_type, exc_value, traceback):
|
|
||||||
print(f"comfy-modal - cleanup", exc_type, exc_value, traceback)
|
|
||||||
# Get the current event loop
|
|
||||||
loop = asyncio.get_event_loop()
|
|
||||||
|
|
||||||
# Check if the event loop is closed
|
|
||||||
if loop.is_closed():
|
|
||||||
print("The event loop is closed.")
|
|
||||||
else:
|
else:
|
||||||
try:
|
return {"error": "Max retries reached while waiting for image generation"}
|
||||||
self.server_process.terminate()
|
except Exception as e:
|
||||||
await self.server_process.wait()
|
return {"error": f"Error waiting for image generation: {str(e)}"}
|
||||||
except Exception as e:
|
|
||||||
print("Issues when cleaning up", e)
|
|
||||||
print("The event loop is open.")
|
|
||||||
|
|
||||||
@method()
|
print(f"comfy-modal - Finished, turning off")
|
||||||
async def run(self, input: Input):
|
server_process.terminate()
|
||||||
import signal
|
|
||||||
import time
|
|
||||||
import aiohttp
|
|
||||||
|
|
||||||
stdout_task = asyncio.create_task(
|
# Get the generated image and return it as URL in an AWS bucket or as base64
|
||||||
self.read_stream(self.server_process.stdout, False))
|
# images_result = process_output_images(history[prompt_id].get("outputs"), job["id"])
|
||||||
stderr_task = asyncio.create_task(
|
# result = {**images_result, "refresh_worker": REFRESH_WORKER}
|
||||||
self.read_stream(self.server_process.stderr, True))
|
result = {"status": status}
|
||||||
|
|
||||||
try:
|
|
||||||
class TimeoutError(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def timeout_handler(signum, frame):
|
return result
|
||||||
data = json.dumps({
|
print("Running remotely on Modal!")
|
||||||
"run_id": input.prompt_id,
|
|
||||||
"status": "timeout",
|
|
||||||
"time": datetime.now().isoformat()
|
|
||||||
}).encode('utf-8')
|
|
||||||
req = urllib.request.Request(input.status_endpoint, data=data, method='POST')
|
|
||||||
urllib.request.urlopen(req)
|
|
||||||
raise TimeoutError("Operation timed out")
|
|
||||||
|
|
||||||
signal.signal(signal.SIGALRM, timeout_handler)
|
|
||||||
|
|
||||||
try:
|
|
||||||
signal.alarm(run_timeout)
|
|
||||||
|
|
||||||
ok = await check_server(
|
|
||||||
f"http://{COMFY_HOST}",
|
|
||||||
COMFY_API_AVAILABLE_MAX_RETRIES,
|
|
||||||
COMFY_API_AVAILABLE_INTERVAL_MS,
|
|
||||||
)
|
|
||||||
|
|
||||||
if not ok:
|
|
||||||
raise Exception("ComfyUI API is not available")
|
|
||||||
# Set an alarm for some seconds in the future
|
|
||||||
|
|
||||||
data = json.dumps({
|
|
||||||
"run_id": input.prompt_id,
|
|
||||||
"status": "started",
|
|
||||||
"time": datetime.now().isoformat()
|
|
||||||
}).encode('utf-8')
|
|
||||||
async with aiohttp.ClientSession() as session:
|
|
||||||
async with session.post(input.status_endpoint, data=data) as response:
|
|
||||||
pass
|
|
||||||
|
|
||||||
job_input = input
|
|
||||||
|
|
||||||
try:
|
|
||||||
queued_workflow = await queue_workflow_comfy_deploy(job_input) # queue_workflow(workflow)
|
|
||||||
prompt_id = queued_workflow["prompt_id"]
|
|
||||||
print(f"comfy-modal - queued workflow with ID {prompt_id}")
|
|
||||||
except Exception as e:
|
|
||||||
import traceback
|
|
||||||
print(traceback.format_exc())
|
|
||||||
return {"error": f"Error queuing workflow: {str(e)}"}
|
|
||||||
|
|
||||||
# Poll for completion
|
|
||||||
print(f"comfy-modal - wait until image generation is complete")
|
|
||||||
retries = 0
|
|
||||||
status = ""
|
|
||||||
try:
|
|
||||||
print("getting request")
|
|
||||||
# while retries < COMFY_POLLING_MAX_RETRIES:
|
|
||||||
while True:
|
|
||||||
status_result = await check_status(prompt_id=prompt_id)
|
|
||||||
if 'status' in status_result and (status_result['status'] == 'success' or status_result['status'] == 'failed'):
|
|
||||||
status = status_result['status']
|
|
||||||
print(status)
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
# Wait before trying again
|
|
||||||
await asyncio.sleep(COMFY_POLLING_INTERVAL_MS / 1000)
|
|
||||||
retries += 1
|
|
||||||
else:
|
|
||||||
return {"error": "Max retries reached while waiting for image generation"}
|
|
||||||
except Exception as e:
|
|
||||||
return {"error": f"Error waiting for image generation: {str(e)}"}
|
|
||||||
|
|
||||||
print(f"comfy-modal - Finished, turning off")
|
|
||||||
|
|
||||||
result = {"status": status}
|
|
||||||
|
|
||||||
except TimeoutError:
|
|
||||||
print("Operation timed out")
|
|
||||||
return {"status": "failed"}
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Unexpected error occurred: {str(e)}")
|
|
||||||
data = json.dumps({
|
|
||||||
"run_id": input.prompt_id,
|
|
||||||
"status": "failed",
|
|
||||||
"time": datetime.now().isoformat()
|
|
||||||
}).encode('utf-8')
|
|
||||||
async with aiohttp.ClientSession() as session:
|
|
||||||
async with session.post(input.status_endpoint, data=data) as response:
|
|
||||||
print("response", response)
|
|
||||||
self.machine_logs.append({
|
|
||||||
"logs": str(e),
|
|
||||||
"timestamp": time.time()
|
|
||||||
})
|
|
||||||
finally:
|
|
||||||
signal.alarm(0)
|
|
||||||
|
|
||||||
print("uploading log_data")
|
|
||||||
data = json.dumps({
|
|
||||||
"run_id": input.prompt_id,
|
|
||||||
"time": datetime.now().isoformat(),
|
|
||||||
"log_data": self.machine_logs
|
|
||||||
}).encode('utf-8')
|
|
||||||
print("my logs", len(self.machine_logs))
|
|
||||||
# Clear logs
|
|
||||||
timeout = aiohttp.ClientTimeout(total=60) # 60 seconds total timeout
|
|
||||||
# Use HTTP/1.1 explicitly and increase the connection pool size
|
|
||||||
connector = TCPConnector(limit=100, force_close=True, enable_cleanup_closed=True)
|
|
||||||
|
|
||||||
async with aiohttp.ClientSession(timeout=timeout, connector=connector) as session:
|
|
||||||
try:
|
|
||||||
async with session.post(input.status_endpoint, data=data) as response:
|
|
||||||
print("response", response)
|
|
||||||
# Process your response here
|
|
||||||
except asyncio.TimeoutError:
|
|
||||||
print("Request timed out")
|
|
||||||
except Exception as e:
|
|
||||||
print(f"An error occurred: {e}")
|
|
||||||
print("uploaded log_data")
|
|
||||||
# print(data)
|
|
||||||
self.machine_logs = []
|
|
||||||
finally:
|
|
||||||
stdout_task.cancel()
|
|
||||||
stderr_task.cancel()
|
|
||||||
await stdout_task
|
|
||||||
await stderr_task
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@web_app.post("/run")
|
@web_app.post("/run")
|
||||||
async def post_run(request_input: RequestInput):
|
async def bar(request_input: RequestInput):
|
||||||
|
# print(request_input)
|
||||||
if not deploy_test:
|
if not deploy_test:
|
||||||
# print(request_input.input.prompt_id, request_input.input.status_endpoint)
|
run.spawn(request_input.input)
|
||||||
data = json.dumps({
|
return {"status": "success"}
|
||||||
"run_id": request_input.input.prompt_id,
|
# pass
|
||||||
"status": "queued",
|
|
||||||
"time": datetime.now().isoformat()
|
|
||||||
}).encode('utf-8')
|
|
||||||
req = urllib.request.Request(request_input.input.status_endpoint, data=data, method='POST')
|
|
||||||
urllib.request.urlopen(req)
|
|
||||||
|
|
||||||
model = ComfyDeployRunner()
|
|
||||||
call = await model.run.spawn.aio(request_input.input)
|
|
||||||
|
|
||||||
print("call", call)
|
@stub.function(image=image)
|
||||||
|
|
||||||
# call = run.spawn()
|
|
||||||
return {"call_id": None}
|
|
||||||
|
|
||||||
return {"call_id": None}
|
|
||||||
|
|
||||||
@stub.function(image=image
|
|
||||||
,volumes=volumes
|
|
||||||
)
|
|
||||||
@asgi_app()
|
@asgi_app()
|
||||||
def comfyui_api():
|
def comfyui_api():
|
||||||
return web_app
|
return web_app
|
||||||
@@ -444,7 +289,6 @@ def spawn_comfyui_in_background():
|
|||||||
# to be on a single container.
|
# to be on a single container.
|
||||||
concurrency_limit=1,
|
concurrency_limit=1,
|
||||||
timeout=10 * 60,
|
timeout=10 * 60,
|
||||||
volumes=volumes,
|
|
||||||
)
|
)
|
||||||
@asgi_app()
|
@asgi_app()
|
||||||
def comfyui_app():
|
def comfyui_app():
|
||||||
@@ -463,4 +307,4 @@ def comfyui_app():
|
|||||||
},
|
},
|
||||||
)()
|
)()
|
||||||
|
|
||||||
return make_simple_proxy_app(ProxyContext(config))
|
return make_simple_proxy_app(ProxyContext(config))
|
||||||
@@ -1,10 +1 @@
|
|||||||
config = {
|
config = {"name": "my-app", "deploy_test": "True", "gpu": "T4"}
|
||||||
"name": "my-app",
|
|
||||||
"deploy_test": "False",
|
|
||||||
"gpu": "T4",
|
|
||||||
"public_model_volume": "model-store",
|
|
||||||
"private_model_volume": "private-model-store",
|
|
||||||
"pip": [],
|
|
||||||
"run_timeout": 60 * 5,
|
|
||||||
"idle_timeout": 60
|
|
||||||
}
|
|
||||||
@@ -1,26 +1,11 @@
|
|||||||
public:
|
comfyui:
|
||||||
base_path: /public_models/
|
base_path: /runpod-volume/ComfyUI/
|
||||||
checkpoints: checkpoints
|
checkpoints: models/checkpoints/
|
||||||
clip: clip
|
clip: models/clip/
|
||||||
clip_vision: clip_vision
|
clip_vision: models/clip_vision/
|
||||||
configs: configs
|
configs: models/configs/
|
||||||
controlnet: controlnet
|
controlnet: models/controlnet/
|
||||||
embeddings: embeddings
|
embeddings: models/embeddings/
|
||||||
loras: loras
|
loras: models/loras/
|
||||||
upscale_models: upscale_models
|
upscale_models: models/upscale_models/
|
||||||
vae: vae
|
vae: models/vae/
|
||||||
ipadapter: ipadapter
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
|
||||||
base_path: /private_models/
|
|
||||||
checkpoints: checkpoints
|
|
||||||
clip: clip
|
|
||||||
clip_vision: clip_vision
|
|
||||||
configs: configs
|
|
||||||
controlnet: controlnet
|
|
||||||
embeddings: embeddings
|
|
||||||
loras: loras
|
|
||||||
upscale_models: upscale_models
|
|
||||||
vae: vae
|
|
||||||
ipadapter: ipadapter
|
|
||||||
@@ -49,9 +49,15 @@ with open('models.json') as f:
|
|||||||
models = json.load(f)
|
models = json.load(f)
|
||||||
|
|
||||||
for model in models:
|
for model in models:
|
||||||
|
import os
|
||||||
|
if "civitai.com/api" in model['url'] and not "token=" in model['url']:
|
||||||
|
if "?" in model['url']:
|
||||||
|
model['url'] += "&token=" + os.environ.get('CIVITAI_TOKEN', '')
|
||||||
|
else:
|
||||||
|
model['url'] += "?token=" + os.environ.get('CIVITAI_TOKEN', '')
|
||||||
response = requests.request("POST", f"{root_url}/model/install", json=model, headers=headers)
|
response = requests.request("POST", f"{root_url}/model/install", json=model, headers=headers)
|
||||||
print(response.text)
|
print(response.text)
|
||||||
|
|
||||||
# Close the server
|
# Close the server
|
||||||
server_process.terminate()
|
server_process.terminate()
|
||||||
print("Finished installing dependencies.")
|
print("Finished installing dependencies.")
|
||||||
@@ -1,10 +1,5 @@
|
|||||||
{
|
{
|
||||||
"comfyui": "d0165d819afe76bd4e6bdd710eb5f3e571b6a804",
|
"comfyui": "d0165d819afe76bd4e6bdd710eb5f3e571b6a804",
|
||||||
"git_custom_nodes": {
|
"git_custom_nodes": {},
|
||||||
"https://github.com/BennyKok/comfyui-deploy.git": {
|
"file_custom_nodes": []
|
||||||
"hash": "df46e3a0e5ad93fa71f5d216997e376af33b2a6d",
|
}
|
||||||
"disabled": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"file_custom_nodes": []
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
import modal
|
|
||||||
from config import config
|
|
||||||
|
|
||||||
public_model_volume = modal.Volume.persisted(config["public_model_volume"])
|
|
||||||
private_volume = modal.Volume.persisted(config["private_model_volume"])
|
|
||||||
|
|
||||||
PUBLIC_BASEMODEL_DIR = "/public_models"
|
|
||||||
PRIVATE_BASEMODEL_DIR = "/private_models"
|
|
||||||
volumes = {PUBLIC_BASEMODEL_DIR: public_model_volume, PRIVATE_BASEMODEL_DIR: private_volume}
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
from fastapi import FastAPI, Request
|
|
||||||
from fastapi.responses import HTMLResponse
|
|
||||||
import modal
|
|
||||||
from config import config
|
|
||||||
import os
|
|
||||||
import subprocess
|
|
||||||
from pprint import pprint
|
|
||||||
|
|
||||||
stub = modal.Stub(config["app_name"])
|
|
||||||
vol_name_to_links = config["volume_names"]
|
|
||||||
vol_name_to_path = config["volume_paths"]
|
|
||||||
callback_url = config["callback_url"]
|
|
||||||
callback_body = config["callback_body"]
|
|
||||||
civitai_key = config["civitai_api_key"]
|
|
||||||
web_app = FastAPI()
|
|
||||||
|
|
||||||
# Volume names may only contain alphanumeric characters, dashes, periods, and underscores, and must be less than 64 characters in length.
|
|
||||||
def is_valid_name(name: str) -> bool:
|
|
||||||
allowed_characters = set("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._")
|
|
||||||
return 0 < len(name) <= 64 and all(char in allowed_characters for char in name)
|
|
||||||
|
|
||||||
def create_volumes(volume_names, paths):
|
|
||||||
path_to_vol = {}
|
|
||||||
for volume_name in volume_names.keys():
|
|
||||||
if not is_valid_name(volume_name):
|
|
||||||
pass
|
|
||||||
modal_volume = modal.Volume.persisted(volume_name)
|
|
||||||
path_to_vol[paths[volume_name]] = modal_volume
|
|
||||||
|
|
||||||
return path_to_vol
|
|
||||||
|
|
||||||
volumes = create_volumes(vol_name_to_links, vol_name_to_path)
|
|
||||||
image = (
|
|
||||||
modal.Image.debian_slim().apt_install("wget").pip_install("requests")
|
|
||||||
)
|
|
||||||
|
|
||||||
# download config { "download_url": "", "folder_path": ""}
|
|
||||||
timeout=5000
|
|
||||||
@stub.function(volumes=volumes, image=image, timeout=timeout, gpu=None)
|
|
||||||
def download_model(volume_name, download_config):
|
|
||||||
import requests
|
|
||||||
download_url = download_config["download_url"]
|
|
||||||
folder_path = download_config["folder_path"]
|
|
||||||
|
|
||||||
volume_base_path = vol_name_to_path[volume_name]
|
|
||||||
model_store_path = os.path.join(volume_base_path, folder_path)
|
|
||||||
modified_download_url = download_url + ("&" if "?" in download_url else "?") + "token=" + civitai_key # civitai requires auth
|
|
||||||
print('downloading', modified_download_url)
|
|
||||||
|
|
||||||
subprocess.run(["wget", modified_download_url , "--content-disposition", "-P", model_store_path, "-nv"])
|
|
||||||
subprocess.run(["ls", "-la", volume_base_path])
|
|
||||||
subprocess.run(["ls", "-la", model_store_path])
|
|
||||||
volumes[volume_base_path].commit()
|
|
||||||
|
|
||||||
|
|
||||||
status = {"status": "success"}
|
|
||||||
requests.post(callback_url, json={**status, **callback_body})
|
|
||||||
print(f"finished! sending to {callback_url}")
|
|
||||||
pprint({**status, **callback_body})
|
|
||||||
|
|
||||||
@stub.function(image=image)
|
|
||||||
# @modal.asgi_app()
|
|
||||||
def simple_download():
|
|
||||||
import requests
|
|
||||||
try:
|
|
||||||
list(download_model.starmap([(vol_name, download_conf) for vol_name,download_conf in vol_name_to_links.items()]))
|
|
||||||
except modal.exception.FunctionTimeoutError as e:
|
|
||||||
status = {"status": "failed", "error_logs": f"{str(e)}", "timeout": timeout}
|
|
||||||
requests.post(callback_url, json={**status, **callback_body})
|
|
||||||
print(f"finished! sending to {callback_url}")
|
|
||||||
pprint({**status, **callback_body})
|
|
||||||
except Exception as e:
|
|
||||||
status = {"status": "failed", "error_logs": str(e)}
|
|
||||||
requests.post(callback_url, json={**status, **callback_body})
|
|
||||||
print(f"finished! sending to {callback_url}")
|
|
||||||
pprint({**status, **callback_body})
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
config = {
|
|
||||||
"volume_names": {
|
|
||||||
"user4": {
|
|
||||||
"download_url": "https://civitai.com/api/download/models/11745",
|
|
||||||
"folder_path": "checkpoints"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"volume_paths": {
|
|
||||||
"user4": "/volumes/something",
|
|
||||||
},
|
|
||||||
"callback_url": "",
|
|
||||||
"callback_body": {
|
|
||||||
"model_id": "",
|
|
||||||
"volume_id": "",
|
|
||||||
"folder_path": "checkpoints",
|
|
||||||
},
|
|
||||||
"civitai_api_key": "",
|
|
||||||
"app_name": "",
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
import modal
|
|
||||||
import requests
|
|
||||||
from app import stub
|
|
||||||
from config import config
|
|
||||||
|
|
||||||
modal.runner.deploy_stub(stub)
|
|
||||||
print("deployed stub")
|
|
||||||
# web_url = stub["simple_download"].web_url
|
|
||||||
f = modal.Function.lookup(config['app_name'], "simple_download")
|
|
||||||
f.spawn()
|
|
||||||
# print(f"web_url: {web_url}")
|
|
||||||
# requests.post(web_url)
|
|
||||||
@@ -29,9 +29,7 @@ class ComfyUIDeployExternalText:
|
|||||||
CATEGORY = "text"
|
CATEGORY = "text"
|
||||||
|
|
||||||
def run(self, input_id, default_value=None):
|
def run(self, input_id, default_value=None):
|
||||||
if not input_id or len(input_id.strip()) == 0:
|
return [default_value]
|
||||||
return [default_value]
|
|
||||||
return [input_id]
|
|
||||||
|
|
||||||
|
|
||||||
NODE_CLASS_MAPPINGS = {"ComfyUIDeployExternalText": ComfyUIDeployExternalText}
|
NODE_CLASS_MAPPINGS = {"ComfyUIDeployExternalText": ComfyUIDeployExternalText}
|
||||||
|
|||||||
+165
-1
@@ -22,6 +22,8 @@ from logging.handlers import RotatingFileHandler
|
|||||||
from enum import Enum
|
from enum import Enum
|
||||||
from urllib.parse import quote
|
from urllib.parse import quote
|
||||||
import threading
|
import threading
|
||||||
|
import hashlib
|
||||||
|
import aiohttp
|
||||||
|
|
||||||
api = None
|
api = None
|
||||||
api_task = None
|
api_task = None
|
||||||
@@ -99,6 +101,7 @@ async def comfy_deploy_run(request):
|
|||||||
prompt_metadata[prompt_id] = {
|
prompt_metadata[prompt_id] = {
|
||||||
'status_endpoint': data.get('status_endpoint'),
|
'status_endpoint': data.get('status_endpoint'),
|
||||||
'file_upload_endpoint': data.get('file_upload_endpoint'),
|
'file_upload_endpoint': data.get('file_upload_endpoint'),
|
||||||
|
'workflow_api': workflow_api
|
||||||
}
|
}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -115,6 +118,8 @@ async def comfy_deploy_run(request):
|
|||||||
"stack_trace": stack_trace
|
"stack_trace": stack_trace
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
# When there are critical errors, the prompt is actually not run
|
||||||
|
await update_run(prompt_id, Status.FAILED)
|
||||||
return web.Response(status=500, reason=f"{error_type}: {e}, {stack_trace_short}")
|
return web.Response(status=500, reason=f"{error_type}: {e}, {stack_trace_short}")
|
||||||
|
|
||||||
status = 200
|
status = 200
|
||||||
@@ -143,6 +148,138 @@ async def comfy_deploy_run(request):
|
|||||||
|
|
||||||
sockets = dict()
|
sockets = dict()
|
||||||
|
|
||||||
|
def get_comfyui_path_from_file_path(file_path):
|
||||||
|
file_path_parts = file_path.split("\\")
|
||||||
|
|
||||||
|
if file_path_parts[0] == "input":
|
||||||
|
print("matching input")
|
||||||
|
file_path = os.path.join(folder_paths.get_directory_by_type("input"), *file_path_parts[1:])
|
||||||
|
elif file_path_parts[0] == "models":
|
||||||
|
print("matching models")
|
||||||
|
file_path = folder_paths.get_full_path(file_path_parts[1], os.path.join(*file_path_parts[2:]))
|
||||||
|
|
||||||
|
print(file_path)
|
||||||
|
|
||||||
|
return file_path
|
||||||
|
|
||||||
|
# Form ComfyUI Manager
|
||||||
|
def compute_sha256_checksum(filepath):
|
||||||
|
filepath = get_comfyui_path_from_file_path(filepath)
|
||||||
|
"""Compute the SHA256 checksum of a file, in chunks"""
|
||||||
|
sha256 = hashlib.sha256()
|
||||||
|
with open(filepath, 'rb') as f:
|
||||||
|
for chunk in iter(lambda: f.read(4096), b''):
|
||||||
|
sha256.update(chunk)
|
||||||
|
return sha256.hexdigest()
|
||||||
|
|
||||||
|
# This is start uploading the files to Comfy Deploy
|
||||||
|
@server.PromptServer.instance.routes.post('/comfyui-deploy/upload-file')
|
||||||
|
async def upload_file(request):
|
||||||
|
data = await request.json()
|
||||||
|
|
||||||
|
file_path = data.get("file_path")
|
||||||
|
|
||||||
|
print("Original file path", file_path)
|
||||||
|
|
||||||
|
file_path = get_comfyui_path_from_file_path(file_path)
|
||||||
|
|
||||||
|
# return web.json_response({
|
||||||
|
# "error": f"File not uploaded"
|
||||||
|
# }, status=500)
|
||||||
|
|
||||||
|
token = data.get("token")
|
||||||
|
get_url = data.get("url")
|
||||||
|
|
||||||
|
try:
|
||||||
|
base = folder_paths.base_path
|
||||||
|
file_path = os.path.join(base, file_path)
|
||||||
|
|
||||||
|
if os.path.exists(file_path):
|
||||||
|
file_size = os.path.getsize(file_path)
|
||||||
|
file_extension = os.path.splitext(file_path)[1]
|
||||||
|
|
||||||
|
if file_extension in ['.jpg', '.jpeg']:
|
||||||
|
file_type = 'image/jpeg'
|
||||||
|
elif file_extension == '.png':
|
||||||
|
file_type = 'image/png'
|
||||||
|
elif file_extension == '.webp':
|
||||||
|
file_type = 'image/webp'
|
||||||
|
else:
|
||||||
|
file_type = 'application/octet-stream' # Default to binary file type if unknown
|
||||||
|
else:
|
||||||
|
return web.json_response({
|
||||||
|
"error": f"File not found: {file_path}"
|
||||||
|
}, status=404)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
return web.json_response({
|
||||||
|
"error": str(e)
|
||||||
|
}, status=500)
|
||||||
|
|
||||||
|
if get_url:
|
||||||
|
try:
|
||||||
|
async with aiohttp.ClientSession() as session:
|
||||||
|
headers = {'Authorization': f'Bearer {token}'}
|
||||||
|
params = {'file_size': file_size, 'type': file_type}
|
||||||
|
async with session.get(get_url, params=params, headers=headers) as response:
|
||||||
|
if response.status == 200:
|
||||||
|
content = await response.json()
|
||||||
|
upload_url = content["upload_url"]
|
||||||
|
|
||||||
|
with open(file_path, 'rb') as f:
|
||||||
|
headers = {
|
||||||
|
"Content-Type": file_type,
|
||||||
|
"x-amz-acl": "public-read",
|
||||||
|
"Content-Length": str(file_size)
|
||||||
|
}
|
||||||
|
async with session.put(upload_url, data=f, headers=headers) as upload_response:
|
||||||
|
if upload_response.status == 200:
|
||||||
|
return web.json_response({
|
||||||
|
"message": "File uploaded successfully",
|
||||||
|
"download_url": content["download_url"]
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
return web.json_response({
|
||||||
|
"error": f"Failed to upload file to {upload_url}. Status code: {upload_response.status}"
|
||||||
|
}, status=upload_response.status)
|
||||||
|
else:
|
||||||
|
return web.json_response({
|
||||||
|
"error": f"Failed to fetch data from {get_url}. Status code: {response.status}"
|
||||||
|
}, status=response.status)
|
||||||
|
except Exception as e:
|
||||||
|
return web.json_response({
|
||||||
|
"error": f"An error occurred while fetching data from {get_url}: {str(e)}"
|
||||||
|
}, status=500)
|
||||||
|
|
||||||
|
return web.json_response({
|
||||||
|
"error": f"File not uploaded"
|
||||||
|
}, status=500)
|
||||||
|
|
||||||
|
|
||||||
|
@server.PromptServer.instance.routes.get('/comfyui-deploy/get-file-hash')
|
||||||
|
async def get_file_hash(request):
|
||||||
|
file_path = request.rel_url.query.get('file_path', '')
|
||||||
|
|
||||||
|
if file_path is None:
|
||||||
|
return web.json_response({
|
||||||
|
"error": "file_path is required"
|
||||||
|
}, status=400)
|
||||||
|
|
||||||
|
try:
|
||||||
|
base = folder_paths.base_path
|
||||||
|
file_path = os.path.join(base, file_path)
|
||||||
|
# print("file_path", file_path)
|
||||||
|
file_hash = compute_sha256_checksum(
|
||||||
|
file_path
|
||||||
|
)
|
||||||
|
return web.json_response({
|
||||||
|
"file_hash": file_hash
|
||||||
|
})
|
||||||
|
except Exception as e:
|
||||||
|
return web.json_response({
|
||||||
|
"error": str(e)
|
||||||
|
}, status=500)
|
||||||
|
|
||||||
@server.PromptServer.instance.routes.get('/comfyui-deploy/ws')
|
@server.PromptServer.instance.routes.get('/comfyui-deploy/ws')
|
||||||
async def websocket_handler(request):
|
async def websocket_handler(request):
|
||||||
ws = web.WebSocketResponse()
|
ws = web.WebSocketResponse()
|
||||||
@@ -221,6 +358,17 @@ async def send_json_override(self, event, data, sid=None):
|
|||||||
if not have_pending_upload(prompt_id):
|
if not have_pending_upload(prompt_id):
|
||||||
update_run(prompt_id, Status.SUCCESS)
|
update_run(prompt_id, Status.SUCCESS)
|
||||||
|
|
||||||
|
if event == 'executing' and data.get('node') is not None:
|
||||||
|
node = data.get('node')
|
||||||
|
|
||||||
|
if 'prompt_id' in prompt_metadata:
|
||||||
|
if 'last_updated_node' in prompt_metadata[prompt_id] and prompt_metadata[prompt_id]['last_updated_node'] == node:
|
||||||
|
return
|
||||||
|
prompt_metadata[prompt_id]['last_updated_node'] = node
|
||||||
|
class_type = prompt_metadata[prompt_id]['workflow_api'][node]['class_type']
|
||||||
|
print("updating run live status", class_type)
|
||||||
|
await update_run_live_status(prompt_id, "Executing " + class_type)
|
||||||
|
|
||||||
if event == 'execution_error':
|
if event == 'execution_error':
|
||||||
# Careful this might not be fully awaited.
|
# Careful this might not be fully awaited.
|
||||||
await update_run_with_output(prompt_id, data)
|
await update_run_with_output(prompt_id, data)
|
||||||
@@ -243,6 +391,20 @@ class Status(Enum):
|
|||||||
# Global variable to keep track of the last read line number
|
# Global variable to keep track of the last read line number
|
||||||
last_read_line_number = 0
|
last_read_line_number = 0
|
||||||
|
|
||||||
|
async def update_run_live_status(prompt_id, live_status):
|
||||||
|
if prompt_id not in prompt_metadata:
|
||||||
|
return
|
||||||
|
|
||||||
|
status_endpoint = prompt_metadata[prompt_id]['status_endpoint']
|
||||||
|
body = {
|
||||||
|
"run_id": prompt_id,
|
||||||
|
"live_status": live_status,
|
||||||
|
}
|
||||||
|
# requests.post(status_endpoint, json=body)
|
||||||
|
async with aiohttp.ClientSession() as session:
|
||||||
|
await session.post(status_endpoint, json=body)
|
||||||
|
|
||||||
|
|
||||||
def update_run(prompt_id, status: Status):
|
def update_run(prompt_id, status: Status):
|
||||||
global last_read_line_number
|
global last_read_line_number
|
||||||
|
|
||||||
@@ -353,7 +515,9 @@ async def upload_file(prompt_id, filename, subfolder=None, content_type="image/p
|
|||||||
"Content-Length": str(len(data)),
|
"Content-Length": str(len(data)),
|
||||||
}
|
}
|
||||||
response = requests.put(ok.get("url"), headers=headers, data=data)
|
response = requests.put(ok.get("url"), headers=headers, data=data)
|
||||||
print("upload file response", response.status_code)
|
async with aiohttp.ClientSession() as session:
|
||||||
|
async with session.put(ok.get("url"), headers=headers, data=data) as response:
|
||||||
|
print("upload file response", response.status)
|
||||||
|
|
||||||
def have_pending_upload(prompt_id):
|
def have_pending_upload(prompt_id):
|
||||||
if 'prompt_id' in prompt_metadata and 'uploading_nodes' in prompt_metadata[prompt_id] and len(prompt_metadata[prompt_id]['uploading_nodes']) > 0:
|
if 'prompt_id' in prompt_metadata and 'uploading_nodes' in prompt_metadata[prompt_id] and len(prompt_metadata[prompt_id]['uploading_nodes']) > 0:
|
||||||
|
|||||||
+199
-20
@@ -1,6 +1,7 @@
|
|||||||
import { app } from "./app.js";
|
import { app } from "./app.js";
|
||||||
import { api } from "./api.js";
|
import { api } from "./api.js";
|
||||||
import { ComfyWidgets, LGraphNode } from "./widgets.js";
|
import { ComfyWidgets, LGraphNode } from "./widgets.js";
|
||||||
|
import { generateDependencyGraph } from "https://esm.sh/[email protected]";
|
||||||
|
|
||||||
/** @typedef {import('../../../web/types/comfy.js').ComfyExtension} ComfyExtension*/
|
/** @typedef {import('../../../web/types/comfy.js').ComfyExtension} ComfyExtension*/
|
||||||
/** @type {ComfyExtension} */
|
/** @type {ComfyExtension} */
|
||||||
@@ -178,6 +179,92 @@ function showError(title, message) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createDynamicUIHtml(data) {
|
||||||
|
console.log(data);
|
||||||
|
let html =
|
||||||
|
'<div style="max-width: 1024px; margin: 14px auto; display: flex; flex-direction: column; gap: 24px;">';
|
||||||
|
const bgcolor = "var(--comfy-input-bg)";
|
||||||
|
const evenBg = "var(--border-color)";
|
||||||
|
const textColor = "var(--input-text)";
|
||||||
|
|
||||||
|
// Custom Nodes
|
||||||
|
html += `<div style="background-color: ${bgcolor}; padding: 24px; border-radius: 8px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);">`;
|
||||||
|
html +=
|
||||||
|
'<h2 style="margin-top: 0px; font-size: 24px; font-weight: bold; margin-bottom: 16px;">Custom Nodes</h2>';
|
||||||
|
|
||||||
|
if (data.missing_nodes?.length > 0) {
|
||||||
|
html += `
|
||||||
|
<div style="border-bottom: 1px solid #e2e8f0; padding: 4px 12px; background-color: ${evenBg}">
|
||||||
|
<h3 style="font-size: 14px; font-weight: semibold; margin-bottom: 8px;">Missing Nodes</h3>
|
||||||
|
<p style="font-size: 12px;">These nodes are not found with any matching custom_nodes in the ComfyUI Manager Database</p>
|
||||||
|
${data.missing_nodes
|
||||||
|
.map((node) => {
|
||||||
|
return `<p style="font-size: 14px; color: #d69e2e;">${node}</p>`;
|
||||||
|
})
|
||||||
|
.join("")}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.values(data.custom_nodes).forEach((node) => {
|
||||||
|
html += `
|
||||||
|
<div style="border-bottom: 1px solid #e2e8f0; padding-top: 16px;">
|
||||||
|
<a href="${
|
||||||
|
node.url
|
||||||
|
}" target="_blank" style="font-size: 18px; font-weight: semibold; color: white; text-decoration: none;">${
|
||||||
|
node.name
|
||||||
|
}</a>
|
||||||
|
<p style="font-size: 14px; color: #4b5563;">${node.hash}</p>
|
||||||
|
${
|
||||||
|
node.warning
|
||||||
|
? `<p style="font-size: 14px; color: #d69e2e;">${node.warning}</p>`
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
});
|
||||||
|
html += "</div>";
|
||||||
|
|
||||||
|
// Models
|
||||||
|
html += `<div style="background-color: ${bgcolor}; padding: 24px; border-radius: 8px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);">`;
|
||||||
|
html +=
|
||||||
|
'<h2 style="margin-top: 0px; font-size: 24px; font-weight: bold; margin-bottom: 16px;">Models</h2>';
|
||||||
|
|
||||||
|
Object.entries(data.models).forEach(([section, items]) => {
|
||||||
|
html += `
|
||||||
|
<div style="border-bottom: 1px solid #e2e8f0; padding-top: 8px; padding-bottom: 8px;">
|
||||||
|
<h3 style="font-size: 18px; font-weight: semibold; margin-bottom: 8px;">${
|
||||||
|
section.charAt(0).toUpperCase() + section.slice(1)
|
||||||
|
}</h3>`;
|
||||||
|
items.forEach((item) => {
|
||||||
|
html += `<p style="font-size: 14px; color: ${textColor};">${item.name}</p>`;
|
||||||
|
});
|
||||||
|
html += "</div>";
|
||||||
|
});
|
||||||
|
html += "</div>";
|
||||||
|
|
||||||
|
// Models
|
||||||
|
html += `<div style="background-color: ${bgcolor}; padding: 24px; border-radius: 8px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);">`;
|
||||||
|
html +=
|
||||||
|
'<h2 style="margin-top: 0px; font-size: 24px; font-weight: bold; margin-bottom: 16px;">Files</h2>';
|
||||||
|
|
||||||
|
Object.entries(data.files).forEach(([section, items]) => {
|
||||||
|
html += `
|
||||||
|
<div style="border-bottom: 1px solid #e2e8f0; padding-top: 8px; padding-bottom: 8px;">
|
||||||
|
<h3 style="font-size: 18px; font-weight: semibold; margin-bottom: 8px;">${
|
||||||
|
section.charAt(0).toUpperCase() + section.slice(1)
|
||||||
|
}</h3>`;
|
||||||
|
items.forEach((item) => {
|
||||||
|
html += `<p style="font-size: 14px; color: ${textColor};">${item.name}</p>`;
|
||||||
|
});
|
||||||
|
html += "</div>";
|
||||||
|
});
|
||||||
|
html += "</div>";
|
||||||
|
|
||||||
|
html += "</div>";
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
|
||||||
function addButton() {
|
function addButton() {
|
||||||
const menu = document.querySelector(".comfy-menu");
|
const menu = document.querySelector(".comfy-menu");
|
||||||
|
|
||||||
@@ -189,8 +276,29 @@ function addButton() {
|
|||||||
/** @type {LGraph} */
|
/** @type {LGraph} */
|
||||||
const graph = app.graph;
|
const graph = app.graph;
|
||||||
|
|
||||||
|
let { endpoint, apiKey, displayName } = getData();
|
||||||
|
|
||||||
|
if (!endpoint || !apiKey || apiKey === "" || endpoint === "") {
|
||||||
|
configDialog.show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ok = await confirmDialog.confirm(
|
||||||
|
"Confirm deployment -> " + displayName,
|
||||||
|
`A new version will be deployed, are you conform? <br><br><input id="include-deps" type="checkbox" checked>Include dependence</input>`,
|
||||||
|
);
|
||||||
|
if (!ok) return;
|
||||||
|
|
||||||
|
const includeDeps = document.getElementById("include-deps").checked;
|
||||||
|
|
||||||
|
if (endpoint.endsWith("/")) {
|
||||||
|
endpoint = endpoint.slice(0, -1);
|
||||||
|
}
|
||||||
|
loadingDialog.showLoading("Generating snapshot", "Please wait...");
|
||||||
|
|
||||||
const snapshot = await fetch("/snapshot/get_current").then((x) => x.json());
|
const snapshot = await fetch("/snapshot/get_current").then((x) => x.json());
|
||||||
// console.log(snapshot);
|
// console.log(snapshot);
|
||||||
|
loadingDialog.close();
|
||||||
|
|
||||||
if (!snapshot) {
|
if (!snapshot) {
|
||||||
showError(
|
showError(
|
||||||
@@ -224,32 +332,94 @@ function addButton() {
|
|||||||
|
|
||||||
const deployMetaNode = deployMeta[0];
|
const deployMetaNode = deployMeta[0];
|
||||||
|
|
||||||
// console.log(deployMetaNode);
|
|
||||||
|
|
||||||
const workflow_name = deployMetaNode.widgets[0].value;
|
const workflow_name = deployMetaNode.widgets[0].value;
|
||||||
const workflow_id = deployMetaNode.widgets[1].value;
|
const workflow_id = deployMetaNode.widgets[1].value;
|
||||||
|
|
||||||
console.log(workflow_name, workflow_id);
|
|
||||||
|
|
||||||
const prompt = await app.graphToPrompt();
|
const prompt = await app.graphToPrompt();
|
||||||
console.log(graph);
|
let deps = undefined;
|
||||||
console.log(prompt);
|
|
||||||
|
|
||||||
// const endpoint = localStorage.getItem("endpoint") ?? "";
|
if (includeDeps) {
|
||||||
// const apiKey = localStorage.getItem("apiKey");
|
loadingDialog.showLoading("Fetching existing version", "Please wait...");
|
||||||
|
|
||||||
const { endpoint, apiKey, displayName } = getData();
|
const existing_workflow = await fetch(
|
||||||
|
endpoint + "/api/workflow/" + workflow_id,
|
||||||
|
{
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
Authorization: "Bearer " + apiKey,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.then((x) => x.json())
|
||||||
|
.catch(() => {
|
||||||
|
return {};
|
||||||
|
});
|
||||||
|
|
||||||
if (!endpoint || !apiKey || apiKey === "" || endpoint === "") {
|
loadingDialog.close();
|
||||||
configDialog.show();
|
|
||||||
return;
|
loadingDialog.showLoading(
|
||||||
|
"Generating dependency graph",
|
||||||
|
"Please wait...",
|
||||||
|
);
|
||||||
|
deps = await generateDependencyGraph({
|
||||||
|
workflow_api: prompt.output,
|
||||||
|
snapshot: snapshot,
|
||||||
|
computeFileHash: async (file) => {
|
||||||
|
console.log(file);
|
||||||
|
loadingDialog.showLoading("Generating hash", file);
|
||||||
|
const hash = await fetch(
|
||||||
|
`/comfyui-deploy/get-file-hash?file_path=${encodeURIComponent(
|
||||||
|
file,
|
||||||
|
)}`,
|
||||||
|
).then((x) => x.json());
|
||||||
|
loadingDialog.showLoading("Generating hash", file);
|
||||||
|
console.log(hash);
|
||||||
|
return hash.file_hash;
|
||||||
|
},
|
||||||
|
handleFileUpload: async (file, hash, prevhash) => {
|
||||||
|
console.log("Uploading ", file);
|
||||||
|
loadingDialog.showLoading("Uploading file", file);
|
||||||
|
try {
|
||||||
|
const { download_url } = await fetch(
|
||||||
|
`/comfyui-deploy/upload-file`,
|
||||||
|
{
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify({
|
||||||
|
file_path: file,
|
||||||
|
token: apiKey,
|
||||||
|
url: endpoint + "/api/upload-url",
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.then((x) => x.json())
|
||||||
|
.catch(() => {
|
||||||
|
loadingDialog.close();
|
||||||
|
confirmDialog.confirm("Error", "Unable to upload file " + file);
|
||||||
|
});
|
||||||
|
loadingDialog.showLoading("Uploaded file", file);
|
||||||
|
console.log(download_url);
|
||||||
|
return download_url;
|
||||||
|
} catch (error) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
existingDependencies: existing_workflow.dependencies,
|
||||||
|
});
|
||||||
|
|
||||||
|
loadingDialog.close();
|
||||||
|
|
||||||
|
const depsOk = await confirmDialog.confirm(
|
||||||
|
"Check dependencies",
|
||||||
|
// JSON.stringify(deps, null, 2),
|
||||||
|
createDynamicUIHtml(deps),
|
||||||
|
);
|
||||||
|
if (!depsOk) return;
|
||||||
|
|
||||||
|
console.log(deps);
|
||||||
}
|
}
|
||||||
|
|
||||||
const ok = await confirmDialog.confirm(
|
loadingDialog.showLoading("Deploying...");
|
||||||
"Confirm deployment -> " + displayName,
|
|
||||||
"A new version will be deployed, are you conform?",
|
|
||||||
);
|
|
||||||
if (!ok) return;
|
|
||||||
|
|
||||||
title.innerText = "Deploying...";
|
title.innerText = "Deploying...";
|
||||||
title.style.color = "orange";
|
title.style.color = "orange";
|
||||||
@@ -261,6 +431,8 @@ function addButton() {
|
|||||||
endpoint = endpoint.slice(0, -1);
|
endpoint = endpoint.slice(0, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// console.log(prompt.workflow);
|
||||||
|
|
||||||
const apiRoute = endpoint + "/api/workflow";
|
const apiRoute = endpoint + "/api/workflow";
|
||||||
// const userId = apiKey
|
// const userId = apiKey
|
||||||
try {
|
try {
|
||||||
@@ -270,6 +442,7 @@ function addButton() {
|
|||||||
workflow: prompt.workflow,
|
workflow: prompt.workflow,
|
||||||
workflow_api: prompt.output,
|
workflow_api: prompt.output,
|
||||||
snapshot: snapshot,
|
snapshot: snapshot,
|
||||||
|
dependencies: deps,
|
||||||
};
|
};
|
||||||
console.log(body);
|
console.log(body);
|
||||||
let data = await fetch(apiRoute, {
|
let data = await fetch(apiRoute, {
|
||||||
@@ -289,6 +462,8 @@ function addButton() {
|
|||||||
data = await data.json();
|
data = await data.json();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loadingDialog.close();
|
||||||
|
|
||||||
title.textContent = "Done";
|
title.textContent = "Done";
|
||||||
title.style.color = "green";
|
title.style.color = "green";
|
||||||
|
|
||||||
@@ -305,6 +480,7 @@ function addButton() {
|
|||||||
title.style.color = "white";
|
title.style.color = "white";
|
||||||
}, 1000);
|
}, 1000);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
loadingDialog.close();
|
||||||
app.ui.dialog.show(e);
|
app.ui.dialog.show(e);
|
||||||
console.error(e);
|
console.error(e);
|
||||||
title.textContent = "Error";
|
title.textContent = "Error";
|
||||||
@@ -381,7 +557,7 @@ export class InfoDialog extends ComfyDialog {
|
|||||||
|
|
||||||
showMessage(title, message) {
|
showMessage(title, message) {
|
||||||
this.show(`
|
this.show(`
|
||||||
<div style="width: 400px; display: flex; gap: 18px; flex-direction: column; overflow: unset">
|
<div style="width: 100%; max-width: 600px; display: flex; gap: 18px; flex-direction: column; overflow: unset">
|
||||||
<h3 style="margin: 0px;">${title}</h3>
|
<h3 style="margin: 0px;">${title}</h3>
|
||||||
<label>
|
<label>
|
||||||
${message}
|
${message}
|
||||||
@@ -437,7 +613,10 @@ export class LoadingDialog extends ComfyDialog {
|
|||||||
showLoading(title, message) {
|
showLoading(title, message) {
|
||||||
this.show(`
|
this.show(`
|
||||||
<div style="width: 400px; display: flex; gap: 18px; flex-direction: column; overflow: unset">
|
<div style="width: 400px; display: flex; gap: 18px; flex-direction: column; overflow: unset">
|
||||||
<h3 style="margin: 0px; display: flex; align-items: center; justify-content: center; gap: 4px;">${title} ${this.loadingIcon}</h3>
|
<h3 style="margin: 0px; display: flex; align-items: center; justify-content: center; gap: 12px;">${title} ${
|
||||||
|
this.loadingIcon
|
||||||
|
}</h3>
|
||||||
|
${message ? `<label>${message}</label>` : ""}
|
||||||
</div>
|
</div>
|
||||||
`);
|
`);
|
||||||
}
|
}
|
||||||
@@ -556,7 +735,7 @@ export class ConfirmDialog extends InfoDialog {
|
|||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.callback = resolve;
|
this.callback = resolve;
|
||||||
this.show(`
|
this.show(`
|
||||||
<div style="width: 400px; display: flex; gap: 18px; flex-direction: column; overflow: unset">
|
<div style="width: 100%; max-width: 600px; display: flex; gap: 18px; flex-direction: column; overflow: unset">
|
||||||
<h3 style="margin: 0px;">${title}</h3>
|
<h3 style="margin: 0px;">${title}</h3>
|
||||||
<label>
|
<label>
|
||||||
${message}
|
${message}
|
||||||
|
|||||||
@@ -20,14 +20,3 @@ PLAUSIBLE_DOMAIN=
|
|||||||
|
|
||||||
NEXT_PUBLIC_POSTHOG_KEY="your-api-key"
|
NEXT_PUBLIC_POSTHOG_KEY="your-api-key"
|
||||||
NEXT_PUBLIC_POSTHOG_HOST="your-ph-address"
|
NEXT_PUBLIC_POSTHOG_HOST="your-ph-address"
|
||||||
|
|
||||||
NEXT_PUBLIC_CLERK_SIGN_IN_URL=/auth/sign-in
|
|
||||||
NEXT_PUBLIC_CLERK_SIGN_UP_URL=/auth/sign-up
|
|
||||||
NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL=/
|
|
||||||
NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL=/
|
|
||||||
|
|
||||||
STRIPE_API_KEY="sk_test_"
|
|
||||||
STRIPE_PR_PRO="price_"
|
|
||||||
STRIPE_PR_ENTERPRISE="price_"
|
|
||||||
STRIPE_PR_API="price_"
|
|
||||||
STRIPE_WEBHOOK_SECRET="whsec_"
|
|
||||||
|
|||||||
Binary file not shown.
@@ -1,14 +0,0 @@
|
|||||||
CREATE TABLE IF NOT EXISTS "comfyui_deploy"."user_usage" (
|
|
||||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
||||||
"org_id" text,
|
|
||||||
"user_id" text NOT NULL,
|
|
||||||
"usage_time" real DEFAULT 0 NOT NULL,
|
|
||||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
|
||||||
"ended_at" timestamp DEFAULT now() NOT NULL
|
|
||||||
);
|
|
||||||
--> statement-breakpoint
|
|
||||||
DO $$ BEGIN
|
|
||||||
ALTER TABLE "comfyui_deploy"."user_usage" ADD CONSTRAINT "user_usage_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "comfyui_deploy"."users"("id") ON DELETE cascade ON UPDATE no action;
|
|
||||||
EXCEPTION
|
|
||||||
WHEN duplicate_object THEN null;
|
|
||||||
END $$;
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
DO $$ BEGIN
|
|
||||||
CREATE TYPE "subscription_plan" AS ENUM('basic', 'pro', 'enterprise');
|
|
||||||
EXCEPTION
|
|
||||||
WHEN duplicate_object THEN null;
|
|
||||||
END $$;
|
|
||||||
--> statement-breakpoint
|
|
||||||
DO $$ BEGIN
|
|
||||||
CREATE TYPE "subscription_plan_status" AS ENUM('active', 'deleted', 'paused');
|
|
||||||
EXCEPTION
|
|
||||||
WHEN duplicate_object THEN null;
|
|
||||||
END $$;
|
|
||||||
--> statement-breakpoint
|
|
||||||
CREATE TABLE IF NOT EXISTS "comfyui_deploy"."subscription_status" (
|
|
||||||
"stripe_customer_id" text PRIMARY KEY NOT NULL,
|
|
||||||
"user_id" text,
|
|
||||||
"org_id" text,
|
|
||||||
"plan" "subscription_plan" NOT NULL,
|
|
||||||
"status" "subscription_plan_status" NOT NULL,
|
|
||||||
"subscription_plan_id" text,
|
|
||||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
|
||||||
"updated_at" timestamp DEFAULT now() NOT NULL
|
|
||||||
);
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
ALTER TABLE "comfyui_deploy"."subscription_status" RENAME COLUMN "subscription_plan_id" TO "subscription_id";--> statement-breakpoint
|
|
||||||
ALTER TABLE "comfyui_deploy"."subscription_status" ADD COLUMN "subscription_item_plan_id" text;--> statement-breakpoint
|
|
||||||
ALTER TABLE "comfyui_deploy"."subscription_status" ADD COLUMN "subscription_item_api_id" text;
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
ALTER TABLE "comfyui_deploy"."subscription_status" ADD COLUMN "cancel_at_period_end" boolean DEFAULT false;
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
ALTER TABLE "comfyui_deploy"."workflow_runs" ADD COLUMN "user_id" text;--> statement-breakpoint
|
|
||||||
ALTER TABLE "comfyui_deploy"."workflow_runs" ADD COLUMN "org_id" text;
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
ALTER TABLE "comfyui_deploy"."workflow_runs" ADD COLUMN "gpu" "machine_gpu";
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
ALTER TABLE "comfyui_deploy"."workflow_runs" ADD COLUMN "machine_type" "machine_type";
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
DO $$ BEGIN
|
|
||||||
CREATE TYPE "model_upload_type" AS ENUM('civitai', 'huggingface', 'other');
|
|
||||||
EXCEPTION
|
|
||||||
WHEN duplicate_object THEN null;
|
|
||||||
END $$;
|
|
||||||
--> statement-breakpoint
|
|
||||||
DO $$ BEGIN
|
|
||||||
CREATE TYPE "resource_upload" AS ENUM('started', 'success', 'failed');
|
|
||||||
EXCEPTION
|
|
||||||
WHEN duplicate_object THEN null;
|
|
||||||
END $$;
|
|
||||||
--> statement-breakpoint
|
|
||||||
CREATE TABLE IF NOT EXISTS "comfyui_deploy"."checkpoints" (
|
|
||||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
||||||
"user_id" text,
|
|
||||||
"org_id" text,
|
|
||||||
"description" text,
|
|
||||||
"checkpoint_volume_id" uuid NOT NULL,
|
|
||||||
"model_name" text,
|
|
||||||
"folder_path" text,
|
|
||||||
"civitai_id" text,
|
|
||||||
"civitai_version_id" text,
|
|
||||||
"civitai_url" text,
|
|
||||||
"civitai_download_url" text,
|
|
||||||
"civitai_model_response" jsonb,
|
|
||||||
"hf_url" text,
|
|
||||||
"s3_url" text,
|
|
||||||
"client_url" text,
|
|
||||||
"is_public" boolean DEFAULT false NOT NULL,
|
|
||||||
"status" "resource_upload" DEFAULT 'started' NOT NULL,
|
|
||||||
"upload_machine_id" text,
|
|
||||||
"upload_type" "model_upload_type" NOT NULL,
|
|
||||||
"error_log" text,
|
|
||||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
|
||||||
"updated_at" timestamp DEFAULT now() NOT NULL
|
|
||||||
);
|
|
||||||
--> statement-breakpoint
|
|
||||||
CREATE TABLE IF NOT EXISTS "comfyui_deploy"."checkpoint_volume" (
|
|
||||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
||||||
"user_id" text,
|
|
||||||
"org_id" text,
|
|
||||||
"volume_name" text NOT NULL,
|
|
||||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
|
||||||
"updated_at" timestamp DEFAULT now() NOT NULL,
|
|
||||||
"disabled" boolean DEFAULT false NOT NULL
|
|
||||||
);
|
|
||||||
--> statement-breakpoint
|
|
||||||
DO $$ BEGIN
|
|
||||||
ALTER TABLE "comfyui_deploy"."checkpoints" ADD CONSTRAINT "checkpoints_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "comfyui_deploy"."users"("id") ON DELETE no action ON UPDATE no action;
|
|
||||||
EXCEPTION
|
|
||||||
WHEN duplicate_object THEN null;
|
|
||||||
END $$;
|
|
||||||
--> statement-breakpoint
|
|
||||||
DO $$ BEGIN
|
|
||||||
ALTER TABLE "comfyui_deploy"."checkpoints" ADD CONSTRAINT "checkpoints_checkpoint_volume_id_checkpoint_volume_id_fk" FOREIGN KEY ("checkpoint_volume_id") REFERENCES "comfyui_deploy"."checkpoint_volume"("id") ON DELETE cascade ON UPDATE no action;
|
|
||||||
EXCEPTION
|
|
||||||
WHEN duplicate_object THEN null;
|
|
||||||
END $$;
|
|
||||||
--> statement-breakpoint
|
|
||||||
DO $$ BEGIN
|
|
||||||
ALTER TABLE "comfyui_deploy"."checkpoint_volume" ADD CONSTRAINT "checkpoint_volume_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "comfyui_deploy"."users"("id") ON DELETE no action ON UPDATE no action;
|
|
||||||
EXCEPTION
|
|
||||||
WHEN duplicate_object THEN null;
|
|
||||||
END $$;
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
DO $$ BEGIN
|
|
||||||
CREATE TYPE "model_type" AS ENUM('checkpoint', 'lora', 'embedding', 'vae');
|
|
||||||
EXCEPTION
|
|
||||||
WHEN duplicate_object THEN null;
|
|
||||||
END $$;
|
|
||||||
--> statement-breakpoint
|
|
||||||
ALTER TABLE "comfyui_deploy"."checkpoints" RENAME TO "models";--> statement-breakpoint
|
|
||||||
ALTER TABLE "comfyui_deploy"."checkpoint_volume" RENAME TO "user_volume";--> statement-breakpoint
|
|
||||||
ALTER TABLE "comfyui_deploy"."models" RENAME COLUMN "checkpoint_volume_id" TO "user_volume_id";--> statement-breakpoint
|
|
||||||
ALTER TABLE "comfyui_deploy"."models" DROP CONSTRAINT "checkpoints_user_id_users_id_fk";
|
|
||||||
--> statement-breakpoint
|
|
||||||
ALTER TABLE "comfyui_deploy"."models" DROP CONSTRAINT "checkpoints_checkpoint_volume_id_checkpoint_volume_id_fk";
|
|
||||||
--> statement-breakpoint
|
|
||||||
ALTER TABLE "comfyui_deploy"."user_volume" DROP CONSTRAINT "checkpoint_volume_user_id_users_id_fk";
|
|
||||||
--> statement-breakpoint
|
|
||||||
ALTER TABLE "comfyui_deploy"."models" ADD COLUMN "model_type" "model_type" DEFAULT 'checkpoint' NOT NULL;--> statement-breakpoint
|
|
||||||
DO $$ BEGIN
|
|
||||||
ALTER TABLE "comfyui_deploy"."models" ADD CONSTRAINT "models_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "comfyui_deploy"."users"("id") ON DELETE no action ON UPDATE no action;
|
|
||||||
EXCEPTION
|
|
||||||
WHEN duplicate_object THEN null;
|
|
||||||
END $$;
|
|
||||||
--> statement-breakpoint
|
|
||||||
DO $$ BEGIN
|
|
||||||
ALTER TABLE "comfyui_deploy"."models" ADD CONSTRAINT "models_user_volume_id_user_volume_id_fk" FOREIGN KEY ("user_volume_id") REFERENCES "comfyui_deploy"."user_volume"("id") ON DELETE cascade ON UPDATE no action;
|
|
||||||
EXCEPTION
|
|
||||||
WHEN duplicate_object THEN null;
|
|
||||||
END $$;
|
|
||||||
--> statement-breakpoint
|
|
||||||
DO $$ BEGIN
|
|
||||||
ALTER TABLE "comfyui_deploy"."user_volume" ADD CONSTRAINT "user_volume_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "comfyui_deploy"."users"("id") ON DELETE no action ON UPDATE no action;
|
|
||||||
EXCEPTION
|
|
||||||
WHEN duplicate_object THEN null;
|
|
||||||
END $$;
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
ALTER TABLE "comfyui_deploy"."models" ALTER COLUMN "is_public" SET DEFAULT true;
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
ALTER TYPE "workflow_run_status" ADD VALUE 'started';--> statement-breakpoint
|
|
||||||
ALTER TYPE "workflow_run_status" ADD VALUE 'queued';--> statement-breakpoint
|
|
||||||
ALTER TABLE "comfyui_deploy"."workflow_runs" ADD COLUMN "queued_at" timestamp;
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
ALTER TYPE "model_upload_type" ADD VALUE 'download_url';
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
ALTER TYPE "model_upload_type" ADD VALUE 'download-url';
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
ALTER TYPE "workflow_run_status" ADD VALUE 'timeout';--> statement-breakpoint
|
|
||||||
ALTER TABLE "comfyui_deploy"."workflow_runs" ADD COLUMN "run_log" text;
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
ALTER TABLE "comfyui_deploy"."workflow_runs" DROP COLUMN "run_log";
|
|
||||||
ALTER TABLE "comfyui_deploy"."workflow_runs" ADD COLUMN "run_log" jsonb;
|
|
||||||
@@ -1,894 +0,0 @@
|
|||||||
{
|
|
||||||
"id": "2b2a5d0a-2494-45ea-9d4a-58a70df97829",
|
|
||||||
"prevId": "8d654f92-7f7e-420f-bbd3-73b6b27adf35",
|
|
||||||
"version": "5",
|
|
||||||
"dialect": "pg",
|
|
||||||
"tables": {
|
|
||||||
"api_keys": {
|
|
||||||
"name": "api_keys",
|
|
||||||
"schema": "comfyui_deploy",
|
|
||||||
"columns": {
|
|
||||||
"id": {
|
|
||||||
"name": "id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": true,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "gen_random_uuid()"
|
|
||||||
},
|
|
||||||
"key": {
|
|
||||||
"name": "key",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"name": "name",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"user_id": {
|
|
||||||
"name": "user_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"org_id": {
|
|
||||||
"name": "org_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"revoked": {
|
|
||||||
"name": "revoked",
|
|
||||||
"type": "boolean",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
"created_at": {
|
|
||||||
"name": "created_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
},
|
|
||||||
"updated_at": {
|
|
||||||
"name": "updated_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"indexes": {},
|
|
||||||
"foreignKeys": {
|
|
||||||
"api_keys_user_id_users_id_fk": {
|
|
||||||
"name": "api_keys_user_id_users_id_fk",
|
|
||||||
"tableFrom": "api_keys",
|
|
||||||
"tableTo": "users",
|
|
||||||
"columnsFrom": [
|
|
||||||
"user_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "cascade",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"compositePrimaryKeys": {},
|
|
||||||
"uniqueConstraints": {
|
|
||||||
"api_keys_key_unique": {
|
|
||||||
"name": "api_keys_key_unique",
|
|
||||||
"nullsNotDistinct": false,
|
|
||||||
"columns": [
|
|
||||||
"key"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"auth_requests": {
|
|
||||||
"name": "auth_requests",
|
|
||||||
"schema": "comfyui_deploy",
|
|
||||||
"columns": {
|
|
||||||
"request_id": {
|
|
||||||
"name": "request_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": true,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"user_id": {
|
|
||||||
"name": "user_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"org_id": {
|
|
||||||
"name": "org_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"api_hash": {
|
|
||||||
"name": "api_hash",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"created_at": {
|
|
||||||
"name": "created_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
},
|
|
||||||
"expired_date": {
|
|
||||||
"name": "expired_date",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"updated_at": {
|
|
||||||
"name": "updated_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"indexes": {},
|
|
||||||
"foreignKeys": {},
|
|
||||||
"compositePrimaryKeys": {},
|
|
||||||
"uniqueConstraints": {}
|
|
||||||
},
|
|
||||||
"deployments": {
|
|
||||||
"name": "deployments",
|
|
||||||
"schema": "comfyui_deploy",
|
|
||||||
"columns": {
|
|
||||||
"id": {
|
|
||||||
"name": "id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": true,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "gen_random_uuid()"
|
|
||||||
},
|
|
||||||
"user_id": {
|
|
||||||
"name": "user_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"org_id": {
|
|
||||||
"name": "org_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"workflow_version_id": {
|
|
||||||
"name": "workflow_version_id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"workflow_id": {
|
|
||||||
"name": "workflow_id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"machine_id": {
|
|
||||||
"name": "machine_id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"share_slug": {
|
|
||||||
"name": "share_slug",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"description": {
|
|
||||||
"name": "description",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"showcase_media": {
|
|
||||||
"name": "showcase_media",
|
|
||||||
"type": "jsonb",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"environment": {
|
|
||||||
"name": "environment",
|
|
||||||
"type": "deployment_environment",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"created_at": {
|
|
||||||
"name": "created_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
},
|
|
||||||
"updated_at": {
|
|
||||||
"name": "updated_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"indexes": {},
|
|
||||||
"foreignKeys": {
|
|
||||||
"deployments_user_id_users_id_fk": {
|
|
||||||
"name": "deployments_user_id_users_id_fk",
|
|
||||||
"tableFrom": "deployments",
|
|
||||||
"tableTo": "users",
|
|
||||||
"columnsFrom": [
|
|
||||||
"user_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "cascade",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
},
|
|
||||||
"deployments_workflow_version_id_workflow_versions_id_fk": {
|
|
||||||
"name": "deployments_workflow_version_id_workflow_versions_id_fk",
|
|
||||||
"tableFrom": "deployments",
|
|
||||||
"tableTo": "workflow_versions",
|
|
||||||
"columnsFrom": [
|
|
||||||
"workflow_version_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "no action",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
},
|
|
||||||
"deployments_workflow_id_workflows_id_fk": {
|
|
||||||
"name": "deployments_workflow_id_workflows_id_fk",
|
|
||||||
"tableFrom": "deployments",
|
|
||||||
"tableTo": "workflows",
|
|
||||||
"columnsFrom": [
|
|
||||||
"workflow_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "cascade",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
},
|
|
||||||
"deployments_machine_id_machines_id_fk": {
|
|
||||||
"name": "deployments_machine_id_machines_id_fk",
|
|
||||||
"tableFrom": "deployments",
|
|
||||||
"tableTo": "machines",
|
|
||||||
"columnsFrom": [
|
|
||||||
"machine_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "no action",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"compositePrimaryKeys": {},
|
|
||||||
"uniqueConstraints": {
|
|
||||||
"deployments_share_slug_unique": {
|
|
||||||
"name": "deployments_share_slug_unique",
|
|
||||||
"nullsNotDistinct": false,
|
|
||||||
"columns": [
|
|
||||||
"share_slug"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"machines": {
|
|
||||||
"name": "machines",
|
|
||||||
"schema": "comfyui_deploy",
|
|
||||||
"columns": {
|
|
||||||
"id": {
|
|
||||||
"name": "id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": true,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "gen_random_uuid()"
|
|
||||||
},
|
|
||||||
"user_id": {
|
|
||||||
"name": "user_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"name": "name",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"org_id": {
|
|
||||||
"name": "org_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"endpoint": {
|
|
||||||
"name": "endpoint",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"created_at": {
|
|
||||||
"name": "created_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
},
|
|
||||||
"updated_at": {
|
|
||||||
"name": "updated_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
},
|
|
||||||
"disabled": {
|
|
||||||
"name": "disabled",
|
|
||||||
"type": "boolean",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
"auth_token": {
|
|
||||||
"name": "auth_token",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"type": {
|
|
||||||
"name": "type",
|
|
||||||
"type": "machine_type",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "'classic'"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"name": "status",
|
|
||||||
"type": "machine_status",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "'ready'"
|
|
||||||
},
|
|
||||||
"snapshot": {
|
|
||||||
"name": "snapshot",
|
|
||||||
"type": "jsonb",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"models": {
|
|
||||||
"name": "models",
|
|
||||||
"type": "jsonb",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"gpu": {
|
|
||||||
"name": "gpu",
|
|
||||||
"type": "machine_gpu",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"build_machine_instance_id": {
|
|
||||||
"name": "build_machine_instance_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"build_log": {
|
|
||||||
"name": "build_log",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"indexes": {},
|
|
||||||
"foreignKeys": {
|
|
||||||
"machines_user_id_users_id_fk": {
|
|
||||||
"name": "machines_user_id_users_id_fk",
|
|
||||||
"tableFrom": "machines",
|
|
||||||
"tableTo": "users",
|
|
||||||
"columnsFrom": [
|
|
||||||
"user_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "cascade",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"compositePrimaryKeys": {},
|
|
||||||
"uniqueConstraints": {}
|
|
||||||
},
|
|
||||||
"user_usage": {
|
|
||||||
"name": "user_usage",
|
|
||||||
"schema": "comfyui_deploy",
|
|
||||||
"columns": {
|
|
||||||
"id": {
|
|
||||||
"name": "id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": true,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "gen_random_uuid()"
|
|
||||||
},
|
|
||||||
"org_id": {
|
|
||||||
"name": "org_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"user_id": {
|
|
||||||
"name": "user_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"usage_time": {
|
|
||||||
"name": "usage_time",
|
|
||||||
"type": "real",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": 0
|
|
||||||
},
|
|
||||||
"created_at": {
|
|
||||||
"name": "created_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
},
|
|
||||||
"ended_at": {
|
|
||||||
"name": "ended_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"indexes": {},
|
|
||||||
"foreignKeys": {
|
|
||||||
"user_usage_user_id_users_id_fk": {
|
|
||||||
"name": "user_usage_user_id_users_id_fk",
|
|
||||||
"tableFrom": "user_usage",
|
|
||||||
"tableTo": "users",
|
|
||||||
"columnsFrom": [
|
|
||||||
"user_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "cascade",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"compositePrimaryKeys": {},
|
|
||||||
"uniqueConstraints": {}
|
|
||||||
},
|
|
||||||
"users": {
|
|
||||||
"name": "users",
|
|
||||||
"schema": "comfyui_deploy",
|
|
||||||
"columns": {
|
|
||||||
"id": {
|
|
||||||
"name": "id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": true,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"username": {
|
|
||||||
"name": "username",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"name": "name",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"created_at": {
|
|
||||||
"name": "created_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false,
|
|
||||||
"default": "now()"
|
|
||||||
},
|
|
||||||
"updated_at": {
|
|
||||||
"name": "updated_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false,
|
|
||||||
"default": "now()"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"indexes": {},
|
|
||||||
"foreignKeys": {},
|
|
||||||
"compositePrimaryKeys": {},
|
|
||||||
"uniqueConstraints": {}
|
|
||||||
},
|
|
||||||
"workflow_run_outputs": {
|
|
||||||
"name": "workflow_run_outputs",
|
|
||||||
"schema": "comfyui_deploy",
|
|
||||||
"columns": {
|
|
||||||
"id": {
|
|
||||||
"name": "id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": true,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "gen_random_uuid()"
|
|
||||||
},
|
|
||||||
"run_id": {
|
|
||||||
"name": "run_id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"data": {
|
|
||||||
"name": "data",
|
|
||||||
"type": "jsonb",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"created_at": {
|
|
||||||
"name": "created_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
},
|
|
||||||
"updated_at": {
|
|
||||||
"name": "updated_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"indexes": {},
|
|
||||||
"foreignKeys": {
|
|
||||||
"workflow_run_outputs_run_id_workflow_runs_id_fk": {
|
|
||||||
"name": "workflow_run_outputs_run_id_workflow_runs_id_fk",
|
|
||||||
"tableFrom": "workflow_run_outputs",
|
|
||||||
"tableTo": "workflow_runs",
|
|
||||||
"columnsFrom": [
|
|
||||||
"run_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "cascade",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"compositePrimaryKeys": {},
|
|
||||||
"uniqueConstraints": {}
|
|
||||||
},
|
|
||||||
"workflow_runs": {
|
|
||||||
"name": "workflow_runs",
|
|
||||||
"schema": "comfyui_deploy",
|
|
||||||
"columns": {
|
|
||||||
"id": {
|
|
||||||
"name": "id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": true,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "gen_random_uuid()"
|
|
||||||
},
|
|
||||||
"workflow_version_id": {
|
|
||||||
"name": "workflow_version_id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"workflow_inputs": {
|
|
||||||
"name": "workflow_inputs",
|
|
||||||
"type": "jsonb",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"workflow_id": {
|
|
||||||
"name": "workflow_id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"machine_id": {
|
|
||||||
"name": "machine_id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"origin": {
|
|
||||||
"name": "origin",
|
|
||||||
"type": "workflow_run_origin",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "'api'"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"name": "status",
|
|
||||||
"type": "workflow_run_status",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "'not-started'"
|
|
||||||
},
|
|
||||||
"ended_at": {
|
|
||||||
"name": "ended_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"created_at": {
|
|
||||||
"name": "created_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
},
|
|
||||||
"started_at": {
|
|
||||||
"name": "started_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"indexes": {},
|
|
||||||
"foreignKeys": {
|
|
||||||
"workflow_runs_workflow_version_id_workflow_versions_id_fk": {
|
|
||||||
"name": "workflow_runs_workflow_version_id_workflow_versions_id_fk",
|
|
||||||
"tableFrom": "workflow_runs",
|
|
||||||
"tableTo": "workflow_versions",
|
|
||||||
"columnsFrom": [
|
|
||||||
"workflow_version_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "set null",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
},
|
|
||||||
"workflow_runs_workflow_id_workflows_id_fk": {
|
|
||||||
"name": "workflow_runs_workflow_id_workflows_id_fk",
|
|
||||||
"tableFrom": "workflow_runs",
|
|
||||||
"tableTo": "workflows",
|
|
||||||
"columnsFrom": [
|
|
||||||
"workflow_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "cascade",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
},
|
|
||||||
"workflow_runs_machine_id_machines_id_fk": {
|
|
||||||
"name": "workflow_runs_machine_id_machines_id_fk",
|
|
||||||
"tableFrom": "workflow_runs",
|
|
||||||
"tableTo": "machines",
|
|
||||||
"columnsFrom": [
|
|
||||||
"machine_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "set null",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"compositePrimaryKeys": {},
|
|
||||||
"uniqueConstraints": {}
|
|
||||||
},
|
|
||||||
"workflows": {
|
|
||||||
"name": "workflows",
|
|
||||||
"schema": "comfyui_deploy",
|
|
||||||
"columns": {
|
|
||||||
"id": {
|
|
||||||
"name": "id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": true,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "gen_random_uuid()"
|
|
||||||
},
|
|
||||||
"user_id": {
|
|
||||||
"name": "user_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"org_id": {
|
|
||||||
"name": "org_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"name": "name",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"created_at": {
|
|
||||||
"name": "created_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
},
|
|
||||||
"updated_at": {
|
|
||||||
"name": "updated_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"indexes": {},
|
|
||||||
"foreignKeys": {
|
|
||||||
"workflows_user_id_users_id_fk": {
|
|
||||||
"name": "workflows_user_id_users_id_fk",
|
|
||||||
"tableFrom": "workflows",
|
|
||||||
"tableTo": "users",
|
|
||||||
"columnsFrom": [
|
|
||||||
"user_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "cascade",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"compositePrimaryKeys": {},
|
|
||||||
"uniqueConstraints": {}
|
|
||||||
},
|
|
||||||
"workflow_versions": {
|
|
||||||
"name": "workflow_versions",
|
|
||||||
"schema": "comfyui_deploy",
|
|
||||||
"columns": {
|
|
||||||
"workflow_id": {
|
|
||||||
"name": "workflow_id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"id": {
|
|
||||||
"name": "id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": true,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "gen_random_uuid()"
|
|
||||||
},
|
|
||||||
"workflow": {
|
|
||||||
"name": "workflow",
|
|
||||||
"type": "jsonb",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"workflow_api": {
|
|
||||||
"name": "workflow_api",
|
|
||||||
"type": "jsonb",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"version": {
|
|
||||||
"name": "version",
|
|
||||||
"type": "integer",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"snapshot": {
|
|
||||||
"name": "snapshot",
|
|
||||||
"type": "jsonb",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"created_at": {
|
|
||||||
"name": "created_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
},
|
|
||||||
"updated_at": {
|
|
||||||
"name": "updated_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"indexes": {},
|
|
||||||
"foreignKeys": {
|
|
||||||
"workflow_versions_workflow_id_workflows_id_fk": {
|
|
||||||
"name": "workflow_versions_workflow_id_workflows_id_fk",
|
|
||||||
"tableFrom": "workflow_versions",
|
|
||||||
"tableTo": "workflows",
|
|
||||||
"columnsFrom": [
|
|
||||||
"workflow_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "cascade",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"compositePrimaryKeys": {},
|
|
||||||
"uniqueConstraints": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"enums": {
|
|
||||||
"deployment_environment": {
|
|
||||||
"name": "deployment_environment",
|
|
||||||
"values": {
|
|
||||||
"staging": "staging",
|
|
||||||
"production": "production",
|
|
||||||
"public-share": "public-share"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"machine_gpu": {
|
|
||||||
"name": "machine_gpu",
|
|
||||||
"values": {
|
|
||||||
"T4": "T4",
|
|
||||||
"A10G": "A10G",
|
|
||||||
"A100": "A100"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"machine_status": {
|
|
||||||
"name": "machine_status",
|
|
||||||
"values": {
|
|
||||||
"ready": "ready",
|
|
||||||
"building": "building",
|
|
||||||
"error": "error"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"machine_type": {
|
|
||||||
"name": "machine_type",
|
|
||||||
"values": {
|
|
||||||
"classic": "classic",
|
|
||||||
"runpod-serverless": "runpod-serverless",
|
|
||||||
"modal-serverless": "modal-serverless",
|
|
||||||
"comfy-deploy-serverless": "comfy-deploy-serverless"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"workflow_run_origin": {
|
|
||||||
"name": "workflow_run_origin",
|
|
||||||
"values": {
|
|
||||||
"manual": "manual",
|
|
||||||
"api": "api",
|
|
||||||
"public-share": "public-share"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"workflow_run_status": {
|
|
||||||
"name": "workflow_run_status",
|
|
||||||
"values": {
|
|
||||||
"not-started": "not-started",
|
|
||||||
"running": "running",
|
|
||||||
"uploading": "uploading",
|
|
||||||
"success": "success",
|
|
||||||
"failed": "failed"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"schemas": {
|
|
||||||
"comfyui_deploy": "comfyui_deploy"
|
|
||||||
},
|
|
||||||
"_meta": {
|
|
||||||
"schemas": {},
|
|
||||||
"tables": {},
|
|
||||||
"columns": {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,970 +0,0 @@
|
|||||||
{
|
|
||||||
"id": "4db08fc3-2444-42da-b742-f1832ad8caf1",
|
|
||||||
"prevId": "2b2a5d0a-2494-45ea-9d4a-58a70df97829",
|
|
||||||
"version": "5",
|
|
||||||
"dialect": "pg",
|
|
||||||
"tables": {
|
|
||||||
"api_keys": {
|
|
||||||
"name": "api_keys",
|
|
||||||
"schema": "comfyui_deploy",
|
|
||||||
"columns": {
|
|
||||||
"id": {
|
|
||||||
"name": "id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": true,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "gen_random_uuid()"
|
|
||||||
},
|
|
||||||
"key": {
|
|
||||||
"name": "key",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"name": "name",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"user_id": {
|
|
||||||
"name": "user_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"org_id": {
|
|
||||||
"name": "org_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"revoked": {
|
|
||||||
"name": "revoked",
|
|
||||||
"type": "boolean",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
"created_at": {
|
|
||||||
"name": "created_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
},
|
|
||||||
"updated_at": {
|
|
||||||
"name": "updated_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"indexes": {},
|
|
||||||
"foreignKeys": {
|
|
||||||
"api_keys_user_id_users_id_fk": {
|
|
||||||
"name": "api_keys_user_id_users_id_fk",
|
|
||||||
"tableFrom": "api_keys",
|
|
||||||
"tableTo": "users",
|
|
||||||
"columnsFrom": [
|
|
||||||
"user_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "cascade",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"compositePrimaryKeys": {},
|
|
||||||
"uniqueConstraints": {
|
|
||||||
"api_keys_key_unique": {
|
|
||||||
"name": "api_keys_key_unique",
|
|
||||||
"nullsNotDistinct": false,
|
|
||||||
"columns": [
|
|
||||||
"key"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"auth_requests": {
|
|
||||||
"name": "auth_requests",
|
|
||||||
"schema": "comfyui_deploy",
|
|
||||||
"columns": {
|
|
||||||
"request_id": {
|
|
||||||
"name": "request_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": true,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"user_id": {
|
|
||||||
"name": "user_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"org_id": {
|
|
||||||
"name": "org_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"api_hash": {
|
|
||||||
"name": "api_hash",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"created_at": {
|
|
||||||
"name": "created_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
},
|
|
||||||
"expired_date": {
|
|
||||||
"name": "expired_date",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"updated_at": {
|
|
||||||
"name": "updated_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"indexes": {},
|
|
||||||
"foreignKeys": {},
|
|
||||||
"compositePrimaryKeys": {},
|
|
||||||
"uniqueConstraints": {}
|
|
||||||
},
|
|
||||||
"deployments": {
|
|
||||||
"name": "deployments",
|
|
||||||
"schema": "comfyui_deploy",
|
|
||||||
"columns": {
|
|
||||||
"id": {
|
|
||||||
"name": "id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": true,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "gen_random_uuid()"
|
|
||||||
},
|
|
||||||
"user_id": {
|
|
||||||
"name": "user_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"org_id": {
|
|
||||||
"name": "org_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"workflow_version_id": {
|
|
||||||
"name": "workflow_version_id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"workflow_id": {
|
|
||||||
"name": "workflow_id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"machine_id": {
|
|
||||||
"name": "machine_id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"share_slug": {
|
|
||||||
"name": "share_slug",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"description": {
|
|
||||||
"name": "description",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"showcase_media": {
|
|
||||||
"name": "showcase_media",
|
|
||||||
"type": "jsonb",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"environment": {
|
|
||||||
"name": "environment",
|
|
||||||
"type": "deployment_environment",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"created_at": {
|
|
||||||
"name": "created_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
},
|
|
||||||
"updated_at": {
|
|
||||||
"name": "updated_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"indexes": {},
|
|
||||||
"foreignKeys": {
|
|
||||||
"deployments_user_id_users_id_fk": {
|
|
||||||
"name": "deployments_user_id_users_id_fk",
|
|
||||||
"tableFrom": "deployments",
|
|
||||||
"tableTo": "users",
|
|
||||||
"columnsFrom": [
|
|
||||||
"user_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "cascade",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
},
|
|
||||||
"deployments_workflow_version_id_workflow_versions_id_fk": {
|
|
||||||
"name": "deployments_workflow_version_id_workflow_versions_id_fk",
|
|
||||||
"tableFrom": "deployments",
|
|
||||||
"tableTo": "workflow_versions",
|
|
||||||
"columnsFrom": [
|
|
||||||
"workflow_version_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "no action",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
},
|
|
||||||
"deployments_workflow_id_workflows_id_fk": {
|
|
||||||
"name": "deployments_workflow_id_workflows_id_fk",
|
|
||||||
"tableFrom": "deployments",
|
|
||||||
"tableTo": "workflows",
|
|
||||||
"columnsFrom": [
|
|
||||||
"workflow_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "cascade",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
},
|
|
||||||
"deployments_machine_id_machines_id_fk": {
|
|
||||||
"name": "deployments_machine_id_machines_id_fk",
|
|
||||||
"tableFrom": "deployments",
|
|
||||||
"tableTo": "machines",
|
|
||||||
"columnsFrom": [
|
|
||||||
"machine_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "no action",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"compositePrimaryKeys": {},
|
|
||||||
"uniqueConstraints": {
|
|
||||||
"deployments_share_slug_unique": {
|
|
||||||
"name": "deployments_share_slug_unique",
|
|
||||||
"nullsNotDistinct": false,
|
|
||||||
"columns": [
|
|
||||||
"share_slug"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"machines": {
|
|
||||||
"name": "machines",
|
|
||||||
"schema": "comfyui_deploy",
|
|
||||||
"columns": {
|
|
||||||
"id": {
|
|
||||||
"name": "id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": true,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "gen_random_uuid()"
|
|
||||||
},
|
|
||||||
"user_id": {
|
|
||||||
"name": "user_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"name": "name",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"org_id": {
|
|
||||||
"name": "org_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"endpoint": {
|
|
||||||
"name": "endpoint",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"created_at": {
|
|
||||||
"name": "created_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
},
|
|
||||||
"updated_at": {
|
|
||||||
"name": "updated_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
},
|
|
||||||
"disabled": {
|
|
||||||
"name": "disabled",
|
|
||||||
"type": "boolean",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
"auth_token": {
|
|
||||||
"name": "auth_token",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"type": {
|
|
||||||
"name": "type",
|
|
||||||
"type": "machine_type",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "'classic'"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"name": "status",
|
|
||||||
"type": "machine_status",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "'ready'"
|
|
||||||
},
|
|
||||||
"snapshot": {
|
|
||||||
"name": "snapshot",
|
|
||||||
"type": "jsonb",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"models": {
|
|
||||||
"name": "models",
|
|
||||||
"type": "jsonb",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"gpu": {
|
|
||||||
"name": "gpu",
|
|
||||||
"type": "machine_gpu",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"build_machine_instance_id": {
|
|
||||||
"name": "build_machine_instance_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"build_log": {
|
|
||||||
"name": "build_log",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"indexes": {},
|
|
||||||
"foreignKeys": {
|
|
||||||
"machines_user_id_users_id_fk": {
|
|
||||||
"name": "machines_user_id_users_id_fk",
|
|
||||||
"tableFrom": "machines",
|
|
||||||
"tableTo": "users",
|
|
||||||
"columnsFrom": [
|
|
||||||
"user_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "cascade",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"compositePrimaryKeys": {},
|
|
||||||
"uniqueConstraints": {}
|
|
||||||
},
|
|
||||||
"subscription_status": {
|
|
||||||
"name": "subscription_status",
|
|
||||||
"schema": "comfyui_deploy",
|
|
||||||
"columns": {
|
|
||||||
"stripe_customer_id": {
|
|
||||||
"name": "stripe_customer_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": true,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"user_id": {
|
|
||||||
"name": "user_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"org_id": {
|
|
||||||
"name": "org_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"plan": {
|
|
||||||
"name": "plan",
|
|
||||||
"type": "subscription_plan",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"name": "status",
|
|
||||||
"type": "subscription_plan_status",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"subscription_plan_id": {
|
|
||||||
"name": "subscription_plan_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"created_at": {
|
|
||||||
"name": "created_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
},
|
|
||||||
"updated_at": {
|
|
||||||
"name": "updated_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"indexes": {},
|
|
||||||
"foreignKeys": {},
|
|
||||||
"compositePrimaryKeys": {},
|
|
||||||
"uniqueConstraints": {}
|
|
||||||
},
|
|
||||||
"user_usage": {
|
|
||||||
"name": "user_usage",
|
|
||||||
"schema": "comfyui_deploy",
|
|
||||||
"columns": {
|
|
||||||
"id": {
|
|
||||||
"name": "id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": true,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "gen_random_uuid()"
|
|
||||||
},
|
|
||||||
"org_id": {
|
|
||||||
"name": "org_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"user_id": {
|
|
||||||
"name": "user_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"usage_time": {
|
|
||||||
"name": "usage_time",
|
|
||||||
"type": "real",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": 0
|
|
||||||
},
|
|
||||||
"created_at": {
|
|
||||||
"name": "created_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
},
|
|
||||||
"ended_at": {
|
|
||||||
"name": "ended_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"indexes": {},
|
|
||||||
"foreignKeys": {
|
|
||||||
"user_usage_user_id_users_id_fk": {
|
|
||||||
"name": "user_usage_user_id_users_id_fk",
|
|
||||||
"tableFrom": "user_usage",
|
|
||||||
"tableTo": "users",
|
|
||||||
"columnsFrom": [
|
|
||||||
"user_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "cascade",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"compositePrimaryKeys": {},
|
|
||||||
"uniqueConstraints": {}
|
|
||||||
},
|
|
||||||
"users": {
|
|
||||||
"name": "users",
|
|
||||||
"schema": "comfyui_deploy",
|
|
||||||
"columns": {
|
|
||||||
"id": {
|
|
||||||
"name": "id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": true,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"username": {
|
|
||||||
"name": "username",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"name": "name",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"created_at": {
|
|
||||||
"name": "created_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false,
|
|
||||||
"default": "now()"
|
|
||||||
},
|
|
||||||
"updated_at": {
|
|
||||||
"name": "updated_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false,
|
|
||||||
"default": "now()"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"indexes": {},
|
|
||||||
"foreignKeys": {},
|
|
||||||
"compositePrimaryKeys": {},
|
|
||||||
"uniqueConstraints": {}
|
|
||||||
},
|
|
||||||
"workflow_run_outputs": {
|
|
||||||
"name": "workflow_run_outputs",
|
|
||||||
"schema": "comfyui_deploy",
|
|
||||||
"columns": {
|
|
||||||
"id": {
|
|
||||||
"name": "id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": true,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "gen_random_uuid()"
|
|
||||||
},
|
|
||||||
"run_id": {
|
|
||||||
"name": "run_id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"data": {
|
|
||||||
"name": "data",
|
|
||||||
"type": "jsonb",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"created_at": {
|
|
||||||
"name": "created_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
},
|
|
||||||
"updated_at": {
|
|
||||||
"name": "updated_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"indexes": {},
|
|
||||||
"foreignKeys": {
|
|
||||||
"workflow_run_outputs_run_id_workflow_runs_id_fk": {
|
|
||||||
"name": "workflow_run_outputs_run_id_workflow_runs_id_fk",
|
|
||||||
"tableFrom": "workflow_run_outputs",
|
|
||||||
"tableTo": "workflow_runs",
|
|
||||||
"columnsFrom": [
|
|
||||||
"run_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "cascade",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"compositePrimaryKeys": {},
|
|
||||||
"uniqueConstraints": {}
|
|
||||||
},
|
|
||||||
"workflow_runs": {
|
|
||||||
"name": "workflow_runs",
|
|
||||||
"schema": "comfyui_deploy",
|
|
||||||
"columns": {
|
|
||||||
"id": {
|
|
||||||
"name": "id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": true,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "gen_random_uuid()"
|
|
||||||
},
|
|
||||||
"workflow_version_id": {
|
|
||||||
"name": "workflow_version_id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"workflow_inputs": {
|
|
||||||
"name": "workflow_inputs",
|
|
||||||
"type": "jsonb",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"workflow_id": {
|
|
||||||
"name": "workflow_id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"machine_id": {
|
|
||||||
"name": "machine_id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"origin": {
|
|
||||||
"name": "origin",
|
|
||||||
"type": "workflow_run_origin",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "'api'"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"name": "status",
|
|
||||||
"type": "workflow_run_status",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "'not-started'"
|
|
||||||
},
|
|
||||||
"ended_at": {
|
|
||||||
"name": "ended_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"created_at": {
|
|
||||||
"name": "created_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
},
|
|
||||||
"started_at": {
|
|
||||||
"name": "started_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"indexes": {},
|
|
||||||
"foreignKeys": {
|
|
||||||
"workflow_runs_workflow_version_id_workflow_versions_id_fk": {
|
|
||||||
"name": "workflow_runs_workflow_version_id_workflow_versions_id_fk",
|
|
||||||
"tableFrom": "workflow_runs",
|
|
||||||
"tableTo": "workflow_versions",
|
|
||||||
"columnsFrom": [
|
|
||||||
"workflow_version_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "set null",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
},
|
|
||||||
"workflow_runs_workflow_id_workflows_id_fk": {
|
|
||||||
"name": "workflow_runs_workflow_id_workflows_id_fk",
|
|
||||||
"tableFrom": "workflow_runs",
|
|
||||||
"tableTo": "workflows",
|
|
||||||
"columnsFrom": [
|
|
||||||
"workflow_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "cascade",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
},
|
|
||||||
"workflow_runs_machine_id_machines_id_fk": {
|
|
||||||
"name": "workflow_runs_machine_id_machines_id_fk",
|
|
||||||
"tableFrom": "workflow_runs",
|
|
||||||
"tableTo": "machines",
|
|
||||||
"columnsFrom": [
|
|
||||||
"machine_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "set null",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"compositePrimaryKeys": {},
|
|
||||||
"uniqueConstraints": {}
|
|
||||||
},
|
|
||||||
"workflows": {
|
|
||||||
"name": "workflows",
|
|
||||||
"schema": "comfyui_deploy",
|
|
||||||
"columns": {
|
|
||||||
"id": {
|
|
||||||
"name": "id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": true,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "gen_random_uuid()"
|
|
||||||
},
|
|
||||||
"user_id": {
|
|
||||||
"name": "user_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"org_id": {
|
|
||||||
"name": "org_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"name": "name",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"created_at": {
|
|
||||||
"name": "created_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
},
|
|
||||||
"updated_at": {
|
|
||||||
"name": "updated_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"indexes": {},
|
|
||||||
"foreignKeys": {
|
|
||||||
"workflows_user_id_users_id_fk": {
|
|
||||||
"name": "workflows_user_id_users_id_fk",
|
|
||||||
"tableFrom": "workflows",
|
|
||||||
"tableTo": "users",
|
|
||||||
"columnsFrom": [
|
|
||||||
"user_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "cascade",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"compositePrimaryKeys": {},
|
|
||||||
"uniqueConstraints": {}
|
|
||||||
},
|
|
||||||
"workflow_versions": {
|
|
||||||
"name": "workflow_versions",
|
|
||||||
"schema": "comfyui_deploy",
|
|
||||||
"columns": {
|
|
||||||
"workflow_id": {
|
|
||||||
"name": "workflow_id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"id": {
|
|
||||||
"name": "id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": true,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "gen_random_uuid()"
|
|
||||||
},
|
|
||||||
"workflow": {
|
|
||||||
"name": "workflow",
|
|
||||||
"type": "jsonb",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"workflow_api": {
|
|
||||||
"name": "workflow_api",
|
|
||||||
"type": "jsonb",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"version": {
|
|
||||||
"name": "version",
|
|
||||||
"type": "integer",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"snapshot": {
|
|
||||||
"name": "snapshot",
|
|
||||||
"type": "jsonb",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"created_at": {
|
|
||||||
"name": "created_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
},
|
|
||||||
"updated_at": {
|
|
||||||
"name": "updated_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"indexes": {},
|
|
||||||
"foreignKeys": {
|
|
||||||
"workflow_versions_workflow_id_workflows_id_fk": {
|
|
||||||
"name": "workflow_versions_workflow_id_workflows_id_fk",
|
|
||||||
"tableFrom": "workflow_versions",
|
|
||||||
"tableTo": "workflows",
|
|
||||||
"columnsFrom": [
|
|
||||||
"workflow_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "cascade",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"compositePrimaryKeys": {},
|
|
||||||
"uniqueConstraints": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"enums": {
|
|
||||||
"deployment_environment": {
|
|
||||||
"name": "deployment_environment",
|
|
||||||
"values": {
|
|
||||||
"staging": "staging",
|
|
||||||
"production": "production",
|
|
||||||
"public-share": "public-share"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"machine_gpu": {
|
|
||||||
"name": "machine_gpu",
|
|
||||||
"values": {
|
|
||||||
"T4": "T4",
|
|
||||||
"A10G": "A10G",
|
|
||||||
"A100": "A100"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"machine_status": {
|
|
||||||
"name": "machine_status",
|
|
||||||
"values": {
|
|
||||||
"ready": "ready",
|
|
||||||
"building": "building",
|
|
||||||
"error": "error"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"machine_type": {
|
|
||||||
"name": "machine_type",
|
|
||||||
"values": {
|
|
||||||
"classic": "classic",
|
|
||||||
"runpod-serverless": "runpod-serverless",
|
|
||||||
"modal-serverless": "modal-serverless",
|
|
||||||
"comfy-deploy-serverless": "comfy-deploy-serverless"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"subscription_plan": {
|
|
||||||
"name": "subscription_plan",
|
|
||||||
"values": {
|
|
||||||
"basic": "basic",
|
|
||||||
"pro": "pro",
|
|
||||||
"enterprise": "enterprise"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"subscription_plan_status": {
|
|
||||||
"name": "subscription_plan_status",
|
|
||||||
"values": {
|
|
||||||
"active": "active",
|
|
||||||
"deleted": "deleted",
|
|
||||||
"paused": "paused"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"workflow_run_origin": {
|
|
||||||
"name": "workflow_run_origin",
|
|
||||||
"values": {
|
|
||||||
"manual": "manual",
|
|
||||||
"api": "api",
|
|
||||||
"public-share": "public-share"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"workflow_run_status": {
|
|
||||||
"name": "workflow_run_status",
|
|
||||||
"values": {
|
|
||||||
"not-started": "not-started",
|
|
||||||
"running": "running",
|
|
||||||
"uploading": "uploading",
|
|
||||||
"success": "success",
|
|
||||||
"failed": "failed"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"schemas": {
|
|
||||||
"comfyui_deploy": "comfyui_deploy"
|
|
||||||
},
|
|
||||||
"_meta": {
|
|
||||||
"schemas": {},
|
|
||||||
"tables": {},
|
|
||||||
"columns": {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,984 +0,0 @@
|
|||||||
{
|
|
||||||
"id": "cde8f758-0055-4326-981d-293ac84db54a",
|
|
||||||
"prevId": "4db08fc3-2444-42da-b742-f1832ad8caf1",
|
|
||||||
"version": "5",
|
|
||||||
"dialect": "pg",
|
|
||||||
"tables": {
|
|
||||||
"api_keys": {
|
|
||||||
"name": "api_keys",
|
|
||||||
"schema": "comfyui_deploy",
|
|
||||||
"columns": {
|
|
||||||
"id": {
|
|
||||||
"name": "id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": true,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "gen_random_uuid()"
|
|
||||||
},
|
|
||||||
"key": {
|
|
||||||
"name": "key",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"name": "name",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"user_id": {
|
|
||||||
"name": "user_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"org_id": {
|
|
||||||
"name": "org_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"revoked": {
|
|
||||||
"name": "revoked",
|
|
||||||
"type": "boolean",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
"created_at": {
|
|
||||||
"name": "created_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
},
|
|
||||||
"updated_at": {
|
|
||||||
"name": "updated_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"indexes": {},
|
|
||||||
"foreignKeys": {
|
|
||||||
"api_keys_user_id_users_id_fk": {
|
|
||||||
"name": "api_keys_user_id_users_id_fk",
|
|
||||||
"tableFrom": "api_keys",
|
|
||||||
"tableTo": "users",
|
|
||||||
"columnsFrom": [
|
|
||||||
"user_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "cascade",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"compositePrimaryKeys": {},
|
|
||||||
"uniqueConstraints": {
|
|
||||||
"api_keys_key_unique": {
|
|
||||||
"name": "api_keys_key_unique",
|
|
||||||
"nullsNotDistinct": false,
|
|
||||||
"columns": [
|
|
||||||
"key"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"auth_requests": {
|
|
||||||
"name": "auth_requests",
|
|
||||||
"schema": "comfyui_deploy",
|
|
||||||
"columns": {
|
|
||||||
"request_id": {
|
|
||||||
"name": "request_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": true,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"user_id": {
|
|
||||||
"name": "user_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"org_id": {
|
|
||||||
"name": "org_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"api_hash": {
|
|
||||||
"name": "api_hash",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"created_at": {
|
|
||||||
"name": "created_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
},
|
|
||||||
"expired_date": {
|
|
||||||
"name": "expired_date",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"updated_at": {
|
|
||||||
"name": "updated_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"indexes": {},
|
|
||||||
"foreignKeys": {},
|
|
||||||
"compositePrimaryKeys": {},
|
|
||||||
"uniqueConstraints": {}
|
|
||||||
},
|
|
||||||
"deployments": {
|
|
||||||
"name": "deployments",
|
|
||||||
"schema": "comfyui_deploy",
|
|
||||||
"columns": {
|
|
||||||
"id": {
|
|
||||||
"name": "id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": true,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "gen_random_uuid()"
|
|
||||||
},
|
|
||||||
"user_id": {
|
|
||||||
"name": "user_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"org_id": {
|
|
||||||
"name": "org_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"workflow_version_id": {
|
|
||||||
"name": "workflow_version_id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"workflow_id": {
|
|
||||||
"name": "workflow_id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"machine_id": {
|
|
||||||
"name": "machine_id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"share_slug": {
|
|
||||||
"name": "share_slug",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"description": {
|
|
||||||
"name": "description",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"showcase_media": {
|
|
||||||
"name": "showcase_media",
|
|
||||||
"type": "jsonb",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"environment": {
|
|
||||||
"name": "environment",
|
|
||||||
"type": "deployment_environment",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"created_at": {
|
|
||||||
"name": "created_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
},
|
|
||||||
"updated_at": {
|
|
||||||
"name": "updated_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"indexes": {},
|
|
||||||
"foreignKeys": {
|
|
||||||
"deployments_user_id_users_id_fk": {
|
|
||||||
"name": "deployments_user_id_users_id_fk",
|
|
||||||
"tableFrom": "deployments",
|
|
||||||
"tableTo": "users",
|
|
||||||
"columnsFrom": [
|
|
||||||
"user_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "cascade",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
},
|
|
||||||
"deployments_workflow_version_id_workflow_versions_id_fk": {
|
|
||||||
"name": "deployments_workflow_version_id_workflow_versions_id_fk",
|
|
||||||
"tableFrom": "deployments",
|
|
||||||
"tableTo": "workflow_versions",
|
|
||||||
"columnsFrom": [
|
|
||||||
"workflow_version_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "no action",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
},
|
|
||||||
"deployments_workflow_id_workflows_id_fk": {
|
|
||||||
"name": "deployments_workflow_id_workflows_id_fk",
|
|
||||||
"tableFrom": "deployments",
|
|
||||||
"tableTo": "workflows",
|
|
||||||
"columnsFrom": [
|
|
||||||
"workflow_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "cascade",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
},
|
|
||||||
"deployments_machine_id_machines_id_fk": {
|
|
||||||
"name": "deployments_machine_id_machines_id_fk",
|
|
||||||
"tableFrom": "deployments",
|
|
||||||
"tableTo": "machines",
|
|
||||||
"columnsFrom": [
|
|
||||||
"machine_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "no action",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"compositePrimaryKeys": {},
|
|
||||||
"uniqueConstraints": {
|
|
||||||
"deployments_share_slug_unique": {
|
|
||||||
"name": "deployments_share_slug_unique",
|
|
||||||
"nullsNotDistinct": false,
|
|
||||||
"columns": [
|
|
||||||
"share_slug"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"machines": {
|
|
||||||
"name": "machines",
|
|
||||||
"schema": "comfyui_deploy",
|
|
||||||
"columns": {
|
|
||||||
"id": {
|
|
||||||
"name": "id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": true,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "gen_random_uuid()"
|
|
||||||
},
|
|
||||||
"user_id": {
|
|
||||||
"name": "user_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"name": "name",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"org_id": {
|
|
||||||
"name": "org_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"endpoint": {
|
|
||||||
"name": "endpoint",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"created_at": {
|
|
||||||
"name": "created_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
},
|
|
||||||
"updated_at": {
|
|
||||||
"name": "updated_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
},
|
|
||||||
"disabled": {
|
|
||||||
"name": "disabled",
|
|
||||||
"type": "boolean",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
"auth_token": {
|
|
||||||
"name": "auth_token",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"type": {
|
|
||||||
"name": "type",
|
|
||||||
"type": "machine_type",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "'classic'"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"name": "status",
|
|
||||||
"type": "machine_status",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "'ready'"
|
|
||||||
},
|
|
||||||
"snapshot": {
|
|
||||||
"name": "snapshot",
|
|
||||||
"type": "jsonb",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"models": {
|
|
||||||
"name": "models",
|
|
||||||
"type": "jsonb",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"gpu": {
|
|
||||||
"name": "gpu",
|
|
||||||
"type": "machine_gpu",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"build_machine_instance_id": {
|
|
||||||
"name": "build_machine_instance_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"build_log": {
|
|
||||||
"name": "build_log",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"indexes": {},
|
|
||||||
"foreignKeys": {
|
|
||||||
"machines_user_id_users_id_fk": {
|
|
||||||
"name": "machines_user_id_users_id_fk",
|
|
||||||
"tableFrom": "machines",
|
|
||||||
"tableTo": "users",
|
|
||||||
"columnsFrom": [
|
|
||||||
"user_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "cascade",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"compositePrimaryKeys": {},
|
|
||||||
"uniqueConstraints": {}
|
|
||||||
},
|
|
||||||
"subscription_status": {
|
|
||||||
"name": "subscription_status",
|
|
||||||
"schema": "comfyui_deploy",
|
|
||||||
"columns": {
|
|
||||||
"stripe_customer_id": {
|
|
||||||
"name": "stripe_customer_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": true,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"user_id": {
|
|
||||||
"name": "user_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"org_id": {
|
|
||||||
"name": "org_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"plan": {
|
|
||||||
"name": "plan",
|
|
||||||
"type": "subscription_plan",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"name": "status",
|
|
||||||
"type": "subscription_plan_status",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"subscription_id": {
|
|
||||||
"name": "subscription_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"subscription_item_plan_id": {
|
|
||||||
"name": "subscription_item_plan_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"subscription_item_api_id": {
|
|
||||||
"name": "subscription_item_api_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"created_at": {
|
|
||||||
"name": "created_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
},
|
|
||||||
"updated_at": {
|
|
||||||
"name": "updated_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"indexes": {},
|
|
||||||
"foreignKeys": {},
|
|
||||||
"compositePrimaryKeys": {},
|
|
||||||
"uniqueConstraints": {}
|
|
||||||
},
|
|
||||||
"user_usage": {
|
|
||||||
"name": "user_usage",
|
|
||||||
"schema": "comfyui_deploy",
|
|
||||||
"columns": {
|
|
||||||
"id": {
|
|
||||||
"name": "id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": true,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "gen_random_uuid()"
|
|
||||||
},
|
|
||||||
"org_id": {
|
|
||||||
"name": "org_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"user_id": {
|
|
||||||
"name": "user_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"usage_time": {
|
|
||||||
"name": "usage_time",
|
|
||||||
"type": "real",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": 0
|
|
||||||
},
|
|
||||||
"created_at": {
|
|
||||||
"name": "created_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
},
|
|
||||||
"ended_at": {
|
|
||||||
"name": "ended_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"indexes": {},
|
|
||||||
"foreignKeys": {
|
|
||||||
"user_usage_user_id_users_id_fk": {
|
|
||||||
"name": "user_usage_user_id_users_id_fk",
|
|
||||||
"tableFrom": "user_usage",
|
|
||||||
"tableTo": "users",
|
|
||||||
"columnsFrom": [
|
|
||||||
"user_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "cascade",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"compositePrimaryKeys": {},
|
|
||||||
"uniqueConstraints": {}
|
|
||||||
},
|
|
||||||
"users": {
|
|
||||||
"name": "users",
|
|
||||||
"schema": "comfyui_deploy",
|
|
||||||
"columns": {
|
|
||||||
"id": {
|
|
||||||
"name": "id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": true,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"username": {
|
|
||||||
"name": "username",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"name": "name",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"created_at": {
|
|
||||||
"name": "created_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false,
|
|
||||||
"default": "now()"
|
|
||||||
},
|
|
||||||
"updated_at": {
|
|
||||||
"name": "updated_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false,
|
|
||||||
"default": "now()"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"indexes": {},
|
|
||||||
"foreignKeys": {},
|
|
||||||
"compositePrimaryKeys": {},
|
|
||||||
"uniqueConstraints": {}
|
|
||||||
},
|
|
||||||
"workflow_run_outputs": {
|
|
||||||
"name": "workflow_run_outputs",
|
|
||||||
"schema": "comfyui_deploy",
|
|
||||||
"columns": {
|
|
||||||
"id": {
|
|
||||||
"name": "id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": true,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "gen_random_uuid()"
|
|
||||||
},
|
|
||||||
"run_id": {
|
|
||||||
"name": "run_id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"data": {
|
|
||||||
"name": "data",
|
|
||||||
"type": "jsonb",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"created_at": {
|
|
||||||
"name": "created_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
},
|
|
||||||
"updated_at": {
|
|
||||||
"name": "updated_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"indexes": {},
|
|
||||||
"foreignKeys": {
|
|
||||||
"workflow_run_outputs_run_id_workflow_runs_id_fk": {
|
|
||||||
"name": "workflow_run_outputs_run_id_workflow_runs_id_fk",
|
|
||||||
"tableFrom": "workflow_run_outputs",
|
|
||||||
"tableTo": "workflow_runs",
|
|
||||||
"columnsFrom": [
|
|
||||||
"run_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "cascade",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"compositePrimaryKeys": {},
|
|
||||||
"uniqueConstraints": {}
|
|
||||||
},
|
|
||||||
"workflow_runs": {
|
|
||||||
"name": "workflow_runs",
|
|
||||||
"schema": "comfyui_deploy",
|
|
||||||
"columns": {
|
|
||||||
"id": {
|
|
||||||
"name": "id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": true,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "gen_random_uuid()"
|
|
||||||
},
|
|
||||||
"workflow_version_id": {
|
|
||||||
"name": "workflow_version_id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"workflow_inputs": {
|
|
||||||
"name": "workflow_inputs",
|
|
||||||
"type": "jsonb",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"workflow_id": {
|
|
||||||
"name": "workflow_id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"machine_id": {
|
|
||||||
"name": "machine_id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"origin": {
|
|
||||||
"name": "origin",
|
|
||||||
"type": "workflow_run_origin",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "'api'"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"name": "status",
|
|
||||||
"type": "workflow_run_status",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "'not-started'"
|
|
||||||
},
|
|
||||||
"ended_at": {
|
|
||||||
"name": "ended_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"created_at": {
|
|
||||||
"name": "created_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
},
|
|
||||||
"started_at": {
|
|
||||||
"name": "started_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"indexes": {},
|
|
||||||
"foreignKeys": {
|
|
||||||
"workflow_runs_workflow_version_id_workflow_versions_id_fk": {
|
|
||||||
"name": "workflow_runs_workflow_version_id_workflow_versions_id_fk",
|
|
||||||
"tableFrom": "workflow_runs",
|
|
||||||
"tableTo": "workflow_versions",
|
|
||||||
"columnsFrom": [
|
|
||||||
"workflow_version_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "set null",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
},
|
|
||||||
"workflow_runs_workflow_id_workflows_id_fk": {
|
|
||||||
"name": "workflow_runs_workflow_id_workflows_id_fk",
|
|
||||||
"tableFrom": "workflow_runs",
|
|
||||||
"tableTo": "workflows",
|
|
||||||
"columnsFrom": [
|
|
||||||
"workflow_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "cascade",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
},
|
|
||||||
"workflow_runs_machine_id_machines_id_fk": {
|
|
||||||
"name": "workflow_runs_machine_id_machines_id_fk",
|
|
||||||
"tableFrom": "workflow_runs",
|
|
||||||
"tableTo": "machines",
|
|
||||||
"columnsFrom": [
|
|
||||||
"machine_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "set null",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"compositePrimaryKeys": {},
|
|
||||||
"uniqueConstraints": {}
|
|
||||||
},
|
|
||||||
"workflows": {
|
|
||||||
"name": "workflows",
|
|
||||||
"schema": "comfyui_deploy",
|
|
||||||
"columns": {
|
|
||||||
"id": {
|
|
||||||
"name": "id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": true,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "gen_random_uuid()"
|
|
||||||
},
|
|
||||||
"user_id": {
|
|
||||||
"name": "user_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"org_id": {
|
|
||||||
"name": "org_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"name": "name",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"created_at": {
|
|
||||||
"name": "created_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
},
|
|
||||||
"updated_at": {
|
|
||||||
"name": "updated_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"indexes": {},
|
|
||||||
"foreignKeys": {
|
|
||||||
"workflows_user_id_users_id_fk": {
|
|
||||||
"name": "workflows_user_id_users_id_fk",
|
|
||||||
"tableFrom": "workflows",
|
|
||||||
"tableTo": "users",
|
|
||||||
"columnsFrom": [
|
|
||||||
"user_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "cascade",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"compositePrimaryKeys": {},
|
|
||||||
"uniqueConstraints": {}
|
|
||||||
},
|
|
||||||
"workflow_versions": {
|
|
||||||
"name": "workflow_versions",
|
|
||||||
"schema": "comfyui_deploy",
|
|
||||||
"columns": {
|
|
||||||
"workflow_id": {
|
|
||||||
"name": "workflow_id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"id": {
|
|
||||||
"name": "id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": true,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "gen_random_uuid()"
|
|
||||||
},
|
|
||||||
"workflow": {
|
|
||||||
"name": "workflow",
|
|
||||||
"type": "jsonb",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"workflow_api": {
|
|
||||||
"name": "workflow_api",
|
|
||||||
"type": "jsonb",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"version": {
|
|
||||||
"name": "version",
|
|
||||||
"type": "integer",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"snapshot": {
|
|
||||||
"name": "snapshot",
|
|
||||||
"type": "jsonb",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"created_at": {
|
|
||||||
"name": "created_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
},
|
|
||||||
"updated_at": {
|
|
||||||
"name": "updated_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"indexes": {},
|
|
||||||
"foreignKeys": {
|
|
||||||
"workflow_versions_workflow_id_workflows_id_fk": {
|
|
||||||
"name": "workflow_versions_workflow_id_workflows_id_fk",
|
|
||||||
"tableFrom": "workflow_versions",
|
|
||||||
"tableTo": "workflows",
|
|
||||||
"columnsFrom": [
|
|
||||||
"workflow_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "cascade",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"compositePrimaryKeys": {},
|
|
||||||
"uniqueConstraints": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"enums": {
|
|
||||||
"deployment_environment": {
|
|
||||||
"name": "deployment_environment",
|
|
||||||
"values": {
|
|
||||||
"staging": "staging",
|
|
||||||
"production": "production",
|
|
||||||
"public-share": "public-share"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"machine_gpu": {
|
|
||||||
"name": "machine_gpu",
|
|
||||||
"values": {
|
|
||||||
"T4": "T4",
|
|
||||||
"A10G": "A10G",
|
|
||||||
"A100": "A100"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"machine_status": {
|
|
||||||
"name": "machine_status",
|
|
||||||
"values": {
|
|
||||||
"ready": "ready",
|
|
||||||
"building": "building",
|
|
||||||
"error": "error"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"machine_type": {
|
|
||||||
"name": "machine_type",
|
|
||||||
"values": {
|
|
||||||
"classic": "classic",
|
|
||||||
"runpod-serverless": "runpod-serverless",
|
|
||||||
"modal-serverless": "modal-serverless",
|
|
||||||
"comfy-deploy-serverless": "comfy-deploy-serverless"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"subscription_plan": {
|
|
||||||
"name": "subscription_plan",
|
|
||||||
"values": {
|
|
||||||
"basic": "basic",
|
|
||||||
"pro": "pro",
|
|
||||||
"enterprise": "enterprise"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"subscription_plan_status": {
|
|
||||||
"name": "subscription_plan_status",
|
|
||||||
"values": {
|
|
||||||
"active": "active",
|
|
||||||
"deleted": "deleted",
|
|
||||||
"paused": "paused"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"workflow_run_origin": {
|
|
||||||
"name": "workflow_run_origin",
|
|
||||||
"values": {
|
|
||||||
"manual": "manual",
|
|
||||||
"api": "api",
|
|
||||||
"public-share": "public-share"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"workflow_run_status": {
|
|
||||||
"name": "workflow_run_status",
|
|
||||||
"values": {
|
|
||||||
"not-started": "not-started",
|
|
||||||
"running": "running",
|
|
||||||
"uploading": "uploading",
|
|
||||||
"success": "success",
|
|
||||||
"failed": "failed"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"schemas": {
|
|
||||||
"comfyui_deploy": "comfyui_deploy"
|
|
||||||
},
|
|
||||||
"_meta": {
|
|
||||||
"schemas": {},
|
|
||||||
"tables": {},
|
|
||||||
"columns": {
|
|
||||||
"\"comfyui_deploy\".\"subscription_status\".\"subscription_plan_id\"": "\"comfyui_deploy\".\"subscription_status\".\"subscription_id\""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,989 +0,0 @@
|
|||||||
{
|
|
||||||
"id": "bd893271-b9ea-4832-a3e8-a6970b9f20d9",
|
|
||||||
"prevId": "cde8f758-0055-4326-981d-293ac84db54a",
|
|
||||||
"version": "5",
|
|
||||||
"dialect": "pg",
|
|
||||||
"tables": {
|
|
||||||
"api_keys": {
|
|
||||||
"name": "api_keys",
|
|
||||||
"schema": "comfyui_deploy",
|
|
||||||
"columns": {
|
|
||||||
"id": {
|
|
||||||
"name": "id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": true,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "gen_random_uuid()"
|
|
||||||
},
|
|
||||||
"key": {
|
|
||||||
"name": "key",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"name": "name",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"user_id": {
|
|
||||||
"name": "user_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"org_id": {
|
|
||||||
"name": "org_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"revoked": {
|
|
||||||
"name": "revoked",
|
|
||||||
"type": "boolean",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
"created_at": {
|
|
||||||
"name": "created_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
},
|
|
||||||
"updated_at": {
|
|
||||||
"name": "updated_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"indexes": {},
|
|
||||||
"foreignKeys": {
|
|
||||||
"api_keys_user_id_users_id_fk": {
|
|
||||||
"name": "api_keys_user_id_users_id_fk",
|
|
||||||
"tableFrom": "api_keys",
|
|
||||||
"tableTo": "users",
|
|
||||||
"columnsFrom": [
|
|
||||||
"user_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "cascade",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"compositePrimaryKeys": {},
|
|
||||||
"uniqueConstraints": {
|
|
||||||
"api_keys_key_unique": {
|
|
||||||
"name": "api_keys_key_unique",
|
|
||||||
"nullsNotDistinct": false,
|
|
||||||
"columns": [
|
|
||||||
"key"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"auth_requests": {
|
|
||||||
"name": "auth_requests",
|
|
||||||
"schema": "comfyui_deploy",
|
|
||||||
"columns": {
|
|
||||||
"request_id": {
|
|
||||||
"name": "request_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": true,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"user_id": {
|
|
||||||
"name": "user_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"org_id": {
|
|
||||||
"name": "org_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"api_hash": {
|
|
||||||
"name": "api_hash",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"created_at": {
|
|
||||||
"name": "created_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
},
|
|
||||||
"expired_date": {
|
|
||||||
"name": "expired_date",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"updated_at": {
|
|
||||||
"name": "updated_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"indexes": {},
|
|
||||||
"foreignKeys": {},
|
|
||||||
"compositePrimaryKeys": {},
|
|
||||||
"uniqueConstraints": {}
|
|
||||||
},
|
|
||||||
"deployments": {
|
|
||||||
"name": "deployments",
|
|
||||||
"schema": "comfyui_deploy",
|
|
||||||
"columns": {
|
|
||||||
"id": {
|
|
||||||
"name": "id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": true,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "gen_random_uuid()"
|
|
||||||
},
|
|
||||||
"user_id": {
|
|
||||||
"name": "user_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"org_id": {
|
|
||||||
"name": "org_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"workflow_version_id": {
|
|
||||||
"name": "workflow_version_id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"workflow_id": {
|
|
||||||
"name": "workflow_id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"machine_id": {
|
|
||||||
"name": "machine_id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"share_slug": {
|
|
||||||
"name": "share_slug",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"description": {
|
|
||||||
"name": "description",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"showcase_media": {
|
|
||||||
"name": "showcase_media",
|
|
||||||
"type": "jsonb",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"environment": {
|
|
||||||
"name": "environment",
|
|
||||||
"type": "deployment_environment",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"created_at": {
|
|
||||||
"name": "created_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
},
|
|
||||||
"updated_at": {
|
|
||||||
"name": "updated_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"indexes": {},
|
|
||||||
"foreignKeys": {
|
|
||||||
"deployments_user_id_users_id_fk": {
|
|
||||||
"name": "deployments_user_id_users_id_fk",
|
|
||||||
"tableFrom": "deployments",
|
|
||||||
"tableTo": "users",
|
|
||||||
"columnsFrom": [
|
|
||||||
"user_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "cascade",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
},
|
|
||||||
"deployments_workflow_version_id_workflow_versions_id_fk": {
|
|
||||||
"name": "deployments_workflow_version_id_workflow_versions_id_fk",
|
|
||||||
"tableFrom": "deployments",
|
|
||||||
"tableTo": "workflow_versions",
|
|
||||||
"columnsFrom": [
|
|
||||||
"workflow_version_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "no action",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
},
|
|
||||||
"deployments_workflow_id_workflows_id_fk": {
|
|
||||||
"name": "deployments_workflow_id_workflows_id_fk",
|
|
||||||
"tableFrom": "deployments",
|
|
||||||
"tableTo": "workflows",
|
|
||||||
"columnsFrom": [
|
|
||||||
"workflow_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "cascade",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
},
|
|
||||||
"deployments_machine_id_machines_id_fk": {
|
|
||||||
"name": "deployments_machine_id_machines_id_fk",
|
|
||||||
"tableFrom": "deployments",
|
|
||||||
"tableTo": "machines",
|
|
||||||
"columnsFrom": [
|
|
||||||
"machine_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "no action",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"compositePrimaryKeys": {},
|
|
||||||
"uniqueConstraints": {
|
|
||||||
"deployments_share_slug_unique": {
|
|
||||||
"name": "deployments_share_slug_unique",
|
|
||||||
"nullsNotDistinct": false,
|
|
||||||
"columns": [
|
|
||||||
"share_slug"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"machines": {
|
|
||||||
"name": "machines",
|
|
||||||
"schema": "comfyui_deploy",
|
|
||||||
"columns": {
|
|
||||||
"id": {
|
|
||||||
"name": "id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": true,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "gen_random_uuid()"
|
|
||||||
},
|
|
||||||
"user_id": {
|
|
||||||
"name": "user_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"name": "name",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"org_id": {
|
|
||||||
"name": "org_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"endpoint": {
|
|
||||||
"name": "endpoint",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"created_at": {
|
|
||||||
"name": "created_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
},
|
|
||||||
"updated_at": {
|
|
||||||
"name": "updated_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
},
|
|
||||||
"disabled": {
|
|
||||||
"name": "disabled",
|
|
||||||
"type": "boolean",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
"auth_token": {
|
|
||||||
"name": "auth_token",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"type": {
|
|
||||||
"name": "type",
|
|
||||||
"type": "machine_type",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "'classic'"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"name": "status",
|
|
||||||
"type": "machine_status",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "'ready'"
|
|
||||||
},
|
|
||||||
"snapshot": {
|
|
||||||
"name": "snapshot",
|
|
||||||
"type": "jsonb",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"models": {
|
|
||||||
"name": "models",
|
|
||||||
"type": "jsonb",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"gpu": {
|
|
||||||
"name": "gpu",
|
|
||||||
"type": "machine_gpu",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"build_machine_instance_id": {
|
|
||||||
"name": "build_machine_instance_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"build_log": {
|
|
||||||
"name": "build_log",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"indexes": {},
|
|
||||||
"foreignKeys": {
|
|
||||||
"machines_user_id_users_id_fk": {
|
|
||||||
"name": "machines_user_id_users_id_fk",
|
|
||||||
"tableFrom": "machines",
|
|
||||||
"tableTo": "users",
|
|
||||||
"columnsFrom": [
|
|
||||||
"user_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "cascade",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"compositePrimaryKeys": {},
|
|
||||||
"uniqueConstraints": {}
|
|
||||||
},
|
|
||||||
"subscription_status": {
|
|
||||||
"name": "subscription_status",
|
|
||||||
"schema": "comfyui_deploy",
|
|
||||||
"columns": {
|
|
||||||
"stripe_customer_id": {
|
|
||||||
"name": "stripe_customer_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": true,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"user_id": {
|
|
||||||
"name": "user_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"org_id": {
|
|
||||||
"name": "org_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"plan": {
|
|
||||||
"name": "plan",
|
|
||||||
"type": "subscription_plan",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"name": "status",
|
|
||||||
"type": "subscription_plan_status",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"subscription_id": {
|
|
||||||
"name": "subscription_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"subscription_item_plan_id": {
|
|
||||||
"name": "subscription_item_plan_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"subscription_item_api_id": {
|
|
||||||
"name": "subscription_item_api_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"cancel_at_period_end": {
|
|
||||||
"name": "cancel_at_period_end",
|
|
||||||
"type": "boolean",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false,
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
"created_at": {
|
|
||||||
"name": "created_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
},
|
|
||||||
"updated_at": {
|
|
||||||
"name": "updated_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"indexes": {},
|
|
||||||
"foreignKeys": {},
|
|
||||||
"compositePrimaryKeys": {},
|
|
||||||
"uniqueConstraints": {}
|
|
||||||
},
|
|
||||||
"user_usage": {
|
|
||||||
"name": "user_usage",
|
|
||||||
"schema": "comfyui_deploy",
|
|
||||||
"columns": {
|
|
||||||
"id": {
|
|
||||||
"name": "id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": true,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "gen_random_uuid()"
|
|
||||||
},
|
|
||||||
"org_id": {
|
|
||||||
"name": "org_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"user_id": {
|
|
||||||
"name": "user_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"usage_time": {
|
|
||||||
"name": "usage_time",
|
|
||||||
"type": "real",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": 0
|
|
||||||
},
|
|
||||||
"created_at": {
|
|
||||||
"name": "created_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
},
|
|
||||||
"ended_at": {
|
|
||||||
"name": "ended_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"indexes": {},
|
|
||||||
"foreignKeys": {
|
|
||||||
"user_usage_user_id_users_id_fk": {
|
|
||||||
"name": "user_usage_user_id_users_id_fk",
|
|
||||||
"tableFrom": "user_usage",
|
|
||||||
"tableTo": "users",
|
|
||||||
"columnsFrom": [
|
|
||||||
"user_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "cascade",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"compositePrimaryKeys": {},
|
|
||||||
"uniqueConstraints": {}
|
|
||||||
},
|
|
||||||
"users": {
|
|
||||||
"name": "users",
|
|
||||||
"schema": "comfyui_deploy",
|
|
||||||
"columns": {
|
|
||||||
"id": {
|
|
||||||
"name": "id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": true,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"username": {
|
|
||||||
"name": "username",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"name": "name",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"created_at": {
|
|
||||||
"name": "created_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false,
|
|
||||||
"default": "now()"
|
|
||||||
},
|
|
||||||
"updated_at": {
|
|
||||||
"name": "updated_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false,
|
|
||||||
"default": "now()"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"indexes": {},
|
|
||||||
"foreignKeys": {},
|
|
||||||
"compositePrimaryKeys": {},
|
|
||||||
"uniqueConstraints": {}
|
|
||||||
},
|
|
||||||
"workflow_run_outputs": {
|
|
||||||
"name": "workflow_run_outputs",
|
|
||||||
"schema": "comfyui_deploy",
|
|
||||||
"columns": {
|
|
||||||
"id": {
|
|
||||||
"name": "id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": true,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "gen_random_uuid()"
|
|
||||||
},
|
|
||||||
"run_id": {
|
|
||||||
"name": "run_id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"data": {
|
|
||||||
"name": "data",
|
|
||||||
"type": "jsonb",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"created_at": {
|
|
||||||
"name": "created_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
},
|
|
||||||
"updated_at": {
|
|
||||||
"name": "updated_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"indexes": {},
|
|
||||||
"foreignKeys": {
|
|
||||||
"workflow_run_outputs_run_id_workflow_runs_id_fk": {
|
|
||||||
"name": "workflow_run_outputs_run_id_workflow_runs_id_fk",
|
|
||||||
"tableFrom": "workflow_run_outputs",
|
|
||||||
"tableTo": "workflow_runs",
|
|
||||||
"columnsFrom": [
|
|
||||||
"run_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "cascade",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"compositePrimaryKeys": {},
|
|
||||||
"uniqueConstraints": {}
|
|
||||||
},
|
|
||||||
"workflow_runs": {
|
|
||||||
"name": "workflow_runs",
|
|
||||||
"schema": "comfyui_deploy",
|
|
||||||
"columns": {
|
|
||||||
"id": {
|
|
||||||
"name": "id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": true,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "gen_random_uuid()"
|
|
||||||
},
|
|
||||||
"workflow_version_id": {
|
|
||||||
"name": "workflow_version_id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"workflow_inputs": {
|
|
||||||
"name": "workflow_inputs",
|
|
||||||
"type": "jsonb",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"workflow_id": {
|
|
||||||
"name": "workflow_id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"machine_id": {
|
|
||||||
"name": "machine_id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"origin": {
|
|
||||||
"name": "origin",
|
|
||||||
"type": "workflow_run_origin",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "'api'"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"name": "status",
|
|
||||||
"type": "workflow_run_status",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "'not-started'"
|
|
||||||
},
|
|
||||||
"ended_at": {
|
|
||||||
"name": "ended_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"created_at": {
|
|
||||||
"name": "created_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
},
|
|
||||||
"started_at": {
|
|
||||||
"name": "started_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"indexes": {},
|
|
||||||
"foreignKeys": {
|
|
||||||
"workflow_runs_workflow_version_id_workflow_versions_id_fk": {
|
|
||||||
"name": "workflow_runs_workflow_version_id_workflow_versions_id_fk",
|
|
||||||
"tableFrom": "workflow_runs",
|
|
||||||
"tableTo": "workflow_versions",
|
|
||||||
"columnsFrom": [
|
|
||||||
"workflow_version_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "set null",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
},
|
|
||||||
"workflow_runs_workflow_id_workflows_id_fk": {
|
|
||||||
"name": "workflow_runs_workflow_id_workflows_id_fk",
|
|
||||||
"tableFrom": "workflow_runs",
|
|
||||||
"tableTo": "workflows",
|
|
||||||
"columnsFrom": [
|
|
||||||
"workflow_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "cascade",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
},
|
|
||||||
"workflow_runs_machine_id_machines_id_fk": {
|
|
||||||
"name": "workflow_runs_machine_id_machines_id_fk",
|
|
||||||
"tableFrom": "workflow_runs",
|
|
||||||
"tableTo": "machines",
|
|
||||||
"columnsFrom": [
|
|
||||||
"machine_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "set null",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"compositePrimaryKeys": {},
|
|
||||||
"uniqueConstraints": {}
|
|
||||||
},
|
|
||||||
"workflows": {
|
|
||||||
"name": "workflows",
|
|
||||||
"schema": "comfyui_deploy",
|
|
||||||
"columns": {
|
|
||||||
"id": {
|
|
||||||
"name": "id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": true,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "gen_random_uuid()"
|
|
||||||
},
|
|
||||||
"user_id": {
|
|
||||||
"name": "user_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"org_id": {
|
|
||||||
"name": "org_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"name": "name",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"created_at": {
|
|
||||||
"name": "created_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
},
|
|
||||||
"updated_at": {
|
|
||||||
"name": "updated_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"indexes": {},
|
|
||||||
"foreignKeys": {
|
|
||||||
"workflows_user_id_users_id_fk": {
|
|
||||||
"name": "workflows_user_id_users_id_fk",
|
|
||||||
"tableFrom": "workflows",
|
|
||||||
"tableTo": "users",
|
|
||||||
"columnsFrom": [
|
|
||||||
"user_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "cascade",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"compositePrimaryKeys": {},
|
|
||||||
"uniqueConstraints": {}
|
|
||||||
},
|
|
||||||
"workflow_versions": {
|
|
||||||
"name": "workflow_versions",
|
|
||||||
"schema": "comfyui_deploy",
|
|
||||||
"columns": {
|
|
||||||
"workflow_id": {
|
|
||||||
"name": "workflow_id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"id": {
|
|
||||||
"name": "id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": true,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "gen_random_uuid()"
|
|
||||||
},
|
|
||||||
"workflow": {
|
|
||||||
"name": "workflow",
|
|
||||||
"type": "jsonb",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"workflow_api": {
|
|
||||||
"name": "workflow_api",
|
|
||||||
"type": "jsonb",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"version": {
|
|
||||||
"name": "version",
|
|
||||||
"type": "integer",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"snapshot": {
|
|
||||||
"name": "snapshot",
|
|
||||||
"type": "jsonb",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"created_at": {
|
|
||||||
"name": "created_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
},
|
|
||||||
"updated_at": {
|
|
||||||
"name": "updated_at",
|
|
||||||
"type": "timestamp",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true,
|
|
||||||
"default": "now()"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"indexes": {},
|
|
||||||
"foreignKeys": {
|
|
||||||
"workflow_versions_workflow_id_workflows_id_fk": {
|
|
||||||
"name": "workflow_versions_workflow_id_workflows_id_fk",
|
|
||||||
"tableFrom": "workflow_versions",
|
|
||||||
"tableTo": "workflows",
|
|
||||||
"columnsFrom": [
|
|
||||||
"workflow_id"
|
|
||||||
],
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onDelete": "cascade",
|
|
||||||
"onUpdate": "no action"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"compositePrimaryKeys": {},
|
|
||||||
"uniqueConstraints": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"enums": {
|
|
||||||
"deployment_environment": {
|
|
||||||
"name": "deployment_environment",
|
|
||||||
"values": {
|
|
||||||
"staging": "staging",
|
|
||||||
"production": "production",
|
|
||||||
"public-share": "public-share"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"machine_gpu": {
|
|
||||||
"name": "machine_gpu",
|
|
||||||
"values": {
|
|
||||||
"T4": "T4",
|
|
||||||
"A10G": "A10G",
|
|
||||||
"A100": "A100"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"machine_status": {
|
|
||||||
"name": "machine_status",
|
|
||||||
"values": {
|
|
||||||
"ready": "ready",
|
|
||||||
"building": "building",
|
|
||||||
"error": "error"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"machine_type": {
|
|
||||||
"name": "machine_type",
|
|
||||||
"values": {
|
|
||||||
"classic": "classic",
|
|
||||||
"runpod-serverless": "runpod-serverless",
|
|
||||||
"modal-serverless": "modal-serverless",
|
|
||||||
"comfy-deploy-serverless": "comfy-deploy-serverless"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"subscription_plan": {
|
|
||||||
"name": "subscription_plan",
|
|
||||||
"values": {
|
|
||||||
"basic": "basic",
|
|
||||||
"pro": "pro",
|
|
||||||
"enterprise": "enterprise"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"subscription_plan_status": {
|
|
||||||
"name": "subscription_plan_status",
|
|
||||||
"values": {
|
|
||||||
"active": "active",
|
|
||||||
"deleted": "deleted",
|
|
||||||
"paused": "paused"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"workflow_run_origin": {
|
|
||||||
"name": "workflow_run_origin",
|
|
||||||
"values": {
|
|
||||||
"manual": "manual",
|
|
||||||
"api": "api",
|
|
||||||
"public-share": "public-share"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"workflow_run_status": {
|
|
||||||
"name": "workflow_run_status",
|
|
||||||
"values": {
|
|
||||||
"not-started": "not-started",
|
|
||||||
"running": "running",
|
|
||||||
"uploading": "uploading",
|
|
||||||
"success": "success",
|
|
||||||
"failed": "failed"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"schemas": {
|
|
||||||
"comfyui_deploy": "comfyui_deploy"
|
|
||||||
},
|
|
||||||
"_meta": {
|
|
||||||
"schemas": {},
|
|
||||||
"tables": {},
|
|
||||||
"columns": {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -246,111 +246,6 @@
|
|||||||
"when": 1705902960991,
|
"when": 1705902960991,
|
||||||
"tag": "0034_even_lady_ursula",
|
"tag": "0034_even_lady_ursula",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
|
||||||
{
|
|
||||||
"idx": 35,
|
|
||||||
"version": "5",
|
|
||||||
"when": 1705981452482,
|
|
||||||
"tag": "0035_fearless_golden_guardian",
|
|
||||||
"breakpoints": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idx": 36,
|
|
||||||
"version": "5",
|
|
||||||
"when": 1706081335387,
|
|
||||||
"tag": "0036_flippant_meltdown",
|
|
||||||
"breakpoints": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idx": 37,
|
|
||||||
"version": "5",
|
|
||||||
"when": 1706086271525,
|
|
||||||
"tag": "0037_eager_cyclops",
|
|
||||||
"breakpoints": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idx": 38,
|
|
||||||
"version": "5",
|
|
||||||
"when": 1706095853896,
|
|
||||||
"tag": "0038_yummy_darkhawk",
|
|
||||||
"breakpoints": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idx": 39,
|
|
||||||
"version": "5",
|
|
||||||
"when": 1706109812261,
|
|
||||||
"tag": "0039_nostalgic_lyja",
|
|
||||||
"breakpoints": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idx": 40,
|
|
||||||
"version": "5",
|
|
||||||
"when": 1706110859352,
|
|
||||||
"tag": "0040_salty_archangel",
|
|
||||||
"breakpoints": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idx": 41,
|
|
||||||
"version": "5",
|
|
||||||
"when": 1706111421524,
|
|
||||||
"tag": "0041_thick_norrin_radd",
|
|
||||||
"breakpoints": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idx": 42,
|
|
||||||
"version": "5",
|
|
||||||
"when": 1706164614659,
|
|
||||||
"tag": "0042_windy_madelyne_pryor",
|
|
||||||
"breakpoints": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idx": 43,
|
|
||||||
"version": "5",
|
|
||||||
"when": 1706241449348,
|
|
||||||
"tag": "0043_wealthy_nicolaos",
|
|
||||||
"breakpoints": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idx": 44,
|
|
||||||
"version": "5",
|
|
||||||
"when": 1706317908300,
|
|
||||||
"tag": "0044_panoramic_mister_fear",
|
|
||||||
"breakpoints": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idx": 45,
|
|
||||||
"version": "5",
|
|
||||||
"when": 1706336448134,
|
|
||||||
"tag": "0045_careful_cerise",
|
|
||||||
"breakpoints": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idx": 46,
|
|
||||||
"version": "5",
|
|
||||||
"when": 1706383154642,
|
|
||||||
"tag": "0046_complex_mentallo",
|
|
||||||
"breakpoints": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idx": 47,
|
|
||||||
"version": "5",
|
|
||||||
"when": 1706384528895,
|
|
||||||
"tag": "0047_gifted_starbolt",
|
|
||||||
"breakpoints": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idx": 48,
|
|
||||||
"version": "5",
|
|
||||||
"when": 1706600255919,
|
|
||||||
"tag": "0048_dear_korath",
|
|
||||||
"breakpoints": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idx": 49,
|
|
||||||
"version": "5",
|
|
||||||
"when": 1706631744127,
|
|
||||||
"tag": "0049_sweet_hex",
|
|
||||||
"breakpoints": true
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
+1
-6
@@ -19,26 +19,23 @@
|
|||||||
"@algolia/autocomplete-core": "^1.13.0",
|
"@algolia/autocomplete-core": "^1.13.0",
|
||||||
"@aws-sdk/client-s3": "^3.472.0",
|
"@aws-sdk/client-s3": "^3.472.0",
|
||||||
"@aws-sdk/s3-request-presigner": "^3.472.0",
|
"@aws-sdk/s3-request-presigner": "^3.472.0",
|
||||||
"@clerk/nextjs": "4.29.5",
|
"@clerk/nextjs": "^4.29.3",
|
||||||
"@headlessui/react": "^1.7.17",
|
"@headlessui/react": "^1.7.17",
|
||||||
"@headlessui/tailwindcss": "^0.2.0",
|
"@headlessui/tailwindcss": "^0.2.0",
|
||||||
"@hono/swagger-ui": "^0.2.1",
|
"@hono/swagger-ui": "^0.2.1",
|
||||||
"@hono/zod-openapi": "^0.9.5",
|
"@hono/zod-openapi": "^0.9.5",
|
||||||
"@hono/zod-validator": "^0.1.11",
|
"@hono/zod-validator": "^0.1.11",
|
||||||
"@hookform/resolvers": "^3.3.2",
|
"@hookform/resolvers": "^3.3.2",
|
||||||
"@lemonsqueezy/lemonsqueezy.js": "^1.2.5",
|
|
||||||
"@mdx-js/loader": "^3.0.0",
|
"@mdx-js/loader": "^3.0.0",
|
||||||
"@mdx-js/react": "^3.0.0",
|
"@mdx-js/react": "^3.0.0",
|
||||||
"@neondatabase/serverless": "^0.6.0",
|
"@neondatabase/serverless": "^0.6.0",
|
||||||
"@next/mdx": "^14.0.4",
|
"@next/mdx": "^14.0.4",
|
||||||
"@radix-ui/react-accordion": "^1.1.2",
|
"@radix-ui/react-accordion": "^1.1.2",
|
||||||
"@radix-ui/react-alert-dialog": "^1.0.5",
|
|
||||||
"@radix-ui/react-checkbox": "^1.0.4",
|
"@radix-ui/react-checkbox": "^1.0.4",
|
||||||
"@radix-ui/react-dialog": "^1.0.5",
|
"@radix-ui/react-dialog": "^1.0.5",
|
||||||
"@radix-ui/react-dropdown-menu": "^2.0.6",
|
"@radix-ui/react-dropdown-menu": "^2.0.6",
|
||||||
"@radix-ui/react-label": "^2.0.2",
|
"@radix-ui/react-label": "^2.0.2",
|
||||||
"@radix-ui/react-popover": "^1.0.7",
|
"@radix-ui/react-popover": "^1.0.7",
|
||||||
"@radix-ui/react-progress": "^1.0.3",
|
|
||||||
"@radix-ui/react-radio-group": "^1.1.3",
|
"@radix-ui/react-radio-group": "^1.1.3",
|
||||||
"@radix-ui/react-scroll-area": "^1.0.5",
|
"@radix-ui/react-scroll-area": "^1.0.5",
|
||||||
"@radix-ui/react-select": "^2.0.0",
|
"@radix-ui/react-select": "^2.0.0",
|
||||||
@@ -49,7 +46,6 @@
|
|||||||
"@radix-ui/react-toggle": "^1.0.3",
|
"@radix-ui/react-toggle": "^1.0.3",
|
||||||
"@radix-ui/react-tooltip": "^1.0.7",
|
"@radix-ui/react-tooltip": "^1.0.7",
|
||||||
"@sindresorhus/slugify": "^2.2.1",
|
"@sindresorhus/slugify": "^2.2.1",
|
||||||
"@stripe/stripe-js": "^2.4.0",
|
|
||||||
"@tailwindcss/typography": "^0.5.10",
|
"@tailwindcss/typography": "^0.5.10",
|
||||||
"@tanstack/react-table": "^8.10.7",
|
"@tanstack/react-table": "^8.10.7",
|
||||||
"@tanstack/react-virtual": "beta",
|
"@tanstack/react-virtual": "beta",
|
||||||
@@ -98,7 +94,6 @@
|
|||||||
"shikiji": "^0.9.3",
|
"shikiji": "^0.9.3",
|
||||||
"simple-functional-loader": "^1.2.1",
|
"simple-functional-loader": "^1.2.1",
|
||||||
"sonner": "^1.2.4",
|
"sonner": "^1.2.4",
|
||||||
"stripe": "^14.13.0",
|
|
||||||
"swagger-ui-react": "^5.11.0",
|
"swagger-ui-react": "^5.11.0",
|
||||||
"swr": "^2.2.4",
|
"swr": "^2.2.4",
|
||||||
"tailwind-merge": "^2.1.0",
|
"tailwind-merge": "^2.1.0",
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 29 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 29 KiB |
@@ -1,175 +0,0 @@
|
|||||||
import { auth, clerkClient } from "@clerk/nextjs";
|
|
||||||
import { headers } from "next/headers";
|
|
||||||
import { redirect } from "next/navigation";
|
|
||||||
import { stripe } from "../../../../../server/stripe";
|
|
||||||
import { NextResponse } from "next/server";
|
|
||||||
import { db } from "@/db/db";
|
|
||||||
import { subscriptionStatusTable } from "@/db/schema";
|
|
||||||
import { eq } from "drizzle-orm";
|
|
||||||
|
|
||||||
const secret = process.env.STRIPE_WEBHOOK_SECRET || "";
|
|
||||||
|
|
||||||
export async function POST(req: Request) {
|
|
||||||
try {
|
|
||||||
const body = await req.text();
|
|
||||||
|
|
||||||
const signature = headers().get("stripe-signature");
|
|
||||||
|
|
||||||
if (!signature)
|
|
||||||
return new NextResponse("Signature not found.", {
|
|
||||||
status: 500,
|
|
||||||
});
|
|
||||||
|
|
||||||
const event = stripe.webhooks.constructEvent(body, signature, secret);
|
|
||||||
|
|
||||||
console.log(event);
|
|
||||||
|
|
||||||
if (event.type === "checkout.session.completed") {
|
|
||||||
if (!event.data.object.customer_details?.email) {
|
|
||||||
throw new Error(`missing user email, ${event.id}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const userId = event.data.object.metadata?.userId;
|
|
||||||
const plan = event.data.object.metadata?.plan;
|
|
||||||
if (!userId) {
|
|
||||||
throw new Error(`missing itinerary_id on metadata, ${event.id}`);
|
|
||||||
}
|
|
||||||
if (!plan) {
|
|
||||||
throw new Error(`missing plan on metadata, ${event.id}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const orgId = event.data.object.metadata?.orgId;
|
|
||||||
|
|
||||||
const customerId =
|
|
||||||
typeof event.data.object.customer == "string"
|
|
||||||
? event.data.object.customer
|
|
||||||
: event.data.object.customer?.id;
|
|
||||||
const subscriptionId =
|
|
||||||
typeof event.data.object.subscription == "string"
|
|
||||||
? event.data.object.subscription
|
|
||||||
: event.data.object.subscription?.id;
|
|
||||||
|
|
||||||
if (!customerId) {
|
|
||||||
throw new Error(`missing customerId, ${event.id}`);
|
|
||||||
}
|
|
||||||
if (!subscriptionId) {
|
|
||||||
throw new Error(`missing subscriptionId, ${event.id}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const items = await stripe.subscriptionItems.list({
|
|
||||||
subscription: subscriptionId,
|
|
||||||
limit: 5,
|
|
||||||
});
|
|
||||||
|
|
||||||
// getting the subscription item id for the api plan
|
|
||||||
const subscription_item_api_id = items.data.find(
|
|
||||||
(x) => x.price.id === process.env.STRIPE_PR_API,
|
|
||||||
)?.id;
|
|
||||||
|
|
||||||
// the plan could be either pro or enterprise
|
|
||||||
const subscription_item_plan_id =
|
|
||||||
items.data.find((x) => x.price.id === process.env.STRIPE_PR_PRO)?.id ??
|
|
||||||
items.data.find((x) => x.price.id === process.env.STRIPE_PR_ENTERPRISE)
|
|
||||||
?.id;
|
|
||||||
|
|
||||||
if (!subscription_item_api_id) {
|
|
||||||
throw new Error(
|
|
||||||
`missing plan on subscription_item_api_id, ${event.id}`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (!subscription_item_plan_id) {
|
|
||||||
throw new Error(
|
|
||||||
`missing plan on subscription_item_plan_id, ${event.id}`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(items);
|
|
||||||
|
|
||||||
await db
|
|
||||||
.insert(subscriptionStatusTable)
|
|
||||||
.values({
|
|
||||||
stripe_customer_id: customerId,
|
|
||||||
org_id: orgId && orgId.length > 0 && orgId != "null" ? orgId : null,
|
|
||||||
user_id: userId,
|
|
||||||
subscription_id: subscriptionId,
|
|
||||||
plan: plan as "pro" | "enterprise" | "basic",
|
|
||||||
status: "active",
|
|
||||||
subscription_item_api_id: subscription_item_api_id,
|
|
||||||
subscription_item_plan_id: subscription_item_plan_id,
|
|
||||||
})
|
|
||||||
.onConflictDoNothing();
|
|
||||||
|
|
||||||
// updateDatabase(event.data.object.metadata.itinerary_id);
|
|
||||||
// sendEmail(event.data.object.customer_details.email);
|
|
||||||
} else if (event.type === "customer.subscription.paused") {
|
|
||||||
const customerId =
|
|
||||||
typeof event.data.object.customer == "string"
|
|
||||||
? event.data.object.customer
|
|
||||||
: event.data.object.customer?.id;
|
|
||||||
|
|
||||||
if (!customerId) {
|
|
||||||
throw new Error(`missing customerId, ${event.id}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
await db
|
|
||||||
.update(subscriptionStatusTable)
|
|
||||||
.set({ status: "paused" })
|
|
||||||
.where(eq(subscriptionStatusTable.stripe_customer_id, customerId));
|
|
||||||
} else if (event.type === "customer.subscription.resumed") {
|
|
||||||
const customerId =
|
|
||||||
typeof event.data.object.customer == "string"
|
|
||||||
? event.data.object.customer
|
|
||||||
: event.data.object.customer?.id;
|
|
||||||
|
|
||||||
if (!customerId) {
|
|
||||||
throw new Error(`missing customerId, ${event.id}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
await db
|
|
||||||
.update(subscriptionStatusTable)
|
|
||||||
.set({ status: "active" })
|
|
||||||
.where(eq(subscriptionStatusTable.stripe_customer_id, customerId));
|
|
||||||
} else if (event.type === "customer.subscription.deleted") {
|
|
||||||
const customerId =
|
|
||||||
typeof event.data.object.customer == "string"
|
|
||||||
? event.data.object.customer
|
|
||||||
: event.data.object.customer?.id;
|
|
||||||
|
|
||||||
if (!customerId) {
|
|
||||||
throw new Error(`missing customerId, ${event.id}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
await db
|
|
||||||
.update(subscriptionStatusTable)
|
|
||||||
.set({ status: "deleted" })
|
|
||||||
.where(eq(subscriptionStatusTable.stripe_customer_id, customerId));
|
|
||||||
} else if (event.type === "customer.subscription.updated") {
|
|
||||||
const customerId =
|
|
||||||
typeof event.data.object.customer == "string"
|
|
||||||
? event.data.object.customer
|
|
||||||
: event.data.object.customer?.id;
|
|
||||||
|
|
||||||
if (!customerId) {
|
|
||||||
throw new Error(`missing customerId, ${event.id}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const cancel_at_period_end = event.data.object.cancel_at_period_end;
|
|
||||||
|
|
||||||
await db
|
|
||||||
.update(subscriptionStatusTable)
|
|
||||||
.set({ cancel_at_period_end: cancel_at_period_end })
|
|
||||||
.where(eq(subscriptionStatusTable.stripe_customer_id, customerId));
|
|
||||||
}
|
|
||||||
|
|
||||||
return NextResponse.json({ result: event, ok: true });
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
return NextResponse.json(
|
|
||||||
{
|
|
||||||
message: `Something went wrong: ${error}`,
|
|
||||||
ok: false,
|
|
||||||
},
|
|
||||||
{ status: 500 },
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
import { stripe } from "@/server/stripe";
|
|
||||||
import { auth, clerkClient } from "@clerk/nextjs";
|
|
||||||
import { redirect } from "next/navigation";
|
|
||||||
import { getUrlServerSide } from "@/server/getUrlServerSide";
|
|
||||||
|
|
||||||
export async function GET(req: Request) {
|
|
||||||
const { userId, orgId } = auth();
|
|
||||||
|
|
||||||
const plan = new URL(req.url).searchParams.get("plan");
|
|
||||||
|
|
||||||
if (!userId) return redirect("/");
|
|
||||||
if (!plan) return redirect("/pricing");
|
|
||||||
|
|
||||||
const user = await clerkClient.users.getUser(userId);
|
|
||||||
|
|
||||||
const mapping = {
|
|
||||||
pro: process.env.STRIPE_PR_PRO,
|
|
||||||
enterprise: process.env.STRIPE_PR_ENTERPRISE,
|
|
||||||
};
|
|
||||||
|
|
||||||
const api = process.env.STRIPE_PR_API;
|
|
||||||
|
|
||||||
const session = await stripe.checkout.sessions.create({
|
|
||||||
success_url: getUrlServerSide(),
|
|
||||||
line_items: [
|
|
||||||
{
|
|
||||||
price: mapping[plan as "pro" | "enterprise"],
|
|
||||||
quantity: 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
price: api,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
metadata: {
|
|
||||||
userId: userId,
|
|
||||||
orgId: orgId ?? null,
|
|
||||||
plan: plan,
|
|
||||||
},
|
|
||||||
allow_promotion_codes: true,
|
|
||||||
client_reference_id: orgId ?? userId,
|
|
||||||
customer_email: user.emailAddresses[0].emailAddress,
|
|
||||||
mode: "subscription",
|
|
||||||
});
|
|
||||||
|
|
||||||
if (session.url) redirect(session.url);
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
import { stripe } from "@/server/stripe";
|
|
||||||
import { auth } from "@clerk/nextjs";
|
|
||||||
import { redirect } from "next/navigation";
|
|
||||||
import { getUrlServerSide } from "@/server/getUrlServerSide";
|
|
||||||
import { getCurrentPlan } from "@/server/getCurrentPlan";
|
|
||||||
|
|
||||||
export async function GET(req: Request) {
|
|
||||||
const { userId, orgId } = auth();
|
|
||||||
|
|
||||||
if (!userId) return redirect("/");
|
|
||||||
|
|
||||||
const change = new URL(req.url).searchParams.get("change");
|
|
||||||
|
|
||||||
const sub = await getCurrentPlan({
|
|
||||||
org_id: orgId,
|
|
||||||
user_id: userId,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!sub) return redirect("/pricing");
|
|
||||||
|
|
||||||
const session = await stripe.billingPortal.sessions.create({
|
|
||||||
customer: sub.stripe_customer_id,
|
|
||||||
return_url: getUrlServerSide() + "/pricing",
|
|
||||||
// flow_data:
|
|
||||||
// change === "true" && sub.subscription_id
|
|
||||||
// ? {
|
|
||||||
// type: "subscription_update",
|
|
||||||
// subscription_update: {
|
|
||||||
// subscription: sub.subscription_id,
|
|
||||||
// },
|
|
||||||
// }
|
|
||||||
// : undefined,
|
|
||||||
});
|
|
||||||
|
|
||||||
redirect(session.url);
|
|
||||||
// if (session.url) redirect(session.url);
|
|
||||||
}
|
|
||||||
@@ -1,150 +1,56 @@
|
|||||||
import { parseDataSafe } from "../../../../lib/parseDataSafe";
|
import { parseDataSafe } from "../../../../lib/parseDataSafe";
|
||||||
import { db } from "@/db/db";
|
import { db } from "@/db/db";
|
||||||
import {
|
import { workflowRunOutputs, workflowRunsTable } from "@/db/schema";
|
||||||
WorkflowRunStatusSchema,
|
|
||||||
workflowRunOutputs,
|
|
||||||
workflowRunsTable,
|
|
||||||
} from "@/db/schema";
|
|
||||||
import { getCurrentPlan } from "@/server/getCurrentPlan";
|
|
||||||
import { stripe } from "@/server/stripe";
|
|
||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
const Request = z.object({
|
const Request = z.object({
|
||||||
run_id: z.string(),
|
run_id: z.string(),
|
||||||
status: WorkflowRunStatusSchema.optional(),
|
status: z
|
||||||
time: z.coerce.date().optional(),
|
.enum(["not-started", "running", "uploading", "success", "failed"])
|
||||||
|
.optional(),
|
||||||
output_data: z.any().optional(),
|
output_data: z.any().optional(),
|
||||||
log_data: z.any().optional(),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export async function POST(request: Request) {
|
export async function POST(request: Request) {
|
||||||
try {
|
const [data, error] = await parseDataSafe(Request, request);
|
||||||
const [data, error] = await parseDataSafe(Request, request);
|
if (!data || error) return error;
|
||||||
|
|
||||||
if (!data || error) return error;
|
const { run_id, status, output_data } = data;
|
||||||
|
|
||||||
const { run_id, status, time, output_data, log_data } = data;
|
// console.log(run_id, status, output_data);
|
||||||
|
|
||||||
if (log_data) {
|
if (output_data) {
|
||||||
// It successfully started, update the started_at time
|
const workflow_run_output = await db.insert(workflowRunOutputs).values({
|
||||||
await db
|
run_id: run_id,
|
||||||
.update(workflowRunsTable)
|
data: output_data,
|
||||||
.set({
|
});
|
||||||
run_log: log_data,
|
} else if (status) {
|
||||||
})
|
// console.log("status", status);
|
||||||
.where(eq(workflowRunsTable.id, run_id));
|
const workflow_run = await db
|
||||||
|
.update(workflowRunsTable)
|
||||||
return NextResponse.json(
|
.set({
|
||||||
{
|
status: status,
|
||||||
message: "success",
|
ended_at:
|
||||||
},
|
status === "success" || status === "failed" ? new Date() : null,
|
||||||
{
|
})
|
||||||
status: 200,
|
.where(eq(workflowRunsTable.id, run_id))
|
||||||
},
|
.returning();
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status == "started" && time != undefined) {
|
|
||||||
// It successfully started, update the started_at time
|
|
||||||
await db
|
|
||||||
.update(workflowRunsTable)
|
|
||||||
.set({
|
|
||||||
started_at: time,
|
|
||||||
})
|
|
||||||
.where(eq(workflowRunsTable.id, run_id));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status == "queued" && time != undefined) {
|
|
||||||
// It successfully started, update the started_at time
|
|
||||||
await db
|
|
||||||
.update(workflowRunsTable)
|
|
||||||
.set({
|
|
||||||
queued_at: time,
|
|
||||||
})
|
|
||||||
.where(eq(workflowRunsTable.id, run_id));
|
|
||||||
}
|
|
||||||
|
|
||||||
const ended =
|
|
||||||
status === "success" || status === "failed" || status === "timeout";
|
|
||||||
|
|
||||||
if (output_data) {
|
|
||||||
const workflow_run_output = await db.insert(workflowRunOutputs).values({
|
|
||||||
run_id: run_id,
|
|
||||||
data: output_data,
|
|
||||||
});
|
|
||||||
} else if (status) {
|
|
||||||
const [workflow_run] = await db
|
|
||||||
.update(workflowRunsTable)
|
|
||||||
.set({
|
|
||||||
status: status,
|
|
||||||
ended_at: ended ? new Date() : null,
|
|
||||||
})
|
|
||||||
.where(eq(workflowRunsTable.id, run_id))
|
|
||||||
.returning();
|
|
||||||
|
|
||||||
// Need to filter out only comfy deploy serverless
|
|
||||||
// Also multiply with the gpu selection
|
|
||||||
if (workflow_run.machine_type == "comfy-deploy-serverless") {
|
|
||||||
if (ended && workflow_run.user_id) {
|
|
||||||
const sub = await getCurrentPlan({
|
|
||||||
user_id: workflow_run.user_id,
|
|
||||||
org_id: workflow_run.org_id,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (sub && sub.subscription_item_api_id && workflow_run.ended_at) {
|
|
||||||
let durationInSec = Math.abs(
|
|
||||||
(workflow_run.ended_at.getTime() -
|
|
||||||
workflow_run.created_at.getTime()) /
|
|
||||||
1000,
|
|
||||||
);
|
|
||||||
durationInSec = Math.ceil(durationInSec);
|
|
||||||
switch (workflow_run.gpu) {
|
|
||||||
case "A100":
|
|
||||||
durationInSec *= 7;
|
|
||||||
break;
|
|
||||||
case "A10G":
|
|
||||||
durationInSec *= 4;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
await stripe.subscriptionItems.createUsageRecord(
|
|
||||||
sub.subscription_item_api_id,
|
|
||||||
{
|
|
||||||
quantity: durationInSec,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
} catch (error) {
|
|
||||||
console.log(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NextResponse.json(
|
|
||||||
{
|
|
||||||
message: "success",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
status: 200,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
} catch (error: unknown) {
|
|
||||||
console.log("An error here");
|
|
||||||
|
|
||||||
const errorMessage =
|
|
||||||
error instanceof Error ? error.message : "Unknown error";
|
|
||||||
console.log(errorMessage);
|
|
||||||
|
|
||||||
return NextResponse.json(
|
|
||||||
{
|
|
||||||
error: errorMessage,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
status: 500,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// const workflow_version = await db.query.workflowVersionTable.findFirst({
|
||||||
|
// where: eq(workflowRunsTable.id, workflow_run[0].workflow_version_id),
|
||||||
|
// });
|
||||||
|
|
||||||
|
// revalidatePath(`./${workflow_version?.workflow_id}`);
|
||||||
|
|
||||||
|
return NextResponse.json(
|
||||||
|
{
|
||||||
|
message: "success",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
status: 200,
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,55 +0,0 @@
|
|||||||
import { parseDataSafe } from "../../../../lib/parseDataSafe";
|
|
||||||
import { db } from "@/db/db";
|
|
||||||
import { modelTable } from "@/db/schema";
|
|
||||||
import { eq } from "drizzle-orm";
|
|
||||||
import { NextResponse } from "next/server";
|
|
||||||
import { z } from "zod";
|
|
||||||
|
|
||||||
const Request = z.object({
|
|
||||||
volume_id: z.string(),
|
|
||||||
model_id: z.string(),
|
|
||||||
folder_path: z.string().optional(),
|
|
||||||
status: z.enum(["success", "failed"]),
|
|
||||||
error_log: z.string().optional(),
|
|
||||||
timeout: z.number().optional(),
|
|
||||||
});
|
|
||||||
|
|
||||||
export async function POST(request: Request) {
|
|
||||||
const [data, error] = await parseDataSafe(Request, request);
|
|
||||||
if (!data || error) return error;
|
|
||||||
|
|
||||||
const { model_id, error_log, status, folder_path } = data;
|
|
||||||
console.log(model_id, error_log, status, folder_path);
|
|
||||||
|
|
||||||
if (status === "success") {
|
|
||||||
await db
|
|
||||||
.update(modelTable)
|
|
||||||
.set({
|
|
||||||
status: "success",
|
|
||||||
folder_path,
|
|
||||||
updated_at: new Date(),
|
|
||||||
// build_log: build_log,
|
|
||||||
})
|
|
||||||
.where(eq(modelTable.id, model_id));
|
|
||||||
} else {
|
|
||||||
await db
|
|
||||||
.update(modelTable)
|
|
||||||
.set({
|
|
||||||
status: "failed",
|
|
||||||
error_log,
|
|
||||||
updated_at: new Date(),
|
|
||||||
// status: "error",
|
|
||||||
// build_log: build_log,
|
|
||||||
})
|
|
||||||
.where(eq(modelTable.id, model_id));
|
|
||||||
}
|
|
||||||
|
|
||||||
return NextResponse.json(
|
|
||||||
{
|
|
||||||
message: "success",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
status: 200,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
import { SignIn } from "@clerk/nextjs";
|
|
||||||
|
|
||||||
export default function Page() {
|
|
||||||
return (
|
|
||||||
<div className="w-full h-full items-center flex justify-center">
|
|
||||||
<SignIn />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
import { SignUp } from "@clerk/nextjs";
|
|
||||||
|
|
||||||
export default function Page() {
|
|
||||||
return (
|
|
||||||
<div className="w-full h-full items-center flex justify-center">
|
|
||||||
<SignUp />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
|
import Image from "next/image";
|
||||||
|
import Link from "next/link";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return <Examples />;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type exampleWorkflow = {
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
previewURL: string;
|
||||||
|
image: {
|
||||||
|
src: string,
|
||||||
|
alt: string,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const exampleWorkflows: exampleWorkflow[] = [
|
||||||
|
{
|
||||||
|
title: "Txt2Img SDXL",
|
||||||
|
description: "The basic workflow, type a prompt and generate images based on that.",
|
||||||
|
previewURL: 'https://www.comfydeploy.com/share/comfy-deploy-example-txt2img-sdxl',
|
||||||
|
image: {
|
||||||
|
src: '/example-workflows/txt2img.webp',
|
||||||
|
alt: 'IPAdapter workflow',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Txt2Img LCM SDXL",
|
||||||
|
description: "Images in a couple of seconds, increase the speed of each generation using LCM Lora.",
|
||||||
|
previewURL: 'https://www.comfydeploy.com/share/comfy-deploy-example-lcm-sdxl',
|
||||||
|
image: {
|
||||||
|
src: '/example-workflows/txt2img-lcm.webp',
|
||||||
|
alt: 'txt2img LCM SDXL',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "IPAdapter SDXL",
|
||||||
|
description: "Load images and use them as reference for new generations.",
|
||||||
|
previewURL: 'https://www.comfydeploy.com/share/comfy-deploy-example-ip-adapter-sdxl',
|
||||||
|
image: {
|
||||||
|
src: '/example-workflows/ipadapter.webp',
|
||||||
|
alt: 'IPAdapter workflow',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Upscale and Add Detail SDXL",
|
||||||
|
description: "Upscale and Add Details to your creations",
|
||||||
|
previewURL: 'https://www.comfydeploy.com/share/comfy-deploy-example-upscale-and-add-detail-sdxl',
|
||||||
|
image: {
|
||||||
|
src: '/example-workflows/upscale.webp',
|
||||||
|
alt: 'Upscale and Add Detail SDXL',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
async function Examples() {
|
||||||
|
return (
|
||||||
|
<div className="w-full py-4">
|
||||||
|
<section className="mx-auto flex max-w-[980px] flex-col items-center gap-2 py-8 md:py-12 md:pb-8 lg:py-24 lg:pb-20">
|
||||||
|
<h1 className="scroll-m-20 text-4xl font-extrabold tracking-tight lg:text-5xl text-center">
|
||||||
|
Check out some examples
|
||||||
|
</h1>
|
||||||
|
<p className="max-w-[560px] text-center text-lg text-muted-foreground">Text to Image, Image to Image, IPAdapter, and more. Here are some examples that you can use to deploy your workflow.</p>
|
||||||
|
</section>
|
||||||
|
<section className="flex justify-center flex-wrap gap-4">
|
||||||
|
{exampleWorkflows.map(workflow => {
|
||||||
|
return <Card className="w-[350px]">
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle>{workflow.title}</CardTitle>
|
||||||
|
<CardDescription>{workflow.description}</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<Image src={workflow.image.src} alt={workflow.image.alt} width={350} height={230} />
|
||||||
|
</CardContent>
|
||||||
|
<CardFooter className="flex justify-end gap-2">
|
||||||
|
<Button asChild>
|
||||||
|
<Link href={workflow.previewURL}>View Workflow</Link>
|
||||||
|
</Button>
|
||||||
|
</CardFooter>
|
||||||
|
</Card>;
|
||||||
|
})}
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -35,10 +35,7 @@ export default async function Page({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{machine.status !== "building" && machine.build_log && (
|
{machine.status !== "building" && machine.build_log && (
|
||||||
<LogsViewer
|
<LogsViewer logs={JSON.parse(machine.build_log)} />
|
||||||
logs={JSON.parse(machine.build_log)}
|
|
||||||
className="h-full max-h-[600px]"
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
import { AccessType } from "../../../lib/AccessType";
|
import { AccessType } from "../../../lib/AccessType";
|
||||||
import { MachineList } from "@/components/MachineList";
|
import { MachineList } from "@/components/MachineList";
|
||||||
import { SubscriptionProvider } from "@/components/useCurrentPlan";
|
|
||||||
import { db } from "@/db/db";
|
import { db } from "@/db/db";
|
||||||
import { machinesTable } from "@/db/schema";
|
import { machinesTable } from "@/db/schema";
|
||||||
import { getCurrentPlanWithAuth } from "@/server/getCurrentPlan";
|
|
||||||
import { auth } from "@clerk/nextjs";
|
import { auth } from "@clerk/nextjs";
|
||||||
import { clerkClient } from "@clerk/nextjs/server";
|
import { clerkClient } from "@clerk/nextjs/server";
|
||||||
import { desc, eq, isNull, and } from "drizzle-orm";
|
import { desc, eq, isNull, and } from "drizzle-orm";
|
||||||
@@ -21,8 +19,6 @@ async function MachineListServer() {
|
|||||||
|
|
||||||
const user = await clerkClient.users.getUser(userId);
|
const user = await clerkClient.users.getUser(userId);
|
||||||
|
|
||||||
const sub = await getCurrentPlanWithAuth();
|
|
||||||
|
|
||||||
const machines = await db.query.machinesTable.findMany({
|
const machines = await db.query.machinesTable.findMany({
|
||||||
orderBy: desc(machinesTable.updated_at),
|
orderBy: desc(machinesTable.updated_at),
|
||||||
where:
|
where:
|
||||||
@@ -33,12 +29,11 @@ async function MachineListServer() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<SubscriptionProvider sub={sub}>
|
{/* <div>Machines</div> */}
|
||||||
<MachineList
|
<MachineList
|
||||||
data={machines}
|
data={machines}
|
||||||
userMetadata={AccessType.parse(user.privateMetadata ?? {})}
|
userMetadata={AccessType.parse(user.privateMetadata ?? {})}
|
||||||
/>
|
/>
|
||||||
</SubscriptionProvider>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
import PricingList from "@/components/PricingPlan";
|
|
||||||
|
|
||||||
export default function Home() {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<PricingList />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,19 +1,19 @@
|
|||||||
// app/providers.tsx
|
// app/providers.tsx
|
||||||
"use client";
|
'use client'
|
||||||
import posthog from "posthog-js";
|
import posthog from 'posthog-js'
|
||||||
import { PostHogProvider } from "posthog-js/react";
|
import { PostHogProvider } from 'posthog-js/react'
|
||||||
|
|
||||||
if (typeof window !== "undefined") {
|
if (typeof window !== 'undefined') {
|
||||||
posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {
|
posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {
|
||||||
api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST,
|
api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST,
|
||||||
capture_pageview: false, // Disable automatic pageview capture, as we capture manually
|
capture_pageview: false // Disable automatic pageview capture, as we capture manually
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function PHProvider({
|
export function PHProvider({
|
||||||
children,
|
children,
|
||||||
}: {
|
}: {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode
|
||||||
}) {
|
}) {
|
||||||
return <PostHogProvider client={posthog}>{children}</PostHogProvider>;
|
return <PostHogProvider client={posthog}>{children}</PostHogProvider>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import { LoadingPageWrapper } from "@/components/LoadingWrapper";
|
|
||||||
import { usePathname } from "next/navigation";
|
|
||||||
|
|
||||||
export default function Loading() {
|
|
||||||
const pathName = usePathname();
|
|
||||||
return <LoadingPageWrapper className="h-full" tag={pathName.toLowerCase()} />;
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
import { setInitialUserData } from "../../../lib/setInitialUserData";
|
|
||||||
import { auth } from "@clerk/nextjs";
|
|
||||||
import { clerkClient } from "@clerk/nextjs/server";
|
|
||||||
import { ModelList } from "@/components/ModelList";
|
|
||||||
import { getAllUserModels } from "@/server/getAllUserModel";
|
|
||||||
|
|
||||||
export default function Page() {
|
|
||||||
return <ModelListServer />;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function ModelListServer() {
|
|
||||||
const { userId } = auth();
|
|
||||||
|
|
||||||
if (!userId) {
|
|
||||||
return <div>No auth</div>;
|
|
||||||
}
|
|
||||||
|
|
||||||
const user = await clerkClient.users.getUser(userId);
|
|
||||||
|
|
||||||
if (!user) {
|
|
||||||
await setInitialUserData(userId);
|
|
||||||
}
|
|
||||||
|
|
||||||
const models = await getAllUserModels();
|
|
||||||
|
|
||||||
if (!models) {
|
|
||||||
return <div>No models found</div>;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="w-full">
|
|
||||||
<ModelList data={models} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import { LoadingPageWrapper } from "@/components/LoadingWrapper";
|
|
||||||
import { usePathname } from "next/navigation";
|
|
||||||
|
|
||||||
export default function Loading() {
|
|
||||||
const pathName = usePathname();
|
|
||||||
return <LoadingPageWrapper className="h-full" tag={pathName.toLowerCase()} />;
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
import PricingList from "@/components/PricingPlan";
|
|
||||||
import { Badge } from "@/components/ui/badge";
|
|
||||||
import {
|
|
||||||
Card,
|
|
||||||
CardContent,
|
|
||||||
CardDescription,
|
|
||||||
CardHeader,
|
|
||||||
CardTitle,
|
|
||||||
} from "@/components/ui/card";
|
|
||||||
import { Progress } from "@/components/ui/progress";
|
|
||||||
import { getCurrentPlanWithAuth } from "@/server/getCurrentPlan";
|
|
||||||
import { stripe } from "@/server/stripe";
|
|
||||||
|
|
||||||
const freeTierSeconds = 30000;
|
|
||||||
|
|
||||||
export default async function Home() {
|
|
||||||
const sub = await getCurrentPlanWithAuth();
|
|
||||||
|
|
||||||
let data: Awaited<
|
|
||||||
ReturnType<typeof stripe.subscriptionItems.listUsageRecordSummaries>
|
|
||||||
> | null = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
data = sub?.subscription_item_api_id
|
|
||||||
? await stripe.subscriptionItems.listUsageRecordSummaries(
|
|
||||||
sub?.subscription_item_api_id,
|
|
||||||
)
|
|
||||||
: null;
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="mt-4 flex items-center justify-center">
|
|
||||||
<Card className="p-4 w-full max-w-[600px]">
|
|
||||||
<CardHeader>
|
|
||||||
<CardTitle>Account Usage</CardTitle>
|
|
||||||
<CardDescription>View you account usage</CardDescription>
|
|
||||||
<Badge className="w-fit">{sub?.plan}</Badge>
|
|
||||||
</CardHeader>
|
|
||||||
{data && (
|
|
||||||
<CardContent className="text-sm flex flex-col gap-2">
|
|
||||||
<div className="flex justify-between gap-2">
|
|
||||||
<span>Current free gpu usage:</span>
|
|
||||||
{
|
|
||||||
<div className="flex gap-2">
|
|
||||||
<Badge>
|
|
||||||
{data.data[0].total_usage}s /{Math.floor(freeTierSeconds)}s
|
|
||||||
</Badge>
|
|
||||||
<Badge>
|
|
||||||
{Math.floor(data.data[0].total_usage / 60 / 60)}hr /
|
|
||||||
{Math.floor(freeTierSeconds / 60 / 60)}hr
|
|
||||||
</Badge>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
<Progress
|
|
||||||
value={(data.data[0].total_usage / freeTierSeconds) * 100}
|
|
||||||
></Progress>
|
|
||||||
</CardContent>
|
|
||||||
)}
|
|
||||||
</Card>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { LoadingWrapper } from "@/components/LoadingWrapper";
|
import { LoadingWrapper } from "@/components/LoadingWrapper";
|
||||||
import { DeploymentsTable } from "@/components/DeploymentsTable";
|
import { DeploymentsTable } from "@/components/RunsTable";
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
|
|
||||||
export default async function Page({
|
export default async function Page({
|
||||||
|
|||||||
@@ -13,12 +13,12 @@ export default async function Page({
|
|||||||
const workflow_id = params.workflow_id;
|
const workflow_id = params.workflow_id;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card className="w-full h-fit min-w-0 relative">
|
<Card className="w-full h-fit min-w-0">
|
||||||
<CardHeader>
|
<CardHeader className="relative">
|
||||||
<CardTitle>Run</CardTitle>
|
<CardTitle>Run</CardTitle>
|
||||||
{/* <div className="absolute right-6 top-6">
|
<div className="absolute right-6 top-6">
|
||||||
<RouteRefresher interval={5000} autoRefresh={false} />
|
<RouteRefresher interval={5000} autoRefresh={false} />
|
||||||
</div> */}
|
</div>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
|
|
||||||
<CardContent>
|
<CardContent>
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ import {
|
|||||||
OpenEditButton,
|
OpenEditButton,
|
||||||
RunWorkflowButton,
|
RunWorkflowButton,
|
||||||
VersionSelect,
|
VersionSelect,
|
||||||
|
ViewWorkflowDetailsButton,
|
||||||
} from "@/components/VersionSelect";
|
} from "@/components/VersionSelect";
|
||||||
import { ViewWorkflowDetailsButton } from "@/components/ViewWorkflowDetailsButton";
|
|
||||||
import {
|
import {
|
||||||
Card,
|
Card,
|
||||||
CardContent,
|
CardContent,
|
||||||
@@ -21,8 +21,6 @@ import { getRelativeTime } from "@/lib/getRelativeTime";
|
|||||||
import { getMachines } from "@/server/curdMachine";
|
import { getMachines } from "@/server/curdMachine";
|
||||||
import { findFirstTableWithVersion } from "@/server/findFirstTableWithVersion";
|
import { findFirstTableWithVersion } from "@/server/findFirstTableWithVersion";
|
||||||
|
|
||||||
export const maxDuration = 300; // 5 minutes
|
|
||||||
|
|
||||||
export default async function Page({
|
export default async function Page({
|
||||||
params,
|
params,
|
||||||
}: {
|
}: {
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
export const maxDuration = 300; // 5 minutes
|
|
||||||
|
|
||||||
export default async function Layout({
|
export default async function Layout({
|
||||||
children,
|
children,
|
||||||
deployment,
|
deployment,
|
||||||
|
|||||||
@@ -6,8 +6,6 @@ import { usersTable } from "@/db/schema";
|
|||||||
import { auth } from "@clerk/nextjs";
|
import { auth } from "@clerk/nextjs";
|
||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
|
|
||||||
export const maxDuration = 300; // 5 minutes
|
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
return <WorkflowServer />;
|
return <WorkflowServer />;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
export const metadata = {
|
export const metadata = {
|
||||||
title: 'Quickstart',
|
title: 'Quickstart',
|
||||||
description:
|
description:
|
||||||
'This guide will get you all set up and ready to use Comfy Deploy. We’ll cover how to get started an API client and how to make your first API request.',
|
'This guide will get you all set up and ready to use the Protocol API. We’ll cover how to get started an API client and how to make your first API request.',
|
||||||
}
|
}
|
||||||
|
|
||||||
# Getting started
|
# Getting stated
|
||||||
|
|
||||||
Install Comfy Deploy's plugin on your local ComfyUI to get started with deploying workflow.
|
Install Comfy Deploy's plugin on your local machine to get started with deploying workflow.
|
||||||
|
|
||||||
<CodeGroup>
|
<CodeGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -1,58 +0,0 @@
|
|||||||
export const metadata = {
|
|
||||||
title: 'Comfy Deploy Video tutorials',
|
|
||||||
description:
|
|
||||||
'Get started with API integration to run any deploy ComfyUI workflow',
|
|
||||||
}
|
|
||||||
|
|
||||||
**This is a collection of video tutorials on questions that have come up in our [discord channel](https://discord.gg/Zrar7yP6MJ).**
|
|
||||||
|
|
||||||
# Comfy Deploy workflow walkthrough (comprehensive)
|
|
||||||
|
|
||||||
Local workflow, to production API
|
|
||||||
- Set inputs with Comfy Deploy `External Text` nodes
|
|
||||||
- Deploy the workflow
|
|
||||||
- Create a machine
|
|
||||||
- Deploy an API endpoint for the workflow
|
|
||||||
- Test the workflow in Comfy Deploy
|
|
||||||
|
|
||||||
<video controls>
|
|
||||||
<source src="https://pub-1a2bca0642c24fcfb84ce8d8415958d3.r2.dev/comfydeploy_base-sd-setup.mp4" type="video/mp4"/>
|
|
||||||
Your browser does not support the video tag.
|
|
||||||
</video>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Test with Docs
|
|
||||||
Shows how you can use the <a href='/docs/endpoints'>endpoints docs</a> to test out the API!
|
|
||||||
|
|
||||||
<video controls>
|
|
||||||
<source src="https://pub-1a2bca0642c24fcfb84ce8d8415958d3.r2.dev/comfydeploy_interactive_docs.mp4" type="video/mp4"/>
|
|
||||||
Your browser does not support the video tag.
|
|
||||||
</video>
|
|
||||||
|
|
||||||
## Intermediate IPAdaptor example run
|
|
||||||
Shows off a semi-complex workflow working on Comfy Deploy
|
|
||||||
|
|
||||||
<video controls>
|
|
||||||
<source src="https://pub-1a2bca0642c24fcfb84ce8d8415958d3.r2.dev/ipadapters-test.mp4" type="video/mp4"/>
|
|
||||||
Your browser does not support the video tag.
|
|
||||||
</video>
|
|
||||||
|
|
||||||
## Animate diff on Comfy Deploy
|
|
||||||
Shows off animate diff working on Comfy Deploy
|
|
||||||
|
|
||||||
<video controls>
|
|
||||||
<source src="https://pub-1a2bca0642c24fcfb84ce8d8415958d3.r2.dev/comfydeploy-animediff.mp4" type="video/mp4"/>
|
|
||||||
Your browser does not support the video tag.
|
|
||||||
</video>
|
|
||||||
|
|
||||||
## Cloning workflows
|
|
||||||
What does cloning a workflow look like
|
|
||||||
|
|
||||||
<video controls>
|
|
||||||
<source src="https://pub-1a2bca0642c24fcfb84ce8d8415958d3.r2.dev/comfydeploy-clone-template.mp4" type="video/mp4"/>
|
|
||||||
Your browser does not support the video tag.
|
|
||||||
</video>
|
|
||||||
|
|
||||||
## [Install custom nodes from any github repo (Loom)](https://www.loom.com/share/c2025c5060e348839ade6a3a9d96441d?sid=6a57f779-0209-4341-a5fd-f99769cdb162)
|
|
||||||
- This is only neccessary if the custom node is not in the ComfyUI Manager node list
|
|
||||||
@@ -13,7 +13,10 @@ export async function CodeBlock(props: {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative w-full text-sm">
|
<div className="relative w-full text-sm">
|
||||||
|
{/* max-w-[calc(32rem-1.5rem-1.5rem)] */}
|
||||||
|
{/* <div className=""> */}
|
||||||
<p
|
<p
|
||||||
|
// tabIndex={1}
|
||||||
className="[&>pre]:p-4 rounded-lg max-h-96 overflow-auto w-full"
|
className="[&>pre]:p-4 rounded-lg max-h-96 overflow-auto w-full"
|
||||||
style={{
|
style={{
|
||||||
overflowWrap: "break-word",
|
overflowWrap: "break-word",
|
||||||
@@ -25,6 +28,7 @@ export async function CodeBlock(props: {
|
|||||||
}),
|
}),
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
{/* </div> */}
|
||||||
<CopyButton className="absolute right-2 top-2" text={props.code} />
|
<CopyButton className="absolute right-2 top-2" text={props.code} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,35 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import { CopyButton } from "@/components/CopyButton";
|
|
||||||
import type { StringLiteralUnion } from "shikiji";
|
|
||||||
import useSWR from "swr";
|
|
||||||
import { highlight } from "../server/highlight";
|
|
||||||
|
|
||||||
export function CodeBlockClient({
|
|
||||||
code,
|
|
||||||
lang,
|
|
||||||
}: {
|
|
||||||
code: string;
|
|
||||||
lang: StringLiteralUnion<string>;
|
|
||||||
}) {
|
|
||||||
const { data } = useSWR(code, async () => {
|
|
||||||
return highlight(code.trim(), lang);
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="relative w-full text-sm">
|
|
||||||
{data && (
|
|
||||||
<p
|
|
||||||
className="[&>pre]:p-4 rounded-lg max-h-96 overflow-auto w-full"
|
|
||||||
style={{
|
|
||||||
overflowWrap: "break-word",
|
|
||||||
}}
|
|
||||||
dangerouslySetInnerHTML={{
|
|
||||||
__html: data,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<CopyButton className="absolute right-2 top-2" text={code} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -7,12 +7,10 @@ import { toast } from "sonner";
|
|||||||
|
|
||||||
export function CopyButton({
|
export function CopyButton({
|
||||||
className,
|
className,
|
||||||
children,
|
|
||||||
...props
|
...props
|
||||||
}: {
|
}: {
|
||||||
text: string;
|
text: string;
|
||||||
className?: string;
|
className?: string;
|
||||||
children?: React.ReactNode;
|
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
@@ -23,7 +21,7 @@ export function CopyButton({
|
|||||||
}}
|
}}
|
||||||
className={cn(" p-2 min-h-0 aspect-square", className)}
|
className={cn(" p-2 min-h-0 aspect-square", className)}
|
||||||
>
|
>
|
||||||
{children} <Copy size={14} />
|
<Copy size={14} />
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
"use client";
|
|
||||||
import { getCurrentPlanWithAuth } from "@/server/getCurrentPlan";
|
|
||||||
import * as React from "react";
|
|
||||||
import { createContext } from "react";
|
|
||||||
|
|
||||||
export type CurrentPlanContextType = Awaited<
|
|
||||||
ReturnType<typeof getCurrentPlanWithAuth>
|
|
||||||
>;
|
|
||||||
export const CurrentPlanContext = createContext<
|
|
||||||
CurrentPlanContextType | undefined
|
|
||||||
>(undefined);
|
|
||||||
export function SubscriptionProvider({
|
|
||||||
sub,
|
|
||||||
children,
|
|
||||||
}: {
|
|
||||||
sub: CurrentPlanContextType;
|
|
||||||
children: React.ReactNode;
|
|
||||||
}) {
|
|
||||||
return (
|
|
||||||
<CurrentPlanContext.Provider value={sub}>
|
|
||||||
{children}
|
|
||||||
</CurrentPlanContext.Provider>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -69,16 +69,13 @@ const client = new ComfyDeployClient({
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const jsClientCreateRunTemplate = `
|
const jsClientCreateRunTemplate = `
|
||||||
const { run_id } = await client.run({
|
const { run_id } = await client.run("<ID>", {
|
||||||
deployment_id: "<ID>",
|
|
||||||
inputs: {}
|
inputs: {}
|
||||||
});
|
});
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const jsClientCreateRunNoInputsTemplate = `
|
const jsClientCreateRunNoInputsTemplate = `
|
||||||
const { run_id } = await client.run({
|
const { run_id } = await client.run("<ID>");
|
||||||
deployment_id: "<ID>"
|
|
||||||
});
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const clientTemplate_checkStatus = `
|
const clientTemplate_checkStatus = `
|
||||||
@@ -121,9 +118,15 @@ export function DeploymentDisplay({
|
|||||||
</TabsList>
|
</TabsList>
|
||||||
<TabsContent className="flex flex-col gap-2 !mt-0" value="client">
|
<TabsContent className="flex flex-col gap-2 !mt-0" value="client">
|
||||||
<div>
|
<div>
|
||||||
Install the node comfydeploy SDK
|
Copy and paste the ComfyDeployClient form
|
||||||
<CodeBlock lang="bash" code={`npm i comfydeploy`} />
|
<a
|
||||||
Initialize your client
|
href="https://github.com/BennyKok/comfyui-deploy-next-example/blob/main/src/lib/comfy-deploy.ts"
|
||||||
|
className="text-blue-500 hover:underline"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
>
|
||||||
|
here
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<CodeBlock
|
<CodeBlock
|
||||||
lang="js"
|
lang="js"
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
import {
|
|
||||||
Table,
|
|
||||||
TableBody,
|
|
||||||
TableCaption,
|
|
||||||
TableHead,
|
|
||||||
TableHeader,
|
|
||||||
TableRow,
|
|
||||||
} from "@/components/ui/table";
|
|
||||||
import { headers } from "next/headers";
|
|
||||||
import { findAllDeployments } from "../server/findAllRuns";
|
|
||||||
import { DeploymentDisplay } from "./DeploymentDisplay";
|
|
||||||
|
|
||||||
export async function DeploymentsTable(props: { workflow_id: string }) {
|
|
||||||
const allRuns = await findAllDeployments(props.workflow_id);
|
|
||||||
|
|
||||||
const headersList = headers();
|
|
||||||
const host = headersList.get("host") || "";
|
|
||||||
const protocol = headersList.get("x-forwarded-proto") || "";
|
|
||||||
const domain = `${protocol}://${host}`;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="overflow-auto h-fit w-full">
|
|
||||||
<Table className="">
|
|
||||||
<TableCaption>A list of your deployments</TableCaption>
|
|
||||||
<TableHeader className="bg-background top-0 sticky">
|
|
||||||
<TableRow>
|
|
||||||
<TableHead className=" w-[100px]">Environment</TableHead>
|
|
||||||
<TableHead className=" w-[100px]">Version</TableHead>
|
|
||||||
<TableHead className="">Machine</TableHead>
|
|
||||||
<TableHead className=" text-right">Updated At</TableHead>
|
|
||||||
</TableRow>
|
|
||||||
</TableHeader>
|
|
||||||
<TableBody>
|
|
||||||
{allRuns.map((run) => (
|
|
||||||
<DeploymentDisplay deployment={run} key={run.id} domain={domain} />
|
|
||||||
))}
|
|
||||||
</TableBody>
|
|
||||||
</Table>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
+104
-144
@@ -23,42 +23,14 @@ import * as React from "react";
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import type { UnknownKeysParam, ZodObject, ZodRawShape, z } from "zod";
|
import type { UnknownKeysParam, ZodObject, ZodRawShape, z } from "zod";
|
||||||
|
|
||||||
type ContextType = [Partial<any>, React.Dispatch<React.SetStateAction<any>>];
|
|
||||||
const AutoFormValueContext = React.createContext<ContextType | null>(null);
|
|
||||||
|
|
||||||
function AutoFormValueProvider<Z extends ZodObject<any, any>>({
|
|
||||||
children,
|
|
||||||
value,
|
|
||||||
}: {
|
|
||||||
children: React.ReactNode;
|
|
||||||
value: ContextType;
|
|
||||||
}) {
|
|
||||||
return (
|
|
||||||
<AutoFormValueContext.Provider value={value}>
|
|
||||||
{children}
|
|
||||||
</AutoFormValueContext.Provider>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useAutoFormValueContext<Z extends ZodObject<any, any>>() {
|
|
||||||
const context = React.useContext(AutoFormValueContext);
|
|
||||||
|
|
||||||
// if (!context) {
|
|
||||||
// throw new Error("useInsertModal must be used within a InsertModalProvider");
|
|
||||||
// }
|
|
||||||
|
|
||||||
return context;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function InsertModal<
|
export function InsertModal<
|
||||||
K extends ZodRawShape,
|
K extends ZodRawShape,
|
||||||
Y extends UnknownKeysParam,
|
Y extends UnknownKeysParam,
|
||||||
Z extends ZodObject<K, Y>,
|
Z extends ZodObject<K, Y>
|
||||||
>(props: {
|
>(props: {
|
||||||
tooltip?: string;
|
tooltip?: string;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
title: React.ReactNode;
|
title: string;
|
||||||
buttonTitle?: React.ReactNode;
|
|
||||||
description: string;
|
description: string;
|
||||||
dialogClassName?: string;
|
dialogClassName?: string;
|
||||||
serverAction: (data: z.infer<Z>) => Promise<unknown>;
|
serverAction: (data: z.infer<Z>) => Promise<unknown>;
|
||||||
@@ -68,80 +40,72 @@ export function InsertModal<
|
|||||||
const [open, setOpen] = React.useState(false);
|
const [open, setOpen] = React.useState(false);
|
||||||
const [isLoading, setIsLoading] = React.useState(false);
|
const [isLoading, setIsLoading] = React.useState(false);
|
||||||
|
|
||||||
const [values, setValues] = useState<Partial<z.infer<Z>>>({});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AutoFormValueProvider value={[values, setValues]}>
|
<Dialog open={open} onOpenChange={setOpen}>
|
||||||
<Dialog open={open} onOpenChange={setOpen}>
|
{/* <DialogTrigger disabled={props.disabled}> */}
|
||||||
{/* <DialogTrigger disabled={props.disabled}> */}
|
{props.tooltip ? (
|
||||||
{props.tooltip ? (
|
<Tooltip>
|
||||||
<Tooltip>
|
<TooltipTrigger asChild>
|
||||||
<TooltipTrigger asChild>
|
<Button
|
||||||
<Button
|
variant="default"
|
||||||
variant="default"
|
className={props.disabled ? "opacity-50" : ""}
|
||||||
className={props.disabled ? "opacity-50" : ""}
|
onClick={() => {
|
||||||
onClick={() => {
|
if (props.disabled) return;
|
||||||
if (props.disabled) return;
|
setOpen(true);
|
||||||
setOpen(true);
|
}}
|
||||||
}}
|
>
|
||||||
>
|
{props.title}
|
||||||
{props.buttonTitle ?? props.title}
|
</Button>
|
||||||
</Button>
|
</TooltipTrigger>
|
||||||
</TooltipTrigger>
|
<TooltipContent>
|
||||||
<TooltipContent>
|
<p>{props.tooltip}</p>
|
||||||
<p>{props.tooltip}</p>
|
</TooltipContent>
|
||||||
</TooltipContent>
|
</Tooltip>
|
||||||
</Tooltip>
|
) : (
|
||||||
) : (
|
<Button
|
||||||
<Button
|
variant="default"
|
||||||
variant="default"
|
disabled={props.disabled}
|
||||||
disabled={props.disabled}
|
onClick={() => {
|
||||||
onClick={() => {
|
setOpen(true);
|
||||||
setOpen(true);
|
}}
|
||||||
}}
|
|
||||||
>
|
|
||||||
{props.title}
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
{/* </DialogTrigger> */}
|
|
||||||
<DialogContent
|
|
||||||
className={cn("sm:max-w-[425px]", props.dialogClassName)}
|
|
||||||
>
|
>
|
||||||
<DialogHeader>
|
{props.title}
|
||||||
<DialogTitle>{props.title}</DialogTitle>
|
</Button>
|
||||||
<DialogDescription>{props.description}</DialogDescription>
|
)}
|
||||||
</DialogHeader>
|
{/* </DialogTrigger> */}
|
||||||
{/* <ScrollArea> */}
|
<DialogContent className={cn("sm:max-w-[425px]", props.dialogClassName)}>
|
||||||
<AutoForm
|
<DialogHeader>
|
||||||
values={values}
|
<DialogTitle>{props.title}</DialogTitle>
|
||||||
onValuesChange={setValues}
|
<DialogDescription>{props.description}</DialogDescription>
|
||||||
fieldConfig={props.fieldConfig}
|
</DialogHeader>
|
||||||
formSchema={props.formSchema}
|
{/* <ScrollArea> */}
|
||||||
onSubmit={async (data) => {
|
<AutoForm
|
||||||
setIsLoading(true);
|
fieldConfig={props.fieldConfig}
|
||||||
await callServerPromise(props.serverAction(data));
|
formSchema={props.formSchema}
|
||||||
setIsLoading(false);
|
onSubmit={async (data) => {
|
||||||
setOpen(false);
|
setIsLoading(true);
|
||||||
}}
|
await callServerPromise(props.serverAction(data));
|
||||||
>
|
setIsLoading(false);
|
||||||
<div className="flex justify-end">
|
setOpen(false);
|
||||||
<AutoFormSubmit>
|
}}
|
||||||
Save Changes
|
>
|
||||||
{isLoading && <LoadingIcon />}
|
<div className="flex justify-end">
|
||||||
</AutoFormSubmit>
|
<AutoFormSubmit>
|
||||||
</div>
|
Save Changes
|
||||||
</AutoForm>
|
{isLoading && <LoadingIcon />}
|
||||||
{/* </ScrollArea> */}
|
</AutoFormSubmit>
|
||||||
</DialogContent>
|
</div>
|
||||||
</Dialog>
|
</AutoForm>
|
||||||
</AutoFormValueProvider>
|
{/* </ScrollArea> */}
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function UpdateModal<
|
export function UpdateModal<
|
||||||
K extends ZodRawShape,
|
K extends ZodRawShape,
|
||||||
Y extends UnknownKeysParam,
|
Y extends UnknownKeysParam,
|
||||||
Z extends ZodObject<K, Y>,
|
Z extends ZodObject<K, Y>
|
||||||
>(props: {
|
>(props: {
|
||||||
open?: boolean;
|
open?: boolean;
|
||||||
setOpen?: (open: boolean) => void;
|
setOpen?: (open: boolean) => void;
|
||||||
@@ -154,7 +118,7 @@ export function UpdateModal<
|
|||||||
serverAction: (
|
serverAction: (
|
||||||
data: z.infer<Z> & {
|
data: z.infer<Z> & {
|
||||||
id: string;
|
id: string;
|
||||||
},
|
}
|
||||||
) => Promise<unknown>;
|
) => Promise<unknown>;
|
||||||
formSchema: Z;
|
formSchema: Z;
|
||||||
fieldConfig?: FieldConfig<z.infer<Z>>;
|
fieldConfig?: FieldConfig<z.infer<Z>>;
|
||||||
@@ -173,53 +137,49 @@ export function UpdateModal<
|
|||||||
}, [props.data]);
|
}, [props.data]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AutoFormValueProvider value={[values, setValues]}>
|
<Dialog open={open} onOpenChange={setOpen}>
|
||||||
<Dialog open={open} onOpenChange={setOpen}>
|
{props.trigger ?? (
|
||||||
{props.trigger ?? (
|
<DialogTrigger
|
||||||
<DialogTrigger
|
className="appearance-none hover:cursor-pointer"
|
||||||
className="appearance-none hover:cursor-pointer"
|
asChild
|
||||||
asChild
|
onClick={() => {
|
||||||
onClick={() => {
|
setOpen(true);
|
||||||
setOpen(true);
|
}}
|
||||||
}}
|
|
||||||
>
|
|
||||||
{props.trigger}
|
|
||||||
</DialogTrigger>
|
|
||||||
)}
|
|
||||||
<DialogContent
|
|
||||||
className={cn("sm:max-w-[425px]", props.dialogClassName)}
|
|
||||||
>
|
>
|
||||||
<DialogHeader>
|
{props.trigger}
|
||||||
<DialogTitle>{props.title}</DialogTitle>
|
</DialogTrigger>
|
||||||
<DialogDescription>{props.description}</DialogDescription>
|
)}
|
||||||
</DialogHeader>
|
<DialogContent className={cn("sm:max-w-[425px]", props.dialogClassName)}>
|
||||||
<AutoForm
|
<DialogHeader>
|
||||||
values={values}
|
<DialogTitle>{props.title}</DialogTitle>
|
||||||
onValuesChange={setValues}
|
<DialogDescription>{props.description}</DialogDescription>
|
||||||
fieldConfig={props.fieldConfig}
|
</DialogHeader>
|
||||||
formSchema={props.formSchema}
|
<AutoForm
|
||||||
onSubmit={async (data) => {
|
values={values}
|
||||||
setIsLoading(true);
|
onValuesChange={setValues}
|
||||||
await callServerPromise(
|
fieldConfig={props.fieldConfig}
|
||||||
props.serverAction({
|
formSchema={props.formSchema}
|
||||||
...data,
|
onSubmit={async (data) => {
|
||||||
id: props.data.id,
|
setIsLoading(true);
|
||||||
}),
|
await callServerPromise(
|
||||||
);
|
props.serverAction({
|
||||||
setIsLoading(false);
|
...data,
|
||||||
setOpen(false);
|
id: props.data.id,
|
||||||
}}
|
})
|
||||||
>
|
);
|
||||||
<div className="flex justify-end flex-wrap gap-2">
|
setIsLoading(false);
|
||||||
{props.extraButtons}
|
setOpen(false);
|
||||||
<AutoFormSubmit>
|
}}
|
||||||
Save Changes
|
>
|
||||||
{isLoading && <LoadingIcon />}
|
<div className="flex justify-end flex-wrap gap-2">
|
||||||
</AutoFormSubmit>
|
{props.extraButtons}
|
||||||
</div>
|
<AutoFormSubmit>
|
||||||
</AutoForm>
|
Save Changes
|
||||||
</DialogContent>
|
{isLoading && <LoadingIcon />}
|
||||||
</Dialog>
|
</AutoFormSubmit>
|
||||||
</AutoFormValueProvider>
|
</div>
|
||||||
|
</AutoForm>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export function LiveStatus({
|
|||||||
(state) =>
|
(state) =>
|
||||||
state.data
|
state.data
|
||||||
.filter((x) => x.id === run.id)
|
.filter((x) => x.id === run.id)
|
||||||
.sort((a, b) => b.timestamp - a.timestamp)?.[0],
|
.sort((a, b) => b.timestamp - a.timestamp)?.[0]
|
||||||
);
|
);
|
||||||
|
|
||||||
let status = run.status;
|
let status = run.status;
|
||||||
@@ -51,9 +51,7 @@ export function LiveStatus({
|
|||||||
<>
|
<>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
{data && status != "success"
|
{data && status != "success"
|
||||||
? `${data.json.event}${
|
? `${data.json.event} - ${data.json.data.node}`
|
||||||
data.json.data.node ? " - " + data.json.data.node : ""
|
|
||||||
}`
|
|
||||||
: "-"}
|
: "-"}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell className="truncate text-right">
|
<TableCell className="truncate text-right">
|
||||||
|
|||||||
@@ -1,31 +1,17 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import React, { useEffect, useRef } from "react";
|
import React, { useEffect, useRef } from "react";
|
||||||
import { cn } from "@/lib/utils";
|
|
||||||
import { toast } from "sonner";
|
|
||||||
|
|
||||||
export type LogsType = {
|
export type LogsType = {
|
||||||
machine_id?: string;
|
machine_id?: string;
|
||||||
logs: string;
|
logs: string;
|
||||||
timestamp?: number;
|
timestamp: number;
|
||||||
}[];
|
}[];
|
||||||
|
|
||||||
export function LogsViewer({
|
export function LogsViewer({ logs }: { logs: LogsType }) {
|
||||||
logs,
|
|
||||||
hideTimestamp,
|
|
||||||
className,
|
|
||||||
stickToBottom = true,
|
|
||||||
}: {
|
|
||||||
logs: LogsType;
|
|
||||||
hideTimestamp?: boolean;
|
|
||||||
className?: string;
|
|
||||||
stickToBottom?: boolean;
|
|
||||||
}) {
|
|
||||||
const container = useRef<HTMLDivElement | null>(null);
|
const container = useRef<HTMLDivElement | null>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!stickToBottom) return;
|
|
||||||
|
|
||||||
// console.log(logs.length, container.current);
|
// console.log(logs.length, container.current);
|
||||||
if (container.current) {
|
if (container.current) {
|
||||||
const scrollHeight = container.current.scrollHeight;
|
const scrollHeight = container.current.scrollHeight;
|
||||||
@@ -35,12 +21,11 @@ export function LogsViewer({
|
|||||||
behavior: "smooth",
|
behavior: "smooth",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [logs.length, stickToBottom]);
|
}, [logs.length]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
ref={(ref) => {
|
ref={(ref) => {
|
||||||
if (!stickToBottom) return;
|
|
||||||
if (!container.current && ref) {
|
if (!container.current && ref) {
|
||||||
const scrollHeight = ref.scrollHeight;
|
const scrollHeight = ref.scrollHeight;
|
||||||
|
|
||||||
@@ -51,31 +36,10 @@ export function LogsViewer({
|
|||||||
}
|
}
|
||||||
container.current = ref;
|
container.current = ref;
|
||||||
}}
|
}}
|
||||||
className={cn(
|
className="flex flex-col text-xs p-2 overflow-y-scroll max-h-[400px] whitespace-break-spaces"
|
||||||
"h-full w-full flex flex-col text-xs p-2 overflow-y-scroll whitespace-break-spaces",
|
|
||||||
className,
|
|
||||||
)}
|
|
||||||
>
|
>
|
||||||
{logs.map((x, i) => (
|
{logs.map((x, i) => (
|
||||||
<div
|
<div key={i}>{x.logs}</div>
|
||||||
key={i}
|
|
||||||
className="hover:bg-gray-100 flex flex-row items-center gap-2"
|
|
||||||
onClick={() => {
|
|
||||||
toast.success("Copied to clipboard");
|
|
||||||
navigator.clipboard.writeText(x.logs);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{!hideTimestamp && x.timestamp != undefined && (
|
|
||||||
<>
|
|
||||||
<span className="w-[150px] flex-shrink-0">
|
|
||||||
{new Date(x.timestamp * 1000).toLocaleString()}
|
|
||||||
</span>
|
|
||||||
<div className="h-full w-[1px] bg-stone-400 flex-shrink-0"></div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
{/* Display timestamp */}
|
|
||||||
<div>{x.logs}</div>
|
|
||||||
</div>
|
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -6,19 +6,6 @@ import { getConnectionStatus } from "@/components/getConnectionStatus";
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import useWebSocket from "react-use-websocket";
|
import useWebSocket from "react-use-websocket";
|
||||||
|
|
||||||
import {
|
|
||||||
AlertDialog,
|
|
||||||
AlertDialogAction,
|
|
||||||
AlertDialogCancel,
|
|
||||||
AlertDialogContent,
|
|
||||||
AlertDialogDescription,
|
|
||||||
AlertDialogFooter,
|
|
||||||
AlertDialogHeader,
|
|
||||||
AlertDialogTitle,
|
|
||||||
AlertDialogTrigger,
|
|
||||||
} from "@/components/ui/alert-dialog";
|
|
||||||
import { useRouter } from "next/navigation";
|
|
||||||
|
|
||||||
export function MachineBuildLog({
|
export function MachineBuildLog({
|
||||||
machine_id,
|
machine_id,
|
||||||
endpoint,
|
endpoint,
|
||||||
@@ -30,7 +17,6 @@ export function MachineBuildLog({
|
|||||||
}) {
|
}) {
|
||||||
const [logs, setLogs] = useState<LogsType>([]);
|
const [logs, setLogs] = useState<LogsType>([]);
|
||||||
const [finished, setFinished] = useState(false);
|
const [finished, setFinished] = useState(false);
|
||||||
const [status, setStatus] = useState<"failed" | "succuss">();
|
|
||||||
|
|
||||||
const wsEndpoint = endpoint.replace(/^http/, "ws");
|
const wsEndpoint = endpoint.replace(/^http/, "ws");
|
||||||
const query = { fly_instance_id: instance_id };
|
const query = { fly_instance_id: instance_id };
|
||||||
@@ -41,7 +27,7 @@ export function MachineBuildLog({
|
|||||||
reconnectAttempts: 20,
|
reconnectAttempts: 20,
|
||||||
reconnectInterval: 1000,
|
reconnectInterval: 1000,
|
||||||
queryParams: query,
|
queryParams: query,
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const connectionStatus = getConnectionStatus(readyState);
|
const connectionStatus = getConnectionStatus(readyState);
|
||||||
@@ -57,70 +43,13 @@ export function MachineBuildLog({
|
|||||||
setLogs((logs) => [...(logs ?? []), message.data]);
|
setLogs((logs) => [...(logs ?? []), message.data]);
|
||||||
} else if (message?.event === "FINISHED") {
|
} else if (message?.event === "FINISHED") {
|
||||||
setFinished(true);
|
setFinished(true);
|
||||||
setStatus(message.data.status);
|
|
||||||
}
|
}
|
||||||
}, [lastMessage]);
|
}, [lastMessage]);
|
||||||
|
|
||||||
const router = useRouter();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{connectionStatus}
|
{connectionStatus}
|
||||||
<LogsViewer logs={logs} className="h-full max-h-[600px]" />
|
<LogsViewer logs={logs} />
|
||||||
|
|
||||||
<AlertDialog open={finished}>
|
|
||||||
<AlertDialogContent>
|
|
||||||
{status == "succuss" ? (
|
|
||||||
<>
|
|
||||||
<AlertDialogHeader>
|
|
||||||
<AlertDialogTitle>Machine Built</AlertDialogTitle>
|
|
||||||
<AlertDialogDescription>
|
|
||||||
Your machine is built, you can now integrate your API, or
|
|
||||||
directly run to check this machines.
|
|
||||||
</AlertDialogDescription>
|
|
||||||
</AlertDialogHeader>
|
|
||||||
<AlertDialogFooter>
|
|
||||||
<AlertDialogAction
|
|
||||||
onClick={() => {
|
|
||||||
router.push("/workflows");
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
See Workflows
|
|
||||||
</AlertDialogAction>
|
|
||||||
<AlertDialogAction
|
|
||||||
onClick={() => {
|
|
||||||
router.push("/machines");
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
See All Machines
|
|
||||||
</AlertDialogAction>
|
|
||||||
</AlertDialogFooter>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<AlertDialogHeader>
|
|
||||||
<AlertDialogTitle>Machine Failed</AlertDialogTitle>
|
|
||||||
<AlertDialogDescription>
|
|
||||||
Something went wrong with the machine build, please check the
|
|
||||||
log. Possible cause could be conflits with custom nodes, build
|
|
||||||
got stuck, timeout, or too many custom nodes installed. Please
|
|
||||||
attempt a rebuild or remove some of the custom nodes.
|
|
||||||
</AlertDialogDescription>
|
|
||||||
</AlertDialogHeader>
|
|
||||||
<AlertDialogFooter>
|
|
||||||
<AlertDialogCancel>See logs</AlertDialogCancel>
|
|
||||||
<AlertDialogAction
|
|
||||||
onClick={() => {
|
|
||||||
router.push("/machines");
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Back to machines
|
|
||||||
</AlertDialogAction>
|
|
||||||
</AlertDialogFooter>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</AlertDialogContent>
|
|
||||||
</AlertDialog>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,8 +40,6 @@ import {
|
|||||||
updateCustomMachine,
|
updateCustomMachine,
|
||||||
updateMachine,
|
updateMachine,
|
||||||
} from "@/server/curdMachine";
|
} from "@/server/curdMachine";
|
||||||
import { editWorkflowOnMachine } from "@/server/editWorkflowOnMachine";
|
|
||||||
import { getCurrentPlanWithAuth } from "@/server/getCurrentPlan";
|
|
||||||
import type {
|
import type {
|
||||||
ColumnDef,
|
ColumnDef,
|
||||||
ColumnFiltersState,
|
ColumnFiltersState,
|
||||||
@@ -56,10 +54,9 @@ import {
|
|||||||
getSortedRowModel,
|
getSortedRowModel,
|
||||||
useReactTable,
|
useReactTable,
|
||||||
} from "@tanstack/react-table";
|
} from "@tanstack/react-table";
|
||||||
import { ArrowUpDown, Lock, MoreHorizontal, Plus } from "lucide-react";
|
import { ArrowUpDown, MoreHorizontal } from "lucide-react";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { toast } from "sonner";
|
|
||||||
import type { z } from "zod";
|
import type { z } from "zod";
|
||||||
|
|
||||||
export type Machine = MachineType;
|
export type Machine = MachineType;
|
||||||
@@ -116,18 +113,16 @@ export const columns: ColumnDef<Machine>[] = [
|
|||||||
{row.original.status} <LoadingIcon />
|
{row.original.status} <LoadingIcon />
|
||||||
</Badge>
|
</Badge>
|
||||||
)}
|
)}
|
||||||
{!row.original.disabled &&
|
{!row.original.disabled && row.original.status && (
|
||||||
row.original.status &&
|
<Badge
|
||||||
row.original.status != "building" && (
|
variant={
|
||||||
<Badge
|
row.original.status == "ready" ? "success" : "destructive"
|
||||||
variant={
|
}
|
||||||
row.original.status == "ready" ? "success" : "destructive"
|
className="capitalize"
|
||||||
}
|
>
|
||||||
className="capitalize"
|
{row.original.status}
|
||||||
>
|
</Badge>
|
||||||
{row.original.status}
|
)}
|
||||||
</Badge>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
// </a>
|
// </a>
|
||||||
);
|
);
|
||||||
@@ -149,16 +144,9 @@ export const columns: ColumnDef<Machine>[] = [
|
|||||||
header: () => <div className="text-left">Type</div>,
|
header: () => <div className="text-left">Type</div>,
|
||||||
cell: ({ row }) => {
|
cell: ({ row }) => {
|
||||||
return (
|
return (
|
||||||
<Badge
|
<div className="text-left font-medium truncate">
|
||||||
className="text-left font-medium truncate"
|
|
||||||
variant={
|
|
||||||
row.original.type == "comfy-deploy-serverless"
|
|
||||||
? "success"
|
|
||||||
: "outline"
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{row.original.type}
|
{row.original.type}
|
||||||
</Badge>
|
</div>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -190,7 +178,6 @@ export const columns: ColumnDef<Machine>[] = [
|
|||||||
cell: ({ row }) => {
|
cell: ({ row }) => {
|
||||||
const machine = row.original;
|
const machine = row.original;
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const sub = useCurrentPlan();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
@@ -205,9 +192,7 @@ export const columns: ColumnDef<Machine>[] = [
|
|||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
className="text-destructive"
|
className="text-destructive"
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
callServerPromise(deleteMachine(machine.id), {
|
callServerPromise(deleteMachine(machine.id));
|
||||||
loadingText: "Deleting machine",
|
|
||||||
});
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Delete Machine
|
Delete Machine
|
||||||
@@ -215,9 +200,7 @@ export const columns: ColumnDef<Machine>[] = [
|
|||||||
{machine.disabled ? (
|
{machine.disabled ? (
|
||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
callServerPromise(enableMachine(machine.id), {
|
callServerPromise(enableMachine(machine.id));
|
||||||
loadingText: "Enabling machine",
|
|
||||||
});
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Enable Machine
|
Enable Machine
|
||||||
@@ -226,9 +209,7 @@ export const columns: ColumnDef<Machine>[] = [
|
|||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
className="text-destructive"
|
className="text-destructive"
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
callServerPromise(disableMachine(machine.id), {
|
callServerPromise(disableMachine(machine.id));
|
||||||
loadingText: "Disabling machine",
|
|
||||||
});
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Disable Machine
|
Disable Machine
|
||||||
@@ -236,33 +217,22 @@ export const columns: ColumnDef<Machine>[] = [
|
|||||||
)}
|
)}
|
||||||
{machine.type === "comfy-deploy-serverless" && (
|
{machine.type === "comfy-deploy-serverless" && (
|
||||||
<>
|
<>
|
||||||
<DropdownMenuItem
|
<DropdownMenuItem asChild>
|
||||||
onClick={async () => {
|
<a
|
||||||
const url = await callServerPromise(
|
target="_blank"
|
||||||
editWorkflowOnMachine(machine.id),
|
href={machine.endpoint.replace(
|
||||||
{
|
"comfyui-api",
|
||||||
loadingText: "Getting machine url...",
|
"comfyui-app"
|
||||||
},
|
)} rel="noreferrer"
|
||||||
);
|
>
|
||||||
if (url && typeof url !== "object") {
|
Open ComfyUI
|
||||||
window.open(url, "_blank");
|
</a>
|
||||||
} else if (url && typeof url === "object" && url.error) {
|
|
||||||
console.error(url.error);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Open ComfyUI
|
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
callServerPromise(
|
buildMachine({
|
||||||
buildMachine({
|
id: machine.id,
|
||||||
id: machine.id,
|
});
|
||||||
}),
|
|
||||||
{
|
|
||||||
loadingText: "Starting machine build process",
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Rebuild
|
Rebuild
|
||||||
@@ -299,10 +269,7 @@ export const columns: ColumnDef<Machine>[] = [
|
|||||||
fieldType: "models",
|
fieldType: "models",
|
||||||
},
|
},
|
||||||
gpu: {
|
gpu: {
|
||||||
fieldType: "gpuPicker",
|
inputProps: {},
|
||||||
inputProps: {
|
|
||||||
sub: sub,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@@ -330,8 +297,6 @@ export const columns: ColumnDef<Machine>[] = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
import { useCurrentPlan } from "./useCurrentPlan";
|
|
||||||
|
|
||||||
export function MachineList({
|
export function MachineList({
|
||||||
data,
|
data,
|
||||||
userMetadata,
|
userMetadata,
|
||||||
@@ -341,14 +306,12 @@ export function MachineList({
|
|||||||
}) {
|
}) {
|
||||||
const [sorting, setSorting] = React.useState<SortingState>([]);
|
const [sorting, setSorting] = React.useState<SortingState>([]);
|
||||||
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
|
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
|
||||||
[],
|
[]
|
||||||
);
|
);
|
||||||
const [columnVisibility, setColumnVisibility] =
|
const [columnVisibility, setColumnVisibility] =
|
||||||
React.useState<VisibilityState>({});
|
React.useState<VisibilityState>({});
|
||||||
const [rowSelection, setRowSelection] = React.useState({});
|
const [rowSelection, setRowSelection] = React.useState({});
|
||||||
|
|
||||||
const sub = useCurrentPlan();
|
|
||||||
|
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data,
|
data,
|
||||||
columns,
|
columns,
|
||||||
@@ -368,21 +331,6 @@ export function MachineList({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
let machineMaxCount = 2;
|
|
||||||
|
|
||||||
// Temp fixes for machine count
|
|
||||||
if (userMetadata.betaFeaturesAccess) machineMaxCount = 5;
|
|
||||||
|
|
||||||
if (sub?.plan == "pro") {
|
|
||||||
machineMaxCount = 10;
|
|
||||||
} else if (sub?.plan == "enterprise") {
|
|
||||||
machineMaxCount = 99;
|
|
||||||
}
|
|
||||||
|
|
||||||
const locked =
|
|
||||||
data.some((machine) => machine.type === "modal-serverless") &&
|
|
||||||
data.length >= machineMaxCount;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<div className="flex items-center py-4">
|
<div className="flex items-center py-4">
|
||||||
@@ -397,18 +345,17 @@ export function MachineList({
|
|||||||
<div className="ml-auto flex gap-2">
|
<div className="ml-auto flex gap-2">
|
||||||
<InsertModal
|
<InsertModal
|
||||||
dialogClassName="sm:max-w-[600px]"
|
dialogClassName="sm:max-w-[600px]"
|
||||||
disabled={locked}
|
disabled={
|
||||||
|
data.some(
|
||||||
|
(machine) => machine.type === "comfy-deploy-serverless"
|
||||||
|
) && !userMetadata.betaFeaturesAccess
|
||||||
|
}
|
||||||
tooltip={
|
tooltip={
|
||||||
locked
|
data.some((machine) => machine.type === "comfy-deploy-serverless")
|
||||||
? `Max ${machineMaxCount} ComfyUI machine for your account, upgrade to unlock more cnfiguration.`
|
? "Only one hosted machine at preview stage"
|
||||||
: `Max ${machineMaxCount} ComfyUI machine for your account`
|
: undefined
|
||||||
}
|
}
|
||||||
buttonTitle={
|
title="New Machine"
|
||||||
<>
|
|
||||||
New Machine {locked ? <Lock size={14} /> : <Plus size={14} />}
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
title={"New Machine"}
|
|
||||||
description="Add custom ComfyUI machines to your account."
|
description="Add custom ComfyUI machines to your account."
|
||||||
serverAction={addCustomMachine}
|
serverAction={addCustomMachine}
|
||||||
formSchema={addCustomMachineSchema}
|
formSchema={addCustomMachineSchema}
|
||||||
@@ -434,9 +381,11 @@ export function MachineList({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
gpu: {
|
gpu: {
|
||||||
fieldType: "gpuPicker",
|
fieldType: !userMetadata.betaFeaturesAccess
|
||||||
|
? "fallback"
|
||||||
|
: "select",
|
||||||
inputProps: {
|
inputProps: {
|
||||||
sub: sub,
|
disabled: !userMetadata.betaFeaturesAccess,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
@@ -461,7 +410,7 @@ export function MachineList({
|
|||||||
? null
|
? null
|
||||||
: flexRender(
|
: flexRender(
|
||||||
header.column.columnDef.header,
|
header.column.columnDef.header,
|
||||||
header.getContext(),
|
header.getContext()
|
||||||
)}
|
)}
|
||||||
</TableHead>
|
</TableHead>
|
||||||
);
|
);
|
||||||
@@ -480,7 +429,7 @@ export function MachineList({
|
|||||||
<TableCell key={cell.id}>
|
<TableCell key={cell.id}>
|
||||||
{flexRender(
|
{flexRender(
|
||||||
cell.column.columnDef.cell,
|
cell.column.columnDef.cell,
|
||||||
cell.getContext(),
|
cell.getContext()
|
||||||
)}
|
)}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ type State = {
|
|||||||
json: {
|
json: {
|
||||||
event: string;
|
event: string;
|
||||||
data: any;
|
data: any;
|
||||||
},
|
}
|
||||||
) => void;
|
) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -82,7 +82,7 @@ function MachineWS({
|
|||||||
const logs = useStore((x) =>
|
const logs = useStore((x) =>
|
||||||
x.logs
|
x.logs
|
||||||
.filter((p) => p.machine_id === machine.id)
|
.filter((p) => p.machine_id === machine.id)
|
||||||
.sort((a, b) => a.timestamp - b.timestamp),
|
.sort((a, b) => a.timestamp - b.timestamp)
|
||||||
);
|
);
|
||||||
const [sid, setSid] = useState("");
|
const [sid, setSid] = useState("");
|
||||||
|
|
||||||
@@ -96,7 +96,7 @@ function MachineWS({
|
|||||||
// queryParams: {
|
// queryParams: {
|
||||||
// clientId: sid,
|
// clientId: sid,
|
||||||
// },
|
// },
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const connectionStatus = getConnectionStatus(readyState);
|
const connectionStatus = getConnectionStatus(readyState);
|
||||||
@@ -135,9 +135,7 @@ function MachineWS({
|
|||||||
You can view your run's outputs here
|
You can view your run's outputs here
|
||||||
</DialogDescription>
|
</DialogDescription>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<div className="h-[400px]">
|
<LogsViewer logs={logs} />
|
||||||
<LogsViewer logs={logs} hideTimestamp />
|
|
||||||
</div>
|
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,429 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import { getRelativeTime } from "../lib/getRelativeTime";
|
|
||||||
import { Badge } from "@/components/ui/badge";
|
|
||||||
import { Button } from "@/components/ui/button";
|
|
||||||
import { Checkbox } from "@/components/ui/checkbox";
|
|
||||||
import { InsertModal } from "./InsertModal";
|
|
||||||
import { Input } from "@/components/ui/input";
|
|
||||||
import { ScrollArea } from "@/components/ui/scroll-area";
|
|
||||||
import {
|
|
||||||
DropdownMenu,
|
|
||||||
DropdownMenuContent,
|
|
||||||
DropdownMenuItem,
|
|
||||||
DropdownMenuLabel,
|
|
||||||
DropdownMenuTrigger,
|
|
||||||
} from "@/components/ui/dropdown-menu";
|
|
||||||
import {
|
|
||||||
Table,
|
|
||||||
TableBody,
|
|
||||||
TableCell,
|
|
||||||
TableHead,
|
|
||||||
TableHeader,
|
|
||||||
TableRow,
|
|
||||||
} from "@/components/ui/table";
|
|
||||||
import type { getAllUserModels } from "@/server/getAllUserModel";
|
|
||||||
import type {
|
|
||||||
ColumnDef,
|
|
||||||
ColumnFiltersState,
|
|
||||||
SortingState,
|
|
||||||
VisibilityState,
|
|
||||||
} from "@tanstack/react-table";
|
|
||||||
import {
|
|
||||||
flexRender,
|
|
||||||
getCoreRowModel,
|
|
||||||
getFilteredRowModel,
|
|
||||||
getPaginationRowModel,
|
|
||||||
getSortedRowModel,
|
|
||||||
useReactTable,
|
|
||||||
} from "@tanstack/react-table";
|
|
||||||
import { ArrowUpDown, MoreHorizontal } from "lucide-react";
|
|
||||||
import * as React from "react";
|
|
||||||
import { addModel, deleteModel } from "@/server/curdModel";
|
|
||||||
import { downloadUrlModelSchema } from "@/server/addCivitaiModelSchema";
|
|
||||||
import { modelEnumType } from "@/db/schema";
|
|
||||||
|
|
||||||
export type ModelItemList = NonNullable<
|
|
||||||
Awaited<ReturnType<typeof getAllUserModels>>
|
|
||||||
>[0];
|
|
||||||
|
|
||||||
export const columns: ColumnDef<ModelItemList>[] = [
|
|
||||||
{
|
|
||||||
accessorKey: "id",
|
|
||||||
id: "select",
|
|
||||||
header: ({ table }) => (
|
|
||||||
<Checkbox
|
|
||||||
checked={
|
|
||||||
table.getIsAllPageRowsSelected() ||
|
|
||||||
(table.getIsSomePageRowsSelected() && "indeterminate")
|
|
||||||
}
|
|
||||||
onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)}
|
|
||||||
aria-label="Select all"
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
cell: ({ row }) => (
|
|
||||||
<Checkbox
|
|
||||||
checked={row.getIsSelected()}
|
|
||||||
onCheckedChange={(value) => row.toggleSelected(!!value)}
|
|
||||||
aria-label="Select row"
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
enableSorting: false,
|
|
||||||
enableHiding: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
accessorKey: "model_name",
|
|
||||||
header: ({ column }) => {
|
|
||||||
return (
|
|
||||||
<button
|
|
||||||
className="flex items-center hover:underline"
|
|
||||||
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
|
|
||||||
>
|
|
||||||
Model Name
|
|
||||||
<ArrowUpDown className="ml-2 h-4 w-4" />
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
cell: ({ row }) => {
|
|
||||||
const model = row.original;
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{/*<a
|
|
||||||
className="hover:underline flex gap-2"
|
|
||||||
href={`/storage/${model.id}`} // TODO
|
|
||||||
>*/}
|
|
||||||
<span className="truncate max-w-[200px]">
|
|
||||||
{row.original.model_name}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
{model.is_public ? <></> : <Badge variant="orange">Private</Badge>}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
accessorKey: "status",
|
|
||||||
header: ({ column }) => {
|
|
||||||
return (
|
|
||||||
<button
|
|
||||||
className="flex items-center hover:underline"
|
|
||||||
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
|
|
||||||
>
|
|
||||||
Status
|
|
||||||
<ArrowUpDown className="ml-2 h-4 w-4" />
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
cell: ({ row }) => {
|
|
||||||
return (
|
|
||||||
<Badge
|
|
||||||
variant={
|
|
||||||
row.original.status === "failed"
|
|
||||||
? "red"
|
|
||||||
: row.original.status === "started"
|
|
||||||
? "yellow"
|
|
||||||
: "green"
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{row.original.status}
|
|
||||||
</Badge>
|
|
||||||
);
|
|
||||||
// NOTE: retry downloads on failures
|
|
||||||
// const oneHourAgo = new Date(new Date().getTime() - (60 * 60 * 1000));
|
|
||||||
// const lastUpdated = new Date(row.original.updated_at);
|
|
||||||
// const canRefresh = row.original.status === "failed" && lastUpdated < oneHourAgo;
|
|
||||||
// const canRefresh = row.original.status === "failed" && lastUpdated < oneHourAgo;
|
|
||||||
// cell: ({ row }) => {
|
|
||||||
// // const oneHourAgo = new Date(new Date().getTime() - (60 * 60 * 1000));
|
|
||||||
// // const lastUpdated = new Date(row.original.updated_at);
|
|
||||||
// // const canRefresh = row.original.status === "failed" && lastUpdated < oneHourAgo;
|
|
||||||
// const canReDownload = true;
|
|
||||||
//
|
|
||||||
// return (
|
|
||||||
// <div className="flex items-center space-x-2">
|
|
||||||
// <Badge
|
|
||||||
// variant={row.original.status === "failed"
|
|
||||||
// ? "red"
|
|
||||||
// : row.original.status === "started"
|
|
||||||
// ? "yellow"
|
|
||||||
// : "green"}
|
|
||||||
// >
|
|
||||||
// {row.original.status}
|
|
||||||
// </Badge>
|
|
||||||
// {canReDownload && (
|
|
||||||
// <RefreshCcw
|
|
||||||
// onClick={() => {
|
|
||||||
// redownloadCheckpoint(row.original);
|
|
||||||
// }}
|
|
||||||
// className="h-4 w-4 cursor-pointer" // Adjust the size with h-x and w-x classes
|
|
||||||
// />
|
|
||||||
// )}
|
|
||||||
// </div>
|
|
||||||
// );
|
|
||||||
// },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
accessorKey: "upload_type",
|
|
||||||
header: ({ column }) => {
|
|
||||||
return (
|
|
||||||
<button
|
|
||||||
className="flex items-center hover:underline"
|
|
||||||
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
|
|
||||||
>
|
|
||||||
Source
|
|
||||||
<ArrowUpDown className="ml-2 h-4 w-4" />
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
cell: ({ row }) => {
|
|
||||||
return <Badge variant="cyan">{row.original.upload_type}</Badge>;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
accessorKey: "model_type",
|
|
||||||
header: ({ column }) => {
|
|
||||||
return (
|
|
||||||
<button
|
|
||||||
className="flex items-center hover:underline"
|
|
||||||
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
|
|
||||||
>
|
|
||||||
Model Type
|
|
||||||
<ArrowUpDown className="ml-2 h-4 w-4" />
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
cell: ({ row }) => {
|
|
||||||
const model_type_map: Record<modelEnumType, any> = {
|
|
||||||
checkpoint: "amber",
|
|
||||||
lora: "green",
|
|
||||||
embedding: "violet",
|
|
||||||
vae: "teal",
|
|
||||||
clip: "default",
|
|
||||||
clip_vision: "default",
|
|
||||||
configs: "default",
|
|
||||||
controlnet: "default",
|
|
||||||
upscale_models: "default",
|
|
||||||
ipadapter: "default",
|
|
||||||
};
|
|
||||||
|
|
||||||
function getBadgeColor(modelType: modelEnumType) {
|
|
||||||
return model_type_map[modelType]
|
|
||||||
}
|
|
||||||
|
|
||||||
const color = getBadgeColor(row.original.model_type);
|
|
||||||
return <Badge variant={color}>{row.original.model_type}</Badge>;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
accessorKey: "date",
|
|
||||||
sortingFn: "datetime",
|
|
||||||
enableSorting: true,
|
|
||||||
header: ({ column }) => {
|
|
||||||
return (
|
|
||||||
<button
|
|
||||||
className="w-full flex items-center justify-end hover:underline truncate"
|
|
||||||
// variant="ghost"
|
|
||||||
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
|
|
||||||
>
|
|
||||||
Update Date
|
|
||||||
<ArrowUpDown className="ml-2 h-4 w-4" />
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
cell: ({ row }) => (
|
|
||||||
<div className="w-full capitalize text-right truncate">
|
|
||||||
{getRelativeTime(row.original.updated_at)}
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
// TODO: deletion and editing for future sprint
|
|
||||||
{
|
|
||||||
id: "actions",
|
|
||||||
enableHiding: false,
|
|
||||||
cell: ({ row }) => {
|
|
||||||
const model = row.original;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<DropdownMenu>
|
|
||||||
<DropdownMenuTrigger asChild>
|
|
||||||
<Button variant="ghost" className="h-8 w-8 p-0">
|
|
||||||
<span className="sr-only">Open menu</span>
|
|
||||||
<MoreHorizontal className="h-4 w-4" />
|
|
||||||
</Button>
|
|
||||||
</DropdownMenuTrigger>
|
|
||||||
<DropdownMenuContent align="end">
|
|
||||||
<DropdownMenuLabel>Actions</DropdownMenuLabel>
|
|
||||||
<DropdownMenuItem
|
|
||||||
className="text-destructive"
|
|
||||||
onClick={() => {
|
|
||||||
deleteModel(model.id);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Delete Model
|
|
||||||
</DropdownMenuItem>
|
|
||||||
</DropdownMenuContent>
|
|
||||||
</DropdownMenu>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export function ModelList({ data }: { data: ModelItemList[] }) {
|
|
||||||
const [sorting, setSorting] = React.useState<SortingState>([]);
|
|
||||||
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
const [columnVisibility, setColumnVisibility] =
|
|
||||||
React.useState<VisibilityState>({});
|
|
||||||
const [rowSelection, setRowSelection] = React.useState({});
|
|
||||||
|
|
||||||
const table = useReactTable({
|
|
||||||
data,
|
|
||||||
columns,
|
|
||||||
onSortingChange: setSorting,
|
|
||||||
onColumnFiltersChange: setColumnFilters,
|
|
||||||
getCoreRowModel: getCoreRowModel(),
|
|
||||||
getPaginationRowModel: getPaginationRowModel(),
|
|
||||||
getSortedRowModel: getSortedRowModel(),
|
|
||||||
getFilteredRowModel: getFilteredRowModel(),
|
|
||||||
onColumnVisibilityChange: setColumnVisibility,
|
|
||||||
onRowSelectionChange: setRowSelection,
|
|
||||||
state: {
|
|
||||||
sorting,
|
|
||||||
columnFilters,
|
|
||||||
columnVisibility,
|
|
||||||
rowSelection,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="grid grid-rows-[auto,1fr,auto] h-full">
|
|
||||||
<div className="flex flex-row w-full items-center py-4">
|
|
||||||
<Input
|
|
||||||
placeholder="Filter workflows..."
|
|
||||||
value={
|
|
||||||
(table.getColumn("model_name")?.getFilterValue() as string) ?? ""
|
|
||||||
}
|
|
||||||
onChange={(event) =>
|
|
||||||
table.getColumn("model_name")?.setFilterValue(event.target.value)
|
|
||||||
}
|
|
||||||
className="max-w-sm"
|
|
||||||
/>
|
|
||||||
<div className="ml-auto flex gap-2">
|
|
||||||
<InsertModal
|
|
||||||
dialogClassName="sm:max-w-[600px]"
|
|
||||||
disabled={
|
|
||||||
false // TODO: limitations based on plan
|
|
||||||
}
|
|
||||||
title="Add a Model"
|
|
||||||
description="using a link to a model"
|
|
||||||
serverAction={addModel}
|
|
||||||
formSchema={downloadUrlModelSchema}
|
|
||||||
fieldConfig={{
|
|
||||||
url: {
|
|
||||||
fieldType: "modelUrlPicker",
|
|
||||||
inputProps: { required: true },
|
|
||||||
description: (
|
|
||||||
<>
|
|
||||||
Pick a model from{" "}
|
|
||||||
<a
|
|
||||||
href="https://www.civitai.com/models"
|
|
||||||
target="_blank"
|
|
||||||
className="underline text-blue-600 hover:text-blue-800 visited:text-purple-600"
|
|
||||||
rel="noreferrer"
|
|
||||||
>
|
|
||||||
civitai.com
|
|
||||||
</a>{" "}
|
|
||||||
or a url we can download a model from
|
|
||||||
</>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
model_type: {
|
|
||||||
fieldType: "select",
|
|
||||||
inputProps: { required: true },
|
|
||||||
description: (
|
|
||||||
<>We'll figure this out if you pick a civitai model</>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<ScrollArea className="h-full w-full rounded-md border">
|
|
||||||
<Table>
|
|
||||||
<TableHeader className="bg-background top-0 sticky">
|
|
||||||
{table.getHeaderGroups().map((headerGroup) => (
|
|
||||||
<TableRow key={headerGroup.id}>
|
|
||||||
{headerGroup.headers.map((header) => {
|
|
||||||
return (
|
|
||||||
<TableHead key={header.id}>
|
|
||||||
{header.isPlaceholder
|
|
||||||
? null
|
|
||||||
: flexRender(
|
|
||||||
header.column.columnDef.header,
|
|
||||||
header.getContext(),
|
|
||||||
)}
|
|
||||||
</TableHead>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</TableRow>
|
|
||||||
))}
|
|
||||||
</TableHeader>
|
|
||||||
<TableBody>
|
|
||||||
{table.getRowModel().rows?.length ? (
|
|
||||||
table.getRowModel().rows.map((row) => (
|
|
||||||
<TableRow
|
|
||||||
key={row.id}
|
|
||||||
data-state={row.getIsSelected() && "selected"}
|
|
||||||
>
|
|
||||||
{row.getVisibleCells().map((cell) => (
|
|
||||||
<TableCell key={cell.id}>
|
|
||||||
{flexRender(
|
|
||||||
cell.column.columnDef.cell,
|
|
||||||
cell.getContext(),
|
|
||||||
)}
|
|
||||||
</TableCell>
|
|
||||||
))}
|
|
||||||
</TableRow>
|
|
||||||
))
|
|
||||||
) : (
|
|
||||||
<TableRow>
|
|
||||||
<TableCell
|
|
||||||
colSpan={columns.length}
|
|
||||||
className="h-24 text-center"
|
|
||||||
>
|
|
||||||
No results.
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
)}
|
|
||||||
</TableBody>
|
|
||||||
</Table>
|
|
||||||
</ScrollArea>
|
|
||||||
<div className="flex flex-row items-center justify-end space-x-2 py-4">
|
|
||||||
<div className="flex-1 text-sm text-muted-foreground">
|
|
||||||
{table.getFilteredSelectedRowModel().rows.length} of{" "}
|
|
||||||
{table.getFilteredRowModel().rows.length} row(s) selected.
|
|
||||||
</div>
|
|
||||||
<div className="space-x-2">
|
|
||||||
<Button
|
|
||||||
variant="outline"
|
|
||||||
size="sm"
|
|
||||||
onClick={() => table.previousPage()}
|
|
||||||
disabled={!table.getCanPreviousPage()}
|
|
||||||
>
|
|
||||||
Previous
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
variant="outline"
|
|
||||||
size="sm"
|
|
||||||
onClick={() => table.nextPage()}
|
|
||||||
disabled={!table.getCanNextPage()}
|
|
||||||
>
|
|
||||||
Next
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -22,7 +22,6 @@ import {
|
|||||||
} from "@clerk/nextjs";
|
} from "@clerk/nextjs";
|
||||||
import { Github, Menu } from "lucide-react";
|
import { Github, Menu } from "lucide-react";
|
||||||
import meta from "next-gen/config";
|
import meta from "next-gen/config";
|
||||||
import { useFeatureFlagEnabled } from "posthog-js/react";
|
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { useMediaQuery } from "usehooks-ts";
|
import { useMediaQuery } from "usehooks-ts";
|
||||||
|
|
||||||
@@ -30,17 +29,15 @@ export function Navbar() {
|
|||||||
const { organization } = useOrganization();
|
const { organization } = useOrganization();
|
||||||
const _isDesktop = useMediaQuery("(min-width: 1024px)");
|
const _isDesktop = useMediaQuery("(min-width: 1024px)");
|
||||||
const [isDesktop, setIsDesktop] = useState(true);
|
const [isDesktop, setIsDesktop] = useState(true);
|
||||||
|
const [isSheetOpen, setSheetOpen] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setIsDesktop(_isDesktop);
|
setIsDesktop(_isDesktop);
|
||||||
}, [_isDesktop]);
|
}, [_isDesktop]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="flex flex-row items-center gap-4">
|
<div className="flex flex-row items-center gap-4">
|
||||||
{!isDesktop && (
|
{!isDesktop && (
|
||||||
<Sheet>
|
<Sheet open={isSheetOpen} onOpenChange={(open) => setSheetOpen(open)}>
|
||||||
<SheetTrigger asChild>
|
<SheetTrigger asChild>
|
||||||
<button className="flex items-center justify-center w-8 h-8 p-2">
|
<button className="flex items-center justify-center w-8 h-8 p-2">
|
||||||
<Menu />
|
<Menu />
|
||||||
@@ -51,7 +48,17 @@ export function Navbar() {
|
|||||||
<SheetTitle className="text-start">Comfy Deploy</SheetTitle>
|
<SheetTitle className="text-start">Comfy Deploy</SheetTitle>
|
||||||
</SheetHeader>
|
</SheetHeader>
|
||||||
<div className="grid h-full grid-rows-[1fr_auto]">
|
<div className="grid h-full grid-rows-[1fr_auto]">
|
||||||
<NavbarMenu className=" h-full" />
|
<NavbarMenu
|
||||||
|
className=" h-full"
|
||||||
|
closeSheet={() => setSheetOpen(false)}
|
||||||
|
/>
|
||||||
|
{/* <OrganizationSwitcher
|
||||||
|
appearance={{
|
||||||
|
elements: {
|
||||||
|
rootBox: "flex items-center justify-center z-[50]",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/> */}
|
||||||
<Popover>
|
<Popover>
|
||||||
<PopoverTrigger asChild>
|
<PopoverTrigger asChild>
|
||||||
<Button variant="outline">
|
<Button variant="outline">
|
||||||
@@ -82,26 +89,20 @@ export function Navbar() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex flex-row items-center gap-2">
|
<div className="flex flex-row items-center gap-2">
|
||||||
{isDesktop && <NavbarMenu />}
|
{isDesktop && <NavbarMenu />}
|
||||||
{/* <Button
|
<Button
|
||||||
asChild
|
asChild
|
||||||
variant="link"
|
variant="link"
|
||||||
className="rounded-full aspect-square p-2 mr-4"
|
className="rounded-full aspect-square p-2 mr-4"
|
||||||
>
|
>
|
||||||
<a href="/docs">Docs</a>
|
<a href="/docs">Docs</a>
|
||||||
</Button> */}
|
</Button>
|
||||||
<UserButton
|
<UserButton />
|
||||||
afterSignOutUrl="/"
|
|
||||||
/>
|
|
||||||
<Button
|
<Button
|
||||||
asChild
|
asChild
|
||||||
variant="outline"
|
variant="outline"
|
||||||
className="rounded-full aspect-square p-2"
|
className="rounded-full aspect-square p-2"
|
||||||
>
|
>
|
||||||
<a
|
<a target="_blank" href="https://github.com/BennyKok/comfyui-deploy" rel="noreferrer">
|
||||||
target="_blank"
|
|
||||||
href="https://github.com/BennyKok/comfyui-deploy"
|
|
||||||
rel="noreferrer"
|
|
||||||
>
|
|
||||||
<Github />
|
<Github />
|
||||||
</a>
|
</a>
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -6,11 +6,16 @@ import { cn } from "@/lib/utils";
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { usePathname } from "next/navigation";
|
import { usePathname } from "next/navigation";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import { useFeatureFlagEnabled } from "posthog-js/react";
|
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { useMediaQuery } from "usehooks-ts";
|
import { useMediaQuery } from "usehooks-ts";
|
||||||
|
|
||||||
export function NavbarMenu({ className }: { className?: string }) {
|
export function NavbarMenu({
|
||||||
|
className,
|
||||||
|
closeSheet,
|
||||||
|
}: {
|
||||||
|
className?: string;
|
||||||
|
closeSheet?: () => void;
|
||||||
|
}) {
|
||||||
const _isDesktop = useMediaQuery("(min-width: 1024px)");
|
const _isDesktop = useMediaQuery("(min-width: 1024px)");
|
||||||
const [isDesktop, setIsDesktop] = useState(true);
|
const [isDesktop, setIsDesktop] = useState(true);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -22,8 +27,6 @@ export function NavbarMenu({ className }: { className?: string }) {
|
|||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const pricingPlanFlagEnable = useFeatureFlagEnabled("pricing-plan");
|
|
||||||
|
|
||||||
const pages = [
|
const pages = [
|
||||||
{
|
{
|
||||||
name: "Workflows",
|
name: "Workflows",
|
||||||
@@ -38,27 +41,11 @@ export function NavbarMenu({ className }: { className?: string }) {
|
|||||||
path: "/api-keys",
|
path: "/api-keys",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Storage",
|
name: "Examples",
|
||||||
path: "/storage",
|
path: "/examples"
|
||||||
},
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
if (pricingPlanFlagEnable) {
|
|
||||||
pages.push({
|
|
||||||
name: "Pricing",
|
|
||||||
path: "/pricing",
|
|
||||||
})
|
|
||||||
pages.push({
|
|
||||||
name: "Usage",
|
|
||||||
path: "/usage",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pages.push({
|
|
||||||
name: "Docs",
|
|
||||||
path: "/docs",
|
|
||||||
})
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cn("mr-2", className)}>
|
<div className={cn("mr-2", className)}>
|
||||||
{/* <div className="w-full h-full absolute inset-x-0 top-0 flex items-center justify-center pointer-events-none"> */}
|
{/* <div className="w-full h-full absolute inset-x-0 top-0 flex items-center justify-center pointer-events-none"> */}
|
||||||
@@ -67,7 +54,7 @@ export function NavbarMenu({ className }: { className?: string }) {
|
|||||||
defaultValue={pathname}
|
defaultValue={pathname}
|
||||||
className="w-fit flex pointer-events-auto"
|
className="w-fit flex pointer-events-auto"
|
||||||
>
|
>
|
||||||
<TabsList className=" w-full ">
|
<TabsList className="w-full">
|
||||||
{pages.map((page) => (
|
{pages.map((page) => (
|
||||||
<TabsTrigger
|
<TabsTrigger
|
||||||
key={page.name}
|
key={page.name}
|
||||||
@@ -91,6 +78,9 @@ export function NavbarMenu({ className }: { className?: string }) {
|
|||||||
<Link
|
<Link
|
||||||
key={page.name}
|
key={page.name}
|
||||||
href={page.path}
|
href={page.path}
|
||||||
|
onClick={() => {
|
||||||
|
if (!!closeSheet) closeSheet();
|
||||||
|
}}
|
||||||
className="p-2 hover:bg-gray-100/20 hover:underline"
|
className="p-2 hover:bg-gray-100/20 hover:underline"
|
||||||
>
|
>
|
||||||
{page.name}
|
{page.name}
|
||||||
|
|||||||
@@ -1,25 +1,15 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import useSWR from "swr";
|
|
||||||
import { DownloadButton } from "./DownloadButton";
|
import { DownloadButton } from "./DownloadButton";
|
||||||
import { getFileDownloadUrl } from "@/server/getFileDownloadUrl";
|
import { getFileDownloadUrl } from "@/server/getFileDownloadUrl";
|
||||||
|
|
||||||
export function OutputRender(props: {
|
export async function OutputRender(props: {
|
||||||
run_id: string;
|
run_id: string;
|
||||||
filename: string;
|
filename: string;
|
||||||
}) {
|
}) {
|
||||||
const { data: url } = useSWR(
|
|
||||||
"run-outputs+" + props.run_id + props.filename,
|
|
||||||
async () => {
|
|
||||||
return await getFileDownloadUrl(
|
|
||||||
`outputs/runs/${props.run_id}/${props.filename}`,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!url) return <></>;
|
|
||||||
|
|
||||||
if (props.filename.endsWith(".mp4") || props.filename.endsWith(".webm")) {
|
if (props.filename.endsWith(".mp4") || props.filename.endsWith(".webm")) {
|
||||||
|
const url = await getFileDownloadUrl(
|
||||||
|
`outputs/runs/${props.run_id}/${props.filename}`,
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<video controls autoPlay className="w-[400px]">
|
<video controls autoPlay className="w-[400px]">
|
||||||
<source src={url} type="video/mp4" />
|
<source src={url} type="video/mp4" />
|
||||||
@@ -35,8 +25,17 @@ export function OutputRender(props: {
|
|||||||
props.filename.endsWith(".jpg") ||
|
props.filename.endsWith(".jpg") ||
|
||||||
props.filename.endsWith(".jpeg")
|
props.filename.endsWith(".jpeg")
|
||||||
) {
|
) {
|
||||||
|
const url = await getFileDownloadUrl(
|
||||||
|
`outputs/runs/${props.run_id}/${props.filename}`,
|
||||||
|
);
|
||||||
|
|
||||||
return <img className="max-w-[200px]" alt={props.filename} src={url} />;
|
return <img className="max-w-[200px]" alt={props.filename} src={url} />;
|
||||||
} else {
|
} else {
|
||||||
|
const url = await getFileDownloadUrl(
|
||||||
|
`outputs/runs/${props.run_id}/${props.filename}`,
|
||||||
|
);
|
||||||
|
// console.log(url);
|
||||||
|
|
||||||
return <DownloadButton filename={props.filename} href={url} />;
|
return <DownloadButton filename={props.filename} href={url} />;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user