Tainacan Narrativas
Plugin WordPress: transforma itens Tainacan em narrativas em áudio (leitura documental, IA opcional a partir das fontes, TTS neural ou voz do navegador) com player acessível.
by Marcos Sigismundo · github.com/marcossigismundo/tainacan-narrativas · website
Install
No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:
wp plugin install https://github.com/marcossigismundo/tainacan-narrativas/archive/refs/heads/main.zipReadme
Tainacan Narrativas
Plugin WordPress que transforma itens Tainacan em experiências narrativas em áudio: leitura documental dos metadados e documentos, narrativa opcional assistida por IA (sempre a partir das fontes do próprio item) e síntese de voz, com um player acessível na página pública do item.
Parte do ecossistema do Memorial Digital da Pandemia, ao lado do tainacan-dip-importer, tainacan-metadata-crowdsource (Tainacan Colab) e tainacan-wacz-player. É um plugin independente: não modifica o Tainacan, o tema nem os outros plugins.
OBJETO DIGITAL → METADADOS + DOCUMENTO + ANEXOS → CONTEÚDO DOCUMENTAL → NARRATIVA → VOZ → EXPERIÊNCIA DE ACESSO
Sumário
- O que é
- Arquitetura
- Instalação
- Configuração
- IA
- TTS
- Privacidade
- Segurança
- Processamento (fila, hash, cache)
- Player, shortcode e bloco
- Hooks para extensões
- WP-CLI
- REST API
- Diagnóstico
- Limitações conhecidas
- Desenvolvimento
O que é
Três conceitos separados de propósito:
| Camada | O que faz | Onde |
|---|---|---|
| Leitura documental | Roteiro estritamente montado com título + descrição + metadados públicos + texto do documento e dos anexos. Não interpreta, não acrescenta contexto. | Narrative\ScriptBuilder (template configurável) |
| Narrativa assistida por IA (opcional) | O modelo recebe somente as fontes do item, delimitadas, e produz um roteiro para ser ouvido — sem inventar datas, pessoas, lugares ou acontecimentos. | Narrative\NarrativeGenerator + prompts/ |
| Síntese de voz | Camada independente: TTS neural local/institucional (Kokoro, Piper), API compatível com OpenAI, WordPress AI ou a voz do navegador do visitante. | TTS\* |
Princípio de desempenho: gerar → armazenar → servir. A página pública só reproduz conteúdo previamente gerado; IA e TTS rodam numa fila.
Funciona sem nenhuma chave de IA e em hospedagens simples (roteiro por template + voz do navegador).
Arquitetura
Content Collector → Script Builder / Narrative Generator → TTS Provider → Audio Storage → Frontend Player
(Tainacan APIs) (template | IA + prompts) (browser|api) (Media Library) (Vanilla JS)
tainacan-narrativas/
├── tainacan-narrativas.php bootstrap magro (constantes, autoload, hooks de ativação)
├── includes/
│ ├── Core/ Plugin (wiring no init), Options, Capabilities, Lock, Activator/Deactivator
│ ├── Tainacan/ ItemDetector, ContentCollector, CollectionSettings, ChangeListener
│ ├── Documents/ ExtractorInterface, ExtractorManager (cache), Pdf/Docx/Odt/Text extractors, OcrProviderInterface
│ ├── Narrative/ Normalizer, Chunker, SourceHasher, ContentScore, Modes, PromptLoader, ScriptBuilder, NarrativeGenerator, NarrativeManager
│ ├── AI/ AIProviderInterface, OpenAICompatible, OpenAI, Ollama, Gemini, WordPressAI, ProviderManager
│ ├── TTS/ TTSProviderInterface, Browser, OpenAICompatibleTTS, PiperHttp, WordPressAITTS, AudioConcat, AudioStorage, ProviderManager
│ ├── Queue/ QueueManager (WP-Cron), JobRunner
│ ├── Database/ Tables, NarrativeRepository, JobRepository
│ ├── REST/ Controller (tainacan-narrativas/v1)
│ ├── Frontend/ Player, Shortcode, Block, Assets, views/player.php
│ ├── Admin/ AdminPage (\Tainacan\Pages), SettingsHandler, Diagnostics, views/
│ ├── Security/ Security (SSRF, endpoints, paths)
│ ├── Logging/ Logger (redação de segredos)
│ └── CLI/ Command
├── prompts/ system, faithful, documentary, storytelling, summary, detailed, accessible, children, chunk-summary, consolidate
├── assets/ css/player.css, css/admin.css, js/player.js, js/admin.js, js/block-editor.js
├── vendor/ smalot/pdfparser (distribuído)
├── tests/ PHPUnit (unit) + roteiro de integração
└── AGENTS.md, DEPENDENCIES.md, CHANGELOG.md, readme.txt
Banco de dados: wp_tn_narratives (uma linha por item × versão, is_current, hashes, roteiro gerado/editado, proveniência, status) e wp_tn_jobs (fila). Índices em item_id, (item_id,is_current), collection_id, status, source_hash, (status,run_after).
Instalação
- Envie a pasta (ou o ZIP de release) para
wp-content/plugins/e ative. Requer WordPress 6.5+, PHP 8.0+ e Tainacan 1.0+. - Você será levado a Tainacan → Narrativas (grupo "Outros"), onde um wizard de 5 passos pede coleções, modo, voz, IA opcional e um item de teste. Pode ser pulado.
- Nada é gerado nem enviado a serviços externos até que as narrativas sejam ativadas e pelo menos uma coleção seja habilitada.
Não exige composer install, npm install, build, CDN ou SSH.
Configuração
Abas em Tainacan → Narrativas:
- Painel — cards (prontas, pendentes, revisão, desatualizadas, erro, tempo total de áudio, sem texto, OCR necessário) e geração rápida com "Visualizar fontes".
- Narrativas — tabela (item, coleção, status, modo, duração, última geração, IA, TTS) com ações: gerar, regenerar, ouvir, detalhes (roteiro editável, fontes e saúde, rastreabilidade), aprovar, verificar, excluir áudio, excluir.
- Coleções — opt-in por coleção; player automático; fontes (descrição, documento, anexos, limites); allowlist e ordem de metadados (somente públicos); modo; fluxo editorial; conteúdo sensível (automática / revisão obrigatória / não gerar); IA/TTS/voz; permissão de IA externa e de envio de anexos; download. "Gerar narrativas dos itens" enfileira a coleção.
- IA — provedor, endpoint, modelo, chave (mascarada ou por
wp-config.php), timeout, temperatura, tokens, chunk; endpoints de rede privada; modo infantil. - Voz — mecanismo (navegador, API compatível com OpenAI/Kokoro, Piper, WordPress AI), voz, formato, velocidade; preferências da voz do navegador; testes e áudio de teste.
- Processamento — fila (executar agora, limpar falhas), gatilho ao salvar (marcar desatualizada / enfileirar / nada), WP-Cron, lote, orçamento de tempo, tentativas, limites de caracteres/anexos, versões mantidas (1/3/5/todas).
- Configurações — ativar, player automático, download, nota de proveniência, modo padrão, fluxo editorial padrão (revisão humana recomendada), idioma, fontes padrão, template da leitura documental, debug, apagar dados ao desinstalar.
- Diagnóstico — WordPress, PHP, extensões, Tainacan, HTTPS, WP-Cron, REST, uploads, tabelas, pdfparser, indexação do core, IA/TTS selecionados e endpoints (só host), fila, último job, limites; botões Testar IA / Testar TTS / Gerar áudio de teste / Testar escrita / Executar fila; log recente sem segredos.
Modos narrativos
faithful (leitura fiel), documentary (padrão), storytelling (história contextualizada), summary (1–3 min), detailed (5–10 min), accessible (linguagem simples) e children (somente se habilitado; nunca infantiliza temas sensíveis). Sem IA, os modos aplicam o template com o limite de palavras de cada modo.
Fluxo editorial
- A — automático: roteiro → áudio.
- B — revisão humana (padrão, recomendado para acervos históricos): roteiro pendente → revisor edita/aprova → TTS. Uma edição humana fica em
edited_script, com autor e data; o texto gerado é preservado emgenerated_script. Regenerações de um item cujo roteiro foi editado voltam para revisão mesmo no fluxo A — nunca substituem a edição silenciosamente.
IA
AI\AIProviderInterface com implementações:
| id | Serviço | Configuração |
|---|---|---|
openai_compatible |
Qualquer POST {base}/chat/completions (Ollama, LM Studio, vLLM, LocalAI, OpenRouter, gateways institucionais) |
URL base, modelo, chave opcional |
openai |
OpenAI | modelo, chave (TN_AI_API_KEY) |
ollama |
Ollama nativo (lista modelos em /api/tags) |
URL, modelo |
gemini |
Google Gemini generateContent |
modelo, chave (TN_GEMINI_API_KEY, enviada em header) |
wp_ai |
WordPress AI Client (WP 7.0+) — conectores do próprio site | nenhuma chave no plugin |
Pipeline: fontes normalizadas → (documentos maiores que o chunk) redução factual por trecho → consolidação → prompt do modo → pós-processamento (remove markdown e delimitadores vazados). Reduções intermediárias são cacheadas por hash em transients (7 dias). O painel mostra caracteres, chunks e tokens estimados (nunca custo).
Prompts em prompts/*.php. O system prompt exige uso exclusivo das fontes, proíbe criar datas/pessoas/lugares/acontecimentos e completar lacunas, preserva nomes e datas, evita sensacionalismo e trata todo conteúdo entre <<<SOURCE …>>> e <<<END_SOURCE>>> como documentação, nunca como instrução (defesa contra prompt injection em documentos do acervo).
TTS
TTS\TTSProviderInterface:
| id | Mecanismo | Saída |
|---|---|---|
browser |
Web Speech API no dispositivo do visitante (fallback universal, zero bytes, sem servidor) | roteiro armazenado; áudio local |
openai_compatible |
POST {base}/audio/speech — Kokoro-FastAPI (open source, vozes pt-BR pf_dora, pm_alex, pm_santa, CPU), LocalAI, OpenedAI-Speech, OpenAI |
MP3/WAV na Media Library |
piper_http |
Servidor HTTP do Piper (JSON {text,voice} ou texto puro) |
WAV na Media Library |
wp_ai |
WordPress AI Client com texto-fala | conforme conector |
Estratégia: TTS neural configurado → gera e armazena; senão → voz do navegador. Roteiros longos são sintetizados em partes e concatenados (MP3 por quadros, WAV por reescrita de cabeçalho) sem ffmpeg. Trocar só a voz regenera apenas o áudio (o roteiro é reutilizado via script_hash/audio_hash).
Setup sugerido para pt-BR neural: Kokoro-FastAPI em Docker na mesma rede → URL base http://kokoro:8880/v1, modelo kokoro, voz pf_dora, formato mp3, e "Permitir endpoints de rede privada" ligado.
Privacidade
- Somente metadados públicos entram na narrativa (privados são contados e ignorados).
- Por coleção: proibir IA externa; não enviar anexos; não gerar (sensível); revisão obrigatória.
- "Visualizar fontes" mostra exatamente o que será usado e enviado.
- Nunca são enviados: dados administrativos, logs, IDs desnecessários, usuários, e-mails, tokens.
- Nota de proveniência discreta no player ("Texto narrativo produzido automaticamente a partir das informações documentais deste registro." quando houver IA).
Segurança
- Capabilities próprias:
manage_tainacan_narratives(configurações, chaves, exclusão),generate_tainacan_narratives,review_tainacan_narratives. Administradores recebem as três na ativação; papéis commanage_tainacanrecebem gerar + revisar. - Toda rota REST tem
permission_callbackcom capability real; o endpoint público exige item legível, publicado e coleção habilitada. - Chaves: no banco (mascaradas; nunca em HTML/JS/logs/GET) ou em
wp-config.php(TN_AI_API_KEY,TN_GEMINI_API_KEY,TN_TTS_API_KEY), que bloqueiam o campo no painel. - SSRF:
Security::validate_endpoint()valida esquema (http/https), userinfo, portas e redes privadas; requisições viawp_safe_remote_request(); redes privadas só com a opção explícita (manage) e sem redirecionamentos. - Sem shell, sem caminhos arbitrários (áudio via
wp_upload_bits, leitura só dentro de uploads), sem CDN. - Logs redigem
Bearer,sk-…,AIza…,api_key,token,Authorization.
Processamento
- Fila
wp_tn_jobsem WP-Cron (tn_process_queuea cada minuto, lote e orçamento de tempo configuráveis, lockadd_optionatômico) — sem Action Scheduler. Botão "Executar fila" ewp tainacan-narrativas queuepara hosts sem cron confiável. - Etapas extract → script → audio, idempotentes; retentativas com backoff 1/3/9 min; na última tentativa uma IA indisponível cai para o roteiro por template.
- Lock por item (15 min) impede gerações simultâneas.
- Hash:
source_hash = SHA-256(título + descrição + metadados + textos/assinaturas dos documentos + configuração narrativa);script_hash;audio_hash = script + provedor + voz + velocidade + formato. - Detecção de alterações:
tainacan-insert,tainacan-api-item-updated,save_post, hooks de anexos → limpeza do cache de extração + verificação debounced (tn_check_item, 90 s) →stale(ou enfileira, conforme o gatilho). Varredura diária (tn_stale_sweep) cobre mudanças fora dos hooks. Alterações via Tainacan Colab ou DIP Importer passam pelos mesmos hooks. - Cache: texto extraído por anexo (post meta, assinatura tamanho+mtime), reduções por chunk (transients), roteiro e áudio (versões).
Player, shortcode e bloco
- Injeção automática (por coleção) em
tainacan-interface-single-item-after-attachments(tema Tainacan),tainacan_single_item_content(conteúdo padrão do core) ethe_content(temas clássicos), com guarda anti-duplicação. [tainacan_narrativa],[tainacan_narrativa item_id="123" title="…" transcript="0"].- Bloco dinâmico
tainacan-narrativas/player(itemId 0 = item atual) para temas de blocos. - Controles: play/pause/continuar, ±10 s, progresso com
aria-valuetext, tempo, volume, velocidade 0.75–2×, "Ver texto" (<details>com destaque da sentença atual), download opcional, Media Session. Sem autoplay, ícones SVG locais,system-ui, tokens CSS espelhando--tainacan-*, teclado e foco visível.