Public/Request-AudioSpeech.ps1

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

        # For pipeline input from chat completion
        [Parameter(ParameterSetName = 'Pipeline', DontShow, Mandatory, ValueFromPipeline)]
        [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')]
        [Completions(
            'mp3',
            'opus',
            'aac',
            'flac',
            'wav',
            'pcm'
        )]
        [string][LowerCaseTransformation()]$Format,

        [Parameter(Mandatory)]
        [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()]
        [OpenAIApiType]$ApiType = [OpenAIApiType]::OpenAI,

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

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

        [Parameter()]
        [ValidateSet('openai', 'azure', 'azure_ad')]
        [string]$AuthType = 'openai',

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

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

        [Parameter()]
        [System.Collections.IDictionary]$AdditionalQuery,

        [Parameter()]
        [System.Collections.IDictionary]$AdditionalHeaders,

        [Parameter()]
        [object]$AdditionalBody
    )

    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 context
        $OpenAIParameter = Get-OpenAIContext -EndpointName 'Audio.Speech' -ApiType $ApiType -AuthType $AuthType -ApiBase $ApiBase -ApiVersion $ApiVersion -Engine $Model
    }

    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 }
                '*.wav' { 'wav'; break }
                Default { 'mp3' }
            }
        }
        if ($PSBoundParameters.ContainsKey('Speed')) {
            $PostBody.speed = $Speed
        }

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

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

        #region Output
        try {
            # Convert to absolute path
            $AbsoluteOutFile = $PSCmdlet.GetUnresolvedProviderPathFromPSPath($OutFile)
            # create parent directory if it does not exist
            $ParentDirectory = Split-Path $AbsoluteOutFile -Parent
            if (-not $ParentDirectory) {
                $ParentDirectory = [string](Get-Location -PSProvider FileSystem).ProviderPath
                $AbsoluteOutFile = Join-Path $ParentDirectory $AbsoluteOutFile
            }
            if (-not (Test-Path -LiteralPath $ParentDirectory -PathType Container)) {
                $null = New-Item -Path $ParentDirectory -ItemType Directory -Force
            }

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

    end {

    }
}