|

Освоение загрузки файлов через API: полное руководство по multipart/form-data и практический пример с Sora 2

Загрузка файлов через API — это техническая задача, с которой разработчики часто сталкиваются при вызове интерфейсов для генерации AI-видео, обработки изображений и других подобных операций. В этой статье мы подробно разберем, как работает кодирование multipart/form-data, и на примере API Sora 2 (Image-to-Video) научимся мастерски загружать файлы через API.

Главная польза: после прочтения вы полностью разберетесь в низкоуровневых механизмах multipart/form-data, научитесь использовать команду curl -F для загрузки файлов и сможете самостоятельно реализовать функцию загрузки изображений для таких AI API, как Sora 2.

api-file-upload-multipart-form-data-guide-ru 图示


Основные знания о загрузке файлов через API

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

Зачем нужен multipart/form-data

Когда вы отправляете обычные текстовые данные через API, можно использовать простое кодирование application/x-www-form-urlencoded. Однако этот метод создает серьезные проблемы при работе с файлами:

Тип кодирования Сценарии использования Возможности обработки файлов Эффективность
application/x-www-form-urlencoded Простые пары «ключ-значение» ❌ Не подходит Требуется URL-экранирование для бинарных данных, низкая эффективность
application/json Структурированные данные ⚠️ Требуется Base64-кодирование Объем увеличивается на 33%
multipart/form-data Загрузка файлов ✅ Нативная поддержка Не требует кодирования, высокая эффективность

multipart/form-data — это решение, предложенное в стандарте RFC 2388 в 1998 году специально для устранения проблем с одновременной отправкой текста и бинарных данных по протоколу HTTP.

Принцип работы multipart/form-data

Основная идея multipart/form-data заключается в разделении тела HTTP-запроса на несколько независимых «частей» (parts), каждая из которых может иметь свой собственный тип контента.

api-file-upload-multipart-form-data-guide-ru 图示

Подробный разбор структуры данных

Типичный запрос multipart/form-data имеет следующую структуру:

POST /v1/videos HTTP/1.1
Host: api.apiyi.com
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxk

------WebKitFormBoundary7MA4YWxk
Content-Disposition: form-data; name="prompt"

She turns around and smiles
------WebKitFormBoundary7MA4YWxk
Content-Disposition: form-data; name="model"

sora-2-pro
------WebKitFormBoundary7MA4YWxk
Content-Disposition: form-data; name="input_reference"; filename="sample.jpeg"
Content-Type: image/jpeg

[Бинарные данные изображения]
------WebKitFormBoundary7MA4YWxk--
Компонент Роль Пример
Boundary Уникальный идентификатор для разделения частей данных ----WebKitFormBoundary7MA4YWxk
Content-Disposition Описание метаданных этой части form-data; name="prompt"
Content-Type MIME-тип этой части image/jpeg
Body Фактическое содержимое данных Текстовые или бинарные данные

🎯 Технический нюанс: Boundary должен быть уникальной строкой, которая гарантированно не встретится в теле самого запроса. Сервер использует boundary для парсинга и разделения каждой части данных.


Подробный разбор команды curl -F: загрузка файлов через API на практике

curl — это, пожалуй, самый популярный консольный HTTP-клиент, а его параметр -F специально создан для отправки запросов в формате multipart/form-data.

Базовый синтаксис curl -F

curl -F "имя_поля=значение" URL
curl -F "поле_файла=@/путь/к/файлу" URL
Формат параметра Описание Пример
-F "key=value" Отправка обычного текстового поля -F "prompt=Hello"
-F "key=@file" Загрузка локального файла -F "[email protected]"
-F "key=@file;type=mime" Указание MIME-типа файла -F "[email protected];type=image/jpeg"
-F "key=@file;filename=new.jpg" Кастомное имя файла при загрузке -F "[email protected];filename=upload.jpg"

В чем разница между curl -F и другими параметрами?

Многие разработчики часто путают -F, -d и -X POST. Давайте проясним:

# ❌ ОШИБКА: -d используется для x-www-form-urlencoded, он не подходит для файлов
curl -X POST -d "[email protected]" https://api.example.com/upload

# ❌ ОШИБКА: Вручную прописан Content-Type, но используется -d
curl -X POST -H "Content-Type: multipart/form-data" -d "..." https://api.example.com/upload

# ✅ ПРАВИЛЬНО: Используйте -F, он сам установит нужный Content-Type и boundary
curl -F "[email protected]" https://api.example.com/upload

