Amazon Rekognitionを使ってみる

Amazon Rekognitionを使ってみる

f:id:ueponx:20170903014828p:plain

Amazon Pollyに引き続いて、Amazon RekognitionCLIで使用してみようと思います。詳細は以下のリンクにあります。

製品の詳細 - Amazon Rekognition | AWS

Rekognition では、画像内の物体、シーン、および顔を検出できます。顔を検索および比較し、有名人を認識し、不適切なコンテンツを識別することもできます。

画像認識系のものですね。MicrosoftさんのComputer Vision APIGoogleさんのCloud Vision APIに該当するもののようです。(あってる?)

Computer Vision APIazure.microsoft.com

【Cloud Vision APIcloud.google.com

最近たくさんのAPIが出てきているのであっているのか不安になってきます。 ネットを見ると機能対決に関しても面白いですが、時間とともに学習されていくこともあるので現在の状況はどうなんでしょうか。

qiita.com

AWS CLIの設定に関して

AWS CLIに関しては以前のエントリでインストールしてあると思いますので説明は省略します。

uepon.hatenadiary.com

Amazon Rekognitionを使用するためのIAMの設定する

Polly使用時と同様にAWSマネージメントコンソールから認証情報を設定する必要があります。具体的にはマネージメントコンソールからIAMを設定する必要があります。

IAMの画面からユーザの追加を選択します。今回のユーザー名はRekognition_userとして【プログラムによるアクセス】にチェックを入れ、画面下の【次のステップ:アクセス権限】ボタンをクリックします。

f:id:ueponx:20170903003330j:plain

作成されたRekognition_userの権限を追加する画面です。

f:id:ueponx:20170903003657j:plain

アクセス権限に【既存のポリシーを直接アタッチ】を選択し、フィルターの検索ボックスにRekognitionと入力して検索をします。

f:id:ueponx:20170903003748j:plain

f:id:ueponx:20170903003807j:plain

すると

  • AmazonRekognitionFullAccess
  • AmazonRekognitionReadOnlyAccess

以上の2つが候補に上がります。今回使用するポリシーはAmazonRekognitionFullAccessというポリシーになりますので、にチェックをいれて、【次のステップ:確認】ボタンをクリックします。(注意)実際には、適切な権限を与えるようにしてください。

ボタンをクリックすると、作成内容の確認画面になります。問題なければ【ユーザの作成】ボタンをクリックします。

f:id:ueponx:20170903004242j:plain

成功すると以下のような画面に遷移します。

f:id:ueponx:20170903004344j:plain

ユーザ名、アクセスキーID、シークレットアクセスキーが表示されますが、画面の中ほどにある【.csvのダウンロード】ボタンをクリックすれば、表示された情報が含まれたCSVファイルがダウンロードできるのでそれをダウンロードしておきます。この情報をあとの手順で使用します。

Amazon RekognistionAWS CLIから使用する

AMIの設定が完了したのでCLIから使用してみたいと思います。初回なのでaws configureコマンドで設定を行います。

PS C:\Users\xxx> aws configure
AWS Access Key ID [None]: <ダウンロードしたCSVに記載>
AWS Secret Access Key [None]: <ダウンロードしたCSVに記載>
Default region name [None]: us-west-2
Default output format [None]: json

Pollyの設定が残っている可能性もあるので、自分は一度設定をクリアしています。書き換える場合にはNoneとなっている部分に旧設定が入力されています。

注意点としてはRekognitionが使えるリージョンは以下の通りです。これ以外のリージョンでは使えないので注意してください。ただし、CLIのオプションで設定すればDefault設定が違っていても問題はないと思います。リージョンが異なる状態で使用すると対応していませんという旨のエラーが発生します。

リージョン名 値?
US East (N. Virginia) us-east-1
US West (Oregon) us-west-2
EU (Ireland) eu-west-1

Configureの設定が終わったので早速使用してみたいと思います。

Amazon Rekognitionのドキュメントを読むと

【参照】 docs.aws.amazon.com

AWS CLI を使用して Amazon Rekognition オペレーションを呼び出す場合、呼び出しの一部として画像のバイトを渡すことはサポートされていません。最初に Amazon S3 バケットに画像をアップロードし、次にアップロードした画像を参照するオペレーションを呼び出します。

と書いてあります。CLI経由での仕様ではバイト列の直接送信はできず、S3で画像ファイルにアクセスするしかないようです。 画像はlenaさんを使用しました。

f:id:ueponx:20170903010215j:plain

S3のBucketを作成し(Bucket名:20170831-image-sample)、画像ファイル(画像ファイル名:lena.jpg)を保存しておきたいと思います。 以下のようにBucketを作成して

f:id:ueponx:20170903010912j:plain

CLI経由で画像ファイルを転送してみます。

PS C:\Users\xxx> aws s3 cp C:\Users\xxx\lena.jpg s3://20170831-image-sample/
upload failed: Desktop\lena.jpg to s3://20170831-image-sample/lena.jpg An error occurred (AccessDenied) when calling the PutObject operation: Access Denied

あれ?そうか、IAMの設定にS3の操作権限がありませんでした。

先程設定したIAMにS3FullAccessのポリシーを追加します。アクセス権限に【既存のポリシーを直接アタッチ】を選択し、S3のフィルタをかけるとAmazonS3FullAccessが表示されると思うのでチェックを入れて追加をします。

f:id:ueponx:20170903011116j:plain

【アクセス権限の追加】ボタンをクリックします。

f:id:ueponx:20170903011411j:plain

以下のように権限が追加されてば問題はありません。

f:id:ueponx:20170903011535j:plain

では改めて、コピーをします。

PS C:\Users\xxx> aws s3 cp lena.jpg s3://20170831-image-sample/
upload: Desktop\lena.jpg to s3://20170831-image-sample/lena.jpg

無事にコピーできたようです。マネージメントコンソール上からでも以下のようにアクセスできました。

f:id:ueponx:20170903011723j:plain

(※)基本的にSDK経由でアクセスする場合にはS3上にあるファイルである必要は必ずしもありません。ただし、AWS CLI経由の場合にはS3である必要があるとのことでした。そのため権限にもS3FullAccessが必要になります。

さて、S3に画像ファイルの準備ができたのでRekognitionを使用してみます。 ここで使用しているのはdetect-labelsになります。入力として渡した画像内の物体、概念、シーンを検出してテキスト情報で返します。

