Ava2lon commited on
Commit
43b10b4
·
verified ·
1 Parent(s): e10b026

Upload 10 files

Browse files
Files changed (10) hide show
  1. .dockerignore +15 -0
  2. .env.example +87 -0
  3. .gitignore +14 -0
  4. Dockerfile +64 -7
  5. Dockerfile.full +78 -0
  6. Dockerfile.gateway +44 -0
  7. README.md +772 -5
  8. docker-compose.yml +69 -0
  9. requirements-gateway.txt +4 -0
  10. requirements.txt +10 -10
.dockerignore ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .git
2
+ **/.git
3
+ **/__pycache__
4
+ **/*.pyc
5
+ **/.pytest_cache
6
+ **/.mypy_cache
7
+ **/.ruff_cache
8
+ .env
9
+ data
10
+ services/render_engine/exports
11
+ services/render_engine/jobs
12
+ services/render_engine/temp
13
+ services/render_engine/storage
14
+ services/ffmpeg_automation/temp
15
+ services/whisper/jobs
.env.example ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Required in production. Generate a long random value.
2
+ MAESTER_API_KEY=
3
+
4
+ MAESTER_ENV=production
5
+ MAESTER_CPU_SAFE_MODE=true
6
+ MAESTER_MOUNT_SERVICES=true
7
+ MAESTER_ALLOW_PUBLIC_DOCS=false
8
+ MAESTER_REQUEST_BODY_LIMIT_BYTES=1073741824
9
+ MAESTER_RATE_LIMIT_PER_MINUTE=120
10
+ MAESTER_SERVICE_TIMEOUT_SECONDS=1800
11
+
12
+ # Toggle individual embedded services.
13
+ # All services are enabled by default. CPU-focused env settings keep workers constrained.
14
+ MAESTER_ENABLE_KTTS=true
15
+ MAESTER_ENABLE_MUSICGEN=true
16
+ MAESTER_ENABLE_WHISPER=true
17
+ MAESTER_ENABLE_FFMPEG_AUTOMATION=true
18
+ MAESTER_ENABLE_RENDER_ENGINE=true
19
+
20
+ # Whisper/auth integrations. Required only if enabling Whisper auth and publishing features.
21
+ SECRET_KEY=
22
+ DATABASE_URL=
23
+ GOOGLE_CLIENT_ID=
24
+ GOOGLE_CLIENT_SECRET=
25
+ META_APP_ID=
26
+ META_APP_SECRET=
27
+ TIKTOK_CLIENT_KEY=
28
+ TIKTOK_CLIENT_SECRET=
29
+
30
+ # Render engine security.
31
+ AVA2LON_SIGNING_SECRET=
32
+ BASYX_SIGNING_SECRET=
33
+ AVA2LON_API_KEY=
34
+ BASYX_API_KEY=
35
+ ALLOW_PRIVATE_ASSET_URLS=false
36
+ MAX_DOWNLOAD_BYTES=524288000
37
+ DOWNLOAD_TIMEOUT_SECONDS=60
38
+ FFMPEG_TIMEOUT_SECONDS=900
39
+ MAX_RENDER_WORKERS=1
40
+ WHISPER_DEVICE=cpu
41
+ WHISPER_COMPUTE_TYPE=int8
42
+ WHISPER_MODEL_SIZE=tiny
43
+ CUDA_VISIBLE_DEVICES=
44
+ TOKENIZERS_PARALLELISM=false
45
+ OMP_NUM_THREADS=1
46
+ MKL_NUM_THREADS=1
47
+ NUMEXPR_MAX_THREADS=1
48
+
49
+ # Hugging Face integrations.
50
+ HF_TOKEN=
51
+
52
+ # n8n orchestration.
53
+ # N8N_ENCRYPTION_KEY must stay stable after first startup or saved n8n credentials cannot be decrypted.
54
+ N8N_ENCRYPTION_KEY=
55
+ N8N_HOST=localhost
56
+ N8N_PORT=5678
57
+ N8N_PROTOCOL=http
58
+ N8N_WEBHOOK_URL=http://localhost:5678/
59
+ GENERIC_TIMEZONE=UTC
60
+
61
+ # Provider keys used by importable n8n workflows.
62
+ AI_PROVIDER=openai
63
+ LLM_PROVIDER=openai
64
+ LLM_MODEL=gpt-4o-mini
65
+
66
+ OPENAI_API_KEY=
67
+ OPENAI_BASE_URL=https://api.openai.com/v1
68
+ OPENAI_MODEL=gpt-4o-mini
69
+
70
+ GEMINI_API_KEY=
71
+ GEMINI_BASE_URL=https://generativelanguage.googleapis.com/v1beta
72
+ GEMINI_MODEL=gemini-1.5-flash
73
+
74
+ OPENROUTER_API_KEY=
75
+ OPENROUTER_BASE_URL=https://openrouter.ai/api/v1
76
+ OPENROUTER_MODEL=openai/gpt-4o-mini
77
+ OPENROUTER_SITE_URL=http://localhost:5678
78
+ OPENROUTER_APP_NAME="Maester Enterprise"
79
+
80
+ PEXELS_API_KEY=
81
+ KTTS_MODEL=kokoro-v0_19.onnx
82
+ KTTS_VOICE=af_bella.pt
83
+ TELEGRAM_BOT_TOKEN=
84
+ TELEGRAM_CHAT_ID=
85
+ GOOGLE_SHEETS_WEBHOOK_URL=
86
+ TIKTOK_UPLOAD_ENABLED=false
87
+ TIKTOK_ACCESS_TOKEN=
.gitignore ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .env
2
+ .venv/
3
+ __pycache__/
4
+ *.py[cod]
5
+ .pytest_cache/
6
+ .mypy_cache/
7
+ .ruff_cache/
8
+ data/
9
+ services/render_engine/exports/
10
+ services/render_engine/jobs/
11
+ services/render_engine/temp/
12
+ services/render_engine/storage/
13
+ services/ffmpeg_automation/temp/
14
+ services/whisper/jobs/
Dockerfile CHANGED
@@ -1,21 +1,78 @@
1
- FROM python:3.10-slim
2
 
3
- WORKDIR /app
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
 
5
- # System deps
6
- RUN apt-get update && apt-get install -y \
 
 
7
  git \
 
 
 
8
  ffmpeg \
 
 
 
9
  libsndfile1 \
 
 
 
 
 
