@@ -59,7 +59,7 @@ class OpenAIClient {
5959 return Invoke-RestMethod - Method $method - Uri $url - Headers $this.headers
6060 }
6161 else {
62- return Invoke-RestMethod - Method $method - Uri $url - Headers $this.headers - Body ($body | ConvertTo-Json )
62+ return Invoke-RestMethod - Method $method - Uri $url - Headers $this.headers - Body ($body | ConvertTo-Json - Depth 10 )
6363 }
6464 }
6565
@@ -73,16 +73,30 @@ class AssistantResource {
7373 [OpenAIClient ]$Client
7474 [System.Management.Automation.HiddenAttribute ()]
7575 [string ]$urifragment
76+ [System.Management.Automation.HiddenAttribute ()]
77+ [string ]$objTypeName
7678
77- AssistantResource([OpenAIClient ]$client , [string ]$urifragment ) {
79+ AssistantResource([OpenAIClient ]$client , [string ]$urifragment , [ string ] $objTypeName ) {
7880 $this.Client = $client
7981 $this.urifragment = $urifragment
82+ $this.objTypeName = $objTypeName
8083 }
8184 [psobject []]list() {
85+
86+ if ($this.objTypeName ) {
87+ return $this.Client.web ($this.urifragment ).data | ForEach-Object {
88+ New-Object - TypeName $this.objTypeName - ArgumentList $_
89+ }
90+ }
91+
8292 return $this.Client.web ($this.urifragment ).data
8393 }
8494
8595 [psobject ]get([string ]$id ) {
96+ if ($this.objTypeName ) {
97+ return New-Object - TypeName $this.objTypeName - ArgumentList $this.Client.web (" $ ( $this.urifragment ) /$id " )
98+ }
99+
86100 return $this.Client.web (" $ ( $this.urifragment ) /$id " )
87101 }
88102
@@ -91,12 +105,123 @@ class AssistantResource {
91105 }
92106
93107 [psobject ]create([hashtable ]$body ) {
108+ if ($this.objTypeName ) {
109+ return New-Object - TypeName $this.objTypeName - ArgumentList $this.Client.web (" $ ( $this.urifragment ) " , " POST" , $body )
110+ }
94111 return $this.Client.web (" $ ( $this.urifragment ) " , " POST" , $body )
95112 }
113+
114+ [psobject ]create() {
115+ return $this.create (@ {})
116+ }
117+
118+
119+ [void ]clear() {
120+ # warn user this is very dangerous action, it will remove all the instance, and ask for confirmation
121+ $confirm = Read-Host " Are you sure you want to remove all the instances? (yes/no)"
122+ if ($confirm -ne " yes" -and $confirm -ne " y" ) {
123+ return
124+ }
125+ # get all the instances and remove it
126+ $this.list () | ForEach-Object {
127+ $this.delete ($_.id )
128+ }
129+ }
130+ }
131+
132+ class File :AssistantResource {
133+ File([OpenAIClient ]$client ): base($client , " files" , $null ) {}
134+
135+ [psobject ]create([hashtable ]$body ) {
136+ if ($body.files ) {
137+ $files = $body.files
138+ return $this.upload ($files )
139+ }
140+
141+ throw " The body must contain 'files' key."
142+ }
143+
144+
145+ [System.Management.Automation.HiddenAttribute ()]
146+ [psobject ]upload([string []]$fullname ) {
147+ $url = " {0}{1}" -f $this.Client.baseUri , $this.urifragment
148+ if ($this.Client.baseUri -match " azure" ) {
149+ $url = " {0}?api-version=2024-05-01-preview" -f $url
150+ }
151+
152+ $result = @ ()
153+
154+ foreach ($file in $fullname ) {
155+ Write-Host " process file: $file "
156+ # Define the purpose (e.g., "assistants", "vision", "batch", or "fine-tune")
157+ $purpose = " assistants"
158+ # Create a new web request
159+ $request = [System.Net.WebRequest ]::Create($url )
160+ $request.Method = " POST"
161+
162+ # add the item of headers to request.Headers
163+ $this.Client.headers.GetEnumerator () | Where-Object {
164+ $_.Key -ne " Content-Type"
165+ } | ForEach-Object {
166+ $request.Headers.Add ($_.Key , $_.Value )
167+ }
168+
169+ # Create a boundary for the multipart/form-data content
170+ $boundary = [System.Guid ]::NewGuid().ToString()
171+
172+ # Set the content type and boundary
173+ $request.ContentType = " multipart/form-data; boundary=$boundary "
174+
175+ $name = " {0}-{1}" -f (Get-FileHash $file ).Hash, (Split-Path $file - Leaf)
176+
177+ # Create the request body
178+ $body = @"
179+ --$boundary
180+ Content-Disposition: form-data; name="file"; filename="$name "
181+ Content-Type: application/octet-stream
182+
183+ $ ( Get-Content - Path $file )
184+
185+ --$boundary
186+ Content-Disposition: form-data; name="purpose"
187+
188+ $purpose
189+ --$boundary --
190+ "@
191+
192+
193+ # Convert the body to bytes
194+ $bodyBytes = [System.Text.Encoding ]::UTF8.GetBytes($body )
195+
196+ # Set the content length
197+ $request.ContentLength = $bodyBytes.Length
198+
199+ # Get the request stream and write the body
200+ $requestStream = $request.GetRequestStream ()
201+ $requestStream.Write ($bodyBytes , 0 , $bodyBytes.Length )
202+ $requestStream.Close ()
203+
204+ # Get the response
205+ $response = $request.GetResponse ()
206+
207+ # Read the response content
208+ $responseStream = $response.GetResponseStream ()
209+ $reader = [System.IO.StreamReader ]::new($responseStream )
210+ $responseContent = $reader.ReadToEnd ()
211+ $reader.Close ()
212+
213+ # Print the response content
214+ $result += ($responseContent | ConvertFrom-Json )
215+ }
216+ return $result
217+ }
218+
219+
96220}
97221
98222class Assistant :AssistantResource {
99- Assistant([OpenAIClient ]$client ): base($client , " assistants" ) {}
223+ Assistant([OpenAIClient ]$client ): base($client , " assistants" , " AssistantObject" ) {}
224+
100225
101226 <#
102227 . SYNOPSIS
@@ -106,7 +231,7 @@ class Assistant:AssistantResource {
106231 . PARAMETER body
107232 The body must contain 'name', 'model', and 'instructions' keys. But it can also contain 'config', 'vector_store_ids', 'functions', and 'files' keys.
108233 #>
109- [psobject ]create([hashtable ]$body ) {
234+ [AssistantObject ]create([hashtable ]$body ) {
110235 if ($body.name -and $body.model -and $body.instructions ) {
111236 $vector_store_ids = $body.vector_store_ids
112237 $functions = $body.functions
@@ -123,7 +248,8 @@ class Assistant:AssistantResource {
123248
124249 $body.Add (" tool_resources" , @ {
125250 " file_search" = @ {
126- " vector_stores" = @ (@ {
251+ " vector_stores" = @ (
252+ @ {
127253 file_ids = @ ($file_ids )
128254 })
129255 }
@@ -165,14 +291,40 @@ class Assistant:AssistantResource {
165291 $body.Remove (" functions" )
166292 $body.Remove (" config" )
167293
168- return $this.Client.web (" $ ( $this.urifragment ) " , " POST" , $body )
294+ return [ AssistantObject ]::new( $this.Client.web (" $ ( $this.urifragment ) " , " POST" , $body ) )
169295 }
170296
171297 throw " The body must contain 'name' and 'model', 'instructions' keys."
172298 }
173299}
300+
301+
302+ class AssistantResourceObject {
303+ AssistantResourceObject([psobject ]$data ) {
304+ # check all the properties and assign it to the object
305+ $data.PSObject.Properties | ForEach-Object {
306+ $this | Add-Member - MemberType NoteProperty - Name $_.Name - Value $_.Value
307+ }
308+ }
309+ }
310+
311+ class AssistantObject :AssistantResourceObject {
312+ AssistantObject([psobject ]$data ):base($data ) {}
313+ [void ]chat() {
314+ Write-Host " chat with the assistant : $ ( $this.id ) "
315+ }
316+ }
317+
318+
319+ class ThreadObject :AssistantResourceObject {
320+ ThreadObject([psobject ]$data ):base($data ) {}
321+ }
322+ class Thread :AssistantResource {
323+ Thread([OpenAIClient ]$client ): base($client , " threads" , " ThreadObject" ) {}
324+ }
325+
174326class Vector_store :AssistantResource {
175- Vector_store([OpenAIClient ]$client ): base($client , " vector_stores" ) {}
327+ Vector_store([OpenAIClient ]$client ): base($client , " vector_stores" , $null ) {}
176328
177329 [psobject ]create([hashtable ]$body ) {
178330 <#
@@ -197,96 +349,4 @@ class Vector_store:AssistantResource {
197349
198350 throw " The body must contain 'name', 'file_ids', and 'days_to_expire' keys."
199351 }
200- }
201- class File :AssistantResource {
202- File([OpenAIClient ]$client ): base($client , " files" ) {}
203-
204- [psobject ]create([hashtable ]$body ) {
205- if ($body.files ) {
206- $files = $body.files
207- return $this.upload ($files )
208- }
209-
210- throw " The body must contain 'files' key."
211- }
212-
213-
214- [System.Management.Automation.HiddenAttribute ()]
215- [psobject ]upload([string []]$fullname ) {
216- $url = " {0}{1}" -f $this.Client.baseUri , $this.urifragment
217- if ($this.Client.baseUri -match " azure" ) {
218- $url = " {0}?api-version=2024-05-01-preview" -f $url
219- }
220-
221- $result = @ ()
222-
223- foreach ($file in $fullname ) {
224- Write-Host " process file: $file "
225- # Define the purpose (e.g., "assistants", "vision", "batch", or "fine-tune")
226- $purpose = " assistants"
227- # Create a new web request
228- $request = [System.Net.WebRequest ]::Create($url )
229- $request.Method = " POST"
230-
231- # add the item of headers to request.Headers
232- $this.Client.headers.GetEnumerator () | Where-Object {
233- $_.Key -ne " Content-Type"
234- } | ForEach-Object {
235- $request.Headers.Add ($_.Key , $_.Value )
236- }
237-
238- # Create a boundary for the multipart/form-data content
239- $boundary = [System.Guid ]::NewGuid().ToString()
240-
241- # Set the content type and boundary
242- $request.ContentType = " multipart/form-data; boundary=$boundary "
243-
244- $name = " {0}-{1}" -f (Get-FileHash $file ).Hash, (Split-Path $file - Leaf)
245-
246- # Create the request body
247- $body = @"
248- --$boundary
249- Content-Disposition: form-data; name="file"; filename="$name "
250- Content-Type: application/octet-stream
251-
252- $ ( Get-Content - Path $file )
253-
254- --$boundary
255- Content-Disposition: form-data; name="purpose"
256-
257- $purpose
258- --$boundary --
259- "@
260-
261-
262- # Convert the body to bytes
263- $bodyBytes = [System.Text.Encoding ]::UTF8.GetBytes($body )
264-
265- # Set the content length
266- $request.ContentLength = $bodyBytes.Length
267-
268- # Get the request stream and write the body
269- $requestStream = $request.GetRequestStream ()
270- $requestStream.Write ($bodyBytes , 0 , $bodyBytes.Length )
271- $requestStream.Close ()
272-
273- # Get the response
274- $response = $request.GetResponse ()
275-
276- # Read the response content
277- $responseStream = $response.GetResponseStream ()
278- $reader = [System.IO.StreamReader ]::new($responseStream )
279- $responseContent = $reader.ReadToEnd ()
280- $reader.Close ()
281-
282- # Print the response content
283- $result += ($responseContent | ConvertFrom-Json )
284- }
285- return $result
286- }
287-
288-
289- }
290- class Thread :AssistantResource {
291- Thread([OpenAIClient ]$client ): base($client , " threads" ) {}
292352}
0 commit comments