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
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,10 @@ languages it has a prompt for (`de`, `en`, `es`, `fr`, `it`, `pt`). Any other la
error naming what is available rather than a prompt in the wrong language, which steers the
model worse than none. Use `--prompt "<text>"` to write your own.

> Known limitation: the transcription path currently removes silence before transcribing,
> which deletes the pauses these hesitations live around, so the preset has little to work
> with today. See [#35](https://github.com/crafter-station/trx/issues/35).
Timestamps describe the file you handed in. The cleaning stage adjusts level and noise and
leaves duration alone, so a cue at 36.68s means 36.68s in the source. Up to 0.8.0 it also
removed silence, which moved every cue after the first removed pause: 1.572s of accumulated
drift on one 90.5s recording.

## Commands

Expand Down Expand Up @@ -108,7 +109,7 @@ Input (URL or file)
[yt-dlp] Download media (if URL)
|
v
[ffmpeg] Clean audio (silence removal, noise reduction, normalization)
[ffmpeg] Clean audio (noise reduction, normalization; duration preserved)
|
v
[whisper-cli] Transcribe (local Whisper model)
Expand Down
4 changes: 3 additions & 1 deletion packages/cli/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,14 @@ Global option (all commands): `-o, --output <format>` with `json`, `table`, or `
|------|-------------|
| `-l, --language <lang>` | Force language (ISO 639-1), default auto-detect |
| `-m, --model <size>` | Override model. Local: `tiny`/`base`/`small`/`medium`/`large`/`large-v3-turbo`. OpenAI: `gpt-4o-transcribe`/`gpt-4o-mini-transcribe`/`whisper-1` |
| `-b, --backend <backend>` | `local` or `openai` |
| `-b, --backend <backend>` | `local`, `openai`, or `vercel` |
| `--fields <fields>` | Limit output fields: `text`, `srt`, `metadata`, `files` |
| `--dry-run` | Validate input and show plan without transcribing |
| `--json <payload>` | Raw JSON input for agents |
| `--output-dir <dir>` | Where to write `.wav`/`.srt`/`.txt` (default `.`) |
| `-w, --words` | Word-level timestamps in the SRT |
| `--preset <name>` | `verbatim` keeps fillers and false starts; needs `--language` |
| `--prompt <text>` | Initial prompt in the spoken language; takes precedence over `--preset` |
| `--no-download` | Skip yt-dlp, input must be a local file |
| `--no-clean` | Skip ffmpeg audio cleaning |

Expand Down
2 changes: 1 addition & 1 deletion packages/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ Input (URL or file)
[yt-dlp] Download media (if URL)
|
v
[ffmpeg] Clean audio (silence removal, noise reduction, normalization)
[ffmpeg] Clean audio (noise reduction, normalization; duration preserved)
|
v
[whisper-cli] Transcribe (local Whisper model)
Expand Down
128 changes: 64 additions & 64 deletions packages/cli/schemas/init.json
Original file line number Diff line number Diff line change
@@ -1,66 +1,66 @@
{
"command": "init",
"description": "Install dependencies and configure transcription backend (local whisper-cli, OpenAI API, or Vercel AI Gateway)",
"flags": {
"--backend": {
"type": "string",
"enum": [
"local",
"openai",
"vercel"
],
"default": "local",
"description": "Transcription backend. 'openai' and 'vercel' skip whisper-cli install; 'openai' requires OPENAI_API_KEY, 'vercel' requires AI_GATEWAY_API_KEY"
},
"--model": {
"type": "string",
"default": "small",
"description": "Model to use. Local: tiny, base, small, medium, large, large-v3-turbo. OpenAI: gpt-4o-transcribe, gpt-4o-mini-transcribe, whisper-1. Vercel: creator/model-name, e.g. openai/whisper-1"
},
"--language": {
"type": "string",
"default": "auto",
"description": "Default language for transcription (ISO 639-1 code or 'auto')"
},
"--output": {
"type": "string",
"enum": [
"json",
"table",
"auto"
],
"default": "auto",
"description": "Output format"
}
},
"dependencies": {
"whisper-cli": {
"install": "brew install whisper-cpp",
"purpose": "Local speech-to-text transcription engine (not needed for openai or vercel backends)"
},
"yt-dlp": {
"install": "brew install yt-dlp",
"purpose": "Download video/audio from URLs (YouTube, Twitter, etc.)"
},
"ffmpeg": {
"install": "brew install ffmpeg",
"purpose": "Audio cleaning, conversion, silence removal, noise reduction"
}
},
"output": {
"success": "boolean",
"backend": "string (local | openai | vercel)",
"model": "string",
"language": "string",
"modelPath": "string (local only)",
"config": "TrxConfig object"
},
"examples": [
"trx init",
"trx init --backend openai",
"trx init --backend openai --model gpt-4o-mini-transcribe",
"trx init --backend vercel --model openai/whisper-1",
"trx init --model large-v3-turbo --language es",
"trx init --model large --output json"
]
"command": "init",
"description": "Install dependencies and configure transcription backend (local whisper-cli, OpenAI API, or Vercel AI Gateway)",
"flags": {
"--backend": {
"type": "string",
"enum": [
"local",
"openai",
"vercel"
],
"default": "local",
"description": "Transcription backend. 'openai' and 'vercel' skip whisper-cli install; 'openai' requires OPENAI_API_KEY, 'vercel' requires AI_GATEWAY_API_KEY"
},
"--model": {
"type": "string",
"default": "small",
"description": "Model to use. Local: tiny, base, small, medium, large, large-v3-turbo. OpenAI: gpt-4o-transcribe, gpt-4o-mini-transcribe, whisper-1. Vercel: creator/model-name, e.g. openai/whisper-1"
},
"--language": {
"type": "string",
"default": "auto",
"description": "Default language for transcription (ISO 639-1 code or 'auto')"
},
"--output": {
"type": "string",
"enum": [
"json",
"table",
"auto"
],
"default": "auto",
"description": "Output format"
}
},
"dependencies": {
"whisper-cli": {
"install": "brew install whisper-cpp",
"purpose": "Local speech-to-text transcription engine (not needed for openai or vercel backends)"
},
"yt-dlp": {
"install": "brew install yt-dlp",
"purpose": "Download video/audio from URLs (YouTube, Twitter, etc.)"
},
"ffmpeg": {
"install": "brew install ffmpeg",
"purpose": "Audio cleaning, conversion, noise reduction and normalization. Duration is preserved so transcript timestamps match the input"
}
},
"output": {
"success": "boolean",
"backend": "string (local | openai | vercel)",
"model": "string",
"language": "string",
"modelPath": "string (local only)",
"config": "TrxConfig object"
},
"examples": [
"trx init",
"trx init --backend openai",
"trx init --backend openai --model gpt-4o-mini-transcribe",
"trx init --backend vercel --model openai/whisper-1",
"trx init --model large-v3-turbo --language es",
"trx init --model large --output json"
]
}
18 changes: 17 additions & 1 deletion packages/cli/skills/trx/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,13 +193,29 @@ Example JSON response (filtered with `--fields text`):
},
"metadata": {
"language": "es",
"model": "small"
"model": "small",
"inputDurationMs": 90538,
"transcribedDurationMs": 90539,
"lastCueEndMs": 89120
}
}
```

Full response includes `text`, `files`, `metadata`, `input`, `backend`.

**Read the three durations before trusting a short transcript.** They are numbers, not a
verdict, and the gaps between them say different things:

- `inputDurationMs` against `transcribedDurationMs` is what the cleaning stage changed. They
should now be within a millisecond of each other; a large gap means the timeline was
rewritten and the timestamps do not describe the file you passed in.
- `transcribedDurationMs` against `lastCueEndMs` is audio that produced no words. A big gap
is trailing silence, or a transcription that stopped early.

A five-cue transcript reads identically whether the recording is mostly silence, the model
stopped early, or the file handed in was not the one intended. These separate those cases,
and checking them is faster than filing a bug.

## Flags reference

| Flag | Description | Default |
Expand Down
29 changes: 29 additions & 0 deletions packages/website/src/content/docs/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,35 @@ trx video.mp4 --output json --fields text
trx video.mp4 --dry-run --output json
```

### Reading the result

```json
"metadata": {
"language": "es",
"model": "large-v3-turbo",
"inputDurationMs": 90538,
"transcribedDurationMs": 90539,
"lastCueEndMs": 89120
}
```

Three durations, no verdict. The gaps say different things:

- **`inputDurationMs` against `transcribedDurationMs`** is what the cleaning stage changed. They should be within a millisecond of each other. A large gap means the timeline was rewritten and the timestamps do not describe the file you passed in.
- **`transcribedDurationMs` against `lastCueEndMs`** is audio that produced no words: trailing silence, or a transcription that stopped early.

A short transcript reads the same whether the recording is mostly silence, the model stopped early, or the file handed in was not the one intended. These separate those cases.

### Verbatim transcripts

A transcriber cleans by default, dropping hesitations and false starts as noise. That is right for captions and wrong when the transcript drives an edit, because those spans are exactly the ones worth cutting.

```bash
trx transcribe video.mp4 --words --language es --preset verbatim
```

Measured on one recording: the preset recovers `Ok.` and `Eh,` where the unprompted run drops both. The prompt has to be written in the language being spoken, so the preset needs `--language` and covers `de`, `en`, `es`, `fr`, `it`, `pt`. Any other language is an error naming what is available, because a prompt in the wrong language steers the model worse than none. `--prompt "<text>"` writes your own.

---

## trx models
Expand Down
Loading