Nuxt.js と Python でつくるぬるさく AI アプリ開発入門

技術書典6で購入した本2冊目。
これも素晴らしい。

なんとか連休中に平成最初のリリースまで持って行きたかったのですが、色々つまり出してきたので、実際に何かを作ってリリースするところを目指したいと思い、Docker環境構築までで一旦まとめておきたいと思います。

Jupyter Notebook

いきなり、あなたの知らない世界で、Jupyter Notebook のインストールから。
こちらなども参考に。
https://techacademy.jp/magazine/17430

まずはAnaconda をインストール。Anaconddaで2.3GBも使うんですね・・・

インストールしたら、
Enviroments > 「analytics」
Notebookをインストールしようとして間違えてJupyterLabをインストールしてしまいました。そうしたらNotebookも勝手に入りました。

3.3.1 データセットを読み込む

第1章、第2章も読み応えありますが、作り始めるのは第3章からになります。

初めてJupyter Notebook を使う身としては、色々不明点を抱えながら進めます。どうやって実行するんだ、というところから始まりますが、Runボタンで実行です。

実行すると、エラー。

ModuleNotFoundError                       Traceback (most recent call last)
<ipython-input-2-aed2979e33dd> in <module>
      1 # 分析に必要なライブラリをインポート
----> 2 import pandas as pd
      3 import numpy as np
      4 
      5 # データセットを読み込む

ModuleNotFoundError: No module named 'pandas'

先に
5.5.1 機械学習に必要なライブラリをインストールする
を実行します。
pipenv install scikit-learn pandas numpy

そうすると、さらにその前に、
5.3.1 pipenv のインストール
pip install pipenv
が必要となります。

3.6.2 データ分割

いきなり実行すると

NameError                                 Traceback (most recent call last)
<ipython-input-17-6ab9212361b9> in <module>
      1 # 目的変数
----> 2 Y = df2["delicious"]
      3 # 説明変数
      4 X = df2.drop(["quality", "delicious"], axis=1)
      5 

NameError: name 'df2' is not defined

となってしまいます。直前の実行結果は引き継がれるようですので、先に、df2 = df としておくと大丈夫のようです。

3.6.3 機械学習

こちらも

ModuleNotFoundError                       Traceback (most recent call last)
<ipython-input-18-ad2ebbb1e040> in <module>
      9 from sklearn.linear_model import LogisticRegression
     10 # 交差検証
---> 11 from sklearn.cross_validation import train_test_split
     12 # インスタンス作成
     13 log_model = LogisticRegression()

ModuleNotFoundError: No module named 'sklearn.cross_validation'

https://www.haya-programming.com/entry/2018/12/04/052713
を参考にして、
sklearn.cross_validation

sklearn.model_selection
に変更します。

4.3.2 プロジェクト作成

-bash: npx: command not found

こんなのが一々エラーになってしまうので、最初に環境を殿と得るべきだし、最後にDocker環境でどの環境を使うかでまた問題になるので、最初から環境はDockerでバージョンを固定して作るのが良いのでしょうね。
とりあえず、続けました。インストールは下記を参照します。
https://www.suzu6.net/posts/45/

さて、書籍ではNullSuckディレクトリに、Project name はNullSuckで作ることになっています。
4.1.1 全体のプロジェクト構成 に記載の「NullSuck-AI」と一致していないので、最初は、 NullSuck-AIディレクトリにNullSuckプロジェクトを作ってみました。
すると、まず、Warning: name can no longer contain capital letters が出ている。
さらに、下記エラーが出ています。

Installing packages with yarnTrace: Error: spawn yarn ENOENT
     at Process.ChildProcess._handle.onexit (internal/child_process.js:248:19)
     at onErrorNT (internal/child_process.js:431:16)
     at processTicksAndRejections (internal/process/task_queues.js:84:17) {
   errno: 'ENOENT',
   code: 'ENOENT',
   syscall: 'spawn yarn',
   path: 'yarn',
   spawnargs: [ 'install' ]
 }

この時点で作成された構成も4.1.1 全体のプロジェクト構成のものとは全く異なります。
正解は、4.3.5 プロジェクト構成。
なので、正解は、NullSuck-AI/client に、プロジェクトnullsuckを作るという感じになります。

さらに、最後に選択する、Choose a package manager をyarnではなくnpmにしてはどうか。
(yarnインストールしていないし)
これでとりあえずはできました。

4.3.3 プロジェクトの TypeScript 対応を行う

これについては、具体的な記述は書いてくれていないので、githubのソースを参考に書き換えようと思ったが、若干内容が異なっているのでそのままにしておく。まずは起動してみよう。

起動も、yarn run dev ではなくnpm run dev。
ここで、yarnを入れておくべきだったと気づく(結局、後で入れることになりますが)が、とりあえず起動させよう。OK!

と思ったが、Insert · prettier/prettier のようなエラー多数。
これの解消は、

