headway-news-bot

1

Documentación

Headway News Bot

Bot de aprobación en Telegram y monitor de noticias para el canal de carga de vehículos eléctricos @headway74.

El proyecto busca noticias sobre carga de vehículos eléctricos, crea borradores en ruso para Telegram, adjunta medios relevantes cuando es posible, envía los borradores al propietario para revisión y publica solo después de un comando de aprobación explícito.

Principios fundamentales

  • Publicación con control humano: primero el borrador, la publicación en el canal solo después de публикуй.
  • La voz del canal es independiente del proveedor y se define en vps/channel_agent_rules.md.
  • El bot escribe para conductores de vehículos eléctricos, compradores de cargadores, propietarios de sitios, operadores, instaladores y lectores de infraestructura de vehículos eléctricos.
  • El bot no debe publicar relleno de plantilla ni medios engañosos.
  • Se prefieren los medios del artículo original. Si no existen medios originales, se prefiere la búsqueda exacta de entidades. La generación de imágenes con IA solo se permite tras una orden explícita del propietario.

Archivos principales

  • vps/monitor.py - monitor de noticias programado, análisis de fuentes, redacción con LLM, informes sobre China.
  • vps/bot.py - bot de aprobación en Telegram, comandos de publicar/reescribir/medios.
  • vps/channel_agent_rules.md - reglas editoriales obligatorias para cada modelo/proveedor.
  • vps/database/history.py - historial SQLite, estadísticas de calidad, memoria de comentarios del propietario.
  • vps/media/precise_image_search.py - búsqueda precisa de imágenes para corregir los medios de los borradores.
  • vps/media/media_status.py - mensajes de estado de los medios y guía para el propietario.
  • vps/keyboards.py - teclados inline con datos de callback vinculados al borrador.
  • vps/media/image_dedup.py - detección de duplicados de medios basada en ImageHash.
  • vps/backup.py - copias de seguridad gzip de SQLite.
  • vps/security/rate_limit.py - limitador de frecuencia de comandos simple en memoria.
  • vps/datasette-metadata.json - metadatos Datasette solo local.
  • vps/smoke_check.py - comprobación rápida de despliegue.
  • vps/tests/test_static_guards.py - pruebas estáticas de guardia para comportamientos críticos.

Comprobaciones en el VPS

Ejecutar desde /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

La configuración principal de ejecución debe estar en la raíz del proyecto .env: /opt/headway-news-bot/.env.

Para compatibilidad, el bot también comprueba /opt/headway-news-bot/vps/.env. El orden de carga es primero la raíz .env, luego vps/.env para los valores faltantes. El bot no falla si alguno de los archivos está ausente.

Fiabilidad y gestión del bot

Notificaciones de error

El bot captura errores no controlados, los escribe en el registro y puede enviar al propietario una notificación corta de Telegram sin tokens ni claves de API.

En .env:

ADMIN_TELEGRAM_ID=117574226
ERROR_NOTIFICATIONS_ENABLED=1

Si ADMIN_TELEGRAM_ID no está definido, el bot usa TELEGRAM_REVIEW_CHAT_ID.

Borradores y botones inline

Debajo de cada borrador aparece un panel de acciones:

  • ✅ Публиковать - publica solo el borrador seleccionado.
  • 🖼 Найти фото - ejecuta la búsqueda precisa de fotos según las entidades del borrador.
  • 🎨 Сгенерировать - ejecuta el script de generación existente solo bajo orden explícita del propietario.
  • ✏️ Переделать текст - envía el borrador para reescribir.
  • ❌ Отклонить - retira el borrador de la publicación y guarda la decisión en el historial.
  • ℹ️ Почему подходит? - muestra una explicación breve de la fuente, el tema, los medios y la razón de selección.

Los comandos antiguos de respuesta siguen funcionando: публикуй, найди фото ..., сгенерируй, переделай, отклонить, статистика.

Informe diario

El comando /daily_report muestra un resumen de las últimas 24 horas: fuentes, noticias encontradas, materiales que pasaron el filtro, borradores creados, rechazos, errores de fuentes, principales fuentes y temas del día.

Si aún no hay datos, el bot responde: Статистика за сутки пока не накоплена.

Para el envío automático diario al propietario:

DAILY_REPORT_ENABLED=1
DAILY_REPORT_TIME=09:00
SCHEDULER_ENABLED=1
SCHEDULER_TIMEZONE=Asia/Yekaterinburg

APScheduler usa identificadores de tarea persistentes y no los duplica al reiniciar.

Pytest

Las pruebas smoke de raíz están en tests/ y no requieren un token real de Telegram, API de pago ni publicación en el canal.

python -m pytest tests

Fase 2: gestión de borradores y protección de medios

Botones inline de borradores

Los teclados están en vps/keyboards.py. Cada botón contiene un draft_id corto, por lo que la acción está vinculada a un borrador específico:

  • publish:{draft_id} - primero muestra la confirmación de publicación.
  • confirm_publish:{draft_id} - publica tras el segundo clic del propietario.
  • find_photo:{draft_id} - ejecuta la búsqueda precisa de fotos.
  • generate_image:{draft_id} - ejecuta la generación solo bajo orden explícita del propietario.
  • rewrite:{draft_id} - envía el borrador para reescribir.
  • reject:{draft_id} - muestra las razones de rechazo.
  • reject_reason:{draft_id}:{reason} - guarda la razón y retira el borrador.
  • why:{draft_id} - explica la relevancia de la noticia.

