РазборИИРабота

Новости CS2 в Telegram: бот, который собирает ленту

Без навыков программирования, зато с нейросетью, кучей проверок и постепенным осознанием, что «бот работает» и «бот делает то, что мне нужно» — далеко не одно и то же

24 минОбновлено
Пластилиновый осьминог с микрофоном пожимает руку роботу-репортеру в мире Counter-Strike

Я довольно давно слежу за профессиональной сценой Counter-Strike: интересуюсь турнирами, составами команд, трансферами, результатами матчей и всем остальным, что происходит вокруг соревновательного CS. И у меня, как, наверное, у любого человека, который увлекается какой-то темой, со временем накопился приличный список ресурсов, где можно почитать новости. Есть англоязычные сайты, есть русскоязычные, есть специализированные издания, а есть страницы самих команд. Проблема в том, что читать все это по отдельности довольно неудобно.

Допустим, выходит новость о переходе игрока в другую команду. Один сайт написал об этом первым, второй пересказал ту же историю своими словами, третий перевел ее на русский, четвертый добавил пару предложений и выдал за отдельную публикацию. В итоге я либо должен регулярно обходить все эти площадки, либо подписываться на множество каналов и потом разгребать поток сообщений, половина которых сообщает мне то, что я уже прочитал. И ради чего? Ради одного события, о котором достаточно узнать один раз.

В какой-то момент я подумал: а почему бы не собрать все это в одном месте? Желательно в Телеграме, который у меня и так открыт практически круглосуточно. Чтобы не пришлось ничего искать, обновлять и переключать вкладки: произошло что-то интересное — мой новостник сам нашел публикацию и прислал мне ее в чат. Но с одним принципиальным условием: если пять изданий рассказали об одном событии, я хочу увидеть одно сообщение, а не пять. Вроде бы простая задача для пользователя, но, как выяснилось позже, далеко не такая простая для программы.

С программированием у меня отношения примерно такие же, как с устройством космического корабля: в общих чертах понимаю, что происходит, но собирать своими руками не возьмусь. Зато можно попробовать поручить написание кода Codex — ИИ-помощнику, с которым общаешься на обычном языке. Так и начался мой маленький эксперимент. Я не собирался становиться разработчиком и не планировал писать идеальное техническое задание. Мне хотелось получить конкретную полезную штуку, пользоваться ею каждый день и по ходу разбираться, что в ней нужно улучшить.

Идея и источники

Начал я с формулировки самой идеи. Без архитектуры, схем баз данных и прочих слов, которыми разработчики обычно пугают гуманитариев. Просто объяснил нейросети, что хочу собирать новости о профессиональном Counter-Strike и получать их в телеге, но без повторов. Ни слова о том, как именно все это должно быть устроено изнутри.

Здесь важно пояснить, что я подразумевал под повтором. Если два сайта опубликовали одну и ту же ссылку, распознать совпадение несложно. А вот если один пишет «Команда объявила новый состав», а второй — «Такой-то игрок присоединился к команде», и оба текста посвящены одному и тому же трансферу, то формально это разные статьи. Для меня же это одна новость. Собственно, ради решения именно этой проблемы все и затевалось.

ЗАПРОС ИЗ ПЕРЕПИСКИ · 23 МАЯ · ИДЕЯ

хочу сделать бота в телеграм, который будет парсить новости по контр-страйк (профессиональй сцене соревновательной) и присылать мне их в телегу. Важно не присылать одну и ту же новость из разных источников - нужно присылать из первого, а дубли не присылать - то есть алгоритм должен понимать, что дубль, а что нет

Первую версию нейронка собрала довольно быстро. Программа научилась обращаться к сайту, находить публикации, запоминать то, что уже видела, и пересылать их мне в Telegram. Правда, поначалу все это работало лишь с одним ресурсом. С точки зрения разработки такой подход совершенно разумный: сначала убедиться, что вся цепочка в принципе работает, и только потом усложнять конструкцию. Но когда видишь первые результаты, тут же начинает казаться, что можно еще немного улучшить, а потом еще немного — и вот ты уже придумал следующую десятку задач.

