├── text-to-speech.py ├── script-to-srt.py ├── README.md └── YoutubeAgent.json /text-to-speech.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, request, send_file, jsonify 2 | from gtts import gTTS 3 | import os 4 | import time 5 | 6 | app = Flask(__name__) 7 | 8 | SAVE_FOLDER = os.path.join(os.getcwd(), "audio_files") 9 | os.makedirs(SAVE_FOLDER, exist_ok=True) 10 | 11 | @app.route('/tts', methods=['POST']) 12 | def text_to_speech(): 13 | data = request.get_json() 14 | text = data.get('text') 15 | filename = data.get('filename', 'speech.mp3') 16 | 17 | if not text: 18 | return jsonify({"error": "Text is required"}), 400 19 | 20 | output_path = os.path.join(SAVE_FOLDER, filename) 21 | 22 | try: 23 | tts = gTTS(text=text, lang='en') 24 | tts.save(output_path) 25 | except Exception as e: 26 | return jsonify({"error": str(e)}), 500 27 | 28 | time.sleep(0.3) # Ensure file is ready 29 | 30 | if not os.path.exists(output_path) or os.path.getsize(output_path) == 0: 31 | return jsonify({"error": "Audio file not created properly"}), 500 32 | 33 | return send_file( 34 | output_path, 35 | mimetype="audio/mpeg", 36 | as_attachment=True, 37 | download_name=filename 38 | ) 39 | 40 | if __name__ == '__main__': 41 | app.run(host='0.0.0.0', port=5001) 42 | -------------------------------------------------------------------------------- /script-to-srt.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, request, send_file, jsonify 2 | import io 3 | import re 4 | 5 | app = Flask(__name__) 6 | 7 | WORDS_PER_SECOND = 4.0 8 | 9 | def format_timestamp(seconds): 10 | hours = int(seconds // 3600) 11 | minutes = int((seconds % 3600) // 60) 12 | secs = int(seconds % 60) 13 | milliseconds = int((seconds - int(seconds)) * 1000) 14 | return f"{hours:02}:{minutes:02}:{secs:02},{milliseconds:03}" 15 | 16 | def generate_srt(script, wps=WORDS_PER_SECOND): 17 | sentences = re.split(r'(?<=[.!?])\s+', script.strip()) 18 | srt_output = "" 19 | current_time = 0.0 20 | index = 1 21 | 22 | for sentence in sentences: 23 | sentence = sentence.strip() 24 | if not sentence: 25 | continue 26 | word_count = len(sentence.split()) 27 | duration = word_count / wps 28 | start_time = format_timestamp(current_time) 29 | end_time = format_timestamp(current_time + duration) 30 | srt_output += f"{index}\n{start_time} --> {end_time}\n{sentence}\n\n" 31 | current_time += duration 32 | index += 1 33 | 34 | return srt_output.strip() 35 | 36 | @app.route("/generate-srt", methods=["POST"]) 37 | def generate_srt_file(): 38 | data = request.get_json() 39 | if not data or "script" not in data or "filename" not in data: 40 | return jsonify({"error": "Missing 'script' or 'filename'"}), 400 41 | 42 | script = data["script"] 43 | filename = data["filename"].strip() 44 | if not filename.endswith(".srt"): 45 | filename += ".srt" 46 | 47 | srt_content = generate_srt(script) 48 | 49 | # Return the .srt file as binary stream 50 | file_stream = io.BytesIO(srt_content.encode("utf-8")) 51 | file_stream.seek(0) 52 | 53 | return send_file( 54 | file_stream, 55 | mimetype="application/x-subrip", 56 | as_attachment=True, 57 | download_name=filename 58 | ) 59 | 60 | if __name__ == "__main__": 61 | app.run(host="0.0.0.0", port=8000) 62 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # N8n YouTube/Reel Content Generation Agent 2 | 3 | This N8n workflow automates the creation of various assets for short-form video content (like YouTube Shorts or Instagram Reels) based on a simple text prompt. It generates a script, converts it to speech, creates captions, generates relevant AI images and videos, and finds stock footage. 4 | 5 | **Workflow Visualization:** 6 | 7 | (Consider adding a screenshot of your N8n workflow here) 8 | 9 | ## Features 10 | 11 | * **Input:** Takes a simple text prompt describing the video idea via an N8n Form Trigger. 12 | * **Script Generation:** Uses an AI language model (OpenRouter - Qwen) to write a short, engaging script (~50-70 words). 13 | * **Text-to-Speech (TTS):** Converts the generated script into an audio file (`.wav`) using a local TTS service. 14 | * **Caption Generation:** Creates subtitle (`.srt`) files based on the script using a local captioning service. 15 | * **Image/Video Prompt Generation:** Uses an AI language model (OpenRouter - Qwen VL) to create concise prompts suitable for generating visuals based on the script. 16 | * **AI Image Generation:** Generates an AI image using the Google Gemini API based on the derived prompt. 17 | * **AI Video Generation:** Generates a short AI video clip using a Hugging Face Space API (ZeroScope v2) based on the derived prompt. 18 | * **Stock Video Search:** Searches Pexels for relevant stock videos based on the derived prompt. 19 | * **File Organization:** Creates a unique folder for each execution using the execution ID to store all generated assets. 20 | * **Outputs:** Saves the script (`.txt`), speech audio (`.wav`), captions (`.srt`), AI image (`.png`), AI video (`.mp4`), and downloaded stock videos (`.mp4`) locally where N8n has write access. 21 | 22 | ## Prerequisites 23 | 24 | 1. **N8n Instance:** A running N8n instance (self-hosted or cloud). 25 | 2. **N8n Nodes:** Ensure the `@n8n/n8n-nodes-langchain` package is installed if using relevant nodes. Standard nodes like `HttpRequest`, `ExecuteCommand`, `ReadWriteFile`, `ItemLists`, `ConvertToFile`, `Code`, `FormTrigger` should be available. 26 | 3. **API Keys & Credentials:** 27 | * **OpenRouter:** 28 | * An OpenRouter API Key. This needs to be configured as an N8n credential named "OpenRouter account" (or update the nodes to use your credential name). Used for script and image/video prompt generation. 29 | * **Google Gemini:** 30 | * A Google Cloud API Key with the Generative Language API enabled. This key is currently **hardcoded** in the `Create AI Image` node's query parameters. You **must** edit this node and paste your key. 31 | * **Pexels:** 32 | * A Pexels API Key. This key is currently **hardcoded** as `DLeEua` in the `Search Videos on Pexel` node's header parameters. You **must** edit this node and replace `DLeEua` with your actual Pexels API Key. 33 | 4. **Local Services (Crucial):** 34 | * **Text-to-Speech (TTS) Service:** A TTS service must be running and accessible to your N8n instance at `http://host.docker.internal:5001/tts`. This service needs to accept a POST request with `text` (the script) and `filename` (desired output filename) parameters and return the audio file. 35 | * **Caption (SRT) Generation Service:** An SRT generation service must be running and accessible to your N8n instance at `http://host.docker.internal:8000/generate-srt`. This service needs to accept a POST request with `script` (the script) and `filename` (desired base name for the SRT file) and return the SRT file. 36 | * **Note on `host.docker.internal`**: This hostname typically works when N8n is running as a Docker container on Docker Desktop (Windows/Mac) to allow the container to reach services running on the host machine. If your N8n setup or local service setup is different (e.g., N8n running directly on host, N8n on Linux Docker, different container network), you will need to **adjust these URLs** accordingly to point correctly to your running TTS and SRT services. 37 | 5. **N8n Permissions:** 38 | * **Execute Command:** The N8n instance needs permission to execute the `mkdir` command (enabled via environment variables, e.g., `N8N_ALLOW_NODE=ExecuteCommandNode`). 39 | * **File System Access:** N8n needs write permissions to the directory where it's running or a configured data volume to save the generated files (`./{{ $execution.id }}/...`). 40 | 41 | ## Setup Instructions 42 | 43 | 1. **Import Workflow:** 44 | * Download the `YoutubeAgent.json` file provided. 45 | * In your N8n instance, go to "Workflows" and click "Import from File". 46 | * Upload the JSON file. 47 | 2. **Configure Credentials:** 48 | * Go to "Credentials" in your N8n instance. 49 | * Click "Add Credential". 50 | * Search for "OpenRouter API". 51 | * Enter your OpenRouter API key and give it a recognizable name (e.g., "OpenRouter account", matching the name in the workflow nodes). 52 | * Save the credential. Ensure the `OpenRouter Chat Model` nodes in the workflow are configured to use this credential. 53 | 3. **Configure API Keys in Nodes:** 54 | * **Google Gemini:** Open the workflow, find the `Create AI Image` (HttpRequest) node. Go to the "Query Parameters" section and replace the empty `value` for the `key` parameter with your actual Google Gemini API Key. 55 | * **Pexels:** Open the workflow, find the `Search Videos on Pexel` (HttpRequest) node. Go to the "Headers" section and replace `DLeEua` in the `Authorization` parameter's value with your actual Pexels API Key. 56 | 4. **Set Up Local Services:** 57 | * Ensure your TTS and SRT generation services are running. 58 | * Verify that they are accessible from your N8n environment using the URLs specified in the `Create speech` and `Create Caption` nodes (`http://host.docker.internal:5001/tts` and `http://host.docker.internal:8000/generate-srt`). 59 | * **Adjust URLs if necessary** based on your specific N8n and service hosting setup (see Prerequisites Note on `host.docker.internal`). 60 | 5. **Enable Execute Command (If Needed):** 61 | * If you haven't already, configure your N8n environment variables to allow the Execute Command node. Refer to the N8n documentation on security. For Docker, you might add `-e N8N_ALLOW_NODE=ExecuteCommandNode` to your `docker run` command or `environment` section in `docker-compose.yml`. Restart N8n after changing environment variables. 62 | 6. **Check File Permissions:** 63 | * Ensure the user running the N8n process has write permissions in the N8n installation directory or its configured data directory. 64 | 65 | ## How to Use 66 | 67 | 1. **Activate Workflow:** Open the workflow in N8n and toggle the "Active" switch to ON in the top-right corner. 68 | 2. **Trigger:** The workflow uses a "Form Trigger". Access the Production URL provided by the `Write video idea` (Form Trigger) node. 69 | 3. **Submit Prompt:** Enter your video idea into the form field (e.g., "A cat discovering a hidden portal in a bookshelf") and submit. 70 | 4. **Execution:** N8n will execute the workflow. You can monitor the progress in the "Executions" list. 71 | 5. **Retrieve Outputs:** Once the execution is complete, navigate to the N8n server's file system (or the mapped volume). You will find a folder named after the execution ID (e.g., `./123/`). Inside this folder, you will find the generated files: 72 | * `script.txt` 73 | * `speech.wav` 74 | * `script.srt` 75 | * `image.png` 76 | * `aiVideo.mp4` 77 | * `video.mp4` (potentially multiple if the workflow were modified to download more than one) 78 | 79 | ## Workflow Breakdown 80 | 81 | 1. **Input & Setup:** Form Trigger receives the prompt, Execute Command creates a unique output folder. 82 | 2. **Scripting:** OpenRouter LLM generates the script based on the prompt. 83 | 3. **Local Asset Generation:** 84 | * The script is saved as `.txt`. 85 | * The script is sent to the local TTS service to create `.wav` audio. 86 | * The script is sent to the local SRT service to create `.srt` captions. 87 | 4. **Visual Prompting:** Another OpenRouter LLM (VL model) creates short prompts for visual generation from the script. 88 | 5. **API Asset Generation:** 89 | * **AI Image:** Google Gemini API is called to create a `.png` image. 90 | * **AI Video:** Hugging Face API is called to create and download an `.mp4` video. 91 | * **Stock Video:** Pexels API is searched, and the first relevant `.mp4` video is downloaded. 92 | 6. **Saving:** All downloaded/generated binary files (audio, image, videos) are saved to the execution-specific folder. 93 | 94 | ## Important Notes & Troubleshooting 95 | 96 | * **API Costs & Limits:** Be mindful of the API usage costs and rate limits for OpenRouter, Google Cloud, and Pexels. 97 | * **Local Service Dependency:** The workflow heavily relies on the **availability and correct functioning** of your local TTS and SRT generation services. Ensure they are running before executing the workflow. Errors in these services will cause the workflow to fail at those steps. 98 | * **`host.docker.internal`:** This is a common point of failure if your N8n setup doesn't match the Docker Desktop environment assumption. Double-check connectivity from N8n to your local services. 99 | * **Hugging Face Space Availability:** The AI Video generation relies on a specific Hugging Face Space (`hysts-zeroscope-v2`). These spaces can sometimes be offline, rate-limited, or change their API structure, which would break that part of the workflow. 100 | * **Execution Time:** Generating AI images and especially videos can take a significant amount of time. The workflow might run for several minutes. 101 | * **Error Handling:** This workflow has basic implicit error handling (N8n stops on node failure). For production use, consider adding explicit error handling branches. 102 | * **File Paths:** The workflow assumes it can write to `./{{ $execution.id }}/`. Ensure this relative path works in your N8n environment. You might need to use absolute paths depending on configuration. 103 | -------------------------------------------------------------------------------- /YoutubeAgent.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "YoutubeAgent", 3 | "nodes": [ 4 | { 5 | "parameters": { 6 | "model": "qwen/qwen-2.5-72b-instruct:free", 7 | "options": {} 8 | }, 9 | "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter", 10 | "typeVersion": 1, 11 | "position": [ 12 | 320, 13 | -360 14 | ], 15 | "id": "fe0eb227-7a7c-4842-b191-2ab2cb250d5a", 16 | "name": "OpenRouter Chat Model", 17 | "credentials": { 18 | "openRouterApi": { 19 | "id": "lmQsStnMAVBZiYSe", 20 | "name": "OpenRouter account" 21 | } 22 | } 23 | }, 24 | { 25 | "parameters": { 26 | "fieldToSplitOut": "videos", 27 | "options": { 28 | "destinationFieldName": "videos" 29 | } 30 | }, 31 | "id": "c57b9e9a-5992-4f48-a2ab-f068fdeecb33", 32 | "name": "Split Videos", 33 | "type": "n8n-nodes-base.itemLists", 34 | "position": [ 35 | 1740, 36 | -640 37 | ], 38 | "typeVersion": 3.1 39 | }, 40 | { 41 | "parameters": { 42 | "url": "={{ $json.videos.video_files[0].link }}", 43 | "options": { 44 | "response": { 45 | "response": { 46 | "responseFormat": "file" 47 | } 48 | } 49 | } 50 | }, 51 | "id": "bc1753e0-3ca4-492f-959b-926322a9b560", 52 | "name": "Download Video", 53 | "type": "n8n-nodes-base.httpRequest", 54 | "position": [ 55 | 1960, 56 | -640 57 | ], 58 | "typeVersion": 4.2 59 | }, 60 | { 61 | "parameters": { 62 | "content": "## Local Setup for Script, Speech, and Caption\n", 63 | "height": 760, 64 | "width": 800, 65 | "color": 7 66 | }, 67 | "type": "n8n-nodes-base.stickyNote", 68 | "position": [ 69 | 940, 70 | -360 71 | ], 72 | "typeVersion": 1, 73 | "id": "721617d0-0bd5-4d52-a8a8-f188ee24fe6d", 74 | "name": "Sticky Note" 75 | }, 76 | { 77 | "parameters": { 78 | "content": "## API setup for AI Images, AI Videos, and Videos", 79 | "height": 860, 80 | "width": 1760, 81 | "color": 7 82 | }, 83 | "type": "n8n-nodes-base.stickyNote", 84 | "position": [ 85 | 940, 86 | -1260 87 | ], 88 | "typeVersion": 1, 89 | "id": "ee461724-6a87-465a-bbb4-98b1228f2e1f", 90 | "name": "Sticky Note1" 91 | }, 92 | { 93 | "parameters": { 94 | "formTitle": "Prompt", 95 | "formFields": { 96 | "values": [ 97 | { 98 | "fieldLabel": "Enter your prompt here", 99 | "requiredField": true 100 | } 101 | ] 102 | }, 103 | "options": {} 104 | }, 105 | "type": "n8n-nodes-base.formTrigger", 106 | "typeVersion": 2.2, 107 | "position": [ 108 | -220, 109 | -580 110 | ], 111 | "id": "fa16edbc-d586-4d80-a85e-78e6ceabbd65", 112 | "name": "Write video idea", 113 | "webhookId": "0341d4ce-4b42-4389-9401-cf705ca0b0ed" 114 | }, 115 | { 116 | "parameters": { 117 | "command": "=mkdir {{ $execution.id }}" 118 | }, 119 | "type": "n8n-nodes-base.executeCommand", 120 | "typeVersion": 1, 121 | "position": [ 122 | 0, 123 | -580 124 | ], 125 | "id": "8678003d-f270-4752-96a5-5d2d8aae042d", 126 | "name": "Create Folder" 127 | }, 128 | { 129 | "parameters": { 130 | "promptType": "define", 131 | "text": "=Write a short, exciting script (~50-70 words) for a instagram reel. Keep only script no extra words. So that I can directly make audio out of it. Here is the topic: {{ $json['Enter your prompt here'] }}. ", 132 | "messages": { 133 | "messageValues": [ 134 | { 135 | "message": "You are a instagram reel script writer." 136 | } 137 | ] 138 | } 139 | }, 140 | "type": "@n8n/n8n-nodes-langchain.chainLlm", 141 | "typeVersion": 1.6, 142 | "position": [ 143 | 240, 144 | -580 145 | ], 146 | "id": "5a44c441-db30-4a18-957f-d515a3d77670", 147 | "name": "Write Script" 148 | }, 149 | { 150 | "parameters": { 151 | "promptType": "define", 152 | "text": "=Understand the below script and give me short prompt for generating image only. Donot use special characters only use space: {{ $json.text }}" 153 | }, 154 | "type": "@n8n/n8n-nodes-langchain.chainLlm", 155 | "typeVersion": 1.6, 156 | "position": [ 157 | 1060, 158 | -1100 159 | ], 160 | "id": "95c2dd4d-403a-424c-a2c1-3ebdabcd5847", 161 | "name": "Write image/video prompt" 162 | }, 163 | { 164 | "parameters": { 165 | "method": "POST", 166 | "url": "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash-exp-image-generation:generateContent", 167 | "sendQuery": true, 168 | "queryParameters": { 169 | "parameters": [ 170 | { 171 | "name": "key", 172 | "value": "=AIzaSyCbDNGaAtoE_XZv3rGu-INoCeQvnzuoXBY" 173 | } 174 | ] 175 | }, 176 | "sendBody": true, 177 | "specifyBody": "json", 178 | "jsonBody": "={\n \"contents\": [\n {\n \"parts\": [\n {\n \"text\": \"create image from below data: {{ $json.text }}\"\n }\n ]\n }\n ],\n \"generationConfig\": {\n \"responseModalities\": [\n \"TEXT\",\n \"IMAGE\"\n ]\n }\n}", 179 | "options": {} 180 | }, 181 | "type": "n8n-nodes-base.httpRequest", 182 | "typeVersion": 4.2, 183 | "position": [ 184 | 1480, 185 | -1100 186 | ], 187 | "id": "35a72d53-3ac6-4661-8c3f-f7d768a7b9e6", 188 | "name": "Create AI Image" 189 | }, 190 | { 191 | "parameters": { 192 | "operation": "toBinary", 193 | "sourceProperty": "candidates[0].content.parts[0].inlineData.data", 194 | "options": {} 195 | }, 196 | "type": "n8n-nodes-base.convertToFile", 197 | "typeVersion": 1.1, 198 | "position": [ 199 | 1740, 200 | -1100 201 | ], 202 | "id": "b1eb01d7-9706-4d38-86e7-220846123629", 203 | "name": "Get AI Image" 204 | }, 205 | { 206 | "parameters": { 207 | "operation": "write", 208 | "fileName": "=./{{ $execution.id }}/image{{ $execution.id }}.png", 209 | "options": {} 210 | }, 211 | "type": "n8n-nodes-base.readWriteFile", 212 | "typeVersion": 1, 213 | "position": [ 214 | 1960, 215 | -1100 216 | ], 217 | "id": "f6d770d4-8949-4a9c-a60f-aaaff55239d8", 218 | "name": "Save AI Image" 219 | }, 220 | { 221 | "parameters": { 222 | "method": "POST", 223 | "url": "https://hysts-zeroscope-v2.hf.space/gradio_api/call/run", 224 | "sendBody": true, 225 | "specifyBody": "json", 226 | "jsonBody": "={\n \"data\": [\n \"{{ $json.text }}\",\n 0,\n 24,\n 10\n ]\n}", 227 | "options": {} 228 | }, 229 | "type": "n8n-nodes-base.httpRequest", 230 | "typeVersion": 4.2, 231 | "position": [ 232 | 1480, 233 | -860 234 | ], 235 | "id": "1b0f7ff4-34de-40f0-89b3-c3d456b2c0e4", 236 | "name": "Creat AI Video" 237 | }, 238 | { 239 | "parameters": { 240 | "url": "=https://hysts-zeroscope-v2.hf.space/gradio_api/call/run/{{ $json.event_id }}", 241 | "options": {} 242 | }, 243 | "type": "n8n-nodes-base.httpRequest", 244 | "typeVersion": 4.2, 245 | "position": [ 246 | 1740, 247 | -860 248 | ], 249 | "id": "c144efd5-48c8-4395-9932-d066648b9aa0", 250 | "name": "Get AI Video" 251 | }, 252 | { 253 | "parameters": { 254 | "jsCode": "const inputString = $input.first().json.data\n\n// Step 1: Extract the JSON part after \"data: \"\nconst jsonPart = inputString.split('data: ')[1].trim();\n\n// Step 2: Parse it\nconst parsedData = JSON.parse(jsonPart);\n\n// Step 3: Get the path\nconst path = parsedData[0].video.path;\n\nreturn {path};" 255 | }, 256 | "type": "n8n-nodes-base.code", 257 | "typeVersion": 2, 258 | "position": [ 259 | 1960, 260 | -860 261 | ], 262 | "id": "10cd0e5f-dc5d-4bb6-9f14-4fff82649530", 263 | "name": "Get URL" 264 | }, 265 | { 266 | "parameters": { 267 | "url": "=https://hysts-zeroscope-v2.hf.space/gradio_api/file={{ $json.path }}", 268 | "options": { 269 | "response": { 270 | "response": { 271 | "responseFormat": "file" 272 | } 273 | } 274 | } 275 | }, 276 | "id": "f167c91e-920c-4fc3-93b3-3dee60c4fd4f", 277 | "name": "Download AI Video", 278 | "type": "n8n-nodes-base.httpRequest", 279 | "position": [ 280 | 2220, 281 | -860 282 | ], 283 | "typeVersion": 4.2 284 | }, 285 | { 286 | "parameters": { 287 | "operation": "write", 288 | "fileName": "=./{{ $execution.id }}/aiVideo{{ $execution.id }}.mp4", 289 | "options": {} 290 | }, 291 | "type": "n8n-nodes-base.readWriteFile", 292 | "typeVersion": 1, 293 | "position": [ 294 | 2440, 295 | -860 296 | ], 297 | "id": "4830b8bc-6e73-4a3d-b77c-1fcf02d276d2", 298 | "name": "Save AI Video" 299 | }, 300 | { 301 | "parameters": { 302 | "url": "https://api.pexels.com/videos/search", 303 | "sendQuery": true, 304 | "queryParameters": { 305 | "parameters": [ 306 | { 307 | "name": "query", 308 | "value": "={{ $json.text }}" 309 | }, 310 | { 311 | "name": "per_page", 312 | "value": "3" 313 | } 314 | ] 315 | }, 316 | "sendHeaders": true, 317 | "headerParameters": { 318 | "parameters": [ 319 | { 320 | "name": "Authorization", 321 | "value": "DLeEuwTJ2SL2wxRiQY6J8dEKPteO0cvzeq3GfUlcDQTJMqtPikVt8woa" 322 | } 323 | ] 324 | }, 325 | "options": {} 326 | }, 327 | "id": "3f9691ca-2fab-4178-b1e7-3778518022cd", 328 | "name": "Search Videos on Pexel", 329 | "type": "n8n-nodes-base.httpRequest", 330 | "position": [ 331 | 1480, 332 | -640 333 | ], 334 | "typeVersion": 4.2 335 | }, 336 | { 337 | "parameters": { 338 | "operation": "write", 339 | "fileName": "=./{{ $execution.id }}/video{{ $json.videos.id }}.mp4", 340 | "options": {} 341 | }, 342 | "type": "n8n-nodes-base.readWriteFile", 343 | "typeVersion": 1, 344 | "position": [ 345 | 2220, 346 | -640 347 | ], 348 | "id": "7b35ec47-06f9-4971-8d10-295cbd64e6ad", 349 | "name": "Save Video" 350 | }, 351 | { 352 | "parameters": { 353 | "operation": "toText", 354 | "sourceProperty": "text", 355 | "options": {} 356 | }, 357 | "type": "n8n-nodes-base.convertToFile", 358 | "typeVersion": 1.1, 359 | "position": [ 360 | 1120, 361 | -220 362 | ], 363 | "id": "0ffd9721-7b37-4167-b0b5-00e1e3fa10bd", 364 | "name": "Create Script" 365 | }, 366 | { 367 | "parameters": { 368 | "operation": "write", 369 | "fileName": "=./{{$execution.id}}/script.txt", 370 | "options": {} 371 | }, 372 | "type": "n8n-nodes-base.readWriteFile", 373 | "typeVersion": 1, 374 | "position": [ 375 | 1420, 376 | -220 377 | ], 378 | "id": "2ce5b17a-c472-4181-8358-d14b85cbff6b", 379 | "name": "Save Script" 380 | }, 381 | { 382 | "parameters": { 383 | "method": "POST", 384 | "url": "http://host.docker.internal:5001/tts", 385 | "sendBody": true, 386 | "bodyParameters": { 387 | "parameters": [ 388 | { 389 | "name": "text", 390 | "value": "={{ $json.text }}" 391 | }, 392 | { 393 | "name": "filename", 394 | "value": "=audio{{ $execution.id }}.wav" 395 | } 396 | ] 397 | }, 398 | "options": { 399 | "response": { 400 | "response": { 401 | "responseFormat": "file" 402 | } 403 | } 404 | } 405 | }, 406 | "type": "n8n-nodes-base.httpRequest", 407 | "typeVersion": 4.2, 408 | "position": [ 409 | 1120, 410 | 0 411 | ], 412 | "id": "0717c2d6-3e56-4f2f-841a-62f7878f4bfd", 413 | "name": "Create speech" 414 | }, 415 | { 416 | "parameters": { 417 | "operation": "write", 418 | "fileName": "=./{{ $execution.id }}/speech{{ $execution.id }}.wav", 419 | "options": {} 420 | }, 421 | "type": "n8n-nodes-base.readWriteFile", 422 | "typeVersion": 1, 423 | "position": [ 424 | 1420, 425 | 0 426 | ], 427 | "id": "c7b136fb-7624-4d89-91f6-d2802fe0bc2d", 428 | "name": "Save speech" 429 | }, 430 | { 431 | "parameters": { 432 | "method": "POST", 433 | "url": "http://host.docker.internal:8000/generate-srt", 434 | "sendBody": true, 435 | "bodyParameters": { 436 | "parameters": [ 437 | { 438 | "name": "filename", 439 | "value": "=srt{{ $execution.id }}" 440 | }, 441 | { 442 | "name": "script", 443 | "value": "={{ $json.text }}" 444 | } 445 | ] 446 | }, 447 | "options": { 448 | "response": { 449 | "response": { 450 | "responseFormat": "file" 451 | } 452 | } 453 | } 454 | }, 455 | "type": "n8n-nodes-base.httpRequest", 456 | "typeVersion": 4.2, 457 | "position": [ 458 | 1120, 459 | 220 460 | ], 461 | "id": "61760ff4-f70b-4360-a36b-02e53411b4a2", 462 | "name": "Create Caption" 463 | }, 464 | { 465 | "parameters": { 466 | "operation": "write", 467 | "fileName": "=./{{ $execution.id }}/script.srt", 468 | "options": {} 469 | }, 470 | "type": "n8n-nodes-base.readWriteFile", 471 | "typeVersion": 1, 472 | "position": [ 473 | 1420, 474 | 220 475 | ], 476 | "id": "00bc8d5b-231e-4f60-b0ee-7cb5492bca7b", 477 | "name": "Save Caption" 478 | }, 479 | { 480 | "parameters": { 481 | "model": "qwen/qwen2.5-vl-72b-instruct:free", 482 | "options": {} 483 | }, 484 | "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter", 485 | "typeVersion": 1, 486 | "position": [ 487 | 1160, 488 | -880 489 | ], 490 | "id": "508d47c9-6ee8-493a-bd7d-5548730a10cb", 491 | "name": "OpenRouter Chat Model1", 492 | "credentials": { 493 | "openRouterApi": { 494 | "id": "lmQsStnMAVBZiYSe", 495 | "name": "OpenRouter account" 496 | } 497 | } 498 | } 499 | ], 500 | "pinData": {}, 501 | "connections": { 502 | "OpenRouter Chat Model": { 503 | "ai_languageModel": [ 504 | [ 505 | { 506 | "node": "Write Script", 507 | "type": "ai_languageModel", 508 | "index": 0 509 | } 510 | ] 511 | ] 512 | }, 513 | "Split Videos": { 514 | "main": [ 515 | [ 516 | { 517 | "node": "Download Video", 518 | "type": "main", 519 | "index": 0 520 | } 521 | ] 522 | ] 523 | }, 524 | "Download Video": { 525 | "main": [ 526 | [ 527 | { 528 | "node": "Save Video", 529 | "type": "main", 530 | "index": 0 531 | } 532 | ] 533 | ] 534 | }, 535 | "Write video idea": { 536 | "main": [ 537 | [ 538 | { 539 | "node": "Create Folder", 540 | "type": "main", 541 | "index": 0 542 | } 543 | ] 544 | ] 545 | }, 546 | "Create Folder": { 547 | "main": [ 548 | [ 549 | { 550 | "node": "Write Script", 551 | "type": "main", 552 | "index": 0 553 | } 554 | ] 555 | ] 556 | }, 557 | "Write Script": { 558 | "main": [ 559 | [ 560 | { 561 | "node": "Create Script", 562 | "type": "main", 563 | "index": 0 564 | }, 565 | { 566 | "node": "Create speech", 567 | "type": "main", 568 | "index": 0 569 | }, 570 | { 571 | "node": "Create Caption", 572 | "type": "main", 573 | "index": 0 574 | }, 575 | { 576 | "node": "Write image/video prompt", 577 | "type": "main", 578 | "index": 0 579 | } 580 | ] 581 | ] 582 | }, 583 | "Write image/video prompt": { 584 | "main": [ 585 | [ 586 | { 587 | "node": "Create AI Image", 588 | "type": "main", 589 | "index": 0 590 | }, 591 | { 592 | "node": "Creat AI Video", 593 | "type": "main", 594 | "index": 0 595 | }, 596 | { 597 | "node": "Search Videos on Pexel", 598 | "type": "main", 599 | "index": 0 600 | } 601 | ] 602 | ] 603 | }, 604 | "Create AI Image": { 605 | "main": [ 606 | [ 607 | { 608 | "node": "Get AI Image", 609 | "type": "main", 610 | "index": 0 611 | } 612 | ] 613 | ] 614 | }, 615 | "Get AI Image": { 616 | "main": [ 617 | [ 618 | { 619 | "node": "Save AI Image", 620 | "type": "main", 621 | "index": 0 622 | } 623 | ] 624 | ] 625 | }, 626 | "Creat AI Video": { 627 | "main": [ 628 | [ 629 | { 630 | "node": "Get AI Video", 631 | "type": "main", 632 | "index": 0 633 | } 634 | ] 635 | ] 636 | }, 637 | "Get AI Video": { 638 | "main": [ 639 | [ 640 | { 641 | "node": "Get URL", 642 | "type": "main", 643 | "index": 0 644 | } 645 | ] 646 | ] 647 | }, 648 | "Get URL": { 649 | "main": [ 650 | [ 651 | { 652 | "node": "Download AI Video", 653 | "type": "main", 654 | "index": 0 655 | } 656 | ] 657 | ] 658 | }, 659 | "Download AI Video": { 660 | "main": [ 661 | [ 662 | { 663 | "node": "Save AI Video", 664 | "type": "main", 665 | "index": 0 666 | } 667 | ] 668 | ] 669 | }, 670 | "Search Videos on Pexel": { 671 | "main": [ 672 | [ 673 | { 674 | "node": "Split Videos", 675 | "type": "main", 676 | "index": 0 677 | } 678 | ] 679 | ] 680 | }, 681 | "Create Script": { 682 | "main": [ 683 | [ 684 | { 685 | "node": "Save Script", 686 | "type": "main", 687 | "index": 0 688 | } 689 | ] 690 | ] 691 | }, 692 | "Save Script": { 693 | "main": [ 694 | [] 695 | ] 696 | }, 697 | "Create speech": { 698 | "main": [ 699 | [ 700 | { 701 | "node": "Save speech", 702 | "type": "main", 703 | "index": 0 704 | } 705 | ] 706 | ] 707 | }, 708 | "Create Caption": { 709 | "main": [ 710 | [ 711 | { 712 | "node": "Save Caption", 713 | "type": "main", 714 | "index": 0 715 | } 716 | ] 717 | ] 718 | }, 719 | "OpenRouter Chat Model1": { 720 | "ai_languageModel": [ 721 | [ 722 | { 723 | "node": "Write image/video prompt", 724 | "type": "ai_languageModel", 725 | "index": 0 726 | } 727 | ] 728 | ] 729 | } 730 | }, 731 | "active": false, 732 | "settings": { 733 | "executionOrder": "v1", 734 | "callerPolicy": "workflowsFromSameOwner", 735 | "saveDataErrorExecution": "none", 736 | "saveDataSuccessExecution": "none", 737 | "saveManualExecutions": false 738 | }, 739 | "versionId": "fa2da4c9-12b1-4e5e-bd86-c61f0b2ca108", 740 | "meta": { 741 | "templateCredsSetupCompleted": true, 742 | "instanceId": "dedc19d9bdfc7243f7ee13c48a4edef60ea52cfb037e9ca16e44a41bcd75a2d3" 743 | }, 744 | "id": "P9uM5z2NtH8aJwIN", 745 | "tags": [] 746 | } --------------------------------------------------------------------------------