Commit e53d28e
Add
Implements the `assembly clip` command, which cuts clips out of
audio/video files based on speaker labels, text search, LLM-driven
selection, or explicit time ranges.
## Summary
This PR adds a complete new command (`assembly clip`) that orchestrates
media cutting via ffmpeg, driven by transcript-based selection. The
command supports multiple selection sources (speaker/search filters, LLM
Gateway model picks, explicit ranges), handles YouTube/media-page
downloads via yt-dlp, accepts piped transcripts on stdin, and outputs
clips with optional padding and merging.
## Key Changes
**Core Implementation:**
- `aai_cli/clip_exec.py` (369 lines): Main orchestration logic for
validation, transcript resolution, segment selection, and ffmpeg
invocation. Handles local files, YouTube URLs, piped transcripts (`-t
-`), and LLM-driven selection via the LLM Gateway.
- `aai_cli/clip_select.py` (198 lines): Pure selection logic—range
parsing (seconds and clock times like `1:30-2:45`), utterance filtering
by speaker/search, segment merging with padding, and LLM reply parsing.
- `aai_cli/commands/clip.py` (128 lines): Typer CLI command definition
with all flags (`--speaker`, `--search`, `--llm`, `--range`,
`--padding`, `--out-dir`, `--transcript-id`, etc.) and help text.
**Test Suite:**
- `tests/test_clip_exec.py` (362 lines): Tests validation, ffmpeg
orchestration, range-only cutting, and transcript-backed selection
(ffmpeg boundary faked).
- `tests/test_clip_select.py` (209 lines): Tests pure selection
logic—range parsing, segment merging, utterance filtering, LLM
listing/reply contract, and clock formatting.
- `tests/test_clip_sources.py` (294 lines): Tests YouTube/media-page
downloads, stdin transcript piping (`-t -`), and LLM-driven selection
(all boundaries faked).
- `tests/test_clip_command.py` (158 lines): CLI-level tests for argv
parsing, error rendering, and command placement in help.
- `tests/_clip_helpers.py` (67 lines): Shared test builders (option
defaults, transcript fakes, ffmpeg recording).
**Integration:**
- Updated `aai_cli/main.py` to register the `clip` command sub-app.
- Updated `.importlinter` to allow `clip_exec` and `clip_select`
modules.
- Updated `AGENTS.md` to document the command layer architecture.
- Updated `aai_cli/skills/aai-cli/references/transcription.md` with
`clip` command documentation.
- Updated help snapshot tests in
`tests/__snapshots__/test_snapshots_help_run.ambr`.
- Updated `tests/_snapshot_surface.py` to include `clip` in the help
group.
- Updated `README.md` to list the new command.
- Updated `tests/test_smoke.py` to verify command ordering.
## Notable Implementation Details
- **Selection composition**: `--speaker` and `--search` filter
utterances first; `--llm` then picks windows from the filtered set (or
the whole transcript if unfiltered). `--range` adds explicit segments.
All sources merge and overlap-coalesce.
- **Transcript sources**: Transcripts can be made fresh (with speaker
labels), fetched by ID, or piped as JSON on stdin (`-t -`), avoiding
re-transcription.
- **YouTube support**: Media-page URLs are downloaded via
`youtube.download_audio()` into a temp directory; clips land in
`--out-dir` or the current directory.
- **LLM integration**: The LLM Gateway receives a timestamped utterance
listing and returns JSON segment picks; the reply is parsed robustly
(handles markdown code blocks, surrounding text).
- **Padding & merging**: Segments are padded (clamped at 0), sorted, and
coalesced where they touch or overlap, so consecutive utterances don't
shatter into per-sentence files.
- **ffmpeg orchestration**: Each surviving segment is re-encoded into
its own file (`<name>.clip
https://claude.ai/code/session_011SdBCjATahktayRZfjmwWk
Co-authored-by: Claude <noreply@anthropic.com>assembly clip command to cut media by transcript content (#129)1 parent 2cc701f commit e53d28e
16 files changed
Lines changed: 1912 additions & 6 deletions
File tree
- aai_cli
- commands
- skills/aai-cli/references
- tests
- __snapshots__
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
11 | 11 | | |
12 | 12 | | |
13 | 13 | | |
| 14 | + | |
| 15 | + | |
14 | 16 | | |
15 | 17 | | |
16 | 18 | | |
| |||
54 | 56 | | |
55 | 57 | | |
56 | 58 | | |
| 59 | + | |
57 | 60 | | |
58 | 61 | | |
59 | 62 | | |
| |||
77 | 80 | | |
78 | 81 | | |
79 | 82 | | |
| 83 | + | |
80 | 84 | | |
81 | 85 | | |
82 | 86 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
162 | 162 | | |
163 | 163 | | |
164 | 164 | | |
165 | | - | |
| 165 | + | |
166 | 166 | | |
167 | | - | |
| 167 | + | |
168 | 168 | | |
169 | 169 | | |
170 | 170 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
173 | 173 | | |
174 | 174 | | |
175 | 175 | | |
| 176 | + | |
176 | 177 | | |
177 | 178 | | |
178 | 179 | | |
| |||
0 commit comments