Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,23 @@ env:

jobs:
unit:
name: Unit tests
name: Unit tests (node ${{ matrix.node }})
runs-on: ubuntu-latest
# A stalled apt/playwright install should fail fast, not burn the full
# 6h default job budget. The unit suite itself runs in seconds.
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
# Both ends of the supported range. Testing only the top hid a test
# that used a Node 22+ API and silently collected zero assertions
# everywhere below it.
node: [20, 24]
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: 24
node-version: ${{ matrix.node }}
# ffmpeg is needed for boundary-frame extraction and shader pre-render.
- run: sudo apt-get update && sudo apt-get install -y ffmpeg
- run: npm install
Expand Down
12 changes: 12 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,18 @@ Argo turns Playwright demo scripts into polished product demo videos with AI voi
- Kokoro TTS defaults: model `onnx-community/Kokoro-82M-v1.0-ONNX`, dtype `q8`
- Clear TTS cache if voiceover text changes: `rm -rf .argo/<demo>/clips`

## Optional Engine Dependencies (`src/optional-deps.ts`)

All six TTS/STT SDKs (`kokoro-js`, `@huggingface/transformers`, `openai`, `@elevenlabs/elevenlabs-js`, `@google/genai`, `sarvamai`) are **optional peer dependencies**, not `dependencies` or `optionalDependencies`. This is deliberate: npm installs `optionalDependencies` by default (the field only tolerates install *failure*), while `peerDependenciesMeta.optional` is the one field npm never auto-installs. Base install is ~27 MB; a Kokoro user reaches ~435 MB only if they ask for it.

- Every adapter loads its SDK through `importOptional()`, which converts `ERR_MODULE_NOT_FOUND` into an install hint and lets every other failure propagate untouched. Never replace it with a bare `catch` that assumes "missing package" (that was the old behaviour and it misreported broken installs).
- `src/tts/transcribe.ts` MUST keep its `@huggingface/transformers` import dynamic. A top-level import there is reachable from `src/cli.ts`, so it breaks *every* command (`validate`, `export`, `doctor`) when the package is absent, in all three install modes. This was the single blocker to the whole design.
- `@huggingface/transformers` is declared `^3.5.1 || ^4.2.0` on purpose. `kokoro-js@1.2.1` wants `^3.5.1`; pinning Argo to `^4` forces a second nested copy plus a second ONNX runtime (~765 MB vs ~410 MB) because `overrides` only apply in a root `package.json` and stop working once Argo is a dependency. Word-level Whisper timestamps are verified working on 3.8.1.
- The permissive peer *range* does not license a permissive install *hint*. `TRANSFORMERS_DEP`, `WHISPER_DEP` and `MUSICGEN_DEP` all print `@huggingface/transformers@3`, because `latest` is 4.x and a bare `npm i` next to an existing `kokoro-js` produces exactly the two-runtime tree above. Every command Argo prints must resolve to the major `kokoro-js` shares; `tests/optional-deps.test.ts` pins this. Drop the pin only when `kokoro-js` moves to v4.
- Neither `isDepInstalled()` nor `detectInstallMode()` may propagate a resolver failure. A probe can fail without the package being absent: `ERR_INVALID_PACKAGE_CONFIG` from an interrupted install, `ERR_PACKAGE_PATH_NOT_EXPORTED` from an `exports` map with no matching condition (which this package shipped once, see Publishing). Both run inside `importOptional`'s `catch`, where a throw replaces the import error the user needs, and `argo doctor` calls `detectInstallMode()` before anything else, so a throw there costs the whole table on exactly the broken tree the command exists to diagnose. `isDepInstalled` answers "not known to be absent" and `detectInstallMode` falls back to `project`. Both recover only on errors carrying a `code`: a bug in Argo surfaces as a bare `TypeError` and must still throw.
- `detectInstallMode()` distinguishes project / global / npx, because the correct install command differs. Global trees do not hoist, so Kokoro needs `npm i -g kokoro-js@1 @huggingface/transformers@3` in **one** command; two separate `npm i -g` runs produce two ONNX copies (~840 MB vs ~410 MB). Detection resolves `@argo-video/cli` from the cwd and compares identity with the running copy, which keeps pnpm, nested npm, and Yarn PnP working without path-string special cases.
- Surfaces that report engine availability: `argo doctor` (full table), `argo init` (hint when nothing is installed), and the adapters' runtime errors. Keep them consistent when adding an engine.