PS C:\Users\xxx> aws rekognition detect-labels --image "S3Object={Bucket=20170831-image-sample,Name=lena.jpg}"
{
    "Labels": [
        {
            "Confidence": 99.27481079101562,
            "Name": "Human"
        },
        {
            "Confidence": 99.27967071533203,
            "Name": "People"
        },
        {
            "Confidence": 99.2796859741211,
            "Name": "Person"
        },
        {
            "Confidence": 53.77459716796875,
            "Name": "Female"
        },
        {
            "Confidence": 53.77459716796875,
            "Name": "Girl"
        },
        {
            "Confidence": 53.77459716796875,
            "Name": "Woman"
        },
        {
            "Confidence": 52.33949279785156,
            "Name": "Hat"
        },
        {
            "Confidence": 51.73891830444336,
            "Name": "Cap"
        },
        {
            "Confidence": 51.73891830444336,
            "Name": "Sun Hat"
        },
        {
            "Confidence": 51.37664031982422,
            "Name": "Face"
        },
        {
            "Confidence": 51.37664031982422,
            "Name": "Selfie"
        }
    ],
    "OrientationCorrection": "ROTATE_0"
}

Human、Person、Girl、Woman、Hat、Face、Selfieなど、この画像にあった検出ができているようです。Json形式で返されているのであとはこれを編集するだけですね。

detect-labels以外にもdetect-moderation-labelsという機能もあります。 Moderation(画像の「節度」)を判定する機能です。 具体的には、不適切な画像(例えばヌードや、露骨ないやらしさなど)を判定することができる機能です。

lenaさんのオリジナル画像はアレな画像なので、先程の顔だけの画像(lena.jp)と全身像の画像(lena2.jpg)でdetect-moderation-labelsを判定してみます。

【全身の画像(一応モザイクはかけました。)】 f:id:ueponx:20170903013037j:plain

【顔だけの画像】

PS C:\Users\xxx> aws rekognition detect-moderation-labels --image "S3Object={Bucket=20170831-image-sample,Name=lena.jpg}"
{
    "ModerationLabels": []
}

【全身の画像】

PS C:\Users\xxx> aws rekognition detect-moderation-labels --image "S3Object={Bucket=20170831-image-sample,Name=lena2.jpg}"
{
    "ModerationLabels": [
        {
            "Confidence": 59.9111328125,
            "ParentName": "",
            "Name": "Suggestive"
        },
        {
            "Confidence": 59.9111328125,
            "ParentName": "Suggestive",
            "Name": "Revealing Clothes"
        }
    ]
}

全身の画像ではRevealing Clothesと判別されています。正解です。

おわりに

Amazon RekognitionをAWS CLIから操作してみました。CLIではS3に画像データを置く必要があるので今ひとつですが、SDK経由であればそのようなことはないようです。画像の送信にBASE64エンコードに対応した言語であればすんなり行けるそうです。(ほとんどがOK)

個人的にはその他のサービスに比べてちょっと物足りないかな…こういうものなんでしょうか。

Amazon PollyをPythonから使ってみる

Amazon PollyをPythonから使ってみる

f:id:ueponx:20170831234755p:plain

前回のエントリーではAWS CLIからAmazon Pollyをコールしてみましたが、今度はpythonから呼び出してみたいと思います。

uepon.hatenadiary.com

Pollyに関しては各言語のドキュメントもサンプルもそろっているので行けると思います。.netからも触れるので自分の場合にはそっちからやればよかったなとは少し思いました。

【PollyのSDKのページ】

開発者用リソース - Amazon Polly | AWS

Amazon Polly(Python編)

こう書くとこのエントリー中にほかの言語も入りそうですが、Pythonのみですw。

インストール

github.com

Boto is the Amazon Web Services (AWS) SDK for Python, which allows Python developers to write software that makes use of Amazon services like S3 and EC2. Boto provides an easy to use, object-oriented API as well as low-level direct service access.

BotoAWSのPythonSDKで、Lowレベルと同等のアクセスができるようになってるってことのようです。

一応、インストールの項目通りにやってみると…

PS C:\> python --version
Python 3.6.1 :: Anaconda 4.4.0 (64-bit)
PS C:\> pip -V
pip 9.0.1 from C:\Users\xxx\Anaconda3\lib\site-packages (python 3.6)
PS C:\> pip install boto
Requirement already satisfied: boto in c:\users\xxx\anaconda3\lib\site-packages

メッセージをみると既にAnaconda環境には入っているようなのですが、サンプルソース上でimportされているのってboto3じゃなかったっけ?と思い、 スタートメニューから【Anaconda Prompt】を起動して、以下のようにインストールしてみました。

(C:\Users\xxx\Anaconda3) C:\Users\xxx>pip install boto3
Collecting boto3
  Downloading boto3-1.4.7-py2.py3-none-any.whl (128kB)
    100% |████████████████████████████████| 133kB 2.2MB/s
Collecting s3transfer<0.2.0,>=0.1.10 (from boto3)
  Downloading s3transfer-0.1.10-py2.py3-none-any.whl (54kB)
    100% |████████████████████████████████| 61kB ...
Collecting jmespath<1.0.0,>=0.7.1 (from boto3)
  Downloading jmespath-0.9.3-py2.py3-none-any.whl
Collecting botocore<1.8.0,>=1.7.0 (from boto3)
  Downloading botocore-1.7.0-py2.py3-none-any.whl (3.6MB)
    100% |████████████████████████████████| 3.6MB 225kB/s
Requirement already satisfied: docutils>=0.10 in c:\users\xxx\anaconda3\lib\site-packages (from botocore<1.8.0,>=1.7.0->boto3)
Requirement already satisfied: python-dateutil<3.0.0,>=2.1 in c:\users\xxx\anaconda3\lib\site-packages (from botocore<1.8.0,>=1.7.0->boto3)
Requirement already satisfied: six>=1.5 in c:\users\xxx\anaconda3\lib\site-packages (from python-dateutil<3.0.0,>=2.1->botocore<1.8.0,>=1.7.0->boto3)
Installing collected packages: jmespath, botocore, s3transfer, boto3
Successfully installed boto3-1.4.7 botocore-1.7.0 jmespath-0.9.3 s3transfer-0.1.10

予想通りboto3はインストールされてなかった…サンプルソースでは普通に使用しているのに。

先程のページにはこんな記述が、今後はこっちをみてねってことっぽい。

