maxfie1d のブログ

マイクロソフト系技術ネタを中心に書きます。

Todo アプリを作ることを通して、TypeScript に慣れよう

友人に TypeScript(TS) を覚えてもらうために、コンソールアプリ(黒い画面で動くやつ)で Todo アプリを作るという課題を出しました。

そこで、お手本ではないですが自分も TS で作ったので、 ポイントを解説したいと思います。

Todo アプリの仕様

アプリの仕様は大体こんな感じ。

Todo は以下のように、Todoの内容と一意な ID 番号を持っていること。

interface Todo {
    subject: string;
    id: number
}

使えるサブコマンドは addcomplete の2種類。

# Todo の一覧を表示する
# ts-todo

# Todo を追加する
$ ts-todo add [Todo の内容]

# Todo を完了済みにする
$ ts-todo complete [Todo の ID]

ポイント解説

ではポイントを解説していきます。

ソースコードここにあるので、 全体を見るにはこちらを参照。

github.com

ポイント1: 実行時引数を取得する

Node.js の API を使うことで、実行時の引数(今回はaddcomplete)を取得することができます。 TypeScript の場合は忘れずに npm install @types/node をして、型定義ファイルをインストールしておきましょう。

実行時引数はprocess.argvからアクセスすることができます。 型はstring[]で、3番目以降の要素に欲しい情報があります。 なので、

const subcommand = process.argv[2];
const arg = process.argv[3];

としてもいいのですが、ここは TS で使えるこちらの記法を使うとよりスマートでいいと思います。

const [_1, _2, subcommand, arg] = process.argv;

_1, _2は「破棄する」という意味で、無意味な名前で値を受け取っています。 ちなみに下のコードも有効、で同じことができます。

const [, , subcommand, arg] = process.argv;

ポイント2: 配列の要素に対して同じ処理を行う

特に C言語を経験している場合、for(int i = 0; i < size; i++) {} とやってしまいがちですが、 TS ではfor-ofが使えます。

以下のコードは、登録されている Todo をコンソール画面に一覧するという処理です。 for-ofを使って、それぞれのtodotoString()メソッドを呼び出しています。

export async function list(): Promise<boolean> {
    const todos = await restoreTodos();
    for (const todo of todos) {
        console.log(todo.toString());
    }
    return Promise.resolve(true);
}

for-ofを使うことで、letを使わずに済むというのもポイントです。

ポイント3: async, await, Promise

TS では普通に非同期処理が扱えます。 メソッドや関数内で非同期処理を行う(awaitキーワードを使う)場合は、 asyncキーワードを関数やメソッドの宣言の冒頭につけておきます。

export async function add(todo: string): Promise<boolean> 

また、非同期関数や非同期メソッドの返り値の型は Promise<T>になります(Tは返り値の型)。

内輪で LT 大会を開いた時の話

先日内輪で LT 大会を開きました.

LT 大会を主催するにあたって,メモしておくことがある気がするのでまとめておきます.

Welcome スクリーン

開演前にスクリーンに映しておくスライドを用意しておくと,とてもそれっぽくなります.

スライドには参加者にとって必要な情報(Wi-Fi,トイレなど)を載せておくと良しです.

司会のポイント

LT大会の開始時にはオープニングで LT 大会の趣旨やルールを説明します.分かりきっていることでも,確認しておくと間違いがないです.

また,各 LT 終了後にはひとこと感想を言うと次の発表までの繋ぎになりますし,自分にとっても参加者全体にとっても発表内容の振り返りになるので良いです.

LT終了時には,全体を通して感想を述べて締めくくるとまとまりがよいです.

忘れていたこと

  • BGM

カフェ BGM を流しておくとだいぶ雰囲気がよくなります.当日 Amazon Echo をわざわざ持っていったにも関わらず BGM を流すのを忘れてしまいました笑

当日は誰も見ないとはいえ,YouTube などで LT 大会の模様を中継する予定でしたが忘れていました... また,発表者とスライドと音声がしっかり入るように中継しようと思うとそれなりの工夫がいると思うので,次回に向けて要調整です.

PowerPoint には変更差分を見る機能がある

おそらくあまり知られていない機能です.

実は PowerPoint にはプレゼンテーションの変更部分を 見る機能があります.

次の設定にしたがって,どのように機能するのか説明します.

  1. プレゼンの初稿を作る
  2. 上司の添削を受ける
  3. 添削を元に内容を修正する

プレゼンの初稿を作る

適当にプレゼンを作ります.

f:id:maxfieldwalker:20180226222522p:plain

上司の添削を受ける

ファイルのコピーを作成して,上司に送って添削を受けます.

添削を受けて返ってきたファイルはこのようになっていました. 年度の数字が変更になり,グラフが追加されています.

f:id:maxfieldwalker:20180226222702p:plain

添削を元に内容を修正する

ここからがポイントです.

添削を受けて返ってきたファイルと,手元のファイルを比較します.

まず,手元のファイルを開いて「校閲」タブから「比較」を選びます.

f:id:maxfieldwalker:20180226222839p:plain

ダイアログが開くので,添削を受けて返ってきたファイルを開きます. すると,変更された部分が項目として表示されるので,項目にチェックを付けることで 変更分を手元のファイルに反映することができます.

f:id:maxfieldwalker:20180226223245p:plain

すべての変更分について確認が済んだら,「校閲」タブの「校閲の終了」を押して 比較を終了します.

f:id:maxfieldwalker:20180226223635p:plain

PowerPoint で diff が見れるこの機能,知っておくと便利な時があるかもしれません.

C# から LUIS を利用する

昨日の記事の続きです. 今回は,C#(プログラム)から LUIS にアクセスしてみたいと思います.

maxfie1d.hatenablog.com

