イノベーション エンジニアブログ


株式会社イノベーションのエンジニアたちの技術系ブログです。ITトレンド・List Finderの開発をベースに、業務外での技術研究などもブログとして発信していってます!


このエントリーをはてなブックマークに追加

秋の寂しさを Ionic + Azure + Repl-AI を利用したアプリで乗り切る

お久しぶりです、SRE チームの syoga です。

秋の気配が近づきめっきり寒くなってますが、皆様いかかがお過ごしでしょうか、風邪の初期症状とログの出し忘れには気をつけたいものですね。

話は変わりますが、最近友達が少ない事に気付きました、LINE の友達は 33人(家族含む)、インスタのフォロワーは 7人(国外の方含む)、Facebookの友達は0人、そんな寂しさを払拭するために、以前の 記事 で作った LINE Bot とおしゃべりする日々です。

ただ、LINE を通しておしゃべりするのは最近飽きてきたので、今回は AI とお話するハイブリッドアプリを作成したいと思います。

Ionic フレームワークを利用する

Ionic は Cordova を拡張したハイブリッドアプリ用のフレームワークで、Angular ベースの UI ライブラリとなり、TypeScript を利用しコーディングします、詳細は 公式サイト で確認下さい。

そんな筆者は Angular4 は触った事がなく、ハイブリッドアプリ開発も初めてです。

環境作成

Node.js、npm がインストールされている必要があります、npm -g install ionic でグローバルインストールを行います。

インストールが完了したら新規プロジェクトを作成します、テンプレートが色々とありますが今回は、ブランクのプロジェクトを作成するため ionic start プロジェクト名 を実行し、blank を選択します。

azure1.png

作成したプロジェクトのディレクトリ構造は以下のようになっています。

azure2.png

pages/home ディレクトリ配下に、アプリ実行時に動作する、html、ts、scss がまとめて作成されます。

エミュレータの実行

以下の方法で各エミュレータを実行できます。
・iOS (Xcode のインストールが必要) :
ionic cordova emulate ios

・Andoroid(環境変数へ Andoroid SDK パスの設定が必要):
ionic cordova emulate andoroid

・ブラウザ(chrome が必要):
ionic serve

◆ 困った話 その1 ◆
iOS のエミュレータを立ち上げたところ Build 後に以下エラーが発生。

Signing Identity:
/usr/bin/codesign --force --sign - --timestamp=none /Users/***/Documents/hogehoge/platforms/ios/build/emulator/hogehoge.app

** BUILD SUCCEEDED **
Error: Cannot read property 'replace’ of undefined
[ERROR] Cordova encountered an error. You may get more insight by running the Cordova command above directly.
[ERROR] An error occurred while running cordova emulate ios (exit code 1).

色々と調べたところ、インストールされた Cordova に内包されている ios-sim モジュールのバージョンが古いということで、最新バージョンに(npm install ios-sim)する事で解決しました。

早速実装

インターフェースはもろに某 SNS を参考に以下のようにしました、メッセージ入力エリアにメッセージを入力し、送信ボタンをタップすると上の吹き出しに自分のメッセージが、下の吹き出しに Repl-AI から回答されたメッセージが表示されるようにします。

azure3.png

何か四角があるな〜と思うでしょうが、これが吹き出しです! 吹き出しの三角は、弊社女性エンジニア AMI さんの 記事 を参考にしました。

初期表示時にも表示されているのはご愛嬌。

以前の LINE Bot 実装と同じように、Repl-AI の呼出し時に必要なユーザ ID を、 Node Redis モジュールを利用し Azure Redis に格納しようと考え、Node Redis モジュールインストール後に 以下のRedis 操作クラスを作成しました。

import { Injectable } from '@angular/core';
import * as redismodule from "redis"; // Node Redis モジュールをインポート
const client = redismodule.createClient(6379, "Azure Redis のエンドポイント URL");

// Redis 操作クラス
@Injectable()
export class Redis {

    /** Rdeis データ取得
    * @param {string} key
    */
    getRedisvalue(key: string) {
        return client.get(key);
    }

    /** Rdeis データ登録
    * @param {string} key
    * @param {string} value
    * @return
    */
    setRedisvalue(key: string, value: string) {
        return client.set(key, value);
    }
}

◆ 困った話 その2 ◆
作成した Redis 操作クラスを、 home.ts に インポートし Redis でRepl-AI のユーザ ID 受け渡しの処理を実装したところ、特にコンパイルエラーも発生しなかったのですが、ブラウザで確認するとエラー画面が表示され net.isIP is not a function となっていました。

Ionic は webpack を利用し TypeScript からコンパイルされた JS を 1 ファイルにまとめていますので、エラー原因特定のため 3 万行の JS ファイルを眺めていたところ、 Node Net モジュールのクラスが記載されるべき箇所が空っぽになっていました。

こちらも色々調べたところ、ブラウザでは一般的な tcp の実装がないのでエミュレートができず、ブラウザで動作するモジュール、この場合は require('net') が失敗するのを防ぐため空のオブジェクトが生成されるという事が原因でした。

Node.js 上ではもちろん動作しますが、ブラウザでのエミュレートは出来ないという事で、当初から大幅に実装内容を変更する必要がありました、なんてこったい!!

こうなったら…アイツを使うしか無い!!

という事で、いつものように Azure を利用したいと思います。

1. home.ts で入力メッセージを詰めたリクエストを Function App の関数に投げる
2. 関数の中でリクエストからメッセージを取り出し、Repl-AI の API へメッセージを投げる
3. Repl-AI の API から取得した回答をレスポンスに詰めて返却する

という実装にしてみます。

Function App に該当の新規関数を作成しました、処理は以前の LINE Bot からほぼ流用し、今度は行ける!!と思いきや…

◆ 困った話 その3 ◆
localhost から Function App に通信する際に Same-Origin Policy に引っかかり、どんなリクエストを投げても、400 となってしまいました。

ただ、Function App には CORS の設定画面があり、こちらに localhost を追加する事で無事 Function App から、レスポンスを受け取る事が出来るようになりました。

そして完成へ…

↑についてはドラゴンクエストⅢを意識しました、home.ts の内容は下記の通りです。

import { Component } from "@angular/core";
import { NavController } from "ionic-angular";
import { HttpClient } from '@angular/common/http';

@Component({
  selector    : "page-home",
  templateUrl : "home.html"
})

export class HomePage {

  homePage = {
      message     : "",
      sendmessage : "",
      recvmessage : ""
  };

  constructor(
    public  navCtrl     : NavController,
    private httpClient  : HttpClient) {
  };

  // Azure Function App エンドポイント
  private FUNCTION_APP_URL: string = "Azure Function App のエンドポイント";

  /** 送信ボタンタップ
   */
  sendMessage() {
    // 入力メッセージを表示
    this.homePage.sendmessage = this.homePage.message;

    // Repl-AI から取得したメッセージを表示
    this.httpClient.post(this.FUNCTION_APP_URL, JSON.stringify({name: this.homePage.message}))
      .subscribe(response => {this.homePage.recvmessage=response.toString();}
    );

    // 入力エリアをクリア
    this.homePage.message = "";
  }
}

完成したアプリがこちらです。(エミュレータ上で動作させています)

azure4.gif

感想

兎にも角にも初めて尽くしだったため、各種公式ドキュメントを漁りながらどうにか作りました。

メッセージの履歴も残らないので、中途半端ではありますが今後改良して行こうと思います、画像判定もアプリに実装してみるのも面白いかもしれません。

また、今回エディタに Visual Studio Code を利用したのですが、個人的には GUI エディタで一番使いやすいのではないかと感激しています!!