From aefe44abc61824ec8a11ee383c6613b2bb581eaf Mon Sep 17 00:00:00 2001 From: RiceRound Date: Fri, 27 Dec 2024 22:30:17 +0800 Subject: [PATCH] Fixed some security issues and added daemon boot --- __init__.py | 79 +++++++++++++++++++++--------------------- auth_unit.py | 12 ++----- js/riceconfig.js | 2 +- js/riceround.js | 2 +- rice_prompt_handler.py | 2 +- rice_prompt_info.py | 59 +++++++++++++++++++++---------- rice_url_config.py | 10 +++--- utils.py | 4 +-- 8 files changed, 92 insertions(+), 78 deletions(-) diff --git a/__init__.py b/__init__.py index c99e09c..e70fad4 100644 --- a/__init__.py +++ b/__init__.py @@ -1,33 +1,32 @@ -_e='RiceRoundTempTokenNode' -_d='RiceRoundOutputImageNode' -_c='RiceRoundEncryptNode' -_b='RiceRoundOutputTextNode' -_a='RiceRoundOutputBooleanNode' -_Z='RiceRoundOutputFloatNode' -_Y='RiceRoundOutputIntNode' -_X='RiceRoundOutputMaskBridgeNode' -_W='RiceRoundUploadImageNode' -_V='RiceRoundImageUrlNode' -_U='RiceRoundOutputImageBridgeNode' -_T='RiceRoundDecryptNode' -_S='RiceRoundStrToBooleanNode' -_R='RiceRoundStrToFloatNode' -_Q='RiceRoundStrToIntNode' -_P='RiceRoundBooleanNode' -_O='RiceRoundFloatNode' -_N='RiceRoundIntNode' -_M='RiceRoundDownloadMaskNode' -_L='RiceRoundMaskBridgeNode' -_K='RiceRoundInputTextNode' -_J='RiceRoundRandomSeedNode' -_I='RiceRoundDownloadImageNode' -_H='RiceRoundSimpleImageNode' -_G='RiceRoundImageBridgeNode' -_F='RiceRoundDebugNode' -_E='RiceRoundAdvancedChoiceNode' -_D='RiceRoundSimpleChoiceNode' -_C='dynamic_class' -_B='error' +_d='RiceRoundTempTokenNode' +_c='RiceRoundOutputImageNode' +_b='RiceRoundEncryptNode' +_a='RiceRoundOutputTextNode' +_Z='RiceRoundOutputBooleanNode' +_Y='RiceRoundOutputFloatNode' +_X='RiceRoundOutputIntNode' +_W='RiceRoundOutputMaskBridgeNode' +_V='RiceRoundUploadImageNode' +_U='RiceRoundImageUrlNode' +_T='RiceRoundOutputImageBridgeNode' +_S='RiceRoundDecryptNode' +_R='RiceRoundStrToBooleanNode' +_Q='RiceRoundStrToFloatNode' +_P='RiceRoundStrToIntNode' +_O='RiceRoundBooleanNode' +_N='RiceRoundFloatNode' +_M='RiceRoundIntNode' +_L='RiceRoundDownloadMaskNode' +_K='RiceRoundMaskBridgeNode' +_J='RiceRoundInputTextNode' +_I='RiceRoundRandomSeedNode' +_H='RiceRoundDownloadImageNode' +_G='RiceRoundSimpleImageNode' +_F='RiceRoundImageBridgeNode' +_E='RiceRoundDebugNode' +_D='RiceRoundAdvancedChoiceNode' +_C='RiceRoundSimpleChoiceNode' +_B='dynamic_class' _A='display_name' import platform,random from urllib.parse import unquote @@ -41,14 +40,14 @@ from aiohttp import web from functools import partial from.rice_prompt_handler import RiceRoundPromptHandler from.rice_url_config import RiceUrlConfig -from.rice_prompt_info import RicePromptInfo +from.rice_prompt_info import RiceEnvConfig,RicePromptInfo def create_dynamic_nodes(base_class): rice_prompt_info=RicePromptInfo();dynamic_classes={} - for(node_name,info)in rice_prompt_info.choice_classname_map.items():class_name=node_name;category='RiceRound/Advanced/Choice';dynamic_class=type(class_name,(base_class,),{'__node_name__':node_name,'CATEGORY':category});dynamic_classes[class_name]={_C:dynamic_class,_A:info.get(_A,class_name)} + for(node_name,info)in rice_prompt_info.choice_classname_map.items():class_name=node_name;category='RiceRound/Advanced/Choice';dynamic_class=type(class_name,(base_class,),{'__node_name__':node_name,'CATEGORY':category});dynamic_classes[class_name]={_B:dynamic_class,_A:info.get(_A,class_name)} return dynamic_classes dynamic_choice_nodes=create_dynamic_nodes(RiceRoundBaseChoiceNode) -NODE_CLASS_MAPPINGS={_D:RiceRoundSimpleChoiceNode,_E:RiceRoundAdvancedChoiceNode,_F:RiceRoundDebugNode,_G:RiceRoundImageBridgeNode,_H:RiceRoundSimpleImageNode,_I:RiceRoundDownloadImageNode,_J:RiceRoundRandomSeedNode,_K:RiceRoundInputTextNode,_L:RiceRoundMaskBridgeNode,_M:RiceRoundDownloadMaskNode,_N:RiceRoundIntNode,_O:RiceRoundFloatNode,_P:RiceRoundBooleanNode,_Q:RiceRoundStrToIntNode,_R:RiceRoundStrToFloatNode,_S:RiceRoundStrToBooleanNode,_T:RiceRoundDecryptNode,_U:RiceRoundOutputImageBridgeNode,_V:RiceRoundImageUrlNode,_W:RiceRoundUploadImageNode,_X:RiceRoundOutputMaskBridgeNode,_Y:RiceRoundOutputIntNode,_Z:RiceRoundOutputFloatNode,_a:RiceRoundOutputBooleanNode,_b:RiceRoundOutputTextNode,_c:RiceRoundEncryptNode,_d:RiceRoundOutputImageNode,_e:RiceRoundTempTokenNode,**{name:cls[_C]for(name,cls)in dynamic_choice_nodes.items()}} -NODE_DISPLAY_NAME_MAPPINGS={_D:'Simple Choice',_E:'Advanced Choice',_F:'Debug',_G:'Image Bridge',_H:'Simple Image',_I:'Download Image',_J:'Random Seed',_K:'Input Text',_L:'Mask Bridge',_M:'Download Mask',_N:'RiceRound Int',_O:'RiceRound Float',_P:'RiceRound Boolean',_Q:'RiceRound Str To Int',_R:'RiceRound Str To Float',_S:'RiceRound Str To Boolean',_T:'Decrypt',_U:'Output Image Bridge',_V:'Image URL',_W:'Upload Image',_X:'Output Mask Bridge',_Y:'Output Int',_Z:'Output Float',_a:'Output Boolean',_b:'Output Text',_c:'Encrypt',_d:'Output Image',_e:'Temp Token',**{name:cls[_A]for(name,cls)in dynamic_choice_nodes.items()}} +NODE_CLASS_MAPPINGS={_C:RiceRoundSimpleChoiceNode,_D:RiceRoundAdvancedChoiceNode,_E:RiceRoundDebugNode,_F:RiceRoundImageBridgeNode,_G:RiceRoundSimpleImageNode,_H:RiceRoundDownloadImageNode,_I:RiceRoundRandomSeedNode,_J:RiceRoundInputTextNode,_K:RiceRoundMaskBridgeNode,_L:RiceRoundDownloadMaskNode,_M:RiceRoundIntNode,_N:RiceRoundFloatNode,_O:RiceRoundBooleanNode,_P:RiceRoundStrToIntNode,_Q:RiceRoundStrToFloatNode,_R:RiceRoundStrToBooleanNode,_S:RiceRoundDecryptNode,_T:RiceRoundOutputImageBridgeNode,_U:RiceRoundImageUrlNode,_V:RiceRoundUploadImageNode,_W:RiceRoundOutputMaskBridgeNode,_X:RiceRoundOutputIntNode,_Y:RiceRoundOutputFloatNode,_Z:RiceRoundOutputBooleanNode,_a:RiceRoundOutputTextNode,_b:RiceRoundEncryptNode,_c:RiceRoundOutputImageNode,_d:RiceRoundTempTokenNode,**{name:cls[_B]for(name,cls)in dynamic_choice_nodes.items()}} +NODE_DISPLAY_NAME_MAPPINGS={_C:'Simple Choice',_D:'Advanced Choice',_E:'Debug',_F:'Image Bridge',_G:'Simple Image',_H:'Download Image',_I:'Random Seed',_J:'Input Text',_K:'Mask Bridge',_L:'Download Mask',_M:'RiceRound Int',_N:'RiceRound Float',_O:'RiceRound Boolean',_P:'RiceRound Str To Int',_Q:'RiceRound Str To Float',_R:'RiceRound Str To Boolean',_S:'Decrypt',_T:'Output Image Bridge',_U:'Image URL',_V:'Upload Image',_W:'Output Mask Bridge',_X:'Output Int',_Y:'Output Float',_Z:'Output Boolean',_a:'Output Text',_b:'Encrypt',_c:'Output Image',_d:'Temp Token',**{name:cls[_A]for(name,cls)in dynamic_choice_nodes.items()}} WEB_DIRECTORY='./js' __all__=['NODE_CLASS_MAPPINGS','NODE_DISPLAY_NAMES_MAPPINGS','WEB_DIRECTORY'] handler_instance=RiceRoundPromptHandler() @@ -67,16 +66,16 @@ async def auth_callback(request): async def set_node_additional_info(request):additional_info=await request.json();RicePromptInfo().set_node_additional_info(additional_info);return web.json_response({},status=200) @routes.get('/riceround/open_selector_list_folder') async def open_selector_list_folder(request): + A='error' + if request.remote not in('127.0.0.1','::1'):return web.json_response({A:'Unauthorized access'},status=403) choice_server_folder=RicePromptInfo().get_choice_server_folder() - if not choice_server_folder.exists():return web.json_response({_B:'Folder does not exist'},status=404) + if not choice_server_folder.exists():return web.json_response({A:'Folder does not exist'},status=404) system=platform.system() try: if system=='Windows':os.startfile(choice_server_folder) elif system=='Darwin':subprocess.run(['open',choice_server_folder]) else:subprocess.run(['xdg-open',choice_server_folder]) return web.json_response({'status':'success'},status=200) - except Exception as e:return web.json_response({_B:str(e)},status=500) -@routes.post('/riceround/set_long_token') -async def set_long_token(request): - try:request_data=await request.json();long_token=request_data.get('long_token','');AuthUnit().set_user_long_token(long_token);return web.json_response({},status=200) - except Exception as e:return web.json_response({_B:str(e)},status=500) \ No newline at end of file + except Exception as e:return web.json_response({A:str(e)},status=500) +@routes.get('/riceround/save_current_env_config') +async def save_current_env_config(request):RiceEnvConfig().save_env_config();return web.json_response({},status=200) \ No newline at end of file diff --git a/auth_unit.py b/auth_unit.py index da5def5..f7819c0 100644 --- a/auth_unit.py +++ b/auth_unit.py @@ -6,7 +6,7 @@ import base64,json,os from pathlib import Path import time from urllib.parse import urljoin -from.utils import get_local_app_path,get_machine_id +from.utils import get_local_app_setting_path,get_machine_id from.rice_url_config import RiceUrlConfig from server import PromptServer import urllib.request,urllib.error,configparser @@ -17,17 +17,11 @@ class AuthUnit: return A._instance def __init__(A): B=True - if not hasattr(A,'initialized'):A.machine_id=get_machine_id();A.url_config=RiceUrlConfig();A.callback_path='/riceround/auth_callback';A.shift_key=sum(ord(A)for A in A.machine_id[:8])%20+1;C=get_local_app_path();C.mkdir(parents=B,exist_ok=B);A.config_path=C/'config.ini';A.auto_login=False;A.load_config();A.last_check_time=0;A.temp_token='';A.long_token='';A.initialized=B + if not hasattr(A,'initialized'):A.machine_id=get_machine_id();A.url_config=RiceUrlConfig();A.callback_path='/riceround/auth_callback';A.shift_key=sum(ord(A)for A in A.machine_id[:8])%20+1;C=get_local_app_setting_path();C.mkdir(parents=B,exist_ok=B);A.config_path=C/'config.ini';A.auto_login=False;A.load_config();A.last_check_time=0;A.temp_token='';A.initialized=B def load_config(A):B=configparser.ConfigParser();B.read(A.config_path,encoding=_A);A.auto_login=B.get(_B,'auto_login',fallback=False) def set_temp_token(A,temp_token):A.temp_token=temp_token - def set_user_long_token(A,long_token): - B=long_token - if not B:A.long_token='' - elif len(B)==64:A.long_token=B;A.clear_user_token() def get_user_token(B): - A='' - if B.long_token:A=B.long_token - else:A=B.read_user_token() + A='';A=B.read_user_token() if not A and B.temp_token:A=B.temp_token if A and time.time()-B.last_check_time>120: try: diff --git a/js/riceconfig.js b/js/riceconfig.js index cd12e2f..7209b22 100644 --- a/js/riceconfig.js +++ b/js/riceconfig.js @@ -1 +1 @@ -import{api}from"../../../scripts/api.js";import{ComfyApp,app}from"../../../scripts/app.js";app.registerExtension({name:"riceround.config",async setup(){const e=localStorage.getItem("RiceRound.Setting.user.long_token");e&&64==e.length&&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.name",name:"模型列表存放位置,可以制造需要的ChoiceNode",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}}),app.ui.settings.addSetting({id:"RiceRound.User.long_token",name:"设置用户token,从www.riceround.online获取",type:"text",defaultValue:"",tooltip:"用于非本机授权登录情况,请勿泄露!提倡使用本机登录授权更安全!",onChange:function(e){let t=!1;64==e.length?(localStorage.setItem("RiceRound.Setting.user.long_token",e),t=!0):e||(localStorage.removeItem("RiceRound.Setting.user.long_token"),t=!0),t&&api.fetchApi("/riceround/set_long_token",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({long_token:e})})}})}}); \ No newline at end of file +import{api}from"../../../scripts/api.js";import{ComfyApp,app}from"../../../scripts/app.js";import{showToast,showHtmlMessageBox}from"./riceround.js";app.registerExtension({name:"riceround.config",async setup(){app.ui.settings.addSetting({id:"RiceRound.Setting.name",name:"模型列表存放位置,可以制造需要的ChoiceNode",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}}),app.ui.settings.addSetting({id:"RiceRound.User.env_config",name:"获取ComfyUI环境配置,用于share_client启动",tooltip:"使用conda等虚拟环境的情况下自动获取可能出错,建议手动设置client.toml",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=async()=>{200==(await api.fetchApi("/riceround/save_current_env_config",{method:"GET",headers:{"Content-Type":"application/json"}})).status?showToast("获取参数成功!如果启动后异常,建议手动设置client.toml","info",3e3):showToast("获取参数失败!请手动设置client.toml","error",3e3)},t.appendChild(o),e.appendChild(t),e}})}}); \ No newline at end of file diff --git a/js/riceround.js b/js/riceround.js index e751d69..5f21037 100644 --- a/js/riceround.js +++ b/js/riceround.js @@ -1 +1 @@ -import{api}from"../../../scripts/api.js";import{ComfyApp,app}from"../../../scripts/app.js";const GetHost=()=>{const{protocol:e,hostname:t,port:o}=window.location,n=parseInt(o,10);let i=t;return 80===n&&"http:"===e||443===n&&"https:"===e?i=t:isNaN(n)||0===n||(i=`${t}:${o}`),i};function loadToastScript(){return new Promise(((e,t)=>{const o=document.createElement("script");o.src="https://cdn.jsdelivr.net/npm/toastify-js",o.onload=e,o.onerror=t,document.head.appendChild(o);const n=document.createElement("link");n.href="https://cdn.jsdelivr.net/npm/toastify-js/src/toastify.min.css",n.type="text/css",n.rel="stylesheet",document.head.appendChild(n)}))}let toastHasLoaded=!1;async function loadToast(){toastHasLoaded||(await loadToastScript(),toastHasLoaded=!0)}async function showToast(e,t="info",o=3e3){await loadToast(),"info"==t?Toastify({text:e,duration:o,close:!1,gravity:"top",position:"center",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()}function loadMessageBoxScript(){return new Promise(((e,t)=>{const o=document.createElement("script");o.src="https://cdn.jsdelivr.net/npm/sweetalert2@11",o.onload=e,o.onerror=t,document.head.appendChild(o)}))}let messageBoxHasLoaded=!1;async function loadMssageBox(){messageBoxHasLoaded||(await loadMessageBoxScript(),messageBoxHasLoaded=!0)}async function showHtmlMessageBox(e,t,o,n,i){await loadMssageBox(),Swal.fire({title:e,html:t,icon:o,confirmButtonText:n,preConfirm:()=>{i&&(window.location.href=i)}})}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){console.error("riceround set_node_additional_info error",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"),console.log("changeWidgets",e,t,o,n);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("rice_round_toast",(e=>{showToast(e.detail.content,e.detail.type,e.detail.duration)})),api.addEventListener("rice_round_login",(e=>{const t=e.detail.machine_id,o=e.detail.url_prefix,n=GetHost(),i=`${window.location.protocol}//${n}`,a=`${o}/auth/login?machine_id=${t}&callback_url=${btoa(`${i}/riceround/auth_callback`)}`;showHtmlMessageBox("登录",`RiceRound登录失效,请点击链接重新登录`,"info","确定",a)})),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 console.log("applySimpleChoiceNodeExtraLogic",e),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}app.registerExtension({name:"riceround.custom",async beforeRegisterNodeDef(e,t,o){["RiceRoundAdvancedChoiceNode","RiceRoundSimpleChoiceNode","RiceRoundIntNode","RiceRoundFloatNode"].includes(t.name)&&setupParameterNode(e)},nodeCreated(e,t){if("RiceRoundEncryptNode"==e.comfyClass&&e.widgets&&e.widgets.length>0){const t=window.document.title;if(t){let o=t.replace(/\s*-\s*ComfyUI$/,"").replace(/[<>:"/\\|?*]/g,"_").replace(/^[^a-zA-Z]+|[^a-zA-Z]+$/g,"");for(let t=0;t{const t=generateUUID();for(let o=0;o{const{protocol:e,hostname:t,port:o}=window.location,n=parseInt(o,10);let i=t;return 80===n&&"http:"===e||443===n&&"https:"===e?i=t:isNaN(n)||0===n||(i=`${t}:${o}`),i};function loadToastScript(){return new Promise(((e,t)=>{const o=document.createElement("script");o.src="https://cdn.jsdelivr.net/npm/toastify-js",o.onload=e,o.onerror=t,document.head.appendChild(o);const n=document.createElement("link");n.href="https://cdn.jsdelivr.net/npm/toastify-js/src/toastify.min.css",n.type="text/css",n.rel="stylesheet",document.head.appendChild(n)}))}let toastHasLoaded=!1;async function loadToast(){toastHasLoaded||(await loadToastScript(),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",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()}function loadMessageBoxScript(){return new Promise(((e,t)=>{const o=document.createElement("script");o.src="https://cdn.jsdelivr.net/npm/sweetalert2@11",o.onload=e,o.onerror=t,document.head.appendChild(o)}))}let messageBoxHasLoaded=!1;async function loadMssageBox(){messageBoxHasLoaded||(await loadMessageBoxScript(),messageBoxHasLoaded=!0)}export async function showHtmlMessageBox(e,t,o,n,i){await loadMssageBox(),Swal.fire({title:e,html:t,icon:o,confirmButtonText:n,preConfirm:()=>{i&&(window.location.href=i)}})}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){console.error("riceround set_node_additional_info error",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"),console.log("changeWidgets",e,t,o,n);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("rice_round_toast",(e=>{showToast(e.detail.content,e.detail.type,e.detail.duration)})),api.addEventListener("rice_round_login",(e=>{const t=e.detail.machine_id,o=e.detail.url_prefix,n=GetHost(),i=`${window.location.protocol}//${n}`,a=`${o}/auth/login?machine_id=${t}&callback_url=${btoa(`${i}/riceround/auth_callback`)}`;showHtmlMessageBox("登录",`RiceRound登录失效,请点击链接重新登录`,"info","确定",a)})),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 console.log("applySimpleChoiceNodeExtraLogic",e),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}app.registerExtension({name:"riceround.custom",async beforeRegisterNodeDef(e,t,o){["RiceRoundAdvancedChoiceNode","RiceRoundSimpleChoiceNode","RiceRoundIntNode","RiceRoundFloatNode"].includes(t.name)&&setupParameterNode(e)},nodeCreated(e,t){if("RiceRoundEncryptNode"==e.comfyClass&&e.widgets&&e.widgets.length>0){const t=window.document.title;if(t){let o=t.replace(/\s*-\s*ComfyUI$/,"").replace(/[<>:"/\\|?*]/g,"_").replace(/^[^a-zA-Z]+|[^a-zA-Z]+$/g,"");for(let t=0;t{const t=generateUUID();for(let o=0;o:"/\\\\|?*]','',G);F='RiceRoundAdvancedChoiceNode_'+hashlib.md5(E.lower().encode()).hexdigest() if F in B.choice_classname_map:print(f"Error RicePromptInfo set_node_additional_info python_class_name {F} already exists");PromptServer.instance.send_sync('rice_round_toast',{'content':'选择名称重复,如果本身是同一类型的节点,可以忽略提示','type':'info','duration':5000}) - A[_B]=F;A[_E]=E;B.new_choice_file_map[E]=A - B.choice_node_map[D]=A \ No newline at end of file + A[_D]=F;A[_G]=E;B.new_choice_file_map[E]=A + B.choice_node_map[D]=A +class RiceEnvConfig: + def __init__(A):A.local_app_path=get_local_app_setting_path();A.config_path=A.local_app_path/'config.ini' + def filter_add_cmd(F,add_cmd): + B=add_cmd;C=[];A=_B + if not B:return'' + try: + for D in B.split(): + if A:A=_B;continue + if D in['--listen','--port']:A=_A;continue + C.append(D) + except Exception as E:print(f"Error processing add_cmd: {E}");return'' + return' '.join(C) + def save_env_config(B): + C='ComfyUI';D=sys.executable;E=os.getcwd();F=' '.join(sys.argv[1:]);B.local_app_path.mkdir(parents=_A,exist_ok=_A);A=configparser.ConfigParser() + if B.config_path.exists():A.read(B.config_path,encoding=_C) + if not A.has_section(C):A.add_section(C) + G=B.filter_add_cmd(F).strip();A.set(C,'PythonPath',D);A.set(C,'WorkingDirectory',E);A.set(C,'AddCmd',G) + with open(B.config_path,'w',encoding=_C)as H:A.write(H) \ No newline at end of file diff --git a/rice_url_config.py b/rice_url_config.py index af32d7f..f05cefe 100644 --- a/rice_url_config.py +++ b/rice_url_config.py @@ -13,7 +13,7 @@ from PIL import Image from io import BytesIO import numpy as np,requests from urllib.parse import urljoin -from.utils import get_local_app_path +from.utils import get_local_app_setting_path DEFAULT_SUBDOMAIN='api'if os.getenv('DEBUG')!='true'else'test' DEFAULT_URL_PREFIX=f"https://{DEFAULT_SUBDOMAIN}.riceround.online" DEFAULT_WS_PREFIX=f"wss://{DEFAULT_SUBDOMAIN}.riceround.online" @@ -28,10 +28,10 @@ class RiceUrlConfig: def __init__(A): if not A._initialized:A.comfyui_local_web_server_info={};A.load_comfyui_local_web_server_info();A.server_info={};A.load_server_info();A._initialized=True def set_comfyui_local_web_server_info(B,local_server_info): - A=local_server_info;B.comfyui_local_web_server_info=A;C=get_local_app_path();D=C/_C + A=local_server_info;B.comfyui_local_web_server_info=A;C=get_local_app_setting_path();D=C/_C with open(D,'w')as E:json.dump(A,E) def load_comfyui_local_web_server_info(A): - C=get_local_app_path();B=C/_C + C=get_local_app_setting_path();B=C/_C if B.exists(): with open(B,'r')as D:A.comfyui_local_web_server_info=json.load(D) else:A.comfyui_local_web_server_info={} @@ -44,10 +44,10 @@ class RiceUrlConfig: if B and isinstance(B,dict): A=B.get(_A) if A and isinstance(A,dict): - C.server_info=A;D=get_local_app_path() + C.server_info=A;D=get_local_app_setting_path() with open(D/_D,'w')as E:json.dump(A,E) def load_server_info(B): - C=get_local_app_path();A=C/_D + C=get_local_app_setting_path();A=C/_D if A.exists(): with open(A,'r')as D:B.server_info=json.load(D) def get_server_url(A,url_path):return urljoin(A.url_prefix,url_path) diff --git a/utils.py b/utils.py index 221c22c..2f0c10b 100644 --- a/utils.py +++ b/utils.py @@ -39,9 +39,9 @@ def calculate_machine_id(): except Exception:pass return str(uuid.getnode()) def normalize_machine_id(machine_id):'\n 接受一个机器标识符,并返回经过 MD5 哈希处理的规范化标识符\n ';A=_B;B=machine_id.strip();C=B.lower();D=C+A;E=hashlib.md5(D.encode(_A));return E.hexdigest() -def get_local_app_path():A=Path.home();B=A/_B;return B +def get_local_app_setting_path():A=Path.home();B=A/_B;return B def get_machine_id(): - '\n 返回机器ID,为了兼容各个平台,各个语言,需要统一读写这个值\n ';F='machine_id';B='Machine';D=get_local_app_path();C=D/'machine.ini' + '\n 返回机器ID,为了兼容各个平台,各个语言,需要统一读写这个值\n ';F='machine_id';B='Machine';D=get_local_app_setting_path();C=D/'machine.ini' try:D.mkdir(parents=True,exist_ok=True) except Exception as E:print(f"Error creating directory '{D}': {E}");return'' A=configparser.ConfigParser()