Техническая справка: При использовании -F curl автоматически:

  1. Устанавливает метод запроса на POST.
  2. Прописывает заголовок Content-Type: multipart/form-data.
  3. Генерирует уникальный boundary (разделитель).
  4. Форматирует тело запроса согласно стандартам RFC.

Загрузка файлов в Sora 2 API: Практический пример

Sora 2 — это модель генерации видео от OpenAI, которая позволяет загружать референсные изображения для создания роликов. Это классический сценарий использования multipart/form-data.

Параметры API Sora 2 для генерации видео по картинке

Параметр Тип Обязательно Описание
prompt string Текстовое описание видео (промпт)
model string Выбор модели: sora-2 или sora-2-pro
size string Разрешение: 1280x720, 720x1280, 1024x1792, 1792x1024
seconds integer Длительность: 4, 8, 12 секунд
input_reference file Референсное изображение (первый кадр видео)

api-file-upload-multipart-form-data-guide-ru 图示

Сравнение моделей Sora 2

Характеристика sora-2 sora-2-pro
Качество генерации Хорошее Превосходное
Скорость рендеринга Быстрая Медленная
Сценарии использования Прототипы, проверка концепций Финальный продакшн
Цена Стандартная Высокая
Доступные платформы APIYI (apiyi.com), официальный API APIYI (apiyi.com), официальный API

Полный пример загрузки файла в Sora 2

Вот пример использования curl для вызова Sora 2 API и создания видео на основе картинки:

curl -X POST "https://api.apiyi.com/v1/videos" \
  -H "Authorization: Bearer $APIYI_KEY" \
  -H "Content-Type: multipart/form-data" \
  -F prompt="She turns around and smiles, then slowly walks out of the frame." \
  -F model="sora-2-pro" \
  -F size="1280x720" \
  -F seconds="8" \
  -F input_reference="@sample_720p.jpeg;type=image/jpeg"

Разбор команды

Часть Описание
curl -X POST Указывает метод запроса POST
"https://api.apiyi.com/v1/videos" Эндпоинт генерации видео в APIYI
-H "Authorization: Bearer $APIYI_KEY" Передача API-ключа через переменную окружения
-H "Content-Type: multipart/form-data" Объявление типа контента (curl -F добавит это сам)
-F prompt="..." Текстовый промпт с описанием видео
-F model="sora-2-pro" Выбор высококачественной модели
-F size="1280x720" Горизонтальное разрешение 720p
-F seconds="8" Длительность 8 секунд
-F input_reference="@sample_720p.jpeg;type=image/jpeg" Загрузка референсного изображения

🚀 Быстрый старт: Для тестирования Sora 2 API рекомендуем платформу APIYI (apiyi.com). Там всё работает «из коробки», и интеграцию можно выполнить без лишней головной боли.

На что обратить внимание при загрузке картинок

При работе с референсными изображениями в Sora 2 API учитывайте следующие моменты:

Требование Описание
Соответствие разрешению Разрешение картинки должно совпадать с параметром size будущего видео
Поддерживаемые форматы image/jpeg, image/png, image/webp
Размер файла Рекомендуется не более 10 МБ
Качество картинки Чем четче изображение и лучше композиция, тем круче будет результат

Реализация загрузки multipart/form-data на Python

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

Минималистичный пример

import requests

# 使用 APIYI 统一接口
url = "https://api.apiyi.com/v1/videos"
headers = {"Authorization": "Bearer YOUR_API_KEY"}

# 准备 multipart 数据
files = {
    "input_reference": ("sample.jpeg", open("sample_720p.jpeg", "rb"), "image/jpeg")
}
data = {
    "prompt": "She turns around and smiles, then slowly walks out of the frame.",
    "model": "sora-2-pro",
    "size": "1280x720",
    "seconds": "8"
}

response = requests.post(url, headers=headers, data=data, files=files)
print(response.json())
Посмотреть полный код (с обработкой ошибок и опросом состояния)
import requests
import time
import os

