Category Archives: Python

Linuxに注文の多い料理店をしゃべらそう(Open Jtalk)

Pocket

Nano Pi Neo2にOpen JTalkでしゃべらせたのでメモ。

Open Jtalkは「入力された日本語テキストに基づいて自由な音声を生成するHMMテキスト音声合成システム」とのこと。
http://open-jtalk.sp.nitech.ac.jp/

open-jtalk、辞書をインストールする。
open-jtalkをインストールすれば辞書もついてくる。

$ apt search open-jtalk
ソート中... 完了
全文検索... 完了  
open-jtalk/artful 1.10-1 amd64
  日本語音声合成システム

open-jtalk-mecab-naist-jdic/artful,artful,now 1.10-1 all
  NAIST Japanese Dictionary for Open JTalk

$ sudo apt-get install open-jtalk
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています                
状態情報を読み取っています... 完了
提案パッケージ:
  hts-voice-nitech-jp-atr503-m001
以下のパッケージが新たにインストールされます:
  open-jtalk open-jtalk-mecab-naist-jdic
(略)

提案パッケージであるhts-voice-nitech-jp-atr503-m001も。
これは音声データ。男性の声。

hts-voice-nitech-jp-atr503-m001 - Japanese male voice data for Open JTalk

open-jtalkのコマンドはopen_jtalk(間はアンダースコア)として、open_jtalkの辞書は/var/lib/mecab/dic/open-jtalk/naist-jdicに、音声データは/usr/share/hts-voice/にインストールされる。
「こんにちは」と書いたvoice.txtを作り、open_jtalkに食わす。

$ cat ./voice.txt 
こんにちは

$ open_jtalk -m /usr/share/hts-voice/nitech-jp-atr503-m001/nitech_jp_atr503_m001.htsvoice -x /var/lib/mecab/dic/open-jtalk/naist-jdic -ow test.wav ./voice.txt 

喋ってくれるはず。
やはり女性の声のほうが良いので、名工大のMMDAgentを使う。
http://share.udialogue.org/meissen/login.htm
2018/3/21時点で1.7が最新
ダウンロードして展開し、/usr/share/hts-voice/に格納する。
使うのは中身の「mei」ディレクトリ配下のみ。
Meiさんは名工大キャラクターだそうな。

$ wget https://sourceforge.net/projects/mmdagent/files/MMDAgent_Example/MMDAgent_Example-1.7/MMDAgent_Example-1.7.zip
$ unzip ./MMDAgent_Example-1.7.zip 
$ sudo cp -R ./MMDAgent_Example-1.7/Voice/mei /usr/share/hts-voice/

声には以下の5種類がある。実際に発声させる際に選ぶ。
mei_angry.htsvoice mei_happy.htsvoice mei_sad.htsvoice
mei_bashful.htsvoice mei_normal.htsvoice

以下のスクリプトを用意する。
どこかのサイトから持ってきたんですが、どのサイトからだったか忘れてしもうた…。
これをjtalk.pyとして保存する。1行目は環境に応じて変えること。
htsvoiceは上記の通り喜怒哀通常から選べる。
speedも選べる。
このあたりは試行錯誤。

あとはこれをimportして使う。

#!/usr/bin/python

#coding: utf-8
import subprocess
from datetime import datetime

def jtalk(t):
    open_jtalk=['/usr/bin/open_jtalk']
    mech=['-x','/var/lib/mecab/dic/open-jtalk/naist-jdic']
    htsvoice=['-m','/usr/share/hts-voice/mei/mei_normal.htsvoice']
    speed=['-r','1.0']
    outwav=['-ow','/tmp/open_jtalk.wav']
    cmd=open_jtalk+mech+htsvoice+speed+outwav
    c = subprocess.Popen(cmd,stdin=subprocess.PIPE)
    c.stdin.write(t.encode('utf-8'))
    c.stdin.close()
    c.wait()
    aplay = ['aplay','-q','/tmp/open_jtalk.wav']
    wr = subprocess.Popen(aplay)

