InquirerUndas 2026: Bulacan dogs get Halloween pamperingPunchIkogosi Marathon to groom 10 Ekiti athletesCNN TürkMeclis'te 2027 bütçe mesaisi başlıyor! İşte kasım ayında ekonomi gündemiBollywood HungamaHimesh Reshammiya confirms plans to turn director: “It would collect Rs. 100 cr on day of release!”; wishes to become a superstar actor: “Amitabh Bachchan’s 13th film was a hit; I have done 12 films until now...”The Jerusalem PostShin Bet accused of coercing Gaza targets into deadly strikes to spare families - reportDaily MaverickHEART FOR ART: Award-winning artist Annette Kamfer paints her way back after Parkinson’s diagnosis한겨레박경리 탄생 100주년…토지 무대 ‘하동 평사리’ 방문객 증가ZDF heuteEntdecken Sie das ZDF-NachrichtenstudioCollider‘Resident Evil’ Officially Unleashes a Double Dose of Horror on NetflixDaily MailWave of unrest breaks out across Europe: Protesters firebomb police and loot stores as violence grips France, Germany and Albania on HalloweenVanguardObi accuses Tinubu of neglecting Imo, cites insecurity, povertyNHK 社会茨城 鹿嶋 インドネシア国籍男性4人か 海に転落 2人行方不明
The Daily Newsstand · Free, Always
Sunday, November 1, 2026

Как я автоматизировала еженедельную презентацию и научила AI-бота делать правки прямо в треде

Translate

Расскажу, как я автоматизировала сборку еженедельной презентации: данные берутся из Redash, собирается .pptx, и раз в неделю ссылка на неё приходит в мессенджер. А потом я сделала бота, которому можно написать правку к слайду прямо в треде под презентацией.

Каждую неделю у департамента проходит встреча, и к ней нужна презентация на несколько десятков слайдов с метриками в разных разрезах. Ранее 20+ менеджеров собирали презенатцию руками: открывали Redash, прокликивали фильтры, делали скриншоты, выгружали данные в иксель и делали промежуточные расчеты, вставляли это все на слайды, подписывали цифры, делали ручное форматирование и т.д. Каждую неделю на это уходило несколько часов.

Я опишу основные шаги и как всё устроено. Код в статье упрощённый, под свои задачи его придётся дорабатывать.

Что в итоге получилось

Раз в неделю в 9 утра в канал приходит пост со ссылкой на свежую презентацию.

В самой презентации:

  • графики собраны на свежих данных, в одном стиле, фокусная неделя выделена цветом

  • на каждом слайде есть KPI-карточки: факт, таргет и значение с начала года

  • ручные слайды, которые заполняют коллеги, переносятся из прошлой недели

  • в заметках к слайду лежат ссылки на запросы в Redash

Если кому-то нужно что-то поменять, он пишет в тред под постом, например «на слайде 12 подпиши значения на всех барах», и через пару минут получает исправленный слайд.

Часть 1. Как собирается презентация

Общая схема:

Redash API → pandas → matplotlib (только графики) → python-pptx (всё остальное) → Nextcloud → Mattermost

Шаг 1. Забираем данные из Redash

Подробно про это я писала в прошлой статье. Если коротко, берём query_id, передаём параметры и ждём результат. Если результат не готов сразу, Redash вернёт job, и его надо опрашивать, пока запрос не досчитается.

def fetch_query(session, query_id, params, poll_seconds=2.0):
    r = session.post(
        f"{BASE_URL}/api/queries/{query_id}/results",
        json={"parameters": params, "max_age": 0},
    ).json()
    while "job" in r:
        job = r["job"]
        if job["status"] == 3:  # success
            rid = job["query_result_id"]
            return session.get(f"{BASE_URL}/api/query_results/{rid}").json()
        if job["status"] == 4:  # failure
            raise RuntimeError(job["error"])
        time.sleep(poll_seconds)
        r = session.get(f"{BASE_URL}/api/jobs/{job['id']}").json()
    return r

На всю презентацию у меня больше 40 запросов, и полная сборка идёт 10 минут.

Шаг 2. Каждый слайд собирает своя функция

На каждый слайд у меня отдельная функция. Она сама берёт данные для своего слайда, рисует его и возвращает заголовок и ссылки на запросы.

def build_metric_slide(prs, ctx):
    df = fetch_df(METRIC_QUERY_ID, {"weeks": ctx.weeks})
    slide = prs.slides.add_slide(prs.slide_layouts[6])  # пустой layout
    title(slide, "Metric A", focus_week=ctx.focus)
    kpi_card(slide, fact=df.value.iloc[-1], target=METRIC_TARGET)
    add_chart(slide, bars_png(df, highlight="last"))
    return {"slide": "Metric A", "query_url": redash_link(METRIC_QUERY_ID)}