Boto3, the next version of Boto, is now stable and recommended for general use. It can be used side-by-side with Boto in the same project, so it is easy to start using Boto3 in your existing projects as well as new projects. Going forward, API updates and all new feature work will be focused on Boto3.

github.com

C:\Users\xxx> python
Python 3.6.1 |Anaconda 4.4.0 (64-bit)| (default, May 11 2017, 13:25:24) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from boto3 import Session
>>>

一応、Anaconda環境でないPowerShellのREPLでも動作したので大丈夫です。

使ってみる

ドキュメントはこちら↓

Boto 3 Documentation — Boto 3 Docs 1.4.7 documentation Amazon Polly のドキュメント

BotoAWSサービス制御用のSDKなのでドキュメントもS3EC2などの項目も入っています(というかそっちがメイン)。

上記のリンクからPollyの項目をみつけます。

Polly — Boto 3 Docs 1.4.7 documentation

公式ドキュメントをみると以下のような記載する旨が書かれています。

# Create a client using the credentials and region defined in the [adminuser]
# section of the AWS credentials file (~/.aws/credentials).
session = Session(profile_name="adminuser")
polly = session.client("polly")

ここでいう~/.aws/credentialsaws configure実行時にいれた情報が入ります。credentialsは認証情報、同じディレクトリにある~/.aws/configはregion情報が含まれています。 初期値はdefaultユーザになっているのでドキュメントに従うのであれば

【変更前】

session = Session(profile_name="adminuser")

【変更後】

session = Session(profile_name="default")

になるのですが、defalutの場合には省略できるようで、

polly = boto3.client("polly")

これでもいいのかなと思います。 【参考】 Session — Boto 3 Docs 1.4.7 documentation

もし、リージョン設定が複数跨る場合には(例えば、同時使用するS3とリージョンが異なる場合など)

from boto3 import Session
...
session = Session(region_name="us-west-2")
polly = session.client("polly")

となります。引数で渡しても問題ないようです。大体の基本形はこんな感じになると思います。

from boto3 import Session
...
# 個人的にはリージョンは指定する方が無難かなと思います。
session = Session(region_name="us-west-2")
polly = session.client("polly")
try:
  # TTSの機能をここで呼び出す。CLIの引数はここで指定するイメージ
  response = polly.synthesize_speech(Text="Hello world!", OutputFormat="mp3", VoiceId="Joanna")
except (BotoCoreError, ClientError) as error:
 ...

サンプルコードを眺めながら触ってこんな感じに編集しました。 mainの部分はなくてもいいかなと思います。

【ドキュメントサンプル写経版・改】

"""Getting Started Example for Python 2.7+/3.3+"""
from boto3 import Session
from botocore.exceptions import BotoCoreError, ClientError
from contextlib import closing
import os
import sys
import subprocess
from tempfile import gettempdir
# Create a client using the credentials and region defined in the [adminuser]
# section of the AWS credentials file (~/.aws/credentials).
session = Session(region_name="us-west-2")
polly = session.client("polly")
try:
    # Request speech synthesis
    response = polly.synthesize_speech(Text="Hello world!", OutputFormat="mp3", VoiceId="Joanna")
except (BotoCoreError, ClientError) as error:
    # The service returned an error, exit gracefully
    print(error)
    sys.exit(-1)
# Access the audio stream from the response
if "AudioStream" in response:
    # Note: Closing the stream is important as the service throttles on the
    # number of parallel connections. Here we are using contextlib.closing to
    # ensure the close method of the stream object will be called automatically
    # at the end of the with statement's scope.
    with closing(response["AudioStream"]) as stream:
        # output = os.path.join(gettempdir(), "speech.mp3") # サンプルではtmpフォルダになるけど、わかりにくい場所になるので下記に変更
        output = "speech.mp3"
        try:
            # Open a file for writing the output as a binary stream
            with open(output, "wb") as file:
                file.write(stream.read())
        except IOError as error:
            # Could not write to file, exit gracefully
            print(error)
            sys.exit(-1)
        print("create OK>>" + output)
else:
    # The response didn't contain audio data, exit gracefully
    print("Could not stream audio")
    sys.exit(-1)

ちょっと戸惑ったのはpsynthesize_speech()の戻り値がストリーム(AudioStream)になっているので、それをファイルに書き込む必要があるという点かなと思います。with closing()...の下りはC#とかでいうところのIDisposableインターフェイスを持ったオブジェクトのusing (FileStream fs = new FileStream(…)と同じような表現のようです。

あとサンプルではoutput = os.path.join(gettempdir(), "speech.mp3")のようにテンポラリ領域にファイルを入れるようにしているのですが。Windows10の場合にはかなりわかりにくいところに保存されます。C:\Users\【ユーザ名】\AppData\Local\Tempに格納されます。さすがにわかりにくいので今回はテンポラリは使用せずにカレントに保存するように変えています。

コメントがあるので冗長に感じますが、コメントを除いて簡略化するとこんな感じになります。

【シンプル版サンプル・日本語版】

from boto3 import Session
from botocore.exceptions import BotoCoreError, ClientError
from contextlib import closing
import os
import sys
import subprocess

session = Session(region_name="us-west-2")
polly = session.client("polly")
try:
    response = polly.synthesize_speech(Text="ひとっ走り付き合えよ", OutputFormat="mp3", VoiceId="Mizuki")
except (BotoCoreError, ClientError) as error:
    print(error)
    sys.exit(-1)
if "AudioStream" in response:
    with closing(response["AudioStream"]) as stream:
        output = "speech.mp3"
        try:
            with open(output, "wb") as file:
                file.write(stream.read())
        except IOError as error:
            print(error)
            sys.exit(-1)
        print("synthesize_speech OK ->>" + output)
else:
    print("Could not stream audio")
    sys.exit(-1)

そこそこわかりやすくなったような気がします。あとはmpg321などを外部コマンドで呼び出すか、pygameにmp3を渡せばそのまま音声出力ができるかなと思います。(後述)

【参考】 uepon.hatenadiary.com

おまけ【RaspberryPiでもPython経由でAmazon Polly】

RaspberryPiからも使ってみます。

インストール

$ pip install boto3
Collecting boto3
  Downloading boto3-1.4.7-py2.py3-none-any.whl (128kB)
    100% |????????????????????????????????| 133kB 1.0MB/s
