2017年8月25日 星期五

利用 Google gTTS 文字轉語音 API 讓電腦說話

測試過 Google 的語音辨識轉文字後, 接著要反過來測試 Google 的 gTTS 模組將文字轉成語音, 參考下面這篇大數軟體的教學影片 :

[Open Jarvis] 如何用Python 讓電腦說話?



D:\Python>pip3 install gTTS

D:\Python\test>pip3 install gTTS
Collecting gTTS
  Downloading gTTS-1.2.2.tar.gz
Requirement already satisfied: six in c:\python36\lib\site-packages (from gTTS)
Requirement already satisfied: requests in c:\python36\lib\site-packages (from gTTS)
Collecting gtts_token (from gTTS)
  Downloading gTTS-token-1.1.1.zip
Installing collected packages: gtts-token, gTTS
  Running setup.py install for gtts-token ... done
  Running setup.py install for gTTS ... done
Successfully installed gTTS-1.2.2 gtts-token-1.1.1

如果要離線安裝, 則除了下載 gTTS 模組外, 還必須下載 gTTS-token 模組, 而且要先安裝 gTTS-token 後才能再安裝 gTTS :

https://pypi.python.org/pypi/gTTS/1.2.2
https://pypi.python.org/pypi/gTTS-token/1.1.1

D:\Python>pip3 install gTTS-token-1.1.1.zip
Processing d:\python\gtts-token-1.1.1.zip
Requirement already satisfied: requests in c:\python36\lib\site-packages (from g
TTS-token==1.1.1)
Installing collected packages: gTTS-token
  Running setup.py install for gTTS-token ... done
Successfully installed gTTS-token-1.1.1

D:\Python>pip3 install gTTS-1.2.2.tar.gz
Processing d:\python\gtts-1.2.2.tar.gz
Requirement already satisfied: six in c:\python36\lib\site-packages (from gTTS==
1.2.2)
Requirement already satisfied: requests in c:\python36\lib\site-packages (from g
TTS==1.2.2)
Requirement already satisfied: gtts_token in c:\python36\lib\site-packages (from
 gTTS==1.2.2)
Installing collected packages: gTTS
  Running setup.py install for gTTS ... done
Successfully installed gTTS-1.2.2

安裝好 gTTS 後, 就可以開始進行測試了. 首先是從 gtts 套件匯入 gTTS 模組 , 接著呼叫建構式 gTTS() 傳入文字字串並指定語言以建立一個 gTTS 物件, 然後呼叫 gTTS 物件的 save() 方法將轉出來的語音存成本地的 mp3 檔 :

測試 1 : 中文 TTS 生日快樂

from gtts import gTTS
tts=gTTS(text='生日快樂', lang='zh')
tts.save("E:\python\test\happybirthday.mp3")

此處 save() 的參數為欲儲存的檔名, 可以帶路徑, 若未指定路徑就存在目前工作路徑下.

gTTS() 建構式的 lang 參數為 ISO 639-1 語言代碼, zh 是漢語, 英文是 en, 日文是 ja, 法文是 fr, 俄語是 ru, 西班牙語是 es, 任何語言都可以, 參考 :

List of ISO 639-1 codes

例如要發出日文的 "ありがとう (謝謝)" 的話, 程式要寫成 :

測試 2 : 日文 TTS 謝謝  

from gtts import gTTS
tts=gTTS(text='ありがとう', lang='ja')
tts.save("japanese_thank_you.mp3")

測試結果真的是日文發音的 "阿麗嘎多", 不管哪一種語言都是女聲.

gTTS() 建構式還有一個預設值為 False 的 slow 參數, 若設為 True 會產生一個發音速度比較慢的 mp3 檔案, 不過使用的機會應該不多.

上面的測試程式產生的 mp3 檔案必須手動到檔案總管點擊才會播放, 有沒有辦法用 Python 程式播放呢? 上面教學影片中的第二部分介紹利用 pygame 模組中的 mixer 混音器來播放音檔.

首先要先安裝 pygame 套件 :

https://pypi.python.org/pypi/Pygame/1.9.3

D:\Python>pip3 install pygame 
Collecting pygame
  Downloading pygame-1.9.3-cp36-cp36m-win_amd64.whl (4.2MB)
Installing collected packages: pygame
Successfully installed pygame-1.9.3

這樣就可以來測試音檔播放了, 關於 mixer 模組的用法, 參考 :

https://www.pygame.org/docs/ref/music.html

測試 3 : 播放 mp3 檔案  

from pygame import mixer
mixer.init()
mixer.music.load('E:\\Python\\test\\japanese_thank_you.mp3')
mixer.music.play()

注意, load() 方法的參數若有含路徑符號 '\' 必須跳脫, 即須使用 '\\'. 而 play() 預設是播放一次, 若要播放多次, 可用 loops 參數指定次數, 例如 :

mixer.music.play(loops=5)

"The loops argument controls the number of repeats a music will play. play(5) will cause the music to played once, then repeated five times, for a total of six. If the loops is -1 then the music will repeat indefinitely."

