python Bottle Google Speech Recognition 音声認識

## iPhoneとリレーがつながり、次はボタンでなく音声コマンドだ!
![mecabx.png](https://qiita-image-store.s3.amazonaws.com/0/274715/4f8b7962-5862-0030-830d-1ff38a8c9675.png)
[Youtube](https://youtu.be/J1ak_q7tQiU)


# プログラミングの極意は、サクッと試す。

環境は、Windows 10/chrome

+ Network localhost wsgiにsslがないため、きちんとしたServer with Web serverに設置しないと動作しません。
+ さくっというとhttpsでないとchromeは、マイク・カメラ・・・に対して接続しません。localhostは、OK
+ 22行で形態素解析 Mecabも試す
ファイルのレアウト

```
│  speech.py
├─static
│  │  favicon.ico
│  │  favicon.png
│  │
│  ├─css
│  │      .DS_Store
│  │      bootstrap-grid.css
│  │      bootstrap-grid.css.map
│  │      bootstrap-grid.min.css
│  │      bootstrap-grid.min.css.map
│  │      bootstrap-reboot.css
│  │      bootstrap-reboot.css.map
│  │      bootstrap-reboot.min.css
│  │      bootstrap-reboot.min.css.map
│  │      bootstrap.css
│  │      bootstrap.css.map
│  │      bootstrap.min.css
│  │      bootstrap.min.css.map
│  │
│  └─js
│          bootstrap.bundle.js
│          bootstrap.bundle.js.map
│          bootstrap.bundle.min.js
│          bootstrap.bundle.min.js.map
│          bootstrap.js
│          bootstrap.js.map
│          bootstrap.min.js
│          bootstrap.min.js.map
│          jquery-3.3.1.min.js
│          popper.min.js
│
└─views
        index.tpl
        layout.tpl
```
index.tplには、コーヒーの香りがするjavascriptを書いてある。音声入力をするためのAPIの定義です。
+ ちなみにお茶の香りがするjsは、jqueryを使わないjavascriptです。MITには、コーヒーグループとお茶グループあるらしい。
最近では、緑茶グループがあるらしい。
### python UIを構築する方法は、たくさんあるが一番手軽なのは、wsgiを用いる方法だ
### python できるが、Javascriptの方がサクサク動くし、何ったって「Stupid Phone」で動作するのがうれしい。
+ 「Stupid Phone」とは、使えば使うほどにユーザーがあほになる電話。
+  昔は、100箇所以上の電話番号覚えていたのに家族の携帯電話すら今じゃ覚えていない。

```index.tpl
% rebase('layout.tpl', title='Web Speech API')
<script>
    var fText = '';
    var iText = '';
    $(function(){
        if (!'webkitSpeechRecognition' in window) {
	        alert('Web Speech API には未対応です.');
	        return;
        }
        var r = new webkitSpeechRecognition();
        r.lang = 'ja';
        r.interimResults = true;
        r.onresult = function (e) {
            fText = '';
            iText = '';
            for (var i = 0; i < e.results.length; i++) {
                if (e.results[i].isFinal) {
                    fText += e.results[i][0].transcript;
                } else {
                    var msg = e.results[i][0].transcript;
                    iText += msg;
                }
            }
            $("#voice").val(fText);
        }
        r.onerror = function () {
            $("#voice").val('[onerror]');
        }
        r.onend = function () {
            $.ajax({
                type: "POST",
                url: "/reco",
                data: {
                    'text':$("#voice").val()
                },
                success: function(data){
                    console.log(data); 
                }
            });
        }
        $("#start").click(function () {
            $("#voice").val("");
            r.start();
        });
	});
</script>
<div class="container">
    <br />
    <div class="jumbotron">
        <h1>音声認識</h1>
        <p>Googleの音声認識を利用して制御します</p>
    </div>
	<textarea id="voice" cols="100" rows="10">
	</textarea><br /><br />
    <input class="btn btn-default" type="button" id="start" value="開始" />
</div>
```
bottleとやり取りするための[ajax](https://qiita.com/zakiyamaaaaa/items/bdda422db2ccbaea60d9)
### ボトル対フラスコ論議は、ボトルには、ボトルの立場があるで解説予定!



``` ajax.js
        r.onend = function () {
            $.ajax({
                type: "POST",
                url: "/reco",
                data: {
                    'text':$("#voice").val()
                },
                success: function(data){
                    console.log(data); 
                }
            });
        }
```

```layout.tpl
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
	<meta name="apple-mobile-web-app-capable" content="yes">
	<meta name="apple-mobile-web-app-status-bar-style" content="default">
	<meta name="apple-mobile-web-app-title" content="{{title}}">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{{ title }}</title>
    <link href="/static/css/bootstrap.min.css" rel="stylesheet" />
	<link rel="shortcut icon" type="image/x-icon" href="/static/favicon.ico" />
	<link rel="apple-touch-icon" href="/static/favicon.png" />
	<script src="/static/js/jquery-3.3.1.min.js"></script>
    <script src="/static/js/bootstrap.min.js"></script>
    <script src="/static/js/popper.min.js"></script>
</head>
<body>
<div class="container">
{{!base}}
</div>
</body>
</html>
```

``` speech.py
from bottle import *
import json,MeCab, serial,re
def ON():
    with serial.Serial('COM4', 9600,timeout=0) as s : s.write(bytearray(b"\xA0\x01\x01\xA2")) 
def OFF():
    with serial.Serial('COM4', 9600,timeout=0) as s : s.write(bytearray(b"\xA0\x01\x00\xA1")) 
mc=lambda t :re.split("[\t\n]",MeCab.Tagger ("-Ochasen").parse (t)) #めかぶ大量
sw=lambda t,a,b :a in mc(t) and b in mc(t) #めかぶ選別
@route('/')
@view('index.tpl')
def home():
    return dict()
@route('/reco',method='post')
def reco():
    t = request.forms.text
    if sw(t,"電気","つける") :ON()
    if sw(t,"電気","消す") :OFF()
    return "ok 200"
@route('/static/<file_path:path>')
def static(file_path):
    return static_file(file_path, root='./static')
run(host="localhost",port=911)
```
![speech.PNG](https://qiita-image-store.s3.amazonaws.com/0/274715/3c014b1d-a80e-6205-9a4a-da5b09978b10.png)