Collecting botocore<1.8.0,>=1.7.0 (from boto3)
  Downloading botocore-1.7.1-py2.py3-none-any.whl (3.6MB)
    100% |????????????????????????????????| 3.6MB 40kB/s
Collecting jmespath<1.0.0,>=0.7.1 (from boto3)
  Using cached jmespath-0.9.3-py2.py3-none-any.whl
Collecting s3transfer<0.2.0,>=0.1.10 (from boto3)
  Using cached s3transfer-0.1.10-py2.py3-none-any.whl
Collecting python-dateutil<3.0.0,>=2.1 (from botocore<1.8.0,>=1.7.0->boto3)
  Using cached python_dateutil-2.6.1-py2.py3-none-any.whl
Collecting docutils>=0.10 (from botocore<1.8.0,>=1.7.0->boto3)
  Using cached docutils-0.14-py2-none-any.whl
Collecting futures<4.0.0,>=2.2.0; python_version == "2.6" or python_version == "2.7" (from s3transfer<0.2.0,>=0.1.10->boto3)
  Using cached futures-3.1.1-py2-none-any.whl
Collecting six>=1.5 (from python-dateutil<3.0.0,>=2.1->botocore<1.8.0,>=1.7.0->boto3)
  Using cached six-1.10.0-py2.py3-none-any.whl
Installing collected packages: six, python-dateutil, docutils, jmespath, botocore, futures, s3transfer, boto3
Successfully installed boto3-1.4.7 botocore-1.7.1 docutils-0.14 futures-3.1.1 jmespath-0.9.3 python-dateutil-2.6.1 s3transfer-0.1.10 six-1.10.0

実行

$ python polly_simple.py
synthesize_speech OK ->>speech.mp3
$ ls speech.mp3
speech.mp3

ただし、このやり方はpython2.7で動作させているのでShebangとマジックコメントをつけないと日本語で死ぬとエラーがでると思います。下記のようなエラーが出た場合対応する必要があります。

$ python polly_simple.py
  File "polly_simple.py", line 11
SyntaxError: Non-ASCII character '\xe3' in file polly_simple.py on line 11, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details

【python2なコード】

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from boto3 import Session
from botocore.exceptions import BotoCoreError, ClientError
from contextlib import closing
import os
import sys

session = Session(region_name="us-west-2")
polly = session.client("polly")
try:
    response = polly.synthesize_speech(Text="ひとっ走り付き合えよ", OutputFormat="mp3", VoiceId="Mizuki")
except (BotoCoreError, ClientError) as error:
    print(error)
    sys.exit(-1)
if "AudioStream" in response:
    with closing(response["AudioStream"]) as stream:
        output = "speech.mp3"
        try:
            with open(output, "wb") as file:
                file.write(stream.read())
        except IOError as error:
            print(error)
            sys.exit(-1)
        print("synthesize_speech OK ->>" + output)
else:
    print("Could not stream audio")
    sys.exit(-1)

python3系での実行

もしPython3系で動作させるならインストールはpipではなくpip3で行います。実行もpythonではなくpython3で実行します。

【インストール】

$ pip3 install boto3
Collecting boto3
  Using cached boto3-1.4.7-py2.py3-none-any.whl
Collecting s3transfer<0.2.0,>=0.1.10 (from boto3)
  Using cached s3transfer-0.1.10-py2.py3-none-any.whl
Collecting jmespath<1.0.0,>=0.7.1 (from boto3)
  Using cached jmespath-0.9.3-py2.py3-none-any.whl
Collecting botocore<1.8.0,>=1.7.0 (from boto3)
  Using cached botocore-1.7.1-py2.py3-none-any.whl
Collecting docutils>=0.10 (from botocore<1.8.0,>=1.7.0->boto3)
  Downloading docutils-0.14-py3-none-any.whl (543kB)
    100% |????????????????????????????????| 552kB 489kB/s
Collecting python-dateutil<3.0.0,>=2.1 (from botocore<1.8.0,>=1.7.0->boto3)
  Using cached python_dateutil-2.6.1-py2.py3-none-any.whl
Collecting six>=1.5 (from python-dateutil<3.0.0,>=2.1->botocore<1.8.0,>=1.7.0->boto3)
  Using cached six-1.10.0-py2.py3-none-any.whl
Installing collected packages: docutils, jmespath, six, python-dateutil, botocore, s3transfer, boto3
Successfully installed boto3-1.4.7 botocore-1.7.1 docutils-0.14 jmespath-0.9.3 python-dateutil-2.6.1 s3transfer-0.1.10 six-1.10.0

$ python3 polly_simple3.py
synthesize_speech OK ->>speech.mp3

【Python3用のソース】…このソースではpygameを使って再生まで行っています。pygameではイベントハンドラpygame.event.get():)を使って再生中の状態をイベントで取得できますが、画面のない場合にはエラーとなってしまします(コンソールでは実行できない)。そのため、pygame.mixer.music.get_busy()を使って再生中であるか否かを判別しています。 イベントが使用できない点は以下に記載があります。

Pygame handles all it’s event messaging through an event queue. The routines in this module help you manage that event queue. The input queue is heavily dependent on the pygame display module. If the display has not been initialized and a video mode not set, the event queue will not really work. pygame.event — Pygame v1.9.2 documentation

【Python3用のソース】

from boto3 import Session
from botocore.exceptions import BotoCoreError, ClientError
from contextlib import closing
import os
import sys
import pygame.mixer

session = Session(region_name="us-west-2")
polly = session.client("polly")
try:
    response = polly.synthesize_speech(Text="ひとっ走り付き合えよ", OutputFormat="mp3", VoiceId="Mizuki")
except (BotoCoreError, ClientError) as error:
    print(error)
    sys.exit(-1)
if "AudioStream" in response:
    with closing(response["AudioStream"]) as stream:
        output = "speech.mp3"
        try:
            with open(output, "wb") as file:
                file.write(stream.read())
        except IOError as error:
            print(error)
            sys.exit(-1)
        print("synthesize_speech OK ->>" + output)
else:
    print("Could not stream audio")
    sys.exit(-1)
pygame.init()
pygame.mixer.init()
pygame.mixer.music.load("speech.mp3")
pygame.mixer.music.play()
while pygame.mixer.music.get_busy() == True:
    continue
pygame.mixer.music.stop()
pygame.mixer.quit()
pygame.quit()

【実行】

