Поделиться через


Краткое руководство. Создание видео с помощью Sora (предварительная версия)

Замечание

Этот документ относится к порталу Microsoft Foundry (классическая модель).

🔄 Перейдите к новой документации Microsoft Foundry если вы используете новый портал.

Замечание

Этот документ относится к порталу Microsoft Foundry (new).

В этом кратком руководстве показано, как создать видеоклипы с помощью службы Azure OpenAI. В примере используется модель Sora, которая является моделью создания видео, которая создает реалистичные и образные видео сцены из текстовых инструкций и (или) изображений или видео входных данных. В этом руководстве показано, как создать задание создания видео, провести опрос по его состоянию и получить созданное видео.

Дополнительные сведения о создании видео см. в концепциях создания видео.

Предпосылки

Предварительные требования для идентификатора Microsoft Entra

Для рекомендуемой проверки подлинности без ключа с помощью идентификатора Microsoft Entra необходимо:

  • Установите Azure CLI, используемый для проверки подлинности без ключа с помощью идентификатора Microsoft Entra.
  • Назначьте роль Cognitive Services User своему аккаунту пользователя. Роли можно назначить в портале Azure в разделе Контроль доступа (IAM)>Добавить назначение ролей.

Настройка

  1. Создайте новую папку video-generation-quickstart и перейдите в папку быстрого запуска, используя следующую команду:

    mkdir video-generation-quickstart && cd video-generation-quickstart
    
  2. Создайте виртуальную среду. Если у вас уже установлен Python 3.10 или более поздней версии, можно создать виртуальную среду с помощью следующих команд:

    Виндоус

    py -3 -m venv .venv
    .venv\scripts\activate
    

    Линукс

    python3 -m venv .venv
    source .venv/bin/activate
    

    macOS

    python3 -m venv .venv
    source .venv/bin/activate
    

    Активация среды Python означает, что при запуске python или pip из командной строки используется интерпретатор Python, содержащийся в .venv папке приложения. Вы можете использовать deactivate команду для выхода из виртуальной среды Python, а затем повторно активировать ее при необходимости.

    Подсказка

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

  3. Установите необходимые пакеты.

    Идентификатор Microsoft Entra

    pip install requests azure-identity
    

    Ключ API

    pip install requests
    

Получение сведений о ресурсе

Чтобы проверить подлинность приложения с помощью ресурса Azure OpenAI, необходимо получить следующие сведения:

Имя переменной Ценность
AZURE_OPENAI_ENDPOINT Это значение можно найти в разделе "Ключи и конечная точка доступа" при просмотре ресурса на портале Azure.
AZURE_OPENAI_DEPLOYMENT_NAME Это значение будет соответствовать пользовательскому имени, которое вы выбрали при развертывании модели. Это значение можно найти в разделе Управление ресурсами>Развертывание моделей на портале Azure.

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

Создание видео с помощью Sora

