From 11d2e188c5aa7efde9cff031f904670a470ceff2 Mon Sep 17 00:00:00 2001 From: GeekatplayStudio Date: Sun, 16 Nov 2025 08:26:53 -0700 Subject: [PATCH 1/4] Initial commit: ComfyUI Text2Speech custom node with local TTS server --- README.md | 32 +++++++++++++++++++++++++ __init__.py | 62 ++++++++++++++++++++++++++++++++++++++++++++++++ install.bat | 16 +++++++++++++ requirements.txt | 2 ++ run_tts.bat | 12 ++++++++++ tts_server.py | 50 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 174 insertions(+) create mode 100644 README.md create mode 100644 __init__.py create mode 100644 install.bat create mode 100644 requirements.txt create mode 100644 run_tts.bat create mode 100644 tts_server.py diff --git a/README.md b/README.md new file mode 100644 index 0000000..5493cff --- /dev/null +++ b/README.md @@ -0,0 +1,32 @@ +# ComfyUI-Text2Speech + +A ComfyUI custom node for text-to-speech integration with a local TTS server. + +## Features + +- Custom ComfyUI node `HttpTTSToAudio` for sending text to a local TTS server. +- Local TTS server using Coqui TTS (XTTS v2 model). +- Easy setup with batch files for Windows. + +## Installation + +### TTS Server Setup + +1. Run `install.bat` to create a virtual environment and install dependencies. +2. Run `run_tts.bat` to start the TTS server on `http://127.0.0.1:5002`. + +### ComfyUI Node + +1. Copy the `__init__.py` file to your ComfyUI `custom_nodes` folder (e.g., `ComfyUI/custom_nodes/ComfyUI_Text2Speech/__init__.py`). +2. Install `requests` in your ComfyUI environment: `pip install requests`. +3. Restart ComfyUI. + +## Usage + +- Use the `HttpTTSToAudio` node in ComfyUI under `Audio/TTS`. +- Input text, language, and server URL. +- Output is the path to the generated audio file. + +## Workflow + +Connect the audio path to audio/video processing nodes in ComfyUI for creating TTS-enhanced content. \ No newline at end of file diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..f979853 --- /dev/null +++ b/__init__.py @@ -0,0 +1,62 @@ +import os +import json +import requests +import folder_paths + +class HttpTTSToAudio: + """ + Sends text to a local TTS server and returns an audio file path. + Input: text (string), language (string) + Output: audio filepath (string) + """ + + @classmethod + def INPUT_TYPES(cls): + return { + "required": { + "text": ("STRING", { + "multiline": True, + "default": "Hello from ComfyUI." + }), + "language": ("STRING", { + "default": "en" + }), + "server_url": ("STRING", { + "default": "http://127.0.0.1:5002/tts" + }) + } + } + + RETURN_TYPES = ("STRING",) + RETURN_NAMES = ("audio_path",) + FUNCTION = "do_tts" + CATEGORY = "Audio/TTS" + + def do_tts(self, text, language, server_url): + payload = { + "text": text, + "language": language + } + try: + resp = requests.post(server_url, json=payload, timeout=120) + resp.raise_for_status() + data = resp.json() + path = data.get("path") + if not path or not os.path.isfile(path): + raise RuntimeError(f"No file returned from TTS server: {data}") + # Copy to ComfyUI temp dir + with open(path, "rb") as f: + audio_bytes = f.read() + temp_dir = folder_paths.get_temp_directory() + out_name = os.path.basename(path) + out_path = os.path.join(temp_dir, out_name) + with open(out_path, "wb") as f: + f.write(audio_bytes) + return (out_path,) + except Exception as e: + print("TTS HTTP error:", e) + return ("",) + +NODE_CLASS_MAPPINGS = { + "HttpTTSToAudio": HttpTTSToAudio, +} \ No newline at end of file diff --git a/install.bat b/install.bat new file mode 100644 index 0000000..c31b690 --- /dev/null +++ b/install.bat @@ -0,0 +1,16 @@ +@echo off +echo Setting up TTS environment... + +if not exist venv ( + python -m venv venv +) else ( + echo Virtual environment already exists. +) + +call venv\Scripts\activate + +pip install --upgrade pip +pip install -r requirements.txt + +echo TTS setup complete. Run run_tts.bat to start the server. +pause \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..aa33a59 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +TTS +flask \ No newline at end of file diff --git a/run_tts.bat b/run_tts.bat new file mode 100644 index 0000000..5e92c92 --- /dev/null +++ b/run_tts.bat @@ -0,0 +1,12 @@ +@echo off +echo Starting TTS server... + +if not exist venv ( + echo Virtual environment not found. Run install.bat first. + pause + exit /b 1 +) + +call venv\Scripts\activate + +python tts_server.py \ No newline at end of file diff --git a/tts_server.py b/tts_server.py new file mode 100644 index 0000000..63d139b --- /dev/null +++ b/tts_server.py @@ -0,0 +1,50 @@ +from flask import Flask, request, send_file, jsonify +from TTS.api import TTS +import os +import uuid + +# Choose a model (example: XTTS v2 multilingual; you can pick any supported model) +MODEL_NAME = "tts_models/multilingual/multi-dataset/xtts_v2" + +app = Flask(__name__) +tts = TTS(MODEL_NAME) + +OUTPUT_DIR = "outputs" +os.makedirs(OUTPUT_DIR, exist_ok=True) + +@app.route("/tts", methods=["POST"]) +def tts_route(): + data = request.get_json() + text = data.get("text", "").strip() + speaker = data.get("speaker") # optional + language = data.get("language", "en") # optional + + if not text: + return jsonify({"error": "No text"}), 400 + + out_name = f"{uuid.uuid4().hex}.wav" + out_path = os.path.join(OUTPUT_DIR, out_name) + + # Generate audio + # For XTTS you can pass language, speaker_wav, etc.; adjust to your chosen model + tts.tts_to_file( + text=text, + file_path=out_path, + language=language + ) + + return jsonify({ + "ok": True, + "file": out_name, + "path": out_path + }) + +@app.route("/audio/", methods=["GET"]) +def get_audio(fname): + path = os.path.join(OUTPUT_DIR, fname) + if not os.path.isfile(path): + return jsonify({"error": "Not found"}), 404 + return send_file(path, mimetype="audio/wav") + +if __name__ == "__main__": + app.run(host="127.0.0.1", port=5002) \ No newline at end of file From 124a0f5be45b929046286963c47bad5a902f9215 Mon Sep 17 00:00:00 2001 From: GeekatplayStudio Date: Sun, 16 Nov 2025 08:29:42 -0700 Subject: [PATCH 2/4] Add example ComfyUI workflow JSON --- example_workflow.json | 134 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 example_workflow.json diff --git a/example_workflow.json b/example_workflow.json new file mode 100644 index 0000000..d2e28fa --- /dev/null +++ b/example_workflow.json @@ -0,0 +1,134 @@ +{ + "last_node_id": 5, + "last_link_id": 4, + "nodes": { + "1": { + "id": 1, + "type": "PrimitiveNode", + "pos": [0, 0], + "size": [200, 100], + "flags": {}, + "order": 0, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "STRING", + "type": "STRING", + "links": [1], + "slot_index": 0 + } + ], + "properties": { + "value": "Hello from local TTS in ComfyUI." + }, + "widgets_values": ["Hello from local TTS in ComfyUI."] + }, + "2": { + "id": 2, + "type": "HttpTTSToAudio", + "pos": [250, 0], + "size": [300, 150], + "flags": {}, + "order": 1, + "mode": 0, + "inputs": [ + { + "name": "text", + "type": "STRING", + "link": 1, + "slot_index": 0 + } + ], + "outputs": [ + { + "name": "audio_path", + "type": "STRING", + "links": [2], + "slot_index": 0 + } + ], + "properties": {}, + "widgets_values": ["en", "http://127.0.0.1:5002/tts"] + }, + "3": { + "id": 3, + "type": "LoadAudio", + "pos": [600, 0], + "size": [200, 100], + "flags": {}, + "order": 2, + "mode": 0, + "inputs": [ + { + "name": "audio_path", + "type": "STRING", + "link": 2, + "slot_index": 0 + } + ], + "outputs": [ + { + "name": "audio", + "type": "AUDIO", + "links": [3] + } + ], + "properties": {}, + "widgets_values": [] + }, + "4": { + "id": 4, + "type": "LoadImage", + "pos": [850, 0], + "size": [200, 100], + "flags": {}, + "order": 3, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "image", + "type": "IMAGE", + "links": [4] + } + ], + "properties": {}, + "widgets_values": ["path/to/image.png"] + }, + "5": { + "id": 5, + "type": "VideoCombine", + "pos": [1100, 0], + "size": [200, 100], + "flags": {}, + "order": 4, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 4 + }, + { + "name": "audio", + "type": "AUDIO", + "link": 3 + } + ], + "outputs": [], + "properties": {}, + "widgets_values": [] + } + }, + "links": [ + [1, 1, 0, 2, 0, "STRING"], + [2, 2, 0, 3, 0, "STRING"], + [3, 3, 0, 5, 1, "AUDIO"], + [4, 4, 0, 5, 0, "IMAGE"] + ], + "groups": [], + "config": {}, + "extra": {}, + "version": 0.4 +} \ No newline at end of file From e591828b3afc6213023af37a2f8e6091fb1379cf Mon Sep 17 00:00:00 2001 From: GeekatplayStudio Date: Sun, 16 Nov 2025 08:32:01 -0700 Subject: [PATCH 3/4] Fix install.bat to check for Python before proceeding --- install.bat | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/install.bat b/install.bat index c31b690..ec341c0 100644 --- a/install.bat +++ b/install.bat @@ -1,6 +1,15 @@ @echo off echo Setting up TTS environment... +python --version >nul 2>&1 +if errorlevel 1 ( + echo Python is not installed or not in PATH. + echo Please install Python from https://www.python.org/downloads/ and make sure it's added to PATH. + echo Then run this script again. + pause + exit /b 1 +) + if not exist venv ( python -m venv venv ) else ( From ba4fb4fe3c10a5e73870cc43027954f4f12f2204 Mon Sep 17 00:00:00 2001 From: GeekatplayStudio Date: Sun, 16 Nov 2025 08:32:36 -0700 Subject: [PATCH 4/4] Add prerequisites section for Python installation --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 5493cff..ae4fea2 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,10 @@ A ComfyUI custom node for text-to-speech integration with a local TTS server. - Local TTS server using Coqui TTS (XTTS v2 model). - Easy setup with batch files for Windows. +## Prerequisites + +- Python 3.8+ installed and added to PATH. Download from [python.org](https://www.python.org/downloads/). + ## Installation ### TTS Server Setup