node_modules/.bin/eslint --fix --ext .js,.vue --ignore-path .gitignore .

4.5.1 診断項目カードを作ろう

とりあえず進んでいきます。
FormCard.vue の置き場は、componentsの下ではなく、components/Form。(後で変更しますが)

4.5.2 診断カードをたくさん出せるようにしよう

error  Parsing error: Using the export keyword between a decorator and a class is not allowed. Please use `export @dec class` instead.

ここに至って、4.3.3 プロジェクトの TypeScript 対応を行うに戻って、TypeScript 対応を行うことにします。

ただし、現在の環境は、2.6.3(書籍は、2.4.0 )。
そもそも、nuxt 本体で TypeScript をサポートしてくれるので nuxt-ts はもう不要になったようです。
https://qiita.com/shts/items/e7da59cc568a98d55fb5

このタイミングで、ついでにyarnもインストールします。

ERROR  Cannot import module 'ts-node'

これに対応するためには、

yarn add ts-node -D
<form-card v-for="i in 11" :key="‘${i}‘"/>

はダメと言われるので、いったん

<form-card v-for="i in 11" :key="i" />

にするとOKとか。

しかし、その後もあれこれ、エラーと戦いますが、なかなか動いてくれない。

ここで、一旦リセット。
まずは、これに従います。
TypeScript Support – Nuxt.js
https://nuxtjs.org/guide/typescript/

ここで、–fix は、yarn lint –fix で良いのだと知ったり。

それでもまだ。

Cannot find module 'nuxt-class-component'.

に対しては、

yarn add nuxt-class-component

とか。
もう一息というところに立ちはだかるのは、

Cannot set property 'components' of undefined

というエラーでした。最初は、このメッセージで検索したりしていたのですが、冷静になって考えると、問題は、componentsにあるのではなく、それが属するものが、取得できていないということで、undefinedになってしまっているわけです。要は、JSにおける、ヌルポです。
FormCardがオブジェクトとして認識できていないということであり、すなわちちゃんとインポートされていないということなので、そこを見直すべきという結論にやっとたどり着きました。ここは結構長かった。

結論としては、4.5.1 診断項目カードを作ろうの、FormCard.vueの記述は、下記のようにします。

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
  @Component
export default class FormCard extends Vue {}
</script>

すなわち、@Component を付けます。ここでやっと画面が開きました。

4.6 ヌルサクグラフを実装しよう

今度は、グラフ表示用のコンポーネントを作って、読み込もうということですが・・・

30:28 Property 'wineAttributes' has no initializer and is not definitely assigned in the constructor.
    29 |   @Mutation('SET_TITLE') setTitle
  > 30 |   @Getter('GET_WINE_ATTR') wineAttributes: WineAttribute[]
       |                            ^
    31 |   @Getter('IS_ALL_VALUE_SETTED') isAllValueSetted

コンストラクタで初期化しましょう、の意味。・・・どこで??

一旦強引に

  GET_WINE_ATTR: (state: State): WineAttribute[] => {
    let wAttr: WineAttribute[] = []
    if (state.wineAttributes.length > 0) {
      wAttr = state.wineAttributes
    }
    return wAttr
  },

みたいなことをやってみると、そこは進んで、is not in camel case エラーになったので、言われるがままにcamel caseに直します。しかし、そうすると、また、no initializer エラー。結局対処がわからず、tsconfig.json に

"strictPropertyInitialization": false

を追記しました。

これでサーバは起動するようになりましたが、ページを開こうとすると、

FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory

ギブアップ。先に進むことにします。

5.3.2 pipenv でプロジェクトを作ろう

書籍では、

mkdir responder_test && cd responder_test

と書いていますが、そのフォルダにPipfileが作成されるようなので、serverフォルダでpipenv installを実行すれば良いものと考えられます。

5.4.2 ハンドラを実装しよう

これは、handlers.py についての記述です。

5.5.1 機械学習に必要なライブラリをインストールする

3.3.1で実行してあったわけですが、念の為もう一度実行しておく
インストールは動きますが、すぐに完了します。

5.5.2 モデルを読み込む Service を作成する

書籍ではservice.py、githubではservices.py。
正解は、5.2 プロジェクトの構成 でもservices.pyになっているので、それに従います。

6.2.1 Dockerfile の作成

基本的には、githubのDockerfileをもらってきて、バージョンはローカルの環境に合わせる。

これ以降について

バージョン関係については、現場でこうなったら収集つかないなということで、今後はやはりコンテナを活用して、開発からリリースまでをキレにつなげていくことが求められるということでしょうね。オープンソースを活用した開発というものはそういうものだ。けど、それとは違う世界もまだまだあるというのも実感。

で、このまま頑張っても簡単なサンプルが動くようになって、今度はGoogleから請求が来たりするのだろうと思われるので、一旦終了。

そして自分のデータで動かすものを作りたいですが、どうしようかな・・・連休中に何か動かしたいですがね。