Metadata-Version: 2.4
Name: wan3check
Version: 0.1.0
Summary: Pre-flight validation and cost estimation for Alibaba Wan 3.0 (wan3.0-video) request bodies.
Author: Ray Lin
License-Expression: MIT
Project-URL: Homepage, https://wan-3.run
Project-URL: Specification, https://wan-3.run/wan-3-0-specs
Keywords: wan3,wan-3.0,alibaba,video-generation,validation,dashscope
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Multimedia :: Video
Classifier: Topic :: Software Development :: Quality Assurance
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# wan3check

Pre-flight validation for Alibaba **Wan 3.0** (`wan3.0-video`) request bodies.
No dependencies, Python 3.9+.

Most of this API's rules fail loudly, which is fine — you get an `InvalidParameter` and
you fix it. **Three of them fail silently**: the request succeeds, the job is billed,
and the result is not what you asked for. Those three are the reason this exists.

| Silent failure | What actually happens |
| --- | --- |
| `resolution` omitted | You get **1080P**, four times the 480P rate, with no warning |
| `file` or `link` without `enable_thinking: true` | Request succeeds, is billed, and **the model never reads your document** |
| `prompt` over 20,000 characters | **Truncated silently** — the clip ends mid-idea and nothing says so |

```bash
pip install wan3check
```

## Use it as a library

```python
from wan3check import check

request = {
    "model": "wan3.0-video",
    "input": {
        "prompt": "A chef plates a dish under a heat lamp, then glances at the ticket rail.",
        "media": [{"type": "reference_video", "url": "https://…/dolly.mp4", "seconds": 4.5}],
    },
    "parameters": {"resolution": "720P", "duration": 5},
}

ok, findings, cost = check(request)
print(ok)      # True
print(cost)    # 1.0  — not 0.5; reference video seconds are billed on top
for f in findings:
    print(f)
```

## Use it from the shell

```bash
$ wan3check request.json
WARNING [parameters.resolution] resolution is unset, which means 1080P — four times
        the 480P rate. Set it explicitly and opt up.
ERROR   [media.families] keyframe inputs (first_frame/last_frame) cannot be combined
        with reference inputs — pin the opening shot, or cast the subjects, not both

estimated cost: $6.00 at Alibaba's published list price
spec checked 2026-08-27
```

Exit code is `1` when there is an error, `0` otherwise. `--strict` also fails on
warnings, which is what you want in CI. `--json` gives machine-readable output.

## What it checks

**Combination rules**

- `first_frame`/`last_frame` (keyframe family) cannot appear alongside
  `reference_image`/`reference_video`/`reference_audio`/`file`/`link` (reference family)
- `file` and `link` are exclusive with each other — but `reference_image` *plus* `link`
  is legal, which is the combination most people assume is not
- Per-type caps: 10 reference images, 5 reference videos, 5 reference audio clips,
  1 file, 1 link

**Duration budgets**

- `duration` is 2–30 integer, or `-1` for model-decided
- Reference video and reference audio each cap at **15 seconds in total, not per clip**
  — three 5-second clips pass, two 10-second clips do not
- Input video seconds + output seconds must total 30 or less

**Values that do not exist**

- `resolution` is `480P`/`720P`/`1080P`. There is no 4K tier; the error says so
- `ratio` is `adaptive`/`16:9`/`4:3`/`1:1`/`3:4`/`9:16`. There is no 21:9; the error
  says so

**Cost**

`estimate_cost()` returns Alibaba's published list price, adding reference-video
seconds on top of output seconds and rounding up — reference images, audio, documents
and links are free. It returns `None` for `duration: -1`, because a job whose length
the model chooses cannot be quoted in advance.

## Evidence grades

`wan3check.spec` is the specification as data, with the check date and source URLs on
it. Two entries are **not** from Alibaba's own English reference and are listed
separately in `spec.GATEWAY_SOURCED`:

- **`enable_thinking`** — documented as required for `file`/`link` by fal.ai, Picsart,
  Modellix and WaveSpeed, and present in Alibaba's own console curl examples, but a
  full-text search of the English API reference returns zero matches for `thinking`.
  This package raises it as a *warning*, not an error, for exactly that reason.
- **Reference-video billing** — the formula `input video seconds + output seconds`
  appears identically in evolink, APIXO and aivideoapi's docs, and is corroborated by
  the separate `input_video_duration` and `output_video_duration` fields in Alibaba's
  own `usage` object.

Everything else comes from Alibaba Cloud's Model Studio API reference, read
2026-08-27. A specification is a fact about a moment, so `wan3check.CHECKED` carries
the date and `wan3check.SOURCES` carries the URLs.

## Tests

```bash
python -m unittest discover -s tests -v
```

## Related

I maintain this alongside [wan-3.run](https://wan-3.run), a hosted browser interface
for Wan 3.0 — the same rules are enforced there before a job is submitted, which is
where most of them were learned. The
[spec table with each row linked to Alibaba's own documentation](https://wan-3.run/wan-3-0-specs)
is the human-readable version of `wan3check.spec`, dated the same way and including
the rows that are unflattering.

If you only want to draft a prompt,
[the prompt builder](https://wan-3.run/prompt-generator) is free and needs no account.

## Licence

MIT.