class Sora2Client:
    """Sora 2 API 客户端 - 支持 multipart/form-data 文件上传"""

    def __init__(self, api_key: str, base_url: str = "https://api.apiyi.com/v1"):
        self.api_key = api_key
        self.base_url = base_url
        self.headers = {"Authorization": f"Bearer {api_key}"}

    def create_video(
        self,
        prompt: str,
        model: str = "sora-2",
        size: str = "1280x720",
        seconds: int = 8,
        input_reference: str = None
    ) -> dict:
        """
        创建视频生成任务

        Args:
            prompt: 视频描述
            model: 模型选择 (sora-2 或 sora-2-pro)
            size: 分辨率
            seconds: 时长 (4, 8, 12)
            input_reference: 参考图片路径 (可选)

        Returns:
            任务信息字典
        """
        url = f"{self.base_url}/videos"

        data = {
            "prompt": prompt,
            "model": model,
            "size": size,
            "seconds": str(seconds)
        }

        files = None
        if input_reference and os.path.exists(input_reference):
            # 根据文件扩展名确定 MIME 类型
            ext = os.path.splitext(input_reference)[1].lower()
            mime_types = {
                ".jpg": "image/jpeg",
                ".jpeg": "image/jpeg",
                ".png": "image/png",
                ".webp": "image/webp"
            }
            mime_type = mime_types.get(ext, "application/octet-stream")

            files = {
                "input_reference": (
                    os.path.basename(input_reference),
                    open(input_reference, "rb"),
                    mime_type
                )
            }

        try:
            response = requests.post(
                url,
                headers=self.headers,
                data=data,
                files=files,
                timeout=30
            )
            response.raise_for_status()
            return response.json()
        except requests.exceptions.RequestException as e:
            return {"error": str(e)}
        finally:
            if files and "input_reference" in files:
                files["input_reference"][1].close()

    def get_video_status(self, video_id: str) -> dict:
        """查询视频生成状态"""
        url = f"{self.base_url}/videos/{video_id}"
        response = requests.get(url, headers=self.headers, timeout=30)
        return response.json()

    def wait_for_completion(self, video_id: str, poll_interval: int = 10) -> dict:
        """轮询等待视频生成完成"""
        while True:
            status = self.get_video_status(video_id)
            if status.get("status") in ["completed", "failed"]:
                return status
            print(f"Status: {status.get('status')}... waiting {poll_interval}s")
            time.sleep(poll_interval)


# 使用示例
if __name__ == "__main__":
    client = Sora2Client(api_key=os.getenv("APIYI_KEY"))

    # 创建图生视频任务
    result = client.create_video(
        prompt="She turns around and smiles, then slowly walks out of the frame.",
        model="sora-2-pro",
        size="1280x720",
        seconds=8,
        input_reference="sample_720p.jpeg"
    )

    if "id" in result:
        print(f"Task created: {result['id']}")
        final_result = client.wait_for_completion(result["id"])
        print(f"Video URL: {final_result.get('video_url')}")
    else:
        print(f"Error: {result}")

Совет: Получите бесплатные тестовые баллы на APIYI (apiyi.com), чтобы быстро протестировать функцию генерации видео из изображений.

Обработка multipart в библиотеке requests

Ключевые моменты при работе с multipart/form-data в библиотеке Python requests:

Параметр Назначение Описание
data Обычные поля формы Формат словаря: {"key": "value"}
files Поля файлов Формат кортежа: {"name": (filename, file_obj, content_type)}

⚠️ Внимание: При одновременном использовании параметров data и files, requests автоматически установит правильный Content-Type и boundary, указывать их вручную не нужно.


Реализация на JavaScript/Node.js

Браузерная среда (FormData API)

const formData = new FormData();
formData.append('prompt', 'She turns around and smiles');
formData.append('model', 'sora-2-pro');
formData.append('size', '1280x720');
formData.append('seconds', '8');
formData.append('input_reference', fileInput.files[0]);

fetch('https://api.apiyi.com/v1/videos', {
    method: 'POST',
    headers: {
        'Authorization': 'Bearer YOUR_API_KEY'
        // 注意: 不要手动设置 Content-Type
    },
    body: formData
})
.then(response => response.json())
.then(data => console.log(data));

Среда Node.js

const FormData = require('form-data');
const fs = require('fs');
const axios = require('axios');

const form = new FormData();
form.append('prompt', 'She turns around and smiles');
form.append('model', 'sora-2-pro');
form.append('size', '1280x720');
form.append('seconds', '8');
form.append('input_reference', fs.createReadStream('sample_720p.jpeg'), {
    contentType: 'image/jpeg'
});

axios.post('https://api.apiyi.com/v1/videos', form, {
    headers: {
        ...form.getHeaders(),
        'Authorization': 'Bearer YOUR_API_KEY'
    }
})
.then(response => console.log(response.data));

💡 Важный совет: При использовании FormData в браузере не нужно вручную устанавливать заголовок Content-Type. Браузер автоматически добавит корректный параметр boundary.


Устранение распространенных проблем с multipart/form-data

Основные причины неудачной загрузки