from boto3 import Session
from botocore.exceptions import BotoCoreError, ClientError
from contextlib import closing
import os
import sys
import pygame.mixer

session = Session(region_name="us-west-2")
polly = session.client("polly")
try:
    response = polly.synthesize_speech(Text="ひとっ走り付き合えよ", OutputFormat="mp3", VoiceId="Mizuki")
except (BotoCoreError, ClientError) as error:
    print(error)
    sys.exit(-1)
if "AudioStream" in response:
    with closing(response["AudioStream"]) as stream:
        output = "speech.mp3"
        try:
            with open(output, "wb") as file:
                file.write(stream.read())
        except IOError as error:
            print(error)
            sys.exit(-1)
        print("synthesize_speech OK ->>" + output)
else:
    print("Could not stream audio")
    sys.exit(-1)
pygame.init()
pygame.mixer.init()
pygame.mixer.music.load("speech.mp3")
pygame.mixer.music.play()
while pygame.mixer.music.get_busy() == True:
    continue
pygame.mixer.music.stop()
pygame.mixer.quit()
pygame.quit()

うまく音声ファイルの再生までできました。

終わりに

今回はAmazon PollyをPythonから触るPython編というエントリーとしていますが、その多言語からでもドキュメントやサンプルがしっかりしているので問題なく使えると思います。CLIだけでなくいろいろな言語から呼び出せることで、ツイッターからの読み上げなんていうのも簡単にできそうですね。

Windows10にPyCharmをインストールしてみる

Windows10にPyCharmをインストールしてみる

前から興味はあったのですが、なかなかインストールできなかったpythonIDE環境PyCharmをインストールしてみました。PyCharmはあのIntelliJ IDEAやReSharperで有名なJetBrainsさんのIDEですので、かなり期待期待しています。いまのところVScodeVim(ほとんど設定のされていない)でpythonのコードを書いていますが、pythonシンタックスにそんなに詳しいわけでもないので(というかかなり間違える)のでやっぱIDE入れるしかねえと思ってます。

インストール作業

下記のサイトにいってまずはダウンロードになります。

www.jetbrains.com

画面中の【Download Now】のボタンをクリックすると

f:id:ueponx:20170830181746p:plain

【Professional】か【Community】のエディション選択になります。自分はFreeでも十分かなと思っているので【Community】エディションを選びました。Communityエディションの【Download】ボタンをクリックします。

f:id:ueponx:20170827135449j:plain

ダウンロードすると以下のファイルが保存されます。(2017/08/27現在)

f:id:ueponx:20170827135500j:plain

ダウンロード後はWeb画面は以下のようになりますが、ほおっておいても問題ないでしょう。 内容は手順の説明などになっています。

f:id:ueponx:20170827135508j:plain

インストーラを起動します。ここは【Next】ボタンをクリックします。 (ほかのアプリは落としたほうがいいよって内容です)

f:id:ueponx:20170827135517j:plain

次はインストールパスの設定です。基本デフォルトでいいと思います。変更しないなら【Next】ボタンをクリックします。

f:id:ueponx:20170827135532j:plain

続いてインストールオプションの設定になります。デスクトップのランチャー(ショートカットの作成)や拡張子の関連付けの設定になります。

f:id:ueponx:20170827135538j:plain

自分は以下のように設定しましたが、正直、拡張子の関連付けはいらないかもなあ…とは思います。設定が終わったら【Next】ボタンをクリックします。

f:id:ueponx:20170827135542j:plain

続いてスタートメニューの設定になりますが、変更しないなら【Install】ボタンをクリックします。

f:id:ueponx:20170827135551j:plain

あとはプログレスバーが100%になるのを待ちます。意外と長かったなという印象でした。

f:id:ueponx:20170827135557j:plain

処理が完了するとセットアップは完了になりますので【Finish】ボタンをクリックします。Finishと同時にPyCharmを起動したい場合はチェックをしてください。

f:id:ueponx:20170827135605j:plain

先ほどインストール作業でデスクトップにショートカットの作成を行ったので、以下のようなアイコンができていれば大丈夫です。インストーラーの作業はこれで終わるのですが、JetBrainsのアプリケーションでは初回の起動でも設定する必要があります。

f:id:ueponx:20170827135611j:plain

デスクトップのショートカットをクリックしてPyCharmを起動すると

f:id:ueponx:20170827135620j:plain

過去バージョンの設定を引き継ぐか尋ねられます。初回なのでラジオボタンを【Do not import setting】とし、【OK】ボタンをクリックします。

続いてJetBrainsさんのプライバシーポリシーの同意を求められますので【Accept】ボタンをクリックします。

f:id:ueponx:20170827135630j:plain

これでPyCharmのスプラッシュスクリーンが表示されるのでインストール終わった!と思うのですが。

f:id:ueponx:20170827135636j:plain

キーマップ、テーマ、アイコン、フォントの設定を行うダイアログが表示されます。あとからでも変えられるのでここでは【OK】ボタンをクリックします。

f:id:ueponx:20170827135643j:plain

やっと起動できました!万歳!見た目もなんとなくIntelliJ IDEAに似ていますっていうかそのものに近い。

f:id:ueponx:20170827135650j:plain

あとはプロジェクトを作成(【Create New Project】)を選択して、開発を始めることになります。

f:id:ueponx:20170831001408j:plain

【Create New Project】をクリックするとプロジェクトの場所【Location】と【Interpreter】(実行するPythonの場所)の選択のダイアログが表示されます。【Interpreter】の欄の右にある歯車をボタンクリックするとVirtualENVなども設定できるようです。

f:id:ueponx:20170827135657j:plain

これで終わったと思うのですが、実は起動後もファイルの設定などを行っているので即テストコードをつくって実行しようとするとRunできないという罠があります(メニューがそもそもアクティブにならない。)。少し待つとGUIのボタンなどもアクティブになるので心配はありません。

Tipsのダイアログは消して作業を進めます。

プロジェクトペイン上で作成したプロジェクトで上で右クリックし【NEW】→【Python File】を選択します。

f:id:ueponx:20170831002150j:plain

ファイル名入力のダイアログが表示されるので入力します。

f:id:ueponx:20170831003140p:plain

ファイルの編集を行ったら

f:id:ueponx:20170831010811j:plain

メニューバー上の【RUN】→【RUN】を選択します。

f:id:ueponx:20170831010830j:plain

実行ファイルの選択ダイアログが表示されるので、対象となるファイルを選択します。

