ごった煮

色々な事を書いてます

VSTSでAzure Functionsをリリースマネジメントしたかった話

VSTSでチェックインしたらデプロイみたいなことはできますけどリリース管理できなくね?ってなったのでメモ書きです。

結論

PowerShellスクリプト書きました。

下のような感じ

$path = $args[0]
$uri = "https://" + $args[1] + ".file.core.windows.net/" + $args[2] + "/site/wwwroot"
$key = $args[3]

&"c:\Program Files (x86)\Microsoft SDKs\Azure\AzCopy\AzCopy.exe" /Source:$path /Dest:$uri /DestKey:$key /S /Y

Functionsは、Azure Filesをマウントしてその中身のシンボリックリンクを張る形で配置されるのでAzCopyでAzure Filesに送り付けます。

幸いVSTSの環境には、AzCopyがいるのでそのまま使います。

引数は、

  • args[0] : Functionsのフォルダ
  • args[1] : ストレージアカウント名
  • args[2] : 共有フォルダ名
  • args[3] : ストレージアカウントの接続文字列

って感じです。

スクリプトのAzCopyの指定ですが、ほかのBlobへのデプロイをするやつのソースとかだともっと頭いい感じに書いてたので誰か教えてください

注意

これが使えるのは、Dynamicプランのみです。

Dynamicプランじゃないほうは、フォルダ構造がAzure Filesを使ってないっぽいので別の方法を頑張りましょう。

あと、VSTSのチェックインやGitHub CIをAzureポータルから設定した場合に、デプロイするとFunctionsポータル上からソースコードが編集できなくなるRead Onlyモードに切り替わりますが、

現状この方法だとフラグ立てたりしてないのでそれも切り替わらない点に注意してください。やり方知ってる人は、教えてくれると嬉しいです。

まとめ

とりあえず形だけデプロイできた(形だけ)ので誰かいい感じに改良してください。

VSTSでWeb Appsにリリースする

VSTSを使っててARMのWeb Appsにデプロイする方法のドキュメントがどこを探してもいいものが出てこなかったので備忘録な感じでまとめます。

※結構適当書いてたっぽくてなんで動いてたかよくわからないんで大幅に加筆修正しました

初めに

今回は、ASP.NET MVC5のプロジェクトをWeb Appsにデプロイします。

また、前提としてVSTSの設定でAzureのサブスクリプションを登録しておいてください。(気が向いたらそこらへんも書こうかなと)

ビルド定義の設定

とりあえずデフォルトのVisual Studioのテンプレートでビルド定義を作成してください。

Web Deolyパッケージの生成

MSBuildの設定でいい感じに引数を渡すとWeb Deploy用のパッケージが出てくるので設定します。

/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:CreatePackageOnPublish=true

 

これを下図のMSBuild Argumentsに入れます。

image

 

パッケージの移動

Web Deployパッケージは、ソースのあるフォルダの下にあるobj/~ に配置されます。

リリース定義で作ったパッケージを扱いやすいように移動します。

とりあえず下図のようにCopy Filesを追加します。

image

ファイルコピー用の設定は下図のような感じです。

image

これでビルドを回すとパッケージ完成です。

パッケージをリリースする

今回は、ARMのWeb Appsにデプロイするのでリリース定義をEmptyのテンプレートで作成します。

作成したらDeploy AzureRM Web Appのデプロイテンプレートを追加します。

image

 

設定は以下のような感じです。

image

Packageにデプロイするzipファイルを指定します。

フォルダ階層を掘っていくとPackageフォルダの下にzipファイルがあるのでそれを指定します。

image

 

まとめ

前の投稿の方法なんで動いてたんだろ。。。

Bot v3のメッセージタイプについて 概要編

v3にメッセージタイプが変更になったのでまとめです。

v1のメッセージタイプ

種類は、8つありました。

  • Message
  • Ping
  • DeleteUserData
  • BotAddedToConversation
  • BotRemovedFromConversation
  • UserAddedToConversation
  • UserRemovedFromConversation
  • EndOfConversation

