| | import mimetypes |
| | import manager_core as core |
| | import os |
| | from aiohttp import web |
| | import aiohttp |
| | import json |
| | import hashlib |
| |
|
| | import folder_paths |
| | from server import PromptServer |
| |
|
| |
|
| | def extract_model_file_names(json_data): |
| | """Extract unique file names from the input JSON data.""" |
| | file_names = set() |
| | model_filename_extensions = {'.safetensors', '.ckpt', '.pt', '.pth', '.bin'} |
| |
|
| | |
| | def recursive_search(data): |
| | if isinstance(data, dict): |
| | for value in data.values(): |
| | recursive_search(value) |
| | elif isinstance(data, list): |
| | for item in data: |
| | recursive_search(item) |
| | elif isinstance(data, str) and '.' in data: |
| | file_names.add(os.path.basename(data)) |
| |
|
| | recursive_search(json_data) |
| | return [f for f in list(file_names) if os.path.splitext(f)[1] in model_filename_extensions] |
| |
|
| |
|
| | def find_file_paths(base_dir, file_names): |
| | """Find the paths of the files in the base directory.""" |
| | file_paths = {} |
| |
|
| | for root, dirs, files in os.walk(base_dir): |
| | |
| | dirs[:] = [d for d in dirs if d not in ['.git']] |
| |
|
| | for file in files: |
| | if file in file_names: |
| | file_paths[file] = os.path.join(root, file) |
| | return file_paths |
| |
|
| |
|
| | def compute_sha256_checksum(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() |
| |
|
| |
|
| | @PromptServer.instance.routes.get("/manager/share_option") |
| | async def share_option(request): |
| | if "value" in request.rel_url.query: |
| | core.get_config()['share_option'] = request.rel_url.query['value'] |
| | core.write_config() |
| | else: |
| | return web.Response(text=core.get_config()['share_option'], status=200) |
| |
|
| | return web.Response(status=200) |
| |
|
| |
|
| | def get_openart_auth(): |
| | if not os.path.exists(os.path.join(core.comfyui_manager_path, ".openart_key")): |
| | return None |
| | try: |
| | with open(os.path.join(core.comfyui_manager_path, ".openart_key"), "r") as f: |
| | openart_key = f.read().strip() |
| | return openart_key if openart_key else None |
| | except: |
| | return None |
| |
|
| |
|
| | def get_matrix_auth(): |
| | if not os.path.exists(os.path.join(core.comfyui_manager_path, "matrix_auth")): |
| | return None |
| | try: |
| | with open(os.path.join(core.comfyui_manager_path, "matrix_auth"), "r") as f: |
| | matrix_auth = f.read() |
| | homeserver, username, password = matrix_auth.strip().split("\n") |
| | if not homeserver or not username or not password: |
| | return None |
| | return { |
| | "homeserver": homeserver, |
| | "username": username, |
| | "password": password, |
| | } |
| | except: |
| | return None |
| |
|
| |
|
| | def get_comfyworkflows_auth(): |
| | if not os.path.exists(os.path.join(core.comfyui_manager_path, "comfyworkflows_sharekey")): |
| | return None |
| | try: |
| | with open(os.path.join(core.comfyui_manager_path, "comfyworkflows_sharekey"), "r") as f: |
| | share_key = f.read() |
| | if not share_key.strip(): |
| | return None |
| | return share_key |
| | except: |
| | return None |
| |
|
| |
|
| | def get_youml_settings(): |
| | if not os.path.exists(os.path.join(core.comfyui_manager_path, ".youml")): |
| | return None |
| | try: |
| | with open(os.path.join(core.comfyui_manager_path, ".youml"), "r") as f: |
| | youml_settings = f.read().strip() |
| | return youml_settings if youml_settings else None |
| | except: |
| | return None |
| |
|
| |
|
| | def set_youml_settings(settings): |
| | with open(os.path.join(core.comfyui_manager_path, ".youml"), "w") as f: |
| | f.write(settings) |
| |
|
| |
|
| | @PromptServer.instance.routes.get("/manager/get_openart_auth") |
| | async def api_get_openart_auth(request): |
| | |
| | openart_key = get_openart_auth() |
| | if not openart_key: |
| | return web.Response(status=404) |
| | return web.json_response({"openart_key": openart_key}) |
| |
|
| |
|
| | @PromptServer.instance.routes.post("/manager/set_openart_auth") |
| | async def api_set_openart_auth(request): |
| | json_data = await request.json() |
| | openart_key = json_data['openart_key'] |
| | with open(os.path.join(core.comfyui_manager_path, ".openart_key"), "w") as f: |
| | f.write(openart_key) |
| | return web.Response(status=200) |
| |
|
| |
|
| | @PromptServer.instance.routes.get("/manager/get_matrix_auth") |
| | async def api_get_matrix_auth(request): |
| | |
| | matrix_auth = get_matrix_auth() |
| | if not matrix_auth: |
| | return web.Response(status=404) |
| | return web.json_response(matrix_auth) |
| |
|
| |
|
| | @PromptServer.instance.routes.get("/manager/youml/settings") |
| | async def api_get_youml_settings(request): |
| | youml_settings = get_youml_settings() |
| | if not youml_settings: |
| | return web.Response(status=404) |
| | return web.json_response(json.loads(youml_settings)) |
| |
|
| |
|
| | @PromptServer.instance.routes.post("/manager/youml/settings") |
| | async def api_set_youml_settings(request): |
| | json_data = await request.json() |
| | set_youml_settings(json.dumps(json_data)) |
| | return web.Response(status=200) |
| |
|
| |
|
| | @PromptServer.instance.routes.get("/manager/get_comfyworkflows_auth") |
| | async def api_get_comfyworkflows_auth(request): |
| | |
| | |
| | |
| | comfyworkflows_auth = get_comfyworkflows_auth() |
| | if not comfyworkflows_auth: |
| | return web.Response(status=404) |
| | return web.json_response({"comfyworkflows_sharekey": comfyworkflows_auth}) |
| |
|
| |
|
| | @PromptServer.instance.routes.post("/manager/set_esheep_workflow_and_images") |
| | async def set_esheep_workflow_and_images(request): |
| | json_data = await request.json() |
| | current_workflow = json_data['workflow'] |
| | images = json_data['images'] |
| | with open(os.path.join(core.comfyui_manager_path, "esheep_share_message.json"), "w", encoding='utf-8') as file: |
| | json.dump(json_data, file, indent=4) |
| | return web.Response(status=200) |
| |
|
| |
|
| | @PromptServer.instance.routes.get("/manager/get_esheep_workflow_and_images") |
| | async def get_esheep_workflow_and_images(request): |
| | with open(os.path.join(core.comfyui_manager_path, "esheep_share_message.json"), 'r', encoding='utf-8') as file: |
| | data = json.load(file) |
| | return web.Response(status=200, text=json.dumps(data)) |
| |
|
| |
|
| | def set_matrix_auth(json_data): |
| | homeserver = json_data['homeserver'] |
| | username = json_data['username'] |
| | password = json_data['password'] |
| | with open(os.path.join(core.comfyui_manager_path, "matrix_auth"), "w") as f: |
| | f.write("\n".join([homeserver, username, password])) |
| |
|
| |
|
| | def set_comfyworkflows_auth(comfyworkflows_sharekey): |
| | with open(os.path.join(core.comfyui_manager_path, "comfyworkflows_sharekey"), "w") as f: |
| | f.write(comfyworkflows_sharekey) |
| |
|
| |
|
| | def has_provided_matrix_auth(matrix_auth): |
| | return matrix_auth['homeserver'].strip() and matrix_auth['username'].strip() and matrix_auth['password'].strip() |
| |
|
| |
|
| | def has_provided_comfyworkflows_auth(comfyworkflows_sharekey): |
| | return comfyworkflows_sharekey.strip() |
| |
|
| |
|
| | @PromptServer.instance.routes.post("/manager/share") |
| | async def share_art(request): |
| | |
| | json_data = await request.json() |
| |
|
| | matrix_auth = json_data['matrix_auth'] |
| | comfyworkflows_sharekey = json_data['cw_auth']['cw_sharekey'] |
| |
|
| | set_matrix_auth(matrix_auth) |
| | set_comfyworkflows_auth(comfyworkflows_sharekey) |
| |
|
| | share_destinations = json_data['share_destinations'] |
| | credits = json_data['credits'] |
| | title = json_data['title'] |
| | description = json_data['description'] |
| | is_nsfw = json_data['is_nsfw'] |
| | prompt = json_data['prompt'] |
| | potential_outputs = json_data['potential_outputs'] |
| | selected_output_index = json_data['selected_output_index'] |
| |
|
| | try: |
| | output_to_share = potential_outputs[int(selected_output_index)] |
| | except: |
| | |
| | output_to_share = potential_outputs[0] |
| |
|
| | assert output_to_share['type'] in ('image', 'output') |
| | output_dir = folder_paths.get_output_directory() |
| |
|
| | if output_to_share['type'] == 'image': |
| | asset_filename = output_to_share['image']['filename'] |
| | asset_subfolder = output_to_share['image']['subfolder'] |
| |
|
| | if output_to_share['image']['type'] == 'temp': |
| | output_dir = folder_paths.get_temp_directory() |
| | else: |
| | asset_filename = output_to_share['output']['filename'] |
| | asset_subfolder = output_to_share['output']['subfolder'] |
| |
|
| | if asset_subfolder: |
| | asset_filepath = os.path.join(output_dir, asset_subfolder, asset_filename) |
| | else: |
| | asset_filepath = os.path.join(output_dir, asset_filename) |
| |
|
| | |
| | assetFileType = mimetypes.guess_type(asset_filepath)[0] |
| |
|
| | share_website_host = "UNKNOWN" |
| | if "comfyworkflows" in share_destinations: |
| | share_website_host = "https://comfyworkflows.com" |
| | share_endpoint = f"{share_website_host}/api" |
| |
|
| | |
| | async with aiohttp.ClientSession(trust_env=True, connector=aiohttp.TCPConnector(verify_ssl=False)) as session: |
| | async with session.post( |
| | f"{share_endpoint}/get_presigned_urls", |
| | json={ |
| | "assetFileName": asset_filename, |
| | "assetFileType": assetFileType, |
| | "workflowJsonFileName": 'workflow.json', |
| | "workflowJsonFileType": 'application/json', |
| | }, |
| | ) as resp: |
| | assert resp.status == 200 |
| | presigned_urls_json = await resp.json() |
| | assetFilePresignedUrl = presigned_urls_json["assetFilePresignedUrl"] |
| | assetFileKey = presigned_urls_json["assetFileKey"] |
| | workflowJsonFilePresignedUrl = presigned_urls_json["workflowJsonFilePresignedUrl"] |
| | workflowJsonFileKey = presigned_urls_json["workflowJsonFileKey"] |
| |
|
| | |
| | async with aiohttp.ClientSession(trust_env=True, connector=aiohttp.TCPConnector(verify_ssl=False)) as session: |
| | async with session.put(assetFilePresignedUrl, data=open(asset_filepath, "rb")) as resp: |
| | assert resp.status == 200 |
| |
|
| | |
| | async with aiohttp.ClientSession(trust_env=True, connector=aiohttp.TCPConnector(verify_ssl=False)) as session: |
| | async with session.put(workflowJsonFilePresignedUrl, data=json.dumps(prompt['workflow']).encode('utf-8')) as resp: |
| | assert resp.status == 200 |
| |
|
| | model_filenames = extract_model_file_names(prompt['workflow']) |
| | model_file_paths = find_file_paths(folder_paths.base_path, model_filenames) |
| |
|
| | models_info = {} |
| | for filename, filepath in model_file_paths.items(): |
| | models_info[filename] = { |
| | "filename": filename, |
| | "sha256_checksum": compute_sha256_checksum(filepath), |
| | "relative_path": os.path.relpath(filepath, folder_paths.base_path), |
| | } |
| |
|
| | |
| | async with aiohttp.ClientSession(trust_env=True, connector=aiohttp.TCPConnector(verify_ssl=False)) as session: |
| | form = aiohttp.FormData() |
| | if comfyworkflows_sharekey: |
| | form.add_field("shareKey", comfyworkflows_sharekey) |
| | form.add_field("source", "comfyui_manager") |
| | form.add_field("assetFileKey", assetFileKey) |
| | form.add_field("assetFileType", assetFileType) |
| | form.add_field("workflowJsonFileKey", workflowJsonFileKey) |
| | form.add_field("sharedWorkflowWorkflowJsonString", json.dumps(prompt['workflow'])) |
| | form.add_field("sharedWorkflowPromptJsonString", json.dumps(prompt['output'])) |
| | form.add_field("shareWorkflowCredits", credits) |
| | form.add_field("shareWorkflowTitle", title) |
| | form.add_field("shareWorkflowDescription", description) |
| | form.add_field("shareWorkflowIsNSFW", str(is_nsfw).lower()) |
| | form.add_field("currentSnapshot", json.dumps(core.get_current_snapshot())) |
| | form.add_field("modelsInfo", json.dumps(models_info)) |
| |
|
| | async with session.post( |
| | f"{share_endpoint}/upload_workflow", |
| | data=form, |
| | ) as resp: |
| | assert resp.status == 200 |
| | upload_workflow_json = await resp.json() |
| | workflowId = upload_workflow_json["workflowId"] |
| |
|
| | |
| | if "matrix" in share_destinations: |
| | comfyui_share_room_id = '!LGYSoacpJPhIfBqVfb:matrix.org' |
| | filename = os.path.basename(asset_filepath) |
| | content_type = assetFileType |
| |
|
| | try: |
| | from matrix_client.api import MatrixHttpApi |
| | from matrix_client.client import MatrixClient |
| |
|
| | homeserver = 'matrix.org' |
| | if matrix_auth: |
| | homeserver = matrix_auth.get('homeserver', 'matrix.org') |
| | homeserver = homeserver.replace("http://", "https://") |
| | if not homeserver.startswith("https://"): |
| | homeserver = "https://" + homeserver |
| |
|
| | client = MatrixClient(homeserver) |
| | try: |
| | token = client.login(username=matrix_auth['username'], password=matrix_auth['password']) |
| | if not token: |
| | return web.json_response({"error": "Invalid Matrix credentials."}, content_type='application/json', status=400) |
| | except: |
| | return web.json_response({"error": "Invalid Matrix credentials."}, content_type='application/json', status=400) |
| |
|
| | matrix = MatrixHttpApi(homeserver, token=token) |
| | with open(asset_filepath, 'rb') as f: |
| | mxc_url = matrix.media_upload(f.read(), content_type, filename=filename)['content_uri'] |
| |
|
| | workflow_json_mxc_url = matrix.media_upload(prompt['workflow'], 'application/json', filename='workflow.json')['content_uri'] |
| |
|
| | text_content = "" |
| | if title: |
| | text_content += f"{title}\n" |
| | if description: |
| | text_content += f"{description}\n" |
| | if credits: |
| | text_content += f"\ncredits: {credits}\n" |
| | response = matrix.send_message(comfyui_share_room_id, text_content) |
| | response = matrix.send_content(comfyui_share_room_id, mxc_url, filename, 'm.image') |
| | response = matrix.send_content(comfyui_share_room_id, workflow_json_mxc_url, 'workflow.json', 'm.file') |
| | except: |
| | import traceback |
| | traceback.print_exc() |
| | return web.json_response({"error": "An error occurred when sharing your art to Matrix."}, content_type='application/json', status=500) |
| |
|
| | return web.json_response({ |
| | "comfyworkflows": { |
| | "url": None if "comfyworkflows" not in share_destinations else f"{share_website_host}/workflows/{workflowId}", |
| | }, |
| | "matrix": { |
| | "success": None if "matrix" not in share_destinations else True |
| | } |
| | }, content_type='application/json', status=200) |
| |
|