diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..225fc6f --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/__pycache__ diff --git a/__init__.py b/__init__.py index 68b65d2..581a8c0 100644 --- a/__init__.py +++ b/__init__.py @@ -1,3 +1,4 @@ +import logging import platform import random import sys @@ -119,6 +120,7 @@ async def auth_callback(request): auth_query = await request.json() token = auth_query.get("token", "") client_key = auth_query.get("client_key", "") + logging.info(f"### auth_callback: {token} {client_key}") if token and client_key: token = unquote(token) client_key = unquote(client_key) diff --git a/auth_unit.py b/auth_unit.py index 3fe4e9a..66f1c8c 100644 --- a/auth_unit.py +++ b/auth_unit.py @@ -1,3 +1,4 @@ +import logging import os import time import requests @@ -56,6 +57,9 @@ class AuthUnit: self.last_check_time = time.time() return self.token, "", RiceRoundErrorDef.SUCCESS else: + logging.warn( + f"get_user_token failed, {response.status_code} {response.text}" + ) error_message = "登录结果错误" error_code = RiceRoundErrorDef.UNKNOWN_ERROR try: @@ -119,6 +123,7 @@ class AuthUnit: def set_user_token(self, user_token, client_key): if not client_key or self.client_key != client_key: + logging.warn(f"client_key is not match, {self.client_key} != {client_key}") return if not user_token: user_token = "" diff --git a/js/riceconfig.js b/js/riceconfig.js index 48f693f..4edd1dc 100644 --- a/js/riceconfig.js +++ b/js/riceconfig.js @@ -1 +1,159 @@ -import{api}from"../../../scripts/api.js";import{ComfyApp,app}from"../../../scripts/app.js";import{showToast}from"./riceround.js";const UserTokenKey="riceround_user_token";function isValidJWTFormat(e){if("string"!=typeof e)return!1;if(e.length<50)return!1;const t=e.split(".");if(3!==t.length)return!1;const o=/^[A-Za-z0-9_-]+$/;return t.every((e=>e.length>0&&o.test(e)))}async function set_exclusive_user(e){e?localStorage.setItem("RiceRound.Cloud.exclusive",e):localStorage.removeItem("RiceRound.Cloud.exclusive");200!=(await api.fetchApi("/riceround/set_exclusive_user",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({exclusive_user:e})})).status&&showToast("设置专属用户客户ID失败","error")}app.registerExtension({name:"riceround.config",async setup(){app.ui.settings.addSetting({id:"RiceRound.User.logout",name:"登出当前用户",type:()=>{const e=document.createElement("tr"),t=document.createElement("td"),o=document.createElement("input");return o.type="button",o.value="登出",o.style.borderRadius="8px",o.style.padding="8px 16px",o.style.fontSize="14px",o.style.cursor="pointer",o.style.border="1px solid #666",o.style.backgroundColor="#444",o.style.color="#fff",o.onclick=async()=>{localStorage.removeItem("Comfy.Settings.RiceRound.User.long_token"),localStorage.removeItem(UserTokenKey),app.ui.settings.setSettingValue("RiceRound.User.long_token",""),await api.fetchApi("/riceround/logout"),showToast("登出成功")},t.appendChild(o),e.appendChild(t),e}}),app.ui.settings.addSetting({id:"RiceRound.User.long_token",name:"设置长效token",type:"text",textType:"password",defaultValue:"",tooltip:"用于非本机授权登录情况,请勿泄露!提倡使用本机登录授权更安全!",onChange:async function(e){isValidJWTFormat(e)&&await api.fetchApi("/riceround/set_long_token",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({long_token:e})})}}),app.ui.settings.addSetting({id:"RiceRound.Setting.wait-time",name:"任务排队等待时间(秒)",tooltip:"不建议设置太短,否则可能等不到运行结果就退出了",type:"slider",attrs:{min:30,max:7200,step:10},defaultValue:600,onChange:e=>{api.fetchApi("/riceround/set_wait_time",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({wait_time:e})})}}),app.ui.settings.addSetting({id:"RiceRound.Publish",name:"自动发布工作流",type:"boolean",defaultValue:!0,tooltip:"设置为true时,会自动发布工作流",onChange:function(e){api.fetchApi("/riceround/set_auto_publish",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({auto_publish:e})}),e||localStorage.setItem("RiceRound.Setting.auto_overwrite",e)}}),app.ui.settings.addSetting({id:"RiceRound.Publish.auto_overwrite",name:"自动覆盖更新同id工作流",type:"boolean",tooltip:"设置为true时,会自动覆盖已有的template_id的数据",onChange:function(e){api.fetchApi("/riceround/set_auto_overwrite",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({auto_overwrite:e})})}}),app.ui.settings.addSetting({id:"RiceRound.Cloud.run_client",name:"自启动云节点客户端",type:"boolean",defaultValue:!0,tooltip:"没有任何云节点客户运行的话,则该用户云节点无法运行",onChange:function(e){api.fetchApi("/riceround/set_run_client",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({run_client:e})})}}),app.ui.settings.addSetting({id:"RiceRound.Advanced.setting",name:"模型列表存放位置,手动清理或安装高级节点",type:()=>{const e=document.createElement("tr"),t=document.createElement("td"),o=document.createElement("input");return o.type="button",o.value="打开文件夹",o.style.borderRadius="8px",o.style.padding="8px 16px",o.style.fontSize="14px",o.style.cursor="pointer",o.style.border="1px solid #666",o.style.backgroundColor="#444",o.style.color="#fff",o.onmouseover=()=>{o.style.backgroundColor="#555"},o.onmouseout=()=>{o.style.backgroundColor="#444"},o.onclick=()=>{api.fetchApi("/riceround/open_selector_list_folder",{method:"GET",headers:{"Content-Type":"application/json"}})},t.appendChild(o),e.appendChild(t),e}})}}); \ No newline at end of file +import { api as e } from "../../../scripts/api.js"; + +import { ComfyApp as t, app as o } from "../../../scripts/app.js"; + +import { showToast as n } from "./riceround.js"; + +const i = "riceround_user_token"; + +function r(e) { + if ("string" != typeof e) return !1; + if (e.length < 50) return !1; + const t = e.split("."); + if (3 !== t.length) return !1; + const o = /^[A-Za-z0-9_-]+$/; + return t.every((e => e.length > 0 && o.test(e))); +} + +async function s(t) { + t ? localStorage.setItem("RiceRound.Cloud.exclusive", t) : localStorage.removeItem("RiceRound.Cloud.exclusive"); + 200 != (await e.fetchApi("/riceround/set_exclusive_user", { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify({ + exclusive_user: t + }) + })).status && n("设置专属用户客户ID失败", "error"); +} + +o.registerExtension({ + name: "riceround.config", + async setup() { + o.ui.settings.addSetting({ + id: "RiceRound.User.logout", + name: "登出当前用户", + type: () => { + const t = document.createElement("tr"), r = document.createElement("td"), s = document.createElement("input"); + return s.type = "button", s.value = "登出", s.style.borderRadius = "8px", s.style.padding = "8px 16px", + s.style.fontSize = "14px", s.style.cursor = "pointer", s.style.border = "1px solid #666", + s.style.backgroundColor = "#444", s.style.color = "#fff", s.onclick = async () => { + localStorage.removeItem("Comfy.Settings.RiceRound.User.long_token"), localStorage.removeItem(i), + o.ui.settings.setSettingValue("RiceRound.User.long_token", ""), await e.fetchApi("/riceround/logout"), + n("登出成功"); + }, r.appendChild(s), t.appendChild(r), t; + } + }), o.ui.settings.addSetting({ + id: "RiceRound.User.long_token", + name: "设置长效token", + type: "text", + textType: "password", + defaultValue: "", + tooltip: "用于非本机授权登录情况,请勿泄露!提倡使用本机登录授权更安全!", + onChange: async function(t) { + r(t) && await e.fetchApi("/riceround/set_long_token", { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify({ + long_token: t + }) + }); + } + }), o.ui.settings.addSetting({ + id: "RiceRound.Setting.wait-time", + name: "任务排队等待时间(秒)", + tooltip: "不建议设置太短,否则可能等不到运行结果就退出了", + type: "slider", + attrs: { + min: 30, + max: 7200, + step: 10 + }, + defaultValue: 600, + onChange: t => { + e.fetchApi("/riceround/set_wait_time", { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify({ + wait_time: t + }) + }); + } + }), o.ui.settings.addSetting({ + id: "RiceRound.Publish", + name: "自动发布工作流", + type: "boolean", + defaultValue: !0, + tooltip: "设置为true时,会自动发布工作流", + onChange: function(t) { + e.fetchApi("/riceround/set_auto_publish", { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify({ + auto_publish: t + }) + }), t || localStorage.setItem("RiceRound.Setting.auto_overwrite", t); + } + }), o.ui.settings.addSetting({ + id: "RiceRound.Publish.auto_overwrite", + name: "自动覆盖更新同id工作流", + type: "boolean", + tooltip: "设置为true时,会自动覆盖已有的template_id的数据", + onChange: function(t) { + e.fetchApi("/riceround/set_auto_overwrite", { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify({ + auto_overwrite: t + }) + }); + } + }), o.ui.settings.addSetting({ + id: "RiceRound.Cloud.run_client", + name: "自启动云节点客户端", + type: "boolean", + defaultValue: !0, + tooltip: "没有任何云节点客户运行的话,则该用户云节点无法运行", + onChange: function(t) { + e.fetchApi("/riceround/set_run_client", { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify({ + run_client: t + }) + }); + } + }), o.ui.settings.addSetting({ + id: "RiceRound.Advanced.setting", + name: "模型列表存放位置,手动清理或安装高级节点", + type: () => { + const t = document.createElement("tr"), o = document.createElement("td"), n = document.createElement("input"); + return n.type = "button", n.value = "打开文件夹", n.style.borderRadius = "8px", n.style.padding = "8px 16px", + n.style.fontSize = "14px", n.style.cursor = "pointer", n.style.border = "1px solid #666", + n.style.backgroundColor = "#444", n.style.color = "#fff", n.onmouseover = () => { + n.style.backgroundColor = "#555"; + }, n.onmouseout = () => { + n.style.backgroundColor = "#444"; + }, n.onclick = () => { + e.fetchApi("/riceround/open_selector_list_folder", { + method: "GET", + headers: { + "Content-Type": "application/json" + } + }); + }, o.appendChild(n), t.appendChild(o), t; + } + }); + } +}); \ No newline at end of file diff --git a/js/riceround.js b/js/riceround.js index b98d2d5..c82fc9f 100644 --- a/js/riceround.js +++ b/js/riceround.js @@ -1 +1,432 @@ -import{api}from"../../../scripts/api.js";import{ComfyApp,app}from"../../../scripts/app.js";const style=document.createElement("style");style.textContent="\n .riceround-swal-top-container {\n z-index: 99999 !important;\n }\n",document.head.appendChild(style);export async function loadResource(e,t=""){if(!document.querySelector(`script[src="${e}"]`)){const t=document.createElement("script");t.src=e,document.head.appendChild(t);try{await new Promise(((o,n)=>{t.onload=o,t.onerror=()=>n(new Error(`Failed to load script: ${e}`))}))}catch(e){}}if(t){if(!document.querySelector(`link[href="${t}"]`)){const e=document.createElement("link");e.rel="stylesheet",e.href=t,document.head.appendChild(e);try{await new Promise(((o,n)=>{e.onload=o,e.onerror=()=>n(new Error(`Failed to load stylesheet: ${t}`))}))}catch(e){}}}}let toastHasLoaded=!1;async function loadToast(){if(!toastHasLoaded){const e="https://cdn.jsdelivr.net/npm/toastify-js",t="https://cdn.jsdelivr.net/npm/toastify-js/src/toastify.min.css";await loadResource(e,t),toastHasLoaded=!0}}export async function showToast(e,t="info",o=3e3){await loadToast(),"info"==t?Toastify({text:e,duration:o,close:!1,gravity:"top",position:"center",backgroundColor:"#3498db",stopOnFocus:!1}).showToast():"error"==t?Toastify({text:e,duration:o,close:!0,gravity:"top",position:"center",backgroundColor:"#FF4444",stopOnFocus:!0}).showToast():"warning"==t&&Toastify({text:e,duration:o,close:!0,gravity:"top",position:"center",backgroundColor:"#FFA500",stopOnFocus:!0}).showToast()}let messageBoxHasLoaded=!1;export async function loadMessageBox(){messageBoxHasLoaded||(await loadResource("https://cdn.jsdelivr.net/npm/sweetalert2@11","https://cdn.jsdelivr.net/npm/@sweetalert2/theme-bootstrap-4/bootstrap-4.css"),messageBoxHasLoaded=!0)}async function serverShowMessageBox(e,t){await loadMessageBox();const o={...e,heightAuto:!1};try{const e=await Swal.fire(o);api.fetchApi("/riceround/message",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:`id=${t}&message=${e.isConfirmed?"1":"0"}`})}catch(e){api.fetchApi("/riceround/message",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:`id=${t}&message=0`})}window.addEventListener("beforeunload",(function(){fetch("/riceround/message",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:`id=${t}&message=0`,keepalive:!0})}),{once:!0})}api.addEventListener("riceround_toast",(e=>{showToast(e.detail.content,e.detail.type,e.detail.duration)})),api.addEventListener("riceround_dialog",(e=>{serverShowMessageBox(JSON.parse(e.detail.json_content),e.detail.id)}));let dialogLibHasLoaded=!1;async function waitForObject(e,t,o=5e3){return new Promise(((n,i)=>{const a=Date.now(),s=()=>{Date.now()-a>o?i(new Error(`Timeout waiting for ${t} to load`)):e()?n():setTimeout(s,50)};s()}))}export async function initDialogLib(e=!1){if(!dialogLibHasLoaded)try{const e="https://unpkg.com/vue@3/dist/vue.global.js";await loadResource(e,""),await waitForObject((()=>window.Vue),"vue");const t="https://cdn.jsdelivr.net/npm/element-plus",o="https://cdn.jsdelivr.net/npm/element-plus/dist/index.css";if(await loadResource(t,o),await waitForObject((()=>window.ElementPlus),"element-plus"),null==window.DialogLib){const e="riceround/static/dialog-lib.umd.cjs";await loadResource(e,""),await waitForObject((()=>window.DialogLib),"showLoginDialog")}dialogLibHasLoaded=!0}catch(e){throw e}}async function setNodeAdditionalInfo(e){try{const t={method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)},o=await api.fetchApi("/riceround/set_node_additional_info",t);await o.json()}catch(e){}}function changeWidget(e,t,o,n){e.type=t,e.value=o,e.options=n}function changeWidgets(e,t,o,n){"customtext"===t&&(t="text");const i=n.options;var a=e.widgets[1].value;i?.values?.includes(a)||(a=n.value),"RiceRoundAdvancedChoiceNode"==e.comfyClass||"RiceRoundSimpleChoiceNode"==e.comfyClass?changeWidget(e.widgets[1],t,a,i):"RiceRoundIntNode"!=e.comfyClass&&"RiceRoundFloatNode"!=e.comfyClass||4==e.widgets.length&&(changeWidget(e.widgets[1],"number",a,i),changeWidget(e.widgets[2],"number",i?.min??0,i),changeWidget(e.widgets[3],"number",i?.max??100,i))}function adaptWidgetsBasedOnConnection(e,t,o,n){if(e.outputs[0].type=o.type,"name"===e.widgets[0].label){(["数值","文本","列表","参数","Parameter"].includes(e.widgets[0].value)||""==e.widgets[0].value)&&(e.widgets[0].value=o.label?o.label:o.name)}const i=o.widget?.name?o.widget?.name:o.name,a=t.widgets.find((e=>e.name===i));if(!a)return;changeWidgets(e,a.origType??a.type,t,a)}api.addEventListener("riceround_login_dialog",(e=>{const t=e.detail.client_key,o=e.detail.title;window.DialogLib.showLoginDialog({title:o,spyNetworkError:!0,mainKey:"riceround"}).then((e=>{api.fetchApi("/riceround/auth_callback",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({token:e,client_key:t})}),showToast("登录成功")})).catch((e=>{showToast("登录失败","error")}))})),api.addEventListener("riceround_show_workflow_payment_dialog",(e=>{const t=e.detail.title??"支付",o=e.detail.template_id;o?window.DialogLib.showWorkflowQRPaymentDialog({title:t,template_id:o}).then((({success:e,msg:t})=>{showToast(t,e?"info":"error")})).catch((e=>{showToast("取消支付","error")})):showToast("模板ID不能为空","error")})),api.addEventListener("riceround_clear_user_info",(async e=>{const t=e.detail.clear_key;"all"==t?(localStorage.removeItem("Comfy.Settings.RiceRound.User.long_token"),localStorage.removeItem("riceround_user_token"),app.ui.settings.setSettingValue("RiceRound.User.long_token","")):"long_token"==t?(localStorage.removeItem("Comfy.Settings.RiceRound.User.long_token"),app.ui.settings.setSettingValue("RiceRound.User.long_token","")):"user_token"==t&&localStorage.removeItem("riceround_user_token")})),api.addEventListener("execution_start",(async({detail:e})=>{let t="";const o={};for(const e of app.graph.nodes){if("RiceRoundDecryptNode"===e.type)return;if("RiceRoundEncryptNode"===e.type){const o=e.widgets?.find((e=>"template_id"===e.name&&e.value));if(o){if(t)return;t=o.value}}else if("RiceRoundAdvancedChoiceNode"===e.type||"RiceRoundSimpleChoiceNode"===e.type){if(1===!e.outputs?.[0]?.links?.length)continue;const t=e.widgets[1].options?.values??[];if(!t.length)continue;const n=e.graph.links[e.outputs[0].links[0]];if(!n)continue;const i=e.graph.getNodeById(n.target_id);if(!i?.inputs||"RiceRoundDecryptNode"===i.comfyClass||"RiceRoundEncryptNode"===i.comfyClass)continue;const a=i.inputs[n.target_slot];if(!a||!i.widgets)continue;const s=a.widget?.name||a.name;if(!s)continue;const d=`${i.comfyClass}.${s}`;o[e.id]={class_name:d,options_value:t,node_type:e.type}}}t&&Object.keys(o).length>0&&await setNodeAdditionalInfo({choice_node_map:o,template_id:t})}));let applySimpleChoiceNodeExtraLogicTimer=null;function applySimpleChoiceNodeExtraLogic(e,t){applySimpleChoiceNodeExtraLogicTimer&&clearTimeout(applySimpleChoiceNodeExtraLogicTimer),applySimpleChoiceNodeExtraLogicTimer=setTimeout((()=>{applySimpleChoiceNodeExtraLogicTimer=null;const o=t.graph.extra?.choice_node_map;if(e&&e.widgets&&2===e.widgets.length&&o&&o[e.id]){const t={values:o[e.id]};changeWidget(e.widgets[1],"combo",e.widgets[1].value,t)}}),200)}function adaptWidgetsToConnection(e){if(!e.outputs||0===e.outputs.length)return;const t=e.outputs[0].links;if(t&&1===t.length){const o=e.graph.links[t[0]];if(!o)return;const n=e.graph.getNodeById(o.target_id);if(!n||!n.inputs)return;if("RiceRoundDecryptNode"==n.comfyClass&&"RiceRoundSimpleChoiceNode"==e.comfyClass)return void applySimpleChoiceNodeExtraLogic(e,app);if("RiceRoundEncryptNode"==n.comfyClass||"RiceRoundDecryptNode"==n.comfyClass)return;const i=n.inputs[o.target_slot];if(!i||void 0===n.widgets)return;adaptWidgetsBasedOnConnection(e,n,i,app)}else t&&0!==t.length||("RiceRoundAdvancedChoiceNode"==e.comfyClass||"RiceRoundSimpleChoiceNode"==e.comfyClass?(e.widgets[0].value="Parameter",e.outputs[0].type="*"):"RiceRoundIntNode"==e.comfyClass?4==e.widgets.length&&(e.widgets[0].value="数值",e.widgets[1].value=0,e.widgets[2].value=0,e.widgets[3].value=100):"RiceRoundFloatNode"==e.comfyClass&&4==e.widgets.length&&(e.widgets[0].value="数值",e.widgets[1].value=0,e.widgets[2].value=0,e.widgets[3].value=100))}function setupParameterNode(e){const t=e.prototype.onAdded;e.prototype.onAdded=function(){t?.apply(this,arguments),adaptWidgetsToConnection(this)};const o=e.prototype.onAfterGraphConfigured;e.prototype.onAfterGraphConfigured=function(){o?.apply(this,arguments),adaptWidgetsToConnection(this)};const n=e.prototype.onConnectOutput;e.prototype.onConnectOutput=function(e,t,o,i,a){return!(!o.widget&&!(o.type in["STRING","COMBO","combo"]))&&(!n||(result=n.apply(this,arguments),result))};const i=e.prototype.onConnectionsChange;e.prototype.onConnectionsChange=function(e,t,o,n,a){return 2!=e||o||!this?.type||"RiceRoundAdvancedChoiceNode"!=this.type&&"RiceRoundSimpleChoiceNode"!=this.type||(this.widgets[0].value="Parameter"),app.configuringGraph||adaptWidgetsToConnection(this),i?.apply(this,arguments)}}function generateUUID(){let e="";for(let t=0;t<32;t++){e+=Math.floor(16*Math.random()).toString(16)}return e}function rebootAPI(){if("electronAPI"in window)return window.electronAPI.restartApp(),!0;api.fetchApi("/manager/reboot")}app.registerExtension({name:"riceround.custom",setup(){initDialogLib()},async beforeRegisterNodeDef(e,t,o){if(["RiceRoundAdvancedChoiceNode","RiceRoundSimpleChoiceNode","RiceRoundIntNode","RiceRoundFloatNode"].includes(t.name)&&setupParameterNode(e),"RiceRoundEncryptNode"==t.name){const t=400,o=120,n=e.prototype.onNodeCreated;e.prototype.onNodeCreated=function(){const e=n?n.apply(this):void 0;return void 0!==this.size?.[0]&&(this.size[0]=t),void 0!==this.size?.[1]&&(this.size[1]=Math.max(o,this.size[1])),e},e.prototype.onResize=function(e){return void 0!==e?.[0]&&(e[0]=t),void 0!==e?.[1]&&(e[1]=Math.max(o,e[1])),e}}},loadedGraphNode:async e=>{if(!e.title){const t=e.type;if(t&&t.includes("RiceRoundAdvancedChoiceNode")){const e=t.match(/RiceRoundAdvancedChoiceNode_([^_]+)_/);if(!e)return;const o=e[1];await loadMessageBox();const n=await Swal.fire({title:"高级选择节点安装确认",html:'\n
\n

检测到高级选择节点,是否需要安装相关组件?

\n
\n \n \n
\n
\n ',icon:"question",showCancelButton:!0,confirmButtonText:"安装",cancelButtonText:"取消",heightAuto:!1,backdrop:!0,allowOutsideClick:!1,customClass:{container:"riceround-swal-top-container"},preConfirm:()=>({needReboot:document.getElementById("swal-restart-checkbox").checked})});if(n.isConfirmed)try{if(!(await api.fetchApi("/riceround/install_choice_node",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({template_id:o,need_reboot:n.value.needReboot})})).ok)throw new Error("Installation failed");await Swal.fire({title:"安装成功",text:n.value.needReboot?"组件已安装,服务即将重启":"组件已安装完成",icon:"success",heightAuto:!1,customClass:{container:"riceround-swal-top-container"}})}catch(e){await Swal.fire({title:"安装失败",text:"组件安装过程中出现错误",icon:"error",heightAuto:!1,customClass:{container:"riceround-swal-top-container"}})}}}},nodeCreated(e,t){if("RiceRoundEncryptNode"==e.comfyClass&&e.widgets&&e.widgets.length>0){const t=window.document.title;if(t||(t=localStorage.getItem("Comfy.PreviousWorkflow")),t){let o=t.replace(/[<>:"/\\|?*]/g," ").replace(/^\s+|\s+$/g,"");for(let t=0;t{const t=generateUUID();for(let o=0;o { + t.onload = o, t.onerror = () => n(new Error(`Failed to load script: ${e}`)); + })); + } catch (e) {} + } + if (t) { + if (!document.querySelector(`link[href="${t}"]`)) { + const e = document.createElement("link"); + e.rel = "stylesheet", e.href = t, document.head.appendChild(e); + try { + await new Promise(((o, n) => { + e.onload = o, e.onerror = () => n(new Error(`Failed to load stylesheet: ${t}`)); + })); + } catch (e) {} + } + } +} + +let i = !1; + +async function s() { + if (!i) { + const e = "https://cdn.jsdelivr.net/npm/toastify-js", t = "https://cdn.jsdelivr.net/npm/toastify-js/src/toastify.min.css"; + await loadResource(e, t), i = !0; + } +} + +export async function showToast(e, t = "info", o = 3e3) { + await s(), "info" == t ? Toastify({ + text: e, + duration: o, + close: !1, + gravity: "top", + position: "center", + backgroundColor: "#3498db", + stopOnFocus: !1 + }).showToast() : "error" == t ? Toastify({ + text: e, + duration: o, + close: !0, + gravity: "top", + position: "center", + backgroundColor: "#FF4444", + stopOnFocus: !0 + }).showToast() : "warning" == t && Toastify({ + text: e, + duration: o, + close: !0, + gravity: "top", + position: "center", + backgroundColor: "#FFA500", + stopOnFocus: !0 + }).showToast(); +} + +let a = !1; + +export async function loadMessageBox() { + a || (await loadResource("https://cdn.jsdelivr.net/npm/sweetalert2@11", "https://cdn.jsdelivr.net/npm/@sweetalert2/theme-bootstrap-4/bootstrap-4.css"), + a = !0); +} + +async function c(t, o) { + await loadMessageBox(); + const n = { + ...t, + heightAuto: !1 + }; + try { + const t = await Swal.fire(n); + e.fetchApi("/riceround/message", { + method: "POST", + headers: { + "Content-Type": "application/x-www-form-urlencoded" + }, + body: `id=${o}&message=${t.isConfirmed ? "1" : "0"}` + }); + } catch (t) { + e.fetchApi("/riceround/message", { + method: "POST", + headers: { + "Content-Type": "application/x-www-form-urlencoded" + }, + body: `id=${o}&message=0` + }); + } + window.addEventListener("beforeunload", (function() { + fetch("/riceround/message", { + method: "POST", + headers: { + "Content-Type": "application/x-www-form-urlencoded" + }, + body: `id=${o}&message=0`, + keepalive: !0 + }); + }), { + once: !0 + }); +} + +e.addEventListener("riceround_toast", (e => { + showToast(e.detail.content, e.detail.type, e.detail.duration); +})), e.addEventListener("riceround_dialog", (e => { + c(JSON.parse(e.detail.json_content), e.detail.id); +})); + +let r = !1; + +async function d(e, t, o = 5e3) { + return new Promise(((n, i) => { + const s = Date.now(), a = () => { + Date.now() - s > o ? i(new Error(`Timeout waiting for ${t} to load`)) : e() ? n() : setTimeout(a, 50); + }; + a(); + })); +} + +export async function initDialogLib(e = !1) { + if (!r) try { + const e = "https://unpkg.com/vue@3/dist/vue.global.js"; + await loadResource(e, ""), await d((() => window.Vue), "vue"); + const t = "https://cdn.jsdelivr.net/npm/element-plus", o = "https://cdn.jsdelivr.net/npm/element-plus/dist/index.css"; + if (await loadResource(t, o), await d((() => window.ElementPlus), "element-plus"), + null == window.DialogLib) { + const e = "riceround/static/dialog-lib.umd.cjs"; + await loadResource(e, ""), await d((() => window.DialogLib), "showLoginDialog"); + } + r = !0; + } catch (e) { + throw e; + } +} + +async function l(t) { + try { + const o = { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify(t) + }, n = await e.fetchApi("/riceround/set_node_additional_info", o); + await n.json(); + } catch (e) {} +} + +function u(e, t, o, n) { + e.type = t, e.value = o, e.options = n; +} + +function p(e, t, o, n) { + "customtext" === t && (t = "text"); + const i = n.options; + var s = e.widgets[1].value; + i?.values?.includes(s) || (s = n.value), "RiceRoundAdvancedChoiceNode" == e.comfyClass || "RiceRoundSimpleChoiceNode" == e.comfyClass ? u(e.widgets[1], t, s, i) : "RiceRoundIntNode" != e.comfyClass && "RiceRoundFloatNode" != e.comfyClass || 4 == e.widgets.length && (u(e.widgets[1], "number", s, i), + u(e.widgets[2], "number", i?.min ?? 0, i), u(e.widgets[3], "number", i?.max ?? 100, i)); +} + +function m(e, t, o, n) { + if (e.outputs[0].type = o.type, "name" === e.widgets[0].label) { + ([ "数值", "文本", "列表", "参数", "Parameter" ].includes(e.widgets[0].value) || "" == e.widgets[0].value) && (e.widgets[0].value = o.label ? o.label : o.name); + } + const i = o.widget?.name ? o.widget?.name : o.name, s = t.widgets.find((e => e.name === i)); + if (!s) return; + p(e, s.origType ?? s.type, t, s); +} + +e.addEventListener("riceround_login_dialog", (t => { + const o = t.detail.client_key, n = t.detail.title; + window.DialogLib.showLoginDialog({ + title: n, + spyNetworkError: !0, + mainKey: "riceround" + }).then((t => { + e.fetchApi("/riceround/auth_callback", { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify({ + token: t, + client_key: o + }) + }), showToast("登录成功"); + })).catch((e => { + showToast("登录失败", "error"); + })); +})), e.addEventListener("riceround_show_workflow_payment_dialog", (e => { + const t = e.detail.title ?? "支付", o = e.detail.template_id; + o ? window.DialogLib.showWorkflowQRPaymentDialog({ + title: t, + template_id: o + }).then((({success: e, msg: t}) => { + showToast(t, e ? "info" : "error"); + })).catch((e => { + showToast("取消支付", "error"); + })) : showToast("模板ID不能为空", "error"); +})), e.addEventListener("riceround_clear_user_info", (async e => { + const t = e.detail.clear_key; + "all" == t ? (localStorage.removeItem("Comfy.Settings.RiceRound.User.long_token"), + localStorage.removeItem("riceround_user_token"), o.ui.settings.setSettingValue("RiceRound.User.long_token", "")) : "long_token" == t ? (localStorage.removeItem("Comfy.Settings.RiceRound.User.long_token"), + o.ui.settings.setSettingValue("RiceRound.User.long_token", "")) : "user_token" == t && localStorage.removeItem("riceround_user_token"); +})), e.addEventListener("execution_start", (async ({detail: e}) => { + let t = ""; + const n = {}; + for (const e of o.graph.nodes) { + if ("RiceRoundDecryptNode" === e.type) return; + if ("RiceRoundEncryptNode" === e.type) { + const o = e.widgets?.find((e => "template_id" === e.name && e.value)); + if (o) { + if (t) return; + t = o.value; + } + } else if ("RiceRoundAdvancedChoiceNode" === e.type || "RiceRoundSimpleChoiceNode" === e.type) { + if (1 === !e.outputs?.[0]?.links?.length) continue; + const t = e.widgets[1].options?.values ?? []; + if (!t.length) continue; + const o = e.graph.links[e.outputs[0].links[0]]; + if (!o) continue; + const i = e.graph.getNodeById(o.target_id); + if (!i?.inputs || "RiceRoundDecryptNode" === i.comfyClass || "RiceRoundEncryptNode" === i.comfyClass) continue; + const s = i.inputs[o.target_slot]; + if (!s || !i.widgets) continue; + const a = s.widget?.name || s.name; + if (!a) continue; + const c = `${i.comfyClass}.${a}`; + n[e.id] = { + class_name: c, + options_value: t, + node_type: e.type + }; + } + } + t && Object.keys(n).length > 0 && await l({ + choice_node_map: n, + template_id: t + }); +})); + +let g = null; + +function h(e, t) { + g && clearTimeout(g), g = setTimeout((() => { + g = null; + const o = t.graph.extra?.choice_node_map; + if (e && e.widgets && 2 === e.widgets.length && o && o[e.id]) { + const t = { + values: o[e.id] + }; + u(e.widgets[1], "combo", e.widgets[1].value, t); + } + }), 200); +} + +function f(e) { + if (!e.outputs || 0 === e.outputs.length) return; + const t = e.outputs[0].links; + if (t && 1 === t.length) { + const n = e.graph.links[t[0]]; + if (!n) return; + const i = e.graph.getNodeById(n.target_id); + if (!i || !i.inputs) return; + if ("RiceRoundDecryptNode" == i.comfyClass && "RiceRoundSimpleChoiceNode" == e.comfyClass) return void h(e, o); + if ("RiceRoundEncryptNode" == i.comfyClass || "RiceRoundDecryptNode" == i.comfyClass) return; + const s = i.inputs[n.target_slot]; + if (!s || void 0 === i.widgets) return; + m(e, i, s, o); + } else t && 0 !== t.length || ("RiceRoundAdvancedChoiceNode" == e.comfyClass || "RiceRoundSimpleChoiceNode" == e.comfyClass ? (e.widgets[0].value = "Parameter", + e.outputs[0].type = "*") : "RiceRoundIntNode" == e.comfyClass ? 4 == e.widgets.length && (e.widgets[0].value = "数值", + e.widgets[1].value = 0, e.widgets[2].value = 0, e.widgets[3].value = 100) : "RiceRoundFloatNode" == e.comfyClass && 4 == e.widgets.length && (e.widgets[0].value = "数值", + e.widgets[1].value = 0, e.widgets[2].value = 0, e.widgets[3].value = 100)); +} + +function w(e) { + const t = e.prototype.onAdded; + e.prototype.onAdded = function() { + t?.apply(this, arguments), f(this); + }; + const n = e.prototype.onAfterGraphConfigured; + e.prototype.onAfterGraphConfigured = function() { + n?.apply(this, arguments), f(this); + }; + const i = e.prototype.onConnectOutput; + e.prototype.onConnectOutput = function(e, t, o, n, s) { + return !(!o.widget && !(o.type in [ "STRING", "COMBO", "combo" ])) && (!i || (result = i.apply(this, arguments), + result)); + }; + const s = e.prototype.onConnectionsChange; + e.prototype.onConnectionsChange = function(e, t, n, i, a) { + return 2 != e || n || !this?.type || "RiceRoundAdvancedChoiceNode" != this.type && "RiceRoundSimpleChoiceNode" != this.type || (this.widgets[0].value = "Parameter"), + o.configuringGraph || f(this), s?.apply(this, arguments); + }; +} + +function y() { + let e = ""; + for (let t = 0; t < 32; t++) { + e += Math.floor(16 * Math.random()).toString(16); + } + return e; +} + +function R() { + if ("electronAPI" in window) return window.electronAPI.restartApp(), !0; + e.fetchApi("/manager/reboot"); +} + +o.registerExtension({ + name: "riceround.custom", + setup() { + initDialogLib(); + }, + async beforeRegisterNodeDef(e, t, o) { + if ([ "RiceRoundAdvancedChoiceNode", "RiceRoundSimpleChoiceNode", "RiceRoundIntNode", "RiceRoundFloatNode" ].includes(t.name) && w(e), + "RiceRoundEncryptNode" == t.name) { + const t = 400, o = 120, n = e.prototype.onNodeCreated; + e.prototype.onNodeCreated = function() { + const e = n ? n.apply(this) : void 0; + return void 0 !== this.size?.[0] && (this.size[0] = t), void 0 !== this.size?.[1] && (this.size[1] = Math.max(o, this.size[1])), + e; + }, e.prototype.onResize = function(e) { + return void 0 !== e?.[0] && (e[0] = t), void 0 !== e?.[1] && (e[1] = Math.max(o, e[1])), + e; + }; + } + }, + loadedGraphNode: async t => { + if (!t.title) { + const o = t.type; + if (o && o.includes("RiceRoundAdvancedChoiceNode")) { + const t = o.match(/RiceRoundAdvancedChoiceNode_([^_]+)_/); + if (!t) return; + const n = t[1]; + await loadMessageBox(); + const i = await Swal.fire({ + title: "高级选择节点安装确认", + html: '\n
\n

检测到高级选择节点,是否需要安装相关组件?

\n
\n \n \n
\n
\n ', + icon: "question", + showCancelButton: !0, + confirmButtonText: "安装", + cancelButtonText: "取消", + heightAuto: !1, + backdrop: !0, + allowOutsideClick: !1, + customClass: { + container: "riceround-swal-top-container" + }, + preConfirm: () => ({ + needReboot: document.getElementById("swal-restart-checkbox").checked + }) + }); + if (i.isConfirmed) try { + if (!(await e.fetchApi("/riceround/install_choice_node", { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify({ + template_id: n, + need_reboot: i.value.needReboot + }) + })).ok) throw new Error("Installation failed"); + await Swal.fire({ + title: "安装成功", + text: i.value.needReboot ? "组件已安装,服务即将重启" : "组件已安装完成", + icon: "success", + heightAuto: !1, + customClass: { + container: "riceround-swal-top-container" + } + }); + } catch (e) { + await Swal.fire({ + title: "安装失败", + text: "组件安装过程中出现错误", + icon: "error", + heightAuto: !1, + customClass: { + container: "riceround-swal-top-container" + } + }); + } + } + } + }, + nodeCreated(e, t) { + if ("RiceRoundEncryptNode" == e.comfyClass && e.widgets && e.widgets.length > 0) { + const t = window.document.title; + if (t || (t = localStorage.getItem("Comfy.PreviousWorkflow")), t) { + let o = t.replace(/[<>:"/\\|?*]/g, " ").replace(/^\s+|\s+$/g, ""); + for (let t = 0; t < e.widgets.length; t++) { + let n = e.widgets[t]; + if ("project_name" == n.name && ("" == n.value || null == n.value || "my_project" == n.value)) { + n.value = o; + break; + } + } + } + e.widgets.push({ + name: "generate_uuid", + type: "button", + label: "Generate UUID", + callback: () => { + const t = y(); + for (let o = 0; o < e.widgets.length; o++) { + let n = e.widgets[o]; + if ("template_id" == n.name) { + n.value = t; + break; + } + } + } + }); + const o = document.getElementById(e.id); + o && o.appendChild(button); + } + } +}); \ No newline at end of file diff --git a/publish.py b/publish.py index fb90e90..5528a17 100644 --- a/publish.py +++ b/publish.py @@ -1,4 +1,5 @@ import json +import logging import os import requests from .rice_prompt_info import RicePromptInfo @@ -112,6 +113,7 @@ class Publish: else: return False, response_data.get("message", "Unknown error") else: + logging.error(f"Server returned status: {response}") return False, f"Server returned status code: {response.status_code}" except Exception as e: return False, str(e) diff --git a/share_client_darwin b/share_client_darwin deleted file mode 100644 index 024d9f8..0000000 Binary files a/share_client_darwin and /dev/null differ diff --git a/share_client_linux b/share_client_linux deleted file mode 100644 index 750f037..0000000 Binary files a/share_client_linux and /dev/null differ diff --git a/share_client_windows.exe b/share_client_windows.exe deleted file mode 100644 index a32916f..0000000 Binary files a/share_client_windows.exe and /dev/null differ