先日の記事で、古いノートPCを復活させた話を書きましたが、早速使う時がきました。
伊勢市内の中学校を対象に、キャリア教育の一環として、市内の事業者などの有志が仕事の話をするビジネスパーク伊勢というのがあって、私も都合が合う時にたまに参加しています。
コロナが落ち着いたこともあり、先日、対面式で再開され、その際にプログラマーの仕事について話す機会がありました。 で、せっかくなのでデモがてら、こんなことできるよ、という紹介の一つとして、 python での text-to-speech を実演してきました。
その際に行ったセットアップなどについて、まとめておきます。
実行環境は次の通りです。
- Lubuntu 18.04.6, 32bit 版
- python 3.6.9
- pip3 9.0.1
pyttsx3 のインストール
python で text-to-speech をするには pyttsx3 をつかうと簡単にできることを知りました(cs50.jp 見てたら出てきたので、さっそく使わせてもらいました)。このライブラリって、オフラインで動くんですよね、すげー。
まずは pip3 と pyttsx3 をインストールします。
mor@Lenovo3000:~$ sudp apt install python3-pip mor@Lenovo3000:~$ pip3 install pyttsx3
使ってみます。
mor@Lenovo3000:~$ python3 Python 3.6.9 (default, Jan 26 2021, 15:33:00) [GCC 8.4.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import pyttsx3 >>> engine = pyttsx3.init() Traceback (most recent call last): File "/home/mor/.local/lib/python3.6/site-packages/pyttsx3/__init__.py", line 20, in init eng = _activeEngines[driverName] File "/usr/lib/python3.6/weakref.py", line 137, in __getitem__ o = self.data[key]() KeyError: None During handling of the above exception, another exception occurred: Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/home/mor/.local/lib/python3.6/site-packages/pyttsx3/__init__.py", line 22, in init eng = Engine(driverName, debug) File "/home/mor/.local/lib/python3.6/site-packages/pyttsx3/engine.py", line 30, in __init__ self.proxy = driver.DriverProxy(weakref.proxy(self), driverName, debug) File "/home/mor/.local/lib/python3.6/site-packages/pyttsx3/driver.py", line 50, in __init__ self._module = importlib.import_module(name) File "/usr/lib/python3.6/importlib/__init__.py", line 126, in import_module return _bootstrap._gcd_import(name[level:], package, level) File "<frozen importlib._bootstrap>", line 994, in _gcd_import File "<frozen importlib._bootstrap>", line 971, in _find_and_load File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked File "<frozen importlib._bootstrap>", line 665, in _load_unlocked File "<frozen importlib._bootstrap_external>", line 678, in exec_module File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed File "/home/mor/.local/lib/python3.6/site-packages/pyttsx3/drivers/espeak.py", line 9, in <module> from . import _espeak, toUtf8, fromUtf8 File "/home/mor/.local/lib/python3.6/site-packages/pyttsx3/drivers/_espeak.py", line 18, in <module> dll = cdll.LoadLibrary('libespeak.so.1') File "/usr/lib/python3.6/ctypes/__init__.py", line 426, in LoadLibrary return self._dlltype(name) File "/usr/lib/python3.6/ctypes/__init__.py", line 348, in __init__ self._handle = _dlopen(self._name, mode) OSError: libespeak.so.1: cannot open shared object file: No such file or directory >>>
あれ?初期化しただけなのにエラーになりました。
ちょっとネットを調べてみると、 Linux の場合、 espeak というパッケージがないとだめなようです。
- GitHub - nateshmbhat/pyttsx3: Offline Text To Speech synthesis for python
- python - OSError: libespeak.so.1: cannot open shared object file: No such file or directory - Stack Overflow
なので、必要なパッケージをインストールします。
mor@Lenovo3000:~$ sudo apt install espeak mor@Lenovo3000:~$ sudo apt install ffmpeg
libespeak1 は espeak を入れると入るようです。
もう一度試すと
mor@Lenovo3000:~/work$ python3 Python 3.6.9 (default, Jan 26 2021, 15:33:00) [GCC 8.4.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import pyttsx3 >>> engine = pyttsx3.init() >>> engine.say("hello world") >>> engine.runAndWait() >>>
ちゃんと聞こえますね。これ、結構楽しいですね。
英語だけだとなんなので、日本語も試してみます。
>>> >>> engine.say("こんにちは") >>> engine.runAndWait() >>>
あれ?日本語だと使えないですね。
日本語への対応
調べてみると、
python - Pyttsx3 does not read text in other languages - Stack Overflow
言語設定を調べて、切り替える必要があるようです。確認してみます。
こんな内容の test_tts.py を作ります。
import pyttsx3 engine = pyttsx3.init() voices = engine.getProperty('voices') for voice in voices: print(f"Voice: {voice.name}")
これを実行してみます。
mor@Lenovo3000:~/work$ python3 test_tts.py Voice: afrikaans Voice: aragonese Voice: bulgarian Voice: bosnian Voice: catalan Voice: czech Voice: welsh Voice: danish Voice: german Voice: greek Voice: default Voice: english Voice: en-scottish Voice: english-north Voice: english_rp Voice: english_wmids Voice: english-us Voice: en-westindies Voice: esperanto Voice: spanish Voice: spanish-latin-am Voice: estonian Voice: persian Voice: persian-pinglish Voice: finnish Voice: french-Belgium Voice: french Voice: irish-gaeilge Voice: greek-ancient Voice: hindi Voice: croatian Voice: hungarian Voice: armenian Voice: armenian-west Voice: indonesian Voice: icelandic Voice: italian Voice: lojban Voice: georgian Voice: kannada Voice: kurdish Voice: latin Voice: lingua_franca_nova Voice: lithuanian Voice: latvian Voice: macedonian Voice: malayalam Voice: malay Voice: nepali Voice: dutch Voice: norwegian Voice: punjabi Voice: polish Voice: brazil Voice: portugal Voice: romanian Voice: russian Voice: slovak Voice: albanian Voice: serbian Voice: swedish Voice: swahili-test Voice: tamil Voice: turkish Voice: vietnam Voice: vietnam_hue Voice: vietnam_sgn Voice: Mandarin Voice: cantonese mor@Lenovo3000:~/work$
まじですか。確かに、日本語が入っていないです。
もう少し調べてみると、 espeak で対応していない言語も espeak-ng だとカバーされている場合があるとのことです。
なので、下記記事を参考に espeak-ng に切り替えてみます。
Is there a way to use the espeak-ng engine? · Issue #103 · nateshmbhat/pyttsx3 · GitHub
mor@Lenovo3000:~/work$ sudo apt purge espeak mor@Lenovo3000:~/work$ sudo apt autoremove mor@Lenovo3000:~/work$ sudo apt install espeak-ng mor@Lenovo3000:~/work$ cd /usr/lib/i386-linux-gnu/ mor@Lenovo3000:/usr/lib/i386-linux-gnu$ sudo ln -s libespeak-ng.so.1 libespeak.so.1
espeak (および libespeak1 )をアンインストールして、espeak-ng を入れて、libespeak-ng.so.1 にシンボリックリンクを張ればよいようです。 そのうえで、しゃべる前に、前述の記事にあったように setProperty で言語を指定すればよいようです。
試してみます。
mor@Lenovo3000:~/work$ python3 Python 3.6.9 (default, Jan 26 2021, 15:33:00) [GCC 8.4.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import pyttsx3 >>> engine = pyttsx3.init() >>> engine.setProperty("voice", "Japanese") >>> engine.say("こんにちは") >>> engine.runAndWait()
おお、日本語でしゃべれますね。
ただ、漢字は読めずに、ひらがなでないとダメとか、文がながいと途端に聞き取りにくくなるとか、微妙な点もあるけど、まずもって動くのはいいですね。
まとめ
冒頭の出前授業でも無事に text-to-speach を見せることができました。デモ的には、
import pyttsx3 engine = pyttsx3.init() engine.setProperty("voice", "Japanese") #rate = engine.getProperty("rate") #print(f"rate: {rate}") engine.setProperty("rate", 130) while (1): txt = input("ひらがなで文字をにゅうりょくしてください: ") #print(f"text is: [{txt}]") if txt == None or len(txt) == 0: exit() engine.say(txt) engine.runAndWait()
上記のように、コマンドラインで入力した文言をそのまま音声で読む形にしました。機械的な合成音が面白いようで、ややうけ、という感じでした。
ちなみに、 Scratch でネコを動かしたほうがウケていたのは、内緒にしておいてください。恐るべし、 Scratch 。