def say_datetime():
    d = datetime.now()
    text = '%s月%s日、%s時%s分%s秒' % (d.month, d.day, d.hour, d.minute, d.second)
    jtalk(text)

if __name__ == '__main__':
    say_datetime()

先ほどのファイルをimportして、jtalk.jtalk(string)で、発話させたい文章を渡せばOK。

#!/usr/bin/python

#coding: utf-8
import jtalk

jtalk.jtalk('何か話してください')

さあテストである。
青空文庫「注文の多い料理店」を朗読させてみる。
「新字新仮名」版をダウンロード。
http://www.aozora.gr.jp/cards/000081/card43754.html

そのままではOpen Jtalkに渡せないので、以下の変更を加える。

  • 文字コードをShift-JISからUTF-8へ
  • ルビを削除(正規表現パターンは”《.*?》”。)
  • ルビの個所を示す区切り記号を削除(”|”)
  • 構成を示す注釈を削る(正規表現パターンは”\[.*?\]”。)
  • 改行コードをCR+LFをLFのみに。(\rを削る)

できれば以下も。

  • 行頭字下げ、要するに行頭の全角スペースを削除(正規表現パターンは”^ ”。)
  • セリフのカギかっこを削る。行頭のものだけでよい。(正規表現パターンは”^「”。)

以下までできれば完璧

  • 改行をいったん全て削り、句点のあとに改行コード(\n)を挿入

neko.txtとでも保存し、以下のPythonスクリプトを実行。

#!/usr/bin/python

import jtalk

for line in open('neko.txt','r'):
    print(line)
    jtalk.jtalk(line)

こんな感じ。

試してみるとわかるが、漢字の読み方が変だったり(山猫軒を「やまねこのき」と読んだり)、読めない漢字があったりする。
そりゃまあ仕方ないよね。

 
それはさておき。
十分なスペックがあるときに複数行の文章を読ませると、発話が終わっていないのに次の行の処理を始めてしまって困ることがある。
そういうときは発話の終了を待つよう、wait()を入れればよい。
関数jtalk()の最後に一行追加。

def jtalk(t):
    open_jtalk=['/usr/bin/open_jtalk']
    mech=['-x','/var/lib/mecab/dic/open-jtalk/naist-jdic']
    htsvoice=['-m','/usr/share/hts-voice/mei/mei_normal.htsvoice']
    speed=['-r','1.0']
    outwav=['-ow','/tmp/open_jtalk.wav']
    cmd=open_jtalk+mech+htsvoice+speed+outwav
    c = subprocess.Popen(cmd,stdin=subprocess.PIPE)
    c.stdin.write(t.encode('utf-8'))
    c.stdin.close()
    c.wait()
    aplay = ['aplay','-q','/tmp/open_jtalk.wav']
    wr = subprocess.Popen(aplay)
    wr.wait()

 

参考サイト
Raspberry piで日本語音声合成(Open JTalk)を試してみる。

[メモ] SlackとMattermostそれぞれのincomingWebhookへのポスト方法の違い

Pocket

MattermostはSlackのクローンであるが、incomingWebhookへのポストだけは、どうも違いがあるようだ。
以下にSlack/Mattermostそれぞれでの実例を示す。
まずmattermost

# mattermost

import requests

incomWebHook = 'http://192.168.10.1/hooks/xxxxx'
msg = 'test message'
icon_url = 'http://192.168.10.10/graphix/robot.png'
username = 'bot'

def sendMsg(incomWebHook, icon_url, username, msg):
    payload = {
            'text': msg,
            'icon_url': icon_url,
            'username': username}

    r = requests.post(
        incomWebHook,
        json=payload)

    return r

r = sendMsg(incomWebHook, icon_url, username, msg)

Slack

# slack
import requests

incomWebHook ="https://slack.com/api/chat.postMessage"
msg = 'test message'
username = 'bot'
token = "xoxb-xxxx-xxxx"

def sendMsg(incomWebHook, token, username, msg):
    payload_dic = {
            "token": token
            "type": "message",
            "channel": "#general",
            "text": msg,
            "username": username,
            "icon_emoji": ":bird:",
            }

    headers = {
            'Content-type': 'application/json',
            'Accept': 'text/plain'
            }

    r = requests.post(
            incomWebHook,
            params=payload_dic,
            headers=headers)

    return r

