From b93ae5af40524741e4100cb124b951793410c9ae Mon Sep 17 00:00:00 2001 From: thecooltechguy Date: Fri, 20 Oct 2023 17:06:39 -0700 Subject: [PATCH] added matrix server as a destination for sharing --- __init__.py | 135 +++++++++++++++++++++++++++++------------- js/comfyui-manager.js | 79 +++++++++++++++++++++--- requirements.txt | 3 +- 3 files changed, 165 insertions(+), 52 deletions(-) diff --git a/__init__.py b/__init__.py index 68ce38f..50e724a 100644 --- a/__init__.py +++ b/__init__.py @@ -1196,12 +1196,25 @@ async def channel_url_list(request): return web.Response(status=200) +@server.PromptServer.instance.routes.get("/manager/check_matrix") +async def check_matrix(request): + # Check if the user has provided Matrix credentials in a file called 'matrix_accesstoken' + # in the same directory as the ComfyUI base folder + print("Checking for Matrix credentials...") + if not os.path.exists(os.path.join(folder_paths.base_path, "matrix_accesstoken")): + return web.Response(status=404) + with open(os.path.join(folder_paths.base_path, "matrix_accesstoken"), "r") as f: + access_token = f.read() + if not access_token.strip(): + return web.Response(status=404) + return web.Response(status=200) @server.PromptServer.instance.routes.post("/manager/share") async def share_art(request): # get json data json_data = await request.json() + share_destinations = json_data['share_destinations'] credits = json_data['credits'] title = json_data['title'] description = json_data['description'] @@ -1228,49 +1241,87 @@ async def share_art(request): # get the mime type of the asset assetFileType = mimetypes.guess_type(asset_filepath)[0] - share_website_host = "https://comfyworkflows.com" - share_endpoint = f"{share_website_host}/api" - - # get presigned urls - 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, - }, - ) as resp: - assert resp.status == 200 - presigned_urls_json = await resp.json() - assetFilePresignedUrl = presigned_urls_json["assetFilePresignedUrl"] - assetFileKey = presigned_urls_json["assetFileKey"] - - # upload asset - 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 - - # make a POST request to /api/upload_workflow with form data key values - async with aiohttp.ClientSession(trust_env=True, connector=aiohttp.TCPConnector(verify_ssl=False)) as session: - form = aiohttp.FormData() - form.add_field("assetFileKey", assetFileKey) - form.add_field("assetFileType", assetFileType) - 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()) - - 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 "comfyworkflows" in share_destinations: + share_website_host = "https://comfyworkflows.com" + share_endpoint = f"{share_website_host}/api" + + # get presigned urls + 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, + }, + ) as resp: + assert resp.status == 200 + presigned_urls_json = await resp.json() + assetFilePresignedUrl = presigned_urls_json["assetFilePresignedUrl"] + assetFileKey = presigned_urls_json["assetFileKey"] + + # upload asset + 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 + + # make a POST request to /api/upload_workflow with form data key values + async with aiohttp.ClientSession(trust_env=True, connector=aiohttp.TCPConnector(verify_ssl=False)) as session: + form = aiohttp.FormData() + form.add_field("assetFileKey", assetFileKey) + form.add_field("assetFileType", assetFileType) + 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()) + + 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"] + + # check if the user has provided Matrix credentials + if "matrix" in share_destinations: + with open(os.path.join(folder_paths.base_path, "matrix_accesstoken"), "r") as f: + access_token = f.read().strip() + + comfyui_share_room_id = '!LGYSoacpJPhIfBqVfb:matrix.org' + filename = os.path.basename(asset_filepath) + content_type = assetFileType + + try: + from matrix_client.api import MatrixHttpApi + matrix = MatrixHttpApi("https://matrix.org", token=access_token) + with open(asset_filepath, 'rb') as f: + mxc_url = matrix.media_upload(f.read(), content_type, filename=filename)['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) + print(response) + response = matrix.send_content(comfyui_share_room_id, mxc_url, filename, 'm.image') + print(response) + 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({"url" : f"{share_website_host}/workflows/{workflowId}"}, content_type='application/json', status=200) + 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) WEB_DIRECTORY = "js" NODE_CLASS_MAPPINGS = {} diff --git a/js/comfyui-manager.js b/js/comfyui-manager.js index 13ec618..b98bf80 100644 --- a/js/comfyui-manager.js +++ b/js/comfyui-manager.js @@ -1995,6 +1995,16 @@ class ShareDialog extends ComfyDialog { this.is_nsfw_checkbox.style.color = "var(--fg-color)"; this.is_nsfw_checkbox.checked = false; + this.matrix_destination_checkbox = $el("input", { type: 'checkbox', id: "matrix_destination" }, []) + const matrix_destination_checkbox_text = $el("label", {}, [" ComfyUI Matrix server"]) + this.matrix_destination_checkbox.style.color = "var(--fg-color)"; + this.matrix_destination_checkbox.checked = true; + + this.comfyworkflows_destination_checkbox = $el("input", { type: 'checkbox', id: "comfyworkflows_destination" }, []) + const comfyworkflows_destination_checkbox_text = $el("label", {}, [" ComfyWorkflows.com"]) + this.comfyworkflows_destination_checkbox.style.color = "var(--fg-color)"; + this.comfyworkflows_destination_checkbox.checked = true; + this.credits_input = $el("input", { type: "text", placeholder: "This will be used to give you credits", @@ -2026,6 +2036,35 @@ class ShareDialog extends ComfyDialog { const nodes = app.graph._nodes; + const destinations = []; + if (this.matrix_destination_checkbox.checked) { + destinations.push("matrix"); + } + if (this.comfyworkflows_destination_checkbox.checked) { + destinations.push("comfyworkflows"); + } + + // if destinations includes matrix, make an api call to /manager/check_matrix to ensure that the user has configured their matrix settings + if (destinations.includes("matrix")) { + const response = await api.fetchApi(`/manager/check_matrix`); + if (response.status != 200) { + alert("Please add your Matrix access token in a file called 'matrix_accesstoken' in the ComfyUI folder. To get your Matrix access token, go to https://app.element.io/, click on your profile, click on 'All settings', click on 'Help & About', and copy 'Access Token', and then click on 'Regenerate'."); + // Reset state + this.matrix_destination_checkbox.checked = true; + this.comfyworkflows_destination_checkbox.checked = true; + this.share_button.textContent = "Share"; + this.share_button.style.display = "inline-block"; + this.final_message.innerHTML = ""; + this.final_message.style.color = "white"; + this.credits_input.value = ""; + this.title_input.value = ""; + this.description_input.value = ""; + this.is_nsfw_checkbox.checked = false; + this.close(); + return; + } + } + const potential_outputs = []; const potential_output_nodes = []; @@ -2068,6 +2107,7 @@ class ShareDialog extends ComfyDialog { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ + share_destinations: destinations, credits: this.credits_input.value, title: this.title_input.value, description: this.description_input.value, @@ -2086,7 +2126,17 @@ class ShareDialog extends ComfyDialog { const response_json = await response.json(); - this.final_message.innerHTML = "Your art has been shared: " + response_json.url + ""; + if (response_json.comfyworkflows.url) { + this.final_message.innerHTML = "Your art has been shared: " + response_json.comfyworkflows.url + ""; + if (response_json.matrix.success) { + this.final_message.innerHTML += "
Your art has been shared in the ComfyUI Matrix server's #share channel!"; + } + } else { + if (response_json.matrix.success) { + this.final_message.innerHTML = "Your art has been shared in the ComfyUI Matrix server's #share channel!"; + } + } + this.final_message.style.color = "green"; // hide the share button @@ -2101,18 +2151,27 @@ class ShareDialog extends ComfyDialog { [ $el("tr.td", { width: "100%" }, [ $el("font", { size: 6, color: "white" }, [`Share your art`]), - $el("div", { size: 3, color: "white" }, [ - $el("a", { - href: `https://comfyworkflows.com/?ref=cms`, - target: `_blank`, - color: "white", - // style: `color:white;` - }, `comfyworkflows.com`) - ]) + // $el("div", { size: 3, color: "white" }, [ + // $el("a", { + // href: `https://comfyworkflows.com/?ref=cms`, + // target: `_blank`, + // color: "white", + // // style: `color:white;` + // }, `comfyworkflows.com`) + // ]) ]), $el("p", { size: 4, color: "white" }, [`Get a public link for this art & workflow.`]), // $el("br", {}, []), + $el("div", {}, [ + $el("p", { size: 3, color: "white" }, [`Select where to share your art:`]), + this.matrix_destination_checkbox, + matrix_destination_checkbox_text, + $el("br", {}, []), + this.comfyworkflows_destination_checkbox, + comfyworkflows_destination_checkbox_text, + ]), + $el("h2", { textContent: "Your name/username (optional)", size: 3, @@ -2148,6 +2207,8 @@ class ShareDialog extends ComfyDialog { textContent: "Close", onclick: () => { // Reset state + this.matrix_destination_checkbox.checked = true; + this.comfyworkflows_destination_checkbox.checked = true; this.share_button.textContent = "Share"; this.share_button.style.display = "inline-block"; this.final_message.innerHTML = ""; diff --git a/requirements.txt b/requirements.txt index 5779f39..3467b3e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,2 @@ -GitPython \ No newline at end of file +GitPython +matrix-client==0.4.0 \ No newline at end of file