Skip to content

Commit 272891f

Browse files
committed
Add new functions for video generation.
- New-Video - Get-Video - Get-VideoContent - Remove-Video
1 parent 4227c6b commit 272891f

15 files changed

Lines changed: 1180 additions & 0 deletions

PSOpenAI.Types.ps1xml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,17 @@
220220
</ScriptMethod>
221221
</Members>
222222
</Type>
223+
<Type>
224+
<Name>PSOpenAI.Video.Job</Name>
225+
<Members>
226+
<ScriptMethod>
227+
<Name>ToString</Name>
228+
<Script>
229+
$this.id -as [string]
230+
</Script>
231+
</ScriptMethod>
232+
</Members>
233+
</Type>
223234
<Type>
224235
<Name>PSOpenAI.Model</Name>
225236
<Members>

PSOpenAI.psd1

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,13 @@
8787
'Request-ImageEdit',
8888
'Request-ImageGeneration',
8989
'Request-ImageVariation',
90+
#### Videos ####
91+
'New-Video',
92+
'New-VideoRemix',
93+
'Get-Video',
94+
'Get-VideoContent',
95+
'Remove-Video',
96+
'Wait-Video',
9097
#### Moderation ####
9198
'Request-Moderation',
9299
#### Responses ####

Private/Get-OpenAIAPIEndpoint.ps1

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,26 @@ function Get-OpenAIAPIEndpoint {
290290
}
291291
continue
292292
}
293+
'Videos' {
294+
$UriBuilder.Path += 'videos'
295+
@{
296+
Name = 'videos'
297+
Method = 'Post'
298+
Uri = $UriBuilder.Uri
299+
ContentType = 'multipart/form-data'
300+
}
301+
continue
302+
}
303+
'Videos.Remix' {
304+
$UriBuilder.Path += 'videos/{0}/remix'
305+
@{
306+
Name = 'videos_remix'
307+
Method = 'Post'
308+
Uri = $UriBuilder.Uri
309+
ContentType = 'application/json'
310+
}
311+
continue
312+
}
293313
default {
294314
Write-Error -Message ('{0} API endpoint is not provided by OpenAI' -f $_)
295315
}

