Hylang で適当にHTTPサーバを立てる(3) （2018年7月現在）

# 前回
[Hylang で適当にHTTPサーバを立てる(1) （2018年7月現在）](https://qiita.com/elect/items/76b56a97c444298d52ee)
[Hylang で適当にHTTPサーバを立てる(2) （2018年7月現在）](https://qiita.com/elect/items/abde4ab668b17c39393d)
# JSON を返そう
ちょこっと変えるだけで十分だった。
content-type を変えること、dictなデータにjson.dumps 関数をかけることに注意すれば難しいことはない。

``` hylang
(import [http.server [HTTPServer SimpleHTTPRequestHandler BaseHTTPRequestHandler]]
        [urllib.parse [urlparse]]
        json)

(defclass EchoHandler [BaseHTTPRequestHandler]
  (defn do_GET [self]
    (setv content-len (int (.get self.headers "content-length")))
    (setv request-body (-> (.read self.rfile content-len)
                          (.decode "UTF-8")))
    (print request-body)
    (setv json-data (.loads json request-body))
    (print json-data)
    (print (. json-data ["type"]))
    (print (. json-data ["params"]))
    (.send_response self 200)
    (.send_header self "Content-type" "application/json")
    (.end_headers self)
    (setv response-body {"status" 200
                         "message" "JSONデータ"})
    (.wfile.write self (.encode (.dumps json response-body) "utf-8"))))

(setv httpd (HTTPServer (, "localhost" 8887) EchoHandler))

(.serve_forever httpd)
```

## 結果
日本語とシェル的な問題でうまく表示できなかったが、正しいデータが返ってきているとおもわれる。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/147520/b99bc274-9ba8-d95e-ec7d-498189f31192.png)

# 機械学習的な息吹を感じよう
なんか良いテーマないかなーって見つけたのは、文章の極性判定。    
極性判定とは、要するにその話がどんな雰囲気なの？っていうことを考えさせることで、Pythonでは nltk というパッケージがこれをものすごく簡単にやってくれる。    
勿論TensorFlowやChainerで実装する方が勉強になるけど、タイトル的にあんまり重いことはしない方が良い、ということでちゃちゃっと書いてしまう。

以下のようなフォルダ構造を作る。

```
.-
 |- senti_analysis.hy
 |- test.hy <前回を引き継ぐ>
```

これから、この senti_analysis.hy を書いていく。

## 3分でできる文章の極性判定
### まず、 twython をインストールする。

```
pip install twython
```

（普通に nltk が入ったときに入ると思いきや入っておらずエラーが出てしまったため。）

### コードを書く

*senti_analysis.hy*

``` hylang 
;; require 'pip install twython'
(import [nltk.sentiment.vader [SentimentIntensityAnalyzer]]
        nltk)

;; (.download nltk "vader_lexicon")
(setv vader-analyzer (SentimentIntensityAnalyzer))

(defn get-senti [text]
  (.polarity_scores vader_analyzer text))
```

途中で書かれている `(.donwload ...` は必要なファイルのダウンロードで、初回の一回だけ行えば良い。

具体的な内容を説明すると、
SentimentIntensityAnalyzerというクラスのインスタンス vader-analyzer を作ってこのメンバ関数である polarity_scores 関数に任意のテキストを与えている。

実際に適用して見ると、以下のようなデータが返ってくる。

``` hylang
(get-senti "I'm happy")

;; => {"neg": 0.0, "neu": 0.213, "pos": 0.787, "compound": 0.5719}
```

8割 positive であることがわかる。9割くらいは欲しかったが、これは別の機会に(**求：おすすめの手法**)

さて、残るはこれをサーバにくっつけるだけだ。
## test.hy をアップデートしよう
前の項で作った get-senti 関数が欲しているデータは英文テキストである。

想定される利用方法は、クライアントから送られてくる英文テキストに対して get-senti 関数を適用しその結果を返すというものだろう。

よってそのようにハンドラを更新する。


*test.hy*

``` hylang
(defclass EchoHandler [BaseHTTPRequestHandler]
  (defn do_GET [self]
    (setv content-len (int (.get self.headers "content-length")))
    (setv request-body (-> (.read self.rfile content-len)
                          (.decode "UTF-8")))
    (print request-body)
    (setv json-data (.loads json request-body))
    (print json-data)
    (print (. json-data ["type"]))
    (print (. json-data ["params"]))
    (.send_response self 200)
    (.send_header self "Content-type" "application/json")
    (.end_headers self)
    (setv response-body {"status" 400
                         "params" "不適切なパラメータです"})
    (when (= "senti-analysis" (. json-data ["type"]))
      (setv response-body
            {"status" 200
             "params" (senti_analysis.get-senti (. json-data ["params"]))}))
    (.wfile.write self (.encode (.dumps json response-body) "utf-8"))))
```

内容は、入力されるJSONの type が senti-analysis であれば senti_analysis.hy の get-senti 関数を実行し、それ以外ではエラーを返す、というものだ。

## 全体のファイルとフォルダ構成
*senti_analysis.hy*

``` hylang
;; require 'pip install twython'
(import [nltk.sentiment.vader [SentimentIntensityAnalyzer]]
        nltk)

;; (.download nltk "vader_lexicon")
(setv vader-analyzer (SentimentIntensityAnalyzer))

(defn get-senti [text]
  (.polarity_scores vader_analyzer text))
```

*test.hy*

``` hylang
(import [http.server [HTTPServer SimpleHTTPRequestHandler BaseHTTPRequestHandler]]
        [urllib.parse [urlparse]]
        json)
(import senti_analysis)

(defclass EchoHandler [BaseHTTPRequestHandler]
  (defn do_GET [self]
    (setv content-len (int (.get self.headers "content-length")))
    (setv request-body (-> (.read self.rfile content-len)
                          (.decode "UTF-8")))
    (print request-body)
    (setv json-data (.loads json request-body))
    (print json-data)
    (print (. json-data ["type"]))
    (print (. json-data ["params"]))
    (.send_response self 200)
    (.send_header self "Content-type" "application/json")
    (.end_headers self)
    (setv response-body {"status" 400
                         "params" "不適切なパラメータです"})
    (when (= "senti-analysis" (. json-data ["type"]))
      (setv response-body
            {"status" 200
             "params" (senti_analysis.get-senti (. json-data ["params"]))}))
    (.wfile.write self (.encode (.dumps json response-body) "utf-8"))))

(setv httpd (HTTPServer (, "localhost" 8887) EchoHandler))

(.serve_forever httpd) 
```

```
.-
 |- senti_analysis.hy
 |- test.hy
```

## 結果
![image.png](https://qiita-image-store.s3.amazonaws.com/0/147520/017fa2e0-654b-5d91-3d50-d1a2087af292.png)

## 次にやること
何かあればやる
でもHylang＋有名ライブラリで書くよりCommon Lispのライブラリを利用したり(機械学習ライブラリであるMGLの更新がほぼ止まっていたりする)、Clojureのライブラリを利用したり(coretexかDeeplearning4j)、するのも楽しそう

# repository
https://github.com/MokkeMeguru/hylang-simple-server

# 参考
[https://qiita.com/yukinoi/items/c3c4e4e24a66b88d8215](https://qiita.com/yukinoi/items/c3c4e4e24a66b88d8215)