Меня довольно быстро перестал устраивать вариант с одним изданием. Ведь если вся задумка заключалась в том, чтобы не ходить по разным сайтам, какой смысл ограничиваться одним из них? Я попросил подключить другие медиа, причем не только английские, но и русскоязычные, поскольку материалы на разных языках нередко пересказывают одно и то же, а мне как раз и хотелось собрать их в общую ленту.

Потом появилась следующая мысль. А почему, собственно, ориентироваться исключительно на журналистов? Команды сами публикуют анонсы, изменения составов и прочие новости на своих сайтах и в соцсетях. Иногда первоисточник вообще интереснее перепечаток. Поэтому я предложил добавить официальные площадки команд из топа HLTV — ориентировочно первых пятидесяти.

В результате в настройках оказалось 15 медиа и отдельный список из 54 ресурсов команд. Выглядело уже довольно солидно, особенно если помнить, что еще недавно никакого агрегатора не было. Но тут обнаружилась первая важная для меня разница между «добавили в проект» и «получили работающий результат». То, что адрес внесен в конфигурацию, еще не значит, что сайт разрешает забирать с него публикации, что данные правильно считываются и что сообщения вообще будут приходить. На тот момент у меня был многообещающий перечень площадок и код для их обработки, но никак не тщательно проверенная новостная редакция.

ЗАПРОС ИЗ ПЕРЕПИСКИ · 23 МАЯ · РАСШИРЕНИЕ ИСТОЧНИКОВ

будет кайфово еще добавить русскоязычные источники, а также сами команды и их сайты и соцсети как источники, например, топ-50 команд рейтинга хлтв - если сможем тащить новости от них по общим правилам

Если будете повторять такой эксперимент, я бы советовал с самого начала отдельно проговорить логику повторов. Не просто написать «не присылай дубли», а объяснить на примерах, что именно считать одним событием. Ссылка, заголовок и смысл материала — три разные вещи. Причем чем больше изданий вы подключаете, тем заметнее становится разница между ними.

Первый запуск

Следующим этапом нужно было все это запустить и посмотреть, как новостник поведет себя не в отчетах кодекса, а в моей собственной телеге. И тут внезапно выяснилось, что даже создание простого бота подразумевает определенное количество действий, которые для человека без опыта программирования совсем не очевидны.

Я сразу попросил объяснять мне все пошагово: говоришь, что сделать, я делаю, показываю результат, и только после этого переходим дальше. Такой формат мне был нужен не из любви к подробным инструкциям. Когда человек, разбирающийся в коде, выдает десять команд подряд, он обычно пропускает половину промежуточных вопросов как само собой разумеющиеся. А у меня эти вопросы, наоборот, и составляли основную часть процесса.

С BotFather, через которого создают ботов для Telegram, все прошло более-менее гладко. А потом ИИшка предложила открыть PowerShell. На этом месте я буквально написал: «стоп, я чайник, какой еще повершелл». Пришлось перестраивать объяснения под мой уровень понимания. Где-то помощник делал настройку сам, где-то я присылал скриншоты, чтобы он видел ту же картину, что и я. Постепенно мы прошли эти первые технические препятствия.

ЗАПРОС ИЗ ПЕРЕПИСКИ · 23 МАЯ · НАСТРОЙКА

окей давай поднимем бота дл тестлокально, дай мне пошаговую инструкцию что делать. шаг - ждешь от меня результат - и только потом следующий шаг

И вот в телеге появляется тестовое сообщение. Ничего особенного: короткая фраза о том, что отправка работает, и ссылка для примера. Но именно в этот момент вся затея перестала быть абстрактным разговором с нейросетью. Программа действительно написала мне в чат, и я, конечно, обрадовался.

