Files
TashaSkyUp-EternalKernelPyt…/3d.py
T
Tasha Upchurch d9170f804b New Features: Added nodes for advanced video and audio processing
Key updates:

Added AddFramesToVideoFolder node to add frames to a video folder
Introduced VideoFolderProvider and VideoDefinitionProvider nodes to manage video folders and video definitions
Added FadeToInVideoFolder node for fading between frames in a video folder
Implemented ListedSVDConditioning node for applying SVD conditioning to a list of parameters
Added VideoFolderFFMPEGVideoInterpolate node to interpolate frames in a video folder using FFmpeg
Introduced AudioFolderProvider and AudioDefinitionProvider nodes for managing audio folders and definitions
Added AddAudioToAudioFolder and AddSilenceToAudioFolder nodes for adding audio files and silence to audio folders
Implemented GetAudioFilesLengthsFromAudioFolder node to retrieve lengths of audio files in a folder
Added AudioFolderRenderAudio node to join audio files in an audio folder
Introduced GenerateMusic node for generating music from descriptions using the AudioCraft library
Added XttsNode for text-to-speech conversion using the XTTS library
Implemented AdjustAudioVolumeForFiles node to adjust volume for a list of audio files
The changes also include the addition of LiteLLM nodes for text generation:

Added FuncAnysToText node that runs Python code with multiple input types and outputs a string
Introduced FuncAnysToLatent node for running code that outputs a latent representation
Added FuncAnysToString node for executing code with various inputs and producing a string output
Implemented FuncAnysToList node to run code that takes different input types and returns a list
Added FuncAnysToCond node for running code with multiple inputs and generating a conditioning output

These new nodes expand the capabilities for video and audio processing, allowing more advanced manipulations and generation of video and audio content within the graph.
2024-04-15 13:29:31 -04:00

160 lines
5.7 KiB
Python

NODE_CLASS_MAPPINGS = {}
NODE_DISPLAY_NAME_MAPPINGS = {}
def ETK_3d_base(cls):
import functools
cls.CATEGORY = "ETK/3d"
# Add spaces to the camel case class name
pretty_name = cls.__name__
for i in range(1, len(pretty_name)):
if pretty_name[i].isupper():
pretty_name = pretty_name[:i] + " " + pretty_name[i:]
cls.DISPLAY_NAME = pretty_name
NODE_CLASS_MAPPINGS[cls.__name__] = cls
NODE_DISPLAY_NAME_MAPPINGS[cls.DISPLAY_NAME] = pretty_name
return cls
@ETK_3d_base
class TripoSRNode:
def __init__(self):
import os
from folder_paths import output_directory
self.output_dir = output_directory
self.repo_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "repos", "img23d")
self.repo_url = "https://github.com/VAST-AI-Research/TripoSR.git"
self.venv_dir = os.path.join(self.repo_dir, "venv")
self.python_executable = os.path.join(self.venv_dir, "Scripts", "python")
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"image": ("IMAGE",),
"output_dir": ("STRING", {"default": "outputs/TripoSR"}),
"mc_resolution": ("INT", {"default": 256}),
}
}
RETURN_TYPES = ("STRING",)
FUNCTION = "generate_3d_models"
CATEGORY = "3D"
def generate_3d_models(self, image, output_dir=None, mc_resolution=256):
import asyncio
if output_dir is not None:
#self.output_dir = f"{self.output_dir}/{output_dir}"
self.final_out_dir = f"{self.output_dir}/{output_dir}"
# Create a new asyncio loop
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
# Run the async function within the loop
output_paths = loop.run_until_complete(self.async_generate_3d_models(image, mc_resolution))
return (output_paths,)
async def async_generate_3d_models(self, image, mc_resolution):
import os
import numpy as np
from PIL import Image
import asyncio
# Check if the TripoSR repository is installed
if not os.path.exists(self.repo_dir):
# Clone the repository if it doesn't exist
await self.clone_repository()
# Create a virtual environment and install requirements
await self.create_venv_and_install_requirements()
# Create a temporary directory for saving input images
temp_dir = "temp_images"
os.makedirs(temp_dir, exist_ok=True)
# Save each image in the batch as a separate file
# each image is a torch tensor with shape (b,h,w,c)
image_paths = []
for i in range(image.shape[0]):
image_np = image[i].cpu().numpy()
image_pil = Image.fromarray((image_np * 255).astype(np.uint8))
image_path = os.path.join(temp_dir, f"image_{i}.png")
image_pil.save(image_path)
image_paths.append(image_path)
# Run inference using the TripoSR CLI for each image simultaneously
output_paths = await asyncio.gather(*[self.run_inference(image_path,mc_resolution) for image_path in image_paths])
# Clean up the temporary image files
for image_path in image_paths:
os.remove(image_path)
return output_paths
async def run_inference(self, image_path, mc_resolution):
import asyncio
import os
# Create a virtual environment and install requirements if they don't exist
command = [
self.python_executable,
os.path.join(self.repo_dir, "run.py"),
image_path,
"--mc-resolution",
f"{mc_resolution}",
"--output-dir",
self.final_out_dir,
]
process = await asyncio.create_subprocess_exec(*command)
await process.wait()
output_path = self.get_output_path(image_path)
return output_path
async def clone_repository(self):
import asyncio
# Clone the TripoSR repository
command = ["git", "clone", self.repo_url, self.repo_dir]
process = await asyncio.create_subprocess_exec(*command)
await process.wait()
async def create_venv_and_install_requirements(self):
import asyncio
import os
# Create a virtual environment
command = ["python", "-m", "venv", self.venv_dir]
# use os to execute the command
os.system(" ".join(command))
# install pip "python -m ensurepip"
command = [self.python_executable, "-m", "ensurepip"]
os.system(" ".join(command))
# install wheel
command = [self.python_executable, "-m", "pip", "install", "wheel"]
os.system(" ".join(command))
# install torch
# TODO: detect what version of torch to install based on what is installed on system
command = [self.python_executable, "-m", "pip", "install", "torch",
"--index-url https://download.pytorch.org/whl/cu121"]
#command = [self.python_executable, "-m", "pip", "install", "torch",
# "--index-url https://download.pytorch.org/whl/cu118"]
os.system(" ".join(command))
# Install requirements
command = [self.python_executable, "-m", "pip", "install", "-r",
os.path.join(self.repo_dir, "requirements.txt")]
os.system(" ".join(command))
def get_output_path(self, image_path):
import os
# Extract the base name of the input image file
base_name = os.path.splitext(os.path.basename(image_path))[0]
# Construct the output path based on the base name and output directory
output_path = os.path.join(self.output_dir, base_name, "obj", "mesh_norm.obj")
return output_path