## Publishing

- Package: `@argo-video/cli` (npm org: `@argo-video`)
Expand Down
60 changes: 48 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,15 @@ Write a demo script with Playwright. Add a scenes manifest. Run one command. Get
## Quick start

```bash
# Install
# Install the core (about 27 MB, no TTS engine yet)
npm i -D @argo-video/cli

# Add the TTS engine you want. Engines are optional peer dependencies,
# so you only pay for the one you use. Run `npx argo doctor` any time to
# see which engines are installed and the exact command for your setup.
npm i kokoro-js@1 # local, free, no API key (~410 MB of ONNX runtime)
npm i openai # cloud, needs OPENAI_API_KEY (~20 MB)

# Initialize project
npx argo init

Expand Down Expand Up @@ -352,8 +358,8 @@ import { defineConfig, demosProject, engines } from '@argo-video/cli';

## Requirements

- **Node.js** >= 18
- **Playwright** >= 1.40 (peer dependency)
- **Node.js** >= 20 (Playwright requires it)
- **Playwright** >= 1.59 (peer dependency)
- **ffmpeg** — system install required for export

```bash
Expand All @@ -374,15 +380,45 @@ choco install ffmpeg # Windows
});
```

| Engine | Type | Install | API Key |
|--------|------|---------|---------|
| `engines.kokoro()` | local | built-in | none |
| `engines.mlxAudio()` | local | `pip install mlx-audio` | none |
| `engines.openai()` | cloud | `npm i openai` | `OPENAI_API_KEY` |
| `engines.elevenlabs()` | cloud | `npm i @elevenlabs/elevenlabs-js` | `ELEVENLABS_API_KEY` |
| `engines.gemini()` | cloud | `npm i @google/genai` | `GEMINI_API_KEY` |
| `engines.sarvam()` | cloud | `npm i sarvamai` | `SARVAM_API_KEY` |
| `engines.transformers()` | local | built-in | none |
Every engine is an **optional peer dependency**: npm does not install it
for you, so the base package stays small. Install the one you use.

| Engine | Type | Install | Size | API Key |
|--------|------|---------|------|---------|
| `engines.kokoro()` | local | `npm i kokoro-js@1` | ~410 MB | none |
| `engines.mlxAudio()` | local | `pip install mlx-audio` | n/a (Python) | none |
| `engines.openai()` | cloud | `npm i openai` | ~20 MB | `OPENAI_API_KEY` |
| `engines.elevenlabs()` | cloud | `npm i @elevenlabs/elevenlabs-js` | ~88 MB | `ELEVENLABS_API_KEY` |
| `engines.gemini()` | cloud | `npm i @google/genai` | ~36 MB | `GEMINI_API_KEY` |
| `engines.sarvam()` | cloud | `npm i sarvamai` | ~7 MB | `SARVAM_API_KEY` |
| `engines.transformers()` | local | `npm i @huggingface/transformers@3` | ~380 MB | none |

Sizes are `node_modules` on disk for that package alone in an empty
project. They do not simply add up, because engines share transitive
dependencies with Argo. Measured end to end, a project install comes to
about 27 MB with no engine, 47 MB with OpenAI, and 435 MB with Kokoro.

The commands above are for a project-local install. A **global** install
(`npm i -g @argo-video/cli`) needs `-g` on the engine too, and Kokoro
needs both packages in **one** command, because separate global installs
do not deduplicate and you end up with two copies of the ONNX runtime:

```bash
npm i -g kokoro-js@1 @huggingface/transformers@3 # one command, ~410 MB
```

With **npx**, compose the engine into the same invocation:

```bash
npx -p @argo-video/cli -p openai -- argo pipeline example
```

`npx argo doctor` prints the right command for whichever of the three
you are using.

Word-level transcription (`tts.transcribe`) needs
`@huggingface/transformers`. Installing `kokoro-js` already brings it in
on a project install, so there is usually nothing extra to do.

**Transformers.js** — Use any HuggingFace `text-to-speech` model locally. Supertonic, or any future ONNX TTS model:

Expand Down
Loading
Loading