Правда, довольно быстро пришлось напомнить себе, что радоваться пока рано. Отправить пробное сообщение и собрать нормальную новостную ленту — разные задачи. Я еще не знал, насколько актуальными будут публикации, умеет ли парсер правильно доставать их содержимое и что он сделает с двумя статьями об одном событии. То есть канал связи заработал. Сам продукт еще предстояло проверить.

Первое тестовое сообщение от бота в Telegram
Первое тестовое сообщение от бота в Telegram

Чтобы в первые же минуты новостник не вывалил на меня весь архив подключенных сайтов, нейросеть сначала отметила старые публикации как уже известные. Логика понятная, но возник другой вопрос: как вообще оценивать ленту, если мне пока ничего не пришло? Ждать свежего материала неизвестно сколько не хотелось. Поэтому я попросил вручную отправить десять последних заметок — просто чтобы увидеть, как все это выглядит глазами обычного получателя.

Вот здесь начинается самое интересное в подобных проектах. Пока обсуждаешь функции словами, все кажется очевидным. «Бот присылает новость» — ну отлично. А когда открываешь реальное сообщение, выясняется, что одного заголовка мало. Мне хотелось сразу понимать, о чем статья, не переходя каждый раз по ссылке на сайт. Значит, нужен хотя бы небольшой фрагмент текста, плюс ссылка на первоисточник для тех случаев, когда захочется прочитать материал целиком. Объяснил это в чате — ИИ добавил и превью, и ссылку.

В итоге наш агрегатор стал проверять подключенные площадки каждые пятнадцать минут. Это был уже вполне осязаемый результат: публикации начали приходить в привычный мессенджер, и стало возможно оценивать не абстрактную работоспособность скрипта, а реальное удобство чтения.

ЗАПРОС ИЗ ПЕРЕПИСКИ · 23 МАЯ · ПРОВЕРКА ЛЕНТЫ

запускаем, но мы можем заодно прислать пускай 10 последних новостей, чтобы я хоть посомтрел как это выглядит

С этого момента я усвоил простой прием: просить сначала одно контрольное сообщение, затем несколько настоящих публикаций и только после этого включать регулярную работу. Ответ нейронки «готово, все настроено» не говорит о качестве результата ровным счетом ничего. Другое дело — десять сообщений в собственной телеге. Там все достоинства и недостатки становятся видны за пару минут.

Сводка за день

Когда основная лента начала подавать признаки жизни, мне захотелось добавить еще одну удобную штуку — ежедневную сводку. Представьте, что за день произошло полтора десятка событий: несколько матчей, пара трансферов, очередные анонсы турниров. В течение дня публикации еще можно просматривать по мере поступления, но иногда хочется вечером открыть одно сообщение, за минуту вспомнить самое важное и закрыть Телеграм. Причем на русском языке, независимо от того, на каком языке вышли оригинальные материалы.

Я спросил у кодекса, можно ли для этой задачи прикрутить Gemini. Идея выглядела вполне логичной: наш парсер собирает материалы, языковая модель читает их, вычленяет главное и составляет связный итог дня. Звучит даже красивее, чем просто лента. Но первый же результат заставил усомниться в том, что мы получили именно то, что обсуждали.

Дайджест прилетел в TG — и оборвался на полуслове. Причина нашлась довольно прозаическая: для сообщения действовало ограничение длины, рассчитанное раньше на обычную новость, а вовсе не на полноценный обзор. Ограничение поправили. Следующая попытка уже не обрывалась так же, зато обнаружилась новая странность: весь итог дня состоял из двух заметок, и обе были про BLAST.

Я смотрю на это и думаю: неужели за целый день во всем профессиональном Counter-Strike произошло ровно два события, и оба связаны с одним организатором турниров? Конечно, хотелось понять, действительно ли программа нашла всего две подходящие публикации или что-то пошло не так при их отборе. Так и написал в чат с ИИ: «всего 2 новости и обе про бласт? так и должно быть?».

