Resúmenes de un vídeo de YouTube, desde un Linux de una IP residencial: si no hay subtítulos que convertir en transcripción, se baja el audio y lo transcribe. Luego hace un resumen. (CLI y skill para integrar en el flujo de trabajo de un LLM: "dame un resumen de este vídeo de youtube: URL"). Sin coste excepto el del LLM (si no se usa tier free), teóricamente sin bloqueos al ser IP residencial. En setup original ofrece también hacer un documento y presentación de libreoffice (ampliable a presentación web, que lo lea por audio... cualquier configuración).
Find a file
2026-10-21 00:13:21 +01:00
docs docs: stage-1 validation run — both paths verified, av<13 pin + parser findings recorded 2026-10-20 00:28:39 +01:00
src/yt_digest feat: telegram subcommand (v0.1.1) — short technical abstract, paste-safe Telegram format + lint retry 2026-10-21 00:13:21 +01:00
.gitignore feat: CLI v0.1.0 — probe/transcript/run/abstract, all paths verified (captions, whisper, remote+local abstract) 2026-10-20 22:17:18 +01:00
.python-version feat: install toolchain — uv project with yt-dlp[default,deno], faster-whisper, av<13; verified end-to-end 2026-10-20 22:05:47 +01:00
AGENTS.md feat: telegram subcommand (v0.1.1) — short technical abstract, paste-safe Telegram format + lint retry 2026-10-21 00:13:21 +01:00
pyproject.toml feat: telegram subcommand (v0.1.1) — short technical abstract, paste-safe Telegram format + lint retry 2026-10-21 00:13:21 +01:00
README.md feat: telegram subcommand (v0.1.1) — short technical abstract, paste-safe Telegram format + lint retry 2026-10-21 00:13:21 +01:00
SKILL.md feat: telegram subcommand (v0.1.1) — short technical abstract, paste-safe Telegram format + lint retry 2026-10-21 00:13:21 +01:00
uv.lock feat: telegram subcommand (v0.1.1) — short technical abstract, paste-safe Telegram format + lint retry 2026-10-21 00:13:21 +01:00

yt-digest

Status: 🟡 ACTIVE (toolchain) — un-parked by owner 2026-10-20: uv project with all dependencies installed and end-to-end verified; the pipeline runs via the SKILL.md scaffold. The CLI is not yet implemented — the design history below documents every decision.

What it is

A small, harness-agnostic tool that turns a YouTube video into a formatted abstract, in three stages:

  1. Acquire a transcript — captions if they exist, local speech-to-text if not
  2. Abstract — remote LLM by default (1M ctx, seconds, cents per abstract); local LLM (RTX 3060 via ollama) as the offline/privacy fallback
  3. Format & deliver — clean abstract plus optional ways to work with it (report, note, slides)

HeadlessX is explicitly not part of this (see Why not HeadlessX).

Pipeline shape

URL
 └─ probe captions (yt-dlp --list-subs)
     ├─ captions exist (most of YouTube)
     │    └─ yt-dlp --write-auto-subs / --write-subs --skip-download
     │        → parse caption file → clean text (+ timestamps)
     └─ no captions
          └─ yt-dlp -f bestaudio -x → faster-whisper (local GPU)
              → text (+ timestamps)
 → REMOTE abstract (default): zai-glm-5-3 via Mistral API, 1M ctx — seconds, cents
 └─ fallback: offline | privacy | API outage | budget cap
      → LOCAL ollama — Gemma 4 12B QAT @64K (~5 h ceiling; E2B tier for
        short structured runs)
 → format abstract (markdown is canonical)
 → optional deliverables: report (.odt) · note (SilverBullet) · slides (.odp)

Runtime decision rule: always probe captions first — it's a 30-second win; Whisper is the fallback, never the default.

Stage 1 — transcript acquisition (options evaluated 2026-10-19)

