238 lines
9.6 KiB
Python
238 lines
9.6 KiB
Python
import json
|
|
import os
|
|
from server import PromptServer
|
|
from aiohttp import web
|
|
|
|
# Global dictionary to store current weights for each node
|
|
CURRENT_WEIGHTS = {}
|
|
|
|
# Path for persistent storage
|
|
STORAGE_DIR = os.path.join(os.path.dirname(os.path.realpath(__file__)), "storage")
|
|
WEIGHTS_FILE = os.path.join(STORAGE_DIR, "radar_weights_weights.json")
|
|
|
|
# Ensure storage directory exists
|
|
os.makedirs(STORAGE_DIR, exist_ok=True)
|
|
|
|
# Load saved weights if they exist
|
|
def load_saved_weights():
|
|
global CURRENT_WEIGHTS
|
|
if os.path.exists(WEIGHTS_FILE):
|
|
try:
|
|
with open(WEIGHTS_FILE, 'r') as f:
|
|
CURRENT_WEIGHTS = json.load(f)
|
|
print(f"[Radar Weights] Loaded {len(CURRENT_WEIGHTS)} saved weights from {WEIGHTS_FILE}")
|
|
except Exception as e:
|
|
print(f"[Radar Weights] Error loading saved weights: {e}")
|
|
CURRENT_WEIGHTS = {}
|
|
|
|
# Save weights to file
|
|
def save_weights():
|
|
try:
|
|
with open(WEIGHTS_FILE, 'w') as f:
|
|
json.dump(CURRENT_WEIGHTS, f)
|
|
print(f"[Radar Weights] Saved {len(CURRENT_WEIGHTS)} weights to {WEIGHTS_FILE}")
|
|
except Exception as e:
|
|
print(f"[Radar Weights] Error saving weights: {e}")
|
|
|
|
# Load saved weights on module import
|
|
load_saved_weights()
|
|
|
|
class RadarWeightsNode:
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"axes_count": ("INT", {
|
|
"default": 5,
|
|
"min": 3,
|
|
"max": 10,
|
|
"step": 1,
|
|
"display": "number"
|
|
})
|
|
},
|
|
"hidden": {
|
|
"_weights_sync": ("STRING", {"default": ""}),
|
|
"unique_id": "UNIQUE_ID"
|
|
}
|
|
}
|
|
|
|
# Define dynamic RETURN_TYPES and RETURN_NAMES based on max possible axes
|
|
RETURN_TYPES = tuple(["FLOAT"] * 10) # Support up to 10 axes
|
|
RETURN_NAMES = tuple([str(i+1) for i in range(10)]) # Name them "1" through "10"
|
|
|
|
FUNCTION = "generate"
|
|
CATEGORY = "Spider/Widgets"
|
|
|
|
def generate(self, axes_count, **kwargs):
|
|
# Get node ID from kwargs
|
|
node_id = kwargs.get('unique_id')
|
|
_weights_sync = kwargs.get('_weights_sync', "") # Keep for logging/debugging
|
|
|
|
print(f"[Radar Weights] Generate called for node {node_id}")
|
|
# print(f"[Spider Widget] Full kwargs received: {kwargs}") # Optional: uncomment for deep debug
|
|
print(f"[Radar Weights] Current weights in global state: {CURRENT_WEIGHTS}")
|
|
# print(f"[Spider Widget] Sync widget value received: {_weights_sync}") # Optional: uncomment for deep debug
|
|
|
|
weights_string = None
|
|
node_id_str = str(node_id) if node_id else None
|
|
|
|
# Primarily rely on the global state updated by the API
|
|
if node_id_str and node_id_str in CURRENT_WEIGHTS:
|
|
weights_string = CURRENT_WEIGHTS[node_id_str]
|
|
print(f"[Radar Weights] Using weights from global state for node {node_id_str}: {weights_string}")
|
|
else:
|
|
# If no weights found for this node, use defaults
|
|
print(f"[Radar Weights] No weights found for node {node_id_str}. Using default weights.")
|
|
# Create default weights based on axes_count
|
|
default_weights = [1.0] * axes_count
|
|
weights_string = ",".join(["{:.2f}".format(w) for w in default_weights])
|
|
|
|
# Store these default weights in the global state
|
|
if node_id_str:
|
|
CURRENT_WEIGHTS[node_id_str] = weights_string
|
|
print(f"[Radar Weights] Stored default weights for node {node_id_str}: {weights_string}")
|
|
# Save weights to persistent storage
|
|
save_weights()
|
|
|
|
# Parse weights from string
|
|
try:
|
|
current_weights = [float(w.strip()) for w in weights_string.split(',') if w.strip()]
|
|
|
|
# Ensure the list matches axes_count (pad or truncate)
|
|
if len(current_weights) != axes_count:
|
|
print(f"[Radar Weights] Adjusting weights length ({len(current_weights)}) to match axes_count ({axes_count}) for node {node_id_str}.")
|
|
if len(current_weights) < axes_count:
|
|
current_weights.extend([1.0] * (axes_count - len(current_weights)))
|
|
else:
|
|
current_weights = current_weights[:axes_count]
|
|
|
|
except Exception as e:
|
|
print(f"[Error] RadarWeightsNode: Failed to parse weights for node {node_id_str}. Error: {e}. Using defaults.")
|
|
current_weights = [1.0] * axes_count
|
|
|
|
# Format weights for potential storage update (though API handles primary update)
|
|
# We format for storage/API, but round for output
|
|
formatted_weights = ["{:.2f}".format(w) for w in current_weights]
|
|
updated_weights_string = ",".join(formatted_weights)
|
|
|
|
# Round the weights for output to two decimal places
|
|
rounded_weights = [round(w, 2) for w in current_weights]
|
|
|
|
print(f"[Radar Weights] Returning rounded weights for node {node_id_str}: {rounded_weights}")
|
|
|
|
# Pad with zeros to match max number of outputs (10)
|
|
padded_weights = rounded_weights + [0.0] * (10 - len(rounded_weights))
|
|
return tuple(padded_weights)
|
|
|
|
@classmethod
|
|
def IS_CHANGED(cls, **kwargs):
|
|
# sync_val = kwargs.get('_weights_sync', '') # No longer rely on this potentially stale value
|
|
unique_id = kwargs.get('unique_id', '')
|
|
axes_count = kwargs.get('axes_count', 5)
|
|
|
|
# The hash should depend only on the user-controlled input (axes_count)
|
|
# and the actual state stored in the backend (CURRENT_WEIGHTS retrieved via unique_id).
|
|
node_id_str = str(unique_id) if unique_id else "-1"
|
|
current_weights_str = CURRENT_WEIGHTS.get(node_id_str, "") # Get the ground truth from global state
|
|
|
|
print(f"[Radar Weights] IS_CHANGED called for node {node_id_str}. Axes: {axes_count}, Current Backend Weights: {current_weights_str}")
|
|
|
|
# Create a hash based *only* on reliable data
|
|
return f"{unique_id}-{axes_count}-{current_weights_str}"
|
|
|
|
# API endpoint to handle weight updates
|
|
@PromptServer.instance.routes.post("/radar_weights/update_weights")
|
|
async def update_weights_route(request):
|
|
try:
|
|
data = await request.json()
|
|
node_id = data.get('node_id')
|
|
weights = data.get('weights')
|
|
|
|
if not node_id or not weights:
|
|
return web.json_response({"error": "Missing node_id or weights"}, status=400)
|
|
|
|
print(f"[Radar Weights] API received update for node {node_id}: {weights}")
|
|
CURRENT_WEIGHTS[str(node_id)] = weights
|
|
print(f"[Radar Weights] Updated weights for node {node_id}: {weights}")
|
|
print(f"[Radar Weights] Current global state: {CURRENT_WEIGHTS}")
|
|
|
|
# Save weights to persistent storage
|
|
save_weights()
|
|
|
|
return web.json_response({
|
|
"status": "success",
|
|
"node_id": node_id,
|
|
"weights": weights
|
|
})
|
|
except Exception as e:
|
|
print(f"[Radar Weights] Error in update_weights_route: {str(e)}")
|
|
return web.json_response({"error": str(e)}, status=500)
|
|
|
|
# Add a route to get the current weights for a node
|
|
@PromptServer.instance.routes.get("/radar_weights/get_weights/{node_id}")
|
|
async def get_weights_route(request):
|
|
try:
|
|
node_id = request.match_info.get('node_id')
|
|
if not node_id:
|
|
return web.json_response({"error": "Missing node_id"}, status=400)
|
|
|
|
weights = CURRENT_WEIGHTS.get(str(node_id), "")
|
|
print(f"[Radar Weights] Retrieved weights for node {node_id}: {weights}")
|
|
|
|
return web.json_response({
|
|
"status": "success",
|
|
"node_id": node_id,
|
|
"weights": weights
|
|
})
|
|
except Exception as e:
|
|
print(f"[Radar Weights] Error in get_weights_route: {str(e)}")
|
|
return web.json_response({"error": str(e)}, status=500)
|
|
|
|
# Add a route to get the most recent weights
|
|
@PromptServer.instance.routes.get("/radar_weights/get_latest_weights")
|
|
async def get_latest_weights_route(request):
|
|
try:
|
|
if not CURRENT_WEIGHTS:
|
|
return web.json_response({
|
|
"status": "success",
|
|
"weights": ""
|
|
})
|
|
|
|
# Get the last key-value pair from the dictionary
|
|
last_node_id, last_weights = list(CURRENT_WEIGHTS.items())[-1]
|
|
print(f"[Radar Weights] Retrieved latest weights from node {last_node_id}: {last_weights}")
|
|
|
|
return web.json_response({
|
|
"status": "success",
|
|
"node_id": last_node_id,
|
|
"weights": last_weights
|
|
})
|
|
except Exception as e:
|
|
print(f"[Radar Weights] Error in get_latest_weights_route: {str(e)}")
|
|
return web.json_response({"error": str(e)}, status=500)
|
|
|
|
# Add a route to get all saved weights
|
|
@PromptServer.instance.routes.get("/radar_weights/get_all_weights")
|
|
async def get_all_weights_route(request):
|
|
try:
|
|
return web.json_response({
|
|
"status": "success",
|
|
"weights": CURRENT_WEIGHTS
|
|
})
|
|
except Exception as e:
|
|
print(f"[Radar Weights] Error in get_all_weights_route: {str(e)}")
|
|
return web.json_response({"error": str(e)}, status=500)
|
|
|
|
# It's good practice to update the NODE_CLASS_MAPPINGS if this file defines it
|
|
# Assuming it might be in __init__.py or similar, but adding here for completeness if stand-alone
|
|
NODE_CLASS_MAPPINGS = {
|
|
"RadarWeightsNode": RadarWeightsNode
|
|
}
|
|
|
|
# Optionally, update display name mapping
|
|
NODE_DISPLAY_NAME_MAPPINGS = {
|
|
"RadarWeightsNode": "Radar Weights Node"
|
|
}
|
|
|
|
# If web directory registration exists, update it (less common in single file nodes)
|
|
# WEB_DIRECTORY = "./js" |