Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Moderation: Update Response&Request #894

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 88 additions & 6 deletions moderation.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ var (
ErrModerationInvalidModel = errors.New("this model is not supported with moderation, please use text-moderation-stable or text-moderation-latest instead") //nolint:lll
)

type ModerationItemType string

const (
ModerationItemTypeText ModerationItemType = "text"
ModerationItemTypeImageURL ModerationItemType = "image_url"
)

var validModerationModel = map[string]struct{}{
ModerationOmniLatest: {},
ModerationOmni20240926: {},
Expand All @@ -39,11 +46,63 @@ type ModerationRequest struct {
Model string `json:"model,omitempty"`
}

func (m ModerationRequest) Convert() ModerationRequestV2 {
return ModerationRequestV2{
Input: m.Input,
Model: m.Model,
}
}

type ModerationStrArrayRequest struct {
Input []string `json:"input,omitempty"`
Model string `json:"model,omitempty"`
}

func (m ModerationStrArrayRequest) Convert() ModerationRequestV2 {
return ModerationRequestV2{
Input: m.Input,
Model: m.Model,
}
}

type ModerationArrayRequest struct {
Input []ModerationRequestItem `json:"input,omitempty"`
Model string `json:"model,omitempty"`
}

func (m ModerationArrayRequest) Convert() ModerationRequestV2 {
return ModerationRequestV2{
Input: m.Input,
Model: m.Model,
}
}

type ModerationRequestItem struct {
Type ModerationItemType `json:"type"`

ImageURL ModerationImageURL `json:"image_url,omitempty"`
Text string `json:"text,omitempty"`
}

type ModerationImageURL struct {
URL string `json:"url,omitempty"`
}

type ModerationRequestV2 struct {
Input any `json:"input,omitempty"`
Model string `json:"model,omitempty"`
}

type ModerationRequestConverter interface {
Convert() ModerationRequestV2
}

// Result represents one of possible moderation results.
type Result struct {
Categories ResultCategories `json:"categories"`
CategoryScores ResultCategoryScores `json:"category_scores"`
Flagged bool `json:"flagged"`
Categories ResultCategories `json:"categories"`
CategoryScores ResultCategoryScores `json:"category_scores"`
Flagged bool `json:"flagged"`
CategoryAppliedInputTypes CategoryAppliedInputType `json:"category_applied_input_types"`
}

// ResultCategories represents Categories of Result.
Expand All @@ -59,6 +118,8 @@ type ResultCategories struct {
SexualMinors bool `json:"sexual/minors"`
Violence bool `json:"violence"`
ViolenceGraphic bool `json:"violence/graphic"`
Illicit bool `json:"illicit"`
IllicitViolent bool `json:"illicit/violent"`
}

// ResultCategoryScores represents CategoryScores of Result.
Expand All @@ -74,6 +135,24 @@ type ResultCategoryScores struct {
SexualMinors float32 `json:"sexual/minors"`
Violence float32 `json:"violence"`
ViolenceGraphic float32 `json:"violence/graphic"`
Illicit float32 `json:"illicit"`
IllicitViolent float32 `json:"illicit/violent"`
}

type CategoryAppliedInputType struct {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@chenhhA thank you for the PR! In the OpenAI API reference, items here might contain text or image values, while ModerationItemType contains text and image_url.

Could you please add an integration test as well, it is challenging to nail down all the details!

Doc link: https://platform.openai.com/docs/api-reference/moderations/create?lang=curl

image

Harassment []ModerationItemType `json:"harassment"`
HarassmentThreatening []ModerationItemType `json:"harassment/threatening"`
Sexual []ModerationItemType `json:"sexual"`
Hate []ModerationItemType `json:"hate"`
HateThreatening []ModerationItemType `json:"hate/threatening"`
Illicit []ModerationItemType `json:"illicit"`
IllicitViolent []ModerationItemType `json:"illicit/violent"`
SelfHarmIntent []ModerationItemType `json:"self-harm/intent"`
SelfHarmInstructions []ModerationItemType `json:"self-harm/instructions"`
SelfHarm []ModerationItemType `json:"self-harm"`
SexualMinors []ModerationItemType `json:"sexual/minors"`
Violence []ModerationItemType `json:"violence"`
ViolenceGraphic []ModerationItemType `json:"violence/graphic"`
}

// ModerationResponse represents a response structure for moderation API.
Expand All @@ -87,15 +166,18 @@ type ModerationResponse struct {

// Moderations — perform a moderation api call over a string.
// Input can be an array or slice but a string will reduce the complexity.
func (c *Client) Moderations(ctx context.Context, request ModerationRequest) (response ModerationResponse, err error) {
if _, ok := validModerationModel[request.Model]; len(request.Model) > 0 && !ok {
func (c *Client) Moderations(ctx context.Context,
request ModerationRequestConverter) (response ModerationResponse, err error) {
realRequest := request.Convert()

if _, ok := validModerationModel[realRequest.Model]; len(realRequest.Model) > 0 && !ok {
err = ErrModerationInvalidModel
return
}
req, err := c.newRequest(
ctx,
http.MethodPost,
c.fullURL("/moderations", withModel(request.Model)),
c.fullURL("/moderations", withModel(realRequest.Model)),
withBody(&request),
)
if err != nil {
Expand Down
Loading
Loading