Private/ObjectParser.ps1

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -547,4 +547,29 @@ function ParseImageGenerationObject {
547547
}
548548
}
549549
Write-Output $InputObject
550+
}
551+
552+
function ParseVideoJobObject {
553+
[CmdletBinding()]
554+
param (
555+
[Parameter(Mandatory, Position = 0, ValueFromPipeline)]
556+
[PSCustomObject]$InputObject
557+
)
558+
559+
# Add custom type name and properties to output object.
560+
$InputObject.PSObject.TypeNames.Insert(0, 'PSOpenAI.Video.Job')
561+
('created_at', 'expires_at', 'started_at', 'cancelled_at', 'failed_at', 'completed_at') | ForEach-Object {
562+
if ($null -ne $InputObject.$_ -and ($unixtime = $InputObject.$_ -as [long])) {
563+
# convert unixtime to [DateTime] for read suitable
564+
$InputObject | Add-Member -MemberType NoteProperty -Name $_ -Value ([System.DateTimeOffset]::FromUnixTimeSeconds($unixtime).LocalDateTime) -Force
565+
}
566+
}
567+
Write-Output $InputObject
568+
569+
# Output warning message if the status is not success.
570+
if ($null -ne $InputObject.error -or $InputObject.status -eq 'failed') {
571+
$WarnMessage = ('The status of job with id "{0}" is "{1}". Error: "{2}" ({3})' -f `
572+
$InputObject.id, $InputObject.status, $InputObject.error.message, $InputObject.error.code)
573+
Write-Warning -Message $WarnMessage
574+
}
550575
}

Public/Videos/Get-Video.ps1

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
function Get-Video {
2+
[CmdletBinding(DefaultParameterSetName = 'List')]
3+
[OutputType([pscustomobject])]
4+
param (
5+
[Parameter(ParameterSetName = 'Get', Mandatory, Position = 0, ValueFromPipeline, ValueFromPipelineByPropertyName)]
6+
[ValidateNotNullOrEmpty()]
7+
[Alias('video_id')]
8+
[Alias('Id')]
9+
[string][UrlEncodeTransformation()]$VideoId,
10+
11+
[Parameter(ParameterSetName = 'List')]
12+
[ValidateRange(0, 100)]
13+
[int]$Limit = 20,
14+
15+
[Parameter(ParameterSetName = 'List')]
16+
[ValidateSet('asc', 'desc')]
17+
[string][LowerCaseTransformation()]$Order = 'asc',
18+
19+
[Parameter(ParameterSetName = 'List')]
20+
[switch]$All,
21+
22+
[Parameter(ParameterSetName = 'List', DontShow)]
23+
[string]$After,
24+
25+
[Parameter()]
26+
[int]$TimeoutSec = 0,
27+
28+
[Parameter()]
29+
[ValidateRange(0, 100)]
30+
[int]$MaxRetryCount = 0,
31+
32+
[Parameter()]
33+
[OpenAIApiType]$ApiType = [OpenAIApiType]::OpenAI,
34+
35+
[Parameter()]
36+
[System.Uri]$ApiBase,
37+
38+
[Parameter(DontShow)]
39+
[string]$ApiVersion,
40+
41+
[Parameter()]
42+
[ValidateSet('openai', 'azure', 'azure_ad')]
43+
[string]$AuthType = 'openai',
44+
45+
[Parameter()]
46+
[securestring][SecureStringTransformation()]$ApiKey,
47+
48+
[Parameter()]
49+
[Alias('OrgId')]
50+
[string]$Organization,
51+
52+
[Parameter()]
53+
[System.Collections.IDictionary]$AdditionalQuery,
54+
55+
[Parameter()]
56+
[System.Collections.IDictionary]$AdditionalHeaders,
57+
58+
[Parameter()]
59+
[object]$AdditionalBody
60+
)
61+
62+
begin {
63+
# Get API context
64+
$OpenAIParameter = Get-OpenAIAPIParameter -EndpointName 'Videos' -Parameters $PSBoundParameters -ErrorAction Stop
65+
66+
# Iterator flag
67+
[bool]$HasMore = $true
68+
}
69+
70+
process {
71+
# Create cancellation token for timeout
72+
$Cancellation = [System.Threading.CancellationTokenSource]::new()
73+
if ($TimeoutSec -gt 0) {
74+
$Cancellation.CancelAfter([timespan]::FromSeconds($TimeoutSec))
75+
}
76+
77+
try {
78+
#region Pagenation Loop
79+
while ($HasMore) {
80+
#region Construct Query URI
81+
$UriBuilder = [System.UriBuilder]::new($OpenAIParameter.Uri)
82+
if ($PSCmdlet.ParameterSetName -eq 'Get') {
83+
$UriBuilder.Path += "/$VideoId"
84+
$QueryUri = $UriBuilder.Uri
85+
}
86+
else {
87+
$QueryParam = [System.Web.HttpUtility]::ParseQueryString($UriBuilder.Query)
88+
if ($All) {
89+
$Limit = 100
90+
}
91+
$QueryParam.Add('limit', $Limit)
92+
$QueryParam.Add('order', $Order)
93+
if ($After) {
94+
$QueryParam.Add('after', $After)
95+
}
96+
$UriBuilder.Query = $QueryParam.ToString()
97+
$QueryUri = $UriBuilder.Uri
98+
}
99+
#endregion
100+
101+
#region Send API Request
102+
$params = @{
103+
Method = 'Get'
104+
Uri = $QueryUri
105+
TimeoutSec = $OpenAIParameter.TimeoutSec
106+
MaxRetryCount = $OpenAIParameter.MaxRetryCount
107+
ApiKey = $OpenAIParameter.ApiKey
108+
AuthType = $OpenAIParameter.AuthType
109+
Organization = $OpenAIParameter.Organization
110+
AdditionalQuery = $AdditionalQuery
111+
AdditionalHeaders = $AdditionalHeaders
112+
AdditionalBody = $AdditionalBody
113+
}
114+
$Response = Invoke-OpenAIAPIRequest @params
115+
116+
# error check
117+
if ($null -eq $Response) {
118+
return
119+
}
120+
#endregion
121+
122+
#region Parse response object
123+
try {
124+
$Response = $Response | ConvertFrom-Json -ErrorAction Stop
125+
}
126+
catch {
127+
Write-Error -Exception $_.Exception
128+
return
129+
}
130+
#endregion
131+
132+
$Cancellation.Token.ThrowIfCancellationRequested()
133+
134+
# Update iterator flag
135+
if ($HasMore = [bool]$Response.has_more) {
136+
if ($All -and $Response.last_id) {
137+
$After = $Response.last_id
138+
}
139+
else {
140+
$HasMore = $false
141+
if (-not $PSBoundParameters.ContainsKey('Limit')) {
142+
Write-Warning 'There is more data that has not been retrieved.'
143+
}
144+
}
145+
}
146+
147+
#region Output
148+
if ($Response.object -eq 'list' -and ($null -ne $Response.data)) {
149+
$Responses = @($Response.data)
150+
}
151+
else {
152+
$Responses = @($Response)
153+
}
154+
foreach ($res in $Responses) {
155+
ParseVideoJobObject $res
156+
}
157+
#endregion
158+
}
159+
}
160+
catch [OperationCanceledException] {
161+
Write-TimeoutError
162+
return
163+
}
164+
catch {
165+
Write-Error -Exception $_.Exception
166+
return
167+
}
168+
finally {
169+
if ($null -ne $Cancellation) {
170+
$Cancellation.Dispose()
171+
}
172+
}
173+
}
174+
175+
end {
176+
177+
}
178+
}

Public/Videos/Get-VideoContent.ps1

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
function Get-VideoContent {
2+
[CmdletBinding()]
3+
[OutputType([byte[]])]
4+
param (
5+
[Parameter(Mandatory, Position = 0, ValueFromPipeline, ValueFromPipelineByPropertyName)]
6+
[ValidateNotNullOrEmpty()]
7+
[Alias('video_id')]
8+
[Alias('Id')]
9+
[string][UrlEncodeTransformation()]$VideoId,
10+
11+
[Parameter()]
12+
[ValidateNotNullOrEmpty()]
13+
[string]$OutFile,
14+
15+
[Parameter()]
16+
[Completions('video', 'thumbnail', 'spritesheet')]
17+
[string][LowerCaseTransformation()]$Variant,
18+
19+
[Parameter()]
20+
[switch]$WaitForCompletion,
21+
22+
[Parameter()]
23+
[int]$TimeoutSec = 0,
24+
25+
[Parameter()]
26+
[ValidateRange(0, 100)]
27+
[int]$MaxRetryCount = 0,
28+
29+
[Parameter()]
30+
[OpenAIApiType]$ApiType = [OpenAIApiType]::OpenAI,
31+
32+
[Parameter()]
33+
[System.Uri]$ApiBase,
34+
35+
[Parameter(DontShow)]
36+
[string]$ApiVersion,
37+
38+
[Parameter()]
39+
[ValidateSet('openai', 'azure', 'azure_ad')]
40+
[string]$AuthType = 'openai',
41+
42+
[Parameter()]
43+
[securestring][SecureStringTransformation()]$ApiKey,
44+
45+
[Parameter()]
46+
[Alias('OrgId')]
47+
[string]$Organization,
48+
49+
[Parameter()]
50+
[System.Collections.IDictionary]$AdditionalQuery,
51+
52+
[Parameter()]
53+
[System.Collections.IDictionary]$AdditionalHeaders,
54+
55+
[Parameter()]
56+
[object]$AdditionalBody
57+
)
58+
59+
begin {
60+
# Get API context
61+
$OpenAIParameter = Get-OpenAIAPIParameter -EndpointName 'Videos' -Parameters $PSBoundParameters -ErrorAction Stop
62+
63+
# Parse Common params
64+
$CommonParams = ParseCommonParams $PSBoundParameters
65+
}
66+
67+
process {
68+
# region Wait for completion
69+
if ($WaitForCompletion) {
70+
$null = $VideoId | PSOpenAI\Wait-Video @CommonParams
71+
}
72+
# endregion
73+
74+
#region Construct Query URI
75+
$UriBuilder = [System.UriBuilder]::new($OpenAIParameter.Uri)
76+
$UriBuilder.Path += "/$VideoId/content"
77+
$QueryUri = $UriBuilder.Uri
78+
79+
if ($PSBoundParameters.ContainsKey('Variant')) {
80+
$QueryParam = [System.Web.HttpUtility]::ParseQueryString($UriBuilder.Query)
81+
$QueryParam.Add('variant', $Variant)
82+
$UriBuilder.Query = $QueryParam.ToString()
83+
$QueryUri = $UriBuilder.Uri
84+
}
85+
#endregion
86+
87+
#region Send API Request
88+
$params = @{
89+
Method = 'Get'
90+
Uri = $QueryUri
91+
TimeoutSec = $OpenAIParameter.TimeoutSec
92+
MaxRetryCount = $OpenAIParameter.MaxRetryCount
93+
ApiKey = $OpenAIParameter.ApiKey
94+
AuthType = $OpenAIParameter.AuthType
95+
Organization = $OpenAIParameter.Organization
96+
AdditionalQuery = $AdditionalQuery
97+
AdditionalHeaders = $AdditionalHeaders
98+
AdditionalBody = $AdditionalBody
99+
}
100+
$Response = Invoke-OpenAIAPIRequest @params
101+
102+
# error check
103+
if ($null -eq $Response) {
104+
return
105+
}
106+
#endregion
107+
108+
#region Output
109+
if ($OutFile) {
110+
Write-ByteContent -OutFile $OutFile -Bytes ([byte[]]$Response)
111+
}
112+
else {
113+
Write-Output $Response
114+
}
115+
#endregion
116+
}
117+
118+
end {
119+
120+
}
121+
}

0 commit comments

Comments
 (0)