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.
Files changed (44) hide show
  1. demodsl-2.0.0/.github/workflows/deploy-docs.yml +47 -0
  2. demodsl-2.0.0/.github/workflows/publish.yml +48 -0
  3. demodsl-2.0.0/.gitignore +31 -0
  4. demodsl-2.0.0/LICENSE +21 -0
  5. demodsl-2.0.0/MANIFEST.in +4 -0
  6. demodsl-2.0.0/PKG-INFO +181 -0
  7. demodsl-2.0.0/README.md +143 -0
  8. demodsl-2.0.0/demodsl/__init__.py +3 -0
  9. demodsl-2.0.0/demodsl/cli.py +155 -0
  10. demodsl-2.0.0/demodsl/commands.py +117 -0
  11. demodsl-2.0.0/demodsl/effects/__init__.py +0 -0
  12. demodsl-2.0.0/demodsl/effects/browser_effects.py +267 -0
  13. demodsl-2.0.0/demodsl/effects/post_effects.py +113 -0
  14. demodsl-2.0.0/demodsl/effects/registry.py +60 -0
  15. demodsl-2.0.0/demodsl/engine.py +233 -0
  16. demodsl-2.0.0/demodsl/models.py +270 -0
  17. demodsl-2.0.0/demodsl/pipeline/__init__.py +0 -0
  18. demodsl-2.0.0/demodsl/pipeline/stages.py +240 -0
  19. demodsl-2.0.0/demodsl/pipeline/workspace.py +71 -0
  20. demodsl-2.0.0/demodsl/providers/__init__.py +0 -0
  21. demodsl-2.0.0/demodsl/providers/base.py +136 -0
  22. demodsl-2.0.0/demodsl/providers/browser.py +100 -0
  23. demodsl-2.0.0/demodsl/providers/render.py +200 -0
  24. demodsl-2.0.0/demodsl/providers/voice.py +524 -0
  25. demodsl-2.0.0/docs/next-env.d.ts +6 -0
  26. demodsl-2.0.0/docs/next.config.js +8 -0
  27. demodsl-2.0.0/docs/package-lock.json +1651 -0
  28. demodsl-2.0.0/docs/package.json +24 -0
  29. demodsl-2.0.0/docs/postcss.config.js +5 -0
  30. demodsl-2.0.0/docs/src/app/docs/page.tsx +1083 -0
  31. demodsl-2.0.0/docs/src/app/globals.css +26 -0
  32. demodsl-2.0.0/docs/src/app/layout.tsx +24 -0
  33. demodsl-2.0.0/docs/src/app/page.tsx +19 -0
  34. demodsl-2.0.0/docs/src/components/Architecture.tsx +101 -0
  35. demodsl-2.0.0/docs/src/components/CodeExample.tsx +136 -0
  36. demodsl-2.0.0/docs/src/components/Features.tsx +69 -0
  37. demodsl-2.0.0/docs/src/components/Footer.tsx +43 -0
  38. demodsl-2.0.0/docs/src/components/Hero.tsx +50 -0
  39. demodsl-2.0.0/docs/src/components/Install.tsx +51 -0
  40. demodsl-2.0.0/docs/src/components/Navbar.tsx +57 -0
  41. demodsl-2.0.0/docs/tsconfig.json +21 -0
  42. demodsl-2.0.0/example.yaml +326 -0
  43. demodsl-2.0.0/prompt.md +662 -0
  44. 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
@@ -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.
@@ -0,0 +1,4 @@
1
+ include LICENSE
2
+ include README.md
3
+ include example.yaml
4
+ recursive-include demodsl *.py
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
@@ -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,3 @@
1
+ """DemoDSL — DSL-driven automated product demo video generator."""
2
+
3
+ __version__ = "2.0.0"
@@ -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()