r = sendMsg(incomWebHook, token, username, msg)

[メモ][Python] AnacondaをWindows xpにインストールしようとすると失敗する

Pocket

Anacondaは、Pythonのほかに、IPython、Spyder、pandas他便利ライブラリが一式でついてくるお手軽Python環境である。

しかしAnacondaをWindows xpにインストールしようとすると失敗する。
具体的には、インストール途中の「メニューを作る」ステップで失敗。
無視して進めると、C:\Anaconda3に実行ファイルは揃っているので、「なんだ気のせいか」と安心して起動しようとすると「有効なWin32アプリケーションではありません」という旨のエラーが発生する。

原因は、最新版がxpに対応していないせい。
以下から2.2.0をダウンロードし、インストールする。

https://repo.continuum.io/archive/

念のためファイル名とハッシュ値も残す。

Anaconda3-2.2.0-Windows-x86.exe
7c49a4e76e1c383038c4a1e8c4ac506f

Anaconda-2.2.0-Windows-x86.exe
32246b48658d4c3faeef425cec64a131

AnacondaのFAQにしっかり記載がある。

https://docs.continuum.io/anaconda/faq

How can I use Anaconda on Windows XP?
Windows XP is supported on Anaconda versions 2.2 and earlier. Download it from our archive.

Slack/MattermostのbotをPythonのFlaskで作ろう

Pocket

Slack/Mattermost(以降、まとめてSlack)のbotといえばHubotが有名だ。
Hubotはcoffeescriptで書かれているのだが、botのためだけに新しい言語を覚えるのも面倒。
加えてHubotを動作させるにはnpmが必要。
ちょっとそこまでは…。
Pythonなら普段使いで最初から環境は作ってあるし、楽だし。
そう思っていろいろと調べてみた。

Slackのbotに必要なことは?

Slackのbotに必要なのは、端的に以下の二つ。
1. Slackからのデータ送信を受ける。
2. Slackへ何かをする。

1.は、HTTP POSTでやってくるので、POSTを受けることさえできればよい。
2.は、例えばSlack上で何かの発言をすることだが、こちらはcurl(Pythonならrequests)でも使えば簡単にできる。

PythonでHTTP POSTを受けるには?

Flaskである。
Flaskとはごくごく軽量なwebフレームワークである。
驚くくらい簡単にwebサーバを作ることができる。
もちろんPOSTを受けるのもすぐにできる。
以下、説明。

Flaskのインストール

pipでもなんでも、好きなものを使ってインストールせい。

Flaskのテスト

以下のようなスクリプトを書く。
適当な名前で保存する。
flask.pyとかはやめようね。

#!/usr/local/bin/python

from flask import Flask

app = Flask(__name__)

@app.route('/')
def welcome():
    html = '<html><title>welcome</title>'
    html = html + '<body>welcome</body></html>'
    return html

if __name__ == '__main__':
    app.debug = True
    app.run(host='0.0.0.0')

上記のapp.route(‘/’)とは、ルーティング。
ルートディレクトリ(’/’)へのアクセスがあったら、次のdef welcome()が(デコレートによって)呼ばれる、ということである。

上記の場合、welcomeと表示するhtmlが返る。

app.debug = Trueについては後述。
app.run(host=’0.0.0.0)のhost=…の記述により、サーバを外部に公開することになる。

テストスクリプトの実行

$ python ./flasktest.py
 * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger pin code: 213-546-048

localhostのポート5000でサーバが立ち上がったと分かる。
ブラウザでアクセスして「welcome」と表示されればよい。

ところで、app.debut = Trueだが、スクリプトを書き換えると、自動的に再読み込みをしてくれる。
実際のログは以下。

 * Detected change in '/usr/home/doe/py/flasktest.py', reloading
 * Restarting with stat
 * Debugger is active!

激烈に便利な機能なので、開発中は有効にしておくこと。

