Microsoft Cognitive Services を使ったサンプルを ABC 2017 Spring で作ってみたら動かなくて悲しい目にあったので、全部スマホでやってた処理を、きちんとサーバーサイドとクライアントサイドにわけてデータも1度処理したものは永続化してというのをやってサンプルプログラムにしてみました。
どんなプログラムなの?
Twitter から #microsoft のハッシュタグを検索して画像を収集するアプリケーションになります。収集した画像は、Microsoft Cognitive Services の Vision API を使ってカテゴリ分けを行い、画像がどんなものかという説明文も Vision API を使って生成しています。 Vision API の結果は英語でかえってくるので Microsoft Cognitive Services の Translator Text API を使って日本語に翻訳しています。
カテゴリ分けされた画像のデータは Microsoft Azure の Cosmos DB に保存しています。画像の収集と Vision API による認識処理は Azure Functions を使って定周期で実行しています。
クライアントアプリケーションは Xamarin.Forms で作ってるので Android / iOS / UWP で動かすことが出来ますが作業環境の都合上 iOS で動作確認が出来てません!後でやらないと…。クライアントアプリケーションの実行結果は以下のような感じになります。
ポイント
何を見たらいいのだろうか?
Cognitive Services API の呼び出し方
Cognitive Services の API を呼び出すコード例として見ることが出来ると思います。具体的には VisionService
クラスあたりがそれになります。
Cosmos DB に C# からアクセスする方法
Cosmos DB に対して C# からアクセスする際のコード例になります。DBの作成からデータの追加検索を行っています。また、データ件数が多くなったときのページング処理も実装しています。
Prism.Forms を使ったコード例として
Prism.Forms を使ったコード例としても見てください。具体的には CognitiveServicesSample.Client
プロジェクトになります。
Xamarin.Forms の ListView を使ったインクリメンタルローディング
データは基本的に50件ずつ取得してListViewが下までスクロールされたらデータを追加で読み込むようにしています。
Xamarin.Forms の ListView には、このようなインクリメンタルローディングの処理は組み込みでサポートされていないため ListView を拡張して IncrementalLoadingListView
を作成して使っています。
実際に使っているのは CategorizedImagePage
になります。
CategorizedImagePageViewModel
に追加読み込みのロジックがあります。
作ってて諦めたことや、やらないといけないこと
.NET Standard
.NET Standard で出来るところは .NET Standard のプロジェクトにして WebAPI は ASP.NET Core で実装しようと思ってたのですが Cosmos DB の SDK の要求する .NET Standard のバージョンが 1.6 だったりした関係で UWP のプロジェクトから参照できなかったりして泣いて諦めました。
自動ビルド
リポジトリに Push したら自動でビルドしてテスト流して配備とかやるとかっこいいなぁと思ってるけど、そもそも単体テストが無い!!!一応、外部リソースに依存する部分とかは interface 切ってたりするので単体テスト書いたりできる土壌は出来てるのでそのうちやらないといけないと思いつつやってない…。
おまけとして
ここで作ってる Controller 2つですが
http://cogsample.azurewebsites.net
にデプロイしてあるので API を叩くことでデータがとってこれます。
http://cogsample.azurewebsites.net/api/Categoryで現在収集してる画像のカテゴリ一覧が取れます。
http://cogsample.azurewebsites.net/api/CategorizedImage?category=people_で指定した名前のカテゴリの画像を50件とってくることが出来ます。続きのデータを読み込みたいときは結果の JSON の Continuation の値を continuation パラメータとしてくっつけて送ることで取得できます。
結果の JSON の形式は以下のクラスを使えば JSON.NET とかでデシリアライズできます。
実際に URL を叩いてるコードは以下のクラスになります。
まとめ
突っ込みかなんかあったら PullRequest や Issue 待ってます。日本語でおk。