f:id:ueponx:20170831011204j:plain

すると、ウインドウの下部に実行時のコンソールが開きます。これで実行完了です。

f:id:ueponx:20170831012415j:plain

終わりに

ブレークポイントの指定をしたデバックや変数のモニタもできます。いままでとは大違いで開発が容易になりました!スニペットも使えるし、ハイライトも、ファイルのDiffも取れるので超便利!いろいろ捗るので今後も使っていこうと思います。

Windows10のAWS CLI経由でAmazon Pollyを使用してみる

Windows10のAWS CLIを使ってAmazon Pollyを使用してみる

先日、JAWS-UG名古屋の勉強会に行ってきました。久々のCLIという感じだったのですが、RaspberryPiを触っているので何とかなるだろうと思っていたのですが、Windows10のBash環境からの前提だったためか、Webの画面からのコピー&ペーストがうまくいかず泣きたくなりました。

jawsug-nagoya.doorkeeper.jp

CLIの使い方に関しては勉強にはなりましたが、コマンドラインヘルパーみたいなものがないと正直厳しいなあと感じました。

Windows10のBash環境はさすがにアレなので、それ以外の方法を探してみたらふつうにあるんすね>標準のCLIインストーラ。ってことで復習もかねてWindows10でAWS CLIをインストールして、さらに最近Amazonの方が会社に来られたときにPollyっていうのもあるんですよと言われていたので、CLI経由で試してみることにしました。(基本はRESTでの使用ではなく、SDK経由の利用っぽいですけど。)

f:id:ueponx:20170827155118j:plain

Amazon Pollyとは?

Amazon Pollyは、文章をリアルな音声に変換するサービスで、話すことができるアプリケーションを作成でき、まったく新しいカテゴリの音声対応製品を構築できます。Amazon Polly は、高度なディープラーニング技術を使用したテキスト読み上げサービスで、人間の声のような音声を合成します。

引用元 aws.amazon.com

TTS+ディープラーニングという感じのようです。抑揚の部分なんかがディープラーニングの効果なんでしょうかね。

AWS CLIのインストール

AWS コマンドラインインターフェイスAWS CLI)のインストーラは以下のリンクからダウンロードできます。

aws.amazon.com

リンクを開くと以下のような画面になると思います。

f:id:ueponx:20170827155126j:plain

画面の右のほうにインストーラのダウンロードリンクがありますので、OSのbit数にあわせてインストーラをダウンロードします。自分は64bit版を選択しました。

f:id:ueponx:20170827155141j:plain

Windows10のBash環境やそのほかのOSではPythonpipを使ってインストールできます。どっちが簡単かというと…難しいところですね。(Windows10のBash環境でコピペができなかったのはWindowsのビルドに関係しているような気がします。) ダウンロードが終わったらインストーラを起動します。

インストーラが起動したら【Next】ボタンをクリックします。

f:id:ueponx:20170827155152j:plain

続いてライセンス確認の画面になるので、下にある【I accept the terms in the License Agreement】にチェックを入れて、【Next】ボタンをクリックします。

f:id:ueponx:20170827155158j:plain

次はインストールする場所の設定画面になります。デフォルトのロケーションはC:\Program Files\Amazon\AWSCLI\になりますので、変更する際は【Browse…】を押して変更を行ってください。問題ない場合には【Next】ボタンをクリックします。

f:id:ueponx:20170827155204j:plain

あとはインストールを行うだけです。ここまでで問題なければ【Install】ボタンをクリックします。

f:id:ueponx:20170827155211j:plain

進捗がプログレスバーに表示されます。

f:id:ueponx:20170827155218j:plain

以下の画面がでればインストールは完了です。【Finish】をクリックしてインストーラを終了させます。

f:id:ueponx:20170827155229j:plain

あとは実行の確認です。powershellを起動し、以下のように打ち込みます。

PS C:\> aws --version
aws-cli/1.11.141 Python/2.7.9 Windows/8 botocore/1.6.8

CLIのバージョン情報がでていれば問題ありません。(Windows10なのになぜWindows8ってなるのだろうか?)

f:id:ueponx:20170827155312j:plain

インストーラでセットアップを行うとpowershellだけでなくcmdでもAWS CLIを使用できます。

f:id:ueponx:20170827155238j:plain

(注意)PowerShellのCodePageをchcpコマンドで変更していると実行できないようです。

PS > aws configure
Traceback (most recent call last):
  File "aws", line 27, in <module>
  File "aws", line 23, in main
  File "awscli\clidriver.pyc", line 56, in main
  File "awscli\clidriver.pyc", line 192, in main
  File "awscli\argparser.pyc", line 100, in parse_known_args
LookupError: unknown encoding: cp65001

このようになったら

PS > chcp 932
現在のコード ページ: 932

として変更してください。つまりShift_JIS環境でしか使えないということです。cmdでの実行には関係はありません。

Amazon Pollyを使用するためのIAMの設定する

AWS CLIでは使用する際に認証情報を設定しないといけないのでAWSマネージメントコンソールからIAMを設定し、CLIに設定する必要があります。ここからはその設定になります。ここからはあまり自分も詳しくないのでつらい…

IAMの画面からユーザの追加を選択します。今回のユーザー名はpolly_userとして【プログラムによるアクセス】にチェックを入れ、画面下の【次のステップ:アクセス権限】ボタンをクリックします。

f:id:ueponx:20170827155532j:plain

作成されたpolly_userの権限を追加する画面です。

f:id:ueponx:20170827155540j:plain

アクセス権限に【既存のポリシーを直接アタッチ】を選択し、フィルターの検索ボックスにpollyと入力して検索をします。

f:id:ueponx:20170827155550j:plain

すると検索されたリストに

  • AmazonPollyFullAccess
  • AmazonPollyReadOnlyAccess

がでてくるので、今回はAmazonPollyFullAccessにチェックをいれて、【次のステップ:確認】ボタンをクリックします。

(注意)実際には、適切な権限を与えるようにしてください。

ボタンをクリックすると、作成内容の確認画面になります。問題なければ【ユーザの作成】ボタンをクリックします。

f:id:ueponx:20170827155558j:plain

成功すると以下のような画面に遷移します。

f:id:ueponx:20170827155655j:plain

