cx-content-moderation/main.go (86 lines of code) (raw):
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"context"
"fmt"
"log"
"os"
documentai "cloud.google.com/go/documentai/apiv1beta3"
"cloud.google.com/go/documentai/apiv1beta3/documentaipb"
"google.golang.org/api/option"
"github.com/googlecloudplatform/ezcx"
)
var (
contentModerationProcessorName = envCheck("CONTENT_MODERATION_NAME", "")
port = envCheck("PORT", "8080")
)
const location = "us"
func main() {
log.Printf("cx-content-moderation")
if contentModerationProcessorName == "" {
log.Fatal("need to provide CONTENT_MODERATION_NAME reference to name of Content Moderation API Document Processor name")
}
ctx := context.Background()
server := ezcx.NewServer(ctx, ":"+port, log.Default())
server.HandleCx("/analyze", analyzeCommentHandler)
server.ListenAndServe(ctx)
}
// analyzeCommentHandler is the Dialogflow CX interface for the Content Moderation API
func analyzeCommentHandler(res *ezcx.WebhookResponse, req *ezcx.WebhookRequest) error {
params := req.GetSessionParameters()
text := req.GetText()
if text == "" {
return fmt.Errorf("no text provided")
}
// perform content moderation on text
ctx := context.Background()
resp, err := rateToxicityContentModeration(ctx, text)
if err != nil {
log.Printf("unable to process document: %v", err)
return err
}
// map the content moderation API results to a CX Session parameter
attributes := make(map[string]interface{})
for _, attribute := range resp.Document.Entities {
attributes[attribute.GetType()] = attribute.GetConfidence()
}
if params == nil {
params = make(map[string]interface{})
}
params["content-moderation"] = attributes
// add this parameter to the response parameters
err = res.AddSessionParameters(params)
if err != nil {
log.Printf("unable to add content-moderation session params: %v", err)
}
log.Printf("%+v", res)
return nil
}
// rateToxicityContentModeration invokes the Content Moderation API DocumentAI Processor with a given text content string
func rateToxicityContentModeration(ctx context.Context, content string) (*documentaipb.ProcessResponse, error) {
resp := &documentaipb.ProcessResponse{}
c, err := documentai.NewDocumentProcessorClient(ctx, option.WithEndpoint(apiEndpoint()))
if err != nil {
log.Printf("error creating Document Processor client: %v", err)
return resp, err
}
defer c.Close()
req := &documentaipb.ProcessRequest{
Source: &documentaipb.ProcessRequest_InlineDocument{
InlineDocument: &documentaipb.Document{
Text: content,
MimeType: "text/plain",
},
},
Name: contentModerationProcessorName,
}
resp, err = c.ProcessDocument(ctx, req)
if err != nil {
return resp, err
}
return resp, nil
}
// apiEndpoint returns the URL of the Document AI API endpoint based upon the
// user's choice for the Document AI API location
func apiEndpoint() string {
return fmt.Sprintf("%s-documentai.googleapis.com:443", location)
}
// envCheck checks for an environment variable, otherwise returns default
func envCheck(environmentVariable, defaultVar string) string {
envar, ok := os.LookupEnv(environmentVariable)
if envar == "" || !ok {
return defaultVar
}
return envar
}