Path Tool Key options Notes
Captions yt-dlp --list-subs (probe) · --write-subs (creator-uploaded) · --write-auto-subs (YouTube ASR) · --skip-download · --sub-langs en,-live_chat · --sub-format json3 (word-level timing) or vtt · --convert-subs srt Returns caption files, not text — needs a parse step to strip timestamps/cues
Captions (simpler) youtube-transcript-api plain text per language, one call can replace yt-dlp entirely for the captioned path
No captions yt-dlp → faster-whisper -f bestaudio -x, then STT faster-whisper — GPU (RTX 3060) preferred for batch; Mistral voxtral (API ASR) is fallback only: its cost compounds under batch extraction while the 3060 absorbs it at zero marginal cost. Engine ladder incl. WhisperX (batched, word-aligned, diarization): see SKILL.md

Auto-generated captions are YouTube's own ASR: decent quality, available for most videos, no local compute. Word-level timing (json3) and Whisper segments both survive into stage 3 so citations/quotes stay precise.

Stage 2 — abstract

  • Default: remote LLM (owner-set 2026-10-20 — the local-hardware path was walked before, deliberately not again). Any capable mid-tier, 256K+ ctx is plenty (owner-verified: huge transcripts abstract fine on 256K medium models); zai-glm-5-3 is the known-good default in this setup, and the OpenCode Zen free tier (cat-jam-free / longcat-2.5-preview-free / space-bunny-free) is $0 when the harness mediates the abstract step. Cost: noted, not worried about — an abstract is a one-shot job (tokens in, tokens out, end of run, end of session), so even frontier-ish paid tiers are trivially cheap. Full options + analysis in docs/model-planning.md.
  • Fallback: local (RTX 3060 12 GB, ollama) for offline / privacy-sensitive content / API outage / hard budget cap. Local plan (all retained in docs/model-planning.md): Gemma 4 12B QAT @ 64K ctx (~8.6 GB incl. KV; ~5 h video ceiling); E2B-class only as a structured extractive tier for short videos; fill ≤ 75%; never trust ollama's default context — set num_ctx explicitly and assert transcript < window.
  • Parked sub-decision: for very long transcripts where privacy matters more than simplicity, chunk + map-reduce locally instead of going remote.

Stage 3 — format & deliverables