但我實際測試似乎次數不到 5 次, 只有 3 次, 很奇怪. 更奇怪的是, 上面測試 3 的程式在 IDLE 介面執行沒問題, 但若存成 .py 檔案用 python 指令去執行卻不會播放語音, 但也不會出現錯誤. (是我筆電的問題).

上面範例是明確指定 mp3 音檔, 可以利用 tempfile 模組使用暫存檔, 執行過後即自動刪除, 如下範例所示 :

測試 4 : 使用暫存檔儲存音檔 

from gtts import gTTS
from pygame import mixer
import tempfile
with tempfile.NamedTemporaryFile(delete=True) as fp:
    tts=gTTS(text='ありがとう', lang='ja')
    tts.save('{}.mp3'.format(fp.name))
    mixer.init()
    mixer.music.load('{}.mp3'.format(fp.name))
    mixer.music.play()

同樣地, 上述程式要在 IDLE 中執行才有效, 將其存成 tts.py 後用 python tts.py 雖可執行卻沒有播放. 上面測試 4 程式可進一步寫成函數, 如下所示 :

測試 5 : 寫成 spesk() 函數

import time
from gtts import gTTS
from pygame import mixer
import tempfile

def speak(sentence, lang, loops=1):
    with tempfile.NamedTemporaryFile(delete=True) as fp:
        tts=gTTS(text=sentence, lang=lang)
        tts.save('{}.mp3'.format(fp.name))
        mixer.init()
        mixer.music.load('{}.mp3'.format(fp.name))
        mixer.music.play(loop)

speak('ありがとう', 'ja')
time.sleep(3)
speak('全國的軍民同胞們, 川普是笨蛋', 'zh')
time.sleep(10)
speak('Hello World!', 'en')
time.sleep(3)

以上便是 Google TTS 的測試, 語音品質還不錯. 只是為何用執行 .py 檔案無效果還有待研究. (好像是我筆電的問題).

2017-08-25 :

用家裡電腦測試結果, 執行 .py 檔案沒問題, 可能我筆電有問題.

10 則留言 :

追隨上帝的新鮮人 提到...

版主,您好
我是南台科大的學生,我從你的文章中學習很多
然後也跟版主在"測試五"有相同問題,我使用raspberry pi 運作,有出現error
然後我將loop刪除掉,就可以正常運作
code:

import time
from gtts import gTTS
from pygame import mixer
import tempfile

def speak(sentence, lang):
with tempfile.NamedTemporaryFile(delete=True) as fp:
tts=gTTS(text=sentence, lang=lang)
tts.save('{}.mp3'.format(fp.name))
mixer.init()
mixer.music.load('{}.mp3'.format(fp.name))
mixer.music.play(1)

speak('ありがとう', 'ja')
time.sleep(3)
speak('全國的軍民同胞們, 川普是笨蛋', 'zh')
time.sleep(10)
speak('Hello World!', 'en')
time.sleep(3)

小狐狸事務所 提到...

謝謝分享, 我試試看喔!

匿名 提到...

speak('全國的軍民同胞們, 川普是笨蛋', 'zh')
這裡的zh少"tw",在Window執行會顯示"ValueError: Language not supported: zh"。
完整的如下:
speak('全國的軍民同胞們, 川普是笨蛋', 'zh-tw')

小狐狸事務所 提到...

不知是我誤打還是機器不同, 待我有空重試看看, 感謝您!

阿宏宏 提到...

我測出來也是跟上面測的人一樣的結果

1、zh少"tw",在Window執行會顯示"ValueError: Language not supported: zh"。
2、第二個錯是「NameError: name 'loop' is not defined」沒有定義loop,拿掉就解決了

xxx 開發團隊 提到...

應該是python跟套件版本的問題
我的版本為conda create -n python36env python=3.6 anaconda
底下測試過!!正確無誤~~~

import time
from gtts import gTTS
from pygame import mixer
import tempfile

def speak(sentence, lang,loop=1):
with tempfile.NamedTemporaryFile(delete=True) as fp:
tts=gTTS(text=sentence, lang=lang)
tts.save('{}.mp3'.format(fp.name))
mixer.init()
mixer.music.load('{}.mp3'.format(fp.name))
mixer.music.play(loop)

speak('ありがとう', 'ja')
time.sleep(3)
speak('全國的軍民同胞們, 川普是笨蛋', 'zh-tw')
time.sleep(10)
speak('Hello World!', 'en')
time.sleep(3)

小狐狸事務所 提到...

感謝您的留言, 我再試試看!

匿名 提到...

「NameError: name 'loop' is not defined」
原因應該是「def speak(sentence, lang, loops=1):」中,
loops=1要改成loop=1吧?

匿名 提到...

出來的語音,聲音變好奇怪唷,這可以語速跟音調可以調嗎?

小狐狸事務所 提到...

我的筆電測試不會啊, 會不會是音訊卡問題