SlackからのPOSTを受ける。

先ほどのスクリプト冒頭のimportを以下のように変更。

from flask import Flask, request

さらに以下を追加。

@app.route('/matter', methods=['POST'])
def post():
    print request.form

上記のようにしておいて、Slack側のOutgoing Webhookで、呼び出すURLに「http://<あなたのサーバのアドレス>:5000/matter」を指定する。

Slack側からwebhookを呼び出してみると、POSTされた内容がログに表示されるはず。
なお、def post()が何も返さないのでエラーは出るが気にしない。

以下が例。

ImmutableMultiDict([('user_id', u'xxxxx'), ('channel_id', u'xxxxx'), ('timestamp', u'1414562326'), ('team_id', u'xxxx'), ('trigger_word', u'test'), ('channel_name', u'off-topic'), ('token', u'xxxtokenxxx'), ('text', u'test'), ('team_domain', u'xxxx'), ('user_name', u'xxxx')])

つまりPOSTの内容はディクショナリになっている。

Slackへ応答を返そう

Slackへ応答を返す場合には、POSTでもらった中にあるtokenが必要である。
応答文、tokenのディクショナリを作っておいて、それをjsonに変換し、返してやればよい。
Mattermostの場合、tokenのキーは’MATTERMOST_TOKEN’

先ほどのスクリプトを最終的に以下のようにする。
(わざわざjsonをimportしているが、Flaskにもそういう機能がある気がしてならない)
これでSlackから通知を受けると、「You said <トリガーワード>」という応答がSlackへ帰る。

#!/usr/local/bin/python

from flask import Flask, request
import requests
import json

app = Flask(__name__)

@app.route('/')
def welcome():
    html = '<html><title>welcome</title>'
    html = html + '<body>welcome</body></html>'
    return html

@app.route('/matter', methods=['POST'])
def post():
    postdic = request.form
    incomeText = postdic['text']
    token = postdic['token']
    text = 'You said ' + incomeText

    payload = {
            'text': text,
            'MATTERMOST_TOKEN': token}
    json_payload = json.dumps(payload)
    return json_payload

if __name__ == '__main__':
    app.debug = True
    app.run(host='0.0.0.0')

あとはどんどん膨らませていけばよい。

 

[Python] listの差分を知るには

Pocket

Pythonで、二つのリストの差分を知るには。
リストのままでは引き算ができない。
set()でset型にしてから引き算をする。
ただしset()すると、与えられたリストから重複した要素が除かれること、順序も保持されないことに注意
また、set()して要素を操作した結果はset型のまま。
list()でリストに戻す必要がある。

以下、サンプル。

>>> a = ["a"]
>>> b = ["b","c","d"]
>>> b - a
Traceback (most recent call last):
  File "", line 1, in 
TypeError: unsupported operand type(s) for -: 'list' and 'list'
>>> c = list(set(b) - set(a))
>>> c
['c', 'b', 'd']
>>> c.sort()
>>> c
['b', 'c', 'd']

[Python][memo] タイムスタンプの差を求める

Pocket

すぐ忘れるのでメモ。

文字列としてのタイムスタンプは、datetime.datetime.strptimeで、フォーマットを指定してdatetime.datetime型に変換。
そうしたら加減算ができる。datetime.timeでは出来ないので注意。
以下、IPythonでの例。

In [1]: from datetime import datetime

In [2]: t1 = datetime.strptime("14:36:02.0689", "%H:%M:%S.%f")

In [3]: t2 = datetime.strptime("14:36:03.0102", "%H:%M:%S.%f")

In [4]: print type(t1)


In [5]: delta = t2 - t1

In [6]: print str(delta)
0:00:00.941300

In [7]: print str(delta)[6:]
0.941300

In [8]: 

[Python] requestsとlxmlで京急の運行情報を抽出しよう

Pocket

botに京急の運行情報を調べさせて、Slackで発言させたい。
使用言語はPython。
さあどうしようかと思ったら、さいきんは、どんなものでもライブラリが揃っていて、あっという間になんでも出来てしまうのな。

