Perl Hackers Hub

第54回 サーバレスでもPerl―Microsoft Azure Functionsで動かそう!(3)

この記事を読むのに必要な時間:およそ 3.5 分

(1)こちら⁠2)こちらから。

関数の実装

いよいよコードを実装します。ここでは作業環境にMacを利用する前提で説明します。

まず,関数のプロジェクトとなるフォルダを用意します。顔認識をさせるプロジェクトですので,名前をFaceDetectProjectとして作っておきましょう。

プロジェクトとなるフォルダを作っておく

$ mkdir FaceDetectProject

Face APIを利用するモジュールの導入

Functionsには,Face APIへ顔認識のリクエストを行うためのバインディングが用意されていません。そのため,CPANモジュールを使用します。Face API向けのモジュールとして,MetaCPANで拙作のNet::Azure::CognitiveService::Face(執筆時点ではv0.04)を公開していますので,これを利用します。

CPANモジュールの導入には,本連載でお馴染みのcpanmを使います。プロジェクトフォルダ直下でcpanmを使い,プロジェクトにモジュールを導入します。

CPANモジュールをプロジェクトに導入する

$ cpanm -n -L local Net::Azure::CognitiveServices::Face

関数名フォルダの作成

関数名フォルダの名称はそのまま関数名となりますので,わかりやすい名称がよいでしょう。今から作るのは顔認識の結果(年齢と性別)を返す関数ですので,InspectFaceという名称で関数名フォルダを作ります。

関数名フォルダを作る

$ mkdir InspectFace

ここから先は,InspectFaceフォルダ内での作業となります。

function.jsonの作成

トリガとバインディングの設定をするために,function.jsonを作成します。InspectFaceはHTTPリクエストを受けてHTTPレスポンスを返す関数ですので,HTTPトリガを設定します。内容は,先述したHTTPトリガのfunction.jsonと同じです。

run.shの作成

関数本体となるrun.shは次の内容です。

run.sh

perl task.pl > $res

Functionsから起動されたときにtask.plを起動し,環境変数resで指定されたファイルにレスポンスデータを出力させる役割を担います。

Perlプログラムの作成

関数本体から呼び出されるtask.plを作ります。

task.pl

use strict;
use warnings;
use lib "../local/lib/perl5";
use Net::Azure::CognitiveServices::Face;
use JSON 'encode_json';

# (1)長い名前なので変数に入れて短くする
my $cog = 'Net::Azure::CognitiveServices::Face';

# (2)環境変数から,Face APIの設定値を取得する
$cog->endpoint($ENV{FACEAPI_URL});
$cog->access_key($ENV{FACEAPI_KEY});

# (3)HTTPクエリパラメータimageを取得する
my $image_url = $ENV{REQ_QUERY_IMAGE};

# (4)デフォルトのレスポンスを定義する
my $res = {
    status => 400,
    headers => {'Content-Type' => 'application/json'},
    body => {
    message => 'parameter "image" is required',
        }
};

# (5)画像URLが指定されている場合のみ顔認識を試みる
if ($image_url) {

    # (6)Face APIクライアントを使って顔認識を行う
    my $faceapi = $cog->Face;
    my $result = $faceapi->detect(
        $image_url,
        returnFaceAttributes => ['age', 'gender']
    );

    # (7)認識した顔情報から年齢と性別を抽出する
    my @faces = ();
    if ($result->[0]) {
        @faces = map { $_->{faceAttributes} } @$result;
    }

    # (8)レスポンスデータを上書きする
    $res = {
        status => 200,
        headers => {
            'Content-Type' => 'application/json'
        },
        body => {
            faces => [@faces]
        }
    };
}

# (9)レスポンスを返す
print encode_json($res);

冒頭のuse文では,4行目でNet::Azure::CognitiveService::Faceモジュールを利用するので,3行目でライブラリパスの指定を行っています。名前が長いモジュールですので,(1)で変数$cogにモジュール名を代入し,表記を短縮しています。5行目ではJSONモジュールをuseしていますが,これはレスポンスをJSON形式にするためです。

(2)では,Net::Azure::CognitiveService::Faceに対し,Face APIのエンドポイントURLとFace APIのアクセスキーを渡しています。これらの値は,のちほど環境変数の設定を行うときに登場します。

(3)では,HTTPリクエストのクエリパラメータimageを取得しています。

(4)ではデフォルトのレスポンスを定義しています。もしクエリパラメータimageが指定されていない場合,(5)の条件分岐で顔認識を行うロジックに入らず,そのまま400エラーを返すためです。

(6)でFace APIに顔認識のリクエストを行い,レスポンスを受け取ります。顔が認識された場合は,(7)で認識した顔情報から年齢と性別を取り出し,@facesに格納します。顔が認識されなかった場合は何もしません。

(8)でレスポンスデータを正常系のものに上書きしています。このとき,bodyに@facesを配列リファレンスに展開します。

そして(9)でレスポンスデータをJSONに変換して,printで出力しています。run.shではtask.plの出力内容をそのまま環境変数resで指定されているファイルにリダイレクトしており,これでFunctionsにレスポンスを引き渡すことができています。