下準備

  • LUIS で作成したアプリの「App ID」と「App Key」をメモする

これがちょっと分かりにくいです. まず,「PUBLISH」タブを開いて,赤枠で囲われたところに 「App ID」と「App Key」が含まれる URL があります.

f:id:maxfieldwalker:20180223221822p:plain

URL はだいたい以下のような構造になっていると思うので, 「App ID」と「App Key」の部分だけを抜き出してメモしておきます.

https://westus.api.cognitive.microsoft.com/luis/v2.0/apps/<App ID>?subscription-key=<App Key>&verbose=true&timezoneOffset=0&q=」

  • LUIS アプリケーションを公開する

アプリケーションを公開することで,外部から LUIS にアクセスできるようになります. 「PUBLISH」タブを開いて,タイムゾーンを日本のものに設定して 「Publish to production slot」ボタンを押します.

f:id:maxfieldwalker:20180223224931p:plain

  • C# でコンソールアプリケーションを作成する.今回はプラットフォーム固有の機能にアクセスしないので .NET Core で OK です.また, NuGet で Microsoft.Cognitive.LUIS を入れておきます. www.nuget.org

C# から LUIS にアクセスしてみる

「2分30秒のタイマーを開始」という文字列を投げて, 「2分」や「30秒」といった Entity が取得できるか試してみます.

using Microsoft.Cognitive.LUIS;
using System;
using System.Threading.Tasks;

namespace ConsoleApp2
{
    class Program
    {
        static async Task Main(string[] args)
        {
            string appId = "<APP ID>";
            string appKey = "<APP KEY>";

            var client = new LuisClient(appId, appKey, verbose: true);

            var result = await client.Predict("2分30秒のタイマーを開始");
            if (result != null && result.Intents[0].Name == "SetTimer")
            {
                var entities = result.GetAllEntities();
                foreach (var entity in entities)
                {
                    Console.WriteLine($"Name: {entity.Name}, Value: {entity.Value}");
                }
            }
            else
            {
                Console.WriteLine("解析に失敗しました");
            }

            Console.ReadKey();
        }
    }
}

うまく取得できたようです.

f:id:maxfieldwalker:20180223225212p:plain

はじめて LUIS (Language Understanding Intelligent Service) を使ってみる

LUIS (Language Understanding Intelligent Service) はマイクロソフト提供の 自然言語解析サービスです.

自然言語とは,人間が日常で使う「話し言葉」のことです.

LUISを使うことで,自分の作ったアプリケーション (例えば Bot) に簡単に 自然言語解析の力を統合することができます.

やってみよう

さっそくLUISのサイトを開きます(ドメインai...).

https://luis.ai/

サイトが開いたら,ログイン (Login) もしくは登録 (Sign Up) を行います(Microsoft アカウントを持っていればokです).

ログインしたら,アプリの作成を行います. 飛ばし飛ばしですが,スクショを参考にしてください.

f:id:maxfieldwalker:20180222215959p:plain

f:id:maxfieldwalker:20180222220102p:plain

アプリの作成ができたら,続いて Entity と Intent というものを設定を行います. ここで言う Entity とは,自然言語における『キーワード』のことです. 例えば「東京の天気を教えて」では『東京』が Entity になります. 「2分30秒のタイマーを開始」なら『2分』『30秒』がそれぞれ Entity になります.

次に,Intent は「(ユーザーが)やりたいこと」のことです. 「天気を知る」とか「タイマーをセットする」が Intent になります.

今回は,自然言語でタイマーのセットを行うことを目標に作っていきます.

さっそく Entity から登録を行います. 左側のメニューの「Entities」を押して,次に「Create new entity」を押します.

f:id:maxfieldwalker:20180222221605p:plain

まず,タイマーの「時 (Hour)」を Entity として登録します. 同じようにして「分 (Minute)」と「秒 (Second)」も登録してください.

f:id:maxfieldwalker:20180222221823p:plain

次に Intent を登録します. 今回の Intent は「タイマーをセットする」なので,Intent 名は「SetTimer」にしました.

f:id:maxfieldwalker:20180222222637p:plain

「SetTimer」Intent を作成できたら,次は学習フェーズです.ここが一番おもしろい! スクショの赤枠に,ユーザーが話しかけるだろう例文を入力していきます. 例えば「2分30秒のタイマーをセットして」などです. ポイントは,さまざまなパターンを言い回しを替えて入力として与えることです. 今回は「Hour」「Minute」「Second」の3つの Entityがあるので,3つの Entity がすべて 含まれているパターンや,1つの Entity のみが含まれているパターンなど, 本当にありとあらゆるパターンが考えられるので,思いつく限りでいいので できるだけたくさん入力しておきましょう.

f:id:maxfieldwalker:20180222223236p:plain

例文の入力が終わったら,少し下の「Utterance」のところで 例文のどの単語がどの Entity に対応するかを教えてあげます. 単語にカーソルを合わせてクリックすると,先ほど登録した Entity の一覧が 表示されます.

f:id:maxfieldwalker:20180222224242p:plain

すべての例文について,Entity の対応づけを行ったら最後に右上の方にある「Train」ボタンをクリックして AI を訓練させます.

f:id:maxfieldwalker:20180222224509p:plain

訓練が終わったら,「Train」ボタンのすぐ隣にある「Test」ボタンを押して 学習が上手くいっているかテストしてみましょう. 自然言語から思い通りに Entity を取得できましたか?

f:id:maxfieldwalker:20180222224713p:plain

まとめ

LUIS を動かしてみてどうでしたか?びっくりするくらい簡単に自然言語を解析できて 驚いたのではないでしょうか.

次回の投稿では,プログラム側から LUIS にアクセスする方法を書きたいと思います.

maxfie1d.hatenablog.com