From c02dfdb5dcf185c24721e1d49fc9b5aa487bf0d0 Mon Sep 17 00:00:00 2001 From: BobRandomNumber Date: Mon, 28 Apr 2025 03:26:53 -0400 Subject: [PATCH 1/5] Use .safetensor model Rework to use available safetensor model and remove huggingface downloads --- README.md | 66 +++++--- __init__.py | 6 +- dia_lib/model.py | 421 +++++++++++++---------------------------------- nodes.py | 317 ++++++++++++++++++----------------- requirements.txt | 7 +- 5 files changed, 324 insertions(+), 493 deletions(-) diff --git a/README.md b/README.md index 9ec2b11..7abcadc 100644 --- a/README.md +++ b/README.md @@ -1,43 +1,57 @@ # ComfyUI DiaTest TTS Node -Warning LLM Code there are probably better options +This node pack integrates the [Nari Labs Dia](https://github.com/nari-labs/dia) text-to-speech model into ComfyUI using separate nodes for loading the model from a local file and generating audio. -This node pack partially integrates the [Nari Labs Dia](https://github.com/nari-labs/dia) text-to-speech model into ComfyUI using a single node for loading (onto GPU) and generation. -This is only text input, no audio input. +Dia allows generating dialogue with speaker tags (`[S1]`, `[S2]`) and non-verbal sounds (`(laughs)`, etc.). This node pack loads the model from a local `.safetensors` file onto the GPU and generates audio. It **requires a CUDA-enabled GPU**. -Dia allows generating dialogue with speaker tags (`[S1]`, `[S2]`) and non-verbal sounds (`(laughs)`, etc.). This node loads the model from Hugging Face Hub and generates audio directly using float32 precision. It requires a CUDA-enabled GPU. +**Note:** This version is specifically configured for the `nari-labs/Dia-1.6B` model architecture. ## Installation 1. Ensure you have a CUDA-enabled GPU and the necessary NVIDIA drivers installed. -2. Navigate to your `ComfyUI/custom_nodes/` directory. -3. Clone this repository: +2. Download the Dia-1.6B model weights file (`dia-1.6B.safetensors`) from Hugging Face Hub: + * **Direct Download URL:** [https://huggingface.co/nari-labs/Dia-1.6B/resolve/main/dia-1.6B.safetensors](https://huggingface.co/nari-labs/Dia-1.6B/resolve/main/dia-1.6B.safetensors) +3. Place the downloaded `.safetensors` file into one of the directories ComfyUI recognizes for `diffusion_models` (e.g., `ComfyUI/models/diffusion_models/`). You might want to rename it to `Dia-1.6B.safetensors` for clarity. +4. Navigate to your `ComfyUI/custom_nodes/` directory. +5. Clone this repository: ```bash git clone https://github.com/BobRandomNumber/ComfyUI-DiaTest.git ``` Alternatively, download the ZIP and extract it into `custom_nodes`. -4. Install the required dependencies: +6. Install the required dependencies: * Activate ComfyUI's Python environment (e.g., `source ./venv/bin/activate`). * Navigate to the node directory: `cd ComfyUI/custom_nodes/ComfyUI-DiaTest` * Install requirements: `pip install -r requirements.txt` -5. Restart ComfyUI. +7. Restart ComfyUI. -## Node +## Nodes -### Dia TTS Generate (`DiaGenerate`) +### Dia 1.6b Loader (`DiaLoader`) -Loads the specified Dia model from Hugging Face Hub onto the GPU (if not already cached) and generates audio based on the provided text and parameters. Uses float32 precision internally. Requires CUDA. +Loads the Dia-1.6B TTS model from a local `.safetensors` checkpoint file located in one of your configured `diffusion_models` directories. Loads the model weights and the required DAC codec onto the GPU using the embedded Dia-1.6B configuration. **Inputs:** -* `repo_id`: The Hugging Face repository ID (default: `nari-labs/Dia-1.6B`). +* `ckpt_name`: Dropdown list of found `.safetensors` files within your `diffusion_models` directories. Select the file corresponding to the Dia-1.6B model. + +**Outputs:** + +* `dia_model`: A custom `DIA_MODEL` object containing the loaded Dia model instance, ready for the `DiaGenerate` node. + +### Dia TTS Generate (`DiaGenerate`) + +Generates audio using a pre-loaded Dia model provided by the `DiaLoader` node. Displays a progress bar during generation. + +**Inputs:** + +* `dia_model`: The `DIA_MODEL` output from the `DiaLoader` node. * `text`: The main text transcript to generate audio for. Use `[S1]`, `[S2]` for speaker turns and parentheses for non-verbals like `(laughs)`. * `max_tokens`: Maximum number of audio tokens to generate (controls length). -* `cfg_scale`: Classifier-Free Guidance scale (higher means stronger adherence to text). -* `temperature`: Sampling temperature (higher means more randomness). +* `cfg_scale`: Classifier-Free Guidance scale. +* `temperature`: Sampling temperature. * `top_p`: Nucleus sampling probability. * `cfg_filter_top_k`: Top-K filtering applied during CFG. -* `speed_factor`: Adjusts the speed of the generated audio (1.0 = original speed, <1.0 = slower, >1.0 = faster). Default: 0.94. +* `speed_factor`: Adjusts the speed of the generated audio (1.0 = original speed). * `seed`: Random seed for reproducibility. **Outputs:** @@ -46,15 +60,19 @@ Loads the specified Dia model from Hugging Face Hub onto the GPU (if not already ## Usage Example -1. Add the `Dia TTS Generate` node from the `audio/DiaTest` category. -2. Enter your dialogue script into the `text` input. -3. Adjust generation parameters (`cfg_scale`, `temperature`, `speed_factor`, etc.) as needed. -4. Connect the `audio` output to a `SaveAudio` or `PreviewAudio` node. -5. Queue the prompt. +1. Download `dia-1.6B.safetensors` and place it in a `diffusion_models` directory (e.g., `ComfyUI/models/diffusion_models/`). +2. Add the `Dia 1.6b Loader` node from the `audio/DiaTest` category. +3. Select your Dia model file (e.g., `dia-1.6B.safetensors`) from the `ckpt_name` dropdown. +4. Add the `Dia TTS Generate` node (also from `audio/DiaTest`). +5. Connect the `dia_model` output of the Loader node to the `dia_model` input of the Generate node. +6. Enter your dialogue script into the `text` input on the Generate node. +7. Adjust generation parameters on the Generate node as needed. +8. Connect the `audio` output of the Generate node to a `SaveAudio` or `PreviewAudio` node. +9. Queue the prompt. ## Notes -* This node **requires a CUDA-enabled GPU**. It will fail to load if CUDA is not detected. -* The first time you run the node it will download the model files from Hugging Face Hub, which may take some time. Subsequent runs will use the cached model. -* The model uses float32 precision internally. -* The Descript Audio Codec (DAC) dependency (`descript-audio-codec`) must be installed via `requirements.txt`. +* This node pack **requires a CUDA-enabled GPU**. +* Only the `.safetensors` weights file is required. +* The first time you load a specific model with the `DiaLoader`, it loads the weights and the required DAC codec. Subsequent runs using the same loader node will use the cached model object. Switching models in the loader clears the cache. +* Dependencies `descript-audio-codec`, `huggingface_hub`, and `safetensors` must be installed via `requirements.txt`. \ No newline at end of file diff --git a/__init__.py b/__init__.py index ff089ba..d097698 100644 --- a/__init__.py +++ b/__init__.py @@ -1,9 +1,5 @@ # ComfyUI-DiaTest/__init__.py -# Import the final mappings from nodes.py from .nodes import NODE_CLASS_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS -# Expose them for ComfyUI -__all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS'] - -print("### Loading: ComfyUI-DiaTest Nodes ###") \ No newline at end of file +__all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS'] \ No newline at end of file diff --git a/dia_lib/model.py b/dia_lib/model.py index aa1fa7b..128da92 100644 --- a/dia_lib/model.py +++ b/dia_lib/model.py @@ -1,3 +1,5 @@ +# ComfyUI-DiaTest/dia_lib/model.py + import time from enum import Enum @@ -6,37 +8,32 @@ import numpy as np import torch import torchaudio from huggingface_hub import hf_hub_download +from tqdm.auto import tqdm # Import tqdm for command-line progress from .audio import apply_audio_delay, build_delay_indices, build_revert_indices, decode, revert_audio_delay from .config import DiaConfig from .layers import DiaModel from .state import DecoderInferenceState, DecoderOutput, EncoderInferenceState - DEFAULT_SAMPLE_RATE = 44100 def _get_default_device(): - if torch.cuda.is_available(): - return torch.device("cuda") - elif hasattr(torch.backends, "mps") and torch.backends.mps.is_available(): - return torch.device("mps") + """Gets the default torch device.""" + if torch.cuda.is_available(): return torch.device("cuda") + if hasattr(torch.backends, "mps") and torch.backends.mps.is_available(): return torch.device("mps") return torch.device("cpu") -def _sample_next_token( - logits_BCxV: torch.Tensor, - temperature: float, - top_p: float, - cfg_filter_top_k: int | None = None, -) -> torch.Tensor: - if temperature == 0.0: - return torch.argmax(logits_BCxV, dim=-1) +def _sample_next_token(logits_BCxV, temperature, top_p, cfg_filter_top_k=None) -> torch.Tensor: + """Samples the next token based on logits, temperature, and top_p.""" + exec_device = logits_BCxV.device + if temperature == 0.0: return torch.argmax(logits_BCxV, dim=-1) logits_BCxV = logits_BCxV / temperature if cfg_filter_top_k is not None: _, top_k_indices_BCxV = torch.topk(logits_BCxV, k=cfg_filter_top_k, dim=-1) - mask = torch.ones_like(logits_BCxV, dtype=torch.bool) + mask = torch.ones_like(logits_BCxV, dtype=torch.bool, device=exec_device) mask.scatter_(dim=-1, index=top_k_indices_BCxV, value=False) logits_BCxV = logits_BCxV.masked_fill(mask, -torch.inf) @@ -44,404 +41,214 @@ def _sample_next_token( probs_BCxV = torch.softmax(logits_BCxV, dim=-1) sorted_probs_BCxV, sorted_indices_BCxV = torch.sort(probs_BCxV, dim=-1, descending=True) cumulative_probs_BCxV = torch.cumsum(sorted_probs_BCxV, dim=-1) - sorted_indices_to_remove_BCxV = cumulative_probs_BCxV > top_p sorted_indices_to_remove_BCxV[..., 1:] = sorted_indices_to_remove_BCxV[..., :-1].clone() sorted_indices_to_remove_BCxV[..., 0] = 0 - - indices_to_remove_BCxV = torch.zeros_like(sorted_indices_to_remove_BCxV) + indices_to_remove_BCxV = torch.zeros_like(sorted_indices_to_remove_BCxV, device=exec_device) indices_to_remove_BCxV.scatter_(dim=-1, index=sorted_indices_BCxV, src=sorted_indices_to_remove_BCxV) logits_BCxV = logits_BCxV.masked_fill(indices_to_remove_BCxV, -torch.inf) final_probs_BCxV = torch.softmax(logits_BCxV, dim=-1) - sampled_indices_BC = torch.multinomial(final_probs_BCxV, num_samples=1) - sampled_indices_C = sampled_indices_BC.squeeze(-1) - return sampled_indices_C + return sampled_indices_BC.squeeze(-1) class ComputeDtype(str, Enum): - FLOAT32 = "float32" - FLOAT16 = "float16" - BFLOAT16 = "bfloat16" - + """Enum for compute dtypes.""" + FLOAT32 = "float32"; FLOAT16 = "float16"; BFLOAT16 = "bfloat16" def to_dtype(self) -> torch.dtype: - if self == ComputeDtype.FLOAT32: - return torch.float32 - elif self == ComputeDtype.FLOAT16: - return torch.float16 - elif self == ComputeDtype.BFLOAT16: - return torch.bfloat16 - else: - raise ValueError(f"Unsupported compute dtype: {self}") + """Converts enum value to torch.dtype.""" + return getattr(torch, self.value) class Dia: - def __init__( - self, - config: DiaConfig, - compute_dtype: str | ComputeDtype = ComputeDtype.FLOAT32, - device: torch.device | None = None, - ): - """Initializes the Dia model. - - Args: - config: The configuration object for the model. - device: The device to load the model onto. If None, will automatically select the best available device. - - Raises: - RuntimeError: If there is an error loading the DAC model. - """ + """Main class for Dia TTS model loading and generation.""" + def __init__(self, config: DiaConfig, compute_dtype=ComputeDtype.FLOAT32, device=None): + """Initializes the Dia model, ensuring placement on the specified device.""" super().__init__() self.config = config self.device = device if device is not None else _get_default_device() - if isinstance(compute_dtype, str): - compute_dtype = ComputeDtype(compute_dtype) + if isinstance(compute_dtype, str): compute_dtype = ComputeDtype(compute_dtype) self.compute_dtype = compute_dtype.to_dtype() self.model = DiaModel(config, self.compute_dtype) + self.model.to(self.device) self.dac_model = None - @classmethod - def from_local( - cls, - config_path: str, - checkpoint_path: str, - compute_dtype: str | ComputeDtype = ComputeDtype.FLOAT32, - device: torch.device | None = None, - ) -> "Dia": - """Loads the Dia model from local configuration and checkpoint files. - - Args: - config_path: Path to the configuration JSON file. - checkpoint_path: Path to the model checkpoint (.pth) file. - device: The device to load the model onto. If None, will automatically select the best available device. - - Returns: - An instance of the Dia model loaded with weights and set to eval mode. - - Raises: - FileNotFoundError: If the config or checkpoint file is not found. - RuntimeError: If there is an error loading the checkpoint. - """ - config = DiaConfig.load(config_path) - if config is None: - raise FileNotFoundError(f"Config file not found at {config_path}") - - dia = cls(config, compute_dtype, device) - - try: - state_dict = torch.load(checkpoint_path, map_location=dia.device) - dia.model.load_state_dict(state_dict) - except FileNotFoundError: - raise FileNotFoundError(f"Checkpoint file not found at {checkpoint_path}") - except Exception as e: - raise RuntimeError(f"Error loading checkpoint from {checkpoint_path}") from e - - dia.model.to(dia.device) - dia.model.eval() - dia._load_dac_model() - return dia - - @classmethod - def from_pretrained( - cls, - model_name: str = "nari-labs/Dia-1.6B", - compute_dtype: str | ComputeDtype = ComputeDtype.FLOAT32, - device: torch.device | None = None, - ) -> "Dia": - """Loads the Dia model from a Hugging Face Hub repository. - - Downloads the configuration and checkpoint files from the specified - repository ID and then loads the model. - - Args: - model_name: The Hugging Face Hub repository ID (e.g., "NariLabs/Dia-1.6B"). - device: The device to load the model onto. If None, will automatically select the best available device. - - Returns: - An instance of the Dia model loaded with weights and set to eval mode. - - Raises: - FileNotFoundError: If config or checkpoint download/loading fails. - RuntimeError: If there is an error loading the checkpoint. - """ - config_path = hf_hub_download(repo_id=model_name, filename="config.json") - checkpoint_path = hf_hub_download(repo_id=model_name, filename="dia-v0_1.pth") - return cls.from_local(config_path, checkpoint_path, compute_dtype, device) + def _devices_equal(self, device1: torch.device, device2: torch.device) -> bool: + """Robustly compares two torch.device objects.""" + if device1.type != device2.type: return False + if device1.type == 'cuda': + index1 = device1.index if device1.index is not None else 0 + index2 = device2.index if device2.index is not None else 0 + return index1 == index2 + return True def _load_dac_model(self): + """Loads the Descript Audio Codec model to the instance's device.""" + if self.dac_model is not None: + if not self._devices_equal(self.dac_model.device, self.device): + self.dac_model.to(self.device) + return try: + print(f"Loading DAC model to {self.device}...") dac_model_path = dac.utils.download() - dac_model = dac.DAC.load(dac_model_path).to(self.device) + self.dac_model = dac.DAC.load(dac_model_path).to(self.device) + self.dac_model.eval() + print(f"DAC model loaded successfully on {self.dac_model.device}.") except Exception as e: + self.dac_model = None raise RuntimeError("Failed to load DAC model") from e - self.dac_model = dac_model def _prepare_text_input(self, text: str) -> torch.Tensor: - """Encodes text prompt, pads, and creates attention mask and positions.""" - text_pad_value = self.config.data.text_pad_value - max_len = self.config.data.text_length - + """Encodes text prompt, pads, and creates tensor on the model's device.""" + text_pad_value = self.config.data.text_pad_value; max_len = self.config.data.text_length byte_text = text.encode("utf-8") replaced_bytes = byte_text.replace(b"[S1]", b"\x01").replace(b"[S2]", b"\x02") text_tokens = list(replaced_bytes) - current_len = len(text_tokens) padding_needed = max_len - current_len if padding_needed <= 0: text_tokens = text_tokens[:max_len] padded_text_np = np.array(text_tokens, dtype=np.uint8) else: - padded_text_np = np.pad( - text_tokens, - (0, padding_needed), - mode="constant", - constant_values=text_pad_value, - ).astype(np.uint8) - - src_tokens = torch.from_numpy(padded_text_np).to(torch.long).to(self.device).unsqueeze(0) # [1, S] - return src_tokens + padded_text_np = np.pad(text_tokens, (0, padding_needed), 'constant', constant_values=text_pad_value).astype(np.uint8) + return torch.from_numpy(padded_text_np).to(dtype=torch.long, device=self.device).unsqueeze(0) def _prepare_audio_prompt(self, audio_prompt: torch.Tensor | None) -> tuple[torch.Tensor, int]: - num_channels = self.config.data.channels - audio_bos_value = self.config.data.audio_bos_value - audio_pad_value = self.config.data.audio_pad_value - delay_pattern = self.config.data.delay_pattern + """Prepares the initial audio tokens (BOS and optional prompt) on the model's device.""" + num_channels = self.config.data.channels; audio_bos_value = self.config.data.audio_bos_value + audio_pad_value = self.config.data.audio_pad_value; delay_pattern = self.config.data.delay_pattern max_delay_pattern = max(delay_pattern) - - prefill = torch.full( - (1, num_channels), - fill_value=audio_bos_value, - dtype=torch.int, - device=self.device, - ) - + prefill = torch.full((1, num_channels), fill_value=audio_bos_value, dtype=torch.int, device=self.device) prefill_step = 1 - if audio_prompt is not None: + audio_prompt = audio_prompt.to(self.device) prefill_step += audio_prompt.shape[0] prefill = torch.cat([prefill, audio_prompt], dim=0) - - delay_pad_tensor = torch.full( - (max_delay_pattern, num_channels), fill_value=-1, dtype=torch.int, device=self.device - ) + delay_pad_tensor = torch.full((max_delay_pattern, num_channels), fill_value=-1, dtype=torch.int, device=self.device) prefill = torch.cat([prefill, delay_pad_tensor], dim=0) - - delay_precomp = build_delay_indices( - B=1, - T=prefill.shape[0], - C=num_channels, - delay_pattern=delay_pattern, - ) - - prefill = apply_audio_delay( - audio_BxTxC=prefill.unsqueeze(0), - pad_value=audio_pad_value, - bos_value=audio_bos_value, - precomp=delay_precomp, - ).squeeze(0) - + delay_precomp = build_delay_indices(B=1, T=prefill.shape[0], C=num_channels, delay_pattern=delay_pattern) + prefill = apply_audio_delay(prefill.unsqueeze(0), audio_pad_value, audio_bos_value, delay_precomp).squeeze(0) return prefill, prefill_step def _prepare_generation(self, text: str, audio_prompt: str | torch.Tensor | None, verbose: bool): + """Prepares encoder/decoder states and initial inputs, ensuring device consistency.""" + param_device = next(self.model.parameters()).device + if not self._devices_equal(param_device, self.device): + raise RuntimeError(f"Model parameters on {param_device}, expected {self.device}. Device move failed?") enc_input_cond = self._prepare_text_input(text) enc_input_uncond = torch.zeros_like(enc_input_cond) enc_input = torch.cat([enc_input_uncond, enc_input_cond], dim=0) - - if isinstance(audio_prompt, str): - audio_prompt = self.load_audio(audio_prompt) + if isinstance(audio_prompt, str): audio_prompt = self.load_audio(audio_prompt) prefill, prefill_step = self._prepare_audio_prompt(audio_prompt) - - if verbose: - print("generate: data loaded") - enc_state = EncoderInferenceState.new(self.config, enc_input_cond) encoder_out = self.model.encoder(enc_input, enc_state) - dec_cross_attn_cache = self.model.decoder.precompute_cross_attn_cache(encoder_out, enc_state.positions) - dec_state = DecoderInferenceState.new( - self.config, enc_state, encoder_out, dec_cross_attn_cache, self.compute_dtype - ) + dec_state = DecoderInferenceState.new(self.config, enc_state, encoder_out, dec_cross_attn_cache, self.compute_dtype) dec_output = DecoderOutput.new(self.config, self.device) dec_output.prefill(prefill, prefill_step) - dec_step = prefill_step - 1 if dec_step > 0: dec_state.prepare_step(0, dec_step) tokens_BxTxC = dec_output.get_tokens_at(0, dec_step).unsqueeze(0).expand(2, -1, -1) self.model.decoder.forward(tokens_BxTxC, dec_state) - return dec_state, dec_output - def _decoder_step( - self, - tokens_Bx1xC: torch.Tensor, - dec_state: DecoderInferenceState, - cfg_scale: float, - temperature: float, - top_p: float, - cfg_filter_top_k: int, - ) -> torch.Tensor: + def _decoder_step(self, tokens_Bx1xC, dec_state, cfg_scale, temperature, top_p, cfg_filter_top_k) -> torch.Tensor: + """Performs a single autoregressive decoding step.""" audio_eos_value = self.config.data.audio_eos_value logits_Bx1xCxV = self.model.decoder.decode_step(tokens_Bx1xC, dec_state) - - logits_last_BxCxV = logits_Bx1xCxV[:, -1, :, :] - uncond_logits_CxV = logits_last_BxCxV[0, :, :] - cond_logits_CxV = logits_last_BxCxV[1, :, :] - + logits_last_BxCxV = logits_Bx1xCxV[:, -1, :, :]; uncond_logits_CxV = logits_last_BxCxV[0, :, :]; cond_logits_CxV = logits_last_BxCxV[1, :, :] logits_CxV = cond_logits_CxV + cfg_scale * (cond_logits_CxV - uncond_logits_CxV) - logits_CxV[:, audio_eos_value + 1 :] = -torch.inf - logits_CxV[1:, audio_eos_value:] = -torch.inf - - pred_C = _sample_next_token( - logits_CxV.float(), - temperature=temperature, - top_p=top_p, - cfg_filter_top_k=cfg_filter_top_k, - ) - return pred_C + logits_CxV[:, audio_eos_value + 1 :] = -torch.inf; logits_CxV[1:, audio_eos_value:] = -torch.inf + return _sample_next_token(logits_CxV.float(), temperature, top_p, cfg_filter_top_k) def _generate_output(self, generated_codes: torch.Tensor) -> np.ndarray: - num_channels = self.config.data.channels - seq_length = generated_codes.shape[0] - delay_pattern = self.config.data.delay_pattern - audio_pad_value = self.config.data.audio_pad_value + """Reverts delay pattern and decodes audio codes using DAC.""" + if self.dac_model is None: self._load_dac_model() + if not self._devices_equal(self.dac_model.device, self.device): self.dac_model.to(self.device) + num_channels = self.config.data.channels; seq_length = generated_codes.shape[0] + delay_pattern = self.config.data.delay_pattern; audio_pad_value = self.config.data.audio_pad_value max_delay_pattern = max(delay_pattern) - - revert_precomp = build_revert_indices( - B=1, - T=seq_length, - C=num_channels, - delay_pattern=delay_pattern, - ) - - codebook = revert_audio_delay( - audio_BxTxC=generated_codes.unsqueeze(0), - pad_value=audio_pad_value, - precomp=revert_precomp, - T=seq_length, - )[:, :-max_delay_pattern, :] - - min_valid_index = 0 - max_valid_index = 1023 + revert_precomp = build_revert_indices(B=1, T=seq_length, C=num_channels, delay_pattern=delay_pattern) + codebook = revert_audio_delay(generated_codes.unsqueeze(0), audio_pad_value, revert_precomp, seq_length)[:, :-max_delay_pattern, :] + min_valid_index = 0; max_valid_index = 1023 invalid_mask = (codebook < min_valid_index) | (codebook > max_valid_index) codebook[invalid_mask] = 0 - audio = decode(self.dac_model, codebook.transpose(1, 2)) - return audio.squeeze().cpu().numpy() def load_audio(self, audio_path: str) -> torch.Tensor: - audio, sr = torchaudio.load(audio_path, channels_first=True) # C, T - if sr != DEFAULT_SAMPLE_RATE: - audio = torchaudio.functional.resample(audio, sr, DEFAULT_SAMPLE_RATE) - audio = audio.to(self.device).unsqueeze(0) # 1, C, T + """Loads and preprocesses audio prompt file.""" + if self.dac_model is None: self._load_dac_model() + if not self._devices_equal(self.dac_model.device, self.device): self.dac_model.to(self.device) + audio, sr = torchaudio.load(audio_path, channels_first=True) + if sr != DEFAULT_SAMPLE_RATE: audio = torchaudio.functional.resample(audio, sr, DEFAULT_SAMPLE_RATE) + audio = audio.to(self.device).unsqueeze(0) audio_data = self.dac_model.preprocess(audio, DEFAULT_SAMPLE_RATE) - _, encoded_frame, _, _, _ = self.dac_model.encode(audio_data) # 1, C, T - return encoded_frame.squeeze(0).transpose(0, 1) - - def save_audio(self, path: str, audio: np.ndarray): - import soundfile as sf - - sf.write(path, audio, DEFAULT_SAMPLE_RATE) + _, encoded_frame, _, _, _ = self.dac_model.encode(audio_data) + return encoded_frame.squeeze(0).transpose(0, 1).to(self.device) @torch.inference_mode() - def generate( - self, - text: str, - max_tokens: int | None = None, - cfg_scale: float = 3.0, - temperature: float = 1.3, - top_p: float = 0.95, - use_torch_compile: bool = False, - cfg_filter_top_k: int = 35, - audio_prompt: str | torch.Tensor | None = None, - audio_prompt_path: str | None = None, - use_cfg_filter: bool | None = None, - verbose: bool = False, - ) -> np.ndarray: - audio_eos_value = self.config.data.audio_eos_value - audio_pad_value = self.config.data.audio_pad_value + def generate(self, text: str, max_tokens=None, cfg_scale=3.0, temperature=1.3, top_p=0.95, + use_torch_compile=False, cfg_filter_top_k=35, audio_prompt=None, verbose=False, + pbar=None, # ComfyUI progress bar object + **kwargs) -> np.ndarray | None: + """Generates audio waveform from text input, updating progress bars.""" + if 'audio_prompt_path' in kwargs: audio_prompt = kwargs['audio_prompt_path'] + audio_eos_value = self.config.data.audio_eos_value; audio_pad_value = self.config.data.audio_pad_value delay_pattern = self.config.data.delay_pattern - max_tokens = self.config.data.audio_length if max_tokens is None else max_tokens + clamped_max_tokens = self.config.data.audio_length if max_tokens is None else min(max_tokens, self.config.data.audio_length) max_delay_pattern = max(delay_pattern) self.model.eval() - if audio_prompt_path: - print("Warning: audio_prompt_path is deprecated. Use audio_prompt instead.") - audio_prompt = audio_prompt_path - if use_cfg_filter is not None: - print("Warning: use_cfg_filter is deprecated.") - - if verbose: - total_start_time = time.time() - dec_state, dec_output = self._prepare_generation(text, audio_prompt, verbose) dec_step = dec_output.prefill_step - 1 - bos_countdown = max_delay_pattern - eos_detected = False - eos_countdown = -1 - - if use_torch_compile: - step_fn = torch.compile(self._decoder_step, mode="default") - else: - step_fn = self._decoder_step + bos_countdown = max_delay_pattern; eos_detected = False; eos_countdown = -1 + step_fn = torch.compile(self._decoder_step, mode="default") if use_torch_compile else self._decoder_step + # --- Setup Command Line Progress Bar (only if verbose) --- + tqdm_pbar = None if verbose: - print("generate: starting generation loop") - if use_torch_compile: - print("generate: by using use_torch_compile=True, the first step would take long") - start_time = time.time() + tqdm_pbar = tqdm(total=clamped_max_tokens, desc="Dia Generating Tokens", unit="token") + # If there was a prefill step, update tqdm to reflect that progress + if dec_step >= 0: + tqdm_pbar.update(dec_step + 1) # +1 because dec_step is 0-indexed - while dec_step < max_tokens: + # --- Generation Loop --- + while dec_step < clamped_max_tokens: dec_state.prepare_step(dec_step) tokens_Bx1xC = dec_output.get_tokens_at(dec_step).unsqueeze(0).expand(2, -1, -1) - pred_C = step_fn( - tokens_Bx1xC, - dec_state, - cfg_scale, - temperature, - top_p, - cfg_filter_top_k, - ) - - if (not eos_detected and pred_C[0] == audio_eos_value) or dec_step == max_tokens - max_delay_pattern - 1: - eos_detected = True - eos_countdown = max_delay_pattern + pred_C = step_fn(tokens_Bx1xC, dec_state, cfg_scale, temperature, top_p, cfg_filter_top_k) + # EOS handling + if (not eos_detected and pred_C[0] == audio_eos_value) or dec_step == clamped_max_tokens - max_delay_pattern - 1: + eos_detected = True; eos_countdown = max_delay_pattern if eos_countdown > 0: step_after_eos = max_delay_pattern - eos_countdown for i, d in enumerate(delay_pattern): - if step_after_eos == d: - pred_C[i] = audio_eos_value - elif step_after_eos > d: - pred_C[i] = audio_pad_value + if step_after_eos == d: pred_C[i] = audio_eos_value + elif step_after_eos > d: pred_C[i] = audio_pad_value eos_countdown -= 1 bos_countdown = max(0, bos_countdown - 1) dec_output.update_one(pred_C, dec_step + 1, bos_countdown > 0) - - if eos_countdown == 0: - break + if eos_countdown == 0: break dec_step += 1 - if verbose and dec_step % 86 == 0: - duration = time.time() - start_time - print( - f"generate step {dec_step}: speed={86 / duration:.3f} tokens/s, realtime factor={1 / duration:.3f}x" - ) - start_time = time.time() + # --- Update Progress Bars --- + if pbar: pbar.update(1) # ComfyUI Web UI bar + if tqdm_pbar: tqdm_pbar.update(1) # Command Line bar + + # --- Cleanup Command Line Bar --- + if tqdm_pbar: tqdm_pbar.close() + + # --- Post-generation --- if dec_output.prefill_step >= dec_step + 1: - print("Warning: Nothing generated") + print("Dia: Warning - Nothing generated beyond prefill/prompt.") return None - generated_codes = dec_output.generated_tokens[dec_output.prefill_step : dec_step + 1, :] - if verbose: - total_step = dec_step + 1 - dec_output.prefill_step - total_duration = time.time() - total_start_time - print(f"generate: total step={total_step}, total duration={total_duration:.3f}s") - - return self._generate_output(generated_codes) + return self._generate_output(generated_codes) \ No newline at end of file diff --git a/nodes.py b/nodes.py index ae05046..dbfa578 100644 --- a/nodes.py +++ b/nodes.py @@ -4,21 +4,30 @@ import os import torch import numpy as np import folder_paths -import torchaudio # Kept for potential internal use by dia_lib -from huggingface_hub import hf_hub_download import traceback import gc +from safetensors.torch import load_file as load_safetensors_file +import comfy.utils # --- Import Dia library components --- try: from .dia_lib.model import Dia, ComputeDtype, DEFAULT_SAMPLE_RATE from .dia_lib.config import DiaConfig + from .dia_lib.state import EncoderInferenceState, DecoderInferenceState, DecoderOutput except ImportError as e: print("ComfyUI-DiaTest: Error importing Dia library components.") print(f"Ensure the 'dia_lib' folder exists in '{os.path.dirname(__file__)}'.") print(f"Import error: {e}") raise e -# --- End Dia library imports --- + +# --- Hardcoded Config for Dia-1.6B --- +DEFAULT_DIA_1_6B_CONFIG = { + "data": { "audio_bos_value": 1026, "audio_eos_value": 1024, "audio_length": 3072, "audio_pad_value": 1025, "channels": 9, "delay_pattern": [0, 8, 9, 10, 11, 12, 13, 14, 15], "text_length": 1024, "text_pad_value": 0 }, + "model": { "decoder": { "cross_head_dim": 128, "cross_query_heads": 16, "gqa_head_dim": 128, "gqa_query_heads": 16, "kv_heads": 4, "n_embd": 2048, "n_hidden": 8192, "n_layer": 18 }, "dropout": 0.0, "encoder": { "head_dim": 128, "n_embd": 1024, "n_head": 16, "n_hidden": 4096, "n_layer": 12 }, "normalization_layer_epsilon": 1e-05, "rope_max_timescale": 10000, "rope_min_timescale": 1, "src_vocab_size": 256, "tgt_vocab_size": 1028, "weight_dtype": "float32" }, + "training": {}, + "version": "0.1" +} + # --- Helper Functions --- def get_torch_device(): @@ -26,215 +35,217 @@ def get_torch_device(): if torch.cuda.is_available(): return torch.device("cuda") else: - # If CUDA is not available, raise an error as GPU is required. - raise RuntimeError("CUDA device not available. This node requires a CUDA-enabled GPU.") -# --- End Helper Functions --- + raise RuntimeError("CUDA device not available. Dia nodes require a CUDA-enabled GPU.") # --- Global model cache --- -loaded_dia_model = None -loaded_model_key = None +loaded_dia_objects = {} -class DiaGenerate: - """Loads the Dia TTS model from Hub onto GPU and generates audio.""" +class DiaLoader: + """Loads the Dia-1.6B TTS model from a local safetensors file.""" @classmethod def INPUT_TYPES(s): + """Finds .safetensors files in diffusion_models directories.""" + try: + safetensors_files = folder_paths.get_filename_list("diffusion_models") + s.dia_model_files = sorted([f for f in safetensors_files if f.lower().endswith(".safetensors")]) + if not s.dia_model_files: + print("DiaLoader: No .safetensors files found in diffusion_models directories.") + s.dia_model_files = ["None"] + except Exception as e: + print(f"DiaLoader: Warning - Could not access diffusion_models paths: {e}") + s.dia_model_files = ["None"] + + return { "required": { "ckpt_name": (s.dia_model_files,), }, } + + RETURN_TYPES = ("DIA_MODEL",) + RETURN_NAMES = ("dia_model",) + FUNCTION = "load_dia_model" + CATEGORY = "audio/DiaTest" + + def load_dia_model(self, ckpt_name: str): + """Loads the safetensors weights, combines with embedded config, loads DAC, and prepares the Dia object.""" + global loaded_dia_objects + + if ckpt_name == "None": raise ValueError("No Dia model selected in DiaLoader.") + + ckpt_path = folder_paths.get_full_path("diffusion_models", ckpt_name) + if not ckpt_path or not os.path.exists(ckpt_path): + found = False + for directory in folder_paths.get_folder_paths("diffusion_models"): + potential_path = os.path.join(directory, ckpt_name) + if os.path.exists(potential_path): + ckpt_path = potential_path; found = True; break + if not found: raise FileNotFoundError(f"Checkpoint file '{ckpt_name}' not found.") + + device = get_torch_device() + compute_dtype = torch.float32 + + current_key = (ckpt_path, str(compute_dtype), str(device)) + + dia_object = None + if current_key in loaded_dia_objects: + print(f"DiaLoader: Using cached Dia object for '{ckpt_name}'.") + dia_object = loaded_dia_objects[current_key] + # Re-check device and DAC just in case + if not dia_object.model._devices_equal(dia_object.device, device): + print(f"DiaLoader: Moving cached model from {dia_object.device} to {device}.") + try: + dia_object.model.to(device) + if dia_object.dac_model: dia_object.dac_model.to(device) + dia_object.device = device + except Exception as move_e: + print(f"DiaLoader: Error moving cached model: {move_e}") + if current_key in loaded_dia_objects: del loaded_dia_objects[current_key] + raise move_e + if dia_object.dac_model is None: + print("DiaLoader: Cached object missing DAC model, attempting reload...") + try: dia_object._load_dac_model() + except Exception as dac_e: print(f"DiaLoader: Error loading DAC model for cached object: {dac_e}"); raise dac_e + elif not dia_object.model._devices_equal(dia_object.dac_model.device, device): + print(f"DiaLoader: Moving cached DAC from {dia_object.dac_model.device} to {device}.") + try: dia_object.dac_model.to(device) + except Exception as dac_move_e: print(f"DiaLoader: Error moving cached DAC model: {dac_move_e}") + else: + if loaded_dia_objects: + print(f"DiaLoader: Different model requested ('{ckpt_name}'). Clearing cache.") + loaded_dia_objects.clear(); gc.collect(); torch.cuda.empty_cache() + + print(f"DiaLoader: Loading Dia-1.6B model configuration...") + try: config = DiaConfig.model_validate(DEFAULT_DIA_1_6B_CONFIG) + except Exception as config_e: print(f"DiaLoader: Error validating embedded config: {config_e}"); raise config_e + + print(f"DiaLoader: Instantiating Dia model on device={device}...") + dia_object = Dia(config, compute_dtype=str(compute_dtype).split('.')[-1], device=device) + + print(f"DiaLoader: Loading model weights from: {ckpt_path}") + try: + state_dict = load_safetensors_file(ckpt_path, device=str(device)) + missing_keys, unexpected_keys = dia_object.model.load_state_dict(state_dict, strict=True) + if missing_keys: print(f"DiaLoader: Warning - Missing keys in state_dict: {missing_keys}") + if unexpected_keys: print(f"DiaLoader: Warning - Unexpected keys in state_dict: {unexpected_keys}") + print("DiaLoader: Model weights loaded successfully.") + del state_dict; gc.collect() + except Exception as e: + print(f"DiaLoader: Error loading state_dict: {e}"); traceback.print_exc() + raise e + + try: dia_object._load_dac_model() + except Exception as dac_e: print(f"DiaLoader: Error loading required DAC model: {dac_e}"); traceback.print_exc(); raise dac_e + + dia_object.model.eval() + if dia_object.dac_model: dia_object.dac_model.eval() + + print(f"DiaLoader: Caching loaded Dia object.") + loaded_dia_objects[current_key] = dia_object + + return (dia_object,) + + +class DiaGenerate: + """Generates audio using a pre-loaded Dia TTS model.""" + @classmethod + def INPUT_TYPES(s): + """Defines the inputs for audio generation.""" return { "required": { - # Model Loading Params - "repo_id": ("STRING", {"default": "nari-labs/Dia-1.6B"}), - # No device override - GPU is forced - - # Generation Params + "dia_model": ("DIA_MODEL",), "text": ("STRING", {"multiline": True, "dynamicPrompts": False, "default": "[S1] Hello world. [S2] This is a test."}), "max_tokens": ("INT", {"default": 1720, "min": 860, "max": 3072, "step": 10}), "cfg_scale": ("FLOAT", {"default": 3.0, "min": 1.0, "max": 7.0, "step": 0.1}), "temperature": ("FLOAT", {"default": 1.3, "min": 0.1, "max": 1.5, "step": 0.05}), "top_p": ("FLOAT", {"default": 0.95, "min": 0.1, "max": 1.0, "step": 0.01}), "cfg_filter_top_k": ("INT", {"default": 35, "min": 1, "max": 100, "step": 1}), - "speed_factor": ("FLOAT", {"default": 0.94, "min": 0.5, "max": 1.5, "step": 0.01}), # Added speed factor + "speed_factor": ("FLOAT", {"default": 0.94, "min": 0.5, "max": 1.5, "step": 0.01}), "seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}), }, } RETURN_TYPES = ("AUDIO",) RETURN_NAMES = ("audio",) - FUNCTION = "load_and_generate" + FUNCTION = "generate_audio" CATEGORY = "audio/DiaTest" - def load_and_generate(self, repo_id, text: str, max_tokens: int, cfg_scale: float, temperature: float, top_p: float, cfg_filter_top_k: int, speed_factor: float, seed: int): - global loaded_dia_model, loaded_model_key + def generate_audio(self, dia_model: Dia, text: str, max_tokens: int, cfg_scale: float, temperature: float, top_p: float, cfg_filter_top_k: int, speed_factor: float, seed: int): + """Performs TTS generation using the provided Dia model object.""" + if dia_model is None: raise ValueError("Dia model object is required.") + if not isinstance(dia_model, Dia): raise TypeError("Invalid object passed as dia_model.") + if dia_model.model is None: raise ValueError("Dia object missing model.") + if dia_model.dac_model is None: raise RuntimeError("Dia object missing DAC model.") - # --- Model Loading Logic --- - # Force GPU device - device = get_torch_device() # This will raise error if no CUDA + exec_device = dia_model.device + if exec_device.type == 'cuda' and not torch.cuda.is_available(): + raise RuntimeError("Model is on CUDA but CUDA is not available.") - # Use float32 internally - compute_dtype_str = "float32" + clamped_max_tokens = min(max_tokens, dia_model.config.data.audio_length) + if max_tokens > clamped_max_tokens: + print(f"DiaGenerate: Clamping max_tokens ({max_tokens}) to model max ({clamped_max_tokens}).") + max_tokens = clamped_max_tokens # Use the clamped value - print(f"DiaTestGenerate: Target device: {device}, Compute dtype: {compute_dtype_str}") - - # Cache key includes repo and dtype (device is fixed to CUDA) - current_key = (repo_id, compute_dtype_str, str(device)) - - dia_model = None - # Check cache - if loaded_dia_model is not None and current_key == loaded_model_key: - print("DiaTestGenerate: Using cached model.") - dia_model = loaded_dia_model - # Defensive check: ensure cached model is indeed on CUDA - if dia_model.device != device: - print(f"DiaTestGenerate: Warning: Cached model not on expected device ({dia_model.device}). Moving to {device}.") - try: - dia_model.model.to(device) - if dia_model.dac_model: dia_model.dac_model.to(device) - dia_model.device = device - except Exception as move_e: - print(f"DiaTestGenerate: Error moving cached model: {move_e}") - loaded_dia_model = None; loaded_model_key = None; raise move_e - else: - # Clear previous model if config changed - if loaded_dia_model is not None: - print(f"DiaTestGenerate: Configuration changed. Clearing previous model...") - try: - if hasattr(loaded_dia_model, 'model'): del loaded_dia_model.model - if hasattr(loaded_dia_model, 'dac_model'): del loaded_dia_model.dac_model - del loaded_dia_model - except Exception as del_e: print(f"DiaTestGenerate: Error deleting previous model: {del_e}") - loaded_dia_model = None; loaded_model_key = None; gc.collect() - torch.cuda.empty_cache(); print("DiaTestGenerate: Cleared CUDA cache.") - - # Load model from Hub - print(f"DiaTestGenerate: Loading model from Hugging Face Hub: repo_id='{repo_id}'") - try: - # Pre-download files (optional) - try: - cache_dir = os.path.join(folder_paths.models_dir, "huggingface") - os.makedirs(cache_dir, exist_ok=True) - hf_hub_download(repo_id=repo_id, filename="config.json", cache_dir=cache_dir, resume_download=True, etag_timeout=10) - hf_hub_download(repo_id=repo_id, filename="dia-v0_1.pth", cache_dir=cache_dir, resume_download=True, etag_timeout=10) - print(f"DiaTestGenerate: Ensured model files are cached.") - except Exception as download_e: - print(f"DiaTestGenerate: Warning during file pre-check/download: {download_e}") - - # Load the model - dia_model = Dia.from_pretrained( - model_name=repo_id, - compute_dtype=compute_dtype_str, # Use string 'float32' - device=device # Load directly onto GPU - ) - print("DiaTestGenerate: Model loaded successfully.") - loaded_dia_model = dia_model - loaded_model_key = current_key - - except Exception as e: - print(f"DiaTestGenerate: Error loading model: {e}") - traceback.print_exc() - loaded_dia_model = None; loaded_model_key = None - raise e - # --- End Model Loading Logic --- - - - # --- Generation Logic --- if not text or text.isspace(): raise ValueError("Input text cannot be empty.") - # Seed setting MAX_SEED_NUMPY = 2**32 - 1 seed_torch = seed; seed_numpy = seed % MAX_SEED_NUMPY torch.manual_seed(seed_torch); np.random.seed(seed_numpy) - torch.cuda.manual_seed_all(seed_torch) # Seed CUDA - print(f"DiaTestGenerate: Using ComfyUI seed {seed} (Torch: {seed_torch}, NumPy: {seed_numpy})") + if exec_device.type == 'cuda': torch.cuda.manual_seed_all(seed_torch) text_for_generate = text + # --- Progress Bar Setup --- + # The total number of steps is max_tokens (or slightly less if EOS is hit early) + pbar = comfy.utils.ProgressBar(max_tokens) + try: - print(f"DiaTestGenerate: Starting generation...") + print(f"DiaGenerate: Starting generation on {exec_device}...") + # Pass the progress bar object to the generate method + output_np = dia_model.generate( + text=text_for_generate, max_tokens=max_tokens, cfg_scale=cfg_scale, temperature=temperature, + top_p=top_p, cfg_filter_top_k=cfg_filter_top_k, use_torch_compile=False, verbose=True, + pbar=pbar # Pass pbar object here + ) - # Generation Call - with torch.inference_mode(): - output_np = dia_model.generate( - text=text_for_generate, max_tokens=max_tokens, cfg_scale=cfg_scale, temperature=temperature, - top_p=top_p, cfg_filter_top_k=cfg_filter_top_k, - # No audio_prompt - use_torch_compile=False, verbose=True - ) - - # Handle failed generation if output_np is None or output_np.size == 0: - print("DiaTestGenerate: Warning - Generation returned None or empty array. Outputting silence.") + print("DiaGenerate: Warning - Generation returned empty. Outputting silence.") silent_tensor = torch.zeros((1, 1, DEFAULT_SAMPLE_RATE), dtype=torch.float32) - result = {'waveform': silent_tensor, 'sample_rate': DEFAULT_SAMPLE_RATE} - return (result,) + return ({'waveform': silent_tensor, 'sample_rate': DEFAULT_SAMPLE_RATE},) - print(f"DiaTestGenerate: Raw generation complete. Shape: {output_np.shape}") - - # --- Apply Speed Factor --- if speed_factor != 1.0: - # Ensure speed_factor is valid - speed_factor = max(0.1, min(speed_factor, 5.0)) # Clamp to reasonable range + speed_factor = max(0.1, min(speed_factor, 5.0)) original_len = len(output_np) target_len = int(original_len / speed_factor) - if target_len > 0 and target_len != original_len: - print(f"DiaTestGenerate: Applying speed factor {speed_factor:.2f}x (length {original_len} -> {target_len})") + print(f"DiaGenerate: Applying speed factor {speed_factor:.2f}x") x_original = np.arange(original_len) x_resampled = np.linspace(0, original_len - 1, target_len) - # Ensure float input for interp if not already - if not np.issubdtype(output_np.dtype, np.floating): - output_np = output_np.astype(np.float32) + if not np.issubdtype(output_np.dtype, np.floating): output_np = output_np.astype(np.float32) resampled_audio_np = np.interp(x_resampled, x_original, output_np) - output_np = resampled_audio_np # Use the resampled audio - else: - print(f"DiaTestGenerate: Skipping speed adjustment (factor: {speed_factor:.2f}).") - # --- End Speed Factor --- + output_np = resampled_audio_np - - # --- Output Formatting --- try: - # Convert numpy to tensor, ensure float32 output_tensor = torch.from_numpy(output_np.astype(np.float32)) - - # Ensure shape [channels, samples] - if output_tensor.ndim == 1: # Mono [samples] -> [1, samples] - output_tensor = output_tensor.unsqueeze(0) - elif output_tensor.ndim != 2: # Should only be 1D or 2D at this point - raise ValueError(f"Unexpected audio array dimension after speed factor: {output_tensor.ndim}.") - # Assuming 2D is already [channels, samples] - interpolation keeps channel dim first if input was 2D - - # Add batch dimension -> [1, channels, samples] - output_tensor = output_tensor.unsqueeze(0) - output_tensor = output_tensor.contiguous() - - # Final log & sanity checks - final_shape = output_tensor.shape; final_dtype = output_tensor.dtype - print(f"DiaTestGenerate: Final audio tensor shape: {final_shape}, dtype: {final_dtype}") - if len(final_shape) != 3: raise ValueError(f"Internal Error: Final tensor dim not 3! Shape: {final_shape}") - if final_shape[0] != 1: print(f"DiaTestGenerate: Warning - final batch size not 1: {final_shape[0]}") - if final_shape[1] == 0 or final_shape[2] == 0: raise ValueError(f"Internal Error: Final tensor zero dim! Shape: {final_shape}") - - # Create dictionary for ComfyUI AUDIO output type + if output_tensor.ndim == 1: output_tensor = output_tensor.unsqueeze(0) + elif output_tensor.ndim != 2: raise ValueError(f"Unexpected audio dim: {output_tensor.ndim}.") + output_tensor = output_tensor.unsqueeze(0).contiguous() + print(f"DiaGenerate: Final audio tensor shape: {output_tensor.shape}, Sample Rate: {DEFAULT_SAMPLE_RATE}") + if len(output_tensor.shape) != 3: raise ValueError("Final tensor dim not 3!") + if output_tensor.shape[1] == 0 or output_tensor.shape[2] == 0: raise ValueError("Final tensor zero dim!") result = {'waveform': output_tensor, 'sample_rate': DEFAULT_SAMPLE_RATE} - return (result,) # Return dict inside tuple - + return (result,) except Exception as format_e: - print(f"DiaTestGenerate: Error formatting output: {format_e}") - traceback.print_exc() - raise format_e - # --- End Output Formatting --- + print(f"DiaGenerate: Error formatting output: {format_e}"); traceback.print_exc(); raise format_e except Exception as e: - print(f"DiaTestGenerate: Error during generation: {e}") + print(f"DiaGenerate: Error during generation: {e}") traceback.print_exc() raise e # --- Node Mappings --- NODE_CLASS_MAPPINGS = { + "DiaLoader": DiaLoader, "DiaGenerate": DiaGenerate, } NODE_DISPLAY_NAME_MAPPINGS = { + "DiaLoader": "Dia 1.6b Loader", "DiaGenerate": "Dia TTS Generate", -} - -# --- Print message on load --- -print("### Loading: ComfyUI-DiaTest Nodes ###") \ No newline at end of file +} \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 56bf39e..7088e08 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,3 @@ -# ComfyUI-DiaTest/requirements.txt - -descript-audio-codec -huggingface_hub \ No newline at end of file +# ComfyUI-DiaTest/requirements.txt + +descript-audio-codec \ No newline at end of file From 31bfb3156132bd2c40ebad2e00b8728895340fef Mon Sep 17 00:00:00 2001 From: BobRandomNumber Date: Mon, 28 Apr 2025 04:36:47 -0400 Subject: [PATCH 2/5] Update README.md --- README.md | 49 +++++++++++++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 7abcadc..9b5b68b 100644 --- a/README.md +++ b/README.md @@ -1,38 +1,41 @@ -# ComfyUI DiaTest TTS Node +# ComfyUI Dia TTS Nodes -This node pack integrates the [Nari Labs Dia](https://github.com/nari-labs/dia) text-to-speech model into ComfyUI using separate nodes for loading the model from a local file and generating audio. +This node pack integrates the [Nari-Labs Dia](https://github.com/nari-labs/dia) 1.6b text-to-speech model into ComfyUI using the safetensors file nari-labs provided. -Dia allows generating dialogue with speaker tags (`[S1]`, `[S2]`) and non-verbal sounds (`(laughs)`, etc.). This node pack loads the model from a local `.safetensors` file onto the GPU and generates audio. It **requires a CUDA-enabled GPU**. +Dia allows generating dialogue with speaker tags (`[S1]`, `[S2]`) and non-verbal sounds (`(laughs)`, etc.). + +It **requires a CUDA-enabled GPU**. **Note:** This version is specifically configured for the `nari-labs/Dia-1.6B` model architecture. ## Installation 1. Ensure you have a CUDA-enabled GPU and the necessary NVIDIA drivers installed. -2. Download the Dia-1.6B model weights file (`dia-1.6B.safetensors`) from Hugging Face Hub: - * **Direct Download URL:** [https://huggingface.co/nari-labs/Dia-1.6B/resolve/main/dia-1.6B.safetensors](https://huggingface.co/nari-labs/Dia-1.6B/resolve/main/dia-1.6B.safetensors) -3. Place the downloaded `.safetensors` file into one of the directories ComfyUI recognizes for `diffusion_models` (e.g., `ComfyUI/models/diffusion_models/`). You might want to rename it to `Dia-1.6B.safetensors` for clarity. -4. Navigate to your `ComfyUI/custom_nodes/` directory. -5. Clone this repository: +2. Download the Dia-1.6B model safetensors file from Hugging Face: + * **Direct Download URL:** [https://huggingface.co/nari-labs/Dia-1.6B/blob/main/model.safetensors](https://huggingface.co/nari-labs/Dia-1.6B/resolve/main/model.safetensors?download=true) +3. Place the downloaded `.safetensors` file into the `diffusion_models` directory (e.g., `ComfyUI/models/diffusion_models/`). +4. You might want to rename it to `Dia-1.6B.safetensors` for clarity. +5. Navigate to your `ComfyUI/custom_nodes/` directory. +6. Clone this repository: ```bash git clone https://github.com/BobRandomNumber/ComfyUI-DiaTest.git ``` Alternatively, download the ZIP and extract it into `custom_nodes`. -6. Install the required dependencies: +7. Install the required dependencies: * Activate ComfyUI's Python environment (e.g., `source ./venv/bin/activate`). * Navigate to the node directory: `cd ComfyUI/custom_nodes/ComfyUI-DiaTest` * Install requirements: `pip install -r requirements.txt` -7. Restart ComfyUI. +8. Restart ComfyUI. ## Nodes ### Dia 1.6b Loader (`DiaLoader`) -Loads the Dia-1.6B TTS model from a local `.safetensors` checkpoint file located in one of your configured `diffusion_models` directories. Loads the model weights and the required DAC codec onto the GPU using the embedded Dia-1.6B configuration. +Loads the Dia-1.6B TTS model from a local `.safetensors` file located in your `diffusion_models` directorie. Loads the model weights and the required DAC codec onto the GPU. **Inputs:** -* `ckpt_name`: Dropdown list of found `.safetensors` files within your `diffusion_models` directories. Select the file corresponding to the Dia-1.6B model. +* `ckpt_name`: Dropdown list of found `.safetensors` files within your `diffusion_models` directorie. Select the file corresponding to the Dia-1.6B model. **Outputs:** @@ -60,12 +63,18 @@ Generates audio using a pre-loaded Dia model provided by the `DiaLoader` node. D ## Usage Example -1. Download `dia-1.6B.safetensors` and place it in a `diffusion_models` directory (e.g., `ComfyUI/models/diffusion_models/`). -2. Add the `Dia 1.6b Loader` node from the `audio/DiaTest` category. -3. Select your Dia model file (e.g., `dia-1.6B.safetensors`) from the `ckpt_name` dropdown. -4. Add the `Dia TTS Generate` node (also from `audio/DiaTest`). -5. Connect the `dia_model` output of the Loader node to the `dia_model` input of the Generate node. -6. Enter your dialogue script into the `text` input on the Generate node. +1. Add the `Dia 1.6b Loader` node from the `audio/DiaTest` category. +2. Select your Dia model file (e.g., `dia-1.6B.safetensors`) from the `ckpt_name` dropdown. +3. Add the `Dia TTS Generate` node (also from `audio/DiaTest`). +4. Connect the `dia_model` output of the Loader node to the `dia_model` input of the Generate node. +5. Enter your dialogue script into the `text` input on the Generate node. + + Control speaker dialogue via `[S1]` and `[S2]` ect., tags. + + Add tags like `(laughs)`, `(clears throat)`, `(sighs)`, `(gasps)`, `(coughs)`, `(singing)`, `(sings)`, `(mumbles)`, `(beep)`, `(groans)`, `(sniffs)`, `(claps)`, `(screams)`, `(inhales)`, `(exhales)`, `(applause)`, `(burps)`, `(humming)`, `(sneezes)`, `(chuckle)`, `(whistles)` + + These verbal tags will be recognized, but may result in unexpected output. + 7. Adjust generation parameters on the Generate node as needed. 8. Connect the `audio` output of the Generate node to a `SaveAudio` or `PreviewAudio` node. 9. Queue the prompt. @@ -74,5 +83,5 @@ Generates audio using a pre-loaded Dia model provided by the `DiaLoader` node. D * This node pack **requires a CUDA-enabled GPU**. * Only the `.safetensors` weights file is required. -* The first time you load a specific model with the `DiaLoader`, it loads the weights and the required DAC codec. Subsequent runs using the same loader node will use the cached model object. Switching models in the loader clears the cache. -* Dependencies `descript-audio-codec`, `huggingface_hub`, and `safetensors` must be installed via `requirements.txt`. \ No newline at end of file +* The first run of the nodes descript-audio-codec may take slightly longer. Subsequent runs will be faster. +* Dependencies `descript-audio-codec` must be installed via `requirements.txt`. From a39efa1474c219d226d98dedafa610b55b5278ab Mon Sep 17 00:00:00 2001 From: BobRandomNumber Date: Mon, 28 Apr 2025 05:10:49 -0400 Subject: [PATCH 3/5] Add files via upload --- example_workflows/DiaTTS.json | 153 ++++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 example_workflows/DiaTTS.json diff --git a/example_workflows/DiaTTS.json b/example_workflows/DiaTTS.json new file mode 100644 index 0000000..75e9fe4 --- /dev/null +++ b/example_workflows/DiaTTS.json @@ -0,0 +1,153 @@ +{ + "id": "00000000-0000-0000-0000-000000000000", + "revision": 0, + "last_node_id": 3, + "last_link_id": 2, + "nodes": [ + { + "id": 2, + "type": "DiaLoader", + "pos": [ + 280, + 390 + ], + "size": [ + 280, + 58 + ], + "flags": {}, + "order": 0, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "dia_model", + "type": "DIA_MODEL", + "links": [ + 1 + ] + } + ], + "properties": { + "aux_id": "BobRandomNumber/ComfyUI-DiaTest", + "ver": "90df0b65f0d20415fa4e5f1822d50d635b4de990", + "Node name for S&R": "DiaLoader" + }, + "widgets_values": [ + "Dia-1.6B.safetensors" + ] + }, + { + "id": 1, + "type": "DiaGenerate", + "pos": [ + 600, + 390 + ], + "size": [ + 460, + 430 + ], + "flags": {}, + "order": 1, + "mode": 0, + "inputs": [ + { + "name": "dia_model", + "type": "DIA_MODEL", + "link": 1 + } + ], + "outputs": [ + { + "name": "audio", + "type": "AUDIO", + "links": [ + 2 + ] + } + ], + "properties": { + "aux_id": "BobRandomNumber/ComfyUI-DiaTest", + "ver": "90df0b65f0d20415fa4e5f1822d50d635b4de990", + "Node name for S&R": "DiaGenerate" + }, + "widgets_values": [ + "[S1] Hey, have you heard about the new TTS model Dia? It's supposed to be amazing!\n[S2] Really? I've been so busy with work, I haven't checked it out yet.\n[S3] (laughs) Well, she sounds incredibly human-like. You won't believe how natural her voice is.\n[S4] That's impressive. Does it handle different emotions well?\n[S1] Oh yeah! She can switch between happy, sad, angry—pretty much anything you throw at her.\n[S2] Sounds like a game changer for the industry.\n[S3] Absolutely. It could revolutionize how we interact with AI in everyday life.\n[S4] I wonder if it's available for public use yet?\n[S1] Not sure, but I'm keeping an eye out. Can't wait to try it myself!", + 3070, + 3, + 1.3, + 0.95, + 30, + 0.8800000000000001, + 57, + "fixed" + ] + }, + { + "id": 3, + "type": "SaveAudio", + "pos": [ + 1090, + 390 + ], + "size": [ + 280, + 112 + ], + "flags": {}, + "order": 2, + "mode": 0, + "inputs": [ + { + "name": "audio", + "type": "AUDIO", + "link": 2 + } + ], + "outputs": [], + "properties": { + "cnr_id": "comfy-core", + "ver": "0.3.30" + }, + "widgets_values": [ + "audio/DiaTTS" + ] + } + ], + "links": [ + [ + 1, + 2, + 0, + 1, + 0, + "DIA_MODEL" + ], + [ + 2, + 1, + 0, + 3, + 0, + "AUDIO" + ] + ], + "groups": [], + "config": {}, + "extra": { + "ds": { + "scale": 1.2284597357367866, + "offset": [ + 44.411603926356264, + -186.08401740634102 + ] + }, + "frontendVersion": "1.17.11", + "VHS_latentpreview": true, + "VHS_latentpreviewrate": 0, + "VHS_MetadataImage": true, + "VHS_KeepIntermediate": true + }, + "version": 0.4 +} \ No newline at end of file From f0e4e59b68dffd3ddf2a2a3635e0bed01539d684 Mon Sep 17 00:00:00 2001 From: BobRandomNumber Date: Mon, 28 Apr 2025 05:18:04 -0400 Subject: [PATCH 4/5] add workflows --- example_workflows/DiaTTS.json | 78 +++++++++++++++++----------------- example_workflows/DiaTTS.png | Bin 0 -> 120074 bytes 2 files changed, 39 insertions(+), 39 deletions(-) create mode 100644 example_workflows/DiaTTS.png diff --git a/example_workflows/DiaTTS.json b/example_workflows/DiaTTS.json index 75e9fe4..7d616d6 100644 --- a/example_workflows/DiaTTS.json +++ b/example_workflows/DiaTTS.json @@ -4,39 +4,6 @@ "last_node_id": 3, "last_link_id": 2, "nodes": [ - { - "id": 2, - "type": "DiaLoader", - "pos": [ - 280, - 390 - ], - "size": [ - 280, - 58 - ], - "flags": {}, - "order": 0, - "mode": 0, - "inputs": [], - "outputs": [ - { - "name": "dia_model", - "type": "DIA_MODEL", - "links": [ - 1 - ] - } - ], - "properties": { - "aux_id": "BobRandomNumber/ComfyUI-DiaTest", - "ver": "90df0b65f0d20415fa4e5f1822d50d635b4de990", - "Node name for S&R": "DiaLoader" - }, - "widgets_values": [ - "Dia-1.6B.safetensors" - ] - }, { "id": 1, "type": "DiaGenerate", @@ -45,8 +12,8 @@ 390 ], "size": [ - 460, - 430 + 590, + 380 ], "flags": {}, "order": 1, @@ -88,7 +55,7 @@ "id": 3, "type": "SaveAudio", "pos": [ - 1090, + 1240, 390 ], "size": [ @@ -113,6 +80,39 @@ "widgets_values": [ "audio/DiaTTS" ] + }, + { + "id": 2, + "type": "DiaLoader", + "pos": [ + 280, + 390 + ], + "size": [ + 280, + 58 + ], + "flags": {}, + "order": 0, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "dia_model", + "type": "DIA_MODEL", + "links": [ + 1 + ] + } + ], + "properties": { + "aux_id": "BobRandomNumber/ComfyUI-DiaTest", + "ver": "90df0b65f0d20415fa4e5f1822d50d635b4de990", + "Node name for S&R": "DiaLoader" + }, + "widgets_values": [ + "Dia-1.6B.safetensors" + ] } ], "links": [ @@ -137,10 +137,10 @@ "config": {}, "extra": { "ds": { - "scale": 1.2284597357367866, + "scale": 1.0152559799477574, "offset": [ - 44.411603926356264, - -186.08401740634102 + 47.47372823767917, + -80.62184306933196 ] }, "frontendVersion": "1.17.11", diff --git a/example_workflows/DiaTTS.png b/example_workflows/DiaTTS.png new file mode 100644 index 0000000000000000000000000000000000000000..37bf8e88415da503b3b581a2195eb8de43bffb67 GIT binary patch literal 120074 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 z zQ8iA&5|JzxfuijY9??$yG7TvjVEO{~$vNM)uPS;Z{n%k=?CGWkJ;>_s3nrhS!{x}0 zGa751C|cwRgyDv@KAPo%zubWi9UKQx;J+Dj{%6P2|MnwkVR3U8(P;s#0m-yY;D3s8 MXJy}<)V=e+0JD3 Date: Mon, 28 Apr 2025 05:24:00 -0400 Subject: [PATCH 5/5] Update README.md typos --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9b5b68b..992208a 100644 --- a/README.md +++ b/README.md @@ -31,11 +31,11 @@ It **requires a CUDA-enabled GPU**. ### Dia 1.6b Loader (`DiaLoader`) -Loads the Dia-1.6B TTS model from a local `.safetensors` file located in your `diffusion_models` directorie. Loads the model weights and the required DAC codec onto the GPU. +Loads the Dia-1.6B TTS model from a local `.safetensors` file located in your `diffusion_models` directory. Loads the model weights and the required DAC codec onto the GPU. **Inputs:** -* `ckpt_name`: Dropdown list of found `.safetensors` files within your `diffusion_models` directorie. Select the file corresponding to the Dia-1.6B model. +* `ckpt_name`: Dropdown list of found `.safetensors` files within your `diffusion_models` directory. Select the file corresponding to the Dia-1.6B model. **Outputs:**