Одна из первых сводок обрывалась на середине
Одна из первых сводок обрывалась на середине
После первой правки сводка все еще свелась к двум новостям про BLAST
После первой правки сводка все еще свелась к двум новостям про BLAST

Дальше началась серия исправлений, которые очень быстро отучают воспринимать фразу «сейчас все поправлю» как гарантию результата. Мы меняли инструкции для Gemini, разбирались с тем, какие материалы попадают в дайджест, увеличивали разрешенную длину ответа. В одном из тестов кодекс заглянул в настоящий ответ API и увидел, что текст обрывался из-за лимита генерации самой модели. То есть проблему нельзя было решить одной только настройкой Телеграма — ответ не успевал целиком сформироваться еще на стороне ИИ.

После очередной правки вечерний обзор наконец перестал обрываться. Казалось бы, победа. Но тут выяснилось, что в подборку попадают старые события. Для исторического архива это, может быть, и пригодилось бы, но я просил итоги за день, а не экскурсию по недавнему прошлому профессиональной сцены. Пришлось отдельно требовать привязки материалов к сегодняшней дате. В одной из проверок дайджест уже формировался на основе пятнадцати публикаций, а не двух однотипных заметок.

Самое забавное, что все эти неприятности по отдельности не выглядели какой-то катастрофой. Сообщение доставляется? Доставляется. Текст генерируется? Генерируется. На русском языке? На русском. Формально каждый компонент выполняет свою работу. Но если обзор обрывается, игнорирует большую часть событий или пересказывает старые публикации, зачем он мне вообще нужен? Хорошая иллюстрация того, как набор технически работающих функций может складываться в совершенно бесполезный для человека результат.

Поэтому дальше я проверял эти итоги довольно приземленно. Смотрел, закончился ли текст, сколько в нем действительно разных тем и относятся ли они к нужному дню. Не «сколько тестов прошло успешно» и не «что рапортует нейросеть», а могу ли я сам прочитать это сообщение и получить ту самую картину дня, ради которой просил функцию. Звучит очевидно, но при работе с ИИ очень легко увлечься отчетами о проделанных исправлениях и забыть посмотреть на сам продукт.

Меню и фильтры

Следующая идея выросла из самой ленты. Когда материалов становится много, возникает противоположная проблема: ты больше не хочешь получать их все подряд. Мне, например, может быть интересно следить за конкретными командами и игроками, читать о трансферах и важных матчах, но вовсе не обязательно видеть каждую мелкую заметку, которую смог найти парсер. И если я делаю этот инструмент для себя, почему бы не настроить его под собственные интересы?

Так появились фильтры и меню. Хотелось прямо в телеге выбирать нужные категории, переключаться в режим «только важное», добавлять команды и игроков в список наблюдения, а при необходимости временно заглушать поток уведомлений. Причем без походов в конфигурационные файлы и без очередного диалога с ИИшкой. Открыл настройки, нажал пару кнопок, получил нужную ленту. В идеале все должно быть именно так.

Первый вариант выглядел вполне пристойно. Кнопки на месте, разделы есть, настройки вроде бы переключаются. Но довольно быстро я заметил, что «все кликается, но кажется не работает». Прекрасная, кстати, формулировка для интерфейса: внешне реагирует на действия, но доверия не вызывает. После правок стало еще веселее — появилось два разных меню, и они показывали разные выбранные режимы. В одном у меня были отмечены все материалы, в другом — только важные. Какой из вариантов действовал на самом деле, оставалось загадкой.

Два меню показывали разные настройки ленты
Два меню показывали разные настройки ленты

Для меня это была уже не косметическая придирка. Допустим, я отключил все лишнее и оставил только важные события. Если панель настроек показывает одно состояние, а программа на самом деле использует другое, я не могу понять, почему мне продолжают приходить ненужные сообщения. Получается, сама функция фильтрации вроде бы существует, но контролировать ее невозможно.

