Clarifai / clarifai-php

Clarifai client library for PHP
Other
21 stars 3 forks source link

Receiving error: "Call to undefined method Clarifai\DTOs\Predictions\FaceDetection::name()" with Workflow #6

Closed makeitaboldmove closed 4 years ago

makeitaboldmove commented 4 years ago

We have a Workflow setup as follows:

Below is (part of) our code:

$this->client = new ClarifaiClient($this->api_key);

$response = $this->client->workflowPredict(
    'workflow-here',
    new ClarifaiURLImage('https://oururl.com/tset-iafiralc/face-detection.jpg')
    // new ClarifaiURLImage('https://oururl.com/tset-iafiralc/nsfw.jpg')

)->executeSync();

if($response->isSuccessful()){
    echo "Response is successful.\n";

    /** @var WorkflowPredictResult $workflowResult */
    $workflowResult = $response->get();

    echo "Predicted concepts:\n";
    /** @var Concept $concept */
    foreach($workflowResult->workflowResult()->predictions() as $output){
        echo 'Predictions for output ' . $output->id() . "\n";
        /** @var Concept $concept */
        foreach($output->data() as $concept){
            echo "\t" . $concept->name() . ': ' . $concept->value() . "\n";
        }
    }
} else{
    echo "Response is not successful. Reason: \n";
    echo $response->status()->description() . "\n";
    echo $response->status()->errorDetails() . "\n";
    echo "Status code: " . $response->status()->statusCode();
}

After running the above code we end up with the error:

An uncaught Exception was encountered

Type: Error
Message: Call to undefined method Clarifai\DTOs\Predictions\FaceDetection::name()

However, when using the sample puppy.jpeg found the docs we receive this without errors:

Response is successful.
Predicted concepts:
Predictions for output a0a5ca2[...]
Predictions for output 8248534[...]
    sfw: 0.9997224
    nsfw: 0.0002775723

It seems when the API detects a face successfully it breaks. Any idea for a patch?

Thanks!

rok-povsic commented 4 years ago

Hello @makeitaboldmove,

The values inside the $output->data() list are not always of type Concept, they depend on the model. In your case, since you're using the Face Detection model, the list will contain objects of type FaceDetection.

You're getting that error because FaceDetection doesn't have a method name(). But it does have a method crop(), which returns the rectangle around the face.

Changing the foreach part of your code to the following will likely solve your issue:

/** @var FaceDetection $faceDetection */
foreach($output->data() as $faceDetection){
    echo "\tA face was detected here: " . $faceDetection->crop() . "\n";
}
makeitaboldmove commented 4 years ago

Thank you for your response. We ended up going the cURL route. During development, we realized the output from the face detection workflow result was different as you mentioned above.

Even though it's cURL based here's our code just in case someone else wants to use it. When/if we get time to revert to the PHP client we'll share that as well.

function clarifai_check($image_url){
    $api_key = 'APIKEYGOESHERE';
    $continue = true;

    // Init curl
    $ch = curl_init('https://api.clarifai.com/v2/workflows/WORKFLOWNAMEGOESHERE/results');
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
        'inputs' => [
            [
                'data' => [
                    'image' => [
                        'url' => $image_url
                    ]
                ]
            ]
        ]
    ]));
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        "Authorization: Key $api_key",
        'Content-Type: application/json'
    ]);
    $result = json_decode(curl_exec($ch));
    curl_close($ch);

    if(!$result){
        $continue = false;
    } else{

        $status_code = $result->status->code;
        if($status_code !== 10000){
            $continue = false;
        } else{

            $workflow_results = $result->results;
            if(!$workflow_results){
                $continue = false;
            } else{

                foreach($workflow_results as $workflow_result){
                    $outputs = $workflow_result->outputs;
                    if(!$outputs){
                        $continue = false;
                        break;
                    } else{

                        foreach($outputs as $output){
                            $model = $output->model->name;

                            // Change model type
                            switch($model){

                                // NSFW
                                case 'nsfw-v1.0':

                                    $concepts = $output->data->concepts ?? false;
                                    if(!$concepts){
                                        $continue = false;
                                        break;
                                    } else{

                                        foreach($concepts as $concept){
                                            switch($concept->name){
                                                case 'nsfw':

                                                    // 0.55 seems to be where things get very risque
                                                    if($concept->value >= 0.55){
                                                        $continue = false;
                                                        break;
                                                    }
                                                break;
                                            }
                                        }
                                    }

                                break;
                                case 'face':

                                    $regions = $output->data->regions ?? false;

                                    // No face detected
                                    if(!$regions){
                                        $continue = false;
                                        break;
                                    }

                                break;
                            }
                        }
                    }
                }
            }
        }
    }
    return $continue;
}