桐間紗路研究所日報

技術以外の話→ https://kirimasyaro.hateblo.jp

ツイート形態素解析で幸福度調査/テキストストリーミングの話(gunicorn)

http://aisunyan.moe.hm/chiaki/emo


生活満足度調査


 こんなアプリを作りました

 ツイートを形態素解析して、某所にある単語のポジティブさ・ネガティブさを数値化した表と比較して、ツイートがポジティブなものかネガティブなものかを測る、というフェイクアプリです

 数値の求め方とか、係り受け分析をしてないとか、いろいろ問題はあると思うんですけど、たとえば「好き」という単語を含むツイートをすると数値が上がったり、「雪」という単語で逆に数値が下がりまくったりするのを見てると、まあ面白いんじゃないかなーみたいな

f:id:copuy:20180701141954j:plain

 ここで%になっている数値は、わかりやすいように百分率に直してあるんですけど、実はもうちょっと違う値で、無理やり%にしてるので色々おかしい、というのも課題・・・

開発の話

 
 それより問題なのは、処理に時間がかかるので、処理状況を表示しているんですが、その間ずっとページがロード中になってしまうことなんですね・・・

 こういうのやるときはwebsocketとか使ったほうが良いんだろうなあって思うんだけど、まあとりあえず成果が上がればいいやの精神でとりあえず作ってみました・・・



 このアプリはflask⇔gunicorn⇔nginxという構成でLinuxで動かしているんですけど、それで、処理状況を表示するのにこういうコードを書いています

def stream_template(template_name, **context):
    app2 = Flask(__name__)
    app2.jinja_loader = FileSystemLoader('templates')
    app2.update_template_context(context)
    t = app2.jinja_env.get_template(template_name)
    rv = t.stream(context)
    rv.disable_buffering()
    return rv

@app.route('/chiaki/emo')
def main2():
    if "oauth_token" not in session:
        auth_info = 'ログインしてください'
    else:
        auth_info = 'あなたは現在ログインしています'
    def generate():
        if request.args.get("analyze", None) is not None:
            for x in analyze():
                yield x
        else:
            yield ['', '', '']
    rows = generate()
    return Response(stream_with_context(stream_template('chiaki/emo3.html', auth_info=auth_info, status=rows)))

 Flask: テキスト・ストリーミングやってみた♬
 このページを参考にしています
 Flask(__name__)をわざわざもう一度生成しているのは、このコードがおいてある場所がアプリのメインとなるファイルではなく、Blueprintを使って読み込んでいるため、app.jinja_env.get_templateとやってしまうと、appがflaskではなくblueprintなのでエラーになってしまうためです(説明しにくい・・・

 ポイントになるのはyielddisable_buffering()です。これで処理中にレスポンスを返すことができます。
 しかしここで引っかかりました。テスト環境ではうまくいくのになぜか本番環境でうまくいかない
 そこでこのページを見つけました
 Deploying Gunicorn — Gunicorn 19.8.1 documentation
 If you want to be able to handle streaming request/responses... のところ、
 To turn off buffering, you only need to add proxy_buffering off;
 これに従ってやるとgunicornでストリーミングとしてレスポンスを垂れ流すことができる(?)みたいです

 nginxのconf

  location @my_app {
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Request-Id $request_id;
    proxy_redirect off;
    proxy_buffering off;
    proxy_pass http://hello;
    proxy_connect_timeout       3600;
    proxy_send_timeout          3600;
    proxy_read_timeout          3600;
    send_timeout                3600;
  }

こんなふうに設定してあります
同様の問題で困ってる方いたら参考になったら幸いです