ユーザ名、アクセスキーID、シークレットアクセスキーが表示されますが、画面の中ほどにある【.csvのダウンロード】ボタンをクリックすれば、表示された情報が含まれたCSVファイルがダウンロードできるのでそれをダウンロードしておきます。この情報をあとの手順で使用します。

Amazon PollyをAWS CLIから使用する

CLIに先ほど作成したユーザ名のIAM情報を登録します。 powershell上から以下のコマンドを実行します。

PS C:\> aws configure 
AWS Access Key ID : <ダウンロードしたCSVに記載>
AWS Secret Access Key :<ダウンロードしたCSVに記載>
Default region name :ap-northeast-1
Default output format :json

これで設定できました。 早速、pollyコマンドを実行してみたいと思います。 以下の情報を参考にしています。

docs.aws.amazon.com

すると…

PS C:\> aws polly synthesize-speech --output-format mp3 --voice-id Joanna --text 'Hello,
earned about the W3C on 10/3 of last year.' hello.mp3

Could not connect to the endpoint URL: "https://polly.ap-northeast-1.amazonaws.com/v1/speech"

APIのエンドポイントに接続できないといわれました。 先ほどの設定ではデフォルトのリージョンをap-northeast-1にしていました。このリージョンはpollyに対応していないので対応しているリージョンに変更する必要があります。環境変数で指定してもいいのですが、今回はデフォルト値を変更することにしました。

再度、awsコマンドで設定を行います。デフォルトのリージョンをus-west-2に変更しています。あとは入力せずEnterで前回の設定値が引き継がれます。

これを行わなくても良いようです。Optionスイッチに以下を追加すれば都度リージョンを変更できます。 --region us-west-2

PS C:\> aws polly synthesize-speech --region us-west-2 --output-format mp3 --voice-id Joanna --text 'Hello,
earned about the W3C on 10/3 of last year.' hello.mp3
PS C:\> aws configure 
AWS Access Key ID [********************]: <そのままEnter>
AWS Secret Access Key [********************]:<そのままEnter>
Default region name [ap-northeast-1]:us-west-2
Default output format [json]:<そのままEnter>

設定後、もう一度pollyにアクセスすると…

PS C:\> aws polly synthesize-speech --output-format mp3 --voice-id Joanna --text 'Hello, my name is Joanna. I l
earned about the W3C on 10/3 of last year.' hello.mp3
{
    "ContentType": "audio/mpeg",
    "RequestCharacters": "71"
}
PS C:\Users\CTV> ls hello.mp3

    ディレクトリ: C:\Users\


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----       2017/08/27     15:12          33743 hello.mp3

無事にPollyによってTTSを行ったmp3ファイル(hello.mp3)がダウンロードされています。

f:id:ueponx:20170827155720j:plain

日本語の場合にはオプションを変更すれば問題ありません。(環境変数を指定してもOKです)

PS C:\Users\> aws polly synthesize-speech --output-format mp3 --voice-id Mizuki --text '坊やだからさ。' polly.mp3
{
    "ContentType": "audio/mpeg",
    "RequestCharacters": "7"
}

f:id:ueponx:20170827155727j:plain

実験してみたのですが、英語と日本語の混じった文章ではどうなるのかなと思ったのですが、英語の部分は英語にしてくれているのでAIっぽさのあるTTSになっているのだなと思いました。他のだと混じっているとうまくいかないことが多いのでかなり助かります。

