Public/Request-AudioSpeech.ps1

function Request-AudioSpeech {
    [CmdletBinding(DefaultParameterSetName = 'Default')]
    [OutputType([void])]
    param (
        [Parameter(ParameterSetName = 'Default', Mandatory = $true, Position = 0)]
        [Alias('Input')]
        [ValidateNotNullOrEmpty()]
        [string]$Text,

        # For pipeline input from chat completion
        [Parameter(ParameterSetName = 'Pipeline', DontShow = $true, Mandatory = $true, ValueFromPipeline = $true)]
        [ValidateNotNull()]
        [Object]$InputObject,

        [Parameter()]
        [Completions('tts-1', 'tts-1-hd')]
        [string][LowerCaseTransformation()]$Model = 'tts-1',

        [Parameter()]
        [Completions(
            'alloy',
            'echo',
            'fable',
            'onyx',
            'nova',
            'shimmer'
        )]
        [string][LowerCaseTransformation()]$Voice = 'alloy',

        [Parameter()]
        [Alias('response_format')]
        [ValidateSet('mp3', 'opus', 'aac', 'flac')]
        [string][LowerCaseTransformation()]$Format,

        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [string]$OutFile,

        [Parameter()]
        [ValidateRange(0.25, 4.0)]
        [double]$Speed = 1.0,

        [Parameter()]
        [int]$TimeoutSec = 0,

        [Parameter()]
        [ValidateRange(0, 100)]
        [int]$MaxRetryCount = 0,

        [Parameter(DontShow = $true)]
        [OpenAIApiType]$ApiType = [OpenAIApiType]::OpenAI,

        [Parameter()]
        [System.Uri]$ApiBase,

        [Parameter(DontShow = $true)]
        [string]$ApiVersion,

        [Parameter(DontShow = $true)]
        [string]$AuthType = 'openai',

        [Parameter()]
        [securestring][SecureStringTransformation()]$ApiKey,

        [Parameter()]
        [Alias('OrgId')]
        [string]$Organization
    )

    begin {
        # Initialize API Key
        [securestring]$SecureToken = Initialize-APIKey -ApiKey $ApiKey

        # Initialize API Base
        $ApiBase = Initialize-APIBase -ApiBase $ApiBase -ApiType ([OpenAIApiType]::OpenAI)

        # Initialize Organization ID
        $Organization = Initialize-OrganizationID -OrgId $Organization

        # Get API endpoint
        if ($ApiType -eq [OpenAIApiType]::Azure) {
            $OpenAIParameter = Get-AzureOpenAIAPIEndpoint -EndpointName 'Audio.Speech' -Engine $Model -ApiBase $ApiBase -ApiVersion $ApiVersion
        }
        else {
            $OpenAIParameter = Get-OpenAIAPIEndpoint -EndpointName 'Audio.Speech' -ApiBase $ApiBase
        }
    }

    process {
        if ($PSCmdlet.ParameterSetName -eq 'Pipeline') {
            if ($InputObject -is [string]) {
                $Text = $InputObject
            }
            elseif ($InputObject.Answer -as [string]) {
                $Text = [string]$InputObject.Answer
            }
            else {
                Write-Error -Exception ([System.ArgumentException]::new('Input object is invalid.'))
                return
            }
        }

        #region Construct parameters for API request
        $PostBody = [System.Collections.Specialized.OrderedDictionary]::new()
        $PostBody.model = $Model
        $PostBody.input = $Text
        $PostBody.voice = $Voice
        if ($PSBoundParameters.ContainsKey('Format')) {
            $PostBody.response_format = $Format
        }
        else {
            $PostBody.response_format = `
                switch -Wildcard ($OutFile) {
                '*.mp3' { 'mp3'; break }
                '*.opus' { 'opus'; break }
                '*.aac' { 'aac'; break }
                '*.flac' { 'flac'; break }
                Default { 'mp3' }
            }
        }
        if ($PSBoundParameters.ContainsKey('Speed')) {
            $PostBody.speed = $Speed
        }

        #region Send API Request
        try {
            $Response = Invoke-OpenAIAPIRequest `
                -Method $OpenAIParameter.Method `
                -Uri $OpenAIParameter.Uri `
                -ContentType $OpenAIParameter.ContentType `
                -TimeoutSec $TimeoutSec `
                -MaxRetryCount $MaxRetryCount `
                -ApiKey $SecureToken `
                -AuthType $AuthType `
                -Organization $Organization `
                -Body $PostBody
        }
        catch {
            Write-Error -Exception $_.Exception
        }

        # error check
        if ($null -eq $Response) {
            return
        }
        #endregion

        #region Output
        # create parent directory if it does not exist
        $ParentDirectory = Split-Path $OutFile -Parent
        if (-not $ParentDirectory) {
            $ParentDirectory = [string]$PWD
        }
        if (-not (Test-Path -LiteralPath $ParentDirectory -PathType Container)) {
            $null = New-Item -Path $ParentDirectory -ItemType Directory -Force
        }
        # error check
        if (-not (Test-Path -LiteralPath $ParentDirectory -PathType Container)) {
            Write-Error -Message ('Destination folder "{0}" does not exist.' -f $ParentDirectory)
            return
        }

        # Output file
        try {
            [System.IO.File]::WriteAllBytes($OutFile, ([byte[]]$Response))
        }
        catch {
            Write-Error -Exception $_.Exception
        }
        #endregion
    }

    end {

    }
}