tag:crieit.net,2005:https://crieit.net/tags/GoogleCloudFunctions/feed
「GoogleCloudFunctions」の記事 - Crieit
Crieitでタグ「GoogleCloudFunctions」に投稿された最近の記事
2019-04-04T12:15:17+09:00
https://crieit.net/tags/GoogleCloudFunctions/feed
tag:crieit.net,2005:PublicArticle/14557
2018-10-01T06:40:00+09:00
2019-04-04T12:15:17+09:00
https://crieit.net/posts/Nuxt-js-Firebase-AI-API
Nuxt.js+FirebaseでAIメーカーのAPIを使ったサンプルを作った
<p>先日<a target="_blank" rel="nofollow noopener" href="https://aimaker.io">AIメーカー</a>にてAPIが公開されたので、試しにAPIを使ったWebアプリケーションを作ってみました。今回は画像をアップしなくても、ボタンを押すだけで自分のTwitterアイコンで判定できるようにしてみました。</p>
<p>ちなみに、現在はAIメーカー本家にもTwitterアイコンで判定できる機能が実装されています。個人開発のサービスでAPIまで公開されているものは珍しいので遊んでみたくなりました。</p>
<h2 id="もくじ"><a href="#%E3%82%82%E3%81%8F%E3%81%98">もくじ</a></h2>
<ul>
<li><a href="#環境構築">環境構築</a></li>
<li><a href="#開発環境の準備">開発環境の準備</a></li>
<li><a href="#Nowにデプロイ">Nowにデプロイ ← デモURLはこちら</a></li>
<li><a href="#細かい処理の流れ">細かい処理の流れ</a></li>
</ul>
<p><a href="https://crieit.now.sh/upload_images/2e35e1d2d635c0517a73a678b03be4cd5baf1dcbc55a1.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/2e35e1d2d635c0517a73a678b03be4cd5baf1dcbc55a1.png?mw=700" alt="ai maker api tester.png" /></a></p>
<h2 id="構築環境"><a href="#%E6%A7%8B%E7%AF%89%E7%92%B0%E5%A2%83">構築環境</a></h2>
<ul>
<li>Nuxt.js</li>
<li>Firebase Authentication</li>
<li>Google Cloud Functions</li>
<li>Now</li>
</ul>
<p>という感じのサーバーレス構成です。GitHubから取得してNowにデプロイするまでをざっと説明していきます。</p>
<h2 id="開発環境の準備"><a href="#%E9%96%8B%E7%99%BA%E7%92%B0%E5%A2%83%E3%81%AE%E6%BA%96%E5%82%99">開発環境の準備</a></h2>
<p>ソースはGitHubにあげてあります。基本的な流れはそちらのREADMEにも書いてあります。</p>
<p><a target="_blank" rel="nofollow noopener" href="https://github.com/dala00/ai-maker-api-sample">dala00/ai-maker-api-sample</a></p>
<h3 id="依存関係のインストール"><a href="#%E4%BE%9D%E5%AD%98%E9%96%A2%E4%BF%82%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB">依存関係のインストール</a></h3>
<pre><code class="bash">yarn
</code></pre>
<h3 id="AIメーカーのapikeyを取得"><a href="#AI%E3%83%A1%E3%83%BC%E3%82%AB%E3%83%BC%E3%81%AEapikey%E3%82%92%E5%8F%96%E5%BE%97">AIメーカーのapikeyを取得</a></h3>
<p>AIメーカーにログインし、他の方が作成されているAIの詳細画面にあるAPIのパラメータを見ると自分のapikeyが表示されていますので、そちらをメモっておきます。</p>
<h3 id="Firebaseの環境設定"><a href="#Firebase%E3%81%AE%E7%92%B0%E5%A2%83%E8%A8%AD%E5%AE%9A">Firebaseの環境設定</a></h3>
<p>予めFirebaseに登録し、Firebase Consoleにてプロジェクトを作成しておきます。</p>
<p><a href="https://crieit.now.sh/upload_images/b5fc524ced36ebb16780d221010fcfcd5baefe99c88ec.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/b5fc524ced36ebb16780d221010fcfcd5baefe99c88ec.png?mw=700" alt="Firebaseのウェブアプリ設定" /></a></p>
<p>プロジェクトの設定画面を開くとこのボタンがありますので、クリックして設定情報を取得します。</p>
<p><code>env.sample.js</code>というファイルがありますので、それを<code>env.development.js</code>、<code>env.production.js</code>としてコピーし、各ファイルの中身を上記で取得した設定で埋めておきます(CLOUD_FUNCTIONS_BASE_URL以外)。</p>
<h4 id="Authenticationの設定"><a href="#Authentication%E3%81%AE%E8%A8%AD%E5%AE%9A">Authenticationの設定</a></h4>
<p>Twitterログインを使用していますので、Firebase ConsoleのAuthenticationのログイン方法設定でTwitterを有効にしておきます。(<a target="_blank" rel="nofollow noopener" href="https://developer.twitter.com/">Twitter側でのアプリケーションの設定</a>も必要です)</p>
<h4 id="Cloud Functionsの設定"><a href="#Cloud+Functions%E3%81%AE%E8%A8%AD%E5%AE%9A">Cloud Functionsの設定</a></h4>
<p>firebase-toolsをPCにインストールし、シェルでfunctions関連の操作を行えるようにします。それを使ってfirebaseにログインし、functionsを初期化します。</p>
<pre><code class="bash">npm install -g firebase-tools
firebase login
firebase init functions
</code></pre>
<h5 id="アプリケーションの設定"><a href="#%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AE%E8%A8%AD%E5%AE%9A">アプリケーションの設定</a></h5>
<p>functions内で使う値を設定しておきます。許可するURLとAIメーカーのapikeyの設定です。</p>
<pre><code class="bash">firebase functions:config:set cors.origin=http://localhost:3000
firebase functions:config:set ai_maker.apikey=apikeygotfromaimaker
</code></pre>
<h5 id="functionsをデプロイ"><a href="#functions%E3%82%92%E3%83%87%E3%83%97%E3%83%AD%E3%82%A4">functionsをデプロイ</a></h5>
<pre><code class="bash">firebase deploy --only functions
</code></pre>
<p>これでfunctionsの管理画面を見るとURLが表示されているので、前述のCLOUD_FUNCTIONS_BASE_URLに値を入れておきます。imageClassificationの前のスラッシュまで入れます。</p>
<h3 id="ローカルで起動"><a href="#%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%AB%E3%81%A7%E8%B5%B7%E5%8B%95">ローカルで起動</a></h3>
<p>問題なければこれでローカル環境で動くようになっていると思います。開発モードで起動し、<code>http://localhost:3000</code>にアクセスします。</p>
<pre><code class="bash">yarn run dev
</code></pre>
<h2 id="Nowにデプロイ"><a href="#Now%E3%81%AB%E3%83%87%E3%83%97%E3%83%AD%E3%82%A4">Nowにデプロイ</a></h2>
<pre><code class="bash">now
</code></pre>
<p>これでデプロイできます。デプロイ時にURLが表示されますので、あとはFirebase Authenticationの許可ホスト名にそのホスト名を設定しておきます。また、cors.originも本番のURLを指定します。</p>
<p>デプロイするたびにホスト名が変わってしまいますが、その度に毎回設定するのは非常に面倒なので、何度もデプロイする場合は<code>now alias</code>を利用するとよいでしょう。一つ固定のホスト名を指定しておき、デプロイ時に発行されるURLにそれを関連付ける事ができます。</p>
<p>下記は実際にデプロイしたデモです。(しばらく誰もアクセスしていないと一度止まるようですので、その場合にアクセスすると表示されるまでに少々時間がかかります)</p>
<p><a target="_blank" rel="nofollow noopener" href="https://ai-maker-api-tester.now.sh">https://ai-maker-api-tester.now.sh</a></p>
<p>あと細かい調整をしていないのですが、Twitterログインから戻ってきた直後は少しだけログイン前の画面の表示になっています。待っていればログイン状態になり判定が行われます。(その他も変な挙動があるかもしれません。SPAだとgetRedirectResultのコールバックとか何度も呼ばれてるかも)</p>
<h2 id="細かい処理の流れ"><a href="#%E7%B4%B0%E3%81%8B%E3%81%84%E5%87%A6%E7%90%86%E3%81%AE%E6%B5%81%E3%82%8C">細かい処理の流れ</a></h2>
<p>細かい処理の流れを簡単に説明しておきます。</p>
<h3 id="データ"><a href="#%E3%83%87%E3%83%BC%E3%82%BF">データ</a></h3>
<p>データは data/ai.js の中に配列で定義されています。現在AIの一覧取得APIは無いようですので、必要な分だけここで定義しておきます。</p>
<h3 id="Twitterアイコンをfunctionsに送信"><a href="#Twitter%E3%82%A2%E3%82%A4%E3%82%B3%E3%83%B3%E3%82%92functions%E3%81%AB%E9%80%81%E4%BF%A1">Twitterアイコンをfunctionsに送信</a></h3>
<p>apikeyは隠したいため、functionsのconfigに設定し、function内でAIメーカーのAPIを実行します。そのため、Nuxt側からはAIのidとTwitterアイコンURLだけをfunctionに送信します。</p>
<pre><code class="javascript"> const params = {
id: this.ai.id,
image: this.$store.state.user.photoURL
};
axios
.post(
process.env.CLOUD_FUNCTIONS_BASE_URL + "imageClassification",
params
)
.then(response => {
this.labels = response.data.labels;
})
.catch(error => {
});
</code></pre>
<h3 id="function内でAPIを実行"><a href="#function%E5%86%85%E3%81%A7API%E3%82%92%E5%AE%9F%E8%A1%8C">function内でAPIを実行</a></h3>
<p>Firebaseで取得できる画像URLは小さい画像のもので、これだといい感じに判定されないため大きい画像のURLに変換します。まずそのURLの画像を取得しておき、それをAPIに送信します。画像ファイル名も送信する必要があります。</p>
<pre><code class="javascript"> const form = new FormData();
const image = await getImage(req.body.image.replace("normal.", "400x400."));
form.append("id", req.body.id);
form.append("apikey", functions.config().ai_maker.apikey);
form.append("file", image, getFileName(req.body.image));
form.submit(
"https://aimaker.io/image/classification/api",
(err, apiResponse) => {
if (err) {
console.error(err);
res.status(500).json({ error: true });
return;
}
chunks = [];
apiResponse
.on("data", chunk => {
chunks.push(chunk);
})
.on("end", () => {
const body = Buffer.concat(chunks).toString();
const labels = JSON.parse(body);
console.info(labels);
res.json(labels);
});
}
);
</code></pre>
<p>ここで返却した値はNuxt側でそのまま表示され、完了です。(実際にはスコア順に並び替えています)</p>
<h2 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h2>
<p>以上のように、Nuxt.js + Firebase + Cloud Functionsを利用したサーバーレス構成でのアプリケーション作成で遊んでみました。Nuxt.jsなのでSPA、SSR、PWAも可能ですし、FirebaseとCloud Functionsでサーバーを持つ必要もないので非常に気が楽ですね。</p>
<p>今回はデプロイにNowを使いましたが、GAE、Herokuでも同様のことが無料枠で可能です。</p>
<p>完成後再度環境構築までは試していないので、もし環境構築でつまづく場合があれば連絡いただければ確認します。</p>
だら@Crieit開発者