Skip to content

Commit

Permalink
Add -Images param to Request-Moderation
Browse files Browse the repository at this point in the history
Only `omni-moderation-*` model supports multi-modal inputs.
  • Loading branch information
mkht committed Oct 1, 2024
1 parent 7ab5659 commit e74d977
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 18 deletions.
15 changes: 11 additions & 4 deletions Docs/Request-Moderation.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ https://platform.openai.com/docs/guides/moderation/overview
### Example 1
```PowerShell
PS C:\> $Result = Request-Moderation -Text "I want to kill them."
PS C:\> $Result.results.categories
PS C:\> $Result.results[0].categories
```
```yaml
sexual : False
Expand All @@ -49,17 +49,24 @@ violence/graphic : False
## PARAMETERS
### -Text
(Required)
The input text to classify.
A string of text to classify for moderation.
```yaml
Type: String[]
Aliases: Input
Required: True
Required: False
Position: 1
Accept pipeline input: True (ByValue)
```
### -Images
An array of images to passing the model. You can specifies local image file or remote url.
```yaml
Type: String[]
Required: False
```
### -Model
The name of model to use.
The default value is `text-moderation-latest`.
Expand Down
49 changes: 40 additions & 9 deletions Public/Request-Moderation.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@ function Request-Moderation {
But avoid using the variable name $Input for variable name,
because it is used as an automatic variable in PowerShell.
#>
[Parameter(Mandatory, Position = 0, ValueFromPipeline)]
[Parameter(Position = 0, ValueFromPipeline)]
[ValidateNotNullOrEmpty()]
[Alias('Input')]
[string[]]$Text,

[Parameter()]
[string[]]$Images,

[Parameter()]
[Completions('text-moderation-latest', 'text-moderation-stable', 'omni-moderation-latest')]
[string][LowerCaseTransformation()]$Model,
Expand Down Expand Up @@ -49,20 +52,48 @@ function Request-Moderation {
}

process {
# Text is required
if ($null -eq $Text -or $Text.Count -eq 0) {
Write-Error -Exception ([System.ArgumentException]::new('"Text" property is required.'))
# Text or Image is required
if ($Text.Count -eq 0 -and $Images.Count -eq 0) {
Write-Error -Exception ([System.ArgumentException]::new('"Text" or "Images" property is required.'))
return
}

#region Construct parameters for API request
$PostBody = [System.Collections.Specialized.OrderedDictionary]::new()
if ($Text.Count -eq 1) {
$PostBody.input = [string](@($Text)[0])
$InputArray = @()

foreach ($txt in $Text) {
if ($Images.Count -gt 0) {
$InputArray += [pscustomobject]@{
raw_input = $txt
input = @{type = 'text'; text = $txt }
}
}
else {
$InputArray += [pscustomobject]@{
raw_input = $txt
input = $txt
}
}
}
else {
$PostBody.input = $Text

foreach ($image in $Images) {
if (Test-Path -LiteralPath $image -PathType Leaf) {
$InputArray += [pscustomobject]@{
raw_input = $image
input = @{type = 'image_url'; image_url = @{url = (Convert-ImageToDataURL $image) } }
}
}
else {
$InputArray += [pscustomobject]@{
raw_input = $image
input = @{type = 'image_url'; image_url = @{url = $image } }
}
}
}

$PostBody.input = @($InputArray.input)

if ($PSBoundParameters.ContainsKey('Model')) {
$PostBody.model = $Model
}
Expand Down Expand Up @@ -104,7 +135,7 @@ function Request-Moderation {
# Add custom type name and properties to output object.
$Response.PSObject.TypeNames.Insert(0, 'PSOpenAI.Moderation')
for ($i = 0; $i -lt @($Response.results).Count; $i++) {
@($Response.results)[$i] | Add-Member -MemberType NoteProperty -Name 'Text' -Value @($Text)[$i]
@($Response.results)[$i] | Add-Member -MemberType NoteProperty -Name 'Input' -Value $InputArray[$i].raw_input

# Output a warning message when input text violates the content policy
if (@($Response.results)[$i].flagged -eq $true) {
Expand Down
45 changes: 40 additions & 5 deletions Tests/Request-Moderation.tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Describe 'Request-Moderation' {
$Result.id | Should -Not -BeNullOrEmpty
$Result.results.GetType().Name | Should -Be 'Object[]'
$Result.results[0].flagged | Should -BeTrue
$Result.results[0].Text | Should -Be 'I want to kill them.'
$Result.results[0].Input | Should -Be 'I want to kill them.'
}

It 'Output warning when the message violates the policy' {
Expand All @@ -43,9 +43,10 @@ Describe 'Request-Moderation' {
$script:Result = ''
}

It 'Text moderation' {
It 'Text moderation (single text)' {
{ $splat = @{
Text = 'I want to kill them.'
Model = 'omni-moderation-latest'
TimeoutSec = 30
ErrorAction = 'Stop'
}
Expand All @@ -55,12 +56,13 @@ Describe 'Request-Moderation' {
$Result.id | Should -Not -BeNullOrEmpty
$Result.results.GetType().Name | Should -Be 'Object[]'
$Result.results[0].flagged | Should -BeTrue
$Result.results[0].Text | Should -Be 'I want to kill them.'
$Result.results[0].Input | Should -Be 'I want to kill them.'
}

It 'Text moderation (multiple texts)' {
{ $splat = @{
Text = ('I want to kill them.', 'I want to eat cake.')
Model = 'omni-moderation-latest'
TimeoutSec = 30
ErrorAction = 'Stop'
}
Expand All @@ -71,9 +73,42 @@ Describe 'Request-Moderation' {
$Result.results.GetType().Name | Should -Be 'Object[]'
$Result.results | Should -HaveCount 2
$Result.results[0].flagged | Should -BeTrue
$Result.results[0].Text | Should -Be 'I want to kill them.'
$Result.results[0].Input | Should -Be 'I want to kill them.'
$Result.results[1].flagged | Should -BeFalse
$Result.results[1].Text | Should -Be 'I want to eat cake.'
$Result.results[1].Input | Should -Be 'I want to eat cake.'
}

It 'Image moderation (Image file)' {
{ $splat = @{
Images = ($script:TestData + '/sweets_donut.png')
Model = 'omni-moderation-latest'
TimeoutSec = 30
ErrorAction = 'Stop'
}
$script:Result = Request-Moderation @splat
} | Should -Not -Throw
$Result | Should -BeOfType [PSCustomObject]
$Result.id | Should -Not -BeNullOrEmpty
$Result.results.GetType().Name | Should -Be 'Object[]'
$Result.results[0].flagged | Should -BeFalse
$Result.results[0].Input | Should -Not -BeNullOrEmpty
}

It 'Multi-modal moderation (Text & Image_url)' {
{ $splat = @{
Text = 'I want to kill them.'
Images = 'https://upload.wikimedia.org/wikipedia/commons/thumb/c/c3/Morakniv_Basic_511_Carbon_Steel_5.jpg/640px-Morakniv_Basic_511_Carbon_Steel_5.jpg'
Model = 'omni-moderation-latest'
TimeoutSec = 30
ErrorAction = 'Stop'
}
$script:Result = Request-Moderation @splat
} | Should -Not -Throw
$Result | Should -BeOfType [PSCustomObject]
$Result.id | Should -Not -BeNullOrEmpty
$Result.results.GetType().Name | Should -Be 'Object[]'
$Result.results[0].flagged | Should -BeTrue
$Result.results[0].Input | Should -Not -BeNullOrEmpty
}
}
}

0 comments on commit e74d977

Please sign in to comment.