|

Dominar la carga de archivos por API: guía completa de multipart/form-data y ejemplo práctico de Sora 2

La subida de archivos vía API es un requisito técnico común para los desarrolladores al llamar a interfaces de generación de vídeo por IA, procesamiento de imágenes, entre otras. En este artículo, explicaremos de forma sistemática el funcionamiento del método de codificación multipart/form-data, tomando como ejemplo la API de imagen a vídeo de Sora 2, para ayudarte a dominar esta habilidad fundamental.

Valor principal: Al terminar de leer este artículo, comprenderás por completo el mecanismo interno de multipart/form-data, aprenderás a usar el comando curl -F para subir archivos y podrás implementar por tu cuenta la subida de imágenes para APIs de IA como Sora 2.

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


Conocimientos fundamentales sobre la subida de archivos vía API

Antes de profundizar en el código, necesitamos entender por qué la subida de archivos por API requiere un método de codificación especial.

¿Por qué es necesario multipart/form-data?

Cuando envías datos de texto normales a través de una API, puedes usar la codificación simple application/x-www-form-urlencoded. Sin embargo, este método presenta problemas graves al manejar archivos:

Tipo de codificación Casos de uso Capacidad de manejo de archivos Eficiencia
application/x-www-form-urlencoded Pares clave-valor simples ❌ No apto El binario requiere escape URL, baja eficiencia
application/json Datos estructurados ⚠️ Requiere codificación Base64 El tamaño aumenta un 33%
multipart/form-data Subida de archivos ✅ Soporte nativo Sin codificación, eficiente

multipart/form-data es una solución propuesta en el estándar RFC 2388 de 1998, diseñada específicamente para resolver el problema de enviar texto y datos binarios de forma mixta en el protocolo HTTP.

Cómo funciona multipart/form-data

La idea central de multipart/form-data es dividir el cuerpo de una solicitud HTTP en múltiples "partes" (parts) independientes, donde cada parte puede tener su propio tipo de contenido.

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

Detalles de la estructura de datos

Una solicitud multipart/form-data típica contiene la siguiente estructura:

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

[Datos binarios de imagen]
------WebKitFormBoundary7MA4YWxk--
Componente Función Ejemplo
Boundary Identificador único que separa las partes de los datos ----WebKitFormBoundary7MA4YWxk
Content-Disposition Metadatos que describen esa parte form-data; name="prompt"
Content-Type Tipo MIME de esa parte image/jpeg
Body Contenido de los datos reales Datos de texto o binarios

🎯 Punto técnico clave: El Boundary debe ser una cadena única que no aparezca en el cuerpo de la solicitud. El servidor utiliza este límite para analizar y separar cada una de las partes de los datos.


Guía detallada del comando curl -F: Subida de archivos a la API en la práctica

curl es la herramienta de línea de comandos más utilizada como cliente HTTP, y su parámetro -F está diseñado específicamente para peticiones multipart/form-data.

Sintaxis básica de curl -F

curl -F "nombre_del_campo=valor" URL
curl -F "campo_archivo=@ruta_del_archivo_local" URL
Formato del parámetro Descripción Ejemplo
-F "key=value" Envía un campo de texto normal -F "prompt=Hola"
-F "key=@file" Sube un archivo local -F "[email protected]"
-F "key=@file;type=mime" Especifica el tipo MIME del archivo -F "[email protected];type=image/jpeg"
-F "key=@file;filename=new.jpg" Personaliza el nombre del archivo subido -F "[email protected];filename=subida.jpg"

Diferencias entre curl -F y otros parámetros

Muchos desarrolladores suelen confundir el uso de -F, -d y -X POST:

# ❌ INCORRECTO: -d se usa para x-www-form-urlencoded, no es apto para subir archivos
curl -X POST -d "[email protected]" https://api.example.com/upload

# ❌ INCORRECTO: Especificar manualmente Content-Type pero usar -d
curl -X POST -H "Content-Type: multipart/form-data" -d "..." https://api.example.com/upload

# ✅ CORRECTO: Usar -F establece automáticamente el Content-Type y el boundary correctos
curl -F "[email protected]" https://api.example.com/upload

Nota técnica: Al usar -F, curl automáticamente:

  1. Establece el método de petición como POST.
  2. Configura Content-Type: multipart/form-data.
  3. Genera un boundary único.
  4. Formatea el cuerpo de la petición según el estándar RFC.

Sora 2 API: Subida de archivos en la práctica

Sora 2 es el modelo de generación de vídeo lanzado por OpenAI que permite subir imágenes de referencia a través de su API para generar vídeos. Este es un escenario típico de uso de multipart/form-data.

Parámetros de la API de Sora 2 (Imagen a Vídeo)

Parámetro Tipo Obligatorio Descripción
prompt string Texto descriptivo (indicación) del vídeo
model string Selección de modelo: sora-2 o sora-2-pro
size string Resolución: 1280x720, 720x1280, 1024x1792, 1792x1024
seconds integer Duración: 4, 8, 12 segundos
input_reference file Imagen de referencia, usada como primer fotograma

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

