-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
537 additions
and
128 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,21 +5,34 @@ inputs: | |
description: "Operating System. macos, linux, windows." | ||
required: true | ||
default: "" | ||
python_version: | ||
description: "Python Version. Will be used in the conda install command for pytorch. 3.9 or 3.10. Only valid when os is linux or windows." | ||
required: false | ||
default: "3.9" | ||
cuda_version: | ||
description: "CUDA Version. Will be used in the conda install command for pytorch. 11.8 or 12.1. Only valid when os is linux or windows." | ||
required: false | ||
default: "12.1" | ||
torch_version: | ||
description: "Pytorch Version. Will be used in the conda install command for pytorch. 1.10.0 or 1.11.0. Only valid when os is linux or windows." | ||
required: false | ||
default: 'stable' | ||
models-json: | ||
description: 'JSON string containing models and their download URLs. The models will be downloaded into the exact directory relative to /ComfyUI/models/. eg { "model_name": { url: "https://example.com/model.pth", "directory": "checkpoints" } }' | ||
required: false | ||
workflow_filenames: | ||
description: "List of workflows to run. Seperate by comma. eg. | ||
'workflow1,workflow2'. The list of workflow is listed in workflows/" | ||
required: true | ||
workflow_name: | ||
description: "Name of the workflow to run. This is used to identify the workflow in the logs." | ||
required: true | ||
workflow_json_path: | ||
description: "Path (relative to the root of the Github repo) of the Workflow | ||
JSON to run. Must be API format JSON." | ||
comfyui_flags: | ||
description: "Flags to pass to the comfyui application. eg. --force-fp16" | ||
required: false | ||
default: "workflow.json" | ||
default: '' | ||
# Not yet supported | ||
workflow_raw_json: | ||
description: "Workflow's raw json file" | ||
required: false | ||
default: '' | ||
timeout: | ||
description: "Timeout for the workflow (in seconds)" | ||
required: false | ||
|
@@ -76,6 +89,7 @@ runs: | |
miniconda-version: latest | ||
activate-environment: comfyui | ||
auto-activate-base: false | ||
python-version: ${{ inputs.python_version }} | ||
|
||
- name: '[Unix-Mac-Only] Install Pytorch nightly' | ||
if: ${{ inputs.os == 'macos' }} | ||
|
@@ -127,13 +141,13 @@ runs: | |
if: ${{ inputs.os != 'windows' }} | ||
shell: bash -el {0} | ||
run: | | ||
python main.py --quick-test-for-ci | ||
comfy launch -- --quick-test-for-ci | ||
- name: '[Unix] Run Python application' | ||
if: ${{ inputs.os != 'windows' }} | ||
shell: bash -el {0} | ||
run: | | ||
python3 main.py --force-fp16 > application.log 2>&1 & | ||
comfy launch -- --force-fp16 > application.log 2>&1 & | ||
- name: '[Unix] Check if the server is running' | ||
if: ${{ inputs.os != 'windows' }} | ||
|
@@ -155,43 +169,12 @@ runs: | |
echo "Script output: " | ||
echo "$PROMPT_ID" | ||
- name: '[Unix] Get start time' | ||
id: unix_start_time | ||
shell: bash | ||
if: ${{ inputs.os != 'windows' }} | ||
run: | | ||
echo "start_time=$(date +%s)" >> $GITHUB_OUTPUT | ||
- name: '[Unix] Check Prompt Status and Get Output Files' | ||
if: ${{ inputs.os != 'windows' }} | ||
shell: bash -el {0} | ||
run: | | ||
cd ${{ github.action_path }} | ||
echo "Prompt ID: ${{ steps.unix_queue_prompt.outputs.prompt_id }}" | ||
python3 check_prompt_status.py ${{ steps.unix_queue_prompt.outputs.prompt_id }} http://localhost:8188/history ${{ inputs.timeout }} | ||
- name: '[Unix] Get end time Unix' | ||
id: unix_end_time | ||
shell: bash | ||
if: ${{ inputs.os != 'windows' }} | ||
run: | | ||
echo "end_time=$(date +%s)" >> $GITHUB_OUTPUT | ||
- name: '[Unix] Auth to GCS' | ||
uses: "google-github-actions/auth@v2" | ||
if: ${{ inputs.os != 'windows' }} | ||
with: | ||
credentials_json: "${{ inputs.google_credentials }}" | ||
|
||
- name: '[Unix] Upload Output Files to GCS' | ||
if: ${{ success() && inputs.os != 'windows' }} | ||
id: unix_upload-output-files | ||
uses: google-github-actions/upload-cloud-storage@v2 | ||
with: | ||
path: ${{ github.workspace }}/output | ||
destination: ${{ inputs.gcs_bucket_name }}/output-files/${{ github.job }}-${{ inputs.os }}-${{ inputs.workflow_name }}-run${{ github.run_id }} | ||
glob: "${{ inputs.output_prefix }}*" | ||
|
||
- name: '[Unix] Upload log file to GCS' | ||
if: ${{ ( success() || failure() ) && inputs.os != 'windows' }} | ||
id: unix_upload-log-files | ||
|
@@ -258,20 +241,21 @@ runs: | |
start_time: $start_time, | ||
end_time: $end_time | ||
}') | ||
echo "$payload" | ||
response_code=$(curl -o "${{ github.workspace }}/application.log" \ | ||
-s -w "%{http_code}" \ | ||
-X POST "${{inputs.api_endpoint}}" \ | ||
-H "Content-Type: application/json" \ | ||
-d "$payload") | ||
if [[ $response_code -ne 200 ]]; then | ||
echo "API request failed with status code $response_code and response body" | ||
cat "${{ github.workspace }}/application.log" | ||
exit 1 | ||
fi | ||
- name: '[Unix] Upload Output Files' | ||
uses: actions/upload-artifact@v4 | ||
|
@@ -297,34 +281,35 @@ runs: | |
run: conda deactivate && conda env remove --name comfyui && conda clean -all | ||
|
||
|
||
##################################################################################### | ||
## Windows Steps (F**k powershell) ## | ||
## ## | ||
## _.-;;-._ _ ## | ||
## '-..-'| || | | | ## | ||
## '-..-'|_.-;;-._| | |===( ) ////// ## | ||
## '-..-'| || | |_| ||| | o o| ## | ||
## '-..-'|_.-''-._| ||| ( c ) ____ ## | ||
## ||| \= / || \_ ## | ||
## |||||| || | ## | ||
## |||||| ...||__/|-" ## | ||
## |||||| __|________|__ ## | ||
## ||| |______________| ## | ||
## ||| || || || || ## | ||
## ||| || || || || ## | ||
## -------------------------------------|||-------------||-||------||-||------- ## | ||
## |__> || || || || ## | ||
## ## | ||
## ## | ||
##################################################################################### | ||
##################################################################################### | ||
## Windows Steps (F**k powershell) ## | ||
## ## | ||
## _.-;;-._ _ ## | ||
## '-..-'| || | | | ## | ||
## '-..-'|_.-;;-._| | |===( ) ////// ## | ||
## '-..-'| || | |_| ||| | o o| ## | ||
## '-..-'|_.-''-._| ||| ( c ) ____ ## | ||
## ||| \= / || \_ ## | ||
## |||||| || | ## | ||
## |||||| ...||__/|-" ## | ||
## |||||| __|________|__ ## | ||
## ||| |______________| ## | ||
## ||| || || || || ## | ||
## ||| || || || || ## | ||
## -------------------------------------|||-------------||-||------||-||------- ## | ||
## |__> || || || || ## | ||
## ## | ||
## ## | ||
##################################################################################### | ||
|
||
- name: '[Win] Setup Conda' | ||
uses: conda-incubator/[email protected] | ||
if: ${{ inputs.os == 'windows' }} | ||
with: | ||
auto-update-conda: true | ||
miniconda-version: latest | ||
activate-environment: comfyui | ||
python-version: ${{ inputs.python_version }} | ||
continue-on-error: true | ||
|
||
- name: '[Win-Only] Install Pytorch' | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,43 +0,0 @@ | ||
import requests | ||
import time | ||
import sys | ||
|
||
def get_status(prompt_id, url): | ||
response = requests.get(f"{url}/{prompt_id}") | ||
if response.status_code == 200: | ||
return response.json() | ||
return None | ||
|
||
def is_completed(status_response, prompt_id): | ||
# Check if the expected fields exist in the response | ||
return ( | ||
status_response and | ||
prompt_id in status_response and | ||
'status' in status_response[prompt_id] and | ||
status_response[prompt_id]['status'].get('completed', False) | ||
) | ||
|
||
def main(prompt_id, server_url, timeout): | ||
start_time = time.time() | ||
while True: | ||
status_response = get_status(prompt_id, server_url) | ||
if is_completed(status_response, prompt_id): | ||
print("Prompt completed.") | ||
break | ||
|
||
if time.time() - start_time > timeout: | ||
print("Timeout reached without completion.") | ||
sys.exit(1) | ||
|
||
time.sleep(10) # Check every 10 seconds | ||
|
||
if __name__ == "__main__": | ||
if len(sys.argv) != 4: | ||
print("Usage: python check_prompt_status.py <prompt_id> <server_url> <timeout>") | ||
sys.exit(1) | ||
|
||
prompt_id_arg = sys.argv[1] | ||
server_url_arg = sys.argv[2] | ||
timeout_arg = int(sys.argv[3]) | ||
|
||
main(prompt_id_arg, server_url_arg, timeout_arg) | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,37 +1,127 @@ | ||
import argparse | ||
import json | ||
import subprocess | ||
import datetime | ||
|
||
import requests | ||
import argparse | ||
|
||
from firebase_admin import storage | ||
|
||
def read_json_file(file_path): | ||
with open(file_path, 'r') as file: | ||
with open(file_path, 'r', encoding='utf-8') as file: | ||
return json.load(file) | ||
|
||
def post_json_to_server(json_data, url): | ||
return requests.post(url, json=json_data) | ||
|
||
def main(json_file_path, server_url): | ||
# Read JSON file | ||
json_contents = read_json_file(json_file_path) | ||
# Print the json_contents | ||
#print(json.dumps(json_contents, indent=4)) | ||
# Construct the new JSON object | ||
data_to_send = {"prompt": json_contents} | ||
|
||
# Post the JSON to the server | ||
response = post_json_to_server(data_to_send, server_url) | ||
#print("Status Code:" + str(response.status_code)) | ||
#print("Response:" + response.text) | ||
response_json = response.json() | ||
if ('prompt_id' not in response_json): | ||
print("Error: prompt_id not found in response.") | ||
print(response_json) | ||
def get_status(prompt_id, url): | ||
response = requests.get(f"{url}/{prompt_id}") | ||
if response.status_code == 200: | ||
return response.json() | ||
return None | ||
|
||
def is_completed(status_response, prompt_id): | ||
# Check if the expected fields exist in the response | ||
return ( | ||
status_response | ||
and prompt_id in status_response | ||
and 'status' in status_response[prompt_id] | ||
and status_response[prompt_id]['status'].get('completed', False) | ||
) | ||
|
||
#TODO: add support for different file type | ||
def upload_img_from_filename(bucket_name: str, gs_path: str, file_path: str, public: bool = True, content_type="image/png"): | ||
bucket = storage.bucket(bucket_name) | ||
blob = bucket.blob(gs_path) | ||
blob.upload_from_filename(file_path, content_type=content_type) | ||
if public: | ||
blob.make_public() | ||
|
||
|
||
def send_payload_to_api(args, output_files_gcs_paths, | ||
start_time, end_time): | ||
|
||
# Create the payload as a dictionary | ||
payload = { | ||
"repo": args.repo, | ||
"run_id": args.run_id, | ||
"os": args.os, | ||
"cuda_version": args.cuda_version, | ||
"output_files_gcs_paths": output_files_gcs_paths, | ||
"commit_hash": args.commit_hash, | ||
"commit_time": args.commit_time, | ||
"commit_message": args.commit_message, | ||
"branch_name": args.branch_name, | ||
"bucket_name": args.bucket_name, | ||
"workflow_name": args.workflow_name, | ||
"start_time": start_time, | ||
"end_time": end_time | ||
} | ||
|
||
# Convert payload dictionary to a JSON string | ||
payload_json = json.dumps(payload) | ||
|
||
# Send POST request | ||
headers = {'Content-Type': 'application/json'} | ||
response = requests.post(args.api_endpoint, headers=headers, data=payload_json) | ||
|
||
# Write response to application.log | ||
log_file_path = "./application.log" | ||
with open(log_file_path, 'w', encoding='utf-8') as log_file: | ||
log_file.write("\n##### Comfy CI Post Response #####\n") | ||
log_file.write(response.text) | ||
|
||
# Check the response code | ||
if response.status_code != 200: | ||
print(f"API request failed with status code {response.status_code} and response body") | ||
print(response.text) | ||
exit(1) | ||
else: | ||
print(response_json['prompt_id']) | ||
print("API request successful") | ||
|
||
return response.status_code | ||
|
||
def main(args): | ||
# Split the workflow file names using "," | ||
workflow_files = args.comfy_workflow_names.split(',') | ||
|
||
counter = 1 | ||
|
||
for file_name in workflow_files: | ||
# Construct the file path | ||
file_path = f"workflows/{file_name}" | ||
start_time = int(datetime.datetime.now().timestamp()) | ||
subprocess.run( | ||
["comfycli", "run", "--workflow", file_path], | ||
check=True, | ||
) | ||
end_time = int(datetime.datetime.now().timestamp()) | ||
|
||
#TODO: add support for multiple file outputs | ||
gs_path = f"output-files/{args.github_action_workflow_name}-{args.os}-{args.comfy_workflow_name}-run-${args.run_id}" | ||
upload_img_from_filename(args.bucket_name, gs_path, f"{args.workspace_path}/output/{args.output_file_prefix}_{counter:05}_.png", public=True) | ||
|
||
send_payload_to_api(args, gs_path, start_time, end_time) | ||
counter += 1 | ||
|
||
|
||
if __name__ == "__main__": | ||
parser = argparse.ArgumentParser(description='Send a JSON file contents to a server as a prompt.') | ||
parser.add_argument('json_file_path', type=str, help='Path to the JSON file to send.') | ||
parser.add_argument('--server-url', type=str, default='http://localhost:8188/prompt', help='URL of the server to send the JSON to.') | ||
parser.add_argument('--comfy-workflow-names', type=str, help='List of comfy workflow names.') | ||
parser.add_argument('--github-action-workflow-name', type=str, help='Github action workflow name.') | ||
parser.add_argument('--os', type=str, help='Operating system.') | ||
parser.add_argument('--run-id', type=str, help='Github Run ID.') | ||
parser.add_argument('--repo', type=str, help='Github repo.') | ||
parser.add_argument('--cuda-version', type=str, help='CUDA version.') | ||
parser.add_argument('--commit-hash', type=str, help='Commit hash.') | ||
parser.add_argument('--commit-time', type=str, help='Commit time.') | ||
parser.add_argument('--commit-message', type=str, help='Commit message.') | ||
parser.add_argument('--branch-name', type=str, help='Branch name.') | ||
parser.add_argument('--workflow-file-names', type=str, help='Workflow file names.') | ||
parser.add_argument('--gsc-bucket-name', type=str, help='Name of the GCS bucket to store the output files in.') | ||
parser.add_argument('--workspace-path', type=str, help='Workspace (ComfyUI repo) path, likely ${HOME}/action_runners/_work/ComfyUI/ComfyUI/.') | ||
parser.add_argument('--action-path', type=str, help='Action path., likely ${HOME}/action_runners/_work/comfy-action/.') | ||
parser.add_argument('--output-file-prefix', type=str, help='Output file prefix.') | ||
|
||
args = parser.parse_args() | ||
main(args.json_file_path, args.server_url) | ||
main(args) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,3 @@ | ||
requests | ||
comfy-cli | ||
firebase_admin |
File renamed without changes.
File renamed without changes.
Oops, something went wrong.