詳細は以前の記事を参照してください。

 

v3のメッセージタイプについて

v1は、そもそもメッセージタイプが文字列定義だったので最高にしんどかったですが、v3になってようやくenumとして定義されて使いやすくなりました。

 

タイプは、6種類になったようです。

  • Message
  • ConversationUpdate
  • ContactRelationUpdate
  • Typing
  • Ping
  • DeleteUserData

それぞれの役割とかは下記のような感じです。

Message

ユーザとBotの間のシンプルなコミュニケーション時は、これを使います。

普通にメッセージのやり取り時はこれになります。

ConversationUpdate

Botが会話に追加された場合や、会話のメタデータが変更になった場合の通知に使われるメッセージタイプです。

v1の頃のBot・User/Added・Remove/From・To/Conversationメッセージタイプは、すべてこのメッセージタイプに統合されます。

ContactRelationUpdate

Botがユーザのコンタクトリストに追加、削除された際の通知に使われるメッセージタイプです。

Skypeでコンタクトリストに追加された際のThanksメッセージを返すためのトリガーなどが用途かなって感じです。

Typing

Botまたは、ユーザが現在メッセージを入力中というステータスを送る際に使われるメッセージタイプ

Ping

Botのセキュリティテスト用のメッセージに使われるメッセージタイプ

DeleteUserData

ユーザがBotに対してプロフィールやユーザデータの削除を要求する際に使われるメッセージタイプ

まとめ

メッセージタイプも根本的に置き換えられてますが、より普通のチャットで使われるアクティビティの挙動に合わせられての改変なので機能も豊富でかなりいい感じになったっぽいです。

Botのv3対応について

Bot Framework v3への更新に際してかなり大幅な変更があるのでとりあえずベースの部分だけまとめます。

初めに

V3対応前の最終バージョンのEmulatorを開くと以下のように警告が出ます。

image

hereの部分から更新用のリンクに飛べるのでそこで更新しましょう。

v3対応Emulator

hereのところから入れると、古いEmulatorの更新じゃなくて新規アプリケーションとしてインストールされるようです。

バージョン番号は、3.0.0.54のようです。

アプリ名も以前のものは、Microsoft Bot Framework EmulatorだったのがMicrosoft Bot Framework Channel Emulatorに名称が変わっています。

image

挙動もちょこちょこ変わっているので動かしてみます。

 

v1デフォルトでの動作

以前配布されていたテンプレート(v1.0.0)で実行してメッセージを投げると下記のように失敗します。

image

v3対応

結構大幅に変わってて辛いです。

設定ファイル

v1の設定ファイル

  
<add key="AppId" value="YourAppId" /> <add key="AppSecret" value="YourAppSecret" />

 

AppIdとAppSecretを記述する必要がありました。

v3の設定ファイル

    
<add key="BotId" value="YourBotId" />
<add key="MicrosoftAppId" value="" />
<add key="MicrosoftAppPassword" value="" />

 

AppId、AppSecretの代わりに

BotId、MicrosoftAppId、MicrosoftAppPasswordの3つを設定するように変更になります。

この中のMicrosoftAppIdとMicrosoftAppPasswordをEmulatorの上部に入れます。

image

公式のドキュメントだとBot Idの入力欄も用意されているように見えますが、公式の画像が3.0.0.49になっていて、最新版は、3.0.0.54になってBot Idの入力欄が省かれているので必要ないようです。

ちなみにローカルのBotに対してAppIdとAppPasswordを空白以外にしてEmulatorにもその値を入れると認証失敗で通信にコケるので一旦入力しないようにしたほうがよさそうです。

ライブラリ

Bot Builder、Bot Connectorのライブラリも3.0.0に変更されています。

3.0.0にしないとv3用のEmulatorと通信できません。

現在NuGetからBot Connectorを入れようとすると1.1.0が最新として公開されていて3.0.0が手に入らないように見えますが、Bot Builderを入れると自動的にBot Connectorの3.0.0も入るのでBot Builderだけ入れましょう。

 

