mirror of
https://gitverse.ru/kpa39l/vesti.git
synced 2026-09-29 09:55:03 +00:00
Initial import: vesti.nixg.ru — новостной апрув-проект (web, crawler, classifier, publisher, openspec)
This commit is contained in:
@@ -0,0 +1,196 @@
|
||||
# PRD — VESTI: новостной агрегатор с веб-интерфейсом
|
||||
|
||||
> **Правило проекта (пользователь, 2026-09-09): все задачи выполняются через OpenSpec** —
|
||||
> каждый элемент/изменение оформляется как change (proposal, design, specs, tasks),
|
||||
> проверяется `openspec validate`. Изменения фиксировать в STATUS.md / TODO.md /
|
||||
> WALKTHROUGH.md / PRD.md.
|
||||
|
||||
- Статус: v0.2 (2026-09-10) — прототип работает, реальная публикация включена
|
||||
- Расположение: /opt/vesti
|
||||
- Эволюция: /opt/news (наследие — код, схема, sources.yaml, Telethon-сессия)
|
||||
- Репозитории: vesti-* (источник истины gitverse.ru, зеркало gitea bigbox:3000)
|
||||
|
||||
## 1. Цель
|
||||
|
||||
Построить собственный новостной конвейер «СМИ»: собирать новости из многих
|
||||
источников (RSS, почтовые рассылки, сайты, Telegram, WeChat, X), дедуплицировать
|
||||
и объединять в одну статью со ссылками на все источники (юридическая защита),
|
||||
проверять факты, дополнять мультимедиа, категоризировать по направлениям,
|
||||
и формировать:
|
||||
|
||||
1. **Дайджесты по направлениям** — для еженедельных видео (учитывают
|
||||
популярность тем, реакции, мои оценки интересности).
|
||||
2. **Ленты новостных ботов** — Telegram, VK, fediverse по направлениям.
|
||||
|
||||
Всё управление — через веб-сайт с авторизацией: списки внешних новостей
|
||||
с метриками популярности, списки опубликованных со своими метриками,
|
||||
редактирование прямо в интерфейсе.
|
||||
|
||||
Собственный контент (канал @dedinit «Дед в АйТи» ~1092 поста) — отдельный
|
||||
класс: is_own=1/is_own_canonical=1, приоритетная классификация (critical без
|
||||
LLM при словарном попадании), fan-out по направлениям.
|
||||
|
||||
## 2. Направления (категории)
|
||||
|
||||
Технологии, Политика, Игры, Электроника, БЯМ (большие языковые модели), Линукс.
|
||||
|
||||
## 3. Языки ботов
|
||||
|
||||
Отдельные боты под комбинации направление×язык: ru, en, zh, ko.
|
||||
Именование: @dedinit_vesti_<направление>_<язык>_bot.
|
||||
Прототип (текущий): **бот-контроллер @dedinit_controller_bot публикует в канал
|
||||
@dedinit_vesti** (один бот → много каналов через добавление админом; каналы из
|
||||
VESTI_BOT_CHANNELS). Отдельные боты направлений — фаза 2.
|
||||
|
||||
## 4. Принципы
|
||||
|
||||
- **Каноническая БД — PostgreSQL** (решение D1; для прототипа допустим SQLite,
|
||||
миграция на Postgres на фазе 2).
|
||||
- **Банк статей — markdown-бандлы с frontmatter** + мультимедиа рядом:
|
||||
`bundles/<направление>/<YYYY-MM>/<slug>.md` + `media/<slug>/`.
|
||||
- **Всё локально** на bigbox; массовая классификация — Ollama qwen3:8b-nothink;
|
||||
облачный LLM (deepseek, отдельный API/ключ — учёт затрат проекта) — факт-чек,
|
||||
слияние, дайджесты (решение E2).
|
||||
- **n8n — оркестратор** для RSS/email/сайтов (отдельный контейнер, общий для
|
||||
инфраструктуры), НЕ для Telegram (Bot API не читает чужие каналы — только
|
||||
MTProto/Telethon).
|
||||
- **Публикация ботов — режим «черновик на подтверждение»** (решение C2-b):
|
||||
сначала подтверждение человеком, потом смягчение.
|
||||
- **Переиспользуем существующий стек**: Qdrant (docker-qdrant-1, :6333),
|
||||
Redis (:6379), Ollama (:11434), telegram-tunnel (SOCKS5 :1080 → VPS01),
|
||||
Garage S3 (медиа, фаза 2), GoToSocial (fediverse-бот, фаза 2),
|
||||
gitea (:3000, зеркало) / gitverse.ru (истина).
|
||||
- Тихие watchdogs: молчат, пока всё живо (политика пользователя).
|
||||
|
||||
## 5. Архитектура (текущая, 2026-09-10)
|
||||
|
||||
```
|
||||
sources.yaml (реестр, git)
|
||||
│
|
||||
▼
|
||||
telegram_crawler.py (cron каждые 30 мин, Telethon MTProto, SOCKS5 :1080)
|
||||
│ инкрементально после last_post_id; метрики views/reactions; --all / --source
|
||||
▼
|
||||
backfill_dedinit.py (разовый бэкфилл своего канала ~1092 постов, is_own=1, медиа)
|
||||
│
|
||||
▼
|
||||
SQLite vesti.db (raw-посты, tg_state, runs, классификации) ──► Postgres (фаза 2)
|
||||
│
|
||||
▼
|
||||
classifier.py (Ollama qwen3:8b-nothink + словарный фильтр)
|
||||
│ направление, relevance, interest 1-5, summary; мультинаправления
|
||||
▼
|
||||
vesti-web (FastAPI + Bootstrap 5.3 + Jinja2 + HTMX, 127.0.0.1:8400)
|
||||
│ авторизация; кандидаты → подтвердить/отклонить; «Свои»; метрики
|
||||
▼ (подтверждённые)
|
||||
publisher-service (FastAPI-микросервис, Docker vesti-publisher, :8410)
|
||||
│ POST /api/v1/publish → Bot API через SOCKS5 :1080 (host.docker.internal)
|
||||
│ медиа: маунт ../../media/media:/srv/publisher/media:ro (веб шлёт media/<file>)
|
||||
▼
|
||||
Telegram @dedinit_vesti (бот-контроллер @dedinit_controller_bot; каналы из VESTI_BOT_CHANNELS)
|
||||
│
|
||||
▼
|
||||
bundles/<направление>/<YYYY-MM>/<slug>.md (markdown + frontmatter) + media/
|
||||
```
|
||||
|
||||
Сервисы/порты (актуально):
|
||||
| Сервис | Порт | Способ запуска |
|
||||
|---|---|---|
|
||||
| vesti-web | 127.0.0.1:8400 | systemd-юнит vesti-web.service (установлен; daemon-reload на bigbox зависает — внешняя проблема, подхватится при перезагрузке). Пароль: VESTI_WEB_PASSWORD or ADMIN_PASSWORD из .env |
|
||||
| publisher-service | 127.0.0.1:8410 | Docker (docker-compose, restart policy), healthz |
|
||||
| telegram-tunnel | SOCKS5 127.0.0.1:1080 | systemd telegram-tunnel.service |
|
||||
| Ollama | 127.0.0.1:11434 | существующий (qwen3:8b-nothink) |
|
||||
|
||||
Cron (Hermes cron, no_agent, тихие):
|
||||
- vesti-crawler-all-sources (`*/30 * * * *`) — краулер по всем включённым источникам,
|
||||
лог /opt/vesti/logs/crawler-cron.log; молчит при успехе.
|
||||
- vesti-watchdog (`*/15 * * * *`) — publisher :8410 healthz, веб :8400, SOCKS5 :1080,
|
||||
контейнер, БД; шумит в Telegram только при проблеме.
|
||||
|
||||
Фаза 2+: n8n (RSS/email/сайты), Postgres, S3 (Garage), семантический dedup
|
||||
(Qdrant bge-m3), факт-чек облаком, дайджесты для видео, боты VK/fediverse,
|
||||
WeChat/X.
|
||||
|
||||
## 6. Метрики популярности
|
||||
|
||||
- Внешние TG-посты: views + reactions (через Telethon при краулинге).
|
||||
- Свои посты: views через Bot API (GET /api/v1/views/{channel}/{mid}).
|
||||
- Сайты/RSS (фаза 2): только свои переходы (UTM-метки в ссылках).
|
||||
- Интерес темы: кол-во реакций/просмотров → показатель хайповости;
|
||||
залайканные комментарии — сигнал (фаза 2).
|
||||
|
||||
## 7. Дайджесты (G1, G3)
|
||||
|
||||
Отдельная сущность по направлению: по каждой теме — суть, источники, оценка
|
||||
популярности. Для еженедельного видео: 5–10 новостных поводов в выпуске,
|
||||
выходные. Оценки интересности — в вебе (1–5 + флаг «в дайджест»).
|
||||
|
||||
## 8. Технологический стек
|
||||
|
||||
| Слой | Технология | Статус |
|
||||
|---|---|---|
|
||||
| Язык | Python 3.12, venv /opt/vesti/.venv | новый |
|
||||
| Telegram-краулер | Telethon (MTProto), SOCKS5 :1080, сессия /opt/vesti/telegram/ | новый (переисп. код /opt/news) |
|
||||
| Бот-публикатор | publisher-service: httpx[socks] → Bot API (не python-telegram-bot) | новый |
|
||||
| Каноническая БД | SQLite (прототип) → PostgreSQL (фаза 2) | новый |
|
||||
| LLM-классификация | Ollama qwen3:8b-nothink (:11434) | существующий |
|
||||
| Облачный LLM | deepseek (отдельный API/ключ) | фаза 2 |
|
||||
| Векторный поиск | Qdrant :6333 (коллекция news), bge-m3 | существующий |
|
||||
| Веб | FastAPI + Bootstrap 5.3 + Jinja2 + HTMX | новый, :8400 |
|
||||
| Оркестратор | n8n (отдельный контейнер, :5678), общий | фаза 2 |
|
||||
| Медиа | локально /opt/vesti/media/media/ → Garage S3 | фаза 2 |
|
||||
| Git | gitverse.ru (истина), gitea bigbox :3000 (зеркало) | существующий |
|
||||
| Доставка | Telegram-боты, потом VK/fediverse | новый |
|
||||
|
||||
## 9. OpenSpec
|
||||
|
||||
Проект ведётся по OpenSpec: /opt/vesti/openspec/.
|
||||
Active changes:
|
||||
- `tg-crawler-publisher-prototype` (прототип конвейера; реализован),
|
||||
- `own-content-hub` (свой канал @dedinit, fan-out; код готов, бэкфилл идёт,
|
||||
интеграционная проверка после него),
|
||||
- `publisher-service` (микросервис публикации; создан 2026-09-09, validate чист,
|
||||
реальная публикация работает).
|
||||
Файлы: proposal.md, design.md, specs/*/spec.md, tasks.md.
|
||||
|
||||
## 10. Прототип — текущее состояние
|
||||
|
||||
Вертикаль Линукс (ru) + свой контент:
|
||||
1. TG-краулер 8 публичных каналов (Telethon, SOCKS5, инкрементальный, метрики;
|
||||
форварды из своих каналов отфильтровываются, чужие — с fwd-полями без медиа).
|
||||
2. Классификатор (словари + локальный qwen3:8b-nothink; мультинаправления;
|
||||
свои посты → critical без LLM при словарном попадании).
|
||||
3. Реальная публикация: бот-контроллер @dedinit_controller_bot → @dedinit_vesti
|
||||
(проверено: message_id 2–4, approve через веб работает).
|
||||
4. Веб (127.0.0.1:8400): кандидаты → подтвердить/отклонить, «Свои», метрики,
|
||||
опубликованные.
|
||||
5. Банк статей markdown с frontmatter (bundles/, origin:own для своих).
|
||||
6. Бэкфилл канала @dedinit (~1092 постов is_own=1, медиа) — скрипт
|
||||
crawler/backfill_dedinit.py, запущен 2026-09-10.
|
||||
|
||||
Источники: linuxklub, linuxos_tg, dotfiles_linux, linux_education, LinuxMastery,
|
||||
linuxcamp_tg, gitgate, krxnotes + канал dedinit (own).
|
||||
|
||||
## 11. Критерии готовности прототипа (DoD)
|
||||
|
||||
1. Краулер собирает посты из линукс-каналов с метриками, без дублей (проверка: count по sha256 = count id). — ДОСТИГНУТО
|
||||
2. Классификатор корректно относит ≥90% контрольных постов к направлению. — В ПРОВЕРКЕ (после бэкфилла — прогон по 543+ неклассифицированным)
|
||||
3. Бот публикует карточку-пост только после подтверждения в вебе. — ДОСТИГНУТО
|
||||
4. Веб доступен локально, с авторизацией; кандидаты/опубликованные/метрики видны. — ДОСТИГНУТО
|
||||
5. Бандл создан в bundles/linux/YYYY-MM/<slug>.md с frontmatter и источниками. — ДОСТИГНУТО
|
||||
6. Watchdog молчит 3 дня подряд при здоровой системе. — В ПРОВЕРКЕ (cron создан 2026-09-10)
|
||||
7. Смягчение публикации (C2: b → a/в) — отдельное решение после прототипа.
|
||||
|
||||
## 12. Открытые вопросы / следующие фазы
|
||||
|
||||
- Миграция SQLite → Postgres (когда поток статей вырастет).
|
||||
- Облачный LLM API для факт-чека/слияния/дайджестов — отдельный ключ/учёт затрат.
|
||||
- n8n-воркфлоу для RSS/email/сайтов (общий контейнер).
|
||||
- Боты VK, fediverse (GoToSocial) — фаза 2; отдельные боты направлений
|
||||
(@dedinit_vesti_<dir>_<lang>_bot) — фаза 2.
|
||||
- WeChat (закрытый, сложный) и X (платный API) — исследование отдельно.
|
||||
- Автопубликация/смягчение условий (после прототипа).
|
||||
- Дайджесты: сущность, связь с видео-сценарием.
|
||||
- git-репозиторий /opt/vesti (gitverse истина, gitea зеркало) — инициализировать.
|
||||
- openspec archive publisher-service / tg-crawler-publisher-prototype после
|
||||
подтверждения и интеграционных проверок.
|
||||
Reference in New Issue
Block a user