Vue.js で axios await/async を使って Azure Face API にファイルアップロードのデータを application/octet-stream で送るメモです。
Node.js で送る方法はこちら
今回は Vue.js でフロントエンドの JavaScript で行う方法です。もし、 Node.js で送る場合は以下を参考ください。
axios await/async で受信した画像を application/octet-stream でAzure Face APIに送るメモ
ともあれ、Array Bufferでデータを送るところは、そのまま参考にできます。
おもな仕組み
Vue.js でファイルアップロードの入力から、FileReaderクラスでデータを取り出します。さらにそこから、readAsArrayBuffer を使って ArrayBuffer としてデータを取り出します。
本来は onnload でリスナーを使って取り出しますが、Promiseでくるんで await / async で呼び出せるようにしています。
あとは、axios await/async で受信した画像を application/octet-stream でAzure Face APIに送るメモ で行っている流れと同じです。
ソースコード
実際に動くコードはこちらです。Bootstrap Vueを使って見た目をサッと作りやすいので、ブログ用にこうしています。
'Ocp-Apim-Subscription-Key':'Key'
の部分の ‘Key’ を自分のキーに置き換えてください。
- Windows 10
- Google Chrome
で検証しています。
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Vue.js FaceAPI as FileData</title> <!-- Load required Bootstrap and BootstrapVue CSS --> <link rel="stylesheet" href="//unpkg.com/bootstrap/dist/css/bootstrap.min.css" /> <link rel="stylesheet" href="//unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue.min.css" /> <!-- Load polyfills to support older browsers --> <script src="//polyfill.io/v3/polyfill.min.js?features=es2015%2CIntersectionObserver" crossorigin="anonymous"></script> <!-- Load Vue followed by BootstrapVue --> <script src="//unpkg.com/vue@latest/dist/vue.min.js"></script> <script src="//unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue.min.js"></script> <!-- Load the following for BootstrapVueIcons support --> <script src="//unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue-icons.min.js"></script> </head> <body> <div class="container"> <div id="appFaceAPI-File"> <div class="row"> <div class="col"> <h1>Vue.js FaceAPI as FileData</h1> </div> </div> <div class="row"> <div class="col"> <div class="form-group"> <!-- https://bootstrap-vue.org/docs/components/form-file --> <div> <!-- Styled --> <b-form-file v-model="file" :state="Boolean(file)" placeholder="Choose a file or drop it here..." drop-placeholder="Drop file here..." @change="handlerFileChange" ></b-form-file> <div class="mt-3">Selected file: {{ file ? file.name : '' }}</div> </div> </div> </div> </div> <div class="row"> <div class="col"> <h2>response JSON Data : </h2> <pre><code>{{ response }}</code></pre> </div> </div> </div> </div> <!-- axios --> <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> <script> const app = new Vue({ el: '#appFaceAPI-File', data: { response: '', file: null }, methods: { handlerFileChange: async function (e) { console.log('handlerFileChange'); // 1. ファイルアップロードの入力から、まずファイル情報を取り出す // ここはファイル選択した瞬間に発動 const files = e.target.files || e.dataTransfer.files; const file = files[0]; // 2. ファイル参照の中から ArrayBuffer としてデータを取り出す let contentBuffer = await this.readFileAsync(file); // console.log(contentBuffer); this.sendCognitiveAsFile(contentBuffer); }, // ファイル情報の中から ArrayBuffer としてデータを取り出す // 本来 onnload で取り出すが await / async で呼び出せるようにしている readFileAsync: function (file) { return new Promise((resolve, reject) => { let reader = new FileReader(); reader.onload = () => { resolve(reader.result); }; reader.onerror = reject; reader.readAsArrayBuffer(file); }) }, // このあたりは以下の記事を参考に。 // https://www.1ft-seabass.jp/memo/2020/05/07/azure-face-api-application-octet-stream-using-axios/ sendCognitiveAsFile: async function(contentBuffer) { // エンドポイント // 米国西部2の場合は West US 2 なので、 westus2.api.cognitive.microsoft.com // // 設定 // returnFaceId true // recognitionModel detection_02 // detectionModel detection_02 const FACE_API_ENDPOINT_URL = 'https://westus2.api.cognitive.microsoft.com/face/v1.0/detect?returnFaceId=true&returnFaceLandmarks=false&recognitionModel=recognition_02&returnRecognitionModel=false&detectionModel=detection_02'; // サブスクリプションをOcp-Apim-Subscription-Keyヘッダーに // 画像で送るのでContent-typeヘッダーにapplication/octet-stream指定 const config = { url: FACE_API_ENDPOINT_URL, method: 'post', headers: { 'Content-type': 'application/octet-stream', 'Ocp-Apim-Subscription-Key':'Key' }, data: contentBuffer }; // axios try { // POSTリクエストで送る const responseAzure = await axios.request(config); console.log('post OK'); // データ送信が成功するとレスポンスが来る console.log(responseAzure.data); // this.response = JSON.stringify( response.data, null , "\t"); } catch (error) { console.log('post Error'); // ダメなときはエラー console.error(error); } } } , mounted() { console.log('mounted'); } }) </script> </body> </html>
そして、以下のよう動きます。
サブスクリプションキーが見えてしまうので対策の必要はあり
どこかにログインしているような場所でユーザーごとしか見れない状態であればこれでもいいですね。ただ、このまま誰でも見れる形で公開しするとサブスクリプションキーがソースコードで見えてしまうので、そのときは、なにかしらバックエンドで隠蔽したり対策の必要ですね。