たとえば以下のようにすると```you````の部分はユーと話してくれます。ルー語もOKのようです。

PS C:\Users\> aws polly synthesize-speech --output-format mp3 --voice-id Mizuki --text 'youは坊やだからさ。' polly.mp3

{
    "ContentType": "audio/mpeg",
    "RequestCharacters": "11"
}

番外編

RaspberryPiにもAWS CLIをインストールしてみました。ドキュメント通りpip install awscliでインストールしています。

$ pip install awscli
Collecting awscli
  Downloading awscli-1.11.141-py2.py3-none-any.whl (1.2MB)
    100% |????????????????????????????????| 1.2MB 225kB/s
Collecting PyYAML<=3.12,>=3.10 (from awscli)
  Downloading PyYAML-3.12.tar.gz (253kB)
    100% |????????????????????????????????| 256kB 807kB/s
Collecting rsa<=3.5.0,>=3.1.2 (from awscli)
  Downloading rsa-3.4.2-py2.py3-none-any.whl (46kB)
    100% |????????????????????????????????| 51kB 1.7MB/s
Collecting botocore==1.6.8 (from awscli)
  Downloading botocore-1.6.8-py2.py3-none-any.whl (3.6MB)
    100% |????????????????????????????????| 3.6MB 71kB/s
Collecting docutils>=0.10 (from awscli)
  Downloading docutils-0.14-py2-none-any.whl (543kB)
    100% |????????????????????????????????| 552kB 419kB/s
Collecting s3transfer<0.2.0,>=0.1.9 (from awscli)
  Downloading s3transfer-0.1.10-py2.py3-none-any.whl (54kB)
    100% |????????????????????????????????| 61kB 1.8MB/s
Collecting colorama<=0.3.7,>=0.2.5 (from awscli)
  Downloading colorama-0.3.7-py2.py3-none-any.whl
Collecting pyasn1>=0.1.3 (from rsa<=3.5.0,>=3.1.2->awscli)
  Downloading pyasn1-0.3.3-py2.py3-none-any.whl (63kB)
    100% |????????????????????????????????| 71kB 1.9MB/s
Collecting python-dateutil<3.0.0,>=2.1 (from botocore==1.6.8->awscli)
  Downloading python_dateutil-2.6.1-py2.py3-none-any.whl (194kB)
    100% |????????????????????????????????| 194kB 968kB/s
Collecting jmespath<1.0.0,>=0.7.1 (from botocore==1.6.8->awscli)
  Downloading jmespath-0.9.3-py2.py3-none-any.whl
Collecting futures<4.0.0,>=2.2.0; python_version == "2.6" or python_version == "2.7" (from s3transfer<0.2.0,>=0.1.9->awscli)
  Downloading futures-3.1.1-py2-none-any.whl
Collecting six>=1.5 (from python-dateutil<3.0.0,>=2.1->botocore==1.6.8->awscli)
  Downloading six-1.10.0-py2.py3-none-any.whl
Building wheels for collected packages: PyYAML
  Running setup.py bdist_wheel for PyYAML ... done
  Stored in directory: /home/pi/.cache/pip/wheels/2c/f7/79/13f3a12cd723892437c0cfbde1230ab4d82947ff7b3839a4fc
Successfully built PyYAML
Installing collected packages: PyYAML, pyasn1, rsa, six, python-dateutil, docutils, jmespath, botocore, futures, s3transfer, colorama, awscli
Successfully installed PyYAML-3.12 awscli-1.11.141 botocore-1.6.8 colorama-0.3.7 docutils-0.14 futures-3.1.1 jmespath-0.9.3 pyasn1-0.3.3 python-dateutil-2.6.1 rsa-3.4.2 s3transfer-0.1.10 six-1.10.0

awsコマンドを実行してもうまく行かなったのですが、インストールパスが違っていたようです。

$ ~/.local/bin/aws --version
aws-cli/1.11.141 Python/2.7.13 Linux/4.9.41-v7+ botocore/1.6.8
$ ~/.local/bin/aws configure
AWS Access Key ID : <ダウンロードしたCSVに記載>
AWS Secret Access Key :<ダウンロードしたCSVに記載>
Default region name :us-west-2
Default output format :json

設定はこれでOKです。

では、Pollyを呼び出して見ます。

$ ~/.local/bin/aws polly synthesize-speech --output-format mp3 --voice-id Mizuki --text 'youは坊やだからさ。' polly.mp3 ; mpg321 polly.mp3
{
    "ContentType": "audio/mpeg",
    "RequestCharacters": "11"
}
High Performance MPEG 1.0/2.0/2.5 Audio Player for Layer 1, 2, and 3.
Version 0.3.2-1 (2012/03/25). Written and copyrights by Joe Drew,
now maintained by Nanakos Chrysostomos and others.
Uses code from various people. See 'README' for more!
THIS SOFTWARE COMES WITH ABSOLUTELY NO WARRANTY! USE AT YOUR OWN RISK!

Playing MPEG stream from polly.mp3 ...
MPEG 2.0 layer III, 48 kbit/s, 22050 Hz mono

[0:01] Decoding of polly.mp3 finished.

無事にTTSが行われました。

おわりに

AWS CLIAmazon Pollyを使ってみました。アルファベット混じり文章も使えるし、抑揚もいい感じなので使えそうですね!というか英語はもう実用レベルでしょう。

DragonBoard410cでもつかえるのかな?pythonだし使えると思いますが、あとで実験してみます。

Windows10にPython3を入れたくなったのでAnacondaでインストールしてみる

Windows10にPython3を入れたくなったのでAnacondaでインストールしてみる

最近、pythonを使うことが多くなってきたのですが、いろいろうまくいかないこともあってインストールに迷うことが多くありました。

それまでは以下からインストーラをダウンロードしていました。

www.python.org

f:id:ueponx:20170827105301j:plain

こちらをインストールしていても問題なく使えてはいたのですが。たまにパッケージ関係や環境によって引っかかることも、ワークショップでこれにひかっかるとそのあとは全くなにもできなくなってしまいます。

MACなどでは引っかからないみたいですし、個人的にもUbuntuやRaspberryPiでは引っかかったことはないのでWindowsに特有な話なのかもしてません。

以前、コミュニティなどの集まりに行ったときによく聞いたのは

Anacondaをインストールして環境構築をしたほうが容易ですよ!

ということでした。

今後のことも考えてWindows10にAnacondaをインストールしてみます。

インストール

以下のサイトからAnacondaをダウンロードします。

Download Anaconda Now! | Continuum

OSのbitに合わせてファイルを選択してください。

f:id:ueponx:20170827104800j:plain

自分は64bitOSにインストールするので64bit版を選択しました。

Anaconda3-4.4.0-Windows-x86_64.exe(2017.08.27時点)

f:id:ueponx:20170827104809j:plain

ダウンロードが完了したら、インストーラを起動します。

AnacondaのStepupダイアログが開いたら【Next】ボタンをクリックします。

f:id:ueponx:20170827104815j:plain

次に適応するユーザの設定の選択になります。 JustMe(自分のみ)かAll User(全ユーザ)から選択することになります。今回はJustMeを選択しました。 ラジオボタンを選択したら【Next】ボタンをクリックします。

f:id:ueponx:20170827104823j:plain

次はインストールパスの設定になります。特にこだわりがなければデフォルトでいいと思います。(最近はこだわる理由がなくなってきたので、デフォルトパスにすることにしました。)画面中は【Destination Folder】の欄が空欄になっているのですが、実際はデフォルトのインストールパスが格納されています。

設定ができたら【Next】ボタンをクリックします。 クリックすると【Advance Option】の選択画面となります。

f:id:ueponx:20170827104833j:plain

内容としては * Anacondaのインストール先を環境変数のPATHに登録するか * デフォルトのpythonをAnacondaでインストールとされたものとするか

になります。

f:id:ueponx:20170827104845j:plain

自分はコマンドラインから使う可能性もあったので一応パス登録しました。 Startメニュー経由で起動するだけならPATHの登録はいらないかもしれません。

f:id:ueponx:20170827104851j:plain

チェックが終わったら【Install】ボタンをクリックします。

f:id:ueponx:20170827105006j:plain

プログレスバーが進んでいって

f:id:ueponx:20170827105016j:plain

インストールが完了します。

f:id:ueponx:20170827105026j:plain

これで終了です。Setuo終了後にAnaconda CloudとAnaconda Supportに関する情報を出すかのチェックボックスがでますが、一読してもいいかなと思います。【Finish】をクリックします。

インストールが完了するとスタートメニューからAnacondaを選択することができます。

f:id:ueponx:20170827110629j:plain

スタートメニューからPythonCLIを使用する場合にはAnaconda Promptを選択します。この場合はcmd環境になるので、保管なども効かないので若干使いにくいかもしれません。

また、AnacondaをインストールするとJupyter NoteBookなども同時にインストールできるので便利ですね。

スタートメニューでクリックするとコンソールが開いてローカルサーバープロセスが起動し、ブラウザで使用できるようになります。

f:id:ueponx:20170827125525j:plain

f:id:ueponx:20170827125537j:plain

かなりいい感じです。

おわりに

インストールも問題なく終わりました。 Jupyter Notebookもありますし、pipなどでモジュールのインストールも容易にできるので満足です。

Bash on Ubuntu on Windowsなどにインストールしてもいいのかなと思ったりもしたのですが、まあ、当面はこれでやっていこうと思います。

/* -----codeの行番号----- */