Представлена открытая библиотека Telegram-ботов для разных задач Awesome Telegram. Там есть боты: поисковики, интеграторы с сотнями сервисов, для удаления ватермарок, загрузчики видео, аудио и картинок, генераторы картинок, стикеров, текстов, поздравлений. К каждому боту авторы приложили описание работы и инструкцию.
Компьютерное зрение для кода: что PVS-Studio разглядел в OpenCV
Что общего у компьютерного зрения и статического анализа? Оба ищут смысл в данных. OpenCV находит образы среди миллионов пикселей, а PVS-Studio — ошибки среди тысяч строк кода. Изучим же исходники крупнейшей библиотеки компьютерного зрения.
На примере 14 фрагментов кода из OpenCV предлагаю посмотреть, как статический анализ помогает избежать попадания багов в релиз и облегчить жизнь разработчикам.
Давайте посмотрим на кусок кода из проекта:
template<typename T>
struct Ptr : public std::shared_ptr<T>;
// ....
Ptr<FlannNeighborhoodGraph> FlannNeighborhoodGraph::create(....)
{
return makePtr<FlannNeighborhoodGraphImpl>(....);
}
void Utils::densitySort (const Mat &points, int knn,
Mat &sorted_points, std::vector<int> &sorted_mask)
{
// ....
FlannNeighborhoodGraph &graph = // <=
*FlannNeighborhoodGraph::create(....);
std::vector<double> sum_knn_distances (points_size, 0);
for (int p = 0; p < points_size; p++) {
const std::vector<double> &dists = graph.getNeighborsDistances(p);
for (int k = 0; k < knn; k++)
sum_knn_distances[p] += dists[k];
}
// ....
}
Если вы думаете, что использование умных указателей раз и навсегда решает проблему "висячих" ссылок и доступов к памяти, то здесь всё пошло не так. Давайте разбираться. Сейчас код работает следующим образом:
Функция create создаёт и возвращает умный указатель на тип FlannNeighborhoodGraphImpl, и его счётчик ссылок на объект равен единице;
Создаётся ссылка graph на значение этого умного указателя, при этом счётчик ссылок на объект не изменяется;
Указатель является временным объектом, и поэтому после завершения инициализации счётчик ссылок уменьшится до нуля, что приведёт к освобождению управляемого объекта. Теперь ссылка указывает на разрушенный объект;
В цикле for происходит обращение к невалидной ссылке.
В итоге код, который казался правильным, приводит к неопределённому поведению. Кроме того, эту проблему находит не только PVS-Studio, но и санитайзер. Пруф.
Для исправления необходимо сохранить умный указатель, тогда объект типа FlannNeighborhoodGraph будет жить до конца блока. Можно сделать так:
std::vector<double> sum_knn_distances (points_size, 0);
{
// get neighbors
auto graph = FlannNeighborhoodGraph::create(....);
for (int p = 0; p < points_size; p++) {
const std::vector<double> &dists = graph->getNeighborsDistances(p);
for (int k = 0; k < knn; k++)
sum_knn_distances[p] += dists[k];
}
}
Дополнительно ограничили область видимости graph, чтобы ресурс освободился после выполнения циклов.
Хотите узнать больше?
Статический анализ выявляет скрытые дефекты даже в больших работающих проектах. Какие ещё опасные фрагменты кода мы нашли в коде OpenCV? Полный разбор можно найти в отдельной статье.
Совет по Joomla: использовать выключенное состояние для кнопок в списках элементов админки - listCheck().
Мы добавляем в тулбар панели администратора Joomla некую кнопку, которая что-то делает со списком id выделенных элементов и ajax-запросом отсылаем их в свой плагин. Но нам надо предупредить нажатия на кнопку в тех случаях, когда ни один элемент не был выбран. Для этого можно написать свою проверку на js. А можно воспользоваться встроенной в Joomla.
Добавить кнопку в тулбар Joomla 6.
use Joomla\CMS\Toolbar\Button\BasicButton;
use Joomla\CMS\Language\Text;
// ниже по коду, где-нибудь в плагине на onAfterDispatch()
// Предварительно проверяем в каком компоненте мы находимся по option из $app->getInput()
// пример из плагина, поэтому $this->getApplication()
$app = $this->getApplication();
// Берём текущий тулбар
$toolbar = $app->getDocument()->getToolbar('toolbar');
// Создаём кнопку
$button = (new BasicButton('send-to-indexnow'))
->text(Text::_('PLG_WTINDEXNOWSWJPROJECTS_BUTTON_LABEL'))
->icon('fa-solid fa-arrow-up-right-dots')
->onclick("window.wtindexnowswjprojects()");
// Добавляем кнопку в тулбар
$toolbar->appendButton($button);
Заблокировать кнопку тулбара Joomla, если не выбраны элементы списка.
Теперь нам надо проверить находимся ли мы в списке. Делаем это по view из $app->getInput().
И если мы в списке - используем метод $button->listCheck(true), который сделает проверку за нас. Если ни один элемент не выбран - кнопка в тулбаре Joomla будет заблокирована и JS-обработчик не будет вызван. Этот метод есть у всех классов кнопок, наследующих класс \Joomla\CMS\Toolbar\ToolbarButton.
Всем привет! Меня зовут Катя, я развиваю Gramax, open source-платформу для управления технической документацией. За последние 3 месяца мы сделали много новых полезных функций, коротко расскажу о самых важных.
Интеграция с GitVerse. Теперь в качестве хранилища можно использовать GitVerse. Как подключить GitVerse к Gramax читайте в статье.
Поддержка Gitea. Также добавили поддержку Gitea: доступно подключение в качестве хранилища и использование всех возможностей Gramax.
Экспорт в PDF и DOCX в собственных стилях. Можно настроить вид документа: добавить титульную страницу, оглавление, номера заголовков, собственные шрифты и отступы и так далее. Для DOCX — с помощью стилей, для PDF — с помощью CSS. Применяется при экспорте из приложения, портала документации и в CI/CD.
Предпросмотр загруженных файлов. Теперь при клике на загруженный файл в статье открывается окно предпросмотра. Отображаются файлы форматов DOCX и PDF. Остальные форматы — скачиваются.
Улучшения поиска.
Новое ранжирование. Больший вес дается результатам, в которых искомое слово содержится в названии статьи или в одном из заголовков.
Переход к поисковой фразе. После клика на результат поиска статья откроется на том фрагменте, в котором есть поисковый запрос.
Настройка поисковой выдачи. Для статей можно указать поисковые запросы: если в поиске ввести один из них, статья отобразится выше остальных.
Поиск по свойствам в приложении. Если на статьях установлены свойства — в поисковой строке можно отфильтровать по ним.
Улучшение внешнего вида. Теперь в результатах есть указание на каталог, в котором содержится запрос. А также отображается иерархия заголовков в статье.
Улучшения Gramax Enterprise Server.
Разворачивание с помощью Helm. Добавили новый способ разворачивания Gramax Enterprise Server в Kubernetes.
Тестирование знаний. Реализовали модуль проверки знаний читателей: в статью можно добавить тест с разными типами вопросов. После прохождения статистика пользователей отобразится в панели администрирования.
Поиск по вложенным файлам. Теперь поиск учитывает не только контент статьи, но и контент из PDF и DOCX-файлов.
Привет, Хабр! Тем, кому регулярно приходится заглядывать в etcd — будь то QA, поддержка или разработчики — хорошо знакома ситуация, когда нужно разобраться с неожиданным состоянием сервиса, проверить конфиги или найти застрявший лок. И каждый раз всё сводится к одному: копировать ключ, запускать etcdctl get, читать многострочный JSON в терминале, ошибаться в пути… и в какой-то момент понимаешь, что это однообразие выматывает больше, чем сама проблема.
Поэтому наш коллега из Хайстекс сделал небольшой TUI-инструмент, который заметно упрощает работу с etcd и делает её куда дружелюбнее для тех, кто каждый день копается в окружениях. Он снимает рутину etcdctl, даёт привычную “каталожную” навигацию, подсвечивает скрытые _-ключи, позволяет комфортно открывать большие конфиги и помогает разбираться с локами, которые любят появляться в самых неожиданных местах.
Если вы в QA, поддержке или просто часто работаете с etcd, этот инструмент легко сэкономит вам время и нервы.
📊 Multi‑LLM Orchestrator v0.6.0: метрики провайдеров и умный роутинг
На этой неделе на Хабре вышла статья про Multi-LLM Orchestrator — библиотеку для работы с российскими LLM через единый интерфейс. Сегодня релиз v0.6.0 добавляет метрики провайдеров и стратегию роутинга на основе health status.
Автоматический сбор метрик
Роутер отслеживает каждый запрос и собирает статистику по провайдерам. Latency, success rate, количество ошибок — всё фиксируется без дополнительной настройки.
from orchestrator import Router
from orchestrator.providers import GigaChatProvider, ProviderConfig
router = Router(strategy="best-available")
router.add_provider(GigaChatProvider(
ProviderConfig(name="gigachat", api_key="...", model="GigaChat")
))
# После нескольких запросов
metrics = router.get_metrics()
print(f"{metrics['gigachat'].avg_latency_ms:.0f}ms")
print(f"Health: {metrics['gigachat'].health_status}")
Система отслеживает среднюю задержку и rolling average по последним 100 запросам. Если провайдер начинает деградировать, это видно сразу.
Health status провайдеров
Роутер классифицирует каждого провайдера автоматически:
healthy — error rate меньше 30%, стабильная latency
degraded — error rate 30-60% или задержки растут
unhealthy — error rate выше 60%
Классификация происходит на лету, без пороговых значений в конфигах.
Стратегия best-available
Новая стратегия роутинга выбирает провайдера на основе метрик. Приоритет отдаётся healthy-провайдерам, среди них — с минимальной задержкой.
router = Router(strategy="best-available")
router.add_provider(gigachat_provider)
router.add_provider(yandexgpt_provider)
# Роутер выбирает самого здорового и быстрого
response = await router.route("Вопрос")
Если GigaChat деградирует до 3 секунд, а YandexGPT стабильно отвечает за 500ms — роутер переключится на YandexGPT.
Тестирование на боевых API
Запущена серия тестов с реальными запросами к GigaChat и YandexGPT. Результаты подтверждают стабильность системы метрик.
Метрики провайдеров: GigaChat vs YandexGPT (fallback-тест)
Первый тест показал базовую работу: GigaChat отвечает за ~1.7 секунды со 100% success rate. Второй тест проверил fallback при ошибке авторизации — роутер переключился на YandexGPT без потери запроса. Третий тест подтвердил корректность метрик при streaming-запросах.
YandexGPT показал стабильные 500-700ms на серии из шести запросов. GigaChat медленнее (~1.7s), но это ожидаемо для более тяжёлой модели. Success rate обоих провайдеров — 100%.
Structured logging
Каждый запрос логируется в структурированном формате с полями provider, model, latency_ms, streaming, success. Интеграция с Prometheus или Grafana требует только парсинг JSON
# При успехе
logger.info("llm_request_completed", extra={
"provider": "gigachat",
"latency_ms": 1723
})
# При ошибке
logger.warning("llm_request_failed", extra={
"provider": "yandexgpt",
"error_type": "RateLimitError"
})
[ВИДЕО] AmoCRM + Joomla: быстрая настройка интеграции. Библиотека WT AmoCRM.
- Как быстро настроить интеграцию AmoCRM и сайта на Joomla?
- использовать PHP библиотеку WT AmoCRM для Joomla, которая предполагает использование её разработчиками. А разработчики могут написать любое количество плагинов и решений по интеграции и автоматизации AmoCRM и Joomla.
Больше никаких мучений с Markdown — расширение Markdown Viewer превращает все файлы Markdown в Word-документы без боли и страданий. Захватывает инфографику: любые схемы, диаграммы, графики в чистые картинки. Берёт формулы из LaTeX и переносит их в Word нативно, а не в формате ужасных вставок. Переносит форматирование — подсвечивает код, сохраняет таблицы и списки, как в оригинале. Работает локально. Подходит для работы с GitHub: открывает документы и даёт перенести всё в Word.
Представлен проект открытого бота на Python для Telegram с торрент клиентом. Решение умеет загружать файлы по магнет-ссылкам и ссылкам на Google-диск, есть поисковик торрентов и встроенный yt-dlp.
Представлен открытый проект Telegram Downloader, который умеет легально, быстро и легко скачивать любые файлы даже из защищённых каналов и чатов, где закрыта пересылка контента:
качает даже тяжёлые файлы за несколько секунд.
загрузки экспортируются в JSON-формат прямо на локальный диск.
работает локально — вся информация о загрузках будет только на локальном ПК.
Repeater запускает задачи по расписанию. Задачи описываются в toml-файлах и отображаются в веб-интерфейсе.
title = "wiki"
cron = "55 * * * *"
[[tasks]]
name = "wiki_pageviews"
cmd = "python3 ./examples/wiki_pageviews.py --end_date={{.scheduled_dt}}"
[[tasks]]
name = "trigger_outliers_update"
cmd = "python3 ./examples/trigger_outliers_update.py"
Возможен запуск при завершении другой задачи, уведомления о падениях, параллельные этапы. Repeater подойдёт для импорта данных и обновления витрин в хранилище.
Представлена подборка Awesome Privacy из 100 сервисов-аналогов всем популярным платформам, но с упором на безопасность и приватность данных, включая файловые менеджеры, облачные хранилища и клавиатуры.
База проектов опен-сорсных игр, а также различных аналогов платных тайтлов различных жанров. Многие проекты устанавливаются за один клик или открываются прямо в браузере.
В июле я писал о том, что Gaunt Sloth Assistant дошёл до версии 0.9.2. Сегодня мы наконец можем сказать, что вышла версия 1.0.0. В этом релизе мы перевели основную зависимость на LangChain/LangGraph v1, обновили минимальные требования до Node 24/npm 11 и официально объявили CLI готовым к повседневной автоматизации.
Что изменилось с прошлого поста?
Ревью теперь завершаются вызовом встроенного рейтингового инструмента. По умолчанию шкала 10/10, порог прохождения 6/10, и оценки ниже 6 заставляют команду review возвращать ненулевой код (non-zero exit code). Если нужен только режим предупреждений, установите commands.review.rating.enabled (и/или commands.pr.rating.enabled) в false в .gsloth.config.*.
Профили идентичности стали частью базового сценария: один флаг -i profile-name, и вы переключаете промпты, модели и провайдеры на уровень нужной папки.
Middleware теперь сущность первого класса. Можно комбинировать встроенные варианты вроде anthropic-prompt-caching или summarization, подключать собственные объекты на JS, а CLI показывает, что именно выполняется при каждой команде.
Глубокое слияние конфигов команд устранило проблему, когда переопределение источника контента стирало настройки рейтинга. Теперь значения по умолчанию сохраняются даже при частичных правках.
Мы освежили кеш OAuth, документацию и README, чтобы новичкам было проще стартовать, и параллельно усилили безопасность зависимостей.
Профили идентичности — главный QoL‑апгрейд 1.0.0. Они позволяют мгновенно переключаться между системными промптами, пресетами моделей и наборами инструментов под конкретную задачу. gth pr 555 PP-4242 по‑прежнему читает .gsloth/.gsloth-settings, а gth -i devops pr 555 PP-4242 автоматически берёт конфиг из .gsloth/.gsloth-settings/devops/ со своими промптами и провайдерами.
Нужно поговорить с Jira через MCP? Создайте профиль вроде jira-mcp со своим конфигом и запустите gth -i jira-mcp chat. Укороченный пример:
Переключение между такими папками теперь — один флаг, поэтому удобно держать отдельные персоны для DevOps, документации или любого удалённого MCP.
Rater — второй крупный прорыв. Ревью всегда содержали текстовый фидбек, но в 1.0.0 оценка стала действенной: мы сохраняем её в хранилище артефактов, передаём в модуль ревью и вызываем setExitCode, чтобы CI автоматически падал при невыполнении цели по качеству. Настройка защит для продакшн‑сервисов занимает теперь секунды и не требует самописных скриптов.
Наконец, реестр middleware и хранилище артефактов дают аккуратные точки расширения на будущее. Можно оборачивать вызовы моделей и инструментов, логировать каждую операцию и при этом оставлять Gaunt Sloth вести те же chat/code/pr/init команды. CLI как и раньше — небольшой TypeScript‑бинарь, который устанавливается через npm или запускается npx gth, но теперь у него архитектура, позволяющая развиваться без костылей.
Хотите попробовать релиз — быстрый путь всё ещё npm install -g gaunt-sloth-assistant
репозиторий https://github.com/Galvanized-Pukeko/gaunt-sloth-assistant пригодится как справочник и место для issues. Заводите issue, оставляйте фидбек в Discussions или подключайте rater к своему CI и расскажите, как он себя ведёт — буду рад помощи в движении к 1.1.
Человек на GitHub ускорил Joomla в 600 раз на объёме 150к+ материалов в 1700+ категориях.
На старте его сайт на Joomla 3 вообще не смог обновиться на Joomla 5. Пришлось делать экспорт/импорт материалов. Проделав всё это он запустил-таки этот объём данных на Joomla 5. Тестовый скрипт грузил 200 материалов из этого объёма всего за 94 секунды ))) А главная страница с категориями грузилась 20 секунд.
Добавив индекс для таблицы #__content
CREATE INDEX idx_catid_state ON #__content (catid, state);
он сократил время загрузки категорий до 1 секунды. Затем наш герой решил поковырять SQL-запрос в ArticleModel, который отвечает за выборку материалов. И решил заменить тип JOIN на STRAIGHT_JOIN для категорий.
Что сократило загрузку 200 материалов из 150к с 94 секунд до 5. К слову сказать, боевой сайт на Joomla 3 крутится на 12CPU 64GB рамы. А все манипуляции с кодом он делает на базовом 1CPU 1GB сервере и замеры скорости даны именно для базового сервера.
Но это всё в дискуссии, хотя в идеале должно вылиться в Pull Requests. Дальнейшие его изыскания и результаты можно поглядеть в дискуссии на GitHub. Это ещё не конец.
Мы - Open Source сообщество, где никто никому ничего не должен. Джунгли. Но человек ищет пути оптимизации Joomla и предлагает решения. Если оказать поддержку и предложить помощь хотя бы с тестированием самых разнообразных сценариев, то возможно эти улучшения смогут войти в ядро. Пусть не быстро, пусть через несколько лет, пусть не все, но войдут. Достаточно предложить руку помощи и приложить немного усилий.
Обработка HTTP ответа в Joomla 6+. Изменения по сравнению с Joomla 3 - Joomla 5.
В Joomla для выполнения внешних запросов из PHP к сторонним API используется класс Joomla\Http\Http напрямую или же Joomla\Http\HttpFactory, который возвращает для работы преднастроенный по умолчанию класс Http. О работе с HTTP-запросами подробно рассказывалось в статье 2021 года Создание внешних запросов с использованием HttpFactory (Joomla) (на Хабре), (на сайте автора). Некоторые изменения касаются работы с ответами на запросы. Например, наш запрос:
use Joomla\Http\HttpFactory;
$http = (new HttpFactory)->getHttp($options, ['curl', 'stream']);
$response = $http->get('https://any-url.ru/api/any/endpoint');
Раньше можно было получить код ответа или тело ответа как свойство $response - $response->code или $response->body. Однако, Joomla, начиная с Joomla 4 во многом переходит на стандарты PSR. В частности для работы с HTTP-ответами - на PSR-7. Также хорошая статья на Хабре о PSR-7: PSR-7 в примерах.
Прямое обращение к свойствам code, headers, body объявлено устаревшим в Joomla 6.0.0 и обещают удалить в Joomla 7.0.0.
Вместо этого нужно работать с HTTP-ответом по стандартам PSR-7.
Код ответа. Было $response->getContents(). Стало $response->getStatusCode().
Заголовки ответа.
Было $response->headers. Стало $response->getHeaders().
Тело ответа.
Было $response->body. Стало (string)$response->getContents().
В тело ответа теперь приходит не строка, а поток - объект класса Laminas\Diactoros\Stream. Поэтому его нужно привести к строке (если это json, к примеру): (string)$response->getContents(). Чаще всего в коде Joomla встречается именно такой вариант. Однако, есть и вариант с перемещением указателя чтения на начало потока:
// Получили ответ в виде потока
$stream = $response->getBody();
// "перемотали" на начало
$stream->rewind();
// Получили строковый ответ
$json = $stream->getContents();
«Там, где критична скорость, но не требуется оптимизация»: как и зачем МойОфис вышел в OpenSource
На Хабре опубликовано первое большое интервью нашего CTO Тамары Щепалкиной — и оно стоит прочтения, потому что это:
«Не форк с косметикой, а оригинальная инженерия»
Компилятор tsnative прошёл проверку на безопасность, получил документацию, Docker-образ и демо, чтобы любой разработчик мог сразу попробовать его в работе.
«...tsnative — это не «форк с косметическими изменениями», а продукт, в основе которого лежит оригинальная инженерная работа. Именно поэтому мы и приняли решение вывести его в open source: у проекта есть собственная ценность и потенциал для развития, который может быть интересен и полезен гораздо шире, чем внутри одной компании…»
2. Open source как часть стратегии.
Решение не ситуативное — это долгосрочный курс на технологическую независимость, партнёрство с сообществом и развитие совместных инженерных практик.
3. «Где критична скорость, но не требуется оптимизация».
tsnative создавался как инструмент, который помогает веб- и C++-разработчикам ускорять работу и выходить за рамки привычных сценариев. В основе компилятора — открытые библиотеки и собственная инженерия, без компромиссов по производительности.
4. От ядра к экосистеме.
Сначала — компилятор, но потенциально — UI-фреймворк и целая экосистема open source-проектов.
5. Сообщество в центре. Telegram-чат поддержки уже работает, а впереди — расширение комьюнити и совместное развитие открытых технологий.
«Ключевое для нас сейчас — подключить опенсорсное сообщество к развитию наших продуктов. Мы видим в этом не просто обмен кодом, а полноценное партнёрство: разработчики получают доступ к инструментам, которые можно использовать и дорабатывать под собственные задачи, а мы — обратную связь и новые идеи, которые помогают делать продукт лучше…»
В статье Тамара рассказывает, как и зачем МойОфис выходит на уровень open source-разработки, какие цели ставит и какие шаги уже сделаны.
Если вас интересует развитие стратегия открытого кода и сотрудничество с сообществом — обязательно загляните.
На Хабре есть уже много статей про наш детектор голоса (последняя тут). В этот раз с точки зрения юзеров видимых изменений не очень много, но работы было проделано очень много.
Мы в очередной раз полностью перебрали с нуля механизм тренировки нашего детектора голоса. С точки зрения юзера есть следующие улучшения:
Повышена общая стабильность на краевых случаях;
В целом незначительно повышено качество детекции на всех доменах;
Есть существенные улучшения на следующих краевых случаях:
Детские голоса;
Необычные голоса;
Мультяшные голоса;
Приглушённая речь;
Более сложные телефонные звонки;
Музыкальные инструменты, похожие на речь.
Будем признательны пользователям за ваши краевые случаи!
Детектор создан при поддержке Фонда содействия инновациям в рамках федерального проекта «Искусственный интеллект» национальной программы «Цифровая экономика Российской Федерации».
Цитировать детектор можно следующим образом:
@misc{Silero VAD,
author = {Silero Team},
title = {Silero VAD: pre-trained enterprise-grade Voice Activity Detector (VAD), Number Detector and Language Classifier},
year = {2021},
publisher = {GitHub},
journal = {GitHub repository},
howpublished = {\url{https://github.com/snakers4/silero-vad}},
commit = {insert_some_commit_here},
email = {hello@silero.ai}
}