No description
- Python 61.1%
- Nix 20.6%
- JavaScript 12.8%
- Dockerfile 5.5%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
All checks were successful
ci / check (push) Successful in 1m30s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
| .claude | ||
| .forgejo/workflows | ||
| docs | ||
| nix | ||
| src/shorts_render | ||
| tests | ||
| .editorconfig | ||
| .env.example | ||
| .envrc | ||
| .gitattributes | ||
| .gitignore | ||
| .ignore | ||
| .mcp.json | ||
| AGENTS.md | ||
| CLAUDE.md | ||
| compose.yaml | ||
| Dockerfile | ||
| flake.lock | ||
| flake.nix | ||
| opencode.json | ||
| pyproject.toml | ||
| README.md | ||
shorts-render
Turn a voiceover script and a handful of stills into a vertical short, with spoken audio and burned-in word-timed captions.
curl -s localhost:8310/render -H 'content-type: application/json' \
-d '{"script": "Octopuses have three hearts.", "images": ["<base64 png>", "<base64 png>"]}' \
-o short.mp4
It is the render step of a MoneyPrinter-style pipeline: an n8n workflow writes the script and generates the images, this service turns them into a 1080x1920 mp4, and n8n takes it from there. Speech is Piper, caption timing is whisper.cpp, the video is ffmpeg. Everything runs locally on the CPU.
Run it
Three ways, all serving on port 8310:
| Path | Command | Needs |
|---|---|---|
| Nix | nix run . |
Nix with flakes |
| Container | docker compose up --build |
Docker |
| Local | uv run shorts-render |
Python 3.11+, uv, ffmpeg, whisper-cli, piper, a voice and a whisper model; see docs/development.md |
API
| Route | What |
|---|---|
POST /render |
JSON body, returns video/mp4; see below |
GET /voices |
Installed Piper voices and the default |
GET /healthz |
Liveness |
GET /readyz |
503 until every binary, voice and model is present |
POST /render body:
| Field | Type | Default | Notes |
|---|---|---|---|
script |
string | required | Spoken verbatim |
images |
string[] | required | Base64 PNG, JPEG or WebP, or data URLs, in display order; 1 to 20 |
voice |
string | DEFAULT_VOICE |
A name from /voices |
language |
string | auto | ISO code for caption timing |
speed |
number | 1.0 | 0.5 to 2.0 |
subtitles |
bool | true | Burn in captions |
The response header X-Video-Duration carries the length in seconds. There is
no authentication: bind it to loopback or a trusted LAN only.
Docs
docs/architecture.md- the pipeline and why it is shaped this waydocs/development.md- local setup and testsdocs/deployment.md- NixOS module and container
Configuration is environment variables, all listed in .env.example.