ページの取得はrequests、解析はlxmlを使う。

Webページの事前解析

ページのソースから、狙いの箇所を特定するようなキーワードを見つける。
あるいは、たとえばChromeなら、デベロッパーツールで探してもよい。
京急のページであれば、以下のように。

keikyuanalyze
手がかりは”div.unko-panel”。
これをもとにコードを書く。

抽出コード

stackoverflowを調べればサンプルコードなんかいくらでもあるよねー。

import lxml.html
import requests

def getKeikyuStatus():
    target_url = "http://unkou.keikyu.co.jp/"
    target_html = requests.get(target_url).text
    root = lxml.html.fromstring(target_html)

    divs = root.xpath("//div[contains(@class, 'unko-panel')]")
    for div in divs:
        unkouinfo = div.text_content().encode("UTF-8")

    return unkouinfo.strip()

requestsでwebページ取得。
lxmlで読み込んで、class “unko-panel”のdivタグを見つければよい。

[参考]slackへの投稿

ここはサラッと。
詳細はslackのサイトを見る。
前章の関数の戻り値を引数に取る関数。

def noticeSlack(keikyuStatus):
    url ="https://slack.com/api/chat.postMessage"
    msg = keikyuStatus + " #keikyu"

    payload_dic = {
        "token": "xoxb-xxxx-xxxx",
        "type": "message",
        "channel":"#general",
        "text":msg,
        "username":"keikyubot",
        "icon_emoji":":bird:",
        }

    headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}
    r = requests.post(url, params=payload_dic, headers=headers)

    return r

[Python] wxPythonで、タイトルバーにアイコンを表示するには

Pocket

Pythonからpy2exeなどでWindowsアプリケーションを作成したときに、アイコンを設定することができる。
しかし、作成したアプリケーションがGUI版の場合、GUIタイトルバーのアイコンを設定するには、ちょっとしたテクニックが必要である。
py2exe等でアイコン設定済み、かつGUIはwxPythonで作成している前提で、その方法を示す。

サンプル

class MyFrame(wx.Frame):
    def __init__(self, *args, **kwds):
	(略)
		if os.path.exists("myWxApp.exe"):
    		self.SetIcon(wx.Icon("myWxApp.exe",wx.BITMAP_TYPE_ICO))

Frameクラスの初期化defの中で、上記のような記載を加える。
もちろんmyWxApp.exeは最終的なファイル名。

説明

py2exe等でiconファイルを設定するというのは、つまり実行ファイルに埋め込むということ。
上記のようにSetIconで自分自身の実行ファイルを参照すると、埋め込んでおいたアイコンファイルを読み取ることができる。

元ネタ
How to use py2exe icon_resources in wxPython application?

【参考】wxPython

http://ja.wikipedia.org/wiki/WxPython
wxPythonは、「wxPythonはPythonで記述されたクロスプラットフォームなウィジェット・ツールキットである。」
要するにPythonをGUIで動かすツールキット。OSをまたがって使用できる。

[Python] Sublime textのインストールと設定

Pocket

Pythonのエディタとして、長らくIDLEを使っていたけれども、Sublime textに巡り合って満足した。
導入方法について記す。

日曜プログラマのコードエディタ

俺みたいな日曜プログラマは間欠泉的にコードを書く。
つまり日常的にコードを書くわけではないので、文法やらなにやら、すぐに忘れてしまう。
こういう人々にとっては、コードを書くための支援や補助があるエディタは非常にありがたい。
となると、一番に候補に挙がるのはEclipseであるが、日曜プログラマはそんな重量級のIDEを使うほど必死でもない。
となると高機能なテキストエディタくらいがちょうど良いのである。
sublime textは、そんな要望にピッタリであった。

sublime textとは

「コードを書くための洗練されたテキストエディタ」だそうで。
追加機能はパッケージシステムで実現されていて、駆使すれば驚くようなことができる。
sublime textは$70であるが、お金を払わずとも使用はできる。
Windowsでも、Macでも使える。

インストール

http://www.sublimetext.com/3