Los comandos de texto antiguos no se han eliminado.

ImageHash y protección contra duplicados

vps/media/image_dedup.py calcula el hash perceptual de la imagen y lo almacena en vps/database/image_hashes.db.

Configuración:

IMAGE_HASH_ENABLED=1
IMAGE_HASH_THRESHOLD=10

La búsqueda precisa de fotos a través de vps/media/precise_image_search.py comprueba la imagen encontrada con ImageHash. Si la foto es similar a una ya usada, el bot no la sustituye automáticamente y lo registra en el log.

Visualización de estadísticas con Datasette

No es un panel de administración web, sino una vista local de SQLite. No abrir el puerto al exterior.

pip install datasette
datasette vps/database/history.db \
  --host=127.0.0.1 \
  --port=8001 \
  --metadata=vps/datasette-metadata.json

Acceso desde el ordenador:

ssh -L 8001:localhost:8001 root@VPS_IP

Después abrir http://127.0.0.1:8001. Ejemplo de unit de systemd: deploy/headway-datasette.service.example.

Copia de seguridad automática de la base de datos

vps/backup.py hace una copia gzip de todas las bases SQLite de vps/database/*.db y guarda los últimos archivos.

Como mínimo, la copia incluye:

  • history.db
  • image_hashes.db, si la base ya se ha creado con la deduplicación de ImageHash

Configuración:

BACKUP_ENABLED=1
BACKUP_KEEP_DAYS=14
BACKUP_DIR=backups

Ejecución manual en Telegram:

/backup_now

El comando solo está disponible para el propietario. Si la base aún no existe, el bot no falla y responde que no se ha creado la copia.

Comandos solo para el propietario

Las acciones críticas verifican al propietario:

  • publicación;
  • rechazo;
  • generación de imágenes;
  • búsqueda de imágenes;
  • copia de seguridad.

Configuración:

OWNER_CHAT_ID=117574226
ADMIN_TELEGRAM_ID=117574226

Si el comando lo ejecuta alguien que no es el propietario, el bot responde: Команда доступна только владельцу.

Limitación de frecuencia

Limitador simple en memoria sin Redis:

RATE_LIMIT_ENABLED=1
RATE_LIMIT_REQUESTS=30
RATE_LIMIT_WINDOW_SECONDS=60
RATE_LIMIT_OWNER_BYPASS=1

Por defecto, el propietario no está sujeto a la limitación de frecuencia.

Si se supera el límite, el bot responde: Слишком много команд. Попробуйте позже.

Comprobación después del despliegue

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 entrenamiento editorial de 7 días

Este modo temporal se usa cuando el canal se está ajustando de nuevo con los comentarios del propietario. No publica automáticamente. Solo envía borradores al propietario para revisión.

Objetivo de la semana de entrenamiento:

  • recopilar suficientes candidatos cada día;
  • mantener al menos 2 borradores fuertes y publicables por día en el flujo de revisión;
  • guardar comentarios del propietario, rechazos, notas de medios y decisiones de publicación en history.db;
  • permitir que los futuros prompts usen los comentarios de rechazo recientes para que los cambios de proveedor no alteren la voz del canal.

Archivos:

  • vps/headway-news-monitor-training7d.timer
  • vps/headway-news-monitor-training7d.service
  • vps/run_training_monitor.sh

Configuración:

TRAINING_DURATION_HOURS=168
TRAINING_LOOKBACK_HOURS=24
TRAINING_TARGET_DRAFTS_PER_DAY=2

Activar en el 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

El servicio se ejecuta:

/opt/headway-news-bot/.venv/bin/python /opt/headway-news-bot/vps/monitor.py --hours "$TRAINING_LOOKBACK_HOURS" --send-review

No llama al código de publicación en el canal. La publicación sigue requiriendo la aprobación del propietario en Telegram.

Comandos útiles de Telegram durante el entrenamiento:

  • /training_status - muestra si el modo de entrenamiento está activo, cuándo comenzó, horas restantes, candidatos, borradores, publicaciones/rechazos del propietario, reescrituras y errores de medios.
  • /source_quality - muestra la calidad de las fuentes durante 7 días por defecto.
  • /source_quality 30 o /source_quality 90 - muestra una ventana más larga de calidad de fuentes.
  • /bad_sources - muestra fuentes con bajo nivel de aprobación, muchos rechazos, hechos débiles, medios pobres o borradores fuera de tema. El bot solo recomienda, no desactiva fuentes automáticamente.
  • /good_topics - muestra los temas que llegan más a menudo a publicación, incluidos infraestructura de carga, carga rápida, China, subsidios, hubs, cambio de batería y estándares.
  • /daily_report - incluye el bloque "Обучение канала за 7 дней" mientras exista el estado de entrenamiento.
  • /memory o /update_memory - actualiza editorial_memory.md desde el historial.

editorial_memory.md guarda notas manuales fuera de este bloque generado:

<!-- AUTO_HISTORY_START -->
...
<!-- AUTO_HISTORY_END -->

El bloque automático guarda mejores fuentes, malas fuentes, buenos temas, razones frecuentes de rechazo, reglas de medios y frases a evitar.

Detener manualmente:

sudo systemctl disable --now headway-news-monitor-training7d.timer

El temporizador se desactiva solo tras la duración configurada.

Seguridad

No enviar .env, claves de API, tokens de Telegram, claves SSH, borradores en ejecución, almacenamiento de medios, registros ni bases SQLite.

Usar .env.example como única plantilla de entorno confirmada.