demodsl 2.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- demodsl-2.0.0/.github/workflows/deploy-docs.yml +47 -0
- demodsl-2.0.0/.github/workflows/publish.yml +48 -0
- demodsl-2.0.0/.gitignore +31 -0
- demodsl-2.0.0/LICENSE +21 -0
- demodsl-2.0.0/MANIFEST.in +4 -0
- demodsl-2.0.0/PKG-INFO +181 -0
- demodsl-2.0.0/README.md +143 -0
- demodsl-2.0.0/demodsl/__init__.py +3 -0
- demodsl-2.0.0/demodsl/cli.py +155 -0
- demodsl-2.0.0/demodsl/commands.py +117 -0
- demodsl-2.0.0/demodsl/effects/__init__.py +0 -0
- demodsl-2.0.0/demodsl/effects/browser_effects.py +267 -0
- demodsl-2.0.0/demodsl/effects/post_effects.py +113 -0
- demodsl-2.0.0/demodsl/effects/registry.py +60 -0
- demodsl-2.0.0/demodsl/engine.py +233 -0
- demodsl-2.0.0/demodsl/models.py +270 -0
- demodsl-2.0.0/demodsl/pipeline/__init__.py +0 -0
- demodsl-2.0.0/demodsl/pipeline/stages.py +240 -0
- demodsl-2.0.0/demodsl/pipeline/workspace.py +71 -0
- demodsl-2.0.0/demodsl/providers/__init__.py +0 -0
- demodsl-2.0.0/demodsl/providers/base.py +136 -0
- demodsl-2.0.0/demodsl/providers/browser.py +100 -0
- demodsl-2.0.0/demodsl/providers/render.py +200 -0
- demodsl-2.0.0/demodsl/providers/voice.py +524 -0
- demodsl-2.0.0/docs/next-env.d.ts +6 -0
- demodsl-2.0.0/docs/next.config.js +8 -0
- demodsl-2.0.0/docs/package-lock.json +1651 -0
- demodsl-2.0.0/docs/package.json +24 -0
- demodsl-2.0.0/docs/postcss.config.js +5 -0
- demodsl-2.0.0/docs/src/app/docs/page.tsx +1083 -0
- demodsl-2.0.0/docs/src/app/globals.css +26 -0
- demodsl-2.0.0/docs/src/app/layout.tsx +24 -0
- demodsl-2.0.0/docs/src/app/page.tsx +19 -0
- demodsl-2.0.0/docs/src/components/Architecture.tsx +101 -0
- demodsl-2.0.0/docs/src/components/CodeExample.tsx +136 -0
- demodsl-2.0.0/docs/src/components/Features.tsx +69 -0
- demodsl-2.0.0/docs/src/components/Footer.tsx +43 -0
- demodsl-2.0.0/docs/src/components/Hero.tsx +50 -0
- demodsl-2.0.0/docs/src/components/Install.tsx +51 -0
- demodsl-2.0.0/docs/src/components/Navbar.tsx +57 -0
- demodsl-2.0.0/docs/tsconfig.json +21 -0
- demodsl-2.0.0/example.yaml +326 -0
- demodsl-2.0.0/prompt.md +662 -0
- demodsl-2.0.0/pyproject.toml +52 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
name: Deploy Docs to GitHub Pages
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
pages: write
|
|
11
|
+
id-token: write
|
|
12
|
+
|
|
13
|
+
concurrency:
|
|
14
|
+
group: pages
|
|
15
|
+
cancel-in-progress: true
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
build:
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
defaults:
|
|
21
|
+
run:
|
|
22
|
+
working-directory: docs
|
|
23
|
+
steps:
|
|
24
|
+
- uses: actions/checkout@v4
|
|
25
|
+
|
|
26
|
+
- uses: actions/setup-node@v4
|
|
27
|
+
with:
|
|
28
|
+
node-version: "20"
|
|
29
|
+
cache: npm
|
|
30
|
+
cache-dependency-path: docs/package-lock.json
|
|
31
|
+
|
|
32
|
+
- run: npm ci
|
|
33
|
+
- run: npm run build
|
|
34
|
+
|
|
35
|
+
- uses: actions/upload-pages-artifact@v3
|
|
36
|
+
with:
|
|
37
|
+
path: docs/out
|
|
38
|
+
|
|
39
|
+
deploy:
|
|
40
|
+
needs: build
|
|
41
|
+
runs-on: ubuntu-latest
|
|
42
|
+
environment:
|
|
43
|
+
name: github-pages
|
|
44
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
45
|
+
steps:
|
|
46
|
+
- id: deployment
|
|
47
|
+
uses: actions/deploy-pages@v4
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
build:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
|
|
16
|
+
- uses: actions/setup-python@v5
|
|
17
|
+
with:
|
|
18
|
+
python-version: "3.12"
|
|
19
|
+
|
|
20
|
+
- name: Install build tools
|
|
21
|
+
run: pip install build
|
|
22
|
+
|
|
23
|
+
- name: Build package
|
|
24
|
+
run: python -m build
|
|
25
|
+
|
|
26
|
+
- name: Upload artifact
|
|
27
|
+
uses: actions/upload-artifact@v4
|
|
28
|
+
with:
|
|
29
|
+
name: dist
|
|
30
|
+
path: dist/
|
|
31
|
+
|
|
32
|
+
publish:
|
|
33
|
+
needs: build
|
|
34
|
+
runs-on: ubuntu-latest
|
|
35
|
+
environment:
|
|
36
|
+
name: pypi
|
|
37
|
+
url: https://pypi.org/p/demodsl
|
|
38
|
+
permissions:
|
|
39
|
+
id-token: write # trusted publishing
|
|
40
|
+
steps:
|
|
41
|
+
- name: Download artifact
|
|
42
|
+
uses: actions/download-artifact@v4
|
|
43
|
+
with:
|
|
44
|
+
name: dist
|
|
45
|
+
path: dist/
|
|
46
|
+
|
|
47
|
+
- name: Publish to PyPI
|
|
48
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
demodsl-2.0.0/.gitignore
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
dist/
|
|
6
|
+
build/
|
|
7
|
+
.eggs/
|
|
8
|
+
|
|
9
|
+
# Virtual environments
|
|
10
|
+
.venv/
|
|
11
|
+
venv/
|
|
12
|
+
|
|
13
|
+
# IDE
|
|
14
|
+
.idea/
|
|
15
|
+
.vscode/
|
|
16
|
+
*.swp
|
|
17
|
+
|
|
18
|
+
# OS
|
|
19
|
+
.DS_Store
|
|
20
|
+
Thumbs.db
|
|
21
|
+
|
|
22
|
+
# Next.js docs
|
|
23
|
+
docs/node_modules/
|
|
24
|
+
docs/.next/
|
|
25
|
+
docs/out/
|
|
26
|
+
|
|
27
|
+
# Project
|
|
28
|
+
output/
|
|
29
|
+
*.mp4
|
|
30
|
+
*.webm
|
|
31
|
+
*.gif
|
demodsl-2.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Fran-cois
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
demodsl-2.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: demodsl
|
|
3
|
+
Version: 2.0.0
|
|
4
|
+
Summary: DSL-driven automated product demo video generator
|
|
5
|
+
Project-URL: Homepage, https://fran-cois.github.io/demodsl
|
|
6
|
+
Project-URL: Repository, https://github.com/Fran-cois/demodsl
|
|
7
|
+
Project-URL: Documentation, https://fran-cois.github.io/demodsl
|
|
8
|
+
Project-URL: Issues, https://github.com/Fran-cois/demodsl/issues
|
|
9
|
+
Author-email: Fran-cois <francois@demodsl.dev>
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: automation,demo,dsl,playwright,tts,video
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Multimedia :: Video
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
+
Requires-Python: >=3.11
|
|
23
|
+
Requires-Dist: ffmpeg-python>=0.2
|
|
24
|
+
Requires-Dist: httpx>=0.25
|
|
25
|
+
Requires-Dist: moviepy>=1.0
|
|
26
|
+
Requires-Dist: pillow>=10.0
|
|
27
|
+
Requires-Dist: playwright>=1.40
|
|
28
|
+
Requires-Dist: pydantic>=2.0
|
|
29
|
+
Requires-Dist: pydub>=0.25
|
|
30
|
+
Requires-Dist: python-dotenv>=1.0
|
|
31
|
+
Requires-Dist: pyyaml>=6.0
|
|
32
|
+
Requires-Dist: typer>=0.9
|
|
33
|
+
Provides-Extra: dev
|
|
34
|
+
Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
|
|
35
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
36
|
+
Requires-Dist: ruff>=0.4; extra == 'dev'
|
|
37
|
+
Description-Content-Type: text/markdown
|
|
38
|
+
|
|
39
|
+
# DemoDSL
|
|
40
|
+
|
|
41
|
+
**DSL-driven automated product demo video generator.**
|
|
42
|
+
|
|
43
|
+
Define your product demos in YAML or JSON — DemoDSL handles browser automation, voice narration, visual effects, video editing, and final export.
|
|
44
|
+
|
|
45
|
+
## Features
|
|
46
|
+
|
|
47
|
+
- **YAML & JSON DSL** — Declarative scenario definitions with steps, effects, and narration
|
|
48
|
+
- **Browser Automation** — Playwright-powered capture (Chrome, Firefox, WebKit)
|
|
49
|
+
- **Voice Narration** — ElevenLabs TTS with automatic sync to video
|
|
50
|
+
- **18 Visual Effects** — Spotlight, confetti, glitch, neon glow, and more
|
|
51
|
+
- **Video Composition** — Intro/outro, transitions, watermarks via MoviePy
|
|
52
|
+
- **Audio Mixing** — Background music with smart ducking during narration
|
|
53
|
+
- **Multi-format Export** — MP4, WebM, GIF + social media presets (YouTube, Instagram, Twitter)
|
|
54
|
+
|
|
55
|
+
## Installation
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
pip install demodsl
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Then install Playwright browsers:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
playwright install chromium
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Quick Start
|
|
68
|
+
|
|
69
|
+
**1. Generate a template:**
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
demodsl init
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**2. Edit `demo.yaml`:**
|
|
76
|
+
|
|
77
|
+
```yaml
|
|
78
|
+
metadata:
|
|
79
|
+
title: "My Product Demo"
|
|
80
|
+
|
|
81
|
+
scenarios:
|
|
82
|
+
- name: "Main Demo"
|
|
83
|
+
url: "https://myapp.com"
|
|
84
|
+
steps:
|
|
85
|
+
- action: "navigate"
|
|
86
|
+
url: "https://myapp.com"
|
|
87
|
+
narration: "Welcome to our product!"
|
|
88
|
+
effects:
|
|
89
|
+
- type: "spotlight"
|
|
90
|
+
duration: 2.0
|
|
91
|
+
|
|
92
|
+
pipeline:
|
|
93
|
+
- generate_narration: {}
|
|
94
|
+
- edit_video: {}
|
|
95
|
+
- mix_audio: {}
|
|
96
|
+
- optimize:
|
|
97
|
+
format: "mp4"
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**3. Run:**
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
demodsl run demo.yaml
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
**4. Validate without executing:**
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
demodsl validate demo.yaml
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## CLI Commands
|
|
113
|
+
|
|
114
|
+
| Command | Description |
|
|
115
|
+
|---------|-------------|
|
|
116
|
+
| `demodsl run <config>` | Execute the full pipeline |
|
|
117
|
+
| `demodsl validate <config>` | Validate config without executing |
|
|
118
|
+
| `demodsl init` | Generate a minimal template |
|
|
119
|
+
| `demodsl init -o demo.json` | Generate a JSON template |
|
|
120
|
+
|
|
121
|
+
### Options
|
|
122
|
+
|
|
123
|
+
- `--output-dir, -o` — Output directory (default: `output/`)
|
|
124
|
+
- `--dry-run` — Log all steps without executing
|
|
125
|
+
- `--skip-voice` — Skip TTS generation (dev mode)
|
|
126
|
+
- `--verbose, -v` — Debug logging
|
|
127
|
+
|
|
128
|
+
## Architecture
|
|
129
|
+
|
|
130
|
+
DemoDSL uses a modular architecture with 5 design patterns:
|
|
131
|
+
|
|
132
|
+
| Component | Pattern | Purpose |
|
|
133
|
+
|-----------|---------|---------|
|
|
134
|
+
| Providers | Abstract Factory | Voice, Browser, Render provider instantiation |
|
|
135
|
+
| Browser Actions | Command | Navigate, Click, Type, Scroll, WaitFor, Screenshot |
|
|
136
|
+
| Pipeline | Chain of Responsibility | 8 stages with critical/optional error handling |
|
|
137
|
+
| Visual Effects | Registry + Strategy | 18 effects in 2 registries (browser JS + post-processing) |
|
|
138
|
+
| Video Composition | Builder | Progressive intro → segments → watermark → outro assembly |
|
|
139
|
+
|
|
140
|
+
## Pipeline Stages
|
|
141
|
+
|
|
142
|
+
| Stage | Critical | Description |
|
|
143
|
+
|-------|----------|-------------|
|
|
144
|
+
| `restore_audio` | Optional | Denoise + normalize audio |
|
|
145
|
+
| `restore_video` | Optional | Stabilize + sharpen video |
|
|
146
|
+
| `apply_effects` | Optional | Post-processing visual effects |
|
|
147
|
+
| `generate_narration` | **Critical** | TTS generation + video sync |
|
|
148
|
+
| `render_device_mockup` | Optional | Device frame overlay |
|
|
149
|
+
| `edit_video` | **Critical** | Intro, outro, transitions, watermark |
|
|
150
|
+
| `mix_audio` | **Critical** | Voice + background music ducking |
|
|
151
|
+
| `optimize` | **Critical** | Final encoding + compression |
|
|
152
|
+
|
|
153
|
+
## Environment Variables
|
|
154
|
+
|
|
155
|
+
| Variable | Description |
|
|
156
|
+
|----------|-------------|
|
|
157
|
+
| `ELEVENLABS_API_KEY` | ElevenLabs TTS API key |
|
|
158
|
+
| `OPENAI_API_KEY` | OpenAI API key (tts-1-hd) |
|
|
159
|
+
| `GOOGLE_APPLICATION_CREDENTIALS` | Path to Google Cloud service account JSON |
|
|
160
|
+
| `AZURE_SPEECH_KEY` | Azure Cognitive Services Speech key |
|
|
161
|
+
| `AZURE_SPEECH_REGION` | Azure region (default: `eastus`) |
|
|
162
|
+
| `AWS_ACCESS_KEY_ID` | AWS access key for Polly |
|
|
163
|
+
| `AWS_SECRET_ACCESS_KEY` | AWS secret key for Polly |
|
|
164
|
+
| `AWS_DEFAULT_REGION` | AWS region (default: `us-east-1`) |
|
|
165
|
+
| `COSYVOICE_API_URL` | CosyVoice API server URL (default: `http://localhost:50000`) |
|
|
166
|
+
| `COQUI_MODEL` | Coqui TTS model name (default: `xtts_v2`) |
|
|
167
|
+
| `COQUI_LANGUAGE` | Language code for Coqui TTS (default: `en`) |
|
|
168
|
+
| `PIPER_BIN` | Path to piper binary (default: `piper`) |
|
|
169
|
+
| `PIPER_MODEL` | Path to Piper `.onnx` voice model (required for `piper` engine) |
|
|
170
|
+
| `LOCAL_TTS_URL` | OpenAI-compatible local TTS server URL (default: `http://localhost:8000`) |
|
|
171
|
+
| `LOCAL_TTS_API_KEY` | API key for local TTS server (default: `not-needed`) |
|
|
172
|
+
| `LOCAL_TTS_MODEL` | Model name for local TTS server (default: `tts-1`) |
|
|
173
|
+
| `ESPEAK_BIN` | Path to eSpeak-NG binary (default: `espeak-ng`) |
|
|
174
|
+
|
|
175
|
+
Without the required credentials, DemoDSL falls back to a silent dummy provider for development.
|
|
176
|
+
|
|
177
|
+
> **Vintage / debug providers**: `espeak` and `gtts` need no API key — ideal pour le prototypage rapide. `espeak` donne un son robotique rétro, `gtts` utilise Google Translate (nécessite internet + `pip install gtts`).
|
|
178
|
+
|
|
179
|
+
## License
|
|
180
|
+
|
|
181
|
+
MIT
|
demodsl-2.0.0/README.md
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# DemoDSL
|
|
2
|
+
|
|
3
|
+
**DSL-driven automated product demo video generator.**
|
|
4
|
+
|
|
5
|
+
Define your product demos in YAML or JSON — DemoDSL handles browser automation, voice narration, visual effects, video editing, and final export.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **YAML & JSON DSL** — Declarative scenario definitions with steps, effects, and narration
|
|
10
|
+
- **Browser Automation** — Playwright-powered capture (Chrome, Firefox, WebKit)
|
|
11
|
+
- **Voice Narration** — ElevenLabs TTS with automatic sync to video
|
|
12
|
+
- **18 Visual Effects** — Spotlight, confetti, glitch, neon glow, and more
|
|
13
|
+
- **Video Composition** — Intro/outro, transitions, watermarks via MoviePy
|
|
14
|
+
- **Audio Mixing** — Background music with smart ducking during narration
|
|
15
|
+
- **Multi-format Export** — MP4, WebM, GIF + social media presets (YouTube, Instagram, Twitter)
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pip install demodsl
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Then install Playwright browsers:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
playwright install chromium
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Quick Start
|
|
30
|
+
|
|
31
|
+
**1. Generate a template:**
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
demodsl init
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**2. Edit `demo.yaml`:**
|
|
38
|
+
|
|
39
|
+
```yaml
|
|
40
|
+
metadata:
|
|
41
|
+
title: "My Product Demo"
|
|
42
|
+
|
|
43
|
+
scenarios:
|
|
44
|
+
- name: "Main Demo"
|
|
45
|
+
url: "https://myapp.com"
|
|
46
|
+
steps:
|
|
47
|
+
- action: "navigate"
|
|
48
|
+
url: "https://myapp.com"
|
|
49
|
+
narration: "Welcome to our product!"
|
|
50
|
+
effects:
|
|
51
|
+
- type: "spotlight"
|
|
52
|
+
duration: 2.0
|
|
53
|
+
|
|
54
|
+
pipeline:
|
|
55
|
+
- generate_narration: {}
|
|
56
|
+
- edit_video: {}
|
|
57
|
+
- mix_audio: {}
|
|
58
|
+
- optimize:
|
|
59
|
+
format: "mp4"
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**3. Run:**
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
demodsl run demo.yaml
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
**4. Validate without executing:**
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
demodsl validate demo.yaml
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## CLI Commands
|
|
75
|
+
|
|
76
|
+
| Command | Description |
|
|
77
|
+
|---------|-------------|
|
|
78
|
+
| `demodsl run <config>` | Execute the full pipeline |
|
|
79
|
+
| `demodsl validate <config>` | Validate config without executing |
|
|
80
|
+
| `demodsl init` | Generate a minimal template |
|
|
81
|
+
| `demodsl init -o demo.json` | Generate a JSON template |
|
|
82
|
+
|
|
83
|
+
### Options
|
|
84
|
+
|
|
85
|
+
- `--output-dir, -o` — Output directory (default: `output/`)
|
|
86
|
+
- `--dry-run` — Log all steps without executing
|
|
87
|
+
- `--skip-voice` — Skip TTS generation (dev mode)
|
|
88
|
+
- `--verbose, -v` — Debug logging
|
|
89
|
+
|
|
90
|
+
## Architecture
|
|
91
|
+
|
|
92
|
+
DemoDSL uses a modular architecture with 5 design patterns:
|
|
93
|
+
|
|
94
|
+
| Component | Pattern | Purpose |
|
|
95
|
+
|-----------|---------|---------|
|
|
96
|
+
| Providers | Abstract Factory | Voice, Browser, Render provider instantiation |
|
|
97
|
+
| Browser Actions | Command | Navigate, Click, Type, Scroll, WaitFor, Screenshot |
|
|
98
|
+
| Pipeline | Chain of Responsibility | 8 stages with critical/optional error handling |
|
|
99
|
+
| Visual Effects | Registry + Strategy | 18 effects in 2 registries (browser JS + post-processing) |
|
|
100
|
+
| Video Composition | Builder | Progressive intro → segments → watermark → outro assembly |
|
|
101
|
+
|
|
102
|
+
## Pipeline Stages
|
|
103
|
+
|
|
104
|
+
| Stage | Critical | Description |
|
|
105
|
+
|-------|----------|-------------|
|
|
106
|
+
| `restore_audio` | Optional | Denoise + normalize audio |
|
|
107
|
+
| `restore_video` | Optional | Stabilize + sharpen video |
|
|
108
|
+
| `apply_effects` | Optional | Post-processing visual effects |
|
|
109
|
+
| `generate_narration` | **Critical** | TTS generation + video sync |
|
|
110
|
+
| `render_device_mockup` | Optional | Device frame overlay |
|
|
111
|
+
| `edit_video` | **Critical** | Intro, outro, transitions, watermark |
|
|
112
|
+
| `mix_audio` | **Critical** | Voice + background music ducking |
|
|
113
|
+
| `optimize` | **Critical** | Final encoding + compression |
|
|
114
|
+
|
|
115
|
+
## Environment Variables
|
|
116
|
+
|
|
117
|
+
| Variable | Description |
|
|
118
|
+
|----------|-------------|
|
|
119
|
+
| `ELEVENLABS_API_KEY` | ElevenLabs TTS API key |
|
|
120
|
+
| `OPENAI_API_KEY` | OpenAI API key (tts-1-hd) |
|
|
121
|
+
| `GOOGLE_APPLICATION_CREDENTIALS` | Path to Google Cloud service account JSON |
|
|
122
|
+
| `AZURE_SPEECH_KEY` | Azure Cognitive Services Speech key |
|
|
123
|
+
| `AZURE_SPEECH_REGION` | Azure region (default: `eastus`) |
|
|
124
|
+
| `AWS_ACCESS_KEY_ID` | AWS access key for Polly |
|
|
125
|
+
| `AWS_SECRET_ACCESS_KEY` | AWS secret key for Polly |
|
|
126
|
+
| `AWS_DEFAULT_REGION` | AWS region (default: `us-east-1`) |
|
|
127
|
+
| `COSYVOICE_API_URL` | CosyVoice API server URL (default: `http://localhost:50000`) |
|
|
128
|
+
| `COQUI_MODEL` | Coqui TTS model name (default: `xtts_v2`) |
|
|
129
|
+
| `COQUI_LANGUAGE` | Language code for Coqui TTS (default: `en`) |
|
|
130
|
+
| `PIPER_BIN` | Path to piper binary (default: `piper`) |
|
|
131
|
+
| `PIPER_MODEL` | Path to Piper `.onnx` voice model (required for `piper` engine) |
|
|
132
|
+
| `LOCAL_TTS_URL` | OpenAI-compatible local TTS server URL (default: `http://localhost:8000`) |
|
|
133
|
+
| `LOCAL_TTS_API_KEY` | API key for local TTS server (default: `not-needed`) |
|
|
134
|
+
| `LOCAL_TTS_MODEL` | Model name for local TTS server (default: `tts-1`) |
|
|
135
|
+
| `ESPEAK_BIN` | Path to eSpeak-NG binary (default: `espeak-ng`) |
|
|
136
|
+
|
|
137
|
+
Without the required credentials, DemoDSL falls back to a silent dummy provider for development.
|
|
138
|
+
|
|
139
|
+
> **Vintage / debug providers**: `espeak` and `gtts` need no API key — ideal pour le prototypage rapide. `espeak` donne un son robotique rétro, `gtts` utilise Google Translate (nécessite internet + `pip install gtts`).
|
|
140
|
+
|
|
141
|
+
## License
|
|
142
|
+
|
|
143
|
+
MIT
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"""CLI for DemoDSL — Typer-based interface."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
import typer
|
|
9
|
+
|
|
10
|
+
app = typer.Typer(name="demodsl", help="DSL-driven automated product demo video generator. Supports YAML and JSON configs.")
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@app.command()
|
|
14
|
+
def run(
|
|
15
|
+
config: Path = typer.Argument(..., help="Path to the YAML or JSON config file."),
|
|
16
|
+
output_dir: Path = typer.Option("output", "--output-dir", "-o", help="Output directory."),
|
|
17
|
+
dry_run: bool = typer.Option(False, "--dry-run", help="Validate and log without executing."),
|
|
18
|
+
skip_voice: bool = typer.Option(False, "--skip-voice", help="Skip TTS generation."),
|
|
19
|
+
verbose: bool = typer.Option(False, "--verbose", "-v", help="Enable debug logging."),
|
|
20
|
+
) -> None:
|
|
21
|
+
"""Parse and execute a DemoDSL config (YAML or JSON)."""
|
|
22
|
+
_setup_logging(verbose)
|
|
23
|
+
|
|
24
|
+
from demodsl.engine import DemoEngine
|
|
25
|
+
|
|
26
|
+
engine = DemoEngine(
|
|
27
|
+
config_path=config,
|
|
28
|
+
dry_run=dry_run,
|
|
29
|
+
skip_voice=skip_voice,
|
|
30
|
+
output_dir=output_dir,
|
|
31
|
+
)
|
|
32
|
+
result = engine.run()
|
|
33
|
+
if result:
|
|
34
|
+
typer.echo(f"Done → {result}")
|
|
35
|
+
else:
|
|
36
|
+
typer.echo("Done (no output file produced).")
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@app.command()
|
|
40
|
+
def validate(
|
|
41
|
+
config: Path = typer.Argument(..., help="Path to the YAML or JSON config file."),
|
|
42
|
+
verbose: bool = typer.Option(False, "--verbose", "-v"),
|
|
43
|
+
) -> None:
|
|
44
|
+
"""Validate a config (YAML or JSON) without executing."""
|
|
45
|
+
_setup_logging(verbose)
|
|
46
|
+
|
|
47
|
+
from demodsl.engine import DemoEngine
|
|
48
|
+
|
|
49
|
+
engine = DemoEngine(config_path=config, dry_run=True)
|
|
50
|
+
cfg = engine.validate()
|
|
51
|
+
typer.echo(f"Valid ✓ — {cfg.metadata.title} (v{cfg.metadata.version})")
|
|
52
|
+
typer.echo(f" Scenarios: {len(cfg.scenarios)}")
|
|
53
|
+
total_steps = sum(len(s.steps) for s in cfg.scenarios)
|
|
54
|
+
typer.echo(f" Steps: {total_steps}")
|
|
55
|
+
typer.echo(f" Pipeline: {len(cfg.pipeline)} stages")
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@app.command()
|
|
59
|
+
def init(
|
|
60
|
+
output: Path = typer.Option("demo.yaml", "--output", "-o", help="Output file path (.yaml or .json)."),
|
|
61
|
+
) -> None:
|
|
62
|
+
"""Generate a minimal config template (YAML or JSON)."""
|
|
63
|
+
if output.suffix.lower() == ".json":
|
|
64
|
+
import json
|
|
65
|
+
|
|
66
|
+
template_data = {
|
|
67
|
+
"metadata": {
|
|
68
|
+
"title": "My Product Demo",
|
|
69
|
+
"description": "A quick demo",
|
|
70
|
+
"version": "1.0.0",
|
|
71
|
+
},
|
|
72
|
+
"voice": {"engine": "elevenlabs", "voice_id": "josh"},
|
|
73
|
+
"scenarios": [
|
|
74
|
+
{
|
|
75
|
+
"name": "Main Demo",
|
|
76
|
+
"url": "https://example.com",
|
|
77
|
+
"browser": "chrome",
|
|
78
|
+
"viewport": {"width": 1920, "height": 1080},
|
|
79
|
+
"steps": [
|
|
80
|
+
{
|
|
81
|
+
"action": "navigate",
|
|
82
|
+
"url": "https://example.com",
|
|
83
|
+
"narration": "Welcome to the demo!",
|
|
84
|
+
"wait": 2.0,
|
|
85
|
+
}
|
|
86
|
+
],
|
|
87
|
+
}
|
|
88
|
+
],
|
|
89
|
+
"pipeline": [
|
|
90
|
+
{"generate_narration": {}},
|
|
91
|
+
{"edit_video": {}},
|
|
92
|
+
{"mix_audio": {}},
|
|
93
|
+
{"optimize": {"format": "mp4", "codec": "h264", "quality": "high"}},
|
|
94
|
+
],
|
|
95
|
+
"output": {
|
|
96
|
+
"filename": "demo.mp4",
|
|
97
|
+
"directory": "output/",
|
|
98
|
+
"formats": ["mp4"],
|
|
99
|
+
},
|
|
100
|
+
}
|
|
101
|
+
output.write_text(json.dumps(template_data, indent=2) + "\n")
|
|
102
|
+
else:
|
|
103
|
+
template = """\
|
|
104
|
+
metadata:
|
|
105
|
+
title: "My Product Demo"
|
|
106
|
+
description: "A quick demo"
|
|
107
|
+
version: "1.0.0"
|
|
108
|
+
|
|
109
|
+
voice:
|
|
110
|
+
engine: "elevenlabs"
|
|
111
|
+
voice_id: "josh"
|
|
112
|
+
|
|
113
|
+
scenarios:
|
|
114
|
+
- name: "Main Demo"
|
|
115
|
+
url: "https://example.com"
|
|
116
|
+
browser: "chrome"
|
|
117
|
+
viewport:
|
|
118
|
+
width: 1920
|
|
119
|
+
height: 1080
|
|
120
|
+
steps:
|
|
121
|
+
- action: "navigate"
|
|
122
|
+
url: "https://example.com"
|
|
123
|
+
narration: "Welcome to the demo!"
|
|
124
|
+
wait: 2.0
|
|
125
|
+
|
|
126
|
+
pipeline:
|
|
127
|
+
- generate_narration: {}
|
|
128
|
+
- edit_video: {}
|
|
129
|
+
- mix_audio: {}
|
|
130
|
+
- optimize:
|
|
131
|
+
format: "mp4"
|
|
132
|
+
codec: "h264"
|
|
133
|
+
quality: "high"
|
|
134
|
+
|
|
135
|
+
output:
|
|
136
|
+
filename: "demo.mp4"
|
|
137
|
+
directory: "output/"
|
|
138
|
+
formats:
|
|
139
|
+
- "mp4"
|
|
140
|
+
"""
|
|
141
|
+
output.write_text(template)
|
|
142
|
+
typer.echo(f"Template created → {output}")
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def _setup_logging(verbose: bool) -> None:
|
|
146
|
+
level = logging.DEBUG if verbose else logging.INFO
|
|
147
|
+
logging.basicConfig(
|
|
148
|
+
level=level,
|
|
149
|
+
format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
|
|
150
|
+
datefmt="%H:%M:%S",
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
if __name__ == "__main__":
|
|
155
|
+
app()
|