Вы можете создать видео с помощью модели Sora, запустив задачу генерации видео, отслеживая её статус и получив созданное видео. В следующем коде показано, как это сделать с помощью REST API с помощью Python.

  1. sora-quickstart.py Создайте файл и добавьте следующий код для проверки подлинности ресурса:

    Идентификатор Microsoft Entra

    import json
    import requests
    import time
    import os
    from azure.identity import DefaultAzureCredential
    
    # Set environment variables or edit the corresponding values here.
    endpoint = os.environ.get('AZURE_OPENAI_ENDPOINT')
    deployment_name = os.environ.get('AZURE_OPENAI_DEPLOYMENT_NAME')
    if not endpoint or not deployment_name:
        raise ValueError("Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_DEPLOYMENT_NAME.")
    
    # Keyless authentication
    credential = DefaultAzureCredential()
    token = credential.get_token("https://cognitiveservices.azure.com/.default")
    
    api_version = 'preview'
    headers= { "Authorization": f"Bearer {token.token}", "Content-Type": "application/json" }
    

    Ключ API

    import json
    import requests
    import time
    import os
    
    # Set environment variables or edit the corresponding values here.
    endpoint = os.environ.get('AZURE_OPENAI_ENDPOINT')
    deployment_name = os.environ.get('AZURE_OPENAI_DEPLOYMENT_NAME')
    api_key = os.environ.get('AZURE_OPENAI_API_KEY')
    if not endpoint or not deployment_name or not api_key:
        raise ValueError(
            "Set AZURE_OPENAI_ENDPOINT, AZURE_OPENAI_DEPLOYMENT_NAME, and AZURE_OPENAI_API_KEY."
        )
    
    api_version = 'preview'
    headers= { "api-key": api_key, "Content-Type": "application/json" }
    
  2. Создайте задание создания видео. Его можно создать только из текстового запроса или из входного изображения и текстового запроса.

    Текстовый запрос

    # 1. Create a video generation job
    create_url = f"{endpoint}/openai/v1/video/generations/jobs?api-version={api_version}"
    body = {
        "prompt": "A cat playing piano in a jazz bar.",
        "width": 480,
        "height": 480,
        "n_seconds": 5,
        "model": deployment_name
    }
    response = requests.post(create_url, headers=headers, json=body)
    response.raise_for_status()
    print("Full response JSON:", response.json())
    job_id = response.json()["id"]
    print(f"Job created: {job_id}")
    
    # 2. Poll for job status
    status_url = f"{endpoint}/openai/v1/video/generations/jobs/{job_id}?api-version={api_version}"
    status=None
    while status not in ("succeeded", "failed", "cancelled"):
        time.sleep(5)  # Wait before polling again
        status_response = requests.get(status_url, headers=headers).json()
        status = status_response.get("status")
        print(f"Job status: {status}")
    
    # 3. Retrieve generated video 
    if status == "succeeded":
        generations = status_response.get("generations", [])
        if generations:
            print(f"✅ Video generation succeeded.")
            generation_id = generations[0].get("id")
            video_url = f"{endpoint}/openai/v1/video/generations/{generation_id}/content/video?api-version={api_version}"
            video_response = requests.get(video_url, headers=headers)
            if video_response.ok:
                output_filename = "output.mp4"
                with open(output_filename, "wb") as file:
                    file.write(video_response.content)
                    print(f'Generated video saved as "{output_filename}"')
        else:
            raise Exception("No generations found in job result.")
    else:
        raise Exception(f"Job didn't succeed. Status: {status}")
    

    Запрос изображения

    Замените "file_name" поле в "inpaint_items" имени входного файла изображения. Кроме того, замените построение массива files , которое связывает путь к фактическому файлу с именем файла, который использует API.

    "crop_bounds" Используйте данные (расстояния обрезки изображения, от каждого направления в качестве доли общих измерений изображения), чтобы указать, какая часть изображения должна использоваться в создании видео.

    При необходимости можно задать "frame_index" кадр в созданном видео, где должно отображаться изображение (значение по умолчанию — 0, начало видео).

    # 1. Create a video generation job with image inpainting (multipart upload)
    create_url = f"{endpoint}/openai/v1/video/generations/jobs?api-version={api_version}"
    
    # Flatten the body for multipart/form-data
    data = {
        "prompt": "A serene forest scene transitioning into autumn",
        "height": str(1080),
        "width": str(1920),
        "n_seconds": str(10),
        "n_variants": str(1),
        "model": deployment_name,
        # inpaint_items must be JSON string
        "inpaint_items": json.dumps([
            {
                "frame_index": 0,
                "type": "image",
                "file_name": "dog_swimming.jpg",
                "crop_bounds": {
                    "left_fraction": 0.1,
                    "top_fraction": 0.1,
                    "right_fraction": 0.9,
                    "bottom_fraction": 0.9
                }
            }
        ])
    }
    
    # Replace with your own image file path
    with open("dog_swimming.jpg", "rb") as image_file:
        files = [
            ("files", ("dog_swimming.jpg", image_file, "image/jpeg"))
        ]
        multipart_headers = {k: v for k, v in headers.items() if k.lower() != "content-type"}
        response = requests.post(
            create_url,
            headers=multipart_headers,
            data=data,
            files=files
        )
    
    if not response.ok:
        print("Error response:", response.status_code, response.text)
        response.raise_for_status()
    print("Full response JSON:", response.json())
    job_id = response.json()["id"]
    print(f"Job created: {job_id}")
    
    # 2. Poll for job status
    status_url = f"{endpoint}/openai/v1/video/generations/jobs/{job_id}?api-version={api_version}"
    status = None
    while status not in ("succeeded", "failed", "cancelled"):
        time.sleep(5)
        status_response = requests.get(status_url, headers=headers).json()
        status = status_response.get("status")
        print(f"Job status: {status}")
    
    # 3. Retrieve generated video
    if status == "succeeded":
        generations = status_response.get("generations", [])
        if generations:
            generation_id = generations[0].get("id")
            video_url = f"{endpoint}/openai/v1/video/generations/{generation_id}/content/video?api-version={api_version}"
            video_response = requests.get(video_url, headers=headers)
            if video_response.ok:
                output_filename = "output.mp4"
                with open(output_filename, "wb") as file:
                    file.write(video_response.content)
                    print(f'✅ Generated video saved as "{output_filename}"')
        else:
            raise Exception("No generations found in job result.")
    else:
        raise Exception(f"Job didn't succeed. Status: {status}")
    

    Запрос видео

    Замените поле "file_name" в "inpaint_items" на имя вашего входного видеофайла. Кроме того, замените построение массива files , которое связывает путь к фактическому файлу с именем файла, который использует API.

    Используйте данные "crop_bounds" (расстояния обрезки изображения, в каждом направлении, как долю от общего размера кадра), чтобы указать, какая часть кадра видео должна использоваться в видео обработке.

    При необходимости можно задать "frame_index" с кадра в созданном видео, где должно начинаться входное видео (по умолчанию — 0, начало).

    # 1. Create a video generation job with video inpainting (multipart upload)
    create_url = f"{endpoint}/openai/v1/video/generations/jobs?api-version={api_version}"
    
    # Flatten the body for multipart/form-data
    data = {
        "prompt": "A serene forest scene transitioning into autumn",
        "height": str(1080),
        "width": str(1920),
        "n_seconds": str(10),
        "n_variants": str(1),
        "model": deployment_name,
        # inpaint_items must be JSON string
        "inpaint_items": json.dumps([
            {
                "frame_index": 0,
                "type": "video",
                "file_name": "dog_swimming.mp4",
                "crop_bounds": {
                    "left_fraction": 0.1,
                    "top_fraction": 0.1,
                    "right_fraction": 0.9,
                    "bottom_fraction": 0.9
                }
            }
        ])
    }
    
    # Replace with your own video file path
    with open("dog_swimming.mp4", "rb") as video_file:
        files = [
            ("files", ("dog_swimming.mp4", video_file, "video/mp4"))
        ]
        multipart_headers = {k: v for k, v in headers.items() if k.lower() != "content-type"}
        response = requests.post(
            create_url,
            headers=multipart_headers,
            data=data,
            files=files
        )
    
    if not response.ok:
        print("Error response:", response.status_code, response.text)
        response.raise_for_status()
    print("Full response JSON:", response.json())
    job_id = response.json()["id"]
    print(f"Job created: {job_id}")
    
    # 2. Poll for job status
    status_url = f"{endpoint}/openai/v1/video/generations/jobs/{job_id}?api-version={api_version}"
    status = None
    while status not in ("succeeded", "failed", "cancelled"):
        time.sleep(5)
        status_response = requests.get(status_url, headers=headers).json()
        status = status_response.get("status")
        print(f"Job status: {status}")
    
    # 3. Retrieve generated video
    if status == "succeeded":
        generations = status_response.get("generations", [])
        if generations:
            generation_id = generations[0].get("id")
            video_url = f"{endpoint}/openai/v1/video/generations/{generation_id}/content/video?api-version={api_version}"
            video_response = requests.get(video_url, headers=headers)
            if video_response.ok:
                output_filename = "output.mp4"
                with open(output_filename, "wb") as file:
                    file.write(video_response.content)
                    print(f'✅ Generated video saved as "{output_filename}"')
        else:
            raise Exception("No generations found in job result.")
    else:
        raise Exception(f"Job didn't succeed. Status: {status}")
    
  3. Запустите файл Python.

    python sora-quickstart.py
    

    Подождите несколько минут, чтобы получить ответ.

