Community .NET SDK for Azure OpenAI Sora video generation with enhanced prompt suggestions and job management.
$ dotnet add package AzureSoraSDKAzure OpenAI "Sora" Video Generation & Prompt Enhancement SDK

📚 Documentation Wiki | 📋 Changelog | 📦 NuGet Package
This is a community-driven SDK for Azure OpenAI Sora video generation and prompt enhancement. The SDK provides a comprehensive .NET solution for generating high-quality videos using Azure OpenAI's Sora model, with built-in prompt enhancement capabilities to help you create more compelling video content.
IServiceCollection extensions# Install from NuGet
dotnet add package AzureSoraSDK
# Or via Package Manager
Install-Package AzureSoraSDK
using AzureSoraSDK;
using System;
var endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT")!;
var apiKey = Environment.GetEnvironmentVariable("AZURE_OPENAI_KEY")!;
var deployment = "sora";
using var client = new SoraClient(endpoint, apiKey, deployment);
// Submit a video job
var jobId = await client.SubmitVideoJobAsync(
prompt: "A serene sunset over mountain peaks, 10 seconds",
width: 1280,
height: 720,
nSeconds: 10
);
// Wait for completion
var videoUri = await client.WaitForCompletionAsync(jobId);
// Download the video
await client.DownloadVideoAsync(videoUri, "output.mp4");
using AzureSoraSDK;
// Generate video with aspect ratio and quality presets
var jobId = await client.SubmitVideoJobAsync(
prompt: "A beautiful sunset over mountains",
aspectRatio: "16:9",
quality: "high",
nSeconds: 10
);
// Calculate custom dimensions
var (width, height) = SoraClient.CalculateDimensionsFromAspectRatio("21:9", 2048);
// Returns: (2048, 880) - ultrawide cinema format
// Get common dimensions for aspect ratios
var (w, h) = SoraClient.GetCommonDimensions("1:1", "medium");
// Returns: (720, 720) - medium quality square video
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using AzureSoraSDK.Extensions;
using AzureSoraSDK.Interfaces;
// In your Startup.cs or Program.cs
var builder = WebApplication.CreateBuilder(args);
// Option 1: Separate configuration for video generation and prompt enhancement
builder.Services.AddAzureSoraSDK(
configureSoraOptions: options =>
{
options.Endpoint = "https://your-sora-endpoint.openai.azure.com";
options.ApiKey = "your-sora-api-key";
options.DeploymentName = "sora";
options.ApiVersion = "preview"; // Video generation API version
},
configurePromptEnhancerOptions: options =>
{
options.Endpoint = "https://your-chat-endpoint.openai.azure.com";
options.ApiKey = "your-chat-api-key";
options.DeploymentName = "gpt-4";
options.ApiVersion = "2024-02-15-preview"; // Chat completions API version
options.DefaultTemperature = 0.7;
options.MaxTokensPerRequest = 1500;
});
// Option 2: Configuration from appsettings.json with separate sections
builder.Services.AddAzureSoraSDK(builder.Configuration.GetSection("AzureSora"));
// Option 3: Shared configuration (backward compatible)
builder.Services.AddAzureSoraSDK(options =>
{
options.Endpoint = "https://your-resource.openai.azure.com";
options.ApiKey = "your-api-key";
options.DeploymentName = "sora";
options.ApiVersion = "preview";
options.MaxRetryAttempts = 5;
options.HttpTimeout = TimeSpan.FromMinutes(10);
});
// In your service/controller
public class VideoService
{
private readonly ISoraClient _soraClient;
private readonly IPromptEnhancer _promptEnhancer;
private readonly ILogger<VideoService> _logger;
public VideoService(
ISoraClient soraClient,
IPromptEnhancer promptEnhancer,
ILogger<VideoService> logger)
{
_soraClient = soraClient;
_promptEnhancer = promptEnhancer;
_logger = logger;
}
public async Task<string> GenerateVideoAsync(string prompt)
{
try
{
// Enhance the prompt first
var suggestions = await _promptEnhancer.SuggestPromptsAsync(prompt, 3);
var enhancedPrompt = suggestions.FirstOrDefault() ?? prompt;
_logger.LogInformation("Generating video with prompt: {Prompt}", enhancedPrompt);
// Submit video generation job
var jobId = await _soraClient.SubmitVideoJobAsync(
prompt: enhancedPrompt,
width: 1920,
height: 1080,
nSeconds: 15
);
// Wait with timeout
var videoUri = await _soraClient.WaitForCompletionAsync(
jobId,
pollIntervalSeconds: 3,
maxWaitTime: TimeSpan.FromMinutes(30)
);
return videoUri.ToString();
}
catch (SoraValidationException ex)
{
_logger.LogError(ex, "Validation failed: {Errors}", ex.ValidationErrors);
throw;
}
catch (SoraRateLimitException ex)
{
_logger.LogWarning("Rate limited. Retry after: {RetryAfter}", ex.RetryAfter);
throw;
}
}
}
{
"AzureSora": {
"Endpoint": "https://your-sora-endpoint.openai.azure.com",
"ApiKey": "your-sora-api-key",
"DeploymentName": "sora",
"ApiVersion": "preview",
"HttpTimeout": "00:05:00",
"MaxRetryAttempts": 3,
"RetryDelay": "00:00:02",
"DefaultPollingInterval": "00:00:05",
"MaxWaitTime": "01:00:00"
},
"PromptEnhancer": {
"Endpoint": "https://your-chat-endpoint.openai.azure.com",
"ApiKey": "your-chat-api-key",
"DeploymentName": "gpt-4",
"ApiVersion": "2024-02-15-preview",
"HttpTimeout": "00:02:00",
"MaxRetryAttempts": 3,
"RetryDelay": "00:00:01",
"DefaultTemperature": 0.7,
"DefaultTopP": 0.9,
"MaxTokensPerRequest": 1000
}
}
{
"AzureSora": {
"Endpoint": "https://your-resource.openai.azure.com",
"ApiKey": "your-api-key",
"DeploymentName": "sora",
"ApiVersion": "preview",
"HttpTimeout": "00:05:00",
"MaxRetryAttempts": 3,
"RetryDelay": "00:00:02",
"DefaultPollingInterval": "00:00:05",
"MaxWaitTime": "01:00:00"
}
}
# For Video Generation (SoraClient)
export AZURE_OPENAI_SORA_ENDPOINT="https://your-sora-endpoint.openai.azure.com"
export AZURE_OPENAI_SORA_KEY="your-sora-api-key"
export AZURE_OPENAI_SORA_DEPLOYMENT="sora"
# For Prompt Enhancement (PromptEnhancer)
export AZURE_OPENAI_CHAT_ENDPOINT="https://your-chat-endpoint.openai.azure.com"
export AZURE_OPENAI_CHAT_KEY="your-chat-api-key"
export AZURE_OPENAI_CHAT_DEPLOYMENT="gpt-4"
using AzureSoraSDK.Configuration;
// Create prompt enhancer with separate configuration
var promptEnhancerOptions = new PromptEnhancerOptions
{
Endpoint = "https://your-chat-endpoint.openai.azure.com",
ApiKey = "your-chat-api-key",
DeploymentName = "gpt-4",
ApiVersion = "2024-02-15-preview",
DefaultTemperature = 0.5,
DefaultTopP = 0.8,
MaxTokensPerRequest = 2000,
HttpTimeout = TimeSpan.FromMinutes(3)
};
var promptEnhancer = new PromptEnhancer(httpClient, promptEnhancerOptions, logger);
// Use different settings for different scenarios
var creativeSuggestions = await promptEnhancer.SuggestPromptsAsync(
"A sunset scene",
maxSuggestions: 5
);
try
{
var jobId = await client.SubmitVideoJobAsync(...);
}
catch (SoraAuthenticationException ex)
{
// Handle authentication failures
Console.WriteLine($"Auth failed: {ex.Message}");
}
catch (SoraValidationException ex)
{
// Handle validation errors
foreach (var error in ex.ValidationErrors ?? new())
{
Console.WriteLine($"{error.Key}: {string.Join(", ", error.Value)}");
}
}
catch (SoraRateLimitException ex)
{
// Handle rate limiting
if (ex.RetryAfter.HasValue)
{
await Task.Delay(ex.RetryAfter.Value);
// Retry the operation
}
}
catch (SoraTimeoutException ex)
{
// Handle timeouts
Console.WriteLine($"Operation timed out after {ex.Timeout}");
}
catch (SoraNotFoundException ex)
{
// Handle not found errors
Console.WriteLine($"Resource not found: {ex.ResourceId}");
}
// Submit a video generation job with metadata
var jobId = await client.SubmitVideoJobAsync(
prompt: "A futuristic cityscape at night with flying cars",
width: 1920,
height: 1080,
nSeconds: 20
);
// The VideoGenerationRequest model also supports metadata:
var request = new VideoGenerationRequest
{
Prompt = "A beautiful sunset over mountains",
Width = 1920,
Height = 1080,
NSeconds = 15,
Metadata = new Dictionary<string, string>
{
["project"] = "marketing-campaign",
["version"] = "v1"
}
};
// Validate before submission
request.Validate();
var jobId = await client.SubmitVideoJobAsync(...);
while (true)
{
var details = await client.GetJobStatusAsync(jobId);
Console.WriteLine($"Status: {details.Status}");
if (details.ProgressPercentage.HasValue)
{
Console.WriteLine($"Progress: {details.ProgressPercentage}%");
}
if (details.EstimatedTimeRemaining.HasValue)
{
Console.WriteLine($"ETA: {details.EstimatedTimeRemaining}");
}
if (details.Status == JobStatus.Succeeded)
{
Console.WriteLine($"Video URL: {details.VideoUrl}");
break;
}
else if (details.Status == JobStatus.Failed)
{
Console.WriteLine($"Failed: {details.ErrorMessage} (Code: {details.ErrorCode})");
break;
}
await Task.Delay(TimeSpan.FromSeconds(5));
}
var enhancer = serviceProvider.GetRequiredService<IPromptEnhancer>();
// Get multiple suggestions
var suggestions = await enhancer.SuggestPromptsAsync(
"A sunset scene",
maxSuggestions: 5
);
foreach (var suggestion in suggestions)
{
Console.WriteLine($"- {suggestion}");
}
// Output might be:
// - A vibrant sunset over the ocean with golden rays reflecting on calm waters
// - A dramatic sunset behind mountain silhouettes with purple and orange clouds
// - A peaceful sunset in a meadow with warm light casting long shadows
// - A tropical sunset with palm trees swaying in the gentle breeze
// - An urban sunset with city skyline silhouetted against colorful sky
The SDK includes comprehensive unit tests. To run tests:
cd src/AzureSoraSDK.Tests
dotnet test
# With coverage
dotnet test --collect:"XPlat Code Coverage"
# Run specific tests
dotnet test --filter "FullyQualifiedName~SoraClientTests"
SubmitVideoJobAsync - Submit a video generation jobGetJobStatusAsync - Get current job status and detailsWaitForCompletionAsync - Wait for job completion with pollingDownloadVideoAsync - Download generated video to local fileSuggestPromptsAsync - Get AI-powered prompt suggestionsEndpoint - Azure OpenAI endpoint URL for video generationApiKey - API key for video generation authenticationDeploymentName - Name of your Sora deploymentApiVersion - API version for video generation (default: preview)HttpTimeout - HTTP request timeout (default: 5 minutes)MaxRetryAttempts - Max retry attempts (default: 3)RetryDelay - Base delay between retries (default: 2 seconds)DefaultPollingInterval - Job status polling interval (default: 5 seconds)MaxWaitTime - Maximum wait time for job completion (default: 1 hour)Endpoint - Azure OpenAI endpoint URL for chat completionsApiKey - API key for chat completions authenticationDeploymentName - Name of your chat completion deployment (e.g., gpt-4)ApiVersion - API version for chat completions (default: 2024-02-15-preview)HttpTimeout - HTTP request timeout (default: 2 minutes)MaxRetryAttempts - Max retry attempts (default: 3)RetryDelay - Base delay between retries (default: 1 second)DefaultTemperature - Temperature for prompt enhancement (default: 0.7)DefaultTopP - Top-p value for prompt enhancement (default: 0.9)MaxTokensPerRequest - Maximum tokens per request (default: 1000)/samples directory for more examplesContributions are welcome! Please feel free to submit a Pull Request.
MIT © Hazem Ali
See CHANGELOG.md for a detailed list of changes in each release.