aboutsummaryrefslogtreecommitdiff
path: root/web/openai/moderation/moderation.go
blob: 7f73bf29efc38d192b476ac92af7dcf37eab17ce (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package moderation

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"strings"
)

type Request struct {
	Input string `json:"input"`
}

type Response struct {
	ID      string    `json:"id"`
	Model   string    `json:"model"`
	Results []Results `json:"results"`
}

func (r Response) Flagged() bool {
	var result bool

	for _, set := range r.Results {
		if set.Flagged {
			result = true
		}
	}

	return result
}

func (r Response) Reasons() string {
	if !r.Flagged() {
		return ""
	}

	var sb strings.Builder

	fmt.Fprintln(&sb, "Your request failed for the following reasons:")
	fmt.Fprintln(&sb)

	for _, set := range r.Results {
		if set.Categories.Hate {
			fmt.Fprintln(&sb, "- hate")
		}
		if set.Categories.HateThreatening {
			fmt.Fprintln(&sb, "- hate (threatening)")
		}
		if set.Categories.SelfHarm {
			fmt.Fprintln(&sb, "- self harm")
		}
		if set.Categories.Sexual {
			fmt.Fprintln(&sb, "- sexual")
		}
		if set.Categories.SexualMinors {
			fmt.Fprintln(&sb, "- sexual (minors)")
		}
		if set.Categories.Violence {
			fmt.Fprintln(&sb, "- violence")
		}
		if set.Categories.ViolenceGraphic {
			fmt.Fprintln(&sb, "- violence (graphic)")
		}
	}

	return sb.String()
}

type Categories struct {
	Hate            bool `json:"hate"`
	HateThreatening bool `json:"hate/threatening"`
	SelfHarm        bool `json:"self-harm"`
	Sexual          bool `json:"sexual"`
	SexualMinors    bool `json:"sexual/minors"`
	Violence        bool `json:"violence"`
	ViolenceGraphic bool `json:"violence/graphic"`
}
type CategoryScores struct {
	Hate            float64 `json:"hate"`
	HateThreatening float64 `json:"hate/threatening"`
	SelfHarm        float64 `json:"self-harm"`
	Sexual          float64 `json:"sexual"`
	SexualMinors    float64 `json:"sexual/minors"`
	Violence        float64 `json:"violence"`
	ViolenceGraphic float64 `json:"violence/graphic"`
}
type Results struct {
	Categories     Categories     `json:"categories"`
	CategoryScores CategoryScores `json:"category_scores"`
	Flagged        bool           `json:"flagged"`
}

type Client struct {
	httpCli *http.Client
	apiKey  string
}

func (c Client) Check(ctx context.Context, input string) (*Response, error) {
	data := Request{
		Input: input,
	}
	payloadBytes, err := json.Marshal(data)
	if err != nil {
		return nil, err
	}
	body := bytes.NewReader(payloadBytes)

	req, err := http.NewRequestWithContext(ctx, http.MethodPost, "https://api.openai.com/v1/moderations", body)
	if err != nil {
		return nil, err
	}
	req.Header.Set("Authorization", "Bearer "+c.apiKey)
	req.Header.Set("Content-Type", "application/json")

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	var result Response
	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		return nil, err
	}

	return &result, nil
}