К тому же отдельные кнопки жили собственной жизнью. Нажимаешь Mute, чтобы временно выключить уведомления, а бот отвечает, что не понимает команду. Просишь сделать дайджест — и на несколько секунд перестают отвечать обычные команды. Тут я уже приносил в чат не общее «у тебя все сломалось», а конкретные случаи: в одном меню выбрано одно, во втором другое; эта кнопка не распознается; после этой команды программа подвисает.

В итоге нейросеть переделала хранение и отображение настроек: панель стала показывать реально сохраненное состояние, несколько фильтров можно было выбирать одновременно, а формирование вечернего обзора вынесли из обычной обработки команд, чтобы тяжелая операция не тормозила все остальное. Заодно я попросил сделать клавиатуру компактнее и убрать второстепенные действия во вложенные разделы. Мне не нужен был пульт управления атомной станцией — я всего лишь хотел читать новости о Counter-Strike.

Именно на этом этапе я особенно хорошо понял, что интерфейс — это не набор красивых кнопочек. Он должен сообщать пользователю, что именно сейчас происходит. Если переключатель не влияет на результат или экран настроек врет о выбранном режиме, от всей красоты толку немного.

Кнопка Mute сначала не распознавалась как команда
Кнопка Mute сначала не распознавалась как команда

Поэтому проверять такие вещи лучше самым скучным способом: нажать кнопку, посмотреть, изменилось ли состояние, дождаться реальных сообщений и убедиться, что они соответствуют выбранному режиму. Без этой последней проверки можно бесконечно улучшать внешний вид клавиатуры и даже не замечать, что ее основная функция так и не заработала.

Переезд на сервер

До этого момента вся конструкция жила у меня на компьютере. Для первых тестов такой вариант подходил, но пользоваться новостным агрегатором, который отключается вместе с ноутбуком или домашним ПК, — удовольствие сомнительное. Особенно если его основная задача состоит в том, чтобы самостоятельно следить за событиями и присылать их, когда что-нибудь случится. Не стану же я держать компьютер включенным круглосуточно исключительно ради этой затеи.

Поэтому следующим логичным шагом стал переезд на VPS — удаленный сервер, который продолжает работать независимо от моего компьютера. У меня уже был VPS на Beget, где запускались другие боты, так что совсем новую инфраструктуру придумывать не требовалось.

Дальше нейронка снова провела меня через последовательность действий: подобрать ресурсы, перенести файлы, запустить процессы и проверить, что они не завершаются сразу после старта. Здесь у программы уже было два отдельных процесса: один занимался сбором материалов, другой отвечал на команды в Телеграме. Я проверял и то, что происходит на VPS, и то, что вижу непосредственно в чате. В какой-то момент можно было закрыть свой компьютер и понять, что новостник при этом никуда не исчезнет. Вот это уже было похоже на нормальный сервис, а не на эксперимент, который работает, пока я за ним присматриваю.

Но разумеется, переезд не обошелся без сюрпризов. Функция ежедневного обзора, которую мы с таким трудом привели в чувство локально, на VPS отказалась работать. Первое предположение было довольно стандартным: не хватает лимита API. Можно было бы начать бесконечно крутить ограничения или менять модель, но проверка настоящего ответа Gemini показала совсем другое — сервис не принимал запросы из региона, где находился сервер.

То есть дома запрос проходил, а на удаленной машине — нет. Код при этом мог оставаться совершенно одинаковым. Мы попробовали другие модели Gemini, но проблема была не в выборе конкретной версии, поэтому успеха это не принесло.

Вдобавок вылезла еще одна неприятная вещь: одно из сообщений об ошибке показывало в ссылке секретный API-ключ. Вряд ли кому-то понравится обнаружить, что инструмент, который должен экономить ему время, по дороге еще и демонстрирует служебные данные. Эту часть пришлось отдельно исправлять. Хорошее напоминание: когда ИИ собирает программу, стоит проверять не только счастливый сценарий, но и то, что происходит, когда она ломается.

