← все проекты

Пульс Цен: новостной бот

Телеграм-бот команды ПЦ: по кнопке собирает новостной пост (дайджест или разговорный) с обложкой из накопленных RSS и гос-сайтов. DeepSeek через OpenRouter, картинка Kie gpt-image-2, ~3 ₽ за пост.

repo: E:\Проекты для Гитхаба\pulse-news-bot (локально, без git)server: cfru /opt/pulse-news-bot, pm2 pulse-news-bot + pulse-news-collector, SQLite data/news.dbdocs: docs/ARCHITECTURE.md, docs/ACCEPTANCE.mdпамять: pulse-news-bot-project
готовS1 · С1 · Бот с нуля: сбор, отбор, пост, обложка4/4

Цель: Кнопка «Сделать пост» отдаёт пост в двух форматах с брендированной обложкой

Сборщик RSS + гос-сайты, SQLite, дедуп, ретеншн 30 дней
✓ pm2 pulse-news-collector, 9 фидов + Минстрой + Корпорация МСП, ~11 600 записей в неделю
feature
Отбор номерами и текст поста в двух форматах (DeepSeek через OpenRouter)
✓ select.py возвращает номера, write.py пишет по образцам заказчика, ~0,45 ₽ за пост
feature
Обложка gpt-image-2 через Kie + логотип кодом
✓ brand.py кладёт настоящий логотип с pulscen.ru, 2,5 ₽ за картинку
feature
Бот aiogram: кнопки, лимит 50 генераций в сутки, перерисовка картинки
✓ pm2 pulse-news-bot, открыт для всех, через прокси aitodo
feature
готовS2 · С2 · Два выпуска: стройка и металлопрокат14/14

Цель: Команда выбирает выпуск до формата; стройка и металл не смешиваются, общий выпуск сбалансирован

↑ Выпуски «Стройка» / «Металлопрокат» / «Общий» сквозь весь конвейер
Запрос команды ПЦ 22.09: общий дайджест уходил в металл. Причина в коде: в CORE_KEYWORDS 16 строительных слов без застройщика/ипотеки/новостроек, плюс подстрочный поиск («сталь» в «остальные»). Сделано: src/topics.py, collector/keywords.py (матч по началу слова), тема в скоринге, отборе, тексте, обложке, кнопка «Про что выпуск?», /stats по темам, стоп-лист военных сводок. 16 экзаменов tests/test_topics.py зелёные локально и на стейдже cfru.
✓ Выкачено 22.09, 13/13 критериев с пруфами
feature
Бот спрашивает «Про что выпуск?» (Стройка / Металлопрокат / Общий) до формата
✓ tests: BotFlow.test_topic_keyboard_then_format
acceptance
Выпуск «Стройка»: в отбор идут только новости со строительным признаком
✓ tests: TopicWindow.test_stroy_window_has_no_pure_metal; живая база 22.09: 201 новость
acceptance
Выпуск «Металлопрокат»: только новости с признаком металла
✓ tests: TopicWindow.test_metal_window_has_no_pure_stroy; живая база 22.09: 50 новостей
acceptance
Новость про обе темы попадает в оба выпуска
✓ tests: TopicWindow.test_both_topics_news_in_both_windows
acceptance
Первая строка поста называет выпуск (вручную по тексту)
python -m scripts.try_post digest stroy --no-image, ~0,45 ₽; ждёт «трачу?»
✓ try_post digest stroy/metal --no-image 22.09: «🏗 …для строительной отрасли» 9 блоков все стройка; «⚙️ …для рынка металлопроката» 8 блоков все металл, ~0,9 ₽
acceptance
Промпт обложки несёт фактуру выпуска
✓ tests: PromptsCarryTopic.test_image_prompt_carries_topic_scenes
acceptance
Скоринг по началу слова: остальные≠сталь, косметика≠смета, перестройка≠стройка, экран≠кран
✓ tests: KeywordScoring
acceptance
Военные сводки не попадают ни в один выпуск
✓ tests: WarExcluded
acceptance
Мало новостей по теме: бот честно пишет сколько есть, модель не вызывается
✓ tests: NotEnoughNewsHonest
acceptance
/stats показывает запас по каждой теме
✓ tests: TopicWindow.test_stats_show_topic_stock
acceptance
Общий выпуск работает как раньше, старая кнопка go:digest не ломает бота
✓ tests: test_general_window_is_unfiltered, test_parse_go_with_and_without_topic
acceptance
Цена не изменилась: один отбор, один текст, одна картинка
✓ tests: PriceUnchanged
acceptance
Выкачено на cfru: pm2 restart pulse-news-bot + collector, бот отвечает
ждёт «да» на выкат
✓ 22.09 03:53 UTC: scp + pm2 restart, бэкап /opt/backups/pulse-news-bot-src-20260922-0352.tgz, 16 экзаменов OK на проде, @KZ_pulscen_bot polling
acceptance
готовS3 · Проверки по сроку1/1

