FrontPage

2020-11-22

PythonのgTTSが遅い・続

 

 先日の記事、「PythonのgTTSが遅い」の続き。
 同様の不具合の報せが作者の元に届いたようで、gTTSは2.1.2(2020/11/10)、2.2.0(2020/11/14)、2.2.1(2020/11/15)と怒濤のリリースラッシュ。CHANGELOGを読むと、tokenが取れない問題も、なぜか激ノロになっちゃう問題も、両方解決した模様。
 gTTSをアップデートしたら、以下のサンプルコードも快調に動作し、Google Homeが待ち時間なくしゃべるようになった。

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

import pychromecast
from gtts import gTTS
import time

tts = gTTS(text="ハローワールド", lang='ja')
tts.save('./test.mp3')
mp3url = 'http://192.168.0.XXX:8000/test.mp3';

#IPアドレスで特定する
googleHome = pychromecast.Chromecast('192.168.0.YYY')

if not googleHome.is_idle:
    print("Killing current running app")
    googleHome.quit_app()
    time.sleep(5)

#しゃべらせる
googleHome.wait()
googleHome.media_controller.play_media(mp3url, 'audio/mp3')
googleHome.media_controller.block_until_active()

 以上、続報でした。


2020-11-19

燃えよタイガース! '99

 

 ハードディスクの奥底から、1999年に作ったと思われる替え歌の歌詞が発掘された。
 ご笑覧のほど。
 元ネタは、燃えよドラゴンズ! '99

燃えよタイガース! '99

阪神高速にこだまする
トラの泣き声耳にして
甲子園球場につめかけた
僕らをしゅーんと萎えさせる
いいぞ、がんばれ! タイガース!
燃えよタイガース!

一番坪井が塁に出て
二番秀太でダブルプレー
三番新庄三振で
四番ブロワーズ帰国する
いいぞ、がんばれ! タイガース!
燃えよタイガース!

五番ジョンソン真が無く
六番矢野は夢破れ
七番今岡空を切り
八番桧山は天仰ぐ
いいぞ、がんばれ! タイガース!
燃えよタイガース!

藪は大きく負け越して
川尻税金ごまかして
メイは監督批判して
吉田は初回でK.O.だ
いいぞ、がんばれ! タイガース!
燃えよタイガース!

福原だけは信じてる
今でも中込太ってる
遠山左を封じても
竹内一発食らってる
いいぞ、がんばれ! タイガース!
燃えよタイガース!

葛西湯舟と火だるまに
油をそそいで杉山だ
田村伊藤はバテバテで
クイックできない怪人リベラ
いいぞ、がんばれ! タイガース!
燃えよタイガース!

僕もあなたもあきれてる
怒りを込めてボヤいてる
それはいつもの最下位だ
野村監督の更迭だ
いいぞ、がんばれ! タイガース!
燃えよタイガース!
がんばれ! がんばれ! タイガース!
燃えよタイガース!


2020-11-8

PythonのgTTSが遅い

 

 ラズパイ(OSは「Raspbian Stretch」)からPythonで書かれたスクリプトを使ってGoogle Homeをしゃべらせていたのだが、ここ数日、しゃべらなかったり、しゃべりはじめるのに何分もかかったりと、動作がおかしくなっていた。このスクリプトでは、gTTSというモジュールを使っていて、内部でGoogle Text To Speech APIを叩いているのだが、どうやらこのモジュールがうまく動かなくなっているらしい。
 試しに以下のようなスクリプト(speech.py)を動作させてみた。

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

import pychromecast
from gtts import gTTS
import time

tts = gTTS(text="ハローワールド", lang='ja')
tts.save('./test.mp3')
mp3url = 'http://192.168.0.XXX:8000/test.mp3';

#IPアドレスで特定する
googleHome = pychromecast.Chromecast('192.168.0.YYY')

if not googleHome.is_idle:
    print("Killing current running app")
    googleHome.quit_app()
    time.sleep(5)

#しゃべらせる
googleHome.wait()
googleHome.media_controller.play_media(mp3url, 'audio/mp3')
googleHome.media_controller.block_until_active()

 ラズパイのIPアドレスは「192.168.0.XXX」、そこでウェブサーバーを起動しておき、そのドキュメントルートに、gTTSを使って生成された音声ファイル(test.mp3)を保存し、それをPyChromecastというモジュールを使ってGoogle Home(IPアドレスは「192.168.0.YYY」)にしゃべらせている。
 すると、しゃべらないときには、以下のようなエラーを吐いていることがわかった。