Comparativa de modelos Sora 2

Característica sora-2 sora-2-pro
Calidad de generación Buena Excelente
Velocidad de renderizado Más rápida Más lenta
Uso recomendado Prototipado rápido, pruebas Salida de nivel de producción
Precio Estándar Más alto
Plataformas disponibles APIYI apiyi.com, API oficial APIYI apiyi.com, API oficial

Ejemplo completo de subida con Sora 2

A continuación se muestra un ejemplo completo de cómo usar curl para llamar a la API de Sora 2 y generar un vídeo a partir de una imagen:

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"

Desglose del comando

Parte Descripción
curl -X POST Especifica el método de petición POST
"https://api.apiyi.com/v1/videos" Endpoint de generación de vídeo de Sora 2 en APIYI
-H "Authorization: Bearer $APIYI_KEY" Pasa la clave de API mediante una variable de entorno
-H "Content-Type: multipart/form-data" Declara el tipo de contenido (curl -F lo añade automáticamente)
-F prompt="..." La indicación (prompt) descriptiva del vídeo
-F model="sora-2-pro" Selección del modelo de alta calidad
-F size="1280x720" Resolución horizontal 720p
-F seconds="8" Duración de 8 segundos
-F input_reference="@sample_720p.jpeg;type=image/jpeg" Sube la imagen de referencia

🚀 Inicio rápido: Te recomiendo usar la plataforma APIYI (apiyi.com) para probar rápidamente la API de Sora 2. Ofrece interfaces listas para usar que permiten la integración sin configuraciones complejas.

Puntos a tener en cuenta al subir imágenes

Al usar la API de Sora 2 para subir imágenes de referencia, ten en cuenta:

Requisito Descripción
Ajuste de resolución La resolución de la imagen debe coincidir con el parámetro size del vídeo
Formatos compatibles image/jpeg, image/png, image/webp
Tamaño de archivo Se recomienda no exceder los 10MB
Calidad de imagen Imágenes nítidas y con buena composición ofrecen mejores resultados

Implementación de subida multipart/form-data en Python

Además de curl, en el desarrollo real es más común utilizar lenguajes de programación para realizar la subida de archivos. A continuación, se muestra cómo hacerlo con Python.

Ejemplo minimalista

import requests

# Uso de la interfaz unificada de APIYI
url = "https://api.apiyi.com/v1/videos"
headers = {"Authorization": "Bearer YOUR_API_KEY"}

# Preparación de datos 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())
Ver código completo (incluye manejo de errores y sondeo)
import requests
import time
import os

