mirror of
https://gitverse.ru/kpa39l/vesti.git
synced 2026-09-29 09:55:03 +00:00
docs: закрытие сессии 2026-09-15 — TODO/WALKTHROUGH актуализированы (selected-list, почтовый UI); отмечены незакоммиченные наработки прошлых сессий
This commit is contained in:
@@ -60,7 +60,7 @@
|
||||
| 2026-09-13 | Пост без классификации: на карточке значок «?» — понять его роль; если классификации нет — дать возможность вручную указывать/изменять/добавлять направление при анализе | 🔵 открыта | |
|
||||
| 2026-09-13 | git-репозиторий /opt/vesti (gitverse истина, gitea зеркало) | ✅ закрыта | 2026-09-13 (git init + commit; gitverse kpa39l/vesti main; gitea estorozhenko/vesti mirror 8h; .gitignore: backups/media/db/bundles/logs исключены) |
|
||||
| 2026-09-13 | Интерфейс кандидатов: разделить окно на 2 панели — слева список кандидатов, справа меню действий с постом (опубликовать / отклонить / переклассифицировать / переписать новость под себя), ниже блок для моего комментария, потом оригинальный пост со всеми медиа | 🔵 открыта | (зафиксирована, проработать подробности) |
|
||||
| 2026-09-13 | Контент-стратегия: не перепубликовать чужие новости, а публиковать переписанные от себя (персональный контент, добавление ценности). Связано с «переписать новость под себя» в интерфейсе кандидатов — нужна генерация пересказа через LLM + редактирование перед публикацией | 🔵 открыта | (идея, проработать) |
|
||||
| 2026-09-13 | Контент-стратегия: не перепубликовать чужие новости, а публиковать переписанные от себя (персональный контент, добавление ценности). Связано с «переписать новость под себя» в интерфейсе кандидатов — нужна генерация пересказа через LLM + редактирование перед публикацией | ✅ закрыта | 2026-09-15 (change rewrite-as-author: textarea редактируема + кнопка сохранения; публикация идёт с пересказом от имени @dedinit) |
|
||||
| 2026-09-13 | Извлечение источников новостей из полученных постов (каналы/сайты, откуда пришли новости) — чтобы в следующий раз забирать новости напрямую из источника. ДОПОЛНЕНИЕ: возможно стоит разработать сервис поиска источников в интернете (если источник не указан) и ДООБОГАЩАТЬ карточки кандидатов, но — чтобы не тратить лишние деньги — ТОЛЬКО для одобренных кандидатов. Пайплайн: отбор новостей из списка кандидатов → в «выбранные» → обработка/дообогащение/переписывание при необходимости → публикация | 🔵 открыта | (зафиксирована, проработать) |
|
||||
| 2026-09-13 | OpenSpec change `gotosocial-publisher`: proposal/design/tasks/specs/gotosocial-publisher, validate чисто | ✅ закрыта | 2026-09-13 (архивирован как 2026-09-13-gotosocial-publisher, delta влита в specs/gotosocial-publisher/spec.md) |
|
||||
| 2026-09-13 | Аккаунт-бот **vesti** на GtS (admin account create, confirmed+approved, admin=0) — публиковать НЕ от kpa39l | ✅ закрыта | 2026-09-13 (авто-подтверждение; токен в .env GT_SOCIAL_ACCESS_TOKEN) |
|
||||
@@ -69,5 +69,16 @@
|
||||
| 2026-09-13 | Доки + git + backup по gotosocial-publisher (STATUS/WALKTHROUGH/.env.example; коммиты bf176cc, 6b955aa на gitverse) | ✅ закрыта | 2026-09-13 (backup.sh в фоне — уведомление отдельно) |
|
||||
| 2026-09-13 | Пометить аккаунт vesti как bot (PATCH /api/v1/accounts/update_credentials bot:true или actor_type Service) | 🔵 открыта | (косметика, не критично) |
|
||||
| 2026-09-13 | Фан-аут направлений → каналы (в т.ч. fediverse-каналы по направлениям) | 🔵 открыта | (расширение публикации) |
|
||||
| 2026-09-13 | Отдельная страница управления источниками новостей: отображение / добавление / удаление / редактирование, фильтр по типу источника (Telegram, RSS, почтовая рассылка, прямые новости с сайтов, Twitter и т.п.) | 🔵 открыта | (зафиксирована, проработать) |
|
||||
| 2026-09-13 | Отдельная страница управления источниками новостей: отображение / добавление / удаление / редактирование, фильтр по типу источника (Telegram, RSS, почтовая рассылка, прямые новости с сайтов, Twitter и т.п.) | ✅ закрыта | change sources-admin; /sources + CRUD (add/edit/toggle/delete), yaml — источник истины |
|
||||
| 2026-09-14 | Метрики: добавить инсайты — сколько в день новых постов получено / одобрено / опубликовано, по аналогии с существующими карточками метрик; плюс за неделю и месяц (итого 9 карточек: день/неделя/месяц × новые/одобрено/опубликовано) | 🔵 открыта | (задача на потом, просто зафиксировать) |
|
||||
| 2026-09-15 | **rss-crawler**: OpenSpec change (proposal/design/tasks/spec), код rss_crawler.py, lwn | ✅ закрыта | change rss-crawler |
|
||||
| 2026-09-15 | **rss-crawler**: cron vesti-rss-crawler (каждые 15 мин, no_agent, тихий) | ✅ закрыта | cron fa60bc830843 |
|
||||
| 2026-09-15 | **rss-crawler**: собрать первые RSS-посты (15, lwn) | ✅ закрыта | 2026-09-15 |
|
||||
| 2026-09-15 | **rss-crawler**: веб-скедулинг RSS (кнопка запуска краулера в админке) | 🔵 открыта | (зафиксирована, проработать) |
|
||||
| 2026-09-15 | **crawler-очередь**: отдельная страница /crawlers — статус работы краулеров (alive/dead, last_fetch, ошибки) и размер очереди. Двухфазный сбор: (1) краулеры проходят по источникам и ищут новые кандидаты, (2) найденные кладутся в очередь, (3) воркеры разбирают очередь в несколько потоков | ✅ закрыта | change crawler-queue; /crawlers, worker.py (ThreadPoolExecutor) |
|
||||
| 2026-09-15 | Кнопки правой панели: «Обработать моделью / Переписать / Отклонить» — ОДИН ряд НАД полем комментария | ✅ закрыта | change candidates-buttons-order (коммит 562d787) |
|
||||
| 2026-09-15 | После «🚫 Отклонить» оставаться на странице кандидатов в текущей группировке (не уходить в отклонённые) | ✅ закрыта | change reject-stay-candidates (коммит 562d787) |
|
||||
| 2026-09-15 | Флаг прочитанности: непрочитанные карточки жирные, открытый пост — светло-голубая заливка, дефолтная группировка по дате | ✅ закрыта | change candidates-read-flag (коммит c09dff0) |
|
||||
| 2026-09-15 | «✅ Опубликовать» — НИЖЕ поля комментария рядом с «💾 Сохранить комментарий»; оригинальный пост растянут на всю высоту панели | ✅ закрыта | коммит b542e9b |
|
||||
| 2026-09-15 | **Пайплайн «Кандидаты → Отобранные → Опубликованные»**: статус selected, /selected отдельный список, в кандидатах только «⭐ Отобрать», вся обработка в отобранных, классификация по кнопке | ✅ закрыта | change selected-list (коммит ae8af8d) |
|
||||
| 2026-09-15 | Подготовка своего поста в «Отобранных»: поле «✍️ Мой пост» (rewritten_text всегда видно) рядом с оригиналом — черновик «Переписать» редактируется и публикуется | ✅ закрыта | change selected-list (коммит ae8af8d) |
|
||||
@@ -521,3 +521,80 @@ sudo systemctl restart vesti-web && systemctl is-active vesti-web # active
|
||||
2. Архив `candidates-only-external-new`, `keep-candidates-context` + rich-repost-card + gotosocial-publisher (delta в specs).
|
||||
3. Пометить аккаунт vesti как **bot** (GtS 0.22.1, PATCH update_credentials bot:true / actor_type Service).
|
||||
4. Фан-аут направлений → каналы (в т.ч. fediverse-каналы).
|
||||
|
||||
## Сессия 2026-09-15 — LWN→tech, /crawlers + /sources, «Переписать» от имени автора, легенда бейджей
|
||||
|
||||
### 1. Двухфазный пайплайн (сбор → очередь → параллельная обработка)
|
||||
- `crawler/crawl_sources.py` — одиночный сбор всех источников (RSS+TG) в `posts` (status='new').
|
||||
- `crawler/rss_crawler.py` — RSS-краулер по sources.yaml (feed_url), сид state в `rss_state`.
|
||||
- `crawler/worker.py` — параллельный воркер: claim_post (LEFT JOIN sources → source_slug), 8 потоков, MAX_CONCURRENT_LLM=2 (SQLite-соединение ВНУТРИ work_loop — нельзя шарить между потоками), fan-out по направлениям.
|
||||
- Запуск: `.venv/bin/python -m crawler.worker --workers N --limit N`, `.venv/bin/python -m crawler.crawl_sources`.
|
||||
- `web/app.py` /crawlers — страница управления: очередь (pending), источники, кнопка «Запустить воркер» (POST /crawlers/run → subprocess). Фикс: в render() не передавался request=request → добавлен.
|
||||
|
||||
### 2. Правило источника LWN → tech (детерминированно, без LLM)
|
||||
- `classifier/keywords.py`: SOURCE_RULES = {"lwn": ["tech"]} + source_directions(slug); find_direction(text, source_slug)/find_directions_all(...) — правило источника имеет ПРИОРИТЕТ над словарём.
|
||||
- `classifier/classify.py classify_text(post, source_slug)`: при наличии правила → return сразу (method='source-rule'), LLM не тратится.
|
||||
- `crawler/worker.py`: claim_post достаёт source_slug через JOIN; старый CLI classifier.classify тоже JOIN sources.
|
||||
- Проверено: юнит + in-memory пайплайн (LWN → direction=tech, classified).
|
||||
|
||||
### 3. Страница управления источниками /sources (уже была готова)
|
||||
- `web/templates/sources.html` + CRUD в `web/app.py`: ➕ добавить (slug, name, url, crawler, feed_url, direction, priority, enabled), inline-переименование name, ⏸/▶ пауза (enabled), inline-select приоритета P0–P3, 🗑 удаление (каскад: posts.source_id=NULL, runs, rss_state — посты остаются). Валидация slug [a-z0-9_-].
|
||||
- Истина — sources.yaml, каждое изменение пишется в yaml+БД (upsert_source_yaml + sync_yaml_to_db_and_back) — краулеры НЕ затирают правки при sync.
|
||||
- В навбаре (base.html) есть пункт «Источники».
|
||||
|
||||
### 4. Change rewrite-as-author — «✍️ Переписать» публикует ОТ ИМЕНИ автора, поле редактируемо (skip_specs)
|
||||
- Баг 1: textarea пересказа была readonly (подпись обещала «редактируйте и копируйте»). → убрал readonly, добавил «💾 Сохранить пересказ» (POST /posts/{id}/rewrite-save).
|
||||
- Баг 2: make_card публиковал исходный text, игнорируя rewritten_text. → publisher/card.py: при непустом rewritten_text тело=пересказ, подпись «✍️ Дед в АйТи (@dedinit) · Источник: <url>» вместо «🔗 Оригинал» (от имени канала, с атрибуцией). Без пересказа — как раньше.
|
||||
- Проверено read-only на посте id=4 (LWN, есть rewritten_text): карточка начинается с пересказа, есть «Дед в АйТи», нет «🔗 Оригинал».
|
||||
|
||||
### 5. Легенда бейджей + тултипы кнопок + комментарий уходит с «Опубликовать»
|
||||
- candidates.html: под бейджами — details «Бейджи поста — что значит каждый цвет»: направление (серый), critical/high (зелёный/синий — важность), interest N (жёлтый, 1–5), ⭐ СВОЙ, ↩︎ форвард.
|
||||
- Тултипы (title) на кнопках: ✅ Опубликовать, 🤖 Обработать моделью (qwen3:8b), ✍️ Переписать, 💾 Сохранить комментарий, 🚫 Отклонить.
|
||||
- Комментарий внутри approve-формы: textarea + «✅ Опубликовать» (submit) и «💾 Сохранить комментарий» (formaction → /comment, без JS). Потерять комментарий при публикации нельзя: он в той же форме. Reclassify/rewrite/reject — отдельные формы.
|
||||
- Рестарт: sudo systemctl restart vesti-web (uvicorn БЕЗ --reload, Jinja2 кеширует шаблоны — после правок шаблонов рестарт ОБЯЗАТЕЛЕН).
|
||||
|
||||
### Коммит в git (НЕ закоммичено — на проверку в след. сессии)
|
||||
- Изменено: classifier/*, crawler/{worker,crawl_sources,rss_crawler}.py (новые), publisher/card.py, sources/{sources.py,sources.yaml}, web/app.py, web/templates/{candidates,crawlers,sources,base}.html, config.py, requirements.txt, AGENT.MD, STATUS.md, TODO.md, .env.example.
|
||||
- Новые openspec-changes: crawler-queue, rss-crawler, sources-admin (архив), rewrite-as-author; спека specs/sources-admin/.
|
||||
- Пуш НЕ делался — закоммитить и запушить (gitverse истина, gitea зеркало).
|
||||
|
||||
## 2026-09-15 — Сессия: почтовый клиент для кандидатов + пайплайн «Отобранные»
|
||||
|
||||
Ключевой рефакторинг интерфейса кандидатов: «как в почтовом клиенте», затем введение стадии «Отобранные».
|
||||
|
||||
### 1. Кнопки ряда + фикс «Опубликовать» (коммиты 562d787, b542e9b)
|
||||
- Ряд кнопок [🤖 Обработать моделью][✍️ Переписать][🚫 Отклонить] — ОДИН flex-ряд НАД approve-формой (отдельные <form>, чтобы вёрстка не разъезжалась).
|
||||
- После 🚫 Отклонить (single/bulk/reject-old) — редирект на _cand_back(...) БЕЗ status="rejected" → остаёмся на кандидатах, в той же группировке (change reject-stay-candidates).
|
||||
- ✅ Опубликовать перенесён НИЖЕ поля комментария рядом с 💾 Сохранить комментарий (пользователь: «должна быть ниже поля комментария, рядом с кнопкой Сохранить комментарий»).
|
||||
- Правая панель: height:82vh (flex-колонка), «Оригинальный пост» — flex-grow+overflow-auto → занимает всё место до низа (не было пустоты).
|
||||
|
||||
### 2. Флаг прочитанности (коммит c09dff0, change candidates-read-flag)
|
||||
- Колонка posts.is_read (миграция ИДЕМПОТЕНТНО в _db() web/app.py — при каждом подключении; schema.sql тоже обновлён, но db/ в .gitignore, в git не идёт).
|
||||
- Открытие поста (GET /candidates?selected=N) → UPDATE is_read=1.
|
||||
- Непрочитанные карточки — fw-bold, выбранный пост — класс active-row (заливка #dcecfc, base.html).
|
||||
- Дефолт group_by="date" во всех трёх эндпоинтах (GET /candidates, POST select, POST bulk).
|
||||
- Проверка: /tmp/check_read*.py (TestClient), /tmp/check_live_read.py (живой HTTP 127.0.0.1:8400; нужен логин через форму /login с ADMIN_PASSWORD из .env).
|
||||
|
||||
### 3. Пайплайн «Кандидаты → Отобранные → Опубликованные» (коммит ae8af8d, change selected-list)
|
||||
- Новый статус posts.status='selected' (БД-миграции не нужно — status TEXT без CHECK).
|
||||
- Кандидаты (new): ТОЛЬКО отбор. Карточка: «⭐ Отобрать» (POST /posts/{id}/select → status new→selected). Bulk: единственная кнопка «⭐ Отобрать» (action=select).
|
||||
- /selected — отдельный двухпанельный экран (web/templates/selected.html, GET /selected в app.py): фильтруется по status='selected'. ВСЯ обработка здесь:
|
||||
- [🤖 Обработать моделью] POST /posts/{id}/reclassify (только по кнопке — токены на кандидатов НЕ тратятся; bulk process),
|
||||
- [✍️ Переписать] POST /posts/{id}/rewrite → кладёт черновик в rewritten_text; bulk rewrite (добавлен),
|
||||
- [🚫 Отклонить] POST /posts/{id}/reject (→ status rejected, остаёмся в selected — список пустеет, это норма),
|
||||
- комментарий + [✅ Опубликовать] + [💾 Сохранить комментарий].
|
||||
- Поле «✍️ Мой пост» (textarea rewritten_text) — ВСЕГДА видимо (в отличие от старого `{% if rewritten_text %}`), рядом (col-md-6) с «Оригинальный пост» (col-md-6). Публикация: publisher/card.py берёт body = rewritten_text или text — т.е. публикуется СВОЙ текст, а не репост.
|
||||
- _cand_back(group_by, direction, own, q, src='candidates', **extra) — src выбирает список для редиректа (candidates|selected). Во все формы добавлен скрытый <input name="src" value="selected|candidates">, во все обработчики — Form("src", default "candidates").
|
||||
- candidates_bulk: параметр src, action select/rewrite добавлены, редиректы → /{src}.
|
||||
- base.html: навбар «⭐ Отобранные» (/selected) между «Кандидаты» и «Опубликовано».
|
||||
|
||||
### 4. Проверка (важно для воспроизводимости)
|
||||
- Тесты: /tmp/test_selected.py, /tmp/test_select_flow.py, /tmp/test_rewrite.py, /tmp/check_final.py — через TestClient(fastapi): логин POST /login с ADMIN_PASSWORD (.env) → cookie; select single/bulk → /selected (200), кнопки на месте; rewrite — реальный вызов Ollama (qwen), rewritten_text записан.
|
||||
- Живой HTTP: /candidates без авторизации → 303 (в проде env VESTI_WEB_SESSION задан юнитом; в TestClient env пуст → _session_ok возвращает True при отсутствии cookie — тестовая дыра, в проде не воспроизводима).
|
||||
- Откат тестовых мутаций: 85/109 → status='new', rewritten_text=NULL.
|
||||
- Рестарт: sudo systemctl daemon-reload && sudo -S -p '' systemctl restart vesti-web (юнит менялся ранее; Jinja2 кеширует шаблоны — рестарт ОБЯЗАТЕЛЕН).
|
||||
|
||||
### 5. ВНИМАНИЕ — незакоммиченные наработки прошлой сессии (НЕ МОИ)
|
||||
В git status на момент ae8af8d остаются НЕЗАКОММИЧЕННЫМИ/НЕЗАПУШЕННЫМИ изменения прошлых сессий (запись «Коммит в git (НЕ закоммичено…)» выше):
|
||||
- crawler/{crawl_sources,rss_crawler,worker}.py (??), openspec/changes/{crawler-queue,rss-crawler,rewrite-as-author}/ (??), openspec/changes/archive/2026-09-15-sources-admin/, openspec/specs/sources-admin/, web/templates/{crawlers,sources}.html (??), classifier/classify.py, classifier/keywords.py, publisher/card.py, sources/{sources.py,sources.yaml}, config.py, requirements.txt, AGENT.MD, .env.example, WALKTHROUGH.md, TODO.md (M).
|
||||
- СЛЕДУЮЩЕЙ СЕССИИ: проверить, закоммитить и запушить на gitverse (git add -A, commit, push), НЕ трогая db/ (в .gitignore).
|
||||
|
||||
Reference in New Issue
Block a user