Поскольку Gemini с этого VPS работать не хотел, мы попробовали другой путь — OpenRouter, сервис доступа к различным языковым моделям. И здесь все тоже оказалось не совсем гладко. Некоторые выбранные бесплатные варианты возвращали ошибки. В итоге ИИ подключил автоматический выбор модели, и в одном из тестов новый провайдер все-таки составил сводку на основе тех же пятнадцати публикаций.

На тот момент это был важный результат: я увидел на удаленной машине не обещание, что альтернативный сервис «должен заработать», а настоящий сформированный дайджест. Позже я еще попросил подготовить переход на собственный OpenAI API. Однако здесь важно не смешивать планы и сделанное: изменения внесли в локальный код, а вот подтверждения, что именно эта версия после этого успешно работала на VPS, у меня нет. Поэтому записывать ее в перечень побед было бы неправильно. На практике в таких проектах разница между «поправили у меня на компьютере» и «все работает на сервере» иногда оказывается решающей.

Дубли и лишний текст

Первые несколько часов с новостником могут создать обманчивое впечатление, что все замечательно. Материалы приходят, кнопки нажимаются, красивый маленький сервис работает. Но для проверки некоторых функций нужны не минуты, а хотя бы несколько дней обычного использования. И вот как раз через пару дней я вернулся к одной из самых первых своих просьб — не присылать одинаковые новости.

Оказалось, что с этой задачей наш агрегатор справляется далеко не идеально. Например, один и тот же сюжет о турнире IEM Beijing приходил отдельными сообщениями из Dust2 и TalkEsport. Тексты были на разных языках, заголовки отличались, но суть события оставалась той же. Для программы это две публикации, для меня — повтор, от которого я вообще-то и хотел избавиться. Забавно: с этой проблемы началась вся история, а спустя несколько этапов разработки мы снова пришли к ней.

Параллельно обнаружился еще один дефект, на этот раз довольно уродливый с точки зрения читателя. Иногда парсер подтягивал со страницы не только статью, но и все, что расположено вокруг нее: ссылки на соседние публикации, куски меню, рекламные блоки. Представьте, что читаете материал о матче, а посреди текста внезапно появляются заголовки других статей и какие-то обрывки сайта. Получалась не новость, а информационный винегрет, в котором приходилось самому отделять полезное от мусора. Я ведь затеял все это ровно затем, чтобы избавить себя от лишних действий, а не заниматься ручной расшифровкой присланного текста.

ЗАПРОС ИЗ ПЕРЕПИСКИ · 26 МАЯ · ПРОВЕРКА ВЖИВУЮ

потестил бот пару дней:

1. некоторые новости повторяются, а мы хотели, чтобы новость приходила только 1 раз

2. иногда текст новости подтягивает еще все, чтобы было на страинце сайте (ссылки на другие новости, всякие пункты меню и пр) и поулчается месиво из бессвязного текста

Один сюжет об IEM Beijing бот прислал от Dust2 и TalkEsport как две разные новости
Один сюжет об IEM Beijing бот прислал от Dust2 и TalkEsport как две разные новости
Один сюжет об IEM Beijing бот прислал от Dust2 и TalkEsport как две разные новости
Один сюжет об IEM Beijing бот прислал от Dust2 и TalkEsport как две разные новости
В текст другой новости попали фрагменты соседних материалов сайта
В текст другой новости попали фрагменты соседних материалов сайта

На этот раз у меня уже были хорошие примеры. Я сделал скриншоты, где можно было сравнить заголовки и издания двух одинаковых новостей, а заодно увидеть, как выглядит сообщение, в которое случайно попала половина соседней страницы. Это сильно полезнее, чем фраза «что-то дублируется»: у ИИ появилась возможность разобрать конкретный сбой и проверить исправление на нем же.

