Files
AlekPet ee351ea6ba Inplemented select model form list
Support saves selected model in list when reloaded and loaded page
browser.
Write backend code get models in json format, and create file json default models for local server.
Add buttons refresh model list
2024-12-06 18:55:48 +03:00

238 lines
6.9 KiB
Python

import os
import PIL
from PIL import Image, ImageOps
import hashlib
import base64
from io import BytesIO
import torch
import numpy as np
import requests
import asyncio
from server import PromptServer
import time
from aiohttp import web
import folder_paths
import json
# Message Handling
# class MessageHolder:
# messages = {}
# @classmethod
# def addMessage(self, id, message):
# self.messages[str(id)] = message
# @classmethod
# def waitForMessage(self, id, period = 0.1):
# sid = str(id)
# while not (sid in self.messages):
# time.sleep(period)
# message = self.messages.pop(str(id),None)
# return message
# handle proxy response
# @PromptServer.instance.routes.post('/HYPE/proxy_reply')
# async def proxyHandle(request):
# post = await request.json()
# MessageHolder.addMessage(post["node_id"], post["outputs"])
# return web.json_response({"status": "ok"})
# Global variables
DEBUG = True
THREEVIEW_DICT = {} # ThreeView dict instances
# Directory threejs
extension_threejs = os.path.dirname(os.path.realpath(__file__))
# Support extension models
support_ext = ("glb",)
def getModelsInDir(folder, path):
list_models = []
for model in os.scandir(folder):
if not model.is_file():
continue
model_file_size = model.stat().st_size
if model_file_size == 0:
continue
model_file = model.name.split(".")
ext = model_file[-1]
if ext not in support_ext:
continue
pathFile = os.path.join(path, model.name)
# model_file_name = ".".join(model_file[:-1])
list_models.append({"name": model.name, "size": model_file_size, "path": pathFile})
return list_models
def createJsonFileStartup():
models_js_dir = os.path.join(extension_threejs, "js")
models_assets_dir = os.path.join(models_js_dir, "assets")
# Assets directory
if not os.path.exists(models_assets_dir):
return
models = {
"models": {
"default": getModelsInDir(models_assets_dir, "./assets/"),
}
}
saveFilePath = os.path.join(models_js_dir, "models_default.json")
with open(saveFilePath, "w+", encoding="utf-8") as file:
file.write(json.dumps(models, indent=4))
# Create on startup default models json file in assets directory
createJsonFileStartup()
@PromptServer.instance.routes.get("/lth/models")
async def getModels(request):
try:
models_assets_dir = os.path.join(extension_threejs, "js", "assets")
models_input_dir = os.path.join(folder_paths.get_input_directory(), "ThreeViewModels")
models = {
"default": [],
"loaded": []
}
# Assets directory
if os.path.exists(models_assets_dir):
models["default"] = getModelsInDir(models_assets_dir, "assets/")
else:
print(f"ThreeView: Path {models_assets_dir} not exists!")
# Input > ThreeViewModels directory
if os.path.exists(models_input_dir):
models["loaded"] = getModelsInDir(models_input_dir, "ThreeViewModels/")
else:
print(f"ThreeView: Path {models_input_dir} not exists!")
return web.json_response({"status":"ok", "models": models}, status=200)
except Exception as err:
print("ThreeView: Get models error", err)
return web.json_response({"status":"error"}, status=500)
@PromptServer.instance.routes.get("/api/lth/")
async def indexPage(request):
pathIndex = os.path.join(extension_threejs, "js", "index.html")
response = web.FileResponse(pathIndex)
response.headers['Cache-Control'] = 'no-cache'
response.headers["Pragma"] = "no-cache"
response.headers["Expires"] = "0"
return response
@PromptServer.instance.routes.post("/lth/save_complete")
async def checkSaveImage(request):
json_data = await request.json()
unique_id = json_data.get("unique_id", None)
if unique_id is not None and unique_id in THREEVIEW_DICT:
THREEVIEW_DICT[unique_id] = True
return web.json_response({"status": "Complete"}, status=200)
return web.json_response({"status": "Error invalid unique_id"}, status=400)
def waitSaveImage(unique_id, time_out=100):
for _ in range(time_out):
if (THREEVIEW_DICT.get(unique_id, False) == True):
THREEVIEW_DICT[unique_id] = False
if DEBUG:
print(f"File for ThreeView{unique_id} is ready")
return True
time.sleep(0.1)
if DEBUG:
print(f"Timeout waiting for ThreeView{unique_id}")
return False
class ThreeView:
savedimage = False
@classmethod
def INPUT_TYPES(self):
return {
"required": {
"imageThreejs": ("STRING", {"default":"theejs_image.png,theejs_image_lines.png,theejs_image_depth.png,theejs_image_normal.png"},)
},
"hidden": { "unique_id":"UNIQUE_ID" }
}
@classmethod
def IS_CHANGED(self, imageThreejs, unique_id):
if unique_id not in THREEVIEW_DICT:
THREEVIEW_DICT[unique_id] = False
THREEVIEW_DICT[unique_id] = False
# Send to save image
PromptServer.instance.send_sync("lth_save_image", {"unique_id": unique_id})
waitSaveImage(unique_id)
return float("NaN") #m.digest().hex()
RETURN_TYPES = ("IMAGE", "IMAGE", "IMAGE", "IMAGE")
RETURN_NAMES = ("image", "lines", "depth", "normal")
FUNCTION = "process_three_js_image"
CATEGORY = "lth"
def process_three_js_image(self, imageThreejs, unique_id):
imageThreejs = imageThreejs.split(",")
images_make = []
for imageName in imageThreejs:
pathImage = folder_paths.get_annotated_filepath(imageName)
for _ in range(5):
if os.path.exists(pathImage) and os.path.getsize(pathImage) > 0:
try:
with Image.open(pathImage) as i:
i = ImageOps.exif_transpose(i)
image = i.convert("RGB")
image = np.array(image).astype(np.float32) / 255.0
image = torch.from_numpy(image)[None,]
images_make.append(image)
break
except (OSError, SyntaxError, PIL.UnidentifiedImageError) as e:
if DEBUG:
print(f"Error reading image {imageName}: {e}. Retrying...")
else:
if DEBUG:
print(f"File {imageName} not ready. Waiting...")
time.sleep(0.5)
else:
if DEBUG:
print(f"Failed to process {imageName} after multiple attempts.")
images_make.append(None)
return tuple(images_make)
NODE_CLASS_MAPPINGS = {
"ThreeView": ThreeView
}
NODE_DISPLAY_NAME_MAPPINGS = {
"ThreeView": "Three View"
}