Use Go and Clarifai API to Recognize NSFW Images

The ‘Not Safe For Work’ (NSFW) model analyzes images and videos and returns probability scores on the likelihood that the image or video contains pornography. For those of you who don’t know what NSFW is, we’re talking about Not Safe For Work. R-rated content. Stuff that would probably get you fired if you were looking at it at work.

I was reading “How To Use Clarifai To Protect Your Eyes From Seeing Something They Can’t Unsee” and thought of writing a Go program instead of Python, as used in that blog post.

To write our Go program, we shall build upon what we learned in my previous article “Using Go with an image and video recognition API from Clarifai”.

Models

When images or videos are run through the tag endpoint, they are tagged using a model. A model is a trained classifier that can recognize what’s inside an image or video according to what it ‘knows’. Different models are trained to ‘know’ different things. Running an image or video through different models can produce drastically different results.

If you’d like to get tags for an image or video using a different model, you can do so by passing in a model parameter. If you omit this parameter, the API will use the default model for your application.

NSFW

The ‘Not Safe For Work’ model analyzes images and videos and returns probability scores on the likelihood that the image or video contains pornography.

The response for NSFW returns probabilities for nsfw (Not Safe For Work) and sfw (Safe For Work) that sum to 1.0. Generally, if the nsfw probability is less than 0.15, it is most likely Safe For Work. If the nsfw probability is greater than 0.85, it is most likely Not Safe For Work.

We shall be using the Model: nsfw-v1.0 and the following image available at the url — https://samples.clarifai.com/nsfw.jpg:

nsfw

Here’s the complete code for our Go program “mynsfw.go”.

package main

import (
        "encoding/json"
        "fmt"
        "net/http"
        "net/url"
        "strings"
)

const (
        clientID     = "Your ClientID"
        clientSecret = "Your Client Secret"
)

type TokenResp struct {
        AccessToken string `json:"access_token"`
        ExpiresIn   int    `json:"expires_in"`
        Scope       string `json:"scope"`
        TokenType   string `json:"token_type"`
}

type TagResp struct {
        StatusCode string `json:"status_code"`
        StatusMsg string `json:"status_msg"`
        Meta struct {
                Tag struct {
                        Timestamp float64 `json:"timestamp"`
                        Model string `json:"model"`
                        Config string `json:"config"`
                } `json:"tag"`
        } `json:"meta"`
        Results []struct {
                Docid uint64 `json:"docid"`
                URL string `json:"url"`
                StatusCode string `json:"status_code"`
                StatusMsg string `json:"status_msg"`
                LocalID string `json:"local_id"`
                Result struct {
                        Tag struct {
                                ConceptIds []string `json:"concept_ids"`
                                Classes []string `json:"classes"`
                                Probs []float64 `json:"probs"`
                        } `json:"tag"`
                } `json:"result"`
                DocidStr string `json:"docid_str"`
        } `json:"results"`
}

type NSFWResp struct {
        StatusCode string `json:"status_code"`
        StatusMsg string `json:"status_msg"`
        Meta struct {
                Tag struct {
                        Timestamp float64 `json:"timestamp"`
                        Model string `json:"model"`
                        Config string `json:"config"`
                } `json:"tag"`
        } `json:"meta"`
        Results []struct {
                Docid float64 `json:"docid"`
                URL string `json:"url"`
                StatusCode string `json:"status_code"`
                StatusMsg string `json:"status_msg"`
                LocalID string `json:"local_id"`
                Result struct {
                        Tag struct {
                                Classes []string `json:"classes"`
                                Probs []float64 `json:"probs"`
                        } `json:"tag"`
                } `json:"result"`
                DocidStr string `json:"docid_str"`
        } `json:"results"`
}

func main() {
        accessToken, err := requestAccessToken()
        if err != nil {
                fmt.Println(err)
        }
        
        nsfw, err := getNSFW(accessToken)
        if err != nil {
                fmt.Println(err)
        }

        if nsfw[0] > nsfw[1] {
            fmt.Println("Safe for work, you can trust Bob again (for now)!")
        } else {
            fmt.Println("Not safe for work. Classic Bob.")
        }
}

func requestAccessToken() (string, error) {
        form := url.Values{}
        form.Set("grant_type", "client_credentials")
        form.Set("client_id", clientID)
        form.Set("client_secret", clientSecret)
        formData := strings.NewReader(form.Encode())

        url := fmt.Sprintf("https://api.clarifai.com/v1/token/")

        req, err := http.NewRequest("POST", url, formData)
        if err != nil {
                return "", err
        }

        req.Header.Set("Content-Type", "application/x-www-form-urlencoded")

        httpClient := &http.Client{}

        resp, err := httpClient.Do(req)
        if err != nil {
                return "", err
        }

        defer resp.Body.Close()

        var record TokenResp

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

        return record.AccessToken, nil
}

func getNSFW(token string) ([]float64, error) {
        // Analyze the image at https://samples.clarifai.com/nsfw.jpg
        url := fmt.Sprintf("https://api.clarifai.com/v1/tag/?model=nsfw-v1.0&url=https://samples.clarifai.com/nsfw.jpg")

        req, err := http.NewRequest("GET", url, nil)
        if err != nil {
                return nil, err
        }

        req.Header.Set("Content-Type", "application/json")
        req.Header.Set("Authorization", "Bearer "+token)

        httpClient := &http.Client{}

        resp, err := httpClient.Do(req)
        if err != nil {
                return nil, err
        }

        defer resp.Body.Close()
        
        var record NSFWResp

        if err := json.NewDecoder(resp.Body).Decode(&record); err != nil {
                return nil, err
        }
        
        return record.Results[0].Result.Tag.Probs, nil
}

The main thing to observe in the above program is the url:

url := fmt.Sprintf(“https://api.clarifai.com/v1/tag/?model=nsfw-v1.0&url=https://samples.clarifai.com/nsfw.jpg")

in the function:

func getNSFW(token string) ([]float64, error) {

and the new structure:

type NSFWResp struct {
        StatusCode string `json:”status_code”`
        StatusMsg string `json:”status_msg”`
        Meta struct {
                Tag struct {
                        Timestamp float64 `json:”timestamp”`
                        Model string `json:”model”`
                        Config string `json:”config”`
                } `json:”tag”`
        } `json:”meta”`
        Results []struct {
                Docid float64 `json:”docid”`
                URL string `json:”url”`
                StatusCode string `json:”status_code”`
                StatusMsg string `json:”status_msg”`
                LocalID string `json:”local_id”`
                Result struct {
                        Tag struct {
                                Classes []string `json:”classes”`
                                Probs []float64 `json:”probs”`
                        } `json:”tag”`
                } `json:”result”`
                DocidStr string `json:”docid_str”`
        } `json:”results”`
}

When you run the program:

go run mynsfw.go

The output you get is:

Safe for work, you can trust Bob again (for now)!

That’s it!

Advertisements

About indianguru

http://satishtalim.com/
This entry was posted in Go, Tutorials and tagged , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s