Цель: Отложенные проверки: сработало ли

Ушёл ли перекос в металл: спросить команду ПЦ и посмотреть, какие выпуски жмут
Спросить у девушки из ПЦ, устраивают ли выпуски «Стройка» и «Металлопрокат». Замер, какие выпуски жали: ssh cfru "grep -o 'выпуск: [А-Яа-я]*' /var/log/pulse-news-bot/bot.out.log | sort | uniq -c". Падения: ssh cfru "grep -c 'Не получилось' /var/log/pulse-news-bot/bot.out.log". Если стройки мало в базе: cd /opt/pulse-news-bot-stage && venv/bin/python -m scripts.try_select stroy.
✓ Замер сделан 02.10 по /var/log/pulse-news-bot: bot.out.log пуст с 31.07, всё пишется в bot.err*.log, ротация держит только 26.09–02.10. За эти 7 дней один запуск: 28.09 04:47 «выпуск Стройка» (модель отобрала 25 из 186 новостей), «Металлопрокат» не жали ни разу; «Не получилось» 0, падений нет. Более старой истории нажатий нет (логи ушли), в news.db только таблица news (48 361 новость), выпуски не журналируются. По логам перекоса в металл за неделю нет, но и нажатий почти нет. Вопрос команде ПЦ (устраивают ли «Стройка» и «Металлопрокат») — за владельцем, не задавал.
⛔ Ночная смена 01-02.10.2026. В /var/log/pulse-news-bot/bot.out.log строк «выпуск: …» не нашлось вовсе, «Не получилось» — 0: по логу перекос не померить, бот либо пишет в другой файл, либо выпуски не жмут. Спросить девушку из ПЦ про «Стройку» и «Металлопрокат» — это тебе.
check

Ворклог (места остановки)

22.09.2026, 03:54:53 · С2 · claude

С2 закрыт и выкачен 22.09: три выпуска, матч по началу слова, общий пул с обоими словарями, стоп-лист военных сводок, /stats по темам. Тест-прогоны stroy/metal чистые (~0,9 ₽). Бэкап src в /opt/backups.

→ Проверка 29.09: спросить команду, ушёл ли перекос; замер по логам. Кандидат на С3: дедуп заголовков по 50% пересечения схлопывает короткие разные заголовки.

22.09.2026, 03:48:33 · С2 · claude

Заведён проект в Atlas. Спринт 2: три выпуска сквозь конвейер, матч по началу слова, общий пул пополнен словарями обеих тем, стоп-лист военных сводок, /stats по темам. 16 экзаменов зелёные локально и на стейдже /opt/pulse-news-bot-stage.

→ Ждёт владельца: «трачу?» на 2 тестовых прогона текста (~1 ₽) и «да» на выкат (scp в /opt/pulse-news-bot + pm2 restart обоих процессов). После выката: проверка по сроку через неделю, спросить команду ПЦ, ушёл ли перекос.