10
  && rm -rf /var/lib/apt/lists/*
11
 
 
 
12
  COPY requirements.txt .
 
 
 
 
 
13
 
14
- RUN pip install --upgrade pip
15
- RUN pip install --no-cache-dir -r requirements.txt
16
 
17
  COPY . .
18
 
 
 
 
19
  EXPOSE 7860
20
 
21
- CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
 
1
+ FROM python:3.11-slim
2
 
3
+ ENV PYTHONUNBUFFERED=1 \
4
+ PIP_NO_CACHE_DIR=1 \
5
+ MAESTER_BASE_DIR=/app \
6
+ MAESTER_DATA_DIR=/app/data \
7
+ MAESTER_ENV=production \
8
+ MAESTER_CPU_SAFE_MODE=true \
9
+ MAESTER_MOUNT_SERVICES=true \
10
+ MAESTER_ALLOW_PUBLIC_DOCS=false \
11
+ MAESTER_ENABLE_KTTS=true \
12
+ MAESTER_ENABLE_MUSICGEN=true \
13
+ MAESTER_ENABLE_WHISPER=true \
14
+ MAESTER_ENABLE_FFMPEG_AUTOMATION=true \
15
+ MAESTER_ENABLE_RENDER_ENGINE=true \
16
+ TEMP_DIR=/app/data/temp \
17
+ EXPORTS_DIR=/app/data/exports \
18
+ JOBS_DIR=/app/data/jobs \
19
+ STORAGE_DIR=/app/data/storage \
20
+ AVA2LON_BASE_DIR=/app/services/render_engine \
21
+ BASYX_BASE_DIR=/app/services/render_engine \
22
+ WHISPER_MODEL_DIR=/app/data/models \
23
+ WHISPER_DEVICE=cpu \
24
+ WHISPER_COMPUTE_TYPE=int8 \
25
+ WHISPER_MODEL_SIZE=tiny \
26
+ MAX_RENDER_WORKERS=1 \
27
+ FFMPEG_TIMEOUT_SECONDS=900 \
28
+ DOWNLOAD_TIMEOUT_SECONDS=60 \
29
+ MAX_DOWNLOAD_BYTES=524288000 \
30
+ ALLOW_PRIVATE_ASSET_URLS=false \
31
+ CUDA_VISIBLE_DEVICES="" \
32
+ TOKENIZERS_PARALLELISM=false \
33
+ OMP_NUM_THREADS=1 \
34
+ MKL_NUM_THREADS=1 \
35
+ NUMEXPR_MAX_THREADS=1 \
36
+ HF_HOME=/app/data/huggingface \
37
+ TRANSFORMERS_CACHE=/app/data/huggingface/transformers
38
 
39
+ RUN apt-get update && apt-get install -y --no-install-recommends \
40
+ build-essential \
41
+ gcc \
42
+ g++ \
43
  git \
44
+ curl \
45
+ wget \
46
+ ca-certificates \
47
  ffmpeg \
48
+ espeak \
49
+ imagemagick \
50
+ libmagic1 \
51
  libsndfile1 \
52
+ libpq-dev \
53
+ fonts-dejavu-core \
54
+ libsm6 \
55
+ libxext6 \
56
+ libglib2.0-0 \
57
  && rm -rf /var/lib/apt/lists/*
58
 
59
+ WORKDIR /app
60
+
61
  COPY requirements.txt .
62
+ COPY services/ktts/requirements.txt services/ktts/requirements.txt
63
+ COPY services/musicgen/requirements.txt services/musicgen/requirements.txt
64
+ COPY services/whisper/requirements.txt services/whisper/requirements.txt
65
+ COPY services/ffmpeg_automation/requirements.txt services/ffmpeg_automation/requirements.txt
66
+ COPY services/render_engine/requirements.txt services/render_engine/requirements.txt
67
 
68
+ RUN pip install --upgrade pip setuptools wheel \
69
+ && pip install --no-cache-dir -r requirements.txt
70
 
71
  COPY . .
72
 
73
+ RUN mkdir -p /app/data/uploads /app/data/exports /app/data/jobs /app/data/logs /app/data/models /app/data/temp /app/data/storage /app/data/automation /app/data/huggingface \
74
+ && chmod -R 775 /app/data
75
+
76
  EXPOSE 7860
77
 
78
+ CMD ["uvicorn", "maester_enterprise.main:app", "--host", "0.0.0.0", "--port", "7860"]
Dockerfile.full ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.11-slim
2
+
3
+ ENV PYTHONUNBUFFERED=1 \
4
+ PIP_NO_CACHE_DIR=1 \
5
+ MAESTER_BASE_DIR=/app \
6
+ MAESTER_DATA_DIR=/app/data \
7
+ MAESTER_ENV=production \
8
+ MAESTER_CPU_SAFE_MODE=true \
9
+ MAESTER_MOUNT_SERVICES=true \
10
+ MAESTER_ALLOW_PUBLIC_DOCS=false \
11
+ MAESTER_ENABLE_KTTS=true \
12
+ MAESTER_ENABLE_MUSICGEN=true \
13
+ MAESTER_ENABLE_WHISPER=true \
14
+ MAESTER_ENABLE_FFMPEG_AUTOMATION=true \
15
+ MAESTER_ENABLE_RENDER_ENGINE=true \
16
+ TEMP_DIR=/app/data/temp \
17
+ EXPORTS_DIR=/app/data/exports \
18
+ JOBS_DIR=/app/data/jobs \
19
+ STORAGE_DIR=/app/data/storage \
20
+ AVA2LON_BASE_DIR=/app/services/render_engine \
21
+ BASYX_BASE_DIR=/app/services/render_engine \
22
+ WHISPER_MODEL_DIR=/app/data/models \
23
+ WHISPER_DEVICE=cpu \
24
+ WHISPER_COMPUTE_TYPE=int8 \
25
+ WHISPER_MODEL_SIZE=tiny \
26
+ MAX_RENDER_WORKERS=1 \
27
+ FFMPEG_TIMEOUT_SECONDS=900 \
28
+ DOWNLOAD_TIMEOUT_SECONDS=60 \
29
+ MAX_DOWNLOAD_BYTES=524288000 \
30
+ ALLOW_PRIVATE_ASSET_URLS=false \
31
+ CUDA_VISIBLE_DEVICES="" \
32
+ TOKENIZERS_PARALLELISM=false \
33
+ OMP_NUM_THREADS=1 \
34
+ MKL_NUM_THREADS=1 \
35
+ NUMEXPR_MAX_THREADS=1 \
36
+ HF_HOME=/app/data/huggingface \
37
+ TRANSFORMERS_CACHE=/app/data/huggingface/transformers
38
+
39
+ RUN apt-get update && apt-get install -y --no-install-recommends \
40
+ build-essential \
41
+ gcc \
42
+ g++ \
43
+ git \
44
+ curl \
45
+ wget \
46
+ ca-certificates \
47
+ ffmpeg \
48
+ espeak \
49
+ imagemagick \
50
+ libmagic1 \
51
+ libsndfile1 \
52
+ libpq-dev \
53
+ fonts-dejavu-core \
54
+ libsm6 \
55
+ libxext6 \
56
+ libglib2.0-0 \
57
+ && rm -rf /var/lib/apt/lists/*
58
+
59
+ WORKDIR /app
60
+
61
+ COPY requirements.txt .
62
+ COPY services/ktts/requirements.txt services/ktts/requirements.txt
63
+ COPY services/musicgen/requirements.txt services/musicgen/requirements.txt
64
+ COPY services/whisper/requirements.txt services/whisper/requirements.txt
65
+ COPY services/ffmpeg_automation/requirements.txt services/ffmpeg_automation/requirements.txt
66
+ COPY services/render_engine/requirements.txt services/render_engine/requirements.txt
67
+
68
+ RUN pip install --upgrade pip setuptools wheel \
69
+ && pip install --no-cache-dir -r requirements.txt
70
+
71
+ COPY . .
72
+
73
+ RUN mkdir -p /app/data/uploads /app/data/exports /app/data/jobs /app/data/logs /app/data/models /app/data/temp /app/data/storage /app/data/automation /app/data/huggingface \
74
+ && chmod -R 775 /app/data
75
+
76
+ EXPOSE 7860
77
+
78
+ CMD ["uvicorn", "maester_enterprise.main:app", "--host", "0.0.0.0", "--port", "7860"]
Dockerfile.gateway ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.11-slim
2
+
3
+ ENV PYTHONUNBUFFERED=1 \
4
+ PIP_NO_CACHE_DIR=1 \
5
+ MAESTER_BASE_DIR=/app \
6
+ MAESTER_DATA_DIR=/app/data \
7
+ MAESTER_ENV=production \
8
+ MAESTER_CPU_SAFE_MODE=true \
9
+ MAESTER_MOUNT_SERVICES=false \
10
+ MAESTER_ALLOW_PUBLIC_DOCS=false \
11
+ MAESTER_ENABLE_KTTS=false \
12
+ MAESTER_ENABLE_MUSICGEN=false \
13
+ MAESTER_ENABLE_WHISPER=false \
14
+ MAESTER_ENABLE_FFMPEG_AUTOMATION=false \
15
+ MAESTER_ENABLE_RENDER_ENGINE=false \
16
+ TEMP_DIR=/app/data/temp \
17
+ EXPORTS_DIR=/app/data/exports \
18
+ JOBS_DIR=/app/data/jobs \
19
+ STORAGE_DIR=/app/data/storage \
20
+ WHISPER_DEVICE=cpu \
21
+ WHISPER_COMPUTE_TYPE=int8 \
22
+ WHISPER_MODEL_SIZE=tiny \
23
+ MAX_RENDER_WORKERS=1
24
+
25
+ RUN apt-get update && apt-get install -y --no-install-recommends \
26
+ curl \
27
+ ca-certificates \
28
+ && rm -rf /var/lib/apt/lists/*
29
+
30
+ WORKDIR /app
31
+
32
+ COPY requirements-gateway.txt .
33
+ RUN pip install --upgrade pip setuptools wheel \
34
+ && pip install --no-cache-dir -r requirements-gateway.txt
35
+
36
+ COPY maester_enterprise maester_enterprise
37
+ COPY README.md README.md
38
+
39
+ RUN mkdir -p /app/data/uploads /app/data/exports /app/data/jobs /app/data/logs /app/data/models /app/data/temp /app/data/storage /app/data/automation \
40
+ && chmod -R 775 /app/data
41
+
42
+ EXPOSE 7860
43
+
44
+ CMD ["uvicorn", "maester_enterprise.main:app", "--host", "0.0.0.0", "--port", "7860"]
README.md CHANGED
@@ -1,10 +1,777 @@
1
  ---
2
- title: MusicGen
3
- emoji: 📚
4
- colorFrom: indigo
5
- colorTo: blue
6
  sdk: docker
 
7
  pinned: false
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: Maester Enterprise
3
+ emoji: 🎬
4
+ colorFrom: blue
5
+ colorTo: green
6
  sdk: docker
7
+ app_port: 7860
8
  pinned: false
9
+ license: mit
10
  ---
11
 
12
+ # Maester Enterprise
13
+
14
+ Maester Enterprise merges the five existing projects into one deployable workspace:
15
+
16
+ - `services/ktts`: Kokoro ONNX text-to-speech
17
+ - `services/musicgen`: MusicGen audio generation
18
+ - `services/whisper`: Whisper operator, clipping, publishing, and automation
19
+ - `services/ffmpeg_automation`: FFmpeg task hub
20
+ - `services/render_engine`: Ava2lon/Basyx rendering engine
21
+
22
+ The new enterprise gateway lives in `maester_enterprise/` and mounts each service under one secured FastAPI app.
23
+
24
+ ## Service Routes
25
+
26
+ | Service | Route |
27
+ | --- | --- |
28
+ | Gateway health | `/health` |
29
+ | Gateway readiness | `/ready` |
30
+ | Service catalog | `/services` |
31
+ | KTTS | `/services/ktts` |
32
+ | MusicGen | `/services/musicgen` |
33
+ | Whisper | `/services/whisper` |
34
+ | FFmpeg automation | `/services/ffmpeg` |
35
+ | Render engine | `/services/render` |
36
+ | Automation API | `/automation` |
37
+
38
+ All non-public routes require `X-API-Key: <MAESTER_API_KEY>` in production.
39
+
40
+ ## Enterprise Upgrades Added
41
+
42
+ - Single gateway for all services
43
+ - Shared API-key enforcement
44
+ - Shared rate limiting
45
+ - Request body size limits
46
+ - Request IDs and security headers
47
+ - Runtime directory isolation under `/app/data`
48
+ - Service catalog and readiness endpoint
49
+ - Per-service enable/disable environment flags
50
+ - Docker and Docker Compose deployment files
51
+ - `.env.example` for required secrets and integrations
52
+ - Campaign, brand kit, approval, calendar, publishing, analytics, and A/B testing APIs
53
+ - Hugging Face CPU-focused default Dockerfile with all services enabled
54
+
55
+ ## Automation Features
56
+
57
+ The `/automation` API adds the short-form production layer for TikTok, Instagram Reels, Facebook Shorts, and YouTube Shorts.
58
+
59
+ | Feature | Endpoint |
60
+ | --- | --- |
61
+ | Capability map | `GET /automation/capabilities` |
62
+ | Brand kits | `POST /automation/brand-kits`, `GET /automation/brand-kits` |
63
+ | Create campaign | `POST /automation/campaigns` |
64
+ | Create and generate variants | `POST /automation/campaigns/generate` |
65
+ | Generate variants for existing campaign | `POST /automation/campaigns/{campaign_id}/generate` |
66
+ | List campaign variants | `GET /automation/campaigns/{campaign_id}/variants` |
67
+ | Approve/reject variant | `POST /automation/variants/{variant_id}/approval` |
68
+ | Create render job plan | `POST /automation/variants/{variant_id}/render-job` |
69
+ | Recommend schedule | `POST /automation/schedule/recommend` |
70
+ | Apply schedule | `POST /automation/schedule/apply` |
71
+ | Create publish job | `POST /automation/publish` |
72
+ | Ingest analytics | `POST /automation/analytics/events` |
73
+ | Analytics summary | `GET /automation/analytics/summary` |
74
+ | A/B test plan | `POST /automation/ab-tests/{campaign_id}` |
75
+ | Workspaces | `POST /automation/workspaces`, `GET /automation/workspaces` |
76
+ | Team/client review | `GET /automation/client-portals/{workspace_id}/review-bundle` |
77
+ | Social accounts | `POST /automation/accounts`, `GET /automation/accounts` |
78
+ | Cross-post rules | `POST /automation/cross-post-rules`, `POST /automation/cross-post-rules/{rule_id}/plan` |
79
+ | Trends | `POST /automation/trends`, `GET /automation/trends/recommendations` |
80
+ | Competitors | `POST /automation/competitors`, `GET /automation/competitors/insights` |
81
+ | Idea inbox | `POST /automation/ideas`, `POST /automation/ideas/{idea_id}/campaign` |
82
+ | 30-90 day calendar plan | `POST /automation/calendar/plan` |
83
+ | Quality scoring | `POST /automation/quality/hook`, `GET /automation/quality/variants/{variant_id}` |
84
+ | Compliance check | `POST /automation/compliance/check` |
85
+ | Integrations | `POST /automation/integrations`, `GET /automation/integrations/templates` |
86
+ | Queue operations | `GET /automation/queue/summary`, `GET /automation/queue/next` |
87
+ | Usage and reports | `POST /automation/usage`, `POST /automation/reports` |
88
+ | CPU profile | `GET /automation/ops/cpu-profile` |
89
+
90
+ ## Using the API from n8n HTTP Request Nodes
91
+
92
+ The examples below assume n8n is running from this repository's Docker Compose
93
+ stack. In that setup, use these expressions:
94
+
95
+ ```text
96
+ Base URL: ={{ ($env.MAESTER_BASE_URL || 'http://maester-enterprise:7860').replace(/\/$/, '') }}
97
+ API key: ={{ $env.MAESTER_API_KEY }}
98
+ ```
99
+
100
+ For an n8n instance running outside Docker, set `MAESTER_BASE_URL` to the URL
101
+ that n8n can use to reach Maester, for example `http://host.docker.internal:7860`
102
+ or the public HTTPS URL of the deployment. `localhost` means the n8n container
103
+ itself when n8n runs in Docker.
104
+
105
+ ### Common HTTP Request node settings
106
+
107
+ Use these settings for every protected endpoint:
108
+
109
+ | n8n field | Value |
110
+ | --- | --- |
111
+ | Authentication | `None`, or an n8n Header Auth credential |
112
+ | Send Headers | On |
113
+ | Header name | `X-API-Key` |
114
+ | Header value | `={{ $env.MAESTER_API_KEY }}` |
115
+ | URL | `={{ $env.MAESTER_BASE_URL + '/path' }}` |
116
+ | Response Format | `JSON` unless the endpoint returns a file |
117
+ | Timeout | At least `120000` ms for AI operations and `600000` ms for synchronous media operations |
118
+
119
+ An n8n Header Auth credential with the header name `X-API-Key` is preferable
120
+ when workflow editors must not be able to read environment variables. The
121
+ gateway also accepts `api_key` as a query parameter, but headers avoid leaking
122
+ the key into URLs and logs.
123
+
124
+ For a JSON request, enable **Send Body**, select **JSON**, and enter an object or
125
+ an expression such as:
126
+
127
+ ```javascript
128
+ ={{ {
129
+ name: $json.name,
130
+ topic: $json.topic,
131
+ platforms: ['tiktok', 'instagram_reels'],
132
+ quantity: 5
133
+ } }}
134
+ ```
135
+
136
+ For query parameters, enable **Send Query Parameters** and add each named
137
+ parameter shown in the tables below. Values in `{braces}` are path parameters;
138
+ replace them with n8n expressions, for example:
139
+
140
+ ```text
141
+ ={{ $env.MAESTER_BASE_URL + '/automation/campaigns/' + $json.id }}
142
+ ```
143
+
144
+ For file responses, set **Response Format** to **File** and choose an output
145
+ binary property such as `data`. For multipart uploads, select **Form-Data** and
146
+ use an **n8n Binary File** parameter for each file field. Do not manually set
147
+ `Content-Type` for multipart requests; n8n must generate the boundary.
148
+
149
+ ### Gateway endpoints
150
+
151
+ | Method and path | n8n use |
152
+ | --- | --- |
153
+ | `GET /health` | Public health check. No body; JSON response. |
154
+ | `GET /ready` | Public readiness check. No body; JSON response. A `207` response means the gateway started but one or more embedded services failed to mount. |
155
+ | `GET /version` | Public version check. No body; JSON response. |
156
+ | `GET /api/meta` | Add `X-API-Key`; returns version, security mode, mounted services, and mount failures. |
157
+ | `GET /services` | Add `X-API-Key`; returns the enabled and mounted service catalog. |
158
+ | `GET /` | Browser redirect to `/studio/`; it is not normally useful in an n8n workflow. |
159
+
160
+ ### Automation endpoint payloads
161
+
162
+ Automation POST and PATCH routes use a JSON body unless a table explicitly
163
+ says `query` or `multipart`. These minimal bodies can be pasted into an n8n
164
+ HTTP Request node and populated with expressions from earlier nodes.
165
+
166
+ ```json
167
+ {
168
+ "brand_kit": {
169
+ "name": "Acme",
170
+ "primary_color": "#111111",
171
+ "accent_color": "#16a34a"
172
+ },
173
+ "campaign": {
174
+ "name": "Launch week",
175
+ "topic": "Three ways to automate customer support",
176
+ "platforms": ["tiktok", "instagram_reels"],
177
+ "quantity": 5
178
+ },
179
+ "approval": {
180
+ "state": "approved",
181
+ "reviewer": "Editorial team",
182
+ "notes": "Ready to render"
183
+ },
184
+ "publish": {
185
+ "variant_id": "var_id",
186
+ "platforms": ["tiktok"],
187
+ "draft": true
188
+ },
189
+ "analytics_event": {
190
+ "variant_id": "var_id",
191
+ "platform": "tiktok",
192
+ "views": 1000,
193
+ "likes": 100,
194
+ "completion_rate": 0.72
195
+ },
196
+ "workspace": {
197
+ "name": "Acme workspace",
198
+ "client_name": "Acme"
199
+ },
200
+ "member": {
201
+ "workspace_id": "ws_id",
202
+ "email": "editor@example.com",
203
+ "role": "editor"
204
+ },
205
+ "social_account": {
206
+ "workspace_id": "ws_id",
207
+ "platform": "tiktok",
208
+ "handle": "@acme",
209
+ "metadata": {
210
+ "token_env": "TIKTOK_ACCESS_TOKEN",
211
+ "publish_endpoint": "https://publisher.example.com/posts"
212
+ }
213
+ },
214
+ "cross_post_rule": {
215
+ "name": "TikTok to Reels",
216
+ "source_platform": "tiktok",
217
+ "target_platforms": ["instagram_reels", "facebook_shorts"]
218
+ },
219
+ "trend": {
220
+ "platform": "tiktok",
221
+ "keyword": "automation",
222
+ "niche": "small business",
223
+ "score": 75,
224
+ "velocity": 12
225
+ },
226
+ "competitor": {
227
+ "platform": "tiktok",
228
+ "handle": "@competitor",
229
+ "niche": "small business"
230
+ },
231
+ "idea": {
232
+ "text": "Turn one customer question into five short videos",
233
+ "niche": "small business",
234
+ "priority": 4
235
+ },
236
+ "calendar_plan": {
237
+ "niche": "small business",
238
+ "days": 30,
239
+ "posts_per_day": 2,
240
+ "platforms": ["tiktok", "instagram_reels"]
241
+ },
242
+ "compliance": {
243
+ "platform": "tiktok",
244
+ "title": "Automation tips",
245
+ "caption": "Three practical ideas",
246
+ "hashtags": ["automation"],
247
+ "duration_seconds": 30
248
+ },
249
+ "integration": {
250
+ "kind": "n8n",
251
+ "name": "Production n8n",
252
+ "endpoint_url": "https://n8n.example.com/webhook/maester"
253
+ },
254
+ "experiment": {
255
+ "campaign_id": "camp_id",
256
+ "name": "Hook test",
257
+ "variable": "hook",
258
+ "variant_ids": ["var_a", "var_b"]
259
+ }
260
+ }
261
+ ```
262
+
263
+ The outer labels above are examples only. Send the value of one label as the
264
+ actual request body, not the complete combined object. For example, use
265
+ `={{ $json.campaign }}` when the incoming item contains the object above.
266
+
267
+ ### Automation campaign and publishing endpoints
268
+
269
+ | Method and path | n8n body or parameters | Result/use |
270
+ | --- | --- | --- |
271
+ | `GET /automation/capabilities` | None | Discover supported platforms and automation features. |
272
+ | `POST /automation/brand-kits` | JSON `brand_kit` | Create a brand kit. |
273
+ | `GET /automation/brand-kits` | None | List brand kits. |
274
+ | `GET /automation/brand-kits/{brand_id}` | Path `brand_id` | Fetch one brand kit. |
275
+ | `POST /automation/campaigns` | JSON `campaign` | Create a campaign without generating variants. |
276
+ | `GET /automation/campaigns` | None | List campaigns. |
277
+ | `GET /automation/campaigns/{campaign_id}` | Path `campaign_id` | Fetch one campaign. |
278
+ | `POST /automation/campaigns/{campaign_id}/generate` | Path only; no body | Generate deterministic variants for an existing campaign. |
279
+ | `POST /automation/campaigns/generate` | JSON `campaign` | Create a campaign and generate variants in one request. |
280
+ | `POST /automation/campaigns/{campaign_id}/generate-ai` | JSON `{"provider":"openai","model":"gpt-4o-mini","instructions":"Use a direct tone"}` | Generate variants with the configured OpenAI, Gemini, or OpenRouter provider. |
281
+ | `GET /automation/providers` | None | Check selected AI provider and configuration status. |
282
+ | `GET /automation/campaigns/{campaign_id}/variants` | Path `campaign_id` | List variants for one campaign. |
283
+ | `GET /automation/variants` | None | List every variant. |
284
+ | `GET /automation/variants/{variant_id}` | Path `variant_id` | Fetch one variant. |
285
+ | `PATCH /automation/variants/{variant_id}` | JSON containing any of `title`, `hook`, `script`, `caption`, `hashtags`, `cta`, `template`, `creative_style`, `duration_seconds`, `safe_zone`, `render_payload`, or `metadata` | Edit a variant and increment its revision. |
286
+ | `DELETE /automation/variants/{variant_id}` | Path only | Delete a variant. |
287
+ | `POST /automation/variants/{variant_id}/approval` | JSON `approval` | Approve, reject, or move a variant to another approval state. |
288
+ | `POST /automation/variants/{variant_id}/rewrite` | Path only; no body | Rewrite the variant script. |
289
+ | `POST /automation/variants/{variant_id}/render-job` | Path only; no body | Create an automation job containing the render-engine payload. |
290
+ | `POST /automation/repurpose` | JSON `{"name":"Podcast clips","transcript":"...","quantity":5,"platforms":["tiktok"]}` | Split long-form text into a campaign and short-form variants. |
291
+ | `POST /automation/schedule/recommend` | Query `campaign_id`; optional `start_at` ISO timestamp | Return recommended slots without saving them. |
292
+ | `POST /automation/schedule/apply` | Query `campaign_id`; optional `start_at` | Save recommended calendar entries. |
293
+ | `GET /automation/calendar` | None | List saved calendar entries. |
294
+ | `POST /automation/publish` | JSON `publish` | Queue or schedule an approved variant for publishing. |
295
+ | `GET /automation/jobs` | None | List all automation jobs. |
296
+ | `GET /automation/jobs/{job_id}` | Path `job_id` | Fetch one job. |
297
+ | `POST /automation/jobs/{job_id}/state` | JSON `{"state":"ready","result":{},"logs":["Render complete"]}` | Update a job from an external worker. |
298
+ | `POST /automation/jobs/{job_id}/retry` | Path only; no body | Requeue a failed or cancelled job. |
299
+ | `POST /automation/jobs/{job_id}/cancel` | Path only; no body | Cancel a non-terminal job. |
300
+ | `POST /automation/analytics/events` | JSON `analytics_event` | Store metrics and compute a viral score. |
301
+ | `GET /automation/analytics/summary` | None | Return platform averages, winners, and recommendations. |
302
+ | `POST /automation/ab-tests/{campaign_id}` | Path only; no body | Build a simple A/B grouping plan. |
303
+
304
+ ### Automation workspace, research, and operations endpoints
305
+
306
+ | Method and path | n8n body or parameters | Result/use |
307
+ | --- | --- | --- |
308
+ | `POST /automation/workspaces` | JSON `workspace` | Create a workspace. |
309
+ | `GET /automation/workspaces` | None | List workspaces. |
310
+ | `POST /automation/workspaces/{workspace_id}/members` | JSON `member`; the path value overrides `workspace_id` in the body | Add a member. |
311
+ | `GET /automation/workspaces/{workspace_id}/members` | Path only | List workspace members. |
312
+ | `GET /automation/workspaces/{workspace_id}/quota` | Path only | Return usage and remaining quota. |
313
+ | `POST /automation/accounts` | JSON `social_account` | Register a social account and connector metadata. |
314
+ | `GET /automation/accounts` | Optional query `workspace_id` | List social accounts. |
315
+ | `GET /automation/accounts/{account_id}/connector` | Path only | Check whether publishing and analytics credentials are configured. |
316
+ | `GET /automation/accounts/{account_id}/oauth-url` | Path plus required query `redirect_uri` | Generate an OAuth authorization URL. Follow the URL in a browser; an n8n HTTP node should not automatically follow this interactive flow. |
317
+ | `POST /automation/accounts/{account_id}/analytics-sync` | Path only; no body | Queue an analytics synchronization job. |
318
+ | `POST /automation/cross-post-rules` | JSON `cross_post_rule` | Create a cross-post rule. |
319
+ | `GET /automation/cross-post-rules` | Optional query `workspace_id` | List cross-post rules. |
320
+ | `POST /automation/cross-post-rules/{rule_id}/plan` | Path `rule_id`; required query `variant_id` | Plan delayed target-platform posts. |
321
+ | `POST /automation/trends` | JSON `trend` | Store a trend signal. |
322
+ | `GET /automation/trends` | Optional query `niche` | List trend signals. |
323
+ | `GET /automation/trends/recommendations` | Optional query `niche` | Rank trend recommendations. |
324
+ | `POST /automation/competitors` | JSON `competitor` | Store a competitor profile. |
325
+ | `GET /automation/competitors` | Optional query `niche` | List competitor profiles. |
326
+ | `GET /automation/competitors/insights` | Optional query `niche` | Summarize observed hooks and formats. |
327
+ | `POST /automation/ideas` | JSON `idea` | Add an idea to the inbox. |
328
+ | `GET /automation/ideas` | Optional queries `workspace_id` and `status` | List and filter ideas. |
329
+ | `POST /automation/ideas/{idea_id}/campaign` | Path only; no body | Convert an idea into a campaign. |
330
+ | `POST /automation/calendar/plan` | JSON `calendar_plan` | Generate a 1-90 day content plan. |
331
+ | `POST /automation/quality/hook` | JSON `{"hook":"Stop doing this manually"}` | Score a hook. |
332
+ | `POST /automation/quality/script` | JSON `{"script":"..."}` | Score a script. |
333
+ | `POST /automation/quality/caption` | JSON `{"caption":"..."}` | Score a caption. |
334
+ | `GET /automation/quality/variants/{variant_id}` | Path only | Score all text fields and predict retention for a variant. |
335
+ | `POST /automation/compliance/check` | JSON `compliance` | Check platform, duration, disclosure, caption, and hashtag rules. |
336
+ | `POST /automation/integrations` | JSON `integration` | Register an outbound webhook or service integration. |
337
+ | `GET /automation/integrations` | Optional query `workspace_id` | List integrations. |
338
+ | `GET /automation/integrations/templates` | None | Return n8n, Zapier, Make, Slack, Drive, and Shopify integration recipes. |
339
+ | `POST /automation/usage` | JSON `{"workspace_id":"ws_id","kind":"render_minutes","quantity":1,"cost_units":2.5}` | Log usage. |
340
+ | `GET /automation/usage/summary` | Optional query `workspace_id` | Summarize usage. |
341
+ | `GET /automation/queue/summary` | None | Count jobs by state. |
342
+ | `GET /automation/queue/next` | Optional query `kind` | Inspect the next queued job. |
343
+ | `POST /automation/queue/process` | Optional queries `kind` and `limit` (1-25) | Process queued automation jobs. |
344
+ | `POST /automation/reports` | JSON `{"workspace_id":"ws_id","format":"json","include_recommendations":true}` | Build a campaign/workspace report. |
345
+ | `GET /automation/client-portals/{workspace_id}/review-bundle` | Path only | Return variants awaiting client review. |
346
+ | `GET /automation/overview` | Optional query `workspace_id` | Return dashboard totals and summaries. |
347
+ | `GET /automation/ops/cpu-profile` | None | Return recommended CPU deployment settings. |
348
+ | `POST /automation/ops/warmup` | No body | Return the CPU-safe warmup plan. |
349
+
350
+ ### Automation assets, experiments, reviews, and rules
351
+
352
+ | Method and path | n8n body or parameters | Result/use |
353
+ | --- | --- | --- |
354
+ | `POST /automation/assets` | Multipart Form-Data: binary field `file`; optional text fields `workspace_id`, `license`, `attribution`, and comma-separated `tags` | Upload and register an asset. |
355
+ | `GET /automation/assets` | Optional queries `workspace_id`, `kind`, and `tag` | List assets. |
356
+ | `GET /automation/assets/{asset_id}/usage` | Path only | Find variants that reference an asset. |
357
+ | `DELETE /automation/assets/{asset_id}` | Optional query `force=true` | Delete an unused asset, or force deletion. |
358
+ | `POST /automation/experiments` | JSON `experiment` | Create a multi-variant experiment. |
359
+ | `GET /automation/experiments` | Optional query `campaign_id` | List experiments. |
360
+ | `POST /automation/experiments/{experiment_id}/evaluate` | Path only; no body | Recalculate confidence and choose a winner when thresholds are met. |
361
+ | `POST /automation/experiments/{experiment_id}/generate-followups` | Optional query `quantity` (1-10) | Generate variants based on the winner. |
362
+ | `POST /automation/reviews` | JSON `{"workspace_id":"ws_id","variant_ids":["var_a","var_b"],"expires_in_days":7,"created_by":"Producer"}` | Create a signed public review link. Save the returned `token` or `review_url`. |
363
+ | `GET /automation/reviews/public/{token}` | Path token; API key not required while the token is valid | Fetch the public review bundle. |
364
+ | `POST /automation/reviews/public/{token}/comments` | JSON `{"variant_id":"var_a","author":"Client","body":"Shorten the intro"}` | Add a review comment; API key is not required with a valid token. |
365
+ | `POST /automation/reviews/public/{token}/decision` | Required query `variant_id`; JSON `approval` | Approve/reject through a public review link. |
366
+ | `POST /automation/rules` | JSON `{"name":"Render approvals","event":"variant_approved","actions":[{"type":"render"}]}` | Create an event rule. |
367
+ | `GET /automation/rules` | Optional query `workspace_id` | List rules. |
368
+ | `POST /automation/rules/trigger` | Required queries `event` and `resource_id`; optional `workspace_id`. Send `metadata` as a JSON query value only when needed. | Trigger matching notify, render, or publish actions. |
369
+ | `GET /automation/notifications` | Optional query `workspace_id` | List notifications. |
370
+ | `POST /automation/notifications/dispatch` | Query `integration_id`, `subject`, `message`; optional `workspace_id` | Queue delivery through an integration. |
371
+ | `GET /automation/audit` | Optional queries `workspace_id` and `limit` (1-500) | List audit events. |
372
+
373
+ ### Kokoro TTS endpoint
374
+
375
+ Use `POST /services/ktts/v1/audio/speech`. Create an HTTP Request node with URL
376
+ `={{ $env.MAESTER_BASE_URL + '/services/ktts/v1/audio/speech' }}`, JSON body, and
377
+ **Response Format: File**:
378
+
379
+ ```json
380
+ {
381
+ "input": "This narration was generated by Maester.",
382
+ "voice": "af_bella.pt",
383
+ "model": "kokoro-v0_19.onnx",
384
+ "speed": 1.0
385
+ }
386
+ ```
387
+
388
+ The WAV file is written to the node's selected binary property. Pass that
389
+ property to a render upload node or another media-processing node.
390
+
391
+ ### MusicGen endpoints
392
+
393
+ | Method and path | n8n use |
394
+ | --- | --- |
395
+ | `GET /services/musicgen/health` | No body; JSON response. |
396
+ | `POST /services/musicgen/generate` | Add query parameters `prompt` and `duration` (5-60 seconds). Set **Response Format: File** to receive `music.wav`. Example URL: `={{ $env.MAESTER_BASE_URL + '/services/musicgen/generate' }}`. |
397
+
398
+ Music generation can be slow on CPU. Set a long timeout and use the render
399
+ engine's asynchronous `POST /music/generate` route when polling is preferable.
400
+
401
+ ### Whisper endpoints
402
+
403
+ Use `POST /services/whisper/execute/{task_name}` with **Form-Data**. Supply one
404
+ of these inputs:
405
+
406
+ - `file`: an n8n binary file;
407
+ - `url_input`: a downloadable media URL; or
408
+ - `source`: another supported source string.
409
+
410
+ Optional fields are `webhook` and a JSON request body only for tasks whose
411
+ operation consumes publishing metadata. Because the route accepts multipart
412
+ data, normal file-based calls should use Form-Data.
413
+
414
+ Supported `{task_name}` values are `autonomous`, `auto-publish`, `publish`,
415
+ `bulk-publish`, `generate-metadata`, `generate-thumbnail`, `schedule-post`,
416
+ `transcribe`, `subtitles`, `render`, `highlights`, `viral-score`, `strategy`,
417
+ `batch`, and `clips`.
418
+
419
+ | Method and path | n8n use |
420
+ | --- | --- |
421
+ | `POST /services/whisper/execute/{task_name}` | Multipart request described above. Use JSON response for analysis tasks. For `render` and `generate-thumbnail`, set **Response Format: File** when the response is media. |
422
+ | `GET /services/whisper/api/health` | No body; returns operator and auth status. |
423
+ | `GET /services/whisper/api/status/{job_id}` | Poll a `batch` job using the returned `job_id`. |
424
+ | `POST /services/whisper/api/auth/signup` | Optional auth subsystem; JSON `{"email":"user@example.com","username":"user_name","password":"at-least-8-characters"}`. |
425
+ | `POST /services/whisper/api/auth/login` | Optional auth subsystem; JSON `{"email":"user@example.com","password":"..."}`. |
426
+ | `POST /services/whisper/api/auth/verify` | Optional auth subsystem; JSON `{"token":"..."}`. |
427
+ | `POST /services/whisper/api/auth/refresh` | Optional auth subsystem; JSON `{"token":"..."}`. |
428
+ | `POST /services/whisper/api/auth/logout` | Optional auth subsystem; no body. |
429
+
430
+ The auth routes exist only when the Whisper auth dependencies initialize
431
+ successfully. Gateway `X-API-Key` authentication is still required in
432
+ production even when using a Whisper login token.
433
+
434
+ ### FFmpeg automation endpoints
435
+
436
+ The `/n8n/*` routes are the preferred FFmpeg routes for n8n because they accept
437
+ multipart binary fields with any name, URL inputs, base64 JSON, or a raw binary
438
+ body.
439
+
440
+ | Method and path | n8n use |
441
+ | --- | --- |
442
+ | `GET /services/ffmpeg/healthz` | Dependency health details. |
443
+ | `GET /services/ffmpeg/readyz` | Readiness check; returns `503` when FFmpeg or required storage is unavailable. |
444
+ | `GET /services/ffmpeg/tasks` | Discover task IDs, accepted file types, file counts, and output extensions. |
445
+ | `POST /services/ffmpeg/n8n/execute/{task_id}` | Run synchronously. Use Form-Data, URL JSON, base64 JSON, or raw binary. Set **Response Format: File**. |
446
+ | `POST /services/ffmpeg/n8n/jobs/{task_id}` | Submit asynchronously with the same input formats. JSON response contains `job_id`. |
447
+ | `POST /services/ffmpeg/execute/{task_id}` | Standard multipart synchronous endpoint. Binary field name must be `files`. Set **Response Format: File**. |
448
+ | `POST /services/ffmpeg/jobs/{task_id}` | Standard multipart asynchronous endpoint. Binary field name must be `files`. |
449
+ | `GET /services/ffmpeg/status/{job_id}` | Poll until `status` is complete; response then includes `download_url`. |
450
+ | `GET /services/ffmpeg/download/{job_id}` | Set **Response Format: File** to download a completed job. |
451
+ | `GET /services/ffmpeg/history` | List recent outputs. |
452
+ | `GET /services/ffmpeg/history/{history_id}/download` | Set **Response Format: File** to download a retained history item. |
453
+
454
+ Available `{task_id}` values:
455
+
456
+ ```text
457
+ normalize, extract_audio, resize_916, add_subtitles, burn_lyrics,
458
+ text_overlay, merge_music, thumbnail, watermark, compress, batch_compress,
459
+ make_gif, tiktok_lyrics, tiktok_pro_reframer, reels_blur_fit,
460
+ reels_safe_caption, reels_hook_title, reels_progress_bar, reels_loop,
461
+ reels_subtitle_safe, reels_reaction_stack, reels_audio_duck,
462
+ faceless_quote_card, faceless_story_pages, faceless_image_narration,
463
+ faceless_video_narration, faceless_broll_montage, series_split_pack,
464
+ series_episode_badge, series_batch_pack, series_recap_card, concat,
465
+ slideshow, trim, crop_aspect, waveform, extract_frames, add_intro_outro,
466
+ speed, remove_audio, replace_audio
467
+ ```
468
+
469
+ For URL input, send JSON and keep the response as a file:
470
+
471
+ ```json
472
+ {
473
+ "url": "https://cdn.example.com/input.mp4",
474
+ "text": "Episode 1",
475
+ "duration": "30",
476
+ "crf": "23",
477
+ "preset": "veryfast"
478
+ }
479
+ ```
480
+
481
+ For base64 input, send:
482
+
483
+ ```json
484
+ {
485
+ "files": [
486
+ {
487
+ "fileName": "input.mp4",
488
+ "mimeType": "video/mp4",
489
+ "data": "base64-data-from-a-previous-node"
490
+ }
491
+ ],
492
+ "options": {
493
+ "text": "Episode 1",
494
+ "aspect_ratio": "9:16"
495
+ }
496
+ }
497
+ ```
498
+
499
+ Recognized option fields are `text`, `start_time`, `end_time`, `duration`,
500
+ `aspect_ratio`, `resolution`, `crf`, `preset`, `audio_bitrate`, `volume`,
501
+ `position`, `opacity`, `fps`, `width`, `speed`, `timestamp`, `image_duration`,
502
+ `frame_rate`, `font_size`, and `wave_color`. Call `GET /services/ffmpeg/tasks`
503
+ before building a dynamic workflow to validate the required number and type of
504
+ files for the selected task.
505
+
506
+ ### Render engine request bodies
507
+
508
+ Most render-engine mutation routes return a `job_id`, `status_url`, and signed
509
+ `download_url`. The following are the main JSON body shapes.
510
+
511
+ Render request:
512
+
513
+ ```json
514
+ {
515
+ "template": "tiktok_classic",
516
+ "preset": "tiktok_9_16_fast",
517
+ "output_name": "campaign_clip.mp4",
518
+ "voiceover": "https://cdn.example.com/voice.wav",
519
+ "background_music": "https://cdn.example.com/music.mp3",
520
+ "auto_subtitles": true,
521
+ "audio_normalize": true,
522
+ "scenes": [
523
+ {
524
+ "start": 0,
525
+ "duration": 5,
526
+ "media": "https://cdn.example.com/scene.mp4",
527
+ "caption": "Launch faster",
528
+ "transition": "fade"
529
+ }
530
+ ]
531
+ }
532
+ ```
533
+
534
+ Toolkit request:
535
+
536
+ ```json
537
+ {
538
+ "task": "trim",
539
+ "media": "https://cdn.example.com/input.mp4",
540
+ "output_name": "trimmed.mp4",
541
+ "params": {
542
+ "start": 2,
543
+ "duration": 15
544
+ }
545
+ }
546
+ ```
547
+
548
+ Project and timeline requests:
549
+
550
+ ```json
551
+ {
552
+ "create_project": {
553
+ "name": "Launch edit",
554
+ "metadata": {},
555
+ "export_settings": {"preset": "tiktok"}
556
+ },
557
+ "add_timeline_item": {
558
+ "project_id": "project_id",
559
+ "track_type": "video",
560
+ "item": {"source": "https://cdn.example.com/clip.mp4", "start": 0}
561
+ },
562
+ "timeline_operation": {
563
+ "project_id": "project_id",
564
+ "operation": "trim",
565
+ "item_id": "item_id",
566
+ "params": {"start": 1, "end": 8}
567
+ }
568
+ }
569
+ ```
570
+
571
+ As with the automation payload collection, send only the selected nested value.
572
+
573
+ ### Render engine discovery and project endpoints
574
+
575
+ | Method and path | n8n body or parameters | Result/use |
576
+ | --- | --- | --- |
577
+ | `GET /services/render/health` | None | Service health. |
578
+ | `GET /services/render/monitor` | None | Runtime and queue monitoring. |
579
+ | `GET /services/render/queue` | None | Queue summary. |
580
+ | `GET /services/render/workers` | None | Worker and transcription configuration. |
581
+ | `GET /services/render/presets` | None | Render presets, caption templates, styles, effects, and transitions. |
582
+ | `GET /services/render/platforms` | None | Platform profiles. |
583
+ | `GET /services/render/toolkit/tasks` | None | Supported toolkit task names. |
584
+ | `GET /services/render/capabilities` | None | Complete studio capability catalog. |
585
+ | `GET /services/render/effects` | None | Effects catalog. |
586
+ | `GET /services/render/filters` | None | Filter formats and presets. |
587
+ | `GET /services/render/transitions` | None | Transition families and FFmpeg transitions. |
588
+ | `GET /services/render/templates/catalog` | None | Template, preset, and style catalog. |
589
+ | `GET /services/render/projects` | None | List projects. |
590
+ | `POST /services/render/projects` | JSON `create_project` | Create a project. |
591
+ | `POST /services/render/project/create` | Same as `/services/render/projects` | Compatibility alias for project creation. |
592
+ | `GET /services/render/project/{project_id}` | Path only | Fetch a project. |
593
+ | `POST /services/render/project/save` | JSON `{"project_id":"id","project":{...}}` | Save a complete project document. |
594
+ | `POST /services/render/project/assets/add` | JSON `{"project_id":"id","asset":{"source":"https://..."}}` | Add an asset record to a project. |
595
+ | `POST /services/render/timeline/add` | JSON `add_timeline_item` | Add an item to a timeline track. |
596
+ | `POST /services/render/timeline/operation` | JSON `timeline_operation` | Run `drag`, `split`, `trim`, `ripple_delete`, `insert`, `replace`, `group`, `lock`, `hide`, or `duplicate`. |
597
+ | `POST /services/render/timeline/split` | Timeline-operation JSON; `operation` may be omitted | Split an item. |
598
+ | `POST /services/render/timeline/trim` | Timeline-operation JSON; `operation` may be omitted | Trim an item. |
599
+ | `POST /services/render/timeline/ripple-delete` | Timeline-operation JSON; `operation` may be omitted | Ripple-delete an item. |
600
+ | `POST /services/render/timeline/insert` | Timeline-operation JSON; `operation` may be omitted | Insert an item. |
601
+ | `POST /services/render/timeline/replace` | Timeline-operation JSON; `operation` may be omitted | Replace an item. |
602
+ | `POST /services/render/timeline/group` | Timeline-operation JSON; `operation` may be omitted | Group items. |
603
+ | `POST /services/render/timeline/lock` | Timeline-operation JSON; `operation` may be omitted | Lock an item. |
604
+ | `POST /services/render/timeline/hide` | Timeline-operation JSON; `operation` may be omitted | Hide an item. |
605
+ | `POST /services/render/timeline/duplicate` | Timeline-operation JSON; `operation` may be omitted | Duplicate an item. |
606
+ | `POST /services/render/project/{project_id}/render` | JSON `{"output_name":"project.mp4","preset":"tiktok_9_16_fast"}` | Render a saved project asynchronously. |
607
+
608
+ ### Render engine editing, generation, and media endpoints
609
+
610
+ | Method and path | n8n body or parameters | Result/use |
611
+ | --- | --- | --- |
612
+ | `POST /services/render/effect/apply` | JSON `{"project_id":"id","target_id":"item","effect":"glitch","params":{}}` | Save an effect to a project item, or submit an async effect job when project IDs are omitted. |
613
+ | `POST /services/render/filter/apply` | JSON `{"project_id":"id","target_id":"item","filter":"cinema","params":{}}` | Save or asynchronously apply a filter. |
614
+ | `POST /services/render/transition/add` | JSON `{"project_id":"id","from_item_id":"a","to_item_id":"b","transition":"fade","duration":0.45}` | Add or asynchronously generate a transition. |
615
+ | `POST /services/render/keyframe/add` | JSON `{"project_id":"id","target_id":"item","property":"opacity","time":1.5,"value":0.5}` | Add a keyframe. |
616
+ | `POST /services/render/caption/generate` | JSON with one of `media`, `audio`, `text`, `transcript`, or `events`; optional `template`, `language`, and caption flags | Submit caption generation. |
617
+ | `POST /services/render/music/generate` | JSON `{"prompt":"calm cinematic background","provider":"musicgen","params":{"duration":20}}` | Submit music generation. |
618
+ | `POST /services/render/voice/generate` | JSON `{"text":"Narration text","provider":"kokoro","params":{"voice":"af_bella.pt"}}` | Submit voice generation. |
619
+ | `POST /services/render/image/generate` | JSON `{"prompt":"vertical product background","provider":"flux","params":{}}` | Submit image generation. |
620
+ | `POST /services/render/video/generate` | JSON `{"prompt":"slow camera push through an office","provider":"wan","params":{}}` | Submit video generation. |
621
+ | `POST /services/render/ai/{tool}` | JSON `{"media":"...","transcript":"...","platform":"tiktok","params":{}}` | Submit an AI editing tool such as `auto_edit`, `auto_reframe`, or `auto_highlight_detection`. Discover names through `/services/render/capabilities`. |
622
+ | `POST /services/render/assistant/{tool}` | Same general AI body | Run `script_writer`, `hook_generator`, `title_generator`, `description_generator`, `hashtag_generator`, `seo_optimizer`, `thumbnail_prompt_generator`, `b_roll_planner`, or `storyboard_generator`. |
623
+ | `POST /services/render/render` | JSON render request | Submit a normal render or AI Reels-shaped request. |
624
+ | `POST /services/render/render/ai-reels` | JSON `{"script":"...","voiceover":"https://...","assets":["https://..."],"template":"tiktok_classic"}` | Submit AI Reels assembly. |
625
+ | `POST /services/render/render/batch` | JSON `{"jobs":[<render request>, <render request>]}` | Submit multiple renders. |
626
+ | `POST /services/render/automation/batch` | Same batch JSON | Authenticated alias for batch rendering. |
627
+ | `POST /services/render/ingest` | JSON `{"sources":[{"url":"https://...","type":"video"}]}` | Stage remote sources asynchronously. |
628
+ | `POST /services/render/analyze` | JSON `{"media":"https://...","transcript":"...","platform":"tiktok"}` | Analyze media. |
629
+ | `POST /services/render/clips` | JSON `{"media":"https://...","clips":[{"start":0,"end":10}]}` | Create clips. |
630
+ | `POST /services/render/thumbnail` | JSON `{"media":"https://...","text":"Watch this","timestamp":2,"template":"bold"}` | Generate a thumbnail. |
631
+ | `POST /services/render/thumbnail/create` | Same thumbnail JSON | Alias for thumbnail generation. |
632
+ | `POST /services/render/metadata` | JSON `{"topic":"automation","transcript":"...","platform":"tiktok"}` | Generate platform metadata. |
633
+ | `POST /services/render/publish` | JSON `{"media":"path-or-url","title":"Title","platforms":["tiktok"],"draft":true}` | Submit a platform publishing task. |
634
+ | `POST /services/render/toolkit` | JSON toolkit request | Run an FFmpeg/platform toolkit task asynchronously. |
635
+ | `POST /services/render/edit` | Same toolkit JSON | Alias for `/services/render/toolkit`. |
636
+ | `POST /services/render/transcribe` | JSON `{"audio":"https://...","model_size":"tiny","language":"en","word_timestamps":true}` | Transcribe synchronously. |
637
+ | `POST /services/render/subtitles` | JSON `{"events":[{"start":0,"end":2,"text":"Hello"}],"format":"srt","template":"tiktok_classic"}`; **Response Format: File** | Generate an SRT or ASS file. |
638
+ | `POST /services/render/scene-builder` | JSON `{"script":"...","assets":["https://..."],"duration":20,"transition":"fade"}` | Build scene JSON for a subsequent `/services/render/render` request. |
639
+ | `POST /services/render/inspect` | Query `path` | Inspect a server-side or uploaded asset with FFprobe. |
640
+
641
+ ### Render uploads, polling, and downloads
642
+
643
+ | Method and path | n8n body or parameters | Result/use |
644
+ | --- | --- | --- |
645
+ | `POST /services/render/assets/upload` | Form-Data with one or more binary fields named `files` | Stage files and return `path` plus `upload://filename` references. |
646
+ | `POST /services/render/upload` | Form-Data `files`; optional text field `expand_zip` | Stage files and optionally expand ZIP archives. |
647
+ | `POST /services/render/render/upload` | Form-Data text field `request_json` containing a stringified render request, plus binary `files`. Refer to files as `upload://filename` inside `request_json`. | Submit a render using uploaded files. |
648
+ | `POST /services/render/render/ai-reels/upload` | Same multipart pattern using an AI Reels request in `request_json`. | Submit AI Reels assembly using uploaded files. |
649
+ | `POST /services/render/transcribe/upload` | Form-Data binary field `file`; optional text fields `model_size`, `language`, `task`, `beam_size`, `vad_filter`, `word_timestamps` | Transcribe an n8n binary file. |
650
+ | `GET /services/render/status?job_id={job_id}` | Required query `job_id`. | Query form of job polling. |
651
+ | `GET /services/render/status/{job_id}` | Path `job_id`. | Path form of job polling. Wait until `state` is `COMPLETED`. |
652
+ | `POST /services/render/cancel/{job_id}` | Path only; no body | Cancel a queued/running job. |
653
+ | `POST /services/render/admin/cleanup` | Optional query `older_than_seconds` | Remove old job files and records. |
654
+ | `GET /services/render/download?job_id={job_id}&token={token}` | Required query `job_id`; include the returned `token`; **Response Format: File**. | Query-form download. |
655
+ | `GET /services/render/download/{job_id}?token={token}` | Path `job_id`; include the returned `token`; **Response Format: File**. | Path-form download. Preserve the signed token returned by the submission endpoint. |
656
+
657
+ For async jobs, connect the submission node to a **Wait** node, then a status
658
+ HTTP Request node. Loop while the state is `QUEUED` or `RUNNING`; download only
659
+ after `COMPLETED`. A typical status URL expression is:
660
+
661
+ ```text
662
+ ={{ $env.MAESTER_BASE_URL + '/services/render/status/' + $json.job_id }}
663
+ ```
664
+
665
+ The submission response's `status_url` and `download_url` are relative paths.
666
+ Prefix them with `MAESTER_BASE_URL` in n8n. Keep the `token` query string intact
667
+ when constructing a download URL.
668
+
669
+ ## n8n Workflow Examples
670
+
671
+ Importable workflows live in `workflows/n8n/`.
672
+
673
+ - `ai_provider_smoke_test.json`: tests the configured n8n AI provider with OpenAI, Gemini, or OpenRouter and returns the raw provider response.
674
+ - `webhook_tiktok_storytelling_pexels.json`: exposes a POST webhook in n8n, accepts a topic/campaign payload, finds Pexels portrait clips, submits the render to Maester, and returns the render job response.
675
+ - `tiktok_storytelling_pexels.json`: builds a TikTok storytelling mini-series episode, searches Pexels videos per scene, adds captions/text overlay metadata, applies background/effect settings, and submits the result to `/services/render/render`.
676
+ - `autonomous_tiktok_storytelling_miniseries.json`: full workflow for `The Girl Who Disappeared Every Midnight`, including LLM strict JSON story generation, Maester campaign logging, quality/compliance checks, Pexels scene search, KTTS narration, render upload, and final TikTok render submission.
677
+ - `islamic_motivation_tiktok_pipeline.json`: daily Islamic motivation TikTok automation with GPT-4o topic/scenes, Pexels clips, Maester FFmpeg resize/concat/caption/audio tasks, Archive.org nasheed fallback, validation, TikTok dry-run/publish, Google Sheets logging, and Telegram notifications.
678
+
679
+ Example campaign request:
680
+
681
+ ```json
682
+ {
683
+ "name": "Fitness lead magnet week 1",
684
+ "topic": "simple home workouts for busy founders",
685
+ "niche": "fitness coaching",
686
+ "source_url": "https://example.com/source.mp4",
687
+ "platforms": ["tiktok", "instagram_reels", "facebook_shorts"],
688
+ "quantity": 12,
689
+ "tone": "direct, useful, high-retention",
690
+ "target_audience": "busy professionals"
691
+ }
692
+ ```
693
+
694
+ ## Run With Docker Compose
695
+
696
+ ```bash
697
+ cp .env.example .env
698
+ # Edit .env and set MAESTER_API_KEY, N8N_ENCRYPTION_KEY, and any provider secrets you need.
699
+ docker compose up --build
700
+ ```
701
+
702
+ Then call:
703
+
704
+ ```bash
705
+ curl http://localhost:7860/health
706
+ curl -H "X-API-Key: $MAESTER_API_KEY" http://localhost:7860/services
707
+ ```
708
+
709
+ n8n runs with the same stack at:
710
+
711
+ ```text
712
+ http://localhost:5678
713
+ ```
714
+
715
+ Inside n8n imports, `MAESTER_BASE_URL` is already set to `http://maester-enterprise:7860`, so workflow HTTP nodes can call Maester over the Docker network. Import the JSON files from `workflows/n8n/`, then activate the webhook or scheduled workflows you want to use.
716
+
717
+ The n8n container also receives provider-neutral AI configuration:
718
+
719
+ ```env
720
+ AI_PROVIDER=openai|gemini|openrouter
721
+ LLM_PROVIDER=openai|gemini|openrouter
722
+ LLM_MODEL=gpt-4o-mini
723
+ OPENAI_API_KEY=
724
+ GEMINI_API_KEY=
725
+ OPENROUTER_API_KEY=
726
+ ```
727
+
728
+ Use `workflows/n8n/ai_provider_smoke_test.json` to verify the selected provider before wiring it into a production workflow.
729
+
730
+ ## Hugging Face CPU Mode
731
+
732
+ The default [Dockerfile](Dockerfile) is CPU-focused for Hugging Face Spaces and enables all embedded services:
733
+
734
+ ```env
735
+ MAESTER_CPU_SAFE_MODE=true
736
+ MAESTER_MOUNT_SERVICES=true
737
+ MAESTER_ENABLE_KTTS=true
738
+ MAESTER_ENABLE_MUSICGEN=true
739
+ MAESTER_ENABLE_WHISPER=true
740
+ MAESTER_ENABLE_FFMPEG_AUTOMATION=true
741
+ MAESTER_ENABLE_RENDER_ENGINE=true
742
+ CUDA_VISIBLE_DEVICES=
743
+ WHISPER_DEVICE=cpu
744
+ WHISPER_COMPUTE_TYPE=int8
745
+ MAX_RENDER_WORKERS=1
746
+ ```
747
+
748
+ This mode runs the full gateway plus all mounted services while constraining runtime to CPU. MusicGen and Whisper can still be slow on free CPU hardware because model loading and inference are inherently heavy; the defaults keep rendering to one worker, force Whisper CPU/int8, hide CUDA devices, and limit common thread pools.
749
+
750
+ For Hugging Face Spaces, set these as Space secrets before exposing the app:
751
+
752
+ ```env
753
+ MAESTER_API_KEY=your-long-api-key
754
+ AVA2LON_SIGNING_SECRET=your-long-render-secret
755
+ BASYX_SIGNING_SECRET=your-long-render-secret
756
+ ```
757
+
758
+ For a lighter control-plane-only deployment, use [Dockerfile.gateway](Dockerfile.gateway). [Dockerfile.full](Dockerfile.full) is kept as an explicit full-stack alias.
759
+
760
+ ## Local Development
761
+
762
+ Python is not available in the current Termux environment, but on a machine with Python:
763
+
764
+ ```bash
765
+ python -m venv .venv
766
+ . .venv/bin/activate
767
+ pip install -r requirements.txt
768
+ MAESTER_ENV=development MAESTER_ALLOW_DEV_NO_API_KEY=true uvicorn maester_enterprise.main:app --reload
769
+ ```
770
+
771
+ ## Production Notes
772
+
773
+ - Set `MAESTER_API_KEY` before exposing the app.
774
+ - Set `AVA2LON_SIGNING_SECRET` and `BASYX_SIGNING_SECRET`; do not use defaults.
775
+ - Keep `ALLOW_PRIVATE_ASSET_URLS=false` unless the deployment is isolated and trusted.
776
+ - Disable unused services with `MAESTER_ENABLE_<SERVICE>=false` only if you want a smaller/faster deployment.
777
+ - Put this app behind TLS and a real edge proxy for internet exposure.
docker-compose.yml ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ services:
2
+ maester-enterprise:
3
+ build: .
4
+ env_file:
5
+ - .env
6
+ ports:
7
+ - "7860:7860"
8
+ volumes:
9
+ - maester-data:/app/data
10
+ restart: unless-stopped
11
+ healthcheck:
12
+ test: ["CMD", "curl", "-fsS", "http://localhost:7860/health"]
13
+ interval: 30s
14
+ timeout: 10s
15
+ retries: 3
16
+ start_period: 60s
17
+
18
+ n8n:
19
+ image: docker.n8n.io/n8nio/n8n
20
+ env_file:
21
+ - .env
22
+ ports:
23
+ - "5678:5678"
24
+ environment:
25
+ N8N_HOST: ${N8N_HOST:-localhost}
26
+ N8N_PORT: ${N8N_PORT:-5678}
27
+ N8N_PROTOCOL: ${N8N_PROTOCOL:-http}
28
+ WEBHOOK_URL: ${N8N_WEBHOOK_URL:-http://localhost:5678/}
29
+ N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY}
30
+ N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS: "true"
31
+ N8N_RUNNERS_ENABLED: "true"
32
+ N8N_DIAGNOSTICS_ENABLED: "false"
33
+ N8N_PERSONALIZATION_ENABLED: "false"
34
+ GENERIC_TIMEZONE: ${GENERIC_TIMEZONE:-UTC}
35
+ TZ: ${GENERIC_TIMEZONE:-UTC}
36
+ MAESTER_BASE_URL: http://maester-enterprise:7860
37
+ MAESTER_API_KEY: ${MAESTER_API_KEY}
38
+ AI_PROVIDER: ${AI_PROVIDER:-openai}
39
+ LLM_PROVIDER: ${LLM_PROVIDER:-openai}
40
+ LLM_MODEL: ${LLM_MODEL:-gpt-4o-mini}
41
+ OPENAI_API_KEY: ${OPENAI_API_KEY}
42
+ OPENAI_BASE_URL: ${OPENAI_BASE_URL:-https://api.openai.com/v1}
43
+ OPENAI_MODEL: ${OPENAI_MODEL:-gpt-4o-mini}
44
+ GEMINI_API_KEY: ${GEMINI_API_KEY}
45
+ GEMINI_BASE_URL: ${GEMINI_BASE_URL:-https://generativelanguage.googleapis.com/v1beta}
46
+ GEMINI_MODEL: ${GEMINI_MODEL:-gemini-1.5-flash}
47
+ OPENROUTER_API_KEY: ${OPENROUTER_API_KEY}
48
+ OPENROUTER_BASE_URL: ${OPENROUTER_BASE_URL:-https://openrouter.ai/api/v1}
49
+ OPENROUTER_MODEL: ${OPENROUTER_MODEL:-openai/gpt-4o-mini}
50
+ OPENROUTER_SITE_URL: ${OPENROUTER_SITE_URL:-http://localhost:5678}
51
+ OPENROUTER_APP_NAME: "${OPENROUTER_APP_NAME:-Maester Enterprise}"
52
+ PEXELS_API_KEY: ${PEXELS_API_KEY}
53
+ KTTS_MODEL: ${KTTS_MODEL:-kokoro-v0_19.onnx}
54
+ KTTS_VOICE: ${KTTS_VOICE:-af_bella.pt}
55
+ TELEGRAM_BOT_TOKEN: ${TELEGRAM_BOT_TOKEN}
56
+ TELEGRAM_CHAT_ID: ${TELEGRAM_CHAT_ID}
57
+ GOOGLE_SHEETS_WEBHOOK_URL: ${GOOGLE_SHEETS_WEBHOOK_URL}
58
+ TIKTOK_UPLOAD_ENABLED: ${TIKTOK_UPLOAD_ENABLED:-false}
59
+ TIKTOK_ACCESS_TOKEN: ${TIKTOK_ACCESS_TOKEN}
60
+ volumes:
61
+ - n8n-data:/home/node/.n8n
62
+ depends_on:
63
+ maester-enterprise:
64
+ condition: service_healthy
65
+ restart: unless-stopped
66
+
67
+ volumes:
68
+ maester-data:
69
+ n8n-data:
requirements-gateway.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ fastapi>=0.115.0
2
+ uvicorn[standard]>=0.30.0
3
+ python-multipart>=0.0.9
4
+ pydantic>=2.7.0
requirements.txt CHANGED
@@ -1,10 +1,10 @@
1
- fastapi
2
- uvicorn
3
- gradio
4
- torch
5
- torchaudio
6
- transformers
7
- accelerate
8
- soundfile
9
- scipy
10
- numpy
 
1
+ fastapi>=0.115.0
2
+ uvicorn[standard]>=0.30.0
3
+ python-multipart>=0.0.9
4
+
5
+ # Vendored service dependencies
6
+ -r services/ktts/requirements.txt
7
+ -r services/musicgen/requirements.txt
8
+ -r services/whisper/requirements.txt
9
+ -r services/ffmpeg_automation/requirements.txt
10
+ -r services/render_engine/requirements.txt