ソースコードの改変

下記のコードは、v1用のコードです。

v3にするとほぼ完全に名称変更されたりして完全に互換性がないので修正します。

using System;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.Description;
using Microsoft.Bot.Connector;
using Newtonsoft.Json;

namespace v3Sample
{
    [BotAuthentication]
    public class MessagesController : ApiController
    {
        /// 
        /// POST: api/Messages
        /// Receive a message from a user and reply to it
        /// 
        public async Task Post([FromBody]Message message)
        {
            if (message.Type == "Message")
            {
                // calculate something for us to return
                int length = (message.Text ?? string.Empty).Length;

                // return our reply to the user
                return message.CreateReplyMessage($"You sent {length} characters");
            }
            else
            {
                return HandleSystemMessage(message);
            }
        }

        private Message HandleSystemMessage(Message message)
        {
            if (message.Type == "Ping")
            {
                Message reply = message.CreateReplyMessage();
                reply.Type = "Ping";
                return reply;
            }
            else if (message.Type == "DeleteUserData")
            {
                // Implement user deletion here
                // If we handle user deletion, return a real message
            }
            else if (message.Type == "BotAddedToConversation")
            {
            }
            else if (message.Type == "BotRemovedFromConversation")
            {
            }
            else if (message.Type == "UserAddedToConversation")
            {
            }
            else if (message.Type == "UserRemovedFromConversation")
            {
            }
            else if (message.Type == "EndOfConversation")
            {
            }

            return null;
        }
    }
}

 

v3用のベースコードは、下記のような感じになります。

using System;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.Description;
using Microsoft.Bot.Connector;
using Newtonsoft.Json;

namespace v3Sample2
{
    [BotAuthentication]
    public class MessagesController : ApiController
    {
        /// 
        /// POST: api/Messages
        /// Receive a message from a user and reply to it
        /// 
        public async Task Post([FromBody]Activity activity)
        {
            if (activity.Type == ActivityTypes.Message)
            {
                ConnectorClient connector = new ConnectorClient(new Uri(activity.ServiceUrl));
                // calculate something for us to return
                int length = (activity.Text ?? string.Empty).Length;

                // return our reply to the user
                Activity reply = activity.CreateReply($"You sent {activity.Text} which was {length} characters");
                await connector.Conversations.ReplyToActivityAsync(reply);
            }
            else
            {
                HandleSystemMessage(activity);
            }
            var response = Request.CreateResponse(HttpStatusCode.OK);
            return response;
        }

        private Activity HandleSystemMessage(Activity message)
        {
            if (message.Type == ActivityTypes.DeleteUserData)
            {
                // Implement user deletion here
                // If we handle user deletion, return a real message
            }
            else if (message.Type == ActivityTypes.ConversationUpdate)
            {
                // Handle conversation state changes, like members being added and removed
                // Use Activity.MembersAdded and Activity.MembersRemoved and Activity.Action for info
                // Not available in all channels
            }
            else if (message.Type == ActivityTypes.ContactRelationUpdate)
            {
                // Handle add/remove from contact lists
                // Activity.From + Activity.Action represent what happened
            }
            else if (message.Type == ActivityTypes.Typing)
            {
                // Handle knowing tha the user is typing
            }
            else if (message.Type == ActivityTypes.Ping)
            {
            }

            return null;
        }
    }
}

 

以前のコードでは、Botとのやり取りは、大体WebAPIのリクエストとレスポンスの一対一のやり取りをメインに据えている感じでしたが、

このコードを見る限りだと、POSTのレスポンスにメッセージを乗せるのではなく、ConnectorClientクラスでBot Connectorと明示的に接続してReplyToActivityAsyncメソッドでメッセージを送信する形を推奨するのかなって感じです。

また、今までMessageクラスをメッセージの一つの単位として扱ってましたが、これからは、Activityクラスを使うようになるようです。というかMessageクラスは、消滅したっぽいので気を付けましょう。

