惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

H
Help Net Security
腾讯CDC
爱范儿
爱范儿
Google DeepMind News
Google DeepMind News
V
V2EX
Blog — PlanetScale
Blog — PlanetScale
Engineering at Meta
Engineering at Meta
GbyAI
GbyAI
量子位
F
Fortinet All Blogs
G
Google Developers Blog
T
The Blog of Author Tim Ferriss
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Hugging Face - Blog
Hugging Face - Blog
Last Week in AI
Last Week in AI
T
Tailwind CSS Blog
J
Java Code Geeks
S
SegmentFault 最新的问题
D
Docker
博客园 - 司徒正美
The GitHub Blog
The GitHub Blog
Jina AI
Jina AI
M
MIT News - Artificial intelligence
博客园 - 【当耐特】

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания
Практическое махоботоводство в 2026 году. Часть 3: подроб...
lubezniy · 2026-06-25 · via Все публикации подряд на Хабре

Лирически-теоретическое отступление про загрузку файлов

Загрузка файлов осуществляется в два этапа — получение ссылки на загрузку и собственно загрузка файла, в результате (или до) которой выдаётся строковой токен файла, передаваемый в объект вложений к сообщению. Но нормально документировано из них только получение ссылки. А по собственно загрузке файлов запросы идут на разные сервисы в зависимости от типа. И ответы на них, что называется, «кто в лес, кто по дрова». По-видимому, связано это с тем, что в зависимости от типа загружаемого файла загрузка осуществляется в файловые хранилища разных проектов группы VK, которые разрабатываются и поддерживаются разными командами — каждая как знает и как умеет. Подготовил табличку с информацией о том, что возвращается в ответ на запрос собственно загрузки файла.

Тип загрузки

Тип ответа

Содержимое ответа

Примечание

image

JSON

Объект photos с вложенным подобъектом случайного имени, у которого единственное свойство token с токеном

video и audio

XML-подобноэ

<retval>1</retval> при успехе; ошибки не проверял

Токен выдаётся сразу в ответе первого запроса (параметр token)

file

JSON

Объект со свойствами fileId (цифровое значение; видимо, идентификатор файла) и token (нужный нам токен)

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

Вернёмся к учебной задаче

В прошлой части мы договорились, что приложение, с которым работает библиотека, у нас по умолчанию установлено в каталоге /var/maxbot. Здесь и в последующих частях это соглашение также будет соблюдаться; все примеры будут из этого исходить.

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

Также, согласно документации, API-запрос GET /chats начиная с июня 2026 года поддерживаться перестал. Поэтому из библиотеки были удалены объекты запроса lubezniy\yii2max\request\GetChats

и ответа на него

lubezniy\yii2max\response\GetChatsResponse

Кроме того, для сегодняшнего примера в каталог examples/tutorial/files добавлены файлы всех видов, один из которых мы используем в сегодняшнем примере для загрузки с типом file; на других файлах вы дополнительно можете отработать загрузку самостоятельно.

Для обновления либы переходим в её каталог и гитом вытягиваем свежую ветку main:

cd /var/maxbot/vendor/lubezniy/Yii2-max
git pull

Как загружать файлы через библиотеку

Для вызова соответствующих функций библиотеки нам нужны три вещи:

  • тип загружаемого файла согласно документации Bot API;

  • MIME-тип файла;

  • полное имя файла в файловой системе.

Конечно, тип из первого пункта списка частично можно определить по MIME-типу. Но это если бы не тип file . Хотим отправить фото или видео как файл - надо тоже указывать file , а не image или video . Возможно, в будущем для тех, кто не хочет заморачиваться, сделаю общий метод с автоприсвоением типа. А пока как есть.

Последовательность процедуры загрузки такова:

  1. Методом модуля createRequest создаём запрос класса lubezniy\yii2max\request\UploadFilePrepare . В его параметр type вписываем тип загружаемого файла из документации (первый пункт перечня необходимого).

  2. Как обычно, отправляем запрос методом send без параметров. Метод, если не будет ошибок, вернёт в ответ объект класса lubezniy\yii2max\response\UploadFilePrepareResponse . Созданный объект нужно обязательно запомнить в какой-нибудь переменной. Это не совсем обычный тип ответа; у него есть дополнительный метод processUpload, реализующий собственно отправку запроса на загрузку файла. И этот метод нужно вызвать для реализации второго этапа загрузки. В параметры метода передаются сначала полное имя загружаемого файла, затем его MIME-тип. Третьим необязательным параметром можно указать имя файла, под которым файл будет загружен в файлохранилище MAX. Результат выполнения этого метода нас интересует мало, его можно даже не запоминать - просто ловим исключения при ошибке.

  3. После выполнения обоих этапов загрузки осталось только получить токен загруженного файла для подстановки в сообщение. В зависимости от типа файла он появляется или после первого, или после второго этапа, но всегда находится в свойстве token объекта класса UploadFilePrepareResponse. Рекомендация — забирать его значение после выполнения второго этапа; так оно точно будет присутствовать на месте.

Примечание: Документация по API говорит нам о том, что видеофайлы после загрузки проходят ещё процесс подготовки. И, если попытаться отправить сообщение с вложением до окончания этого процесса (на больших видео он может занимать довольно значительное в масштабах исполнения веб-приложения время), то отправка сообщения вернёт ошибку. Сам пока не сталкивался с загрузкой больших видео и не могу сказать чего-либо конкретного на эту тему. Но эти моменты явно надо иметь в виду при реализации своих проектов и не торопиться отправлять сообщение с вложением сразу после загрузки большого видеофайла. Хотя бы несколько секунд стоит подождать.

Наконец, практическая реализация в учебной задаче

Надеюсь, вы ещё не потёрли с прошлой публикации файл /var/maxbot/commands/MaxLearnController.php . Идём в каталог приложения и запускаем этот файл на редактирование:

cd /var/maxbot
nano commands/MaxLearnController.php

В конец файла, в строку между двумя последними закрывающими фигурными скобками (если её нет, то нужно добавить пустую), вписываем action загрузки файла (в примере загрузим docx и выведем на экран полученный токен):

    /**
     * Шаг 2. Пример загрузки файла
     * @return int
     */
    public function actionStep2(): int
    {
        // Загрузка файла
        /**
         * @var \lubezniy\yii2max\Module $module Модуль бота
         */
        /**
         * @var \lubezniy\yii2max\request\UploadFilePrepare $request
         *  Объект запроса на первый этап загрузки
         */
        /**
         * @var \lubezniy\yii2max\response\UploadFilePrepareResponse $prepareResult
         * Объект ответа на первый этап и на всю загрузку
         */
        $module = Yii::$app->getModule('maxbot', true);

        // Создаём объект запроса на первый этап
        $request = $module->createRequest([
            'class' => \lubezniy\yii2max\request\UploadFilePrepare::class,
            'type' => 'file',
        ]);
        // Отправляем запрос, запоминаем результат
        $prepareResult = $request->send();
        // и пробуем загрузить файл        
        $prepareResult->processUpload(
            __DIR__ . '/../vendor/lubezniy/Yii2-max/examples/tutorial/files/docxfile.docx',
            'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
            'docxfile.docx'
        );
        // Выводим токен загруженного файла
        $this->stdout("Uploaded file token is " . $prepareResult->token . "\n");

        return ExitCode::OK;
    }

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

php yii max-learn/step2

Если всё правильно, то в результате мы увидим на экране сообщение с токеном загруженного файла. Токен просьба записать на будущее; он пригодится в следующий раз, когда мы к кнопкам отправленного сообщения добавим загруженный файл.

Подытожим

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