class Sora2Client:
    """Cliente de la API de Sora 2 - Soporta subida de archivos 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:
        """
        Crear tarea de generación de video

        Args:
            prompt: descripción del video (indicación)
            model: selección de modelo (sora-2 o sora-2-pro)
            size: resolución
            seconds: duración (4, 8, 12)
            input_reference: ruta de la imagen de referencia (opcional)

        Returns:
            Diccionario con la información de la tarea
        """
        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):
            # Determinar el tipo MIME según la extensión del archivo
            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:
        """Consultar el estado de generación del video"""
        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:
        """Sondeo (polling) para esperar a que se complete la generación del video"""
        while True:
            status = self.get_video_status(video_id)
            if status.get("status") in ["completed", "failed"]:
                return status
            print(f"Status: {status.get('status')}... esperando {poll_interval}s")
            time.sleep(poll_interval)


# Ejemplo de uso
if __name__ == "__main__":
    client = Sora2Client(api_key=os.getenv("APIYI_KEY"))

    # Crear tarea de imagen a video
    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"Tarea creada: {result['id']}")
        final_result = client.wait_for_completion(result["id"])
        print(f"URL del video: {final_result.get('video_url')}")
    else:
        print(f"Error: {result}")

Sugerencia: Obtén cuota de prueba gratuita en APIYI (apiyi.com) para validar rápidamente la función de imagen a video.

Manejo de multipart en la librería requests

Puntos clave para manejar multipart/form-data con la librería requests de Python:

Parámetro Uso Descripción
data Campos normales del formulario Formato de diccionario: {"key": "value"}
files Campos de archivo Formato de tupla: {"name": (filename, file_obj, content_type)}

⚠️ Nota: Al usar simultáneamente los parámetros data y files, requests configurará automáticamente el Content-Type y el boundary correctos; no es necesario especificarlos manualmente.


Solución en JavaScript/Node.js

Entorno de navegador (API FormData)

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'
        // Nota: NO establezcas manualmente el Content-Type
    },
    body: formData
})
.then(response => response.json())
.then(data => console.log(data));

Entorno 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));

💡 Consejo clave: Al usar FormData en el navegador, no configures manualmente el encabezado Content-Type. El navegador agregará automáticamente el parámetro boundary correcto.


Solución de problemas comunes de multipart/form-data

Causas comunes de fallos en la carga

Problema Síntoma Solución
Falta el boundary El servidor devuelve 400 No configures el Content-Type manualmente, deja que la herramienta lo genere automáticamente
Error en el tipo MIME Archivo rechazado Usa ;type=image/jpeg para especificarlo claramente
Ruta de archivo incorrecta No se encuentra el archivo Asegúrate de que la ruta tras el @ sea correcta; soporta rutas relativas/absolutas
Resolución no coincidente Error en la API de Sora La resolución de la imagen debe coincidir con el parámetro size
Archivo demasiado grande Tiempo de espera agotado o rechazado Comprime la imagen o usa carga por fragmentos

Consejos de depuración

Usa el parámetro -v de curl para ver la solicitud completa:

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

Esto mostrará:

  • Encabezados de la solicitud (incluyendo el Content-Type y boundary autogenerados)
  • Estructura del cuerpo de la solicitud
  • Respuesta del servidor

Preguntas frecuentes

Q1: ¿Qué es mejor: multipart/form-data o codificación Base64?

multipart/form-data es más adecuado para cargar archivos. La codificación Base64 aumenta el tamaño del archivo aproximadamente un 33%, lo que incrementa el tiempo de transmisión de red y la carga de procesamiento del servidor. multipart/form-data transmite datos binarios directamente, lo que resulta en una mayor eficiencia.

Sin embargo, en ciertos escenarios (como WebSockets o APIs JSON de un solo campo), Base64 puede ser la única opción. Al llamar a APIs a través de la plataforma APIYI (apiyi.com), priorizar el uso de multipart/form-data te brindará un mejor rendimiento.

Q2: ¿Por qué falla mi carga con curl -F?

Las causas comunes incluyen:

  1. Problemas con la ruta del archivo: Asegúrate de que el símbolo @ vaya seguido de la ruta correcta del archivo.
  2. Problemas de permisos: Revisa los permisos de lectura del archivo.
  3. Tipo MIME: Algunas APIs requieren que se especifique el content-type correcto.

Se recomienda validar primero el formato de la solicitud en el entorno de pruebas de APIYI (apiyi.com); la plataforma ofrece mensajes de error detallados para ayudarte a localizar el problema rápidamente.

Q3: ¿Qué formatos de imagen soporta la API de Sora 2?

La API de Sora 2 admite los siguientes formatos de imagen para input_reference:

  • JPEG (.jpg, .jpeg): Recomendado, buena tasa de compresión.
  • PNG (.png): Soporta canales de transparencia.
  • WebP (.webp): Formato moderno, tamaño de archivo pequeño.

La resolución de la imagen debe coincidir con el parámetro size del vídeo de destino. Por ejemplo, si usas una resolución de 1280x720, la imagen de referencia también debe ser de 1280×720.

Q4: ¿Cómo manejar la carga de archivos grandes?

Para archivos grandes, puedes considerar:

  1. Carga por fragmentos: Dividir el archivo en trozos pequeños y subirlos secuencialmente.
  2. Optimización por compresión: Comprimir el archivo manteniendo la calidad necesaria.
  3. Reanudación de carga: Implementar soporte para continuar la subida desde el punto donde falló.

multipart/form-data admite la transmisión por flujo (streaming), lo que permite al servidor procesar los datos mientras los recibe, siendo ideal para escenarios de archivos de gran tamaño.


Resumen

Este artículo detalla la tecnología central para la carga de archivos en API: multipart/form-data.

Repaso de puntos clave:

Punto clave Descripción
Principio de codificación El boundary separa los datos en varias partes; cada parte tiene su propio Content-Type independiente.
Comando curl -F -F "key=value" envía texto, -F "key=@file" carga un archivo.
Práctica con Sora 2 Uso del parámetro input_reference para subir imágenes de referencia; la resolución debe coincidir.
Implementación en varios lenguajes Uso de requests en Python o FormData en JavaScript.
Consejos de depuración Usar curl -v para visualizar la solicitud completa.

Dominar multipart/form-data es una habilidad fundamental para el desarrollo con APIs de IA. Ya sea para la generación de video con Sora 2, la comprensión de imágenes con GPT-4 Vision o cualquier otra API que requiera la carga de archivos, los principios básicos son los mismos.

Te recomendamos usar APIYI (apiyi.com) para validar rápidamente la función de carga de archivos y experimentar con una interfaz de API unificada y soporte técnico detallado.


Autor: Equipo APIYI | Especialistas en compartir tecnología de APIs de Modelos de Lenguaje Grande
Intercambio técnico: Visita apiyi.com para obtener más recursos de desarrollo de APIs.

Referencias

  1. RFC 2388: Especificación estándar de multipart/form-data

    • Enlace: tools.ietf.org/html/rfc2388
  2. Documentación oficial de curl: Multipart Formposts

    • Enlace: everything.curl.dev/http/post/multipart
  3. MDN Web Docs: Uso de objetos FormData

    • Enlace: developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest_API/Using_FormData_Objects
  4. Documentación de la API de OpenAI Sora: Guía de generación de video

    • Enlace: platform.openai.com/docs/guides/video-generation

Publicaciones Similares