このコードを使うと、v3用のEmulatroと下記のように通信できます。

image

 

v3用のEmulatorで通信出来たら、一応v3対応ができたのではないかと思われます。

まとめ

とりあえず公式の提供するテンプレートを使ってざっくりv1とv3の変更点とどうすればv3用になるのかをざっくりまとめました。

v1はバージョン番号の扱い的に完全にベータ扱いっぽい雰囲気でしたがここまで変更してくるのは想定外です。

すさまじい量の変更点があるっぽいので誰かまとめてください。

Bot Frameworkがv3になりました

気が付いたらBot Frameworkが大規模更新されてたのでとりあえず概要をまとめます。

概要

だいぶ変わっててかなりしんどいのでとりあえず概要の邦訳的な感じで(間違ってたらすみません)

ちなみにBotのバージョンがV1からV3になります。

新規機能

  • ルーセル、カードの対応
  • Skypeの自動設定
  • ユーザ、グループのアドレスの簡素化
  • ダイアログタイプの追加、Bot Builder SDKの拡張
  • LUIS IntentダイアログのSDKへの追加
  • SDKでのSkype通話のサポート
  • Bot Emulatorの機能強化
  • Slackの最近追加されたボタンのサポート(メッセージボタン)
  • Facebookの多数のBotの新機能のサポート

 

これらの機能を自分のBotで使うためにBotの更新が必要です。

バージョンの変更とかについては、後で諸々まとめます。

基本的には、Botの基本設定画面に下記のようなバージョン指定の項目が追加されているのでそこで設定してください。

image

まとめ

かなり変更点が多いみたいなので早めにまとめていこうと思います。

Cognitive Serviceを使う(Vision API編 その6)

画像分析のAPIには、特定の対象を検索するモードの変更的なことができるのでそれをやってみます。

初めに

例のごとくVision APISDKを入れておいてください

実装する

今回は、ドメインモデルというものを使用して分析モード的な奴を切り替えます。

ドメインモデルを取得する

ドメインモデルは、Cognitive Serviceで提供されているものが使用できます。

コードは、下記のような感じです。

        private static async Task GetDomainModel()
        {
            var visionServiceClient = new VisionServiceClient("APIキー");
            var model = await visionServiceClient.ListModelsAsync();
            return model;
        }

これを出力すると下記のような感じでモデルが取れます。

image

今はcelebritiesしか提供されていないみたいなので一つだけです。

ではこれを使って画像を分析してみます。

分析する

画像を分析する場合は、下記のようなコードです。

まずWebの画像を使用した場合です。

        private static async Task AnalyzeInDomainImageWithWebUri()
        {
            var models = await GetDomainModel();
            foreach(var model in models.Models)
            {
                Console.WriteLine($"\nName : {model.Name}");
                foreach(var category in model.Categories)
                {
                    Console.WriteLine($"category : {category}");
                }
            }
            Console.WriteLine("");

            var visionServiceClient = new VisionServiceClient("APIキー");
            var analyzeModel = models.Models[0] as Model;
            var analysisResult = await visionServiceClient.AnalyzeImageInDomainAsync(new Uri("http://livedoor.blogimg.jp/return_to_forever-flat_display_2/imgs/4/5/45fe6b60.jpg").AbsoluteUri, analyzeModel);

            Console.WriteLine($"result : {analysisResult.Result.ToString()}");

            Console.ReadLine();
        }

画像は下記のサティアナデラのものを使用してみます。

すると結果は下記のような感じです。

image

nameにSatya Nadellaと入っているので分析できたようです。

次にローカルの画像を使います。

