headway-news-bot
1
Documentação
Headway News Bot
Bot de aprovação do Telegram e monitor de notícias para o canal de carregamento de veículos elétricos @headway74.
O projeto busca notícias sobre carregamento de veículos elétricos, cria rascunhos em russo para o Telegram, anexa mídia relevante quando possível, envia rascunhos ao proprietário para revisão e publica somente após um comando explícito de aprovação.
Princípios Fundamentais
- Publicação com aprovação humana: rascunho primeiro, publicação no canal somente após
публикуй. - A voz do canal é independente do provedor e definida em
vps/channel_agent_rules.md. - O bot escreve para motoristas de VE, compradores de carregadores, proprietários de sites, operadores, instaladores e leitores de infraestrutura de VE.
- O bot não deve publicar preenchimento de modelo ou mídia enganosa.
- A mídia do artigo original é preferida. Se não houver mídia original, a busca exata por entidade é preferida. A geração de imagens por IA é permitida somente após um comando explícito do proprietário.
Arquivos Principais
vps/monitor.py- monitor de notícias agendado, parsing de fontes, redação por LLM, relatórios sobre a China.vps/bot.py- bot de aprovação do Telegram, comandos de publicar/reescrever/mídia.vps/channel_agent_rules.md- regras editoriais obrigatórias para todo modelo/provedor.vps/database/history.py- histórico SQLite, estatísticas de qualidade, memória de feedback do proprietário.vps/media/precise_image_search.py- busca precisa de imagens para correções de mídia de rascunhos.vps/media/media_status.py- mensagens de status de mídia e orientação ao proprietário.vps/keyboards.py- teclados inline com dados de callback vinculados ao rascunho.vps/media/image_dedup.py- detecção de duplicidade de mídia baseada em ImageHash.vps/backup.py- backups gzip do SQLite.vps/security/rate_limit.py- limitador de taxa de comandos simples em memória.vps/datasette-metadata.json- metadados Datasette somente locais.vps/smoke_check.py- verificação rápida de sanidade do deploy.vps/tests/test_static_guards.py- testes de guarda estáticos para comportamento crítico.
Verificações no VPS
Execute a partir de /opt/headway-news-bot:
./.venv/bin/python vps/smoke_check.py
./.venv/bin/python -m unittest discover -s tests -p "test_*.py"
./.venv/bin/python -m pytest tests
systemctl status headway-news-bot.service --no-pager
systemctl list-timers --all | grep headway
A configuração principal de runtime deve ficar na raiz do projeto .env:
/opt/headway-news-bot/.env.
Para compatibilidade, o bot também verifica /opt/headway-news-bot/vps/.env.
A ordem de carregamento é a raiz .env primeiro, depois vps/.env para valores ausentes. O bot não falha se qualquer um dos arquivos estiver ausente.
Confiabilidade e gerenciamento do bot
Notificações de erro
O bot captura erros não tratados, escreve-os no log e pode enviar ao proprietário uma notificação curta do Telegram sem tokens ou chaves de API.
Em .env:
ADMIN_TELEGRAM_ID=117574226
ERROR_NOTIFICATIONS_ENABLED=1
Se ADMIN_TELEGRAM_ID não estiver definido, o bot usa TELEGRAM_REVIEW_CHAT_ID.
Rascunhos e botões inline
Abaixo de cada rascunho aparece um painel de ações:
✅ Публиковать- publica apenas o rascunho selecionado.🖼 Найти фото- inicia a busca precisa de fotos pelas entidades do rascunho.🎨 Сгенерировать- executa o script de geração existente mediante comando explícito do proprietário.✏️ Переделать текст- envia o rascunho para reescrita.❌ Отклонить- remove o rascunho da publicação e registra a decisão no histórico.ℹ️ Почему подходит?- mostra uma explicação curta da fonte, do tema, da mídia e do motivo da seleção.
Os antigos comandos de reply continuam funcionando: публикуй, найди фото ..., сгенерируй, переделай, отклонить, статистика.
Relatório diário
O comando /daily_report mostra um resumo das últimas 24 horas: fontes, notícias encontradas, materiais que passaram no filtro, rascunhos criados, rejeições, erros de fontes, principais fontes e temas do dia.
Se ainda não houver dados, o bot responde: Статистика за сутки пока не накоплена.
Para envio automático diário ao proprietário:
DAILY_REPORT_ENABLED=1
DAILY_REPORT_TIME=09:00
SCHEDULER_ENABLED=1
SCHEDULER_TIMEZONE=Asia/Yekaterinburg
O APScheduler usa IDs de tarefas persistentes e não os duplica na reinicialização.
Pytest
Os smoke-tests raiz estão em tests/ e não exigem token real do Telegram, APIs pagas ou publicação no canal.
python -m pytest tests
Etapa 2: gerenciamento de rascunhos e proteção de mídia
Botões inline de rascunhos
Os teclados estão em vps/keyboards.py. Cada botão contém um draft_id curto, portanto a ação está vinculada a um rascunho específico:
publish:{draft_id}- primeiro mostra a confirmação de publicação.confirm_publish:{draft_id}- publica após o segundo clique do proprietário.find_photo:{draft_id}- inicia a busca precisa de fotos.generate_image:{draft_id}- inicia a geração somente mediante comando explícito do proprietário.rewrite:{draft_id}- envia o rascunho para reescrita.reject:{draft_id}- mostra os motivos da rejeição.reject_reason:{draft_id}:{reason}- salva o motivo e remove o rascunho.why:{draft_id}- explica a relevância da notícia.
Os antigos comandos de texto não foram removidos.
ImageHash e proteção contra duplicatas
vps/media/image_dedup.py calcula o perceptual hash da imagem e o armazena em vps/database/image_hashes.db.
Configurações:
IMAGE_HASH_ENABLED=1
IMAGE_HASH_THRESHOLD=10
A busca precisa de fotos via vps/media/precise_image_search.py verifica a imagem encontrada usando ImageHash. Se a foto for semelhante a uma já usada, o bot não a substitui automaticamente e registra isso no log.
Visualização de estatísticas via Datasette
Não é um painel web, mas uma visualização local do SQLite. Não abrir a porta para o exterior.
pip install datasette
datasette vps/database/history.db \
--host=127.0.0.1 \
--port=8001 \
--metadata=vps/datasette-metadata.json
Acesso a partir do computador:
ssh -L 8001:localhost:8001 root@VPS_IP
Depois abrir http://127.0.0.1:8001. Exemplo de unit systemd: deploy/headway-datasette.service.example.
Backup automático do banco
vps/backup.py faz backup gzip de todos os bancos SQLite de vps/database/*.db e armazena os arquivos mais recentes.
No mínimo, entram no backup:
history.dbimage_hashes.db, se o banco já foi criado pela deduplicação ImageHash
Configurações:
BACKUP_ENABLED=1
BACKUP_KEEP_DAYS=14
BACKUP_DIR=backups
Execução manual no Telegram:
/backup_now
O comando está disponível somente para o proprietário. Se o banco ainda não existir, o bot não falha e responde que o backup não foi criado.
Comandos somente do proprietário
Ações críticas verificam o proprietário:
- publicação;
- rejeição;
- geração de imagem;
- busca de imagem;
- backup.
Configurações:
OWNER_CHAT_ID=117574226
ADMIN_TELEGRAM_ID=117574226
Se o comando for chamado por quem não é o proprietário, o bot responde: Команда доступна только владельцу.
Rate limit
Limitador simples em memória sem Redis:
RATE_LIMIT_ENABLED=1
RATE_LIMIT_REQUESTS=30
RATE_LIMIT_WINDOW_SECONDS=60
RATE_LIMIT_OWNER_BYPASS=1
Por padrão, o proprietário não está sujeito ao rate limit.
Ao exceder o limite, o bot responde: Слишком много команд. Попробуйте позже.
Verificação pós-deploy
python -m compileall vps
python -m pytest tests -v
./.venv/bin/python vps/smoke_check.py
systemctl restart headway-news-bot.service
systemctl status headway-news-bot.service --no-pager
Modo de treinamento editorial de 7 dias
Este modo temporário é usado quando o canal está sendo ajustado novamente com o feedback do proprietário. Ele não publica automaticamente. Apenas envia rascunhos ao proprietário para revisão.
Objetivo da semana de treinamento:
- coletar candidatos suficientes todos os dias;
- manter pelo menos 2 rascunhos fortes publicáveis por dia no fluxo de revisão;
- salvar comentários do proprietário, rejeições, anotações de mídia e decisões de publicação em
history.db; - permitir que prompts futuros usem feedback de rejeição recente para que trocas de provedor não mudem a voz do canal.
Arquivos:
vps/headway-news-monitor-training7d.timervps/headway-news-monitor-training7d.servicevps/run_training_monitor.sh
Configurações:
TRAINING_DURATION_HOURS=168
TRAINING_LOOKBACK_HOURS=24
TRAINING_TARGET_DRAFTS_PER_DAY=2
Ativar no VPS:
sudo cp vps/headway-news-monitor-training7d.service /etc/systemd/system/
sudo cp vps/headway-news-monitor-training7d.timer /etc/systemd/system/
sudo chmod +x vps/run_training_monitor.sh
sudo systemctl daemon-reload
sudo systemctl enable --now headway-news-monitor-training7d.timer
sudo systemctl start headway-news-monitor-training7d.service
O serviço executa:
/opt/headway-news-bot/.venv/bin/python /opt/headway-news-bot/vps/monitor.py --hours "$TRAINING_LOOKBACK_HOURS" --send-review
Ele não chama o código de publicação no canal. A publicação continua exigindo aprovação do proprietário no Telegram.
Comandos úteis do Telegram durante o treinamento:
/training_status- mostra se o modo de treinamento está ativo, quando começou, horas restantes, candidatos, rascunhos, publicações/rejeições do proprietário, reescritas e erros de mídia./source_quality- mostra a qualidade das fontes por 7 dias por padrão./source_quality 30ou/source_quality 90- mostra uma janela maior de qualidade de fontes./bad_sources- mostra fontes com baixa aprovação, muitas rejeições, fatos fracos, mídia ruim ou rascunhos fora do tema. O bot apenas recomenda, não desativa fontes automaticamente./good_topics- mostra temas que chegam à publicação com mais frequência, incluindo infraestrutura de carregamento, carregamento rápido, China, subsídios, hubs, troca de baterias e padrões./daily_report- inclui o bloco "Treinamento do canal por 7 dias" enquanto o estado de treinamento existir./memoryou/update_memory- atualizaeditorial_memory.mda partir do histórico.
editorial_memory.md mantém anotações manuais fora deste bloco gerado:
<!-- AUTO_HISTORY_START -->
...
<!-- AUTO_HISTORY_END -->
O bloco automático armazena melhores fontes, fontes ruins, bons temas, motivos frequentes de rejeição, regras de mídia e frases a evitar.
Parar manualmente:
sudo systemctl disable --now headway-news-monitor-training7d.timer
O timer se desativa sozinho após a duração configurada.
Segurança
Não commitar .env, chaves de API, tokens do Telegram, chaves SSH, rascunhos de runtime, armazenamento de mídia, logs ou bancos de dados SQLite.
Use .env.example como o único template de ambiente commitado.