Created
April 19, 2026 19:35
-
-
Save yuceltoluyag/2b08bff182d3b4df944b902ebbfde340 to your computer and use it in GitHub Desktop.
Revisions
-
yuceltoluyag created this gist
Apr 19, 2026 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,68 @@ services: baserow: image: baserow/baserow:1.32.5 container_name: baserow environment: - BASEROW_PUBLIC_URL=http://host.docker.internal:86 volumes: - D:\docker_sources\baserow-data:/baserow/data ports: - "86:80" restart: unless-stopped n8n: image: n8nio/n8n container_name: n8n volumes: - D:\docker_sources\n8n-data:/home/node/.n8n ports: - "5678:5678" restart: unless-stopped minio: image: quay.io/minio/minio:RELEASE.2025-04-22T22-12-26Z container_name: miniio ports: - "9000:9000" - "9001:9001" volumes: - D:\docker_sources\minio-data:/data environment: MINIO_ROOT_USER: admin MINIO_ROOT_PASSWORD: password123 command: server /data --console-address ":9001" kokoro-tts: image: ghcr.io/remsky/kokoro-fastapi-gpu:v0.2.2 container_name: kokoro-tts ports: - "8880:8880" runtime: nvidia environment: NVIDIA_VISIBLE_DEVICES: all nca-toolkit: image: stephengpope/no-code-architects-toolkit:latest container_name: nca-toolkit ports: - "8080:8080" environment: API_KEY: "thekey" S3_ENDPOINT_URL: "http://minio:9000" S3_ACCESS_KEY: "keykey" S3_SECRET_KEY: "keykey" S3_BUCKET_NAME: "nca-toolkit" S3_REGION: "None" GUNICORN_TIMEOUT: 0 GUNICORN_WORKERS: 2 deploy: resources: reservations: devices: - driver: nvidia count: 1 capabilities: [gpu] yt-dlp: image: jauderho/yt-dlp:latest container_name: yt-dlp entrypoint: ["tail", "-f", "/dev/null"] This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,477 @@ { "name": "Shorts Clip Extractor (MinIO Source)", "nodes": [ { "parameters": {}, "type": "n8n-nodes-base.manualTrigger", "typeVersion": 1, "position": [ 16, 96 ], "id": "ff8e0d15-9b3b-465d-9a0f-e2b49187400b", "name": "When clicking 'Execute workflow'" }, { "parameters": { "assignments": { "assignments": [ { "id": "src-video", "name": "source_video_url", "value": "http://host.docker.internal:9000/raw-videos/microsoft.mp4", "type": "string" }, { "id": "base_url", "name": "base_url", "value": "http://host.docker.internal:8080", "type": "string" }, { "id": "api_key", "name": "api_key", "value": "thekey", "type": "string" }, { "id": "lm_studio_url", "name": "lm_studio_url", "value": "http://host.docker.internal:1234/api/v1/chat", "type": "string" }, { "id": "lm_model", "name": "lm_model", "value": "google/gemma-4-e4b:2", "type": "string" }, { "id": "clip_count", "name": "clip_count", "value": 3, "type": "number" }, { "id": "clip_duration", "name": "clip_duration", "value": 60, "type": "number" } ] }, "options": {} }, "type": "n8n-nodes-base.set", "typeVersion": 3.4, "position": [ 320, 96 ], "id": "ffd82f79-0f97-45d7-a939-805b9070c131", "name": "Set Variables" }, { "parameters": { "method": "POST", "url": "={{ $('Set Variables').first().json.base_url }}/v1/media/transcribe", "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "x-api-key", "value": "={{ $('Set Variables').first().json.api_key }}" } ] }, "sendBody": true, "specifyBody": "json", "jsonBody": "={ \"media_url\": \"{{ $('Set Variables').first().json.source_video_url }}\", \"language\": \"tr\", \"include_segments\": true, \"word_timestamps\": false, \"response_type\": \"direct\" }", "options": { "timeout": 1800000 } }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 800, 96 ], "id": "d2ca2bfe-fd0b-415f-8d59-6c3fc0c8f638", "name": "Transcribe (Turkish)" }, { "parameters": { "jsCode": "const segments = $('Transcribe (Turkish)').first().json.response.segments;\nconst videoUrl = $('Set Variables').first().json.source_video_url;\n\n// Use all segments directly, no chunking - compact format for large transcripts\nconst transcriptText = segments.map((s, i) => `[${i}]${s.start.toFixed(0)}s: ${s.text}`).join(' ');\n\nconst prompt = `Viral video uzmanısın. Transkripsiyonu analiz et, en viral potansiyelli kısımları seç.\n\nKRITER: Duygusal etki, hikaye, paylaşılabilirlik.\n\nHer seçim için JSON objesi:\n{\"chunk_index\":id,\"start\":saniye,\"end\":saniye(start+60 max),\"viral_score\":1-10,\"reason\":\"kısa\",\"hook\":\"3sn\"}\n\nTRANSCRIPSYON:\n${transcriptText}\n\nSADECE JSON array döndür, başka hiçbir şey yazma.`;\n\n// Create 60s chunks for post-analysis reference\nconst chunkSize = 60;\nconst chunks = [];\nlet currentChunk = { start: null, end: null, texts: [] };\nsegments.forEach(seg => {\n if (currentChunk.start === null) {\n currentChunk.start = seg.start;\n currentChunk.end = seg.end;\n currentChunk.texts.push(seg.text);\n } else if (seg.end - currentChunk.start <= chunkSize) {\n currentChunk.end = seg.end;\n currentChunk.texts.push(seg.text);\n } else {\n chunks.push({ start: currentChunk.start, end: currentChunk.end, text: currentChunk.texts.join(' ').trim() });\n currentChunk = { start: seg.start, end: seg.end, texts: [seg.text] };\n }\n});\nif (currentChunk.texts.length > 0) chunks.push({ start: currentChunk.start, end: currentChunk.end, text: currentChunk.texts.join(' ').trim() });\n\nreturn [{ json: { prompt, chunks, video_url: videoUrl } }];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 1040, 96 ], "id": "3264e21c-506f-47bf-8f60-dbed5579fb98", "name": "Prepare AI Analysis Prompt" }, { "parameters": { "method": "POST", "url": "={{ $('Set Variables').first().json.lm_studio_url }}", "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Content-Type", "value": "application/json" } ] }, "sendBody": true, "specifyBody": "json", "jsonBody": "={{ JSON.stringify({ model: $('Set Variables').first().json.lm_model, system_prompt: 'You are a YouTube viral content expert. Output ONLY valid JSON.', input: $json.prompt, stream: false}) }}", "options": { "timeout": 300000 } }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 1280, 96 ], "id": "55bdd894-f250-4ac7-8ced-b079aa6ff12f", "name": "🤖 LM Studio - Viral Clip Analysis" }, { "parameters": { "jsCode": "const lmResponse = $('🤖 LM Studio - Viral Clip Analysis').first().json;\n\n// Extract AI response text from Gemma format\nlet aiResponse = '';\nif (lmResponse.output && Array.isArray(lmResponse.output)) {\n const msgObj = lmResponse.output.find(o => o.type === 'message');\n if (msgObj) aiResponse = msgObj.content;\n}\nif (!aiResponse) {\n aiResponse = lmResponse.message?.content || lmResponse.choices?.[0]?.message?.content || lmResponse.response || lmResponse.content || '';\n}\n\n// Strip markdown code fences if present\naiResponse = aiResponse.replace(/^```(?:json)?\\n?([\\s\\S]*?)\\n?```$/gm, '$1').trim();\n\nconst videoUrl = $('Prepare AI Analysis Prompt').first().json.video_url;\nconst segments = $('Transcribe (Turkish)').first().json.response.segments;\nconst clipCount = $('Set Variables').first().json.clip_count;\nconst clipDuration = $('Set Variables').first().json.clip_duration;\n\nlet scoredClips;\ntry {\n const jsonMatch = aiResponse.match(/\\[[\\s\\S]*\\]/);\n if (jsonMatch) {\n scoredClips = JSON.parse(jsonMatch[0]);\n } else {\n const parsed = JSON.parse(aiResponse);\n scoredClips = parsed.clips || parsed.results || [parsed];\n }\n} catch (e) {\n throw new Error('AI response parsing failed: ' + e.message + '\\n\\nRaw response: ' + aiResponse);\n}\n\nconst topClips = scoredClips\n .sort((a, b) => (b.viral_score || 0) - (a.viral_score || 0))\n .slice(0, clipCount)\n .map(clip => {\n const startTime = clip.start;\n const actualEnd = Math.min(clip.end || startTime + clipDuration, startTime + clipDuration);\n const closestSeg = segments.find(s => Math.abs(s.start - startTime) < 2);\n const textPreview = closestSeg?.text?.substring(0, 100) || 'N/A';\n return {\n start_time: startTime,\n end_time: actualEnd,\n viral_score: clip.viral_score,\n reason: clip.reason,\n hook: clip.hook,\n text_preview: textPreview\n };\n });\n\nreturn [{ json: { clips: topClips, video_url: videoUrl, total_analyzed: segments.length, ai_recommendations: topClips.length } }];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 1520, 96 ], "id": "9c069345-c7c8-46b3-9438-e3f38c9cbb88", "name": "Parse AI Results & Select Clips" }, { "parameters": { "fieldToSplitOut": "clips", "options": {} }, "type": "n8n-nodes-base.splitOut", "typeVersion": 1, "position": [ 1760, 96 ], "id": "5f74d6a4-0469-402b-86f5-60d5dc4d4b9d", "name": "Split Clips" }, { "parameters": { "method": "POST", "url": "={{ $('Set Variables').first().json.base_url }}/v1/ffmpeg/compose", "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "x-api-key", "value": "={{ $('Set Variables').first().json.api_key }}" } ] }, "sendBody": true, "specifyBody": "json", "jsonBody": "={{ JSON.stringify({ inputs: [{ file_url: $('Set Variables').first().json.source_video_url }], outputs: [{ options: [{ option: '-ss', argument: String($json.start_time) }, { option: '-t', argument: String($json.end_time - $json.start_time) }, { option: '-c:v', argument: 'libx264' }, { option: '-preset', argument: 'fast' }, { option: '-crf', argument: '23' }, { option: '-c:a', argument: 'aac' }] }], id: 'extract-clip-' + $json.start_time.toFixed(0) }) }}", "options": { "timeout": 600000 } }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 2000, 96 ], "id": "c025a7ae-b234-4ee0-907f-2622e65b535a", "name": "Extract AI-Selected Clip" }, { "parameters": { "method": "POST", "url": "={{ $('Set Variables').first().json.base_url }}/v1/ffmpeg/compose", "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "x-api-key", "value": "={{ $('Set Variables').first().json.api_key }}" } ] }, "sendBody": true, "specifyBody": "json", "jsonBody": "={\n \"inputs\": [\n {\n \"file_url\": \"{{ $json.response[0].file_url }}\"\n }\n ],\n \"filters\": [\n {\n \"filter\": \"crop=w=ih*9/16:h=ih\"\n }\n ],\n \"outputs\": [\n {\n \"options\": [\n {\n \"option\": \"-c:v\",\n \"argument\": \"libx264\"\n },\n {\n \"option\": \"-preset\",\n \"argument\": \"fast\"\n },\n {\n \"option\": \"-crf\",\n \"argument\": \"23\"\n },\n {\n \"option\": \"-c:a\",\n \"argument\": \"aac\"\n }\n ]\n }\n ],\n \"id\": \"resize-clip-{{ $now.format('x') }}\"\n}", "options": { "timeout": 600000 } }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 2240, 96 ], "id": "3075182b-f738-45c6-a671-fcb92513e46b", "name": "Resize to 9:16 (Shorts)" }, { "parameters": { "method": "POST", "url": "={{ $('Set Variables').first().json.base_url }}/v1/video/caption", "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "x-api-key", "value": "={{ $('Set Variables').first().json.api_key }}" } ] }, "sendBody": true, "specifyBody": "json", "jsonBody": "={\n \"video_url\": \"{{ $('Resize to 9:16 (Shorts)').first().json.response[0].file_url }}\",\n \"language\": \"tr\",\n \"settings\": {\n \"line_color\": \"#FFFFFF\",\n \"word_color\": \"#FFD700\",\n \"all_caps\": false,\n \"max_words_per_line\": 3,\n \"font_size\": 50,\n \"bold\": true,\n \"italic\": false,\n \"underline\": false,\n \"strikeout\": false,\n \"outline_width\": 3,\n \"shadow_offset\": 4,\n \"style\": \"highlight\",\n \"font_family\": \"The Bold Font\",\n \"position\": \"bottom_center\"\n },\n \"id\": \"ai-caption-{{ $now.format('x') }}\"\n}\n", "options": { "timeout": 600000 } }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 2480, 96 ], "id": "6e153e6b-f539-4e3c-828c-54aeb9c65187", "name": "Add Turkish Captions" }, { "parameters": { "jsCode": "const allClips = $('Split Clips').all();\nconst finalClips = allClips.map((clip, idx) => ({\n clip_number: idx + 1,\n start_time: clip.json.start_time.toFixed(1) + 's',\n end_time: clip.json.end_time.toFixed(1) + 's',\n duration: (clip.json.end_time - clip.json.start_time).toFixed(1) + 's',\n viral_score: clip.json.viral_score,\n ai_reason: clip.json.reason,\n ai_hook: clip.json.hook,\n final_url: clip.json.response\n}));\n\nreturn [{\n json: {\n total_clips: finalClips.length,\n clips: finalClips,\n summary: `🤖 AI ${finalClips.length} viral clip seçti ve işledi`,\n ai_analysis_complete: true\n }\n}];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 2720, 96 ], "id": "5f327ec5-4ac0-4b2b-a0a9-ff28f8ff502b", "name": "Compile Final Results" }, { "parameters": { "content": "## 1️⃣ Configuration", "height": 300, "width": 480, "color": 3 }, "type": "n8n-nodes-base.stickyNote", "position": [ 192, -16 ], "typeVersion": 1, "id": "25e042c1-d7ac-418e-8b32-c7a79d48966d", "name": "Sticky Note" }, { "parameters": { "content": "## 2️⃣ Transcribe & AI Analysis", "height": 300, "width": 480, "color": 6 }, "type": "n8n-nodes-base.stickyNote", "position": [ 672, -16 ], "typeVersion": 1, "id": "d6583361-cd80-482d-adf0-2a1a4e3a5799", "name": "Sticky Note1" }, { "parameters": { "content": "## 3️⃣ AI Analysis (LM Studio)", "height": 300, "width": 720, "color": 4 }, "type": "n8n-nodes-base.stickyNote", "position": [ 1152, -16 ], "typeVersion": 1, "id": "08eda9fd-4d97-4f80-b15c-83907d19a8b1", "name": "Sticky Note2" }, { "parameters": { "content": "## 4️⃣ Cut & Resize", "height": 300, "width": 480, "color": 2 }, "type": "n8n-nodes-base.stickyNote", "position": [ 1872, -16 ], "typeVersion": 1, "id": "6e57ae8e-4950-42e0-ab48-746982446d8f", "name": "Sticky Note3" }, { "parameters": { "content": "## 5️⃣ Caption & Export", "height": 300, "width": 720, "color": 5 }, "type": "n8n-nodes-base.stickyNote", "position": [ 2352, -16 ], "typeVersion": 1, "id": "9c74c44f-d3a9-4bf0-afe6-f1955fb341c0", "name": "Sticky Note4" } ], "pinData": {}, "connections": { "When clicking 'Execute workflow'": { "main": [ [ { "node": "Set Variables", "type": "main", "index": 0 } ] ] }, "Set Variables": { "main": [ [ { "node": "Transcribe (Turkish)", "type": "main", "index": 0 } ] ] }, "Transcribe (Turkish)": { "main": [ [ { "node": "Prepare AI Analysis Prompt", "type": "main", "index": 0 } ] ] }, "Prepare AI Analysis Prompt": { "main": [ [ { "node": "🤖 LM Studio - Viral Clip Analysis", "type": "main", "index": 0 } ] ] }, "🤖 LM Studio - Viral Clip Analysis": { "main": [ [ { "node": "Parse AI Results & Select Clips", "type": "main", "index": 0 } ] ] }, "Parse AI Results & Select Clips": { "main": [ [ { "node": "Split Clips", "type": "main", "index": 0 } ] ] }, "Split Clips": { "main": [ [ { "node": "Extract AI-Selected Clip", "type": "main", "index": 0 } ] ] }, "Extract AI-Selected Clip": { "main": [ [ { "node": "Resize to 9:16 (Shorts)", "type": "main", "index": 0 } ] ] }, "Resize to 9:16 (Shorts)": { "main": [ [ { "node": "Add Turkish Captions", "type": "main", "index": 0 } ] ] }, "Add Turkish Captions": { "main": [ [ { "node": "Compile Final Results", "type": "main", "index": 0 } ] ] } }, "active": false, "settings": { "executionOrder": "v1", "binaryMode": "separate" }, "versionId": "71c5ff7a-5398-4ccc-a34e-53de75a3deaa", "meta": { "instanceId": "72d749b030d64f8213e78d4219c14df0cf533645d20a7f66d7ed1a0d670713e2" }, "id": "xBgTD4eDTXe2FUau", "tags": [] } This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,137 @@ 🛠️ **Toollarımız - Kurulum Rehberi** Bu rehber, tüm araçlarımızı kolayca kurabilmeniz için hazırlanmıştır. ### Ön Gereksinim Başlamadan önce **[Docker Desktop](https://www.docker.com/products/docker-desktop/)**’u bilgisayarınıza indirip kurun. Tüm araçları Docker üzerinden çalıştıracağız. --- ### ✅ Adım 1: Docker Desktop Kurulumu 1. [Bu adresten](https://www.docker.com/products/docker-desktop/) Docker Desktop’u indirin. 2. Karşınıza çıkan kurulum adımlarını takip ederek kurulumu tamamlayın. 3. Docker Desktop’un çalıştığından emin olun. > Kurulum konusunda yardıma ihtiyacınız olursa şu videoyu izleyebilirsiniz: > [Docker Desktop Kurulum Videosu](https://yuceltoluyag.github.io/arch-linux-docker-kurulumu/) --- ### 📦 Adım 2: Araçları Docker ile Çalıştırma Aşağıdaki tüm araçlar Docker container olarak çalışır. Bilgisayarınıza normal program kurmaktan hiçbir farkı yoktur. #### 🔄 **n8n (Automation Tool)** ```bash docker run -d --name n8n \ -p 5678:5678 \ -e WEBHOOK_URL=http://host.docker.internal:5678 \ -e N8N_DEFAULT_BINARY_DATA_MODE=filesystem \ -v C:\Docker\n8n-data:/home/node/.n8n \ docker.n8n.io/n8nio/n8n ``` **Not:** VPS veya farklı bir adresten erişecekseniz `WEBHOOK_URL` kısmını kendi adresinize göre değiştirin. --- #### 💾 **MiniIO (Depolama)** > **Önemli:** En son sürümü değil, aşağıdaki stabil sürümü kullanmanızı öneririz. ```bash docker run -p 9000:9000 -p 9001:9001 --name miniio \ -v C:\Docker\minio-data:/data \ -e MINIO_ROOT_USER=admin \ -e MINIO_ROOT_PASSWORD=password123 \ quay.io/minio/minio:RELEASE.2025-04-22T22-12-26Z server /data --console-address ":9001" ``` **Konsola Erişim:** - **Adres:** [http://localhost:9001](http://localhost:9001/) - **Username:** `admin` - **Password:** `password123` **Sonraki Adımlar:** 1. Digital Yörük kanalındaki MiniIO kurulum videosunu izleyin. 2. MiniIO arayüzüne giriş yapın. 3. `nca-toolkit` adında bir **bucket** oluşturun. 4. Oluşturduğunuz **Access Key** ve **Secret Key** değerlerini bir yere kaydedin (NCA Toolkit kurarken gerekecek). --- #### 🗣️ **Kokoro TTS (Text-to-Speech)** **GPU’lu Sistemler için (önerilen):** ```bash docker run -d --gpus all -p 8880:8880 --name kokoro-tts \ ghcr.io/remsky/kokoro-fastapi-gpu:v0.2.2 ``` **Sadece CPU için:** ```bash docker run -p 8880:8880 --name kokoro-tts-cpu \ ghcr.io/remsky/kokoro-fastapi-cpu:v0.2.2 ``` --- #### 📋 **Baserow (Veritabanı Arayüzü)** ```bash docker run -d --name baserow \ -e BASEROW_PUBLIC_URL=http://host.docker.internal:85 \ -v C:\Docker\baserow-data:/baserow/data \ -p 85:80 -p 443:443 \ --restart unless-stopped \ --shm-size=256mb \ baserow/baserow:1.34.2 ``` --- ### 🚀 Adım 3: NCA Toolkit Kurulumu MiniIO hazır ve keylerinizi aldıysanız NCA Toolkit’i kurabilirsiniz: ```bash docker run -d -p 8080:8080 --name nca-toolkit \ -e API_KEY=thekey \ -e S3_ENDPOINT_URL=http://host.docker.internal:9000 \ -e S3_ACCESS_KEY=your_access_key \ -e S3_SECRET_KEY=your_secret_key \ -e S3_BUCKET_NAME=nca-toolkit \ -e S3_REGION=None \ stephengpope/no-code-architects-toolkit:latest ``` > `your_access_key` ve `your_secret_key` değerlerini MiniIO’dan aldığınız bilgilerle değiştirin. --- ### ✅ Hazırsınız! Aşağıdaki adreslerden araçlarınıza erişebilirsiniz: | Service | URL | |---------------|------------------------------------------| | **n8n** | [http://host.docker.internal:5678](http://host.docker.internal:5678/) | | **MiniIO** | [http://host.docker.internal:9001](http://localhost:9001/) | | **Kokoro TTS**| [http://host.docker.internal:8880/web](http://host.docker.internal:8880/web) | | **Baserow** | [http://host.docker.internal:85](http://host.docker.internal:85/) | | **NCA Toolkit**| [http://host.docker.internal:8080](http://host.docker.internal:8080/) | **Not:** NCA Toolkit’in görsel bir arayüzü yoktur. GitHub sayfası üzerinden API endpoint’lerini ve açıklamalarını inceleyebilirsiniz. --- **Ekstra:** - [Arch Linux'ta Ollama ve WebUI Kurulumu](https://yuceltoluyag.github.io/arch-linux-ollama-webui-kurulumu-docker/)