Выходные данные

Выходные данные будут отображать полный ответ JSON из запроса на создание задания создания видео, включая идентификатор задания и состояние.

{
    "object": "video.generation.job",
    "id": "task_01jwcet0eje35tc5jy54yjax5q",
    "status": "queued",
    "created_at": 1748469875,
    "finished_at": null,
    "expires_at": null,
    "generations": [],
    "prompt": "A cat playing piano in a jazz bar.",
    "model": "<your-deployment-name>",
    "n_variants": 1,
    "n_seconds": 5,
    "height": 480,
    "width": 480,
    "failure_reason": null
}

Созданное видео будет сохранено как output.mp4 в текущем каталоге.

Job created: task_01jwcet0eje35tc5jy54yjax5q
Job status: preprocessing
Job status: running
Job status: processing
Job status: succeeded
✅ Video generation succeeded.
Generated video saved as "output.mp4"

Предпосылки

Перейдите на портал Microsoft Foundry

Перейдите на портал Foundry и войдите с учетными данными, связанными с ресурсом Azure OpenAI. Во время или после рабочего процесса входа выберите соответствующий каталог, подписку Azure и ресурс Azure OpenAI.

На целевой странице Foundry создайте или выберите новый проект. Перейдите на страницу "Модели + конечные точки" на левой панели навигации . Выберите "Развернуть модель " и выберите модель создания видео Sora из списка. Завершите процесс развертывания.

На странице модели выберите "Открыть на детской площадке".

Попробуйте создание видео

Начните изучать создание видео Sora с использованием подхода без кода на игровой площадке Видео. Введите запрос в текстовое поле и нажмите кнопку "Создать". Когда видео, созданное СИ, будет готово, оно отображается на странице.

Замечание

API создания содержимого входят в фильтр модерации содержимого. Если Azure OpenAI распознает запрос как вредное содержимое, он не возвращает созданное видео. Дополнительные сведения см. в разделе "Фильтрация содержимого".

На игровой площадке видео вы также можете просматривать примеры кода Python и cURL, которые предварительно заполнены в соответствии с параметрами. Нажмите кнопку кода в верхней части области воспроизведения видео. Этот код можно использовать для записи приложения, которое завершает ту же задачу.

Очистите ресурсы

Если вы хотите очистить и удалить ресурс Azure OpenAI, его можно удалить. Перед удалением ресурса необходимо сначала удалить все развернутые модели.