lazier

personal summarizer
Log | Files | Refs | README

README.md (14160B)


      1 # Lazier
      2 
      3 Sistema CLI e Web para **transcrição** e **sumarização** de áudios, vídeos, textos e PDFs usando os modelos mais recentes da OpenAI (família GPT-5 + `gpt-4o-mini-transcribe`/`whisper-1`). Além de transcrição/sumário tradicionais, gera **sumário inteligente** estruturado (TL;DR, pontos-chave, decisões, *action items*, tópicos e citações) e **capítulos com timestamps** para áudio/vídeo. Suporta upload de arquivos, URLs do YouTube e de centenas de outros sites (via yt-dlp), e páginas web. Exporta em DOCX, TXT, Markdown, JSON e PDF.
      4 
      5 ## Requisitos
      6 
      7 - **OpenAI API Key** (Whisper para transcrição, GPT para sumário)
      8 - **Redis** (opcional, para cache de transcrições/sumários)
      9 - **ffmpeg** e **yt-dlp** (instalados automaticamente no Docker; em instalação local, instale manualmente)
     10 
     11 ## Configuração (.env)
     12 
     13 Copie o exemplo e preencha:
     14 
     15 ```bash
     16 cp .env.example .env
     17 ```
     18 
     19 | Variável | Obrigatório | Descrição |
     20 |----------|-------------|-----------|
     21 | `OPENAI_API_KEY` | Sim | Chave da API OpenAI ([obter aqui](https://platform.openai.com/api-keys)) |
     22 | `SESSION_SECRET_KEY` | Sim (Web) | Chave para sessões. Gere com: `openssl rand -hex 32` |
     23 | `ADMIN_USER` / `ADMIN_PASSWORD` | Não | Usuário admin da WebGUI (criado na primeira execução se definidos) |
     24 
     25 ### Modelos e inteligência (opcionais)
     26 
     27 Defaults seguros já vêm configurados; sobrescreva apenas se quiser mudar.
     28 
     29 | Variável | Default | Descrição |
     30 |----------|---------|-----------|
     31 | `OPENAI_CHAT_MODEL` | `gpt-4o-mini` | Modelo de chat usado para sumário, conversão para PT-BR, detecção de tipo e capítulos. Alternativas: `gpt-5-mini`, `gpt-5-nano`, `gpt-4.1-mini`. |
     32 | `OPENAI_TRANSCRIBE_MODEL` | `gpt-4o-mini-transcribe` | Modelo padrão de transcrição (saída em texto). Alternativas: `gpt-4o-transcribe`, `whisper-1`. |
     33 | `OPENAI_TRANSCRIBE_TIMESTAMPS_MODEL` | `whisper-1` | Modelo usado quando precisamos de `verbose_json` para gerar capítulos. Atualmente `whisper-1` é o mais confiável para retornar `start`/`end`. |
     34 | `OPENAI_ENABLE_SMART_SUMMARY` | `true` | Liga/desliga o sumário estruturado (TL;DR, pontos-chave, decisões, ações, tópicos, citações, perguntas em aberto). Quando `false`, mantém o sumário textual legado. |
     35 | `OPENAI_ENABLE_CHAPTERS` | `false` | Capítulos com timestamps (exige STT `verbose_json`, mais lento). |
     36 | `OPENAI_REASONING_EFFORT` | `minimal` | Esforço de raciocínio para modelos da família `gpt-5`/`o-series`. Valores: `minimal`, `low`, `medium`, `high`. |
     37 | `LAZIER_QUALITY_PRESET` | `economico` | Preset global `economico` / `equilibrado` / `maximo` → defaults de chat, transcrição e `reasoning`. |
     38 | `LAZIER_SUMMARY_HIERARCHICAL` | `true` | Acima de `LAZIER_SUMMARY_DIRECT_MAX_CHARS`, o sumário inteligente usa map-reduce com chunks e overlap em vez de um único passe sobre o texto completo. |
     39 | `LAZIER_SUMMARY_DIRECT_MAX_CHARS` | `48000` | Limiar (caracteres) para ativar sumarização hierárquica. |
     40 | `LAZIER_SUMMARY_MAP_CHUNK_CHARS` | `16000` | Tamanho alvo de cada chunk no map. |
     41 | `LAZIER_SUMMARY_CHUNK_OVERLAP_CHARS` | `800` | Sobreposição entre chunks consecutivos. |
     42 | `LAZIER_ENABLE_PT_POLISH` | `false` | Revisão ortográfica extra após PT-BR (mais chamadas chat). |
     43 | `LAZIER_DETECT_CONTENT_TYPE` | `false` | Classificador de tipo antes do sumário (1 chamada chat). |
     44 | `LAZIER_STT_PARALLEL_WORKERS` | `3` | Transcrição paralela de chunks de áudio. |
     45 | `LAZIER_SUMMARY_PARALLEL_WORKERS` | `3` | Sumário inteligente paralelo por chunk. |
     46 | `LAZIER_ALT_STT_ENABLED` | `false` | Reserva para spike de segundo STT ou diarização. |
     47 | `LAZIER_ALWAYS_SUMMARY` | `false` | Se `true`, força geração de sumário mesmo quando o modo pedido é só `transcribe` (override de instalação). |
     48 | `LAZIER_DIARIZATION_PROVIDER` | `none` | Diarização opcional de falantes (`none`, ou provedores futuros). |
     49 
     50 Opcional: `YOUTUBE_PO_TOKEN` para melhor suporte a alguns vídeos do YouTube ([guia](https://github.com/yt-dlp/yt-dlp/wiki/PO-Token-Guide)).
     51 
     52 **Segredos:** nunca commite ficheiros `.env` com valores reais, chaves API ou passwords. Mantenha apenas `.env.example` no Git; use variáveis de ambiente no host ou *secrets* do CI/CD (GitHub Actions, etc.).
     53 
     54 ## Instalação Rápida
     55 
     56 ### Docker (Recomendado)
     57 
     58 ```bash
     59 # 1. Clone o repositório
     60 git clone <repo-url>
     61 cd lazier
     62 
     63 # 2. Configure o .env (OPENAI_API_KEY, SESSION_SECRET_KEY e opcionalmente ADMIN_USER/ADMIN_PASSWORD)
     64 cp .env.example .env
     65 # Edite .env com suas chaves
     66 
     67 # 3. Inicie os serviços (a partir da pasta do projeto)
     68 docker compose -f docker/docker-compose.yml up -d --build
     69 ```
     70 
     71 Ou, a partir da pasta `docker/`:
     72 
     73 ```bash
     74 cd docker
     75 docker compose up -d --build
     76 ```
     77 
     78 Acesse: **http://localhost:19283**
     79 
     80 Arquivos gerados são salvos em `outputs/` na raiz do projeto.
     81 
     82 ### Instalação Local
     83 
     84 ```bash
     85 pip install -r requirements.txt
     86 cp .env.example .env
     87 # Preencha OPENAI_API_KEY e SESSION_SECRET_KEY no .env
     88 
     89 # Redis (opcional, para cache)
     90 docker run -d -p 52847:6379 redis:7-alpine
     91 
     92 lazier web
     93 ```
     94 
     95 Acesse **http://localhost:19283** (ou use `--port` para outra porta).
     96 
     97 ## Uso
     98 
     99 ### CLI
    100 
    101 ```bash
    102 # Só transcrição (texto completo em PT-BR — default, mais económico)
    103 lazier transcribe audio.mp3
    104 lazier transcribe video.mp4
    105 lazier transcribe "https://www.youtube.com/watch?v=VIDEO_ID"
    106 
    107 # Só sumário (STT/extração internos; exporta apenas o sumário)
    108 lazier summarize document.pdf
    109 lazier summarize "https://example.com/artigo" --format md
    110 lazier summarize aula.mp3 --gpt-model gpt-5 --reasoning high
    111 
    112 # Transcrição + sumário (dois artefactos; maior consumo de tokens)
    113 lazier process aula.mp3 --format md
    114 
    115 # Desligar features opcionais
    116 lazier summarize aula.mp3 --no-smart --no-chapters
    117 
    118 # Outras opções
    119 lazier summarize video.mp4 --format json     # docx, txt, md, json, pdf
    120 lazier config                                 # mostra a config corrente
    121 lazier web                                    # inicia servidor web
    122 lazier cache clear                            # limpa cache
    123 ```
    124 
    125 Flags principais:
    126 
    127 - `--model` sobrescreve `OPENAI_TRANSCRIBE_MODEL` para esse comando.
    128 - `--gpt-model` sobrescreve `OPENAI_CHAT_MODEL`.
    129 - `--smart/--no-smart` força ligar/desligar o sumário estruturado.
    130 - `--chapters/--no-chapters` força ligar/desligar capítulos com timestamps.
    131 - `--reasoning {minimal,low,medium,high}` ajusta o esforço de raciocínio para modelos `gpt-5`/`o-series`.
    132 
    133 O pacote custo/qualidade (`economico` / `equilibrado` / `maximo`) vem só de `LAZIER_QUALITY_PRESET` no `.env` (`lazier config` mostra o valor atual).
    134 
    135 ### Economia de tokens
    136 
    137 | Modo | O que gera | Notas |
    138 |------|------------|-------|
    139 | `transcribe` | Transcrição PT-BR | Não chama sumário inteligente nem detecção de tipo de conteúdo. |
    140 | `summarize` | Sumário PT-BR | Áudio/vídeo ainda passam por STT; transcrição completa não é exportada. |
    141 | `process` | Transcrição + sumário | Dois ficheiros na WebGUI; custo total de chat. |
    142 
    143 Na WebGUI escolha **Transcrição**, **Sumário** ou **Ambos**. Na API, omitir `mode` equivale a `transcribe`. Use `"mode": "process"` ou `transcribe: true, summarize: true` para os dois.
    144 
    145 ### Velocidade e custo (defaults)
    146 
    147 O perfil **económico** shipado prioriza latência e preço:
    148 
    149 - **`gpt-4o-mini`** para chat (conversão PT-BR e sumário).
    150 - **Capítulos desligados** — evita STT com `whisper-1` + geração de capítulos.
    151 - **Sem polish nem detecção de tipo** — poupa 1–3 chamadas chat por job.
    152 - **Áudio normalizado** mono 16 kHz antes do STT (ficheiros menores).
    153 - **Chunks STT/sumário em paralelo** (até 3 workers).
    154 
    155 Para máxima qualidade: `LAZIER_QUALITY_PRESET=maximo`, `OPENAI_ENABLE_CHAPTERS=true`, `LAZIER_ENABLE_PT_POLISH=true`.
    156 
    157 ### WebGUI
    158 
    159 Acesse http://localhost:19283 após iniciar com `lazier web` ou Docker. Na primeira vez, faça login com o usuário e senha definidos em `ADMIN_USER` e `ADMIN_PASSWORD` no `.env` (se configurados).
    160 
    161 ### API HTTP
    162 
    163 `POST /api/process` e `POST /api/upload` aceitam, além dos campos clássicos, overrides por requisição:
    164 
    165 ```json
    166 {
    167   "url": "https://example.com/aula.mp3",
    168   "format": "md",
    169   "mode": "summarize"
    170 }
    171 ```
    172 
    173 Modos: `transcribe` (default), `summarize`, `process` (ambos). Overrides opcionais:
    174 
    175 ```json
    176 {
    177   "url": "https://example.com/aula.mp3",
    178   "format": "md",
    179   "mode": "process",
    180   "chat_model": "gpt-5",
    181   "transcribe_model": "gpt-4o-transcribe",
    182   "smart": true,
    183   "chapters": true
    184 }
    185 ```
    186 
    187 Os campos `chat_model`, `transcribe_model`, `smart` e `chapters` são opcionais e sobrescrevem os defaults definidos no `.env` apenas para esse job. `GET /api/jobs/{id}/details` passa a devolver `smart_summary`, `chapters` e `content_type` quando disponíveis.
    188 
    189 ## Inteligência
    190 
    191 ### Sumário estruturado
    192 
    193 Quando `OPENAI_ENABLE_SMART_SUMMARY=true` (default), o Lazier gera um objeto `SmartSummary` validado por Pydantic com Structured Outputs. Cada saída inclui:
    194 
    195 - `tldr`: resumo de 1-3 frases
    196 - `key_points`: pontos principais em ordem lógica
    197 - `decisions`: decisões explícitas tomadas no conteúdo
    198 - `action_items`: lista de `{owner, task, due_hint}`
    199 - `topics`: temas curtos
    200 - `quotes`: trechos literais marcantes
    201 - `open_questions`: perguntas em aberto
    202 
    203 O caminho legado (`summarize_text` em texto livre) ainda é usado como fallback se o modelo não suportar Structured Outputs ou se `OPENAI_ENABLE_SMART_SUMMARY=false`.
    204 
    205 ### Detecção de tipo de conteúdo
    206 
    207 Antes de gerar o sumário, o sistema chama um classificador curto que escolhe entre `lecture`, `podcast`, `interview`, `news`, `tutorial`, `meeting`, `tech_doc` ou `other`. O tipo detectado é exibido na CLI/API e usado para ajustar o prompt do sumário (ex.: reuniões enfatizam `decisions`/`action_items`; palestras enfatizam conceitos e exemplos).
    208 
    209 ### Capítulos com timestamps
    210 
    211 Para áudio/vídeo, quando `OPENAI_ENABLE_CHAPTERS=true`, o Lazier:
    212 
    213 1. Pede ao modelo de transcrição (`whisper-1` por padrão para timestamps) saída em `verbose_json` com `segments`.
    214 2. Envia esses segmentos ao modelo de chat, que devolve uma lista de capítulos com título, resumo e índices inicial/final.
    215 3. Materializa cada capítulo com `start`, `end` e `start_hms`/`end_hms`.
    216 
    217 Os capítulos aparecem nos exports DOCX/Markdown/PDF/TXT e no JSON cru.
    218 
    219 Os ficheiros exportados usam o **título do vídeo ou do conteúdo** (sanitizado) como nome e como cabeçalho do documento. Quando há transcrição e sumário em ficheiros separados, os sufixos `- transcricao` e `- sumario` distinguem cada artefato.
    220 
    221 ## Sites suportados (vídeo/áudio)
    222 
    223 Além do YouTube, você pode colar URLs de vídeo ou áudio de **centenas de sites**. O Lazier usa o [yt-dlp](https://github.com/yt-dlp/yt-dlp) para extrair o áudio; se a URL não for um vídeo, o sistema tenta extrair o texto da página e sumarizar.
    224 
    225 **Exemplos de sites que você pode processar:**
    226 
    227 | | | |
    228 |---|---|---|
    229 | YouTube | TED | Reddit |
    230 | Vimeo | Twitter / X | TikTok |
    231 | Instagram | Facebook | Twitch |
    232 | Dailymotion | BBC, CNN, NBC | NPR, PBS |
    233 | Arte, France TV, RTVE | Khan Academy | Coursera, Udemy |
    234 | LinkedIn Learning | Loom | Streamable |
    235 | BitChute, Odysee | Rumble | PeerTube |
    236 | archive.org | Patreon | Substack |
    237 | Wistia | Niconico | Bilibili |
    238 | Kick, Floatplane | Nebula | CuriosityStream |
    239 | C-SPAN | Al Jazeera | DW, Reuters |
    240 | ESPN, Fox Sports | Formula 1 | Olympics |
    241 | NYTimes | Washington Post | The Guardian |
    242 
    243 E muitos outros. **Lista completa** mantida pelo yt-dlp: [Supported sites](https://github.com/yt-dlp/yt-dlp/blob/master/supportedsites.md).
    244 
    245 **Importante:** Conteúdo cujo **tema é música** (categoria Music no YouTube, tags de clipe oficial, domínios só de música) **não é processado** pelo Lazier. Vídeos com **música de fundo** (vlogs, palestras, tutoriais) continuam sendo processados normalmente.
    246 
    247 ## Docker
    248 
    249 ```bash
    250 # A partir da raiz do projeto
    251 docker compose -f docker/docker-compose.yml up -d --build   # Iniciar (com rebuild)
    252 docker compose -f docker/docker-compose.yml logs -f         # Ver logs
    253 docker compose -f docker/docker-compose.yml down            # Parar
    254 docker compose -f docker/docker-compose.yml down -v         # Parar e limpar volumes
    255 ```
    256 
    257 Ou entre na pasta `docker/` e use `docker compose up -d` (sem o `-f`).
    258 
    259 ## Cache Redis
    260 
    261 Cache automático de transcrições e sumários (TTL: 7 dias).
    262 
    263 ```bash
    264 lazier cache clear    # Limpar cache
    265 lazier cache stats    # Estatísticas
    266 ```
    267 
    268 
    269 **Nota:** ffmpeg e yt-dlp são instalados automaticamente no container Docker.
    270 
    271 ## Troubleshooting
    272 
    273 - **"OPENAI_API_KEY não encontrada"**: Crie/edite o `.env` com `OPENAI_API_KEY=sua_chave`
    274 - **"SESSION_SECRET_KEY não configurada"**: Necessária para a WebGUI. Gere com `openssl rand -hex 32` e adicione ao `.env`
    275 - **"Redis não disponível"**: O sistema funciona sem cache. Para usar cache: `docker run -d -p 52847:6379 redis:7-alpine` (no host use `REDIS_PORT=52847` no `.env` se conectar ao Redis local)
    276 - **Arquivo muito grande**: A API Whisper tem limite de 25 MB. Divida arquivos grandes ou use a divisão automática do Lazier
    277 - **Conteúdo detectado como música**: URLs de música (ex.: categoria Music no YouTube) não são processadas; use apenas vídeos/podcasts
    278 
    279 ## Segurança e repositório público
    280 
    281 Antes de tornar o repositório público no GitHub:
    282 
    283 1. **Secret scanning** — Em *Settings* → *Code security and analysis*, ative **Secret scanning** (e, se disponível, *push protection*) para alertas sobre segredos no código.
    284 2. **Rever o histórico** — Com o remoto atualizado (`git fetch --all`), confirme que nunca houve `.env` ou chaves no histórico, por exemplo:
    285    - `git log --all --full-history -p -- .env`
    286    - `git log --all -S "sk-" --oneline -- "*.py" "*.md"`
    287 3. **Se algum segredo já foi commitado** — Revogue ou regenere imediatamente essa chave na respetiva plataforma (OpenAI, etc.). Limpar o ficheiro no último commit **não** remove o segredo do histórico; use ferramentas como [`git-filter-repo`](https://github.com/newren/git-filter-repo) ou BFG Repo-Cleaner e faça *force push* com consciência do impacto em colaboradores.
    288 
    289 ## Contato
    290 
    291 Pablo Murad - pablomurad@pm.me