実装は下記のような感じです。

        private static async Task AnalyzeInDomainImageWithWebLocalImage()
        {
            var models = await GetDomainModel();
            foreach (var model in models.Models)
            {
                Console.WriteLine($"\nName : {model.Name}");
                foreach (var category in model.Categories)
                {
                    Console.WriteLine($"category : {category}");
                }
            }
            Console.WriteLine("");

            var visionServiceClient = new VisionServiceClient("APIキー");
            var analyzeModel = models.Models[0] as Model;
            using (var imageFileStream = File.OpenRead(@"tom.jpg"))
            {
                var analysisResult = await visionServiceClient.AnalyzeImageInDomainAsync(imageFileStream, analyzeModel);
                Console.WriteLine($"result : {analysisResult.Result.ToString()}");
            }

            Console.ReadLine();
        }

画像はトムクルーズを下記の画像を使用します。

tom

結果は、下記のような感じです。

image

トムクルーズと分析できました。

ちなみになぜかティムクックとスティーブジョブスは分析できませんでした。

まとめ

どういう用途で使うのか若干微妙なAPIですが、雑誌のスキャンをして自動分類するとかそういったことをしようとすると便利かもしれません。

そろそろVision APISDKで叩くのもネタ切れ感が出てきたでいい加減REST APIのまとめか別のAPIをやっていこうかと思います。

Cognitive Serviceを使う(Vision API編 その5)

画像の説明を自動生成できると便利ですよね。ということでVision APIで生成してみます。

初めに

例のごとくVision APIのライブラリをNuGetから入れておいてください。

実装

早速説明を生成してみましょう。

ソースコード

今回も、ローカルのファイルとWebのURIで取得した画像の分析をする2パターンのサンプルです。

まずWebの画像を使うパターン

DescribeAsyncで分析結果を取得します。

このメソッドの第二引数の数が、説明の候補の数です。

5と入れてあると候補が5種類生成されます。

        private static async Task DescrirbeImageFromUri()
        {
            var visionServiceClient = new VisionServiceClient("APIキー");

        var uri = new Uri("http://www.footballchannel.jp/wordpress/assets/2015/04/20150422_juventos_getty.jpg");
        var analysisResult = await visionServiceClient.DescribeAsync(uri.AbsoluteUri, 5);
        Console.WriteLine($"Image Format : {analysisResult.Metadata.Format}");
        Console.WriteLine($"Image Dimensions : {analysisResult.Metadata.Width} x {analysisResult.Metadata.Height}");

        if (analysisResult.Description != null)
        {
            foreach (var caption in analysisResult.Description.Captions)
            {
                Console.WriteLine($"Caption : {caption.Text}; Confidence : {caption.Confidence}");
            }
        }

        Console.ReadLine();
    }

使った画像は下記の画像です。

サッカーチームの画像です。

結果が、下記のような感じになります。

image

Confidenceがそれっぽさ度です。

フットボールチームの写真という説明が一番上高くなっています。

何となくそれっぽい説明が出力されました。

次にローカルの画像です。

        private static async Task DescribeImageFromLocalImage()
        {
            var visionServiceClient = new VisionServiceClient("APIキー");
            using (var imageFileStream = File.OpenRead(@"hoge.jpg"))
            {
                var analysisResult = await visionServiceClient.DescribeAsync(imageFileStream, 5);

                Console.WriteLine($"Image Format : {analysisResult.Metadata.Format}");
                Console.WriteLine($"Image Dimensions : {analysisResult.Metadata.Width} x {analysisResult.Metadata.Height}");

                if (analysisResult.Description != null)
                {
                    foreach (var caption in analysisResult.Description.Captions)
                    {
                        Console.WriteLine($"Caption : {caption.Text}; Confidence : {caption.Confidence}");
                    }
                }
            }
            Console.ReadLine();
        }

使った画像は下記のものです。

hoge

結果は、下記のような感じです。

image

文字の面積が多いからなのか黒のTシャツという説明が一番上に来ています。

次点で白のTシャツといった感じです。

ここら辺は若干微妙な感じなので今後に期待です。

まとめ

画像の説明を簡単に生成できました。

ですが、基本的に英語で返ってくるので表示前にTranslate APIなどで各言語に変換してやるとより丁寧かなという感じです。