Added serial number validity period and days feature. Fixed the bug where the serial number could only be used for 7 days. Code optimization.
349 lines
14 KiB
Python
349 lines
14 KiB
Python
from collections import defaultdict
|
|
import copy
|
|
import os
|
|
import random
|
|
from server import PromptServer
|
|
from .updown_workflow import DownloadWorkflow
|
|
import folder_paths
|
|
import json
|
|
from .file_compressor import FileCompressor
|
|
from typing import Dict, Any
|
|
from .auth_unit import AuthUnit
|
|
|
|
|
|
class CryptoWorkflow:
|
|
def __init__(self, workflow, prompt, template_id):
|
|
self.workflow = copy.deepcopy(workflow)
|
|
self.prompt = copy.deepcopy(prompt)
|
|
self.template_id = template_id
|
|
self.workflow_nodes_dict = {}
|
|
self.link_owner_map = defaultdict(dict)
|
|
self.node_prompt_map = {}
|
|
self.last_node_id = 0
|
|
self.last_link_id = 0
|
|
self.save_crypto_node_id = 0
|
|
self.crypto_bridge_node_id = 0
|
|
self.input_nodes_ids = set()
|
|
self.output_nodes_ids = set()
|
|
self.crypto_nodes_ids = set()
|
|
self.crypto_result = {}
|
|
|
|
def invalid_workflow(self):
|
|
for node in self.workflow["nodes"]:
|
|
node_type = node.get("type", "")
|
|
if node_type == "SaveCryptoBridgeNode":
|
|
if self.crypto_bridge_node_id == 0:
|
|
self.crypto_bridge_node_id = int(node["id"])
|
|
else:
|
|
raise ValueError(
|
|
"Error: Multiple 'SaveCryptoBridgeNode' instances found."
|
|
)
|
|
continue
|
|
elif node_type == "SaveCryptoNode":
|
|
if self.save_crypto_node_id == 0:
|
|
self.save_crypto_node_id = int(node["id"])
|
|
else:
|
|
raise ValueError(
|
|
"Error: Multiple 'SaveCryptoNode' instances found."
|
|
)
|
|
continue
|
|
if self.save_crypto_node_id == 0:
|
|
raise ValueError("Error: No 'SaveCryptoNode' instances found.")
|
|
if self.crypto_bridge_node_id == 0:
|
|
raise ValueError("Error: No 'SaveCryptoBridgeNode' instances found.")
|
|
|
|
def load_workflow(self):
|
|
simplify_workflow = self.workflow
|
|
self.workflow_nodes_dict = {
|
|
int(node["id"]): node for node in simplify_workflow["nodes"]
|
|
}
|
|
for node in simplify_workflow["nodes"]:
|
|
output_nodes = node.get("outputs", [])
|
|
if not output_nodes:
|
|
continue
|
|
for output in output_nodes:
|
|
links = output.get("links", [])
|
|
if not links:
|
|
continue
|
|
for link in links:
|
|
link = int(link)
|
|
self.link_owner_map[link]["links"] = copy.deepcopy(links)
|
|
self.link_owner_map[link]["slot_index"] = output.get(
|
|
"slot_index", 0
|
|
)
|
|
self.link_owner_map[link]["owner_id"] = int(node["id"])
|
|
self.link_owner_map[link]["type"] = output.get("type", "")
|
|
self.last_node_id = int(simplify_workflow.get("last_node_id", 0))
|
|
self.last_link_id = int(simplify_workflow.get("last_link_id", 0))
|
|
|
|
def load_prompt(self):
|
|
simplify_prompt = self.prompt
|
|
self.node_prompt_map = {
|
|
int(node_id): node for (node_id, node) in simplify_prompt.items()
|
|
}
|
|
|
|
def analysis_node(self):
|
|
self.input_nodes_ids.clear()
|
|
self.output_nodes_ids.clear()
|
|
self.crypto_nodes_ids.clear()
|
|
|
|
def find_input_nodes(node_id, visited=None):
|
|
if visited is None:
|
|
visited = set()
|
|
if node_id in visited:
|
|
return
|
|
visited.add(node_id)
|
|
self.input_nodes_ids.add(node_id)
|
|
node = self.workflow_nodes_dict.get(node_id)
|
|
if not node:
|
|
return
|
|
for input_node in node.get("inputs", []):
|
|
input_link = input_node.get("link")
|
|
if input_link is not None and input_link in self.link_owner_map:
|
|
owner_id = self.link_owner_map[input_link]["owner_id"]
|
|
find_input_nodes(owner_id, visited)
|
|
|
|
for input_node in self.workflow_nodes_dict[self.save_crypto_node_id].get(
|
|
"inputs", []
|
|
):
|
|
if input_node["name"] and input_node["name"].startswith("input_anything"):
|
|
input_link = input_node["link"]
|
|
if input_link is not None and input_link in self.link_owner_map:
|
|
owner_id = self.link_owner_map[input_link]["owner_id"]
|
|
find_input_nodes(owner_id)
|
|
|
|
def find_output_nodes(node_id, visited=None):
|
|
if visited is None:
|
|
visited = set()
|
|
if node_id in visited:
|
|
return
|
|
visited.add(node_id)
|
|
self.output_nodes_ids.add(node_id)
|
|
node = self.workflow_nodes_dict.get(node_id)
|
|
if not node:
|
|
return
|
|
for output in node.get("outputs", []):
|
|
if not output or not output.get("links"):
|
|
continue
|
|
for link in output.get("links", []):
|
|
if not link:
|
|
continue
|
|
if link is not None:
|
|
for workflow_link in self.workflow.get("links", []):
|
|
if workflow_link[0] == link:
|
|
target_node_id = workflow_link[3]
|
|
find_output_nodes(target_node_id, visited)
|
|
|
|
output_links = set()
|
|
for output_node in self.workflow_nodes_dict[self.crypto_bridge_node_id].get(
|
|
"outputs", []
|
|
):
|
|
_links = output_node["links"]
|
|
output_links.update(_links)
|
|
for link in self.workflow.get("links", []):
|
|
if len(link) > 3 and link[0] in output_links:
|
|
find_output_nodes(link[3])
|
|
self.crypto_nodes_ids = (
|
|
self.workflow_nodes_dict.keys()
|
|
- self.input_nodes_ids
|
|
- self.output_nodes_ids
|
|
)
|
|
self.crypto_nodes_ids = self.crypto_nodes_ids - {
|
|
self.save_crypto_node_id,
|
|
self.crypto_bridge_node_id,
|
|
}
|
|
|
|
def calculate_crypto_result(self, crypto_file_name):
|
|
self.crypto_result = {"prompt": {}, "workflow": {}, "outputs": []}
|
|
for node_id in self.crypto_nodes_ids:
|
|
if node_id in self.node_prompt_map:
|
|
self.crypto_result["prompt"][node_id] = self.node_prompt_map[node_id]
|
|
if node_id in self.workflow_nodes_dict:
|
|
self.crypto_result["workflow"][node_id] = self.workflow_nodes_dict[
|
|
node_id
|
|
]
|
|
crypto_bridge_node = self.node_prompt_map[self.crypto_bridge_node_id]
|
|
for input_name, input_value in crypto_bridge_node.get("inputs", {}).items():
|
|
if isinstance(input_value, list) and len(input_value) == 2:
|
|
self.crypto_result["outputs"] = input_value[0], input_value[1]
|
|
json_result = json.dumps(self.crypto_result, indent=4, ensure_ascii=False)
|
|
save_dir = folder_paths.temp_directory
|
|
with open(os.path.join(save_dir, crypto_file_name), "w", encoding="utf-8") as f:
|
|
f.write(json_result)
|
|
return save_dir
|
|
|
|
def output_workflow_simple_shell(self, output_workflow_name):
|
|
simplify_workflow = copy.deepcopy(self.workflow)
|
|
save_crypto_node = None
|
|
crypto_bridge_node = None
|
|
for node in simplify_workflow["nodes"]:
|
|
if node["id"] == self.save_crypto_node_id:
|
|
save_crypto_node = node
|
|
if node["id"] == self.crypto_bridge_node_id:
|
|
crypto_bridge_node = node
|
|
except_nodes_ids = self.crypto_nodes_ids
|
|
except_nodes_ids.add(self.crypto_bridge_node_id)
|
|
simplify_workflow["nodes"] = [
|
|
node
|
|
for node in simplify_workflow["nodes"]
|
|
if int(node["id"]) not in except_nodes_ids
|
|
]
|
|
if save_crypto_node is None:
|
|
raise ValueError("SaveCryptoNode not found in workflow")
|
|
if crypto_bridge_node is None:
|
|
raise ValueError("CryptoBridgeNode not found in workflow")
|
|
save_crypto_node["type"] = "DecodeCryptoNode"
|
|
save_crypto_node["widgets_values"] = (
|
|
[save_crypto_node.get("widgets_values", [None])[0]]
|
|
if "widgets_values" in save_crypto_node
|
|
else [None]
|
|
)
|
|
save_crypto_node["widgets_values"].append("")
|
|
save_crypto_node["properties"] = {"Node name for S&R": "DecodeCryptoNode"}
|
|
if "outputs" not in crypto_bridge_node:
|
|
save_crypto_node["outputs"] = []
|
|
else:
|
|
save_crypto_node["outputs"] = copy.deepcopy(crypto_bridge_node["outputs"])
|
|
output_nodes_ids = [int(node["id"]) for node in simplify_workflow["nodes"]]
|
|
filtered_links = []
|
|
for link in simplify_workflow["links"]:
|
|
if len(link) < 5:
|
|
continue
|
|
if link[1] == self.crypto_bridge_node_id:
|
|
link[1] = self.save_crypto_node_id
|
|
if link[1] in output_nodes_ids and link[3] in output_nodes_ids:
|
|
filtered_links.append(link)
|
|
else:
|
|
pass
|
|
simplify_workflow["links"] = filtered_links
|
|
simplify_workflow.pop("groups", None)
|
|
save_dir = folder_paths.output_directory
|
|
with open(
|
|
os.path.join(folder_paths.output_directory, output_workflow_name),
|
|
"w",
|
|
encoding="utf-8",
|
|
) as f:
|
|
json.dump(simplify_workflow, f, ensure_ascii=False, indent=4)
|
|
return save_dir
|
|
|
|
def save_original_workflow(self, output_workflow_name, save_dir):
|
|
with open(
|
|
os.path.join(save_dir, output_workflow_name), "w", encoding="utf-8"
|
|
) as f:
|
|
json.dump(self.workflow, f, ensure_ascii=False, indent=4)
|
|
return save_dir
|
|
|
|
def save_original_prompt(self, output_prompt_name, save_dir):
|
|
with open(
|
|
os.path.join(save_dir, output_prompt_name), "w", encoding="utf-8"
|
|
) as f:
|
|
json.dump(self.prompt, f, ensure_ascii=False, indent=4)
|
|
return save_dir
|
|
|
|
|
|
class DecodeCryptoWorkflow:
|
|
def __init__(self, prompt, workflow, template_id):
|
|
self.prompt = prompt
|
|
self.workflow = workflow
|
|
self.template_id = template_id
|
|
self.crypto_result = {}
|
|
self.input_anything_map = {}
|
|
|
|
def calculate_input_anything_map(self):
|
|
self.input_anything_map.clear()
|
|
for node_id, node in self.prompt.items():
|
|
if node.get("class_type") == "DecodeCryptoNode":
|
|
for input_name, input_value in node.get("inputs", {}).items():
|
|
if input_name.startswith("input_anything"):
|
|
if isinstance(input_value, list) and len(input_value) == 2:
|
|
input_link_key = f"{input_value[0]}_{input_value[1]}"
|
|
self.input_anything_map[input_link_key] = input_name
|
|
return self.input_anything_map
|
|
|
|
def load_crypto_prompt(self, serial_number_token, user_token=None):
|
|
if not user_token:
|
|
user_token = AuthUnit().read_user_token()
|
|
content = DownloadWorkflow().download_workflow(
|
|
self.template_id, serial_number_token, user_token
|
|
)
|
|
if not isinstance(content, str) or content == "":
|
|
raise ValueError("failed to download workflow")
|
|
self.crypto_result = json.loads(content)
|
|
return self.crypto_result["prompt"]
|
|
|
|
def get_hidden_input(self, input_value):
|
|
if isinstance(input_value, list) and len(input_value) == 2:
|
|
key = f"{input_value[0]}_{input_value[1]}"
|
|
return self.input_anything_map.get(key, None)
|
|
|
|
def get_outputs(self):
|
|
return self.crypto_result["outputs"]
|
|
|
|
|
|
class WorkflowTrimHandler:
|
|
@staticmethod
|
|
def onprompt_handler(json_data: Dict[str, Any]) -> Dict[str, Any]:
|
|
prompt = json_data["prompt"]
|
|
has_new_component = False
|
|
has_old_component = False
|
|
for node in prompt.values():
|
|
class_type = node.get("class_type")
|
|
if class_type == "SaveCryptoNode":
|
|
has_new_component = True
|
|
break
|
|
if class_type == "ExcuteCryptoNode":
|
|
has_old_component = True
|
|
break
|
|
if has_new_component:
|
|
user_token, error_msg, error_code = AuthUnit().get_user_token()
|
|
print(
|
|
f"user_token: {user_token}, error_msg: {error_msg}, error_code: {error_code}"
|
|
)
|
|
if not user_token:
|
|
if error_code == 401 or error_code == -3:
|
|
AuthUnit().login_dialog("输出CryptoCat加密工作流,请先完成登录")
|
|
json_data["prompt"] = {}
|
|
else:
|
|
PromptServer.instance.send_sync(
|
|
"cryptocat_toast",
|
|
{"content": f"无法完成鉴权登录,{error_msg}", "type": "error"},
|
|
)
|
|
elif has_old_component:
|
|
prompt = WorkflowTrimHandler.replace_prompt(prompt)
|
|
json_data["prompt"] = prompt
|
|
return json_data
|
|
|
|
@staticmethod
|
|
def replace_prompt(prompt: Dict[str, Any]) -> Dict[str, Any]:
|
|
if not prompt:
|
|
raise ValueError("Invalid JSON format.")
|
|
crypto_file_path = ""
|
|
excute_crypto_id = None
|
|
for node_id, node in list(prompt.items()):
|
|
if node.get("class_type") == "ExcuteCryptoNode":
|
|
crypto_file_path = node["inputs"].get("crypto_file_path")
|
|
excute_crypto_id = node_id
|
|
del prompt[node_id]
|
|
break
|
|
if not crypto_file_path:
|
|
print("No 'ExcuteCryptoNode' found in prompt.")
|
|
return prompt
|
|
inject_json = FileCompressor.decompress_from_json(crypto_file_path, "19040822")
|
|
output_images_ids = inject_json.pop("output_images_ids")
|
|
for node in prompt.values():
|
|
if node.get("class_type") == "CryptoCatImage":
|
|
if excute_crypto_id in node["inputs"]["images"]:
|
|
node["inputs"]["images"] = output_images_ids
|
|
random_seed_node = next(
|
|
(
|
|
node
|
|
for node in inject_json.values()
|
|
if node.get("class_type") == "RandomSeedNode"
|
|
),
|
|
None,
|
|
)
|
|
if random_seed_node:
|
|
random_seed_node["inputs"]["is_changed"] = random.randint(0, 999999)
|
|
prompt.update(inject_json)
|
|
return prompt
|