Логику распознавания повторов нейросеть переработала. Вместо того чтобы ориентироваться преимущественно на совпадение ссылок или похожесть заголовков, программа стала сравнивать суть самого события. Публикации об IEM Beijing в тесте объединились в один сюжет. Но тут есть и обратная сторона: если научить парсер слишком агрессивно объединять похожие сообщения, он может принять два разных матча или два самостоятельных события за один повтор и просто скрыть нужную новость. Поэтому кодекс отдельно проверил, что материал о другом матче не склеивается с историей про IEM Beijing.

С извлечением текста мы поступили похожим образом: сузили область поиска до содержимого самой статьи, а если вытащить чистый текст не получается — используем короткое описание, которое отдает сайт. Для меня такое решение было вполне приемлемым. Лучше получить нормальный анонс со ссылкой, чем огромную простыню, в которой содержание заметки перемешано с меню и рекламой.

Изменения загрузили на VPS, обе части программы снова запустились. Но тут я не хочу приписывать нашему новостнику сверхспособностей. Проверка на конкретных примерах прошла, однако масштабного тестирования на сотнях различных публикаций в этой переписке не было. Так что обещать, будто он теперь навсегда избавился от любых дублей, было бы слишком смело. Впрочем, мы хотя бы разобрались с настоящими ошибками, которые я собственными глазами видел в ленте.

Отказ от сводки

С вечерним дайджестом история продолжалась заметно дольше, чем мне хотелось. Изначально он представлялся красивым дополнением: утром и днем материалы приходят по одному, вечером — понятный обзор самого важного. Но в реальности именно эта функция требовала все новых исправлений. То текст обрезан, то отобраны не те публикации, то языковые модели возвращают ошибку, то результат зависит от того, где именно запущена программа. Постепенно я начал задавать себе вполне резонный вопрос: а оно мне вообще надо?

В июле, когда сводка в очередной раз начала барахлить, я попросил ее отключить и оставить только обычные новости. Помощник внес изменение в локальную версию, но доставить его до VPS тогда не удалось: сервер не принимал подключение. Получилась знакомая ситуация — на компьютере поправили, а рабочий бот продолжает жить своей жизнью.

В октябре я вернулся к вопросу. Дайджест опять выдавал ошибки. Более того, меня начало раздражать меню, которое периодически появлялось на экране без всякой просьбы с моей стороны. Я ведь хотел не постоянно взаимодействовать с каким-то сложным интерфейсом, а получать публикации в спокойном, предсказуемом виде. Если мне понадобится что-то настроить, я сам вызову нужный раздел командой.

В итоге решение получилось радикальным, но, по-моему, вполне разумным: убрать ИИ-сводку совсем, а клавиатуру держать скрытой по умолчанию и показывать только по запросу. Можно было продолжать бесконечно латать вечерний обзор ради самого факта, что у бота есть «искусственный интеллект», но я изначально не ставил задачу сделать демонстрацию возможностей нейросетей. Мне нужна была удобная новостная лента. Если дополнительная функция регулярно мешает основной, возможно, лучшая доработка — просто от нее отказаться.

Поздняя ошибка сводки стала поводом окончательно убрать ее
Поздняя ошибка сводки стала поводом окончательно убрать ее
Такое меню раньше оставалось на экране; теперь его вызывают по команде
Такое меню раньше оставалось на экране; теперь его вызывают по команде

На этот раз все закончилось не только изменением файлов. 22 октября правки действительно добрались до VPS. По отчету в переписке оба процесса работали, восемь проверок прошли успешно, старая клавиатура была убрана. Это не означает, что в программе гарантированно больше нет ни одной ошибки, но означает, что нужные изменения наконец оказались там, где крутится сам новостник.

