> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://summarize.martino.im/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://summarize.martino.im/_mcp/server.

# How It Works

## Architecture

Three surfaces — the CLI, the Streamlit webapp, and the HTTP API — all drive the same engine.

```mermaid
flowchart TD
  user([User or agent]) --> cli[CLI] & ui[Streamlit :8501] & api[HTTP API :8000]
  cli & ui & api --> core[core.main]
  core --> cfg[(yaml, .env, prompts)]
  core --> dl[downloaders] --> src[sources]
  core --> tr[transcription and cache] --> prov[LLM, Whisper, Cobalt]
  core --> jev[chunking and JEV] --> prov
  core --> vis[visual mode] --> prov
  core --> out[summaries]
```

## Pipeline

The default transcript path runs in two stages.

### 1. Acquire the transcript

Cache first, then the downloader fallback chain, then captions or Whisper.

```mermaid
sequenceDiagram
  actor Caller
  participant Core as core.main
  participant Cache as transcript cache
  participant Handlers as handlers
  participant DM as DownloadManager
  participant Trans as transcription
  Caller->>Core: main(config)
  Core->>Cache: get_cached_transcript()
  alt hit
    Cache-->>Core: transcript
  else miss
    Core->>Handlers: _fetch_transcript()
    Handlers->>DM: download_audio()
    DM-->>Handlers: temp path
    Handlers->>Trans: captions or Whisper
    Trans-->>Handlers: transcript
    Handlers-->>Core: transcript
    Core->>Cache: put_cached_transcript()
  end
  Core-->>Caller: transcript
```

### 2. Chunk, filter, summarize

```mermaid
sequenceDiagram
  participant Core as core.main
  participant API as api.py
  participant JEV as jev.py
  participant LLM as LLM
  Core->>API: extract_and_clean_chunks()
  API-->>Core: timestamped chunks
  opt JEV enabled
    API->>JEV: prefilter_chunks()
    JEV->>LLM: SystemOne scores
    LLM-->>JEV: keep or exclude
    JEV-->>API: selected passages
  end
  par each chunk
    API->>LLM: process_chunk()
    LLM-->>API: chunk summary
  end
  API-->>Core: summaries
  Core->>Core: format with timestamps
```

## Download Pipeline

The app uses a **fallback downloader chain**:

1. **yt-dlp** — YouTube, Instagram, TikTok, Twitter/X, Reddit, Facebook
2. **YouTube** (`pytubefix`) — fallback if yt-dlp fails
3. **Cobalt** — fallback for other HTTP video URLs

If a downloader does not support a URL or fails, the next one is tried automatically.

## Key Files

| File                      | Purpose                                                                             |
| ------------------------- | ----------------------------------------------------------------------------------- |
| `summarizer.yaml`         | Provider settings and defaults. Generate with `python -m summarizer --init-config`. |
| `.env`                    | API keys matched by URL keyword or conventional env var names                       |
| `summarizer/prompts.json` | Summary style templates                                                             |

## Processing Paths

* **Transcript path** (default): downloads audio/video, transcribes with Whisper or captions, caches the complete transcript, optionally selects passages with JEV, then summarizes with an LLM.
* **Visual path** (`--visual`): sends the video directly to a vision-capable model, skipping transcription. Uses the same prompts, provider config, and `.env` keys as the transcript path. Supports `base64` chunks (default) and `url` passthrough for YouTube.

See [Visual Mode](features/visual-mode) for provider setup and [Transcription](features/transcription) for Whisper options.

## Notes

> **Tip:** If YouTube captions are unavailable, the tool automatically falls back to audio download + Whisper transcription.
>
> **Tip:** Transcripts are cached in memory by default. Re-summarizing the same source with a different style, provider, or JEV selection skips transcription entirely. Disable with `cache-transcript: false` in `summarizer.yaml`.

* Cloud Whisper uses **Groq Cloud API** and requires a Groq API key.
* The Docker image does **not** include Local Whisper and is aimed at lightweight VPS deployment.