Проблема Симптомы Решение
Отсутствие boundary Сервер возвращает 400 Не устанавливайте Content-Type вручную, позвольте инструменту сгенерировать его автоматически
Ошибка типа MIME Файл отклонен Явно укажите тип с помощью ;type=image/jpeg
Ошибка пути к файлу Файл не найден Убедитесь, что путь после символа @ указан верно; поддерживаются как относительные, так и абсолютные пути
Несоответствие разрешения Ошибка Sora API Разрешение изображения должно строго совпадать с параметром size
Файл слишком большой Таймаут или отказ Сожмите изображение или используйте загрузку по частям (чанками)

Советы по отладке

Используйте флаг -v в curl, чтобы просмотреть детали запроса:

curl -v -F "[email protected]" https://api.example.com/upload

Это покажет:

  • Заголовки запроса (включая автоматически сгенерированный Content-Type и boundary)
  • Структуру тела запроса
  • Ответ сервера

Часто задаваемые вопросы

Q1: Что лучше: multipart/form-data или кодирование в Base64?

Для загрузки файлов multipart/form-data подходит гораздо лучше. Base64 увеличивает объем данных примерно на 33%, что создает лишнюю нагрузку на сеть и замедляет обработку на стороне сервера. Multipart передает бинарные данные напрямую, поэтому он эффективнее.

Однако в некоторых случаях (например, при работе с WebSocket или API, принимающими только JSON), Base64 может быть единственным вариантом. При работе через платформу APIYI apiyi.com мы рекомендуем отдавать приоритет multipart/form-data для лучшей производительности.

Q2: Почему мой запрос curl -F завершается ошибкой?

Самые частые причины:

  1. Проблемы с путем: Убедитесь, что после символа @ идет корректный путь к файлу.
  2. Права доступа: Проверьте, есть ли у системы права на чтение этого файла.
  3. Тип MIME: Некоторые API требуют обязательного указания правильного content-type.

Советуем сначала протестировать запрос в среде APIYI apiyi.com — там можно получить подробную информацию об ошибках и быстро понять, что пошло не так.

Q3: Какие форматы изображений поддерживает Sora 2 API?

Для параметра input_reference в Sora 2 API поддерживаются следующие форматы:

  • JPEG (.jpg, .jpeg) — рекомендуемый вариант, хорошее сжатие.
  • PNG (.png) — если нужна прозрачность.
  • WebP (.webp) — современный формат с небольшим весом.

Разрешение изображения должно соответствовать параметру size целевого видео. Например, если вы создаете видео 1280x720, референсное изображение тоже должно быть 1280x720.

Q4: Как лучше всего загружать большие файлы?

Если файл весит много, попробуйте следующее:

  1. Загрузка по частям (Chunking): разбейте файл на небольшие блоки и отправляйте их по очереди.
  2. Оптимизация: сожмите файл перед отправкой, если это не критично для качества.
  3. Дозагрузка: используйте механизмы, позволяющие продолжить загрузку с места обрыва.

Кстати, multipart/form-data поддерживает потоковую передачу — сервер может начать обработку данных, не дожидаясь окончания загрузки всего файла, что отлично подходит для больших объектов.


Итоги

В этой статье мы подробно разобрали ключевую технологию загрузки файлов через API — multipart/form-data:

Вспомним основные моменты:

Ключевой момент Описание
Принцип кодирования Разделитель boundary разбивает данные на части, у каждой из которых свой Content-Type
Команда curl -F -F "key=value" для отправки текста, -F "key=@file" для загрузки файла
Практика с Sora 2 Параметр input_reference для загрузки референсных изображений (разрешение должно совпадать)
Реализация на разных языках Python requests / JavaScript FormData
Советы по отладке Используйте curl -v для просмотра полного лога запроса

Понимание того, как работает multipart/form-data, — это базовый навык для разработки с использованием AI API. Будь то генерация видео в Sora 2, компьютерное зрение в GPT-4 Vision или любые другие интерфейсы, требующие передачи файлов, — фундаментальные принципы везде одинаковы.

Рекомендуем использовать APIYI (apiyi.com) для быстрой проверки функций загрузки файлов. Попробуйте унифицированный API и воспользуйтесь подробной технической поддержкой.


Автор: Команда APIYI | Делимся технологиями API больших языковых моделей
Техническое сообщество: Посетите apiyi.com для получения дополнительных ресурсов по разработке

Справочные материалы

  1. RFC 2388: Спецификация стандарта multipart/form-data

    • Ссылка: tools.ietf.org/html/rfc2388
  2. Документация curl: Multipart Formposts

    • Ссылка: everything.curl.dev/http/post/multipart
  3. MDN Web Docs: Использование объектов FormData

    • Ссылка: developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest_API/Using_FormData_Objects
  4. Документация OpenAI Sora API: Руководство по генерации видео

    • Ссылка: platform.openai.com/docs/guides/video-generation

Похожие записи