Markdown is the canonical abstract format. Later, optional subcommands ("ways to work with it"):

  • telegram — LIVE (2026-10-20, v0.1.1): short technical abstract in paste-safe Telegram format — bold hook line + • bullets, no headings/ tables/[label](url) syntax (regular markdown breaks Telegram), target ≤ ~800 chars, paste-safety lint + one corrective retry; printed to stdout and written to telegram.txt. Verified on the Proa video (713 chars, lint-clean first generation).
  • report — .odt document. Owner convention: run both pandoc and UNO/pyuno routes, compare renders, keep the better one (see the md→ODT rule in ~/.pi/agent/AGENTS.md); odt skill in ~/.agents/skills/ covers it.
  • note — SilverBullet markdown with wikilinks (owner's note system).
  • slides — .odp via the odp skill (stretch goal).
  • text / json — plain outputs, always available.

Delivery surface (harness-agnostic)

  1. CLI + personal skill (recommended) — one tool, yt-digest <url> (subcommands later), shipped as a skill in ~/.agents/skills/yt-digest/ per the skill-sharing convention (opencode + pi read it natively; hermes via symlink). Any harness, any model, can drive it. ~100 lines of glue. Scaffold drafted: SKILL.md — v0.1 preliminary, project-internal only; publish to ~/.agents/skills/ at implementation time, not before.
  2. MCP server exposing transcribe/abstract as first-class tools for any MCP client — only worth it if it becomes a routine cross-client agent tool; otherwise ceremony.
  3. Agent-decides pattern works under either: captions-first, Whisper fallback, remote-abstract-default, local-LLM-fallback. The wrapper encodes the decisions so agents don't re-derive them.

Environment facts (verified 2026-10-19)

  • ffmpeg 9.0.1 ✓ present · uv 0.12.1 ✓ present
  • yt-dlp, faster-whisper, youtube-transcript-api — not installed yet; each is a uv tool install / uv add one-liner on pickup
  • Local LLM: ollama + NVIDIA RTX 3060 (12 GB) available
  • Remote LLM (default for abstracts): Mistral API (zai-glm-5-3, 1M ctx — pricing + cheaper flash-tier options in docs/model-planning.md)
  • Python on PATH is 3.14 — pin a 3.12 venv if faster-whisper deps lag
  • Owner prefers user-level installs (~/-prefixed, avoid sudo)

Why not HeadlessX

Transcripts are the weakest reason to self-host HeadlessX. Its yt-engine only lists subtitle track URLs (manual + YouTube ASR), ships no STT engine, and has no audio-only download preset — even uncaptioned videos would need this exact pipeline bolted on anyway. HeadlessX "someday" triggers remain the ones from the 2026-10-19 analysis: Google AI Overview extraction, anti-detect scraping past bot defenses, queue-managed YouTube pipelines at scale.

Validation (2026-10-20)

Stage-1 smoke-tested end-to-end on both paths (captions and audio→Whisper) with a throwaway uvx/uv run — reference video, transcripts, timings, and seven hard-won findings (incl. the mandatory av<13 pin) in docs/validation-2026-10-20.md. The stage-2 agent-driven abstract flow was demonstrated in the same run. The project remains parked; no pipeline code committed.

Pickup checklist (when this becomes active)

  1. uv project init (venv pinned 3.12); add yt-dlp, faster-whisper, youtube-transcript-api, and av<13 as a pyproject constraint ✅ DONE 2026-10-20 — uv add 'yt-dlp[default,deno]' faster-whisper 'av<13' youtube-transcript-api, verified against the reference video (transcription parity, no JS-runtime warning). Pinning gotcha found: uv init --python 3.12 sets only the lower bound — also run uv python pin 3.12 and bound requires-python to <3.13, or uv sync picks the newest system interpreter (3.14) and av<13 attempts a source build that fails on missing libav*-dev. It's a pinning bug, never a missing system dependency — do not "fix" with sudo apt libavfilter-dev.
  2. Re-verify docs/model-planning.md against the live ollama catalog (Gemma 4 tags, QAT sizes, default context length all move); wire num_ctx explicitly — never trust ollama's default
  3. Implement stage 1: probe → captions → parse | audio → Whisper ✅ DONE 2026-10-20 — src/yt_digest: probe (yt-dlp as a library), captions (track picker manual>auto, json3 + vtt parsers with the event-boundary space fix), transcribe (audio download + faster-whisper)
  4. Implement stage 2: abstract — remote by default, local fallback ✅ DONE 2026-10-20 — remote via OpenAI-compatible API (default zai-glm-5-3 @ api.mistral.ai; key resolution: --api-key > MISTRAL_API_KEY env > ~/.pi/agent/auth.json, never printed); local via ollama chat (num_ctx set explicitly, fill ≤ 75% guard); --engine auto implements the documented outage-fallback policy (network/5xx → local; 4xx auth errors stop with a clear message)
  5. Wrap as CLI ✅ DONE 2026-10-20 — yt-digest {probe,transcript, run,abstract} (entry point installed by uv sync; run via uv run yt-digest …). Verified live on all paths: captions + remote abstract 9.6 s; audio→Whisper 132 words (validation parity); local ollama fallback OK. Skill publishing: ✅ DONE 2026-10-20 — CLI-first skill at ~/.agents/skills/yt-digest/ + hermes symlink; Forgejo description updated to "CLI y skill para integrar en el flujo de trabajo de un LLM".
  6. Deliverables last: report/note/slides subcommands — future

Renaming this repo is one git mv-free operation (rename dir + update references) — the name was chosen for descriptiveness, not attachment.