Я отдельно подчеркиваю эту разницу, потому что она встречалась у меня несколько раз. ИИшка может совершенно честно сказать, что исправила код. И это действительно будет правдой. Но между исправленным кодом и работающим продуктом есть еще один этап — доставить новую версию туда, где она должна крутиться, запустить и убедиться, что пользователь видит именно новый результат.

Результат

В итоге у меня получился бот для Телеграма, который собирает новости о профессиональном CS2 из подключенных источников, присылает их в чат, умеет работать с выбранными темами и не требует держать включенным мой компьютер. Он живет на VPS, а меню появляется только тогда, когда я сам его вызываю. ИИ-сводки в текущей версии нет — я попробовал, несколько раз исправлял, поборол часть проблем и в конце концов решил, что без нее будет лучше.

Главное, что мне понравилось в этой истории, — возможность сделать работающую вещь, практически не понимая языка, на котором она написана. Несколько лет назад подобная идея у меня, скорее всего, так и осталась бы идеей: нужно искать разработчика, ставить задачу, объяснять нюансы, ждать. Здесь я мог общаться с ИИ почти как с живым разработчиком. По сути, тот же привычный формат общения с ChatGPT, только на выходе получаешь не текстовый ответ, а очередную версию своей программы: «вот чего я хочу», «вот что получилось», «вот это неудобно», «а это вообще не работает, смотри скриншот».

Но есть и обратная сторона. Нейронка не живет с вашим ботом и не чувствует, как он раздражает, когда третий раз за день присылает одну и ту же новость или выдает обрывок чужого меню вместо статьи. Она может исправить конкретную ошибку, отчитаться об успешных тестах и перейти к следующему заданию. А понять, что продукт в целом удобен, все еще должен человек, ради которого этот продукт создавался.

Если бы я начинал заново, то, наверное, шел бы примерно тем же путем: сначала добиться одного настоящего сообщения, затем подключить площадки, несколько дней пользоваться новостником в обычном режиме и постепенно исправлять то, что действительно мешает. Не пытаться сразу напичкать его всеми возможными функциями, а проверять каждую на практике. И самое главное — не доверять фразе «все готово», пока сам не открыл телегу и не убедился, что получаю именно то, чего хотел в самом начале: интересные новости без лишней возни.

Забрать в работу

Схема новостного бота и проверки

Упрощенная схема по статье: от источника до сообщения. Начните с одного источника и контрольной новости, затем расширяйте список.

Посмотреть схему6 этапов
  1. Источники → новые публикации

    Проверять выбранные адреса по расписанию. Отдельно убедиться, что каждый источник действительно отдает свежие новости; наличие адреса в списке этого не доказывает.

  2. Публикация → чистый текст

    Выделить заголовок, дату, ссылку и фрагмент статьи. Если чистый текст не получен, использовать короткое описание источника. Проверить, что в сообщение не попали меню и реклама.

  3. Проверка свежести и темы

    Сверить дату и выбранные темы. При первом запуске не отправлять весь старый архив; контрольную выдачу смотреть отдельно.

  4. Сравнение с уже найденными событиями

    Проверять не только ссылки, но и суть новости. Два текста об одном событии должны объединяться, а похожие заголовки о разных матчах — оставаться разными.

  5. Новость → сообщение в Telegram

    Отправить текст и ссылку на источник. Проверить настоящее сообщение: понятен ли смысл, не обрезан ли текст, работает ли ссылка.

  6. Несколько дней живой ленты

    Собрать примеры повторов, пропущенных событий и лишнего текста. После исправления повторить проверку на сервере с теми же примерами.

В описанной итоговой версии ИИ-сводки нет. Распознавание дублей проверяется на примерах и живой ленте, а не обещанием полностью исключить повторы.

Скачать схему · TXT

Поделиться статьей

В этой статье

Иллюстрация

Продолжим в Telegram

Заметки о маркетинге, эксперименты с ИИ и новые разборы — в «Как подобает». Можно читать между большими статьями.

Есть вопрос или тема для разбора? Напиши мне.