Traceback (most recent call last):
  File "./speech.py", line 11, in <module>
    tts.save('./test.mp3')
  File "/usr/local/lib/python3.8/site-packages/gtts/tts.py", line 295, in save
    self.write_to_fp(f)
  File "/usr/local/lib/python3.8/site-packages/gtts/tts.py", line 251, in write_to_fp
    prepared_requests = self._prepare_requests()
  File "/usr/local/lib/python3.8/site-packages/gtts/tts.py", line 194, in _prepare_requests
    part_tk = self.token.calculate_token(part)
  File "/usr/local/lib/python3.8/site-packages/gtts_token/gtts_token.py", line 29, in calculate_token
    seed = self._get_token_key()
  File "/usr/local/lib/python3.8/site-packages/gtts_token/gtts_token.py", line 58, in _get_token_key
    raise ValueError(
ValueError: Unable to find token seed! Did https://translate.google.com change?

 なぜだかわからないが、Google Text To Speech APIからGETできるデータに所望のモノ(なにかしらのtoken?)がないらしい。
 そこで、gtts_token.pyにちょこっと追記して、retryモジュールを使って、_get_token_key()をリトライさせてみることにした。

from retry import retry #追記

(中略)

    @retry((ValueError, TypeError), tries=10, delay=1) #追記
    def _get_token_key(self):
        if self.token_key is not None:

 これでエラーは出なくなったものの、それでもまだ、しゃべり出すのに何分も待たされることがある。
 プロファイルを取ってみると、どうやらchardetという文字コード判定のモジュールの処理で時間がかかっているようなのだが、なぜそうなるのか(なぜ短時間で処理が終わることもあれば、何分も要することもあるのか)さっぱりわからない。

pi@raspberrypi:~ $ python3 -m cProfile ./speech.py | sort +1 -r | head
         16048373 function calls (16031699 primitive calls) in 123.627 seconds
   Ordered by: standard name
   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
  3918870   29.563    0.000   29.563    0.000 codingstatemachine.py:66(next_state)
        5   27.045    5.409   48.198    9.640 mbcharsetprober.py:61(feed)
        1   12.045   12.045   26.122   26.122 sjisprober.py:56(feed)
  1088785    7.701    0.000   12.662    0.000 jpcntx.py:143(feed)
        1    7.619    7.619   17.055   17.055 eucjpprober.py:56(feed)
     3106    5.281    0.002    5.281    0.002 {method 'findall' of 're.Pattern' objects}
       14    4.777    0.341   10.035    0.717 sbcharsetprober.py:77(feed)

 

解決策その1

 考えるのがめんどうになって、別のモジュールを使ってみることにした。
 ググって、やはりGoogle Text To Speech APIを使っているgoogle_speechというモジュールが公開されているのをみつけ、早速これに置き換えてみると、待たされることはなくなった。

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

import pychromecast
from google_speech import Speech
import time

speech = Speech("ハローワールド", 'ja')
speech.save('./test.mp3')
mp3url = 'http://192.168.0.XXX:8000/test.mp3';

#IPアドレスで特定する
googleHome = pychromecast.Chromecast('192.168.0.YYY')

if not googleHome.is_idle:
    print("Killing current running app")
    googleHome.quit_app()
    time.sleep(5)

#しゃべらせる
googleHome.wait()
googleHome.media_controller.play_media(mp3url, 'audio/mp3')
googleHome.media_controller.block_until_active()

 

解決策その2

 さらに調べていると、この記事の記載から、どうやらモジュールを使うまでもなく、簡単にGoogle Text To Speech APIを叩けるらしい、ということがわかった。2011年に書かれた古い記事なので事情が変わってないか心配だったが、試してみると、あっさり動いてくれた。待たされることもないし、そもそもラズパイ上にmp3ファイルが保存されることもない。

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

import pychromecast
import time
import urllib.parse

s = "ハローワールド"
s_quote = urllib.parse.quote(s)
mp3url = "http://translate.google.com/translate_tts?ie=UTF-8&q="+s_quote+"&tl=ja&client=tw-ob"

#IPアドレスで特定する
googleHome = pychromecast.Chromecast('192.168.0.YYY')

if not googleHome.is_idle:
    print("Killing current running app")
    googleHome.quit_app()
    time.sleep(5)

#しゃべらせる
googleHome.wait()
googleHome.media_controller.play_media(mp3url, 'audio/mp3')
googleHome.media_controller.block_until_active()

 

続報

 後日、gTTSの2.2.1へのアップデートによって問題が解決したことを確認。


2020-9-2

マスクと保冷剤の実験

 

 まず最初に、本実験で使っているマスクや保冷剤のメーカーとは、あくまで「メーカーとそのユーザー」という関係でしかないということをお断りしておく。
 また、本実験はあくまで個人的に行ったものであり、マネをして何かしらの不都合を被ったとしても、こちらとしては全くその責任を負うものではない。
 
 マスクに保冷剤を入れるというのは誰もが思いつくことであり、例えば以下のような、そのためのマスクも発売されているほどである。

 私が愛用しているマスクは、SoToLaBoAdjustable Mask COOLMAX GRAYというもの。

Image00020.jpg

 このマスクにはポケットがあり、中に市販のマスクフィルター等を入れることができる。別にメーカーで推奨しているわけではないが、このポケットに保冷剤を入れて暑さをしのごうとすることは容易に思いつくことであり、私も早速試してみた。

 先ず試したのは、以下のキャッチクール保冷剤20g。大きさは70mmX70mm。

Image00087.jpg

 気をつけなければいけないのは、この保冷剤は少し大きく、凍らせてからだとマスクの開口部からポケット部分に挿入することができないと言うこと。凍らせる前に、予めマスクに保冷剤を詰め込んでおき、マスクごと凍らせればよい。

 ところで、私の通勤時間は45分。うち電車に乗ってるのは3分間だけで、残りは徒歩である(最寄り駅から会社までバスが出ているが、健康のため歩くことにしている)。

 残念ながら、この20gの保冷剤を使っている限り、冷たさを感じられるのは30分ほどであった。
 保冷剤を2コ(合計40g)入れても、4コ(80g)入れても、6コ(120g)入れても、結果は同じ。おおよそ30分程度で冷たくなくなってしまう。
 なお、マスクのサイズの限界から、保冷剤を6コ以上入れることは難しかった。また、120gまでであれば通勤の45分の間一応耐えられたが、耳にかかる重さからも、120g程度が限界であると思われる。

 冷感が続くのが30分では、通勤時間のおよそ3分の2にしかならず、残りの15分はぬるくてかさばるマスクを付けたまま、歩いて会社へ向かわなければならない。これはなかなかに苦痛である。

 次に試したのは、以下の100gの保冷剤。

 これもまた、凍らせる前に、予めマスクに保冷剤を詰めてから、マスクごと凍らせる必要がある。

Image00079.jpg

 結論から言うと、これを使えば45分間の通勤時間の間ずっと冷感を感じ続けることができた(45分後でも芯にまだほんの少し凍った部分が残っている)。
 重さだけで言えば20gX6コの方が重いわけだが、それでもこの1コで100gの保冷剤の方が長い時間冷感を保持できたのは、やはり重さ(これは体積にほぼ比例する)あたりの表面積が小さい方が温度変化が小さくなるからだと考えられる。
 別の機会に試したところでは、この100gの保冷剤であれば1時間弱の間冷たさを感じることができた。

 残念ながら、保冷剤がかさばる分、マスクのフィット感は損なわれる。しかしながら、それは不具合を感じるほどではない。下記の写真の左が保冷剤なし、右が100gの保冷剤ありである。

Image00091.jpg

Image00092.jpg

 ちなみに、以下の150gのものも試してみたのだが、

 一応マスクのポケットに詰め込むことはできたのだが、保冷剤が大きくかさばりすぎてマスクの装着感が非常に悪いこと、150gという重さは重すぎて耳が痛くて通勤時間の45分間は耐えられなかったことから、これを採用するには至らなかった。

 今使っているこのSoToLaBoAdjustable Mask COOLMAX GRAYだが、実は二代目であり、私は初代のユーザーでもあった。
 初代から二代目の改善点は以下の二点。

  • ゴムがソフトタイプになったこと。
  • 裏地がCOOLMAXになったこと。

 この二点も、ソフトなゴムが耳にかかる保冷剤の重さを軽減するように感じられること、保冷剤がかさばる分マスクの内側が口元にぴったりくっ付いても気持ちがいいことから、私にとっては非常に有効な改良だったが、さらに気に入ったのはオプションのAdjustable Mask Nose Fit Wire "Stainless"である。Nose Fit Wireにはソフトタイプもあり、人によって好みもあるだろうが、両方試した私としては断然Stainlessの方をお勧めする(上がソフトタイプ、下がStainless)。

Image00062.jpg

 ソフトタイプはその名の通りアタリがソフトで、特にポケットに重さのある保冷剤が入っている場合には少し頼りない。対してStainlessだと、鼻に引っかかる感じがあり保冷剤入りマスクもしっかり保持できる。
 以下に比較の写真を示す。上がソフトタイプ、下がStainlessのNose Fit Wireが入った状態である。Stainlessの方が、よりしっかりした形状であることがわかる。これにより、よりしっかりしたフィット感が得られるわけである。

Image00058.jpg

 以上、マスクに保冷剤を入れた場合の保冷時間の実験結果と、それに用いたマスクや保冷剤の紹介でした。
 

2020-7-23

ベランダの花・続続続続

 


2020/06/07

Image00001.jpg

2020/06/10

Image00002.jpg

2020/06/12

Image00003.jpg

2020/06/17

Image00004.jpg

2020/06/21

Image00005.jpg

2020/06/24

Image00006.jpg

2020/07/23

Image00007.jpg



これより前の5日分