Так можно пересобрать один слайд, а не всю презентацию: python deck.py --only metric_a. Если правка касается одного графика, ждать полную сборку ради неё нет смысла. Ещё если одна функция упала, остальные слайды всё равно соберутся, и каждый слайд можно отлаживать отдельно.

Шаг 3. Редактируемые элементы вместо картинок

Для удобства правок самим человеком картинкой вставляется только сам график, а заголовки, KPI-карточки, подписи и таблицы я делаю обычными элементами PowerPoint через python-pptx, и их можно поправить руками.

def kpi_card(slide, x, y, fact, target, scope):
    card = slide.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE, x, y, w, h)
    card.fill.solid()
    card.fill.fore_color.rgb = LAVENDER
    tf = card.text_frame
    run(tf.paragraphs[0], scope, size=11, color=INK_SOFT)
    run(tf.add_paragraph(), fmt_pct(fact), size=28, bold=True,
        color=GOOD if fact >= target else BAD)

Заголовок графика тоже текстом на слайде, внутри картинки его нет.

демонстрационный вариант с демо-стилей и демо-данными

демонстрационный вариант с демо-стилей и демо-данными

Шаг 4. Стиль

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

Отдельно расскажу про шрифт. Я использую Manrope, и графики почему-то выглядели сжатыми. Оказалось, что в скачанных TTF-файлах шрифт внутри назывался Manrope ExtraLight. matplotlib не находил Manrope и без всяких предупреждений рисовал DejaVu. Я переименовала шрифты внутри файлов через fontTools и положила их прямо в скрипт, чтобы сборка не зависела от того, что стоит на машине.

Так что если график выглядит как-то странно, проверьте, каким шрифтом matplotlib его на самом деле нарисовал.

Шаг 5. Фокусная неделя

Данные доезжают с задержкой, и у разных метрик она разная. По последней неделе часть событий ещё не закончилась, а какие-то появятся только через несколько недель. Если показать последнюю неделю как есть, кажется, что метрики резко упали.

Поэтому у каждой метрики своя «фокусная неделя»:

  • если данные доезжают быстро, это позапрошлая неделя

  • если медленно, неделя, которая была 4 недели назад

  • значение с начала года считается до воскресенья фокусной недели

Под заголовком каждого слайда написано, за какую неделю цифры, например focus week 05.10-11.10.

Шаг 6. Ручные слайды

Некоторые слайды из данных не собрать: статусы инициатив, договорённости с партнёрами, комментарии. Их заполняют коллеги.

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

PASSTHROUGH_TITLES = {
    "Manual slide A",
    "Manual slide B",
    "Manual slide C",
}

prev_map = {heading(s): s for s in Presentation(prev_path).slides}
...
if title in PASSTHROUGH_TITLES and title in prev_map:
    copy_slide(prev_map[title], into=prs)

Шаг 7. Если слайд не собрался

Запросов много, и иногда какой-то падает: таблица не обновилась или кто-то поменял параметры запроса. Не хотелось, чтобы из-за одного слайда люди остались без всей презентации.

Поэтому каждая функция обёрнута в try/except. Вместо упавшего слайда появляется заглушка с текстом ошибки, а в посте написано, какие слайды не собрались.

try:
    summary = build(prs, ctx)
except Exception as e:
    drop_half_built_slide(prs)
    placeholder(prs, f"[не собрался] {slide_title(name)}", f"{type(e).__name__}: {e}")
    failed.append(name)

Шаг 8. Ссылки на запросы в заметках

В заметки к каждому слайду скрипт пишет ссылки на запросы Redash и подписывает, к какому графику какая ссылка.

Шаг 9. Публикация

Скрипт запускается по крону утром в день встречи и делает следующее:

  1. проверяет, не отправлена ли уже презентация за эту неделю, чтобы не прислать её дважды

  2. скачивает из Nextcloud прошлую презентацию, чтобы взять из неё ручные слайды

  3. собирает новую

  4. загружает её в Nextcloud как Weekly_<воскресенье>.pptx и получает ссылку на редактирование

  5. отправляет пост со ссылкой в Mattermost через webhook

Часть 2. Бот для правок

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

Сначала все правки делала я сама: меняла код, пересобирала слайд, отправляла обратно. Утром перед встречей я только этим и занималась, поэтому сделала бота, которому правки можно писать прямо в тред под постом.

Как это выглядит для коллег

  1. Человек пишет в треде: @deck-bot на слайде 12 подпиши значения на всех барах

  2. Через 1–3 минуты бот отвечает:

@anna.k Готово: слайд 12 с правками
Что поменялось: подписи значений на всех барах, раньше были только на фокусной неделе
Вставьте его в основную презентацию. Правка будет внесена в код проекта,
и начиная с ближайшей встречи вы получите обновлённый слайд.
  1. Человек вставляет исправленный слайд в презентацию. Потом я в течение недели захожу в тред со всеми правками, просматриваю их и отбираю те, которые нужно добавить в код сборки презентации и тогда ерез неделю слайды уже соберётся в новом виде с нужными правками.

Что агенту можно делать

Можно было дать LLM-агенту доступ к репозиторию, Redash и Nextcloud и пусть сам разбирается. Мне такой вариант не понравился: сложно предсказать, что он сделает. Поэтому напрямую агент ничего не трогает. У него есть несколько инструментов (через MCP), и все они реализованы в самом сервисе презентации:

Инструмент

Что делает

deck_slides

список слайдов в опубликованной презентации: номер и первые строки текста

list_slides

короткие имена функций-слайдов

search_code, read_code

поиск и чтение кода

rebuild_slides

пересобрать слайды на свежих данных, код не меняется

preview_fix

применить правку, собрать слайд, сохранить черновик

list_drafts, commit_drafts

собрать черновики за неделю в один коммит

get_job

статус долгой задачи

Агент выбирает, что сделать, а проверки и сборка живут в коде сервиса, и на них можно написать обычные тесты.

Шаг 1. Найти слайд

Коллеги называют слайды по-своему: «слайд 12», «первый слайд», «где конверсия». А в коде у слайдов короткие технические имена.

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

Если слайд ручной и функции у него нет, агент так и отвечает: этот слайд правится руками. Если непонятно, о каком слайде речь, он задаёт один уточняющий вопрос.

Шаг 2. Данные или оформление

Просьбы бывают двух видов:

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

  • «покажи по-другому»: агент читает код функции и делает минимальную правку

Для ошибок Redash я добавила отдельное правило. Если Redash ругается на параметры, скорее всего кто-то поменял сам запрос. В этом случае агент не гадает, а пишет, что запрос изменился, и тегает меня.

Шаг 3. Сначала собрать на копии

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

Если всё собралось, исправленный слайд загружается в Nextcloud отдельным файлом, а правка сохраняется как черновик.

Основную презентацию бот не перезаписывает никогда. Коллеги весь день правят её руками, и при перезаписи их изменения бы пропали. Поэтому бот присылает отдельный файл, и слайд из него вставляют сами.

Шаг 4. Черновики вместо коммитов

В первой версии бот сразу коммитил каждую правку в ветку и добавлял её в PR. В первый же день два человека попросили правки одновременно, и коммиты начали конфликтовать (409 Conflict).

Я переделала это на черновики. Черновик хранится как JSON: что заменить, кто попросил, текст просьбы и ссылка на тред. Новые правки применяются поверх уже сохранённых черновиков, поэтому агент работает с актуальной версией кода.

Когда я пишу в треде «собери правки в PR», агент применяет все черновики за неделю, собирает все слайды, которые они затронули, и делает один коммит и один PR. Если черновик уже не применяется, например его перекрыла более поздняя правка, он попадает в список «Не вошли» с причиной.

PR я смотрю и мержу сама также в треде через агента, без меня в код ничего не попадает.

Шаг 5. Долгие задачи

Слайд собирается 1–3 минуты, а у шага агента таймаут по умолчанию минута. Поэтому rebuild_slides, preview_fix и commit_drafts сразу отдают job_id, а агент спрашивает get_job, пока задача не закончится.

На чём я спотыкалась

  • Пересобирать надо только то, о чём попросили. Когда ради одного слайда несколько минут пересобирается вся презентация, это очень раздражает, так что флаг --only лучше сделать сразу.

  • Когда два человека писали в тред одновременно, очистка временных папок одного запроса удаляла папки другого. Помогло удалять папки по возрасту, а не все, кроме текущей.

  • «Слайд 12» для человека это номер в его файле, а не в коде. Пока не было deck_slides, агент иногда правил не тот слайд.

Как я работала с AI

Код я писала вместе с Claude Code. На мне были постановка задачи, правила (что считать фокусной неделей, когда красить в красный, что вообще показывать на слайде) и проверка каждого слайда. Агент писал и переписывал код, искал ошибки и делал мелкие правки, которых в такой задаче очень много.

Что мне помогало:

  • давать референс: старую презентацию или PDF со стилем, и просить сделать так же

  • после каждого изменения просить картинку слайда и смотреть на неё, а не верить на слово

Заключение

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

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

Об авторе

Меня зовут Валерия Смирнова, я уже более 6 лет работаю в продуктовой и BI-аналитике. Веду канал про BI и визуализацию данных.

View the original on Хабр →

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.