上記からダウンロード、インストールすればよい。
2と3があり、3はベータの段階であるが、まあ3でよいでしょう。
ポータブルバージョンもあるのが嬉しい。
しかし、本体インストールだけでは単なるテキストエディタ。
続けてパッケージシステムを有効にして、パッケージをいくつかインストールする。
その前に。

書いたコードの実行はCtrl + B

そのまま。
コードを書くエディタにテキストエディタを選んだときの一番の欠点は、コードの実行である。
テキストエディタで書いて、ターミナル/コマンドプロンプトを開いて実行し、またエディタに戻って…というのが苦痛。
これが嫌で、かといって重量級IDEも嫌で、しょうがなくPython付属のIDE(?)であるIDLEをしばらく使っていた。
もちろん、テキストエディタでだって、コードを実行することもできる。
しかしそれには(俺にとっては)面倒な設定が必要なんだが、Sublime textならCtrl + Bだけで済む。もちろんpython等がPATHに入っている必要はあるけれども。
ではパッケージの話へ。

パッケージシステムの有効化

パッケージシステムを有効にするには、sublime textでコマンド実行する必要がある。
そこだけ聞くと面倒そうだが、意外に簡単。

ctrl+` と叩くか、View > Show Console。
現れた欄に https://packagecontrol.io/installation にあるコードを貼り付ける。

同サイトに以下の警告がある通り、必ずサイトからコードをコピーすること。

Warning: Please do not redistribute the install code via another website. It will change with every release. Instead, please link to this page.

パッケージのインストール

さっそくパッケージをインストール。
Preference > Package Control > Install Package と進むか、Ctrl + Shift + P  と叩き、さらに”install”とタイプ、リターン。
インストール可能なパッケージが並ぶので、カーソルで選んでリターンを押すだけ。
どのパッケージをインストールするか。
最初は以下のページからザクザクインストールしたらよい。不要なら無効にできるしね。

パッケージ人気ランキング
https://packagecontrol.io/browse/popular

以下、パッケージの説明。

おすすめパッケージ

SublimeLinter
http://sublimelinter.readthedocs.org/en/latest/
Sublime​Linter-pep​8
https://packagecontrol.io/packages/SublimeLinter-pep8
SublimeLinterは書式をチェックしてくれる(Linter)もの。
追加で言語パッケージを入れる必要がある。pep8はPython用。

SideBarEnhancements
https://packagecontrol.io/packages/SideBarEnhancements
Sublime Textは、左側ペインにファイルのリストが表示される。ここでの操作を強化するパッケージ。

Theme-Soda
https://packagecontrol.io/packages/Theme%20-%20Soda
テーマですね。テーマはSublime text全体の見た目を、カラースキームはコード表示を決める。

BracketHighlighter
https://packagecontrol.io/packages/BracketHighlighter
カッコを強調表示。

SublimeCodeIntel
https://packagecontrol.io/packages/SublimeCodeIntel
コード補助だけど、ちょっと鬱陶しいかも。

Alignment
http://wbond.net/sublime_packages/alignment
イコールの場所を揃えてくれる。
以下はWindowsの日本語関係

ConvertToUTF8
https://packagecontrol.io/packages/ConvertToUTF8

IMESupport
https://packagecontrol.io/packages/IMESupport

[Python][Windows] Windows7への純正Pythonインストールメモ

Pocket

ActivePython入れたり純正Python入れたり訳わかんなくなるからメモ。

Pythonのインストール

https://www.python.org/ から2.xでも3.xでもダウンロード、インストール。
アップグレードの場合は、たぶん自分で古いバージョンをアンインストールした方がよい、と思う。
pythoninstallpathadd
インストール時設定は、pythonをpathに追加するところだけ変更した。

pipのインストール

不要ッ!
2.7.9以降、あるいは3.4以降なら最初っからインストールされている。
pip included with Python
実際、デフォルトの状態で以下の通り。

C:\Users\nobwak>python --version
Python 2.7.9

C:\Users\nobwak>pip list
pip (1.5.6)
setuptools (